diff --git a/.env b/.env new file mode 100644 index 0000000..7c67d96 --- /dev/null +++ b/.env @@ -0,0 +1,48 @@ +APP_DEBUG=false +APP_ENV=production +APP_FALLBACK_LOCALE=en + +DB_CONNECTION=mysql +DB_HOST=localhost +DB_PORT=3306 +DB_DATABASE=skin_tdogmc_top +DB_USERNAME=skin_tdogmc_top +DB_PASSWORD=Lcm18876588595 +DB_PREFIX= + +# Hash Algorithm for Passwords +# +# Available values: +# - BCRYPT, ARGON2I, PHP_PASSWORD_HASH +# - MD5, SALTED2MD5 +# - SHA256, SALTED2SHA256 +# - SHA512, SALTED2SHA512 +# +# New sites are *highly* recommended to use BCRYPT. +# +PWD_METHOD=BCRYPT +APP_KEY=base64:J3pS/AID0gUU1u6GHFFOSBtFMOEyx/EFIKc77A0ZGMc= + +MAIL_MAILER=smtp +MAIL_HOST=smtp.163.com +MAIL_PORT=465 +MAIL_USERNAME=tdogmc@163.com +MAIL_PASSWORD=EMJCETKJALZNMPBY +MAIL_ENCRYPTION=ssl +MAIL_FROM_ADDRESS=tdogmc@163.com +MAIL_FROM_NAME=神之愿服务器 + +CACHE_DRIVER=file +SESSION_DRIVER=file +QUEUE_CONNECTION=sync + +REDIS_CLIENT=phpredis +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +PLUGINS_DIR=null +PLUGINS_URL=null +PLUGINS_REGISTRY=https://d2jw1l0ullrzt6.cloudfront.net/registry_{lang}.json + +JWT_SECRET=Jfz3FrSndLFfOE0AaT7UBsvEaufHBHYUAcjeO3eCegaMykRR6MuS5pb0lyDnsyzs \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..057cfce --- /dev/null +++ b/.env.example @@ -0,0 +1,45 @@ +APP_DEBUG=false +APP_ENV=production +APP_FALLBACK_LOCALE=en + +DB_CONNECTION=mysql +DB_HOST=localhost +DB_PORT=3306 +DB_DATABASE=blessingskin +DB_USERNAME=username +DB_PASSWORD=secret +DB_PREFIX= + +# Hash Algorithm for Passwords +# +# Available values: +# - BCRYPT, ARGON2I, PHP_PASSWORD_HASH +# - MD5, SALTED2MD5 +# - SHA256, SALTED2SHA256 +# - SHA512, SALTED2SHA512 +# +# New sites are *highly* recommended to use BCRYPT. +# +PWD_METHOD=BCRYPT +APP_KEY= + +MAIL_MAILER=smtp +MAIL_HOST= +MAIL_PORT=465 +MAIL_USERNAME= +MAIL_PASSWORD= +MAIL_ENCRYPTION= +MAIL_FROM_ADDRESS= +MAIL_FROM_NAME= + +CACHE_DRIVER=file +SESSION_DRIVER=file +QUEUE_CONNECTION=sync + +REDIS_CLIENT=phpredis +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +PLUGINS_DIR=null +PLUGINS_URL=null diff --git a/.htaccess b/.htaccess new file mode 100755 index 0000000..0519ecb --- /dev/null +++ b/.htaccess @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/404.html b/404.html new file mode 100755 index 0000000..ca6e415 --- /dev/null +++ b/404.html @@ -0,0 +1,9 @@ + + +404 Not Found + +

404 Not Found

+
nginx
+ + + \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2aa298c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016-present The Blessing Skin Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/app/Console/Commands/BsInstallCommand.php b/app/Console/Commands/BsInstallCommand.php new file mode 100755 index 0000000..36fc57b --- /dev/null +++ b/app/Console/Commands/BsInstallCommand.php @@ -0,0 +1,52 @@ +exists(storage_path('install.lock'))) { + $this->info('You have installed Blessing Skin Server. Nothing to do.'); + + return; + } + + $this->call('migrate', ['--force' => true]); + if (!$this->getLaravel()->runningUnitTests()) { + // @codeCoverageIgnoreStart + $this->call('key:generate'); + $this->call('passport:keys', ['--no-interaction' => true]); + // @codeCoverageIgnoreEnd + } + + option(['site_url' => url('/')]); + + $admin = new User(); + $admin->email = $this->argument('email'); + $admin->nickname = $this->argument('nickname'); + $admin->score = option('user_initial_score'); + $admin->avatar = 0; + $admin->password = app('cipher')->hash($this->argument('password'), config('secure.salt')); + $admin->ip = '127.0.0.1'; + $admin->permission = User::SUPER_ADMIN; + $admin->register_at = Carbon::now(); + $admin->last_sign_at = Carbon::now()->subDay(); + $admin->verified = true; + $admin->save(); + + $filesystem->put(storage_path('install.lock'), ''); + + $this->info('Installation completed!'); + $this->info('We recommend to modify your "Site URL" option if incorrect.'); + } +} diff --git a/app/Console/Commands/OptionsCacheCommand.php b/app/Console/Commands/OptionsCacheCommand.php new file mode 100755 index 0000000..5a13108 --- /dev/null +++ b/app/Console/Commands/OptionsCacheCommand.php @@ -0,0 +1,28 @@ +delete($path); + $app->forgetInstance(Option::class); + + $content = var_export(resolve(Option::class)->all(), true); + $notice = '// This is auto-generated. DO NOT edit manually.'.PHP_EOL; + $content = 'put($path, $content); + $this->info('Options cached successfully.'); + } +} diff --git a/app/Console/Commands/PluginDisableCommand.php b/app/Console/Commands/PluginDisableCommand.php new file mode 100755 index 0000000..e62c15f --- /dev/null +++ b/app/Console/Commands/PluginDisableCommand.php @@ -0,0 +1,25 @@ +get($this->argument('name')); + if ($plugin) { + $plugins->disable($this->argument('name')); + $title = trans($plugin->title); + $this->info(trans('admin.plugins.operations.disabled', ['plugin' => $title])); + } else { + $this->warn(trans('admin.plugins.operations.not-found')); + } + } +} diff --git a/app/Console/Commands/PluginEnableCommand.php b/app/Console/Commands/PluginEnableCommand.php new file mode 100755 index 0000000..eb45f27 --- /dev/null +++ b/app/Console/Commands/PluginEnableCommand.php @@ -0,0 +1,26 @@ +argument('name'); + $result = $plugins->enable($name); + if ($result === true) { + $plugin = $plugins->get($name); + $title = trans($plugin->title); + $this->info(trans('admin.plugins.operations.enabled', ['plugin' => $title])); + } elseif ($result === false) { + $this->warn(trans('admin.plugins.operations.not-found')); + } + } +} diff --git a/app/Console/Commands/SaltRandomCommand.php b/app/Console/Commands/SaltRandomCommand.php new file mode 100755 index 0000000..de94b64 --- /dev/null +++ b/app/Console/Commands/SaltRandomCommand.php @@ -0,0 +1,44 @@ +generateRandomSalt(); + + if ($this->option('show')) { + return $this->line(''.$salt.''); + } + + // Next, we will replace the application salt in the environment file so it is + // automatically setup for this developer. This salt gets generated using a + // secure random byte generator and is later base64 encoded for storage. + $this->setKeyInEnvironmentFile($salt); + + $this->laravel['config']['secure.salt'] = $salt; + + $this->info("Application salt [$salt] set successfully."); + } + + protected function setKeyInEnvironmentFile(string $salt) + { + file_put_contents($this->laravel->environmentFilePath(), str_replace( + 'SALT = '.$this->laravel['config']['secure.salt'], + 'SALT = '.$salt, + file_get_contents($this->laravel->environmentFilePath()) + )); + } + + protected function generateRandomSalt(): string + { + return bin2hex(resolve(\Illuminate\Contracts\Encryption\Encrypter::class)->generateKey('AES-128-CBC')); + } +} diff --git a/app/Console/Commands/UpdateCommand.php b/app/Console/Commands/UpdateCommand.php new file mode 100755 index 0000000..bbf89a1 --- /dev/null +++ b/app/Console/Commands/UpdateCommand.php @@ -0,0 +1,49 @@ +procedures()->each(function ($procedure, $version) { + if (Comparator::lessThan(option('version'), $version)) { + $procedure(); + } + }); + + option(['version' => config('app.version')]); + $artisan->call('migrate', ['--force' => true]); + $artisan->call('view:clear'); + $filesystem->put(storage_path('install.lock'), ''); + Cache::flush(); + + $this->info(trans('setup.updates.success.title')); + } + + /** + * @codeCoverageIgnore + */ + protected function procedures() + { + return collect([ + // this is just for testing + '0.0.1' => fn () => event('__0.0.1'), + '5.0.0' => function () { + if (option('home_pic_url') === './app/bg.jpg') { + option(['home_pic_url' => './app/bg.webp']); + } + }, + ]); + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php new file mode 100755 index 0000000..257f751 --- /dev/null +++ b/app/Console/Kernel.php @@ -0,0 +1,18 @@ +menu = &$menu; + } +} diff --git a/app/Events/ConfigureExploreMenu.php b/app/Events/ConfigureExploreMenu.php new file mode 100755 index 0000000..36ab7f0 --- /dev/null +++ b/app/Events/ConfigureExploreMenu.php @@ -0,0 +1,14 @@ +menu = &$menu; + } +} diff --git a/app/Events/ConfigureRoutes.php b/app/Events/ConfigureRoutes.php new file mode 100755 index 0000000..20ca265 --- /dev/null +++ b/app/Events/ConfigureRoutes.php @@ -0,0 +1,15 @@ +router = $router; + } +} diff --git a/app/Events/ConfigureUserMenu.php b/app/Events/ConfigureUserMenu.php new file mode 100755 index 0000000..7e882e0 --- /dev/null +++ b/app/Events/ConfigureUserMenu.php @@ -0,0 +1,13 @@ +menu = &$menu; + } +} diff --git a/app/Events/Event.php b/app/Events/Event.php new file mode 100755 index 0000000..caf3481 --- /dev/null +++ b/app/Events/Event.php @@ -0,0 +1,7 @@ +player = $player; + } +} diff --git a/app/Events/PlayerRetrieved.php b/app/Events/PlayerRetrieved.php new file mode 100755 index 0000000..7a29b7a --- /dev/null +++ b/app/Events/PlayerRetrieved.php @@ -0,0 +1,15 @@ +player = $player; + } +} diff --git a/app/Events/PlayerWasAdded.php b/app/Events/PlayerWasAdded.php new file mode 100755 index 0000000..06d52fb --- /dev/null +++ b/app/Events/PlayerWasAdded.php @@ -0,0 +1,15 @@ +player = $player; + } +} diff --git a/app/Events/PlayerWasDeleted.php b/app/Events/PlayerWasDeleted.php new file mode 100755 index 0000000..4e24146 --- /dev/null +++ b/app/Events/PlayerWasDeleted.php @@ -0,0 +1,13 @@ +playerName = $playerName; + } +} diff --git a/app/Events/PlayerWillBeAdded.php b/app/Events/PlayerWillBeAdded.php new file mode 100755 index 0000000..7e55a21 --- /dev/null +++ b/app/Events/PlayerWillBeAdded.php @@ -0,0 +1,13 @@ +playerName = $playerName; + } +} diff --git a/app/Events/PlayerWillBeDeleted.php b/app/Events/PlayerWillBeDeleted.php new file mode 100755 index 0000000..496e2ba --- /dev/null +++ b/app/Events/PlayerWillBeDeleted.php @@ -0,0 +1,15 @@ +player = $player; + } +} diff --git a/app/Events/PluginBootFailed.php b/app/Events/PluginBootFailed.php new file mode 100755 index 0000000..51ca2dc --- /dev/null +++ b/app/Events/PluginBootFailed.php @@ -0,0 +1,15 @@ +plugin = $plugin; + } +} diff --git a/app/Events/PluginWasDeleted.php b/app/Events/PluginWasDeleted.php new file mode 100755 index 0000000..c162c9d --- /dev/null +++ b/app/Events/PluginWasDeleted.php @@ -0,0 +1,15 @@ +plugin = $plugin; + } +} diff --git a/app/Events/PluginWasDisabled.php b/app/Events/PluginWasDisabled.php new file mode 100755 index 0000000..a69b6eb --- /dev/null +++ b/app/Events/PluginWasDisabled.php @@ -0,0 +1,15 @@ +plugin = $plugin; + } +} diff --git a/app/Events/PluginWasEnabled.php b/app/Events/PluginWasEnabled.php new file mode 100755 index 0000000..a3721dd --- /dev/null +++ b/app/Events/PluginWasEnabled.php @@ -0,0 +1,15 @@ +plugin = $plugin; + } +} diff --git a/app/Events/RenderingBadges.php b/app/Events/RenderingBadges.php new file mode 100755 index 0000000..4594d78 --- /dev/null +++ b/app/Events/RenderingBadges.php @@ -0,0 +1,13 @@ +badges = &$badges; + } +} diff --git a/app/Events/RenderingFooter.php b/app/Events/RenderingFooter.php new file mode 100755 index 0000000..7efd142 --- /dev/null +++ b/app/Events/RenderingFooter.php @@ -0,0 +1,18 @@ +contents = &$contents; + } + + public function addContent(string $content) + { + $this->contents[] = $content; + } +} diff --git a/app/Events/RenderingHeader.php b/app/Events/RenderingHeader.php new file mode 100755 index 0000000..c136f33 --- /dev/null +++ b/app/Events/RenderingHeader.php @@ -0,0 +1,18 @@ +contents = &$contents; + } + + public function addContent(string $content) + { + $this->contents[] = $content; + } +} diff --git a/app/Events/TextureDeleting.php b/app/Events/TextureDeleting.php new file mode 100755 index 0000000..59522ff --- /dev/null +++ b/app/Events/TextureDeleting.php @@ -0,0 +1,13 @@ +texture = $texture; + } +} diff --git a/app/Events/UserAuthenticated.php b/app/Events/UserAuthenticated.php new file mode 100755 index 0000000..8faf511 --- /dev/null +++ b/app/Events/UserAuthenticated.php @@ -0,0 +1,15 @@ +user = $user; + } +} diff --git a/app/Events/UserLoggedIn.php b/app/Events/UserLoggedIn.php new file mode 100755 index 0000000..6dc44ea --- /dev/null +++ b/app/Events/UserLoggedIn.php @@ -0,0 +1,15 @@ +user = $user; + } +} diff --git a/app/Events/UserProfileUpdated.php b/app/Events/UserProfileUpdated.php new file mode 100755 index 0000000..6ef8387 --- /dev/null +++ b/app/Events/UserProfileUpdated.php @@ -0,0 +1,17 @@ +type = $type; + $this->user = $user; + } +} diff --git a/app/Events/UserRegistered.php b/app/Events/UserRegistered.php new file mode 100755 index 0000000..1ebf02c --- /dev/null +++ b/app/Events/UserRegistered.php @@ -0,0 +1,15 @@ +user = $user; + } +} diff --git a/app/Events/UserTryToLogin.php b/app/Events/UserTryToLogin.php new file mode 100755 index 0000000..bd851b0 --- /dev/null +++ b/app/Events/UserTryToLogin.php @@ -0,0 +1,16 @@ +identification = $identification; + $this->authType = $authType; + } +} diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php new file mode 100755 index 0000000..8dc3cc8 --- /dev/null +++ b/app/Exceptions/Handler.php @@ -0,0 +1,64 @@ +getModel(); + if (Str::endsWith($model, 'Texture')) { + $exception = new ModelNotFoundException(trans('skinlib.non-existent')); + } + } elseif ($exception instanceof MissingScopeException) { + return json($exception->getMessage(), 403); + } + + return parent::render($request, $exception); + } + + protected function convertExceptionToArray(Throwable $e) + { + return [ + 'message' => $e->getMessage(), + 'exception' => true, + 'trace' => collect($e->getTrace()) + ->map(fn ($trace) => Arr::only($trace, ['file', 'line'])) + ->filter(fn ($trace) => Arr::has($trace, 'file')) + ->map(function ($trace) { + $trace['file'] = str_replace(base_path().DIRECTORY_SEPARATOR, '', $trace['file']); + + return $trace; + }) + ->filter(function ($trace) { + // @codeCoverageIgnoreStart + $isFromPlugins = !app()->runningUnitTests() && + Str::contains($trace['file'], resolve('plugins')->getPluginsDirs()->all()); + // @codeCoverageIgnoreEnd + return Str::startsWith($trace['file'], 'app') || $isFromPlugins; + }) + ->values(), + ]; + } +} diff --git a/app/Exceptions/PrettyPageException.php b/app/Exceptions/PrettyPageException.php new file mode 100755 index 0000000..a15a8c0 --- /dev/null +++ b/app/Exceptions/PrettyPageException.php @@ -0,0 +1,11 @@ +view('errors.pretty', ['code' => $this->code, 'message' => $this->message]); + } +} diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php new file mode 100755 index 0000000..24ec0c5 --- /dev/null +++ b/app/Http/Controllers/AdminController.php @@ -0,0 +1,149 @@ + [ + ['md-6', 'md-6'], + ], + 'widgets' => [ + [ + [ + 'admin.widgets.dashboard.usage', + 'admin.widgets.dashboard.notification', + ], + ['admin.widgets.dashboard.chart'], + ], + ], + ]; + $grid = $filter->apply('grid:admin.index', $grid); + + return view('admin.index', [ + 'grid' => $grid, + 'sum' => [ + 'users' => User::count(), + 'players' => Player::count(), + 'textures' => Texture::count(), + 'storage' => Texture::select('size')->sum('size'), + ], + ]); + } + + public function chartData() + { + $xAxis = Collection::times(31, fn ($i) => Carbon::today()->subDays(31 - $i)->isoFormat('l')); + + $oneMonthAgo = Carbon::today()->subMonth(); + + $grouping = fn ($field) => fn ($item) => Carbon::parse($item->$field)->isoFormat('l'); + $mapping = fn ($item) => count($item); + $aligning = fn ($data) => fn ($day) => ($data->get($day) ?? 0); + + /** @var Collection */ + $userRegistration = User::where('register_at', '>=', $oneMonthAgo) + ->select('register_at') + ->get() + ->groupBy($grouping('register_at')) + ->map($mapping); + + /** @var Collection */ + $textureUploads = Texture::where('upload_at', '>=', $oneMonthAgo) + ->select('upload_at') + ->get() + ->groupBy($grouping('upload_at')) + ->map($mapping); + + return [ + 'labels' => [ + trans('admin.index.user-registration'), + trans('admin.index.texture-uploads'), + ], + 'xAxis' => $xAxis, + 'data' => [ + $xAxis->map($aligning($userRegistration)), + $xAxis->map($aligning($textureUploads)), + ], + ]; + } + + public function status( + Request $request, + PluginManager $plugins, + Filesystem $filesystem, + Filter $filter + ) { + $db = config('database.connections.'.config('database.default')); + $dbType = Arr::get([ + 'mysql' => 'MySQL/MariaDB', + 'sqlite' => 'SQLite', + 'pgsql' => 'PostgreSQL', + ], config('database.default'), ''); + + $enabledPlugins = $plugins->getEnabledPlugins()->map(fn ($plugin) => [ + 'title' => trans($plugin->title), 'version' => $plugin->version, + ]); + + if ($filesystem->exists(base_path('.git'))) { + $process = new \Symfony\Component\Process\Process( + ['git', 'log', '--pretty=%H', '-1'] + ); + $process->run(); + $commit = $process->isSuccessful() ? trim($process->getOutput()) : ''; + } + + $grid = [ + 'layout' => [ + ['md-6', 'md-6'], + ], + 'widgets' => [ + [ + ['admin.widgets.status.info'], + ['admin.widgets.status.plugins'], + ], + ], + ]; + $grid = $filter->apply('grid:admin.status', $grid); + + return view('admin.status') + ->with('grid', $grid) + ->with('detail', [ + 'bs' => [ + 'version' => config('app.version'), + 'env' => config('app.env'), + 'debug' => config('app.debug') ? trans('general.yes') : trans('general.no'), + 'commit' => Str::limit($commit ?? '', 16, ''), + 'laravel' => app()->version(), + ], + 'server' => [ + 'php' => PHP_VERSION, + 'web' => $request->server('SERVER_SOFTWARE', trans('general.unknown')), + 'os' => sprintf('%s %s %s', php_uname('s'), php_uname('r'), php_uname('m')), + ], + 'db' => [ + 'type' => $dbType, + 'host' => Arr::get($db, 'host', ''), + 'port' => Arr::get($db, 'port', ''), + 'username' => Arr::get($db, 'username'), + 'database' => Arr::get($db, 'database'), + 'prefix' => Arr::get($db, 'prefix'), + ], + ]) + ->with('plugins', $enabledPlugins); + } +} diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php new file mode 100755 index 0000000..d750c9a --- /dev/null +++ b/app/Http/Controllers/AuthController.php @@ -0,0 +1,373 @@ +getValidIpAddress(); + $ip = $filter->apply('client_ip', $ip); + + $rows = [ + 'auth.rows.login.notice', + 'auth.rows.login.message', + 'auth.rows.login.form', + 'auth.rows.login.registration-link', + ]; + $rows = $filter->apply('auth_page_rows:login', $rows); + + return view('auth.login', [ + 'rows' => $rows, + 'extra' => [ + 'tooManyFails' => cache(sha1('login_fails_'.$ip)) > 3, + 'recaptcha' => option('recaptcha_sitekey'), + 'invisible' => (bool) option('recaptcha_invisible'), + ], + ]); + } + + public function handleLogin( + Request $request, + Rules\Captcha $captcha, + Dispatcher $dispatcher, + Filter $filter + ) { + $data = $request->validate([ + 'identification' => 'required', + 'password' => 'required|min:6|max:32', + ]); + $identification = $data['identification']; + $password = $data['password']; + + $can = $filter->apply('can_login', null, [$identification, $password]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + // Guess type of identification + $authType = filter_var($identification, FILTER_VALIDATE_EMAIL) ? 'email' : 'username'; + + $dispatcher->dispatch('auth.login.attempt', [$identification, $password, $authType]); + event(new Events\UserTryToLogin($identification, $authType)); + + if ($authType == 'email') { + $user = User::where('email', $identification)->first(); + } else { + $player = Player::where('name', $identification)->first(); + $user = optional($player)->user; + } + + // Require CAPTCHA if user fails to login more than 3 times + $whip = new Whip(); + $ip = $whip->getValidIpAddress(); + $ip = $filter->apply('client_ip', $ip); + $loginFailsCacheKey = sha1('login_fails_'.$ip); + $loginFails = (int) Cache::get($loginFailsCacheKey, 0); + + if ($loginFails > 3) { + $request->validate(['captcha' => ['required', $captcha]]); + } + + if (!$user) { + return json(trans('auth.validation.user'), 2); + } + + $dispatcher->dispatch('auth.login.ready', [$user]); + + if ($user->verifyPassword($request->input('password'))) { + Session::forget('login_fails'); + Cache::forget($loginFailsCacheKey); + + Auth::login($user, $request->input('keep')); + + $dispatcher->dispatch('auth.login.succeeded', [$user]); + event(new Events\UserLoggedIn($user)); + + return json(trans('auth.login.success'), 0, [ + 'redirectTo' => $request->session()->pull('last_requested_path', url('/user')), + ]); + } else { + $loginFails++; + Cache::put($loginFailsCacheKey, $loginFails, 3600); + $dispatcher->dispatch('auth.login.failed', [$user, $loginFails]); + + return json(trans('auth.validation.password'), 1, [ + 'login_fails' => $loginFails, + ]); + } + } + + public function logout(Dispatcher $dispatcher) + { + $user = Auth::user(); + + $dispatcher->dispatch('auth.logout.before', [$user]); + Auth::logout(); + $dispatcher->dispatch('auth.logout.after', [$user]); + + return json(trans('auth.logout.success'), 0); + } + + public function register(Filter $filter) + { + $rows = [ + 'auth.rows.register.notice', + 'auth.rows.register.form', + ]; + $rows = $filter->apply('auth_page_rows:register', $rows); + + return view('auth.register', [ + 'site_name' => option_localized('site_name'), + 'rows' => $rows, + 'extra' => [ + 'player' => (bool) option('register_with_player_name'), + 'recaptcha' => option('recaptcha_sitekey'), + 'invisible' => (bool) option('recaptcha_invisible'), + ], + ]); + } + + public function handleRegister( + Request $request, + Rules\Captcha $captcha, + Dispatcher $dispatcher, + Filter $filter + ) { + $can = $filter->apply('can_register', null); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $rule = option('register_with_player_name') ? + ['player_name' => [ + 'required', + new Rules\PlayerName(), + 'min:'.option('player_name_length_min'), + 'max:'.option('player_name_length_max'), + ]] : + ['nickname' => 'required|max:255']; + $data = $request->validate(array_merge([ + 'email' => 'required|email|unique:users', + 'password' => 'required|min:8|max:32', + 'captcha' => ['required', $captcha], + ], $rule)); + $playerName = $request->input('player_name'); + + $dispatcher->dispatch('auth.registration.attempt', [$data]); + + if ( + option('register_with_player_name') && + Player::where('name', $playerName)->count() > 0 + ) { + return json(trans('user.player.add.repeated'), 1); + } + + // If amount of registered accounts of IP is more than allowed amount, + // reject this registration. + $whip = new Whip(); + $ip = $whip->getValidIpAddress(); + $ip = $filter->apply('client_ip', $ip); + if (User::where('ip', $ip)->count() >= option('regs_per_ip')) { + return json(trans('auth.register.max', ['regs' => option('regs_per_ip')]), 1); + } + + $dispatcher->dispatch('auth.registration.ready', [$data]); + + $user = new User(); + $user->email = $data['email']; + $user->nickname = $data[option('register_with_player_name') ? 'player_name' : 'nickname']; + $user->score = option('user_initial_score'); + $user->avatar = 0; + $password = app('cipher')->hash($data['password'], config('secure.salt')); + $password = $filter->apply('user_password', $password); + $user->password = $password; + $user->ip = $ip; + $user->permission = User::NORMAL; + $user->register_at = Carbon::now(); + $user->last_sign_at = Carbon::now()->subDay(); + $user->save(); + + $dispatcher->dispatch('auth.registration.completed', [$user]); + event(new Events\UserRegistered($user)); + + if (option('register_with_player_name')) { + $dispatcher->dispatch('player.adding', [$playerName, $user]); + + $player = new Player(); + $player->uid = $user->uid; + $player->name = $playerName; + $player->tid_skin = 0; + $player->save(); + + $dispatcher->dispatch('player.added', [$player, $user]); + event(new Events\PlayerWasAdded($player)); + } + + $dispatcher->dispatch('auth.login.ready', [$user]); + Auth::login($user); + $dispatcher->dispatch('auth.login.succeeded', [$user]); + + return json(trans('auth.register.success'), 0); + } + + public function forgot() + { + if (config('mail.default') != '') { + return view('auth.forgot', [ + 'extra' => [ + 'recaptcha' => option('recaptcha_sitekey'), + 'invisible' => (bool) option('recaptcha_invisible'), + ], + ]); + } else { + throw new PrettyPageException(trans('auth.forgot.disabled'), 8); + } + } + + public function handleForgot( + Request $request, + Rules\Captcha $captcha, + Dispatcher $dispatcher, + Filter $filter + ) { + $data = $request->validate([ + 'email' => 'required|email', + 'captcha' => ['required', $captcha], + ]); + + if (!config('mail.default')) { + return json(trans('auth.forgot.disabled'), 1); + } + + $email = $data['email']; + $dispatcher->dispatch('auth.forgot.attempt', [$email]); + + $rateLimit = 180; + $whip = new Whip(); + $ip = $whip->getValidIpAddress(); + $ip = $filter->apply('client_ip', $ip); + $lastMailCacheKey = sha1('last_mail_'.$ip); + $remain = $rateLimit + Cache::get($lastMailCacheKey, 0) - time(); + if ($remain > 0) { + return json(trans('auth.forgot.frequent-mail'), 2); + } + + $user = User::where('email', $email)->first(); + if (!$user) { + return json(trans('auth.forgot.unregistered'), 1); + } + + $dispatcher->dispatch('auth.forgot.ready', [$user]); + + $url = URL::temporarySignedRoute( + 'auth.reset', + Carbon::now()->addHour(), + ['uid' => $user->uid], + false + ); + try { + Mail::to($email)->send(new ForgotPassword(url($url))); + } catch (\Exception $e) { + report($e); + $dispatcher->dispatch('auth.forgot.failed', [$user, $url]); + + return json(trans('auth.forgot.failed', ['msg' => $e->getMessage()]), 2); + } + + $dispatcher->dispatch('auth.forgot.sent', [$user, $url]); + Cache::put($lastMailCacheKey, time(), 3600); + + return json(trans('auth.forgot.success'), 0); + } + + public function reset(Request $request, $uid) + { + abort_unless($request->hasValidSignature(false), 403, trans('auth.reset.invalid')); + + return view('auth.reset')->with('user', User::find($uid)); + } + + public function handleReset(Dispatcher $dispatcher, Request $request, $uid) + { + abort_unless($request->hasValidSignature(false), 403, trans('auth.reset.invalid')); + + ['password' => $password] = $request->validate([ + 'password' => 'required|min:8|max:32', + ]); + $user = User::find($uid); + + $dispatcher->dispatch('auth.reset.before', [$user, $password]); + $user->changePassword($password); + $dispatcher->dispatch('auth.reset.after', [$user, $password]); + + return json(trans('auth.reset.success'), 0); + } + + public function captcha(\Gregwar\Captcha\CaptchaBuilder $builder) + { + $builder->build(100, 34); + session(['captcha' => $builder->getPhrase()]); + + return response($builder->output(), 200, [ + 'Content-Type' => 'image/jpeg', + 'Cache-Control' => 'no-store', + ]); + } + + public function fillEmail(Request $request) + { + $email = $request->validate(['email' => 'required|email|unique:users'])['email']; + $user = $request->user(); + $user->email = $email; + $user->save(); + + return redirect('/user'); + } + + public function verify(Request $request) + { + if (!option('require_verification')) { + throw new PrettyPageException(trans('user.verification.disabled'), 1); + } + + abort_unless($request->hasValidSignature(false), 403, trans('auth.verify.invalid')); + + return view('auth.verify'); + } + + public function handleVerify(Request $request, User $user) + { + abort_unless($request->hasValidSignature(false), 403, trans('auth.verify.invalid')); + + ['email' => $email] = $request->validate(['email' => 'required|email']); + + if ($user->email !== $email) { + return back()->with('errorMessage', trans('auth.verify.not-matched')); + } + + $user->verified = true; + $user->save(); + + return redirect()->route('user.home'); + } +} diff --git a/app/Http/Controllers/ClosetController.php b/app/Http/Controllers/ClosetController.php new file mode 100755 index 0000000..3529cfa --- /dev/null +++ b/app/Http/Controllers/ClosetController.php @@ -0,0 +1,198 @@ + [ + ['md-8', 'md-4'], + ], + 'widgets' => [ + [ + [ + 'user.widgets.email-verification', + 'user.widgets.closet.list', + ], + ['shared.previewer'], + ], + ], + ]; + $grid = $filter->apply('grid:user.closet', $grid); + + return view('user.closet') + ->with('grid', $grid) + ->with('extra', [ + 'unverified' => option('require_verification') && !auth()->user()->verified, + 'rule' => trans('user.player.player-name-rule.'.option('player_name_rule')), + 'length' => trans( + 'user.player.player-name-length', + ['min' => option('player_name_length_min'), 'max' => option('player_name_length_max')] + ), + ]); + } + + public function getClosetData(Request $request) + { + $category = $request->input('category', 'skin'); + /** @var User */ + $user = auth()->user(); + + return $user + ->closet() + ->when( + $category === 'cape', + fn (Builder $query) => $query->where('type', 'cape'), + fn (Builder $query) => $query->whereIn('type', ['steve', 'alex']), + ) + ->when( + $request->input('q'), + fn (Builder $query, $search) => $query->like('item_name', $search) + ) + ->orderBy('texture_tid', 'DESC') + ->paginate((int) $request->input('perPage', 6)); + } + + public function allIds() + { + /** @var User */ + $user = auth()->user(); + + return $user->closet()->pluck('texture_tid'); + } + + public function add( + Request $request, + Dispatcher $dispatcher, + Filter $filter + ) { + ['tid' => $tid, 'name' => $name] = $request->validate([ + 'tid' => 'required|integer', + 'name' => 'required', + ]); + + /** @var User */ + $user = Auth::user(); + $name = $filter->apply('add_closet_item_name', $name, [$tid]); + $dispatcher->dispatch('closet.adding', [$tid, $name, $user]); + + $can = $filter->apply('can_add_closet_item', true, [$tid, $name]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + if ($user->score < option('score_per_closet_item')) { + return json(trans('user.closet.add.lack-score'), 1); + } + + $tid = $request->tid; + $texture = Texture::find($tid); + if (!$texture) { + return json(trans('user.closet.add.not-found'), 1); + } + + if (!$texture->public && ($texture->uploader != $user->uid && !$user->isAdmin())) { + return json(trans('skinlib.show.private'), 1); + } + + if ($user->closet()->where('tid', $request->tid)->count() > 0) { + return json(trans('user.closet.add.repeated'), 1); + } + + $user->closet()->attach($tid, ['item_name' => $request->name]); + $user->score -= option('score_per_closet_item'); + $user->save(); + + $texture->likes++; + $texture->save(); + + $dispatcher->dispatch('closet.added', [$texture, $name, $user]); + + $uploader = User::find($texture->uploader); + if ($uploader && $uploader->uid != $user->uid) { + $uploader->score += option('score_award_per_like', 0); + $uploader->save(); + } + + return json(trans('user.closet.add.success', ['name' => $request->input('name')]), 0); + } + + public function rename( + Request $request, + Dispatcher $dispatcher, + Filter $filter, + $tid + ) { + ['name' => $name] = $request->validate(['name' => 'required']); + /** @var User */ + $user = auth()->user(); + + $name = $filter->apply('rename_closet_item_name', $name, [$tid]); + $dispatcher->dispatch('closet.renaming', [$tid, $name, $user]); + + $item = $user->closet()->find($tid); + if (empty($item)) { + return json(trans('user.closet.remove.non-existent'), 1); + } + $previousName = $item->pivot->item_name; + + $can = $filter->apply('can_rename_closet_item', true, [$item, $name]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $user->closet()->updateExistingPivot($tid, ['item_name' => $name]); + + $dispatcher->dispatch('closet.renamed', [$item, $previousName, $user]); + + return json(trans('user.closet.rename.success', ['name' => $name]), 0); + } + + public function remove(Dispatcher $dispatcher, Filter $filter, $tid) + { + /** @var User */ + $user = auth()->user(); + + $dispatcher->dispatch('closet.removing', [$tid, $user]); + + $item = $user->closet()->find($tid); + if (empty($item)) { + return json(trans('user.closet.remove.non-existent'), 1); + } + + $can = $filter->apply('can_remove_closet_item', true, [$item]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $user->closet()->detach($tid); + + if (option('return_score')) { + $user->score += option('score_per_closet_item'); + $user->save(); + } + + $texture = Texture::find($tid); + $texture->likes--; + $texture->save(); + + $dispatcher->dispatch('closet.removed', [$texture, $user]); + + $uploader = User::find($texture->uploader); + $uploader->score -= option('score_award_per_like', 0); + $uploader->save(); + + return json(trans('user.closet.remove.success'), 0); + } +} diff --git a/app/Http/Controllers/ClosetManagementController.php b/app/Http/Controllers/ClosetManagementController.php new file mode 100755 index 0000000..514f3ea --- /dev/null +++ b/app/Http/Controllers/ClosetManagementController.php @@ -0,0 +1,47 @@ +closet; + } + + public function add(Request $request, Dispatcher $dispatcher, User $user) + { + $tid = $request->input('tid'); + /** @var Texture */ + $texture = Texture::findOrFail($tid); + $name = $texture->name; + + $dispatcher->dispatch('closet.adding', [$tid, $name, $user]); + + $user->closet()->attach($texture->tid, ['item_name' => $name]); + + $dispatcher->dispatch('closet.added', [$texture, $name, $user]); + + return json('', 0, compact('user', 'texture')); + } + + public function remove(Request $request, Dispatcher $dispatcher, User $user) + { + $tid = $request->input('tid'); + $dispatcher->dispatch('closet.removing', [$tid, $user]); + + /** @var Texture */ + $texture = Texture::findOrFail($tid); + + $user->closet()->detach($texture->tid); + + $dispatcher->dispatch('closet.removed', [$texture, $user]); + + return json('', 0, compact('user', 'texture')); + } +} diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php new file mode 100755 index 0000000..23cb22e --- /dev/null +++ b/app/Http/Controllers/Controller.php @@ -0,0 +1,13 @@ +with('user', auth()->user()) + ->with('site_description', option_localized('site_description')) + ->with('transparent_navbar', (bool) option('transparent_navbar', false)) + ->with('fixed_bg', option('fixed_bg')) + ->with('hide_intro', option('hide_intro')) + ->with('home_pic_url', option('home_pic_url') ?: config('options.home_pic_url')); + } + + public function apiRoot() + { + $copyright = Arr::get( + [ + 'Powered with ❤ by Blessing Skin Server.', + 'Powered by Blessing Skin Server.', + 'Proudly powered by Blessing Skin Server.', + '由 Blessing Skin Server 强力驱动。', + '采用 Blessing Skin Server 搭建。', + '使用 Blessing Skin Server 稳定运行。', + '自豪地采用 Blessing Skin Server。', + ], + option_localized('copyright_prefer', 0) + ); + + return response()->json([ + 'blessing_skin' => config('app.version'), + 'spec' => 0, + 'copyright' => $copyright, + 'site_name' => option('site_name'), + ]); + } +} diff --git a/app/Http/Controllers/MarketController.php b/app/Http/Controllers/MarketController.php new file mode 100755 index 0000000..d3857fd --- /dev/null +++ b/app/Http/Controllers/MarketController.php @@ -0,0 +1,100 @@ +fetch()->map(function ($item) use ($manager) { + $plugin = $manager->get($item['name']); + + if ($plugin) { + $item['installed'] = $plugin->version; + $item['can_update'] = Comparator::greaterThan($item['version'], $item['installed']); + } else { + $item['installed'] = false; + } + + $requirements = Arr::get($item, 'require', []); + unset($item['require']); + $item['dependencies'] = [ + 'all' => $requirements, + 'unsatisfied' => $manager->getUnsatisfied(new Plugin('', $item)), + ]; + + return $item; + }); + + return $plugins; + } + + public function download(Request $request, PluginManager $manager, Unzip $unzip) + { + $name = $request->input('name'); + $plugins = $this->fetch(); + $metadata = $plugins->firstWhere('name', $name); + + if (!$metadata) { + return json(trans('admin.plugins.market.non-existent', ['plugin' => $name]), 1); + } + + $fakePlugin = new Plugin('', $metadata); + $unsatisfied = $manager->getUnsatisfied($fakePlugin); + $conflicts = $manager->getConflicts($fakePlugin); + if ($unsatisfied->isNotEmpty() || $conflicts->isNotEmpty()) { + $reason = $manager->formatUnresolved($unsatisfied, $conflicts); + + return json(trans('admin.plugins.market.unresolved'), 1, compact('reason')); + } + + $path = tempnam(sys_get_temp_dir(), $name); + $response = Http::withOptions([ + 'sink' => $path, + 'verify' => CaBundle::getSystemCaRootBundlePath(), + ])->get($metadata['dist']['url']); + + if ($response->ok()) { + $unzip->extract($path, $manager->getPluginsDirs()->first()); + + return json(trans('admin.plugins.market.install-success'), 0); + } else { + return json(trans('admin.download.errors.download', ['error' => $response->status()]), 1); + } + } + + protected function fetch(): Collection + { + $lang = in_array(app()->getLocale(), config('plugins.locales')) + ? app()->getLocale() + : config('app.fallback_locale'); + + $plugins = collect(explode(',', config('plugins.registry'))) + ->map(function ($registry) use ($lang) { + $registry = str_replace('{lang}', $lang, $registry); + $response = Http::withOptions([ + 'verify' => CaBundle::getSystemCaRootBundlePath(), + ])->get(trim($registry)); + + if ($response->ok()) { + return $response->json()['packages']; + } else { + throw new Exception(trans('admin.plugins.market.connection-error', ['error' => $response->status()])); + } + }) + ->flatten(1); + + return $plugins; + } +} diff --git a/app/Http/Controllers/NotificationsController.php b/app/Http/Controllers/NotificationsController.php new file mode 100755 index 0000000..8b7d35e --- /dev/null +++ b/app/Http/Controllers/NotificationsController.php @@ -0,0 +1,72 @@ +validate([ + 'receiver' => 'required|in:all,normal,uid,email', + 'uid' => 'required_if:receiver,uid|nullable|integer|exists:users', + 'email' => 'required_if:receiver,email|nullable|email|exists:users', + 'title' => 'required|max:20', + 'content' => 'string|nullable', + ]); + + $notification = new Notifications\SiteMessage($data['title'], $data['content']); + + switch ($data['receiver']) { + case 'all': + $users = User::all(); + break; + case 'normal': + $users = User::where('permission', User::NORMAL)->get(); + break; + case 'uid': + $users = User::where('uid', $data['uid'])->get(); + break; + case 'email': + $users = User::where('email', $data['email'])->get(); + break; + } + Notification::send($users, $notification); + + session(['sentResult' => trans('admin.notifications.send.success')]); + + return redirect('/admin'); + } + + public function all() + { + return auth()->user() + ->unreadNotifications + ->map(fn ($notification) => [ + 'id' => $notification->id, + 'title' => $notification->data['title'], + ]); + } + + public function read($id) + { + $notification = auth() + ->user() + ->unreadNotifications + ->first(fn ($notification) => $notification->id === $id); + $notification->markAsRead(); + + $converter = new GithubFlavoredMarkdownConverter(); + + return [ + 'title' => $notification->data['title'], + 'content' => $converter->convertToHtml($notification->data['content'] ?? '')->getContent(), + 'time' => $notification->created_at->toDateTimeString(), + ]; + } +} diff --git a/app/Http/Controllers/OptionsController.php b/app/Http/Controllers/OptionsController.php new file mode 100755 index 0000000..a308e0c --- /dev/null +++ b/app/Http/Controllers/OptionsController.php @@ -0,0 +1,266 @@ +text('home_pic_url')->hint(); + + $form->text('favicon_url')->hint()->description(); + + $form->checkbox('transparent_navbar')->label(); + + $form->checkbox('hide_intro')->label(); + + $form->checkbox('fixed_bg')->label(); + + $form->select('copyright_prefer') + ->option('0', 'Powered with ❤ by Blessing Skin Server.') + ->option('1', 'Powered by Blessing Skin Server.') + ->option('2', 'Proudly powered by Blessing Skin Server.') + ->option('3', '由 Blessing Skin Server 强力驱动。') + ->option('4', '采用 Blessing Skin Server 搭建。') + ->option('5', '使用 Blessing Skin Server 稳定运行。') + ->option('6', '自豪地采用 Blessing Skin Server。') + ->description(); + + $form->textarea('copyright_text')->rows(6)->description(); + })->handle(function () { + Option::set('copyright_prefer_'.config('app.locale'), request('copyright_prefer')); + Option::set('copyright_text_'.config('app.locale'), request('copyright_text')); + }); + + $customJsCss = Option::form('customJsCss', OptionForm::AUTO_DETECT, function ($form) { + $form->textarea('custom_css', 'CSS')->rows(6); + $form->textarea('custom_js', 'JavaScript')->rows(6); + })->addMessage()->handle(); + + if ($request->isMethod('post') && $request->input('action') === 'color') { + $navbar = $request->input('navbar'); + if ($navbar) { + option(['navbar_color' => $navbar]); + } + + $sidebar = $request->input('sidebar'); + if ($sidebar) { + option(['sidebar_color' => $sidebar]); + } + } + + return view('admin.customize', [ + 'colors' => [ + 'navbar' => [ + 'primary', 'secondary', 'success', 'danger', 'indigo', + 'purple', 'pink', 'teal', 'cyan', 'dark', 'gray', + 'fuchsia', 'maroon', 'olive', 'navy', + 'lime', 'light', 'warning', 'white', 'orange', + ], + 'sidebar' => [ + 'primary', 'warning', 'info', 'danger', 'success', 'indigo', + 'navy', 'purple', 'fuchsia', 'pink', 'maroon', 'orange', + 'lime', 'teal', 'olive', + ], + ], + 'forms' => [ + 'homepage' => $homepage, + 'custom_js_css' => $customJsCss, + ], + 'extra' => [ + 'navbar' => option('navbar_color'), + 'sidebar' => option('sidebar_color'), + ], + ]); + } + + public function score() + { + $rate = Option::form('rate', OptionForm::AUTO_DETECT, function ($form) { + $form->group('score_per_storage')->text('score_per_storage')->addon(); + + $form->group('private_score_per_storage') + ->text('private_score_per_storage')->addon()->hint(); + + $form->group('score_per_closet_item') + ->text('score_per_closet_item')->addon(); + + $form->checkbox('return_score')->label(); + + $form->group('score_per_player')->text('score_per_player')->addon(); + + $form->text('user_initial_score'); + })->handle(); + + $report = Option::form('report', OptionForm::AUTO_DETECT, function ($form) { + $form->text('reporter_score_modification')->description(); + + $form->text('reporter_reward_score'); + })->handle(); + + $sign = Option::form('sign', OptionForm::AUTO_DETECT, function ($form) { + $form->group('sign_score') + ->text('sign_score_from')->addon(trans('options.sign.sign_score.addon1')) + ->text('sign_score_to')->addon(trans('options.sign.sign_score.addon2')); + + $form->group('sign_gap_time')->text('sign_gap_time')->addon(); + + $form->checkbox('sign_after_zero')->label()->hint(); + })->after(function () { + $sign_score = request('sign_score_from').','.request('sign_score_to'); + Option::set('sign_score', $sign_score); + })->with([ + 'sign_score_from' => @explode(',', option('sign_score'))[0], + 'sign_score_to' => @explode(',', option('sign_score'))[1], + ])->handle(); + + $sharing = Option::form('sharing', OptionForm::AUTO_DETECT, function ($form) { + $form->group('score_award_per_texture') + ->text('score_award_per_texture') + ->addon(trans('general.user.score')); + $form->checkbox('take_back_scores_after_deletion')->label(); + $form->group('score_award_per_like') + ->text('score_award_per_like') + ->addon(trans('general.user.score')); + })->handle(); + + return view('admin.score', ['forms' => compact('rate', 'report', 'sign', 'sharing')]); + } + + public function options() + { + $general = Option::form('general', OptionForm::AUTO_DETECT, function ($form) { + $form->text('site_name'); + $form->text('site_description')->description(); + + $form->text('site_url') + ->hint() + ->format(function ($url) { + if (Str::endsWith($url, '/')) { + $url = substr($url, 0, -1); + } + + if (Str::endsWith($url, '/index.php')) { + $url = substr($url, 0, -10); + } + + return $url; + }); + + $form->checkbox('register_with_player_name')->label(); + $form->checkbox('require_verification')->label(); + + $form->text('regs_per_ip'); + + $form->group('max_upload_file_size') + ->text('max_upload_file_size')->addon('KB') + ->hint(trans('options.general.max_upload_file_size.hint', ['size' => ini_get('upload_max_filesize')])); + + $form->select('player_name_rule') + ->option('official', trans('options.general.player_name_rule.official')) + ->option('cjk', trans('options.general.player_name_rule.cjk')) + ->option('utf8', trans('options.general.player_name_rule.utf8')) + ->option('custom', trans('options.general.player_name_rule.custom')); + + $form->text('custom_player_name_regexp')->hint()->placeholder(); + + $form->group('player_name_length') + ->text('player_name_length_min') + ->addon('~') + ->text('player_name_length_max') + ->addon(trans('options.general.player_name_length.suffix')); + + $form->checkbox('auto_del_invalid_texture')->label()->hint(); + + $form->checkbox('allow_downloading_texture')->label(); + + $form->select('status_code_for_private') + ->option('403', '403 Forbidden') + ->option('404', '404 Not Found'); + + $form->text('texture_name_regexp')->hint()->placeholder(); + + $form->textarea('content_policy')->rows(3)->description(); + })->handle(function () { + Option::set('site_name_'.config('app.locale'), request('site_name')); + Option::set('site_description_'.config('app.locale'), request('site_description')); + Option::set('content_policy_'.config('app.locale'), request('content_policy')); + }); + + $announ = Option::form('announ', OptionForm::AUTO_DETECT, function ($form) { + $form->textarea('announcement')->rows(10)->description(); + })->renderWithoutTable()->handle(function () { + Option::set('announcement_'.config('app.locale'), request('announcement')); + }); + + $meta = Option::form('meta', OptionForm::AUTO_DETECT, function ($form) { + $form->text('meta_keywords')->hint(); + $form->text('meta_description')->hint(); + $form->textarea('meta_extras')->rows(6); + })->handle(); + + $recaptcha = Option::form('recaptcha', 'reCAPTCHA', function ($form) { + $form->text('recaptcha_sitekey', 'sitekey'); + $form->text('recaptcha_secretkey', 'secretkey'); + $form->checkbox('recaptcha_invisible')->label(); + })->handle(); + + return view('admin.options') + ->with('forms', compact('general', 'announ', 'meta', 'recaptcha')); + } + + public function resource(Request $request) + { + $resources = Option::form('resources', OptionForm::AUTO_DETECT, function ($form) { + $form->checkbox('force_ssl')->label()->hint(); + $form->checkbox('auto_detect_asset_url')->label()->description(); + + $form->text('cache_expire_time')->hint(OptionForm::AUTO_DETECT); + $form->text('cdn_address') + ->hint(OptionForm::AUTO_DETECT) + ->description(OptionForm::AUTO_DETECT); + }) + ->type('primary') + ->hint(OptionForm::AUTO_DETECT) + ->after(function () { + $cdnAddress = request('cdn_address'); + if ($cdnAddress == null) { + $cdnAddress = ''; + } + if (Str::endsWith($cdnAddress, '/')) { + $cdnAddress = substr($cdnAddress, 0, -1); + } + Option::set('cdn_address', $cdnAddress); + }) + ->handle(); + + $cache = Option::form('cache', OptionForm::AUTO_DETECT, function ($form) { + $form->checkbox('enable_avatar_cache')->label(); + $form->checkbox('enable_preview_cache')->label(); + }) + ->type('warning') + ->addButton([ + 'text' => trans('options.cache.clear'), + 'type' => 'a', + 'class' => 'float-right', + 'style' => 'warning', + 'href' => '?clear-cache', + ]) + ->addMessage(trans('options.cache.driver', ['driver' => config('cache.default')]), 'info'); + + if ($request->has('clear-cache')) { + Cache::flush(); + $cache->addMessage(trans('options.cache.cleared'), 'success'); + } + $cache->handle(); + + return view('admin.resource')->with('forms', compact('resources', 'cache')); + } +} diff --git a/app/Http/Controllers/PlayerController.php b/app/Http/Controllers/PlayerController.php new file mode 100755 index 0000000..057ecb2 --- /dev/null +++ b/app/Http/Controllers/PlayerController.php @@ -0,0 +1,260 @@ +middleware(function (Request $request, $next) { + /** @var Player */ + $player = $request->route('player'); + if ($player->user->isNot($request->user())) { + return json(trans('admin.players.no-permission'), 1) + ->setStatusCode(403); + } + + return $next($request); + }, [ + 'only' => ['delete', 'rename', 'setTexture', 'clearTexture'], + ]); + } + + public function index(Filter $filter) + { + $grid = [ + 'layout' => [ + ['md-6', 'md-6'], + ], + 'widgets' => [ + [ + [ + 'user.widgets.players.list', + 'user.widgets.players.notice', + ], + ['shared.previewer'], + ], + ], + ]; + $grid = $filter->apply('grid:user.player', $grid); + + /** @var User */ + $user = auth()->user(); + + return view('user.player') + ->with('grid', $grid) + ->with('extra', [ + 'count' => $user->players()->count(), + 'rule' => trans('user.player.player-name-rule.'.option('player_name_rule')), + 'length' => trans( + 'user.player.player-name-length', + ['min' => option('player_name_length_min'), 'max' => option('player_name_length_max')] + ), + 'score' => auth()->user()->score, + 'cost' => (int) option('score_per_player'), + ]); + } + + public function list() + { + return Auth::user()->players; + } + + public function add(Request $request, Dispatcher $dispatcher, Filter $filter) + { + /** @var User */ + $user = Auth::user(); + + $name = $request->validate([ + 'name' => [ + 'required', + new Rules\PlayerName(), + 'min:'.option('player_name_length_min'), + 'max:'.option('player_name_length_max'), + 'unique:players', + ], + ])['name']; + $name = $filter->apply('new_player_name', $name); + + $dispatcher->dispatch('player.add.attempt', [$name, $user]); + + $can = $filter->apply('can_add_player', true, [$name]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + if ($user->score < (int) option('score_per_player')) { + return json(trans('user.player.add.lack-score'), 7); + } + + $dispatcher->dispatch('player.adding', [$name, $user]); + event(new PlayerWillBeAdded($name)); + + $player = new Player(); + $player->uid = $user->uid; + $player->name = $name; + $player->tid_skin = 0; + $player->tid_cape = 0; + $player->save(); + + $user->score -= (int) option('score_per_player'); + $user->save(); + + $dispatcher->dispatch('player.added', [$player, $user]); + event(new PlayerWasAdded($player)); + + return json(trans('user.player.add.success', ['name' => $name]), 0, $player->toArray()); + } + + public function delete( + Dispatcher $dispatcher, + Filter $filter, + Player $player + ) { + /** @var User */ + $user = auth()->user(); + $playerName = $player->name; + + $dispatcher->dispatch('player.delete.attempt', [$player, $user]); + + $can = $filter->apply('can_delete_player', true, [$player]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $dispatcher->dispatch('player.deleting', [$player, $user]); + event(new PlayerWillBeDeleted($player)); + + $player->delete(); + + if (option('return_score')) { + $user->score += (int) option('score_per_player'); + $user->save(); + } + + $dispatcher->dispatch('player.deleted', [$player, $user]); + event(new PlayerWasDeleted($playerName)); + + return json(trans('user.player.delete.success', ['name' => $playerName]), 0); + } + + public function rename( + Request $request, + Dispatcher $dispatcher, + Filter $filter, + Player $player + ) { + $name = $request->validate([ + 'name' => [ + 'required', + new Rules\PlayerName(), + 'min:'.option('player_name_length_min'), + 'max:'.option('player_name_length_max'), + Rule::unique('players')->ignoreModel($player), + ], + ])['name']; + $name = $filter->apply('new_player_name', $name); + + $dispatcher->dispatch('player.renaming', [$player, $name]); + + $can = $filter->apply('can_rename_player', true, [$player, $name]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $old = $player->replicate(); + $player->name = $name; + $player->save(); + + $dispatcher->dispatch('player.renamed', [$player, $old]); + + return json( + trans('user.player.rename.success', ['old' => $old->name, 'new' => $name]), + 0, + $player->toArray() + ); + } + + public function setTexture( + Request $request, + Dispatcher $dispatcher, + Filter $filter, + Player $player + ) { + /** @var User */ + $user = auth()->user(); + + foreach (['skin', 'cape'] as $type) { + $tid = $request->input($type); + + $can = $filter->apply('can_set_texture', true, [$player, $type, $tid]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + if ($tid) { + $texture = Texture::find($tid); + if (empty($texture)) { + return json(trans('skinlib.non-existent'), 1); + } + + if ($user->closet()->where('texture_tid', $tid)->doesntExist()) { + return json(trans('user.closet.remove.non-existent'), 1); + } + + $dispatcher->dispatch('player.texture.updating', [$player, $texture]); + + $field = "tid_$type"; + $player->$field = $tid; + $player->save(); + + $dispatcher->dispatch('player.texture.updated', [$player, $texture]); + } + } + + return json(trans('user.player.set.success', ['name' => $player->name]), 0, $player->toArray()); + } + + public function clearTexture( + Request $request, + Dispatcher $dispatcher, + Filter $filter, + Player $player + ) { + $types = $request->input('type', []); + + foreach (['skin', 'cape'] as $type) { + $can = $filter->apply('can_clear_texture', true, [$player, $type]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + if ($request->has($type) || in_array($type, $types)) { + $dispatcher->dispatch('player.texture.resetting', [$player, $type]); + + $field = "tid_$type"; + $player->$field = 0; + $player->save(); + + $dispatcher->dispatch('player.texture.reset', [$player, $type]); + } + } + + return json(trans('user.player.clear.success', ['name' => $player->name]), 0, $player->toArray()); + } +} diff --git a/app/Http/Controllers/PlayersManagementController.php b/app/Http/Controllers/PlayersManagementController.php new file mode 100755 index 0000000..aa4faf0 --- /dev/null +++ b/app/Http/Controllers/PlayersManagementController.php @@ -0,0 +1,136 @@ +middleware(function (Request $request, $next) { + /** @var Player */ + $player = $request->route('player'); + $owner = $player->user; + + /** @var User */ + $currentUser = $request->user(); + + if ( + $owner->uid !== $currentUser->uid && + $owner->permission >= $currentUser->permission + ) { + return json(trans('admin.players.no-permission'), 1) + ->setStatusCode(403); + } + + return $next($request); + })->except(['list']); + } + + public function list(Request $request) + { + $query = $request->query('q'); + + return Player::usingSearchString($query)->paginate(10); + } + + public function name( + Player $player, + Request $request, + Dispatcher $dispatcher + ) { + $name = $request->validate([ + 'player_name' => [ + 'required', + new Rules\PlayerName(), + 'min:'.option('player_name_length_min'), + 'max:'.option('player_name_length_max'), + 'unique:players,name', + ], + ])['player_name']; + + $dispatcher->dispatch('player.renaming', [$player, $name]); + + $oldName = $player->name; + $player->name = $name; + $player->save(); + + $dispatcher->dispatch('player.renamed', [$player, $oldName]); + + return json(trans('admin.players.name.success', ['player' => $player->name]), 0); + } + + public function owner( + Player $player, + Request $request, + Dispatcher $dispatcher + ) { + $uid = $request->validate(['uid' => 'required|integer'])['uid']; + + $dispatcher->dispatch('player.owner.updating', [$player, $uid]); + + /** @var User */ + $user = User::find($request->uid); + if (empty($user)) { + return json(trans('admin.users.operations.non-existent'), 1); + } + + $player->uid = $uid; + $player->save(); + + $dispatcher->dispatch('player.owner.updated', [$player, $user]); + + return json(trans('admin.players.owner.success', [ + 'player' => $player->name, + 'user' => $user->nickname, + ]), 0); + } + + public function texture( + Player $player, + Request $request, + Dispatcher $dispatcher + ) { + $data = $request->validate([ + 'tid' => 'required|integer', + 'type' => ['required', Rule::in(['skin', 'cape'])], + ]); + $tid = (int) $data['tid']; + $type = $data['type']; + + $dispatcher->dispatch('player.texture.updating', [$player, $type, $tid]); + + if (Texture::where('tid', $tid)->doesntExist() && $tid !== 0) { + return json(trans('admin.players.textures.non-existent', ['tid' => $tid]), 1); + } + + $field = 'tid_'.$type; + $previousTid = $player->$field; + $player->$field = $tid; + $player->save(); + + $dispatcher->dispatch('player.texture.updated', [$player, $type, $previousTid]); + + return json(trans('admin.players.textures.success', ['player' => $player->name]), 0); + } + + public function delete( + Player $player, + Dispatcher $dispatcher + ) { + $dispatcher->dispatch('player.deleting', [$player]); + + $player->delete(); + + $dispatcher->dispatch('player.deleted', [$player]); + + return json(trans('admin.players.delete.success'), 0); + } +} diff --git a/app/Http/Controllers/PluginController.php b/app/Http/Controllers/PluginController.php new file mode 100755 index 0000000..d219e58 --- /dev/null +++ b/app/Http/Controllers/PluginController.php @@ -0,0 +1,140 @@ +get($name); + if ($plugin && $plugin->isEnabled()) { + if ($plugin->hasConfigClass()) { + return app()->call($plugin->getConfigClass().'@render'); + } elseif ($plugin->hasConfigView()) { + return $plugin->getConfigView(); + } else { + return abort(404, trans('admin.plugins.operations.no-config-notice')); + } + } else { + return abort(404, trans('admin.plugins.operations.no-config-notice')); + } + } + + public function readme(PluginManager $plugins, $name) + { + $plugin = $plugins->get($name); + if (empty($plugin)) { + return abort(404, trans('admin.plugins.operations.no-readme-notice')); + } + + $readmePath = $plugin->getReadme(); + if (empty($readmePath)) { + return abort(404, trans('admin.plugins.operations.no-readme-notice')); + } + + $title = trans($plugin->title); + $path = $plugin->getPath().'/'.$readmePath; + $converter = new GithubFlavoredMarkdownConverter(); + $content = $converter->convertToHtml(file_get_contents($path)); + + return view('admin.plugin.readme', compact('content', 'title')); + } + + public function manage(Request $request, PluginManager $plugins) + { + $name = $request->input('name'); + $plugin = $plugins->get($name); + + if ($plugin) { + // Pass the plugin title through the translator. + $plugin->title = trans($plugin->title); + + switch ($request->get('action')) { + case 'enable': + $result = $plugins->enable($name); + + if ($result === true) { + return json(trans('admin.plugins.operations.enabled', ['plugin' => $plugin->title]), 0); + } else { + $reason = $plugins->formatUnresolved($result['unsatisfied'], $result['conflicts']); + + return json(trans('admin.plugins.operations.unsatisfied.notice'), 1, compact('reason')); + } + + // no break + case 'disable': + $plugins->disable($name); + + return json(trans('admin.plugins.operations.disabled', ['plugin' => $plugin->title]), 0); + + case 'delete': + $plugins->delete($name); + + return json(trans('admin.plugins.operations.deleted'), 0); + + default: + return json(trans('admin.invalid-action'), 1); + } + } else { + return json(trans('admin.plugins.operations.not-found'), 1); + } + } + + public function getPluginData(PluginManager $plugins) + { + return $plugins->all() + ->map(function (Plugin $plugin) { + return [ + 'name' => $plugin->name, + 'title' => trans($plugin->title), + 'description' => trans($plugin->description ?? ''), + 'version' => $plugin->version, + 'enabled' => $plugin->isEnabled(), + 'readme' => (bool) $plugin->getReadme(), + 'config' => $plugin->hasConfig(), + 'icon' => array_merge( + ['fa' => 'plug', 'faType' => 'fas', 'bg' => 'navy'], + $plugin->getManifestAttr('enchants.icon', []) + ), + ]; + }) + ->values(); + } + + public function upload(Request $request, PluginManager $manager, Unzip $unzip) + { + $request->validate(['file' => 'required|file|mimetypes:application/zip']); + + $path = $request->file('file')->getPathname(); + $unzip->extract($path, $manager->getPluginsDirs()->first()); + + return json(trans('admin.plugins.market.install-success'), 0); + } + + public function wget(Request $request, PluginManager $manager, Unzip $unzip) + { + $data = $request->validate(['url' => 'required|url']); + + $path = tempnam(sys_get_temp_dir(), 'wget-plugin'); + $response = Http::withOptions([ + 'sink' => $path, + 'verify' => CaBundle::getSystemCaRootBundlePath(), + ])->get($data['url']); + + if ($response->ok()) { + $unzip->extract($path, $manager->getPluginsDirs()->first()); + + return json(trans('admin.plugins.market.install-success'), 0); + } else { + return json(trans('admin.download.errors.download', ['error' => $response->status()]), 1); + } + } +} diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php new file mode 100755 index 0000000..6cb1327 --- /dev/null +++ b/app/Http/Controllers/ReportController.php @@ -0,0 +1,170 @@ +validate([ + 'tid' => 'required|exists:textures', + 'reason' => 'required', + ]); + /** @var User */ + $reporter = auth()->user(); + $tid = $data['tid']; + $reason = $data['reason']; + + $can = $filter->apply('user_can_report', true, [$tid, $reason, $reporter]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $dispatcher->dispatch('report.submitting', [$tid, $reason, $reporter]); + + if (Report::where('reporter', $reporter->uid)->where('tid', $tid)->count() > 0) { + return json(trans('skinlib.report.duplicate'), 1); + } + + $score = option('reporter_score_modification', 0); + if ($score < 0 && $reporter->score < -$score) { + return json(trans('skinlib.upload.lack-score'), 1); + } + $reporter->score += $score; + $reporter->save(); + + $report = new Report(); + $report->tid = $tid; + $report->uploader = Texture::find($tid)->uploader; + $report->reporter = $reporter->uid; + $report->reason = $reason; + $report->status = Report::PENDING; + $report->save(); + + $dispatcher->dispatch('report.submitted', [$report]); + + return json(trans('skinlib.report.success'), 0); + } + + public function track() + { + $reports = Report::where('reporter', auth()->id()) + ->orderBy('report_at', 'desc') + ->paginate(10); + + return view('user.report', ['reports' => $reports]); + } + + public function manage(Request $request) + { + $q = $request->input('q'); + + return Report::usingSearchString($q) + ->with(['texture', 'textureUploader', 'informer']) + ->paginate(9); + } + + public function review( + Report $report, + Request $request, + Dispatcher $dispatcher + ) { + $data = $request->validate([ + 'action' => ['required', Rule::in(['delete', 'ban', 'reject'])], + ]); + $action = $data['action']; + + $dispatcher->dispatch('report.reviewing', [$report, $action]); + + if ($action == 'reject') { + if ( + $report->informer && + ($score = option('reporter_score_modification', 0)) > 0 && + $report->status == Report::PENDING + ) { + $report->informer->score -= $score; + $report->informer->save(); + } + $report->status = Report::REJECTED; + $report->save(); + + $dispatcher->dispatch('report.rejected', [$report]); + + return json(trans('general.op-success'), 0, ['status' => Report::REJECTED]); + } + + switch ($action) { + case 'delete': + /** @var Texture */ + $texture = $report->texture; + if ($texture) { + $dispatcher->dispatch('texture.deleting', [$texture]); + Storage::disk('textures')->delete($texture->hash); + $texture->delete(); + $dispatcher->dispatch('texture.deleted', [$texture]); + } else { + // The texture has been deleted by its uploader + // We will return the score, but will not give the informer any reward + self::returnScore($report); + $report->status = Report::RESOLVED; + $report->save(); + + $dispatcher->dispatch('report.resolved', [$report, $action]); + + return json(trans('general.texture-deleted'), 0, ['status' => Report::RESOLVED]); + } + break; + case 'ban': + $uploader = User::find($report->uploader); + if (!$uploader) { + return json(trans('admin.users.operations.non-existent'), 1); + } + if (auth()->user()->permission <= $uploader->permission) { + return json(trans('admin.users.operations.no-permission'), 1); + } + $uploader->permission = User::BANNED; + $uploader->save(); + $dispatcher->dispatch('user.banned', [$uploader]); + break; + } + + self::returnScore($report); + self::giveAward($report); + $report->status = Report::RESOLVED; + $report->save(); + + $dispatcher->dispatch('report.resolved', [$report, $action]); + + return json(trans('general.op-success'), 0, ['status' => Report::RESOLVED]); + } + + public static function returnScore($report) + { + if ( + $report->status == Report::PENDING && + ($score = option('reporter_score_modification', 0)) < 0 && + $report->informer + ) { + $report->informer->score -= $score; + $report->informer->save(); + } + } + + public static function giveAward($report) + { + if ($report->status == Report::PENDING && $report->informer) { + $report->informer->score += option('reporter_reward_score', 0); + $report->informer->save(); + } + } +} diff --git a/app/Http/Controllers/SetupController.php b/app/Http/Controllers/SetupController.php new file mode 100755 index 0000000..6092fc6 --- /dev/null +++ b/app/Http/Controllers/SetupController.php @@ -0,0 +1,157 @@ +isMethod('get')) { + try { + $connection->getPdo(); + + return redirect('setup/info'); + } catch (\Exception $e) { + return view('setup.wizard.database', [ + 'host' => env('DB_HOST'), + 'port' => env('DB_PORT'), + 'username' => env('DB_USERNAME'), + 'password' => env('DB_PASSWORD'), + 'database' => env('DB_DATABASE'), + 'prefix' => env('DB_PREFIX'), + ]); + } + } + + config([ + 'database.connections.temp.driver' => $request->input('type'), + 'database.connections.temp.host' => $request->input('host'), + 'database.connections.temp.port' => $request->input('port'), + 'database.connections.temp.username' => $request->input('username'), + 'database.connections.temp.password' => $request->input('password'), + 'database.connections.temp.database' => $request->input('db'), + 'database.connections.temp.prefix' => $request->input('prefix'), + ]); + + try { + $manager->connection('temp')->getPdo(); + } catch (\Exception $e) { + $msg = $e->getMessage(); + $type = Arr::get([ + 'mysql' => 'MySQL/MariaDB', + 'sqlite' => 'SQLite', + 'pgsql' => 'PostgreSQL', + ], $request->input('type'), ''); + + throw new PrettyPageException(trans('setup.database.connection-error', compact('msg', 'type')), $e->getCode()); + } + + $content = $filesystem->get(base_path('.env')); + $content = preg_replace( + '/DB_CONNECTION.+/', + 'DB_CONNECTION='.$request->input('type', ''), + $content + ); + $content = preg_replace( + '/DB_HOST.+/', + 'DB_HOST='.$request->input('host', ''), + $content + ); + $content = preg_replace( + '/DB_PORT.+/', + 'DB_PORT='.$request->input('port', ''), + $content + ); + $content = preg_replace( + '/DB_DATABASE.+/', + 'DB_DATABASE='.$request->input('db', ''), + $content + ); + $content = preg_replace( + '/DB_USERNAME.+/', + 'DB_USERNAME='.$request->input('username', ''), + $content + ); + $content = preg_replace( + '/DB_PASSWORD.+/', + 'DB_PASSWORD='.$request->input('password', ''), + $content + ); + $content = preg_replace( + '/DB_PREFIX.+/', + 'DB_PREFIX='.$request->input('prefix', ''), + $content + ); + $filesystem->put(base_path('.env'), $content); + + return redirect('setup/info'); + } + + public function finish(Request $request, Filesystem $filesystem, Artisan $artisan) + { + $data = $request->validate([ + 'email' => 'required|email', + 'nickname' => 'required', + 'password' => 'required|min:8|max:32|confirmed', + 'site_name' => 'required', + ]); + + $artisan->call('passport:keys', ['--no-interaction' => true]); + + // Create tables + $artisan->call('migrate', [ + '--force' => true, + '--path' => [ + 'database/migrations', + 'vendor/laravel/passport/database/migrations', + ], + ]); + + $siteUrl = url('/'); + if (Str::endsWith($siteUrl, '/index.php')) { + $siteUrl = substr($siteUrl, 0, -10); // @codeCoverageIgnore + } + option([ + 'site_name' => $request->input('site_name'), + 'site_url' => $siteUrl, + ]); + + $whip = new Whip(); + $ip = $whip->getValidIpAddress(); + + // Register super admin + $user = new User(); + $user->email = $data['email']; + $user->nickname = $data['nickname']; + $user->score = option('user_initial_score'); + $user->avatar = 0; + $user->password = app('cipher')->hash($data['password'], config('secure.salt')); + $user->ip = $ip; + $user->permission = User::SUPER_ADMIN; + $user->register_at = Carbon::now(); + $user->last_sign_at = Carbon::now()->subDay(); + $user->verified = true; + + $user->save(); + + $filesystem->put(storage_path('install.lock'), ''); + + return view('setup.wizard.finish'); + } +} diff --git a/app/Http/Controllers/SkinlibController.php b/app/Http/Controllers/SkinlibController.php new file mode 100755 index 0000000..454c428 --- /dev/null +++ b/app/Http/Controllers/SkinlibController.php @@ -0,0 +1,441 @@ +middleware(function (Request $request, $next) { + /** @var User */ + $user = $request->user(); + /** @var Texture */ + $texture = $request->route('texture'); + + if ($texture->uploader != $user->uid && !$user->isAdmin()) { + return json(trans('skinlib.no-permission'), 1) + ->setStatusCode(403); + } + + return $next($request); + })->only(['rename', 'privacy', 'type', 'delete']); + + $this->middleware(function (Request $request, $next) { + /** @var User */ + $user = $request->user(); + /** @var Texture */ + $texture = $request->route('texture'); + + if (!$texture->public) { + if (!Auth::check() || ($user->uid != $texture->uploader && !$user->isAdmin())) { + $statusCode = (int) option('status_code_for_private'); + if ($statusCode === 404) { + abort($statusCode, trans('skinlib.show.deleted')); + } else { + abort(403, trans('skinlib.show.private')); + } + } + } + + return $next($request); + })->only(['show', 'info']); + } + + public function library(Request $request) + { + $user = Auth::user(); + + // Available filters: skin, steve, alex, cape + $type = $request->input('filter', 'skin'); + $uploader = $request->input('uploader'); + $keyword = $request->input('keyword'); + $sort = $request->input('sort', 'time'); + $sortBy = $sort == 'time' ? 'upload_at' : $sort; + + return Texture::orderBy($sortBy, 'desc') + ->when( + $type === 'skin', + fn (Builder $query) => $query->whereIn('type', ['steve', 'alex']), + fn (Builder $query) => $query->where('type', $type), + ) + ->when($keyword, fn (Builder $query, $keyword) => $query->like('name', $keyword)) + ->when($uploader, fn (Builder $query, $uploader) => $query->where('uploader', $uploader)) + ->when($user, function (Builder $query, User $user) { + if (!$user->isAdmin()) { + // use closure-style `where` clause to lift up SQL priority + return $query->where(function (Builder $query) use ($user) { + $query + ->where('public', true) + ->orWhere('uploader', $user->uid); + }); + } + }, function (Builder $query) { + // show public textures only to anonymous visitors + return $query->where('public', true); + }) + ->join('users', 'uid', 'uploader') + ->select(['tid', 'name', 'type', 'uploader', 'public', 'likes', 'nickname']) + ->paginate(20); + } + + public function show(Filter $filter, Texture $texture) + { + /** @var User */ + $user = Auth::user(); + /** @var FilesystemAdapter */ + $disk = Storage::disk('textures'); + + if ($disk->missing($texture->hash)) { + if (option('auto_del_invalid_texture')) { + $texture->delete(); + } + abort(404, trans('skinlib.show.deleted')); + } + + $badges = []; + $uploader = $texture->owner; + if ($uploader) { + if ($uploader->isAdmin()) { + $badges[] = ['text' => 'STAFF', 'color' => 'primary']; + } + + $badges = $filter->apply('user_badges', $badges, [$uploader]); + } + + $grid = [ + 'layout' => [ + ['md-8', 'md-4'], + ], + 'widgets' => [ + [ + ['shared.previewer'], + ['skinlib.widgets.show.side'], + ], + ], + ]; + $grid = $filter->apply('grid:skinlib.show', $grid); + + return view('skinlib.show') + ->with('texture', $texture) + ->with('grid', $grid) + ->with('extra', [ + 'download' => option('allow_downloading_texture'), + 'currentUid' => $user ? $user->uid : 0, + 'admin' => $user && $user->isAdmin(), + 'inCloset' => $user && $user->closet()->where('tid', $texture->tid)->count() > 0, + 'uploaderExists' => (bool) $uploader, + 'nickname' => optional($uploader)->nickname ?? trans('general.unexistent-user'), + 'report' => intval(option('reporter_score_modification', 0)), + 'badges' => $badges, + ]); + } + + public function info(Texture $texture) + { + return $texture; + } + + public function upload(Filter $filter) + { + $grid = [ + 'layout' => [ + ['md-6', 'md-6'], + ], + 'widgets' => [ + [ + ['skinlib.widgets.upload.input'], + ['shared.previewer'], + ], + ], + ]; + $grid = $filter->apply('grid:skinlib.upload', $grid); + + $converter = new GithubFlavoredMarkdownConverter(); + + return view('skinlib.upload') + ->with('grid', $grid) + ->with('extra', [ + 'rule' => ($regexp = option('texture_name_regexp')) + ? trans('skinlib.upload.name-rule-regexp', compact('regexp')) + : trans('skinlib.upload.name-rule'), + 'privacyNotice' => trans( + 'skinlib.upload.private-score-notice', + ['score' => option('private_score_per_storage')] + ), + 'score' => (int) auth()->user()->score, + 'scorePublic' => (int) option('score_per_storage'), + 'scorePrivate' => (int) option('private_score_per_storage'), + 'closetItemCost' => (int) option('score_per_closet_item'), + 'award' => (int) option('score_award_per_texture'), + 'contentPolicy' => $converter->convertToHtml(option_localized('content_policy'))->getContent(), + ]); + } + + public function handleUpload( + Request $request, + Filter $filter, + Dispatcher $dispatcher + ) { + $file = $request->file('file'); + if ($file && !$file->isValid()) { + Log::error($file->getErrorMessage()); + } + + $data = $request->validate([ + 'name' => [ + 'required', + option('texture_name_regexp') ? 'regex:'.option('texture_name_regexp') : 'string', + ], + 'file' => 'required|mimes:png|max:'.option('max_upload_file_size'), + 'type' => ['required', Rule::in(['steve', 'alex', 'cape'])], + 'public' => 'required|boolean', + ]); + + /** @var UploadedFile */ + $file = $filter->apply('uploaded_texture_file', $file); + + $name = $data['name']; + $name = $filter->apply('uploaded_texture_name', $name, [$file]); + + $can = $filter->apply('can_upload_texture', true, [$file, $name]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $type = $data['type']; + $size = getimagesize($file); + + if ($size[0] % 64 != 0 || $size[1] % 32 != 0) { + $message = trans('skinlib.upload.invalid-size', [ + 'type' => $type === 'cape' ? trans('general.cape') : trans('general.skin'), + 'width' => $size[0], + 'height' => $size[1], + ]); + + return json($message, 1); + } + + $ratio = $size[0] / $size[1]; + if ($type == 'steve' || $type == 'alex') { + if ($ratio != 2 && $ratio != 1 || $type === 'alex' && $ratio === 2) { + $message = trans('skinlib.upload.invalid-size', [ + 'type' => trans('general.skin'), + 'width' => $size[0], + 'height' => $size[1], + ]); + + return json($message, 1); + } + } elseif ($type == 'cape') { + if ($ratio != 2) { + $message = trans('skinlib.upload.invalid-size', [ + 'type' => trans('general.cape'), + 'width' => $size[0], + 'height' => $size[1], + ]); + + return json($message, 1); + } + } + + $hash = hash_file('sha256', $file); + $hash = $filter->apply('uploaded_texture_hash', $hash, [$file]); + + /** @var User */ + $user = Auth::user(); + + $duplicated = Texture::where('hash', $hash) + ->where( + fn (Builder $query) => $query->where('public', true)->orWhere('uploader', $user->uid) + ) + ->first(); + if ($duplicated) { + // if the texture already uploaded was set to private, + // then allow to re-upload it. + return json(trans('skinlib.upload.repeated'), 2, ['tid' => $duplicated->tid]); + } + + $size = ceil($file->getSize() / 1024); + $isPublic = is_string($data['public']) + ? $data['public'] === '1' + : $data['public']; + $cost = $size * ( + $isPublic + ? option('score_per_storage') + : option('private_score_per_storage') + ); + $cost += option('score_per_closet_item'); + $cost -= option('score_award_per_texture', 0); + if ($user->score < $cost) { + return json(trans('skinlib.upload.lack-score'), 1); + } + + $dispatcher->dispatch('texture.uploading', [$file, $name, $hash]); + + $texture = new Texture(); + $texture->name = $name; + $texture->type = $type; + $texture->hash = $hash; + $texture->size = $size; + $texture->public = $isPublic; + $texture->uploader = $user->uid; + $texture->likes = 1; + $texture->save(); + + /** @var FilesystemAdapter */ + $disk = Storage::disk('textures'); + if ($disk->missing($hash)) { + $file->storePubliclyAs('', $hash, ['disk' => 'textures']); + } + + $user->score -= $cost; + $user->closet()->attach($texture->tid, ['item_name' => $name]); + $user->save(); + + $dispatcher->dispatch('texture.uploaded', [$texture, $file]); + + return json(trans('skinlib.upload.success', ['name' => $name]), 0, [ + 'tid' => $texture->tid, + ]); + } + + public function delete(Texture $texture, Dispatcher $dispatcher, Filter $filter) + { + $can = $filter->apply('can_delete_texture', true, [$texture]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $dispatcher->dispatch('texture.deleting', [$texture]); + + // check if file occupied + if (Texture::where('hash', $texture->hash)->count() === 1) { + Storage::disk('textures')->delete($texture->hash); + } + + $texture->delete(); + + $dispatcher->dispatch('texture.deleted', [$texture]); + + return json(trans('skinlib.delete.success'), 0); + } + + public function privacy(Texture $texture, Dispatcher $dispatcher, Filter $filter) + { + $can = $filter->apply('can_update_texture_privacy', true, [$texture]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $uploader = $texture->owner; + $score_diff = $texture->size + * (option('private_score_per_storage') - option('score_per_storage')) + * ($texture->public ? -1 : 1); + if ($texture->public && option('take_back_scores_after_deletion', true)) { + $score_diff -= option('score_award_per_texture', 0); + } + if ($uploader->score + $score_diff < 0) { + return json(trans('skinlib.upload.lack-score'), 1); + } + + if (!$texture->public) { + $duplicated = Texture::where('hash', $texture->hash) + ->where('public', true) + ->first(); + if ($duplicated) { + return json(trans('skinlib.upload.repeated'), 2, ['tid' => $duplicated->tid]); + } + } + + $dispatcher->dispatch('texture.privacy.updating', [$texture]); + + $uploader->score += $score_diff; + $uploader->save(); + + $texture->public = !$texture->public; + $texture->save(); + + $dispatcher->dispatch('texture.privacy.updated', [$texture]); + + $message = trans('skinlib.privacy.success', [ + 'privacy' => ( + $texture->public + ? trans('general.public') + : trans('general.private')), + ]); + + return json($message, 0); + } + + public function rename( + Request $request, + Dispatcher $dispatcher, + Filter $filter, + Texture $texture + ) { + $data = $request->validate(['name' => [ + 'required', + option('texture_name_regexp') + ? 'regex:'.option('texture_name_regexp') + : 'string', + ]]); + $name = $data['name']; + + $can = $filter->apply('can_update_texture_name', true, [$texture, $name]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $dispatcher->dispatch('texture.name.updating', [$texture, $name]); + + $old = $texture->replicate(); + $texture->name = $name; + $texture->save(); + + $dispatcher->dispatch('texture.name.updated', [$texture, $old]); + + return json(trans('skinlib.rename.success', ['name' => $name]), 0); + } + + public function type( + Request $request, + Dispatcher $dispatcher, + Filter $filter, + Texture $texture + ) { + $data = $request->validate([ + 'type' => ['required', Rule::in(['steve', 'alex', 'cape'])], + ]); + $type = $data['type']; + + $can = $filter->apply('can_update_texture_type', true, [$texture, $type]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $dispatcher->dispatch('texture.type.updating', [$texture, $type]); + + $old = $texture->replicate(); + $texture->type = $type; + $texture->save(); + + $dispatcher->dispatch('texture.type.updated', [$texture, $old]); + + return json(trans('skinlib.model.success', ['model' => $type]), 0); + } +} diff --git a/app/Http/Controllers/TextureController.php b/app/Http/Controllers/TextureController.php new file mode 100755 index 0000000..c1fcec6 --- /dev/null +++ b/app/Http/Controllers/TextureController.php @@ -0,0 +1,177 @@ +middleware('cache.headers:public;max_age='.option('cache_expire_time')) + ->only(['json']); + + $this->middleware('cache.headers:etag;public;max_age='.option('cache_expire_time')) + ->only([ + 'preview', + 'raw', + 'texture', + 'avatarByPlayer', + 'avatarByUser', + 'avatarByTexture', + ]); + } + + public function json($player) + { + $player = Player::where('name', $player)->firstOrFail(); + $isBanned = $player->user->permission === User::BANNED; + abort_if($isBanned, 403, trans('general.player-banned')); + + return response()->json($player)->setLastModified($player->last_modified); + } + + public function previewByHash(Minecraft $minecraft, Request $request, $hash) + { + $texture = Texture::where('hash', $hash)->firstOrFail(); + + return $this->preview($minecraft, $request, $texture); + } + + public function preview(Minecraft $minecraft, Request $request, Texture $texture) + { + $tid = $texture->tid; + $hash = $texture->hash; + $usePNG = $request->has('png') || !(imagetypes() & IMG_WEBP); + $format = $usePNG ? 'png' : 'webp'; + + $disk = Storage::disk('textures'); + abort_if($disk->missing($hash), 404); + + $height = (int) $request->query('height', 200); + $now = Carbon::now(); + $response = Cache::remember( + 'preview-t'.$tid."-$format", + option('enable_preview_cache') ? $now->addYear() : $now->addMinute(), + function () use ($minecraft, $disk, $texture, $hash, $height, $usePNG) { + $file = $disk->get($hash); + if ($texture->type === 'cape') { + $image = $minecraft->renderCape($file, $height); + } else { + $image = $minecraft->renderSkin($file, 12, $texture->type === 'alex'); + } + + $lastModified = $disk->lastModified($hash); + + return Image::make($image) + ->response($usePNG ? 'png' : 'webp', 100) + ->setLastModified(Carbon::createFromTimestamp($lastModified)); + } + ); + + return $response; + } + + public function raw($tid) + { + abort_unless(option('allow_downloading_texture'), 403); + + $texture = Texture::findOrFail($tid); + + return $this->texture($texture->hash); + } + + public function texture(string $hash) + { + $disk = Storage::disk('textures'); + abort_if($disk->missing($hash), 404); + + $lastModified = Carbon::createFromTimestamp($disk->lastModified($hash)); + + return response($disk->get($hash)) + ->withHeaders([ + 'Content-Type' => 'image/png', + 'Content-Length' => $disk->size($hash), + ]) + ->setLastModified($lastModified); + } + + public function avatarByPlayer(Minecraft $minecraft, Request $request, $name) + { + $player = Player::where('name', $name)->firstOrFail(); + + return $this->avatar($minecraft, $request, $player->skin); + } + + public function avatarByUser(Minecraft $minecraft, Request $request, $uid) + { + $texture = Texture::find(optional(User::find($uid))->avatar); + + return $this->avatar($minecraft, $request, $texture); + } + + public function avatarByHash(Minecraft $minecraft, Request $request, $hash) + { + $texture = Texture::where('hash', $hash)->first(); + + return $this->avatar($minecraft, $request, $texture); + } + + public function avatarByTexture(Minecraft $minecraft, Request $request, $tid) + { + $texture = Texture::find($tid); + + return $this->avatar($minecraft, $request, $texture); + } + + protected function avatar(Minecraft $minecraft, Request $request, ?Texture $texture) + { + if (!empty($texture) && $texture->type !== 'steve' && $texture->type !== 'alex') { + return abort(422); + } + + $size = (int) $request->query('size', 100); + $mode = $request->has('3d') ? '3d' : '2d'; + $usePNG = $request->has('png') || !(imagetypes() & IMG_WEBP); + $format = $usePNG ? 'png' : 'webp'; + + $disk = Storage::disk('textures'); + if (is_null($texture) || $disk->missing($texture->hash)) { + return Image::make(resource_path("misc/textures/avatar$mode.png")) + ->resize($size, $size) + ->response($usePNG ? 'png' : 'webp', 100); + } + + $hash = $texture->hash; + $now = Carbon::now(); + $response = Cache::remember( + 'avatar-'.$mode.'-t'.$texture->tid.'-s'.$size."-$format", + option('enable_avatar_cache') ? $now->addYear() : $now->addMinute(), + function () use ($minecraft, $disk, $hash, $size, $mode, $usePNG) { + $file = $disk->get($hash); + if ($mode === '3d') { + $image = $minecraft->render3dAvatar($file, 25); + } else { + $image = $minecraft->render2dAvatar($file, 25); + } + + $lastModified = Carbon::createFromTimestamp($disk->lastModified($hash)); + + return Image::make($image) + ->resize($size, $size) + ->response($usePNG ? 'png' : 'webp', 100) + ->setLastModified($lastModified); + } + ); + + return $response; + } +} diff --git a/app/Http/Controllers/TranslationsController.php b/app/Http/Controllers/TranslationsController.php new file mode 100755 index 0000000..5e011b0 --- /dev/null +++ b/app/Http/Controllers/TranslationsController.php @@ -0,0 +1,70 @@ +validate([ + 'group' => 'required|string', + 'key' => 'required|string', + 'text' => 'required|string', + ]); + + $line = new LanguageLine(); + $line->group = $data['group']; + $line->key = $data['key']; + $line->setTranslation($app->getLocale(), $data['text']); + $line->save(); + + if ($data['group'] === 'front-end') { + $js->resetTime($app->getLocale()); + } + $request->session()->put('success', true); + + return redirect('/admin/i18n'); + } + + public function update( + Request $request, + Application $app, + JavaScript $js, + LanguageLine $line + ) { + $data = $request->validate(['text' => 'required|string']); + + $line->setTranslation($app->getLocale(), $data['text']); + $line->save(); + + if ($line->group === 'front-end') { + $js->resetTime($app->getLocale()); + } + + return json(trans('admin.i18n.updated'), 0); + } + + public function delete( + Application $app, + JavaScript $js, + LanguageLine $line + ) { + $line->delete(); + + if ($line->group === 'front-end') { + $js->resetTime($app->getLocale()); + } + + return json(trans('admin.i18n.deleted'), 0); + } +} diff --git a/app/Http/Controllers/UpdateController.php b/app/Http/Controllers/UpdateController.php new file mode 100755 index 0000000..73eb5ef --- /dev/null +++ b/app/Http/Controllers/UpdateController.php @@ -0,0 +1,93 @@ +getUpdateInfo(); + $canUpdate = $this->canUpdate(Arr::get($info, 'info')); + + return view('admin.update', [ + 'info' => [ + 'latest' => Arr::get($info, 'info.latest'), + 'current' => config('app.version'), + ], + 'error' => Arr::get($info, 'error', $canUpdate['reason']), + 'can_update' => $canUpdate['can'], + ]); + } + + public function download(Unzip $unzip, Filesystem $filesystem) + { + $info = $this->getUpdateInfo(); + if (!$info['ok'] || !$this->canUpdate($info['info'])['can']) { + return json(trans('admin.update.info.up-to-date'), 1); + } + + $info = $info['info']; + $path = tempnam(sys_get_temp_dir(), 'bs'); + + $response = Http::withOptions([ + 'sink' => $path, + 'verify' => CaBundle::getSystemCaRootBundlePath(), + ])->get($info['url']); + + if ($response->ok()) { + $unzip->extract($path, base_path()); + + // Delete options cache. This allows us to update the version. + $filesystem->delete(storage_path('options.php')); + + return json(trans('admin.update.complete'), 0); + } else { + return json(trans('admin.download.errors.download', ['error' => $response->status()]), 1); + } + } + + protected function getUpdateInfo() + { + $response = Http::withOptions([ + 'verify' => CaBundle::getSystemCaRootBundlePath(), + ])->get(config('app.update_source')); + + if ($response->ok()) { + $info = $response->json(); + if (Arr::get($info, 'spec') === self::SPEC) { + return ['ok' => true, 'info' => $info]; + } else { + return ['ok' => false, 'error' => trans('admin.update.errors.spec')]; + } + } else { + return ['ok' => false, 'error' => 'HTTP status code: '.$response->status()]; + } + } + + protected function canUpdate($info = []) + { + $php = Arr::get($info, 'php'); + preg_match('/(\d+\.\d+\.\d+)/', PHP_VERSION, $matches); + $version = $matches[1]; + if (Comparator::lessThan($version, $php)) { + return [ + 'can' => false, + 'reason' => trans('admin.update.errors.php', ['version' => $php]), + ]; + } + + $can = Comparator::greaterThan(Arr::get($info, 'latest'), config('app.version')); + + return ['can' => $can, 'reason' => '']; + } +} diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php new file mode 100755 index 0000000..1e02b43 --- /dev/null +++ b/app/Http/Controllers/UserController.php @@ -0,0 +1,360 @@ +user(); + + return $user + ->makeHidden(['password', 'ip', 'remember_token', 'verification_token']); + } + + public function index(Filter $filter) + { + $user = Auth::user(); + + [$min, $max] = explode(',', option('sign_score')); + $scoreIntro = trans('user.score-intro.introduction', [ + 'initial_score' => option('user_initial_score'), + 'score-from' => $min, + 'score-to' => $max, + 'return-score' => option('return_score') + ? trans('user.score-intro.will-return-score') + : trans('user.score-intro.no-return-score'), + ]); + + $grid = [ + 'layout' => [ + ['md-7', 'md-5'], + ], + 'widgets' => [ + [ + [ + 'user.widgets.email-verification', + 'user.widgets.dashboard.usage', + ], + ['user.widgets.dashboard.announcement'], + ], + ], + ]; + $grid = $filter->apply('grid:user.index', $grid); + + $converter = new GithubFlavoredMarkdownConverter(); + + return view('user.index')->with([ + 'score_intro' => $scoreIntro, + 'rates' => [ + 'storage' => option('score_per_storage'), + 'player' => option('score_per_player'), + 'closet' => option('score_per_closet_item'), + ], + 'announcement' => $converter->convertToHtml(option_localized('announcement')), + 'grid' => $grid, + 'extra' => ['unverified' => option('require_verification') && !$user->verified], + ]); + } + + public function scoreInfo() + { + /** @var User */ + $user = Auth::user(); + + return response()->json([ + 'user' => [ + 'score' => $user->score, + 'lastSignAt' => $user->last_sign_at, + ], + 'rate' => [ + 'storage' => (int) option('score_per_storage'), + 'players' => (int) option('score_per_player'), + ], + 'usage' => [ + 'players' => $user->players()->count(), + 'storage' => (int) Texture::where('uploader', $user->uid)->sum('size'), + ], + 'signAfterZero' => (bool) option('sign_after_zero'), + 'signGapTime' => (int) option('sign_gap_time'), + ]); + } + + public function sign(Dispatcher $dispatcher, Filter $filter) + { + /** @var User */ + $user = Auth::user(); + + $can = $filter->apply('can_sign', true); + if ($can instanceof Rejection) { + return json($can->getReason(), 2); + } + + $lastSignTime = Carbon::parse($user->last_sign_at); + $remainingTime = option('sign_after_zero') + ? Carbon::now()->diffInSeconds( + $lastSignTime <= Carbon::today() ? $lastSignTime : Carbon::tomorrow(), + false + ) + : Carbon::now()->diffInSeconds( + $lastSignTime->addHours((int) option('sign_gap_time')), + false + ); + + if ($remainingTime <= 0) { + [$min, $max] = explode(',', option('sign_score')); + $acquiredScore = rand((int) $min, (int) $max); + $acquiredScore = $filter->apply('sign_score', $acquiredScore); + + $dispatcher->dispatch('user.sign.before', [$acquiredScore]); + + $user->score += $acquiredScore; + $user->last_sign_at = Carbon::now(); + $user->save(); + + $dispatcher->dispatch('user.sign.after', [$acquiredScore]); + + return json(trans('user.sign-success', ['score' => $acquiredScore]), 0, [ + 'score' => $user->score, + ]); + } else { + return json('', 1); + } + } + + public function sendVerificationEmail() + { + if (!option('require_verification')) { + return json(trans('user.verification.disabled'), 1); + } + + // Rate limit of 60s + $remain = 60 + session('last_mail_time', 0) - time(); + + if ($remain > 0) { + return json(trans('user.verification.frequent-mail'), 1); + } + + $user = Auth::user(); + + if ($user->verified) { + return json(trans('user.verification.verified'), 1); + } + + $url = URL::signedRoute('auth.verify', ['user' => $user], null, false); + + try { + Mail::to($user->email)->send(new EmailVerification(url($url))); + } catch (\Exception $e) { + report($e); + + return json(trans('user.verification.failed', ['msg' => $e->getMessage()]), 2); + } + + Session::put('last_mail_time', time()); + + return json(trans('user.verification.success'), 0); + } + + public function profile(Filter $filter) + { + $user = Auth::user(); + + $grid = [ + 'layout' => [ + ['md-6', 'md-6'], + ], + 'widgets' => [ + [ + [ + 'user.widgets.profile.avatar', + 'user.widgets.profile.password', + ], + [ + 'user.widgets.profile.nickname', + 'user.widgets.profile.email', + 'user.widgets.profile.delete-account', + ], + ], + ], + ]; + $grid = $filter->apply('grid:user.profile', $grid); + + return view('user.profile') + ->with('user', $user) + ->with('grid', $grid) + ->with('site_name', option_localized('site_name')); + } + + public function handleProfile(Request $request, Filter $filter, Dispatcher $dispatcher) + { + $action = $request->input('action', ''); + /** @var User */ + $user = Auth::user(); + $addition = $request->except('action'); + + $can = $filter->apply('user_can_edit_profile', true, [$action, $addition]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $dispatcher->dispatch('user.profile.updating', [$user, $action, $addition]); + + switch ($action) { + case 'nickname': + $request->validate(['new_nickname' => 'required']); + + $nickname = $request->input('new_nickname'); + $user->nickname = $nickname; + $user->save(); + + $dispatcher->dispatch('user.profile.updated', [$user, $action, $addition]); + event(new UserProfileUpdated($action, $user)); + + return json(trans('user.profile.nickname.success', ['nickname' => $nickname]), 0); + + case 'password': + $request->validate([ + 'current_password' => 'required|min:6|max:32', + 'new_password' => 'required|min:8|max:32', + ]); + + if (!$user->verifyPassword($request->input('current_password'))) { + return json(trans('user.profile.password.wrong-password'), 1); + } + + $user->changePassword($request->input('new_password')); + $dispatcher->dispatch('user.profile.updated', [$user, $action, $addition]); + event(new UserProfileUpdated($action, $user)); + + Auth::logout(); + + return json(trans('user.profile.password.success'), 0); + + case 'email': + $data = $request->validate([ + 'email' => 'required|email', + 'password' => 'required|min:6|max:32', + ]); + + if (User::where('email', $data['email'])->count() > 0) { + return json(trans('user.profile.email.existed'), 1); + } + + if (!$user->verifyPassword($data['password'])) { + return json(trans('user.profile.email.wrong-password'), 1); + } + + $user->email = $data['email']; + $user->verified = false; + $user->save(); + + $dispatcher->dispatch('user.profile.updated', [$user, $action, $addition]); + event(new UserProfileUpdated($action, $user)); + + Auth::logout(); + + return json(trans('user.profile.email.success'), 0); + + case 'delete': + $request->validate([ + 'password' => 'required|min:6|max:32', + ]); + + if ($user->isAdmin()) { + return json(trans('user.profile.delete.admin'), 1); + } + + if (!$user->verifyPassword($request->input('password'))) { + return json(trans('user.profile.delete.wrong-password'), 1); + } + + Auth::logout(); + + $dispatcher->dispatch('user.deleting', [$user]); + + $user->delete(); + $dispatcher->dispatch('user.deleted', [$user]); + session()->flush(); + + return json(trans('user.profile.delete.success'), 0); + + default: + return json(trans('general.illegal-parameters'), 1); + } + } + + public function setAvatar(Request $request, Filter $filter, Dispatcher $dispatcher) + { + $request->validate(['tid' => 'required|integer']); + $tid = $request->input('tid'); + /** @var User */ + $user = auth()->user(); + + $can = $filter->apply('user_can_update_avatar', true, [$user, $tid]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $dispatcher->dispatch('user.avatar.updating', [$user, $tid]); + + if ($tid == 0) { + $user->avatar = 0; + $user->save(); + + $dispatcher->dispatch('user.avatar.updated', [$user, $tid]); + + return json(trans('user.profile.avatar.success'), 0); + } + + $texture = Texture::find($tid); + if ($texture) { + if ($texture->type == 'cape') { + return json(trans('user.profile.avatar.wrong-type'), 1); + } + + if ( + !$texture->public && + $user->uid !== $texture->uploader && + !$user->isAdmin() + ) { + return json(trans('skinlib.show.private'), 1); + } + + $user->avatar = $tid; + $user->save(); + + $dispatcher->dispatch('user.avatar.updated', [$user, $tid]); + + return json(trans('user.profile.avatar.success'), 0); + } else { + return json(trans('skinlib.non-existent'), 1); + } + } + + public function toggleDarkMode() + { + /** @var User */ + $user = auth()->user(); + $user->is_dark_mode = !$user->is_dark_mode; + $user->save(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/UsersManagementController.php b/app/Http/Controllers/UsersManagementController.php new file mode 100755 index 0000000..92cbe5c --- /dev/null +++ b/app/Http/Controllers/UsersManagementController.php @@ -0,0 +1,174 @@ +middleware(function (Request $request, $next) { + /** @var User */ + $targetUser = $request->route('user'); + /** @var User */ + $authUser = $request->user(); + + if ( + $targetUser->isNot($authUser) && + $targetUser->permission >= $authUser->permission + ) { + return json(trans('admin.users.operations.no-permission'), 1) + ->setStatusCode(403); + } + + return $next($request); + })->except(['list']); + } + + public function list(Request $request) + { + $q = $request->input('q'); + + return User::usingSearchString($q)->paginate(10); + } + + public function email(User $user, Request $request, Dispatcher $dispatcher) + { + $data = $request->validate([ + 'email' => [ + 'required', 'email', Rule::unique('users')->ignore($user), + ], + ]); + $email = $data['email']; + + $dispatcher->dispatch('user.email.updating', [$user, $email]); + + $old = $user->replicate(); + $user->email = $email; + $user->save(); + + $dispatcher->dispatch('user.email.updated', [$user, $old]); + + return json(trans('admin.users.operations.email.success'), 0); + } + + public function verification(User $user, Dispatcher $dispatcher) + { + $dispatcher->dispatch('user.verification.updating', [$user]); + + $user->verified = !$user->verified; + $user->save(); + + $dispatcher->dispatch('user.verification.updated', [$user]); + + return json(trans('admin.users.operations.verification.success'), 0); + } + + public function nickname(User $user, Request $request, Dispatcher $dispatcher) + { + $data = $request->validate([ + 'nickname' => 'required|string', + ]); + $nickname = $data['nickname']; + + $dispatcher->dispatch('user.nickname.updating', [$user, $nickname]); + + $old = $user->replicate(); + $user->nickname = $nickname; + $user->save(); + + $dispatcher->dispatch('user.nickname.updated', [$user, $old]); + + return json(trans('admin.users.operations.nickname.success', [ + 'new' => $request->input('nickname'), + ]), 0); + } + + public function password(User $user, Request $request, Dispatcher $dispatcher) + { + $data = $request->validate([ + 'password' => 'required|string|min:8|max:16', + ]); + $password = $data['password']; + + $dispatcher->dispatch('user.password.updating', [$user, $password]); + + $user->changePassword($password); + $user->save(); + + $dispatcher->dispatch('user.password.updated', [$user]); + + return json(trans('admin.users.operations.password.success'), 0); + } + + public function score(User $user, Request $request, Dispatcher $dispatcher) + { + $data = $request->validate([ + 'score' => 'required|integer', + ]); + $score = (int) $data['score']; + + $dispatcher->dispatch('user.score.updating', [$user, $score]); + + $old = $user->replicate(); + $user->score = $score; + $user->save(); + + $dispatcher->dispatch('user.score.updated', [$user, $old]); + + return json(trans('admin.users.operations.score.success'), 0); + } + + public function permission(User $user, Request $request, Dispatcher $dispatcher) + { + $data = $request->validate([ + 'permission' => [ + 'required', + Rule::in([User::BANNED, User::NORMAL, User::ADMIN]), + ], + ]); + $permission = (int) $data['permission']; + + if ( + $permission === User::ADMIN && + $request->user()->permission < User::SUPER_ADMIN + ) { + return json(trans('admin.users.operations.no-permission'), 1) + ->setStatusCode(403); + } + + if ($user->is($request->user())) { + return json(trans('admin.users.operations.no-permission'), 1) + ->setStatusCode(403); + } + + $dispatcher->dispatch('user.permission.updating', [$user, $permission]); + + $old = $user->replicate(); + $user->permission = $permission; + $user->save(); + + if ($permission === User::BANNED) { + $dispatcher->dispatch('user.banned', [$user]); + } + + $dispatcher->dispatch('user.permission.updated', [$user, $old]); + + return json(trans('admin.users.operations.permission'), 0); + } + + public function delete(User $user, Dispatcher $dispatcher) + { + $dispatcher->dispatch('user.deleting', [$user]); + + $user->delete(); + + $dispatcher->dispatch('user.deleted', [$user]); + + return json(trans('admin.users.operations.delete.success'), 0); + } +} diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php new file mode 100755 index 0000000..47de09a --- /dev/null +++ b/app/Http/Kernel.php @@ -0,0 +1,71 @@ + [ + \Illuminate\Cookie\Middleware\EncryptCookies::class, + \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, + \Illuminate\Session\Middleware\StartSession::class, + \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class, + \App\Http\Middleware\EnforceEverGreen::class, + \App\Http\Middleware\RedirectToSetup::class, + 'bindings', + ], + + 'api' => [ + 'bindings', + ], + + 'authorize' => [ + 'auth:web', + \App\Http\Middleware\RejectBannedUser::class, + \App\Http\Middleware\EnsureEmailFilled::class, + \App\Http\Middleware\FireUserAuthenticated::class, + ], + ]; + + /** + * The application's route middleware. + * + * These middleware may be assigned to groups or used individually. + * + * @var array + */ + protected $routeMiddleware = [ + 'auth' => \App\Http\Middleware\Authenticate::class, + 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, + 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, + 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, + 'role' => \App\Http\Middleware\CheckRole::class, + 'setup' => \App\Http\Middleware\CheckInstallation::class, + 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, + 'verified' => \App\Http\Middleware\CheckUserVerified::class, + 'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class, + 'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class, + ]; +} diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php new file mode 100755 index 0000000..5e2aa13 --- /dev/null +++ b/app/Http/Middleware/Authenticate.php @@ -0,0 +1,20 @@ +expectsJson()) { + session([ + 'last_requested_path' => $request->fullUrl(), + 'msg' => trans('auth.check.anonymous'), + ]); + + return '/auth/login'; + } + } +} diff --git a/app/Http/Middleware/CheckInstallation.php b/app/Http/Middleware/CheckInstallation.php new file mode 100755 index 0000000..100f408 --- /dev/null +++ b/app/Http/Middleware/CheckInstallation.php @@ -0,0 +1,18 @@ +exists(storage_path('install.lock')); + if ($hasLock) { + return response()->view('setup.locked'); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/CheckRole.php b/app/Http/Middleware/CheckRole.php new file mode 100755 index 0000000..88e15a6 --- /dev/null +++ b/app/Http/Middleware/CheckRole.php @@ -0,0 +1,24 @@ + -1, + 'normal' => 0, + 'admin' => 1, + 'super-admin' => 2, + ]; + + public function handle(Request $request, Closure $next, $role) + { + $permission = $request->user()->permission; + abort_if($permission < $this->roles[$role], 403); + + return $next($request); + } +} diff --git a/app/Http/Middleware/CheckUserVerified.php b/app/Http/Middleware/CheckUserVerified.php new file mode 100755 index 0000000..f393c07 --- /dev/null +++ b/app/Http/Middleware/CheckUserVerified.php @@ -0,0 +1,13 @@ +user()->verified, 403, trans('auth.check.verified')); + + return $next($request); + } +} diff --git a/app/Http/Middleware/ConvertEmptyStringsToNull.php b/app/Http/Middleware/ConvertEmptyStringsToNull.php new file mode 100755 index 0000000..4c7403e --- /dev/null +++ b/app/Http/Middleware/ConvertEmptyStringsToNull.php @@ -0,0 +1,25 @@ +path(), $this->excepts)) { + return $next($request); + } + + return parent::handle($request, $next); + } +} diff --git a/app/Http/Middleware/DetectLanguagePrefer.php b/app/Http/Middleware/DetectLanguagePrefer.php new file mode 100755 index 0000000..69eed5b --- /dev/null +++ b/app/Http/Middleware/DetectLanguagePrefer.php @@ -0,0 +1,35 @@ +input('lang') + ?? $request->cookie('locale') + ?? $request->getPreferredLanguage(); + if ( + ($info = Arr::get(config('locales'), $locale)) && + ($alias = Arr::get($info, 'alias')) + ) { + $locale = $alias; + } + $locale ?? app()->getLocale(); + if (!Arr::has(config('locales'), $locale)) { + $locale = config('app.fallback_locale'); + } + + app()->setLocale($locale); + + /** @var Response */ + $response = $next($request); + $response->cookie('locale', $locale, 120); + + return $response; + } +} diff --git a/app/Http/Middleware/EnforceEverGreen.php b/app/Http/Middleware/EnforceEverGreen.php new file mode 100755 index 0000000..1c01ece --- /dev/null +++ b/app/Http/Middleware/EnforceEverGreen.php @@ -0,0 +1,25 @@ +userAgent(); + + preg_match('/Chrome\/(\d+)/', $userAgent, $matches); + $isOldChrome = Arr::has($matches, 1) && $matches[1] < 55; + + if ($isOldChrome || Str::contains($userAgent, ['Trident', 'MSIE'])) { + throw new PrettyPageException(trans('errors.http.ie')); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/EnsureEmailFilled.php b/app/Http/Middleware/EnsureEmailFilled.php new file mode 100755 index 0000000..50e4904 --- /dev/null +++ b/app/Http/Middleware/EnsureEmailFilled.php @@ -0,0 +1,19 @@ +user()->email != '' && $request->is('auth/bind')) { + return redirect('/user'); + } elseif ($request->user()->email == '' && !$request->is('auth/bind')) { + return redirect('/auth/bind'); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/FireUserAuthenticated.php b/app/Http/Middleware/FireUserAuthenticated.php new file mode 100755 index 0000000..d590e2d --- /dev/null +++ b/app/Http/Middleware/FireUserAuthenticated.php @@ -0,0 +1,17 @@ +check()) { + event(new \App\Events\UserAuthenticated($request->user())); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php new file mode 100755 index 0000000..3e6bb7f --- /dev/null +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -0,0 +1,13 @@ +exists(storage_path('install.lock')); + + // If lock isn't existed, it means that BS isn't installed. + // Database is unavailable at this time, so we should disable the loader. + if (!$hasLock) { + config(['translation-loader.translation_loaders' => []]); + } + + if ($hasLock && !$request->is('setup*') && Comparator::greaterThan($version, option('version', $version))) { + Artisan::call('update'); + } + + if ($hasLock || $request->is('setup*')) { + return $next($request); + } + + return redirect('/setup'); + } +} diff --git a/app/Http/Middleware/RejectBannedUser.php b/app/Http/Middleware/RejectBannedUser.php new file mode 100755 index 0000000..41df44c --- /dev/null +++ b/app/Http/Middleware/RejectBannedUser.php @@ -0,0 +1,25 @@ +user()->permission == User::BANNED) { + if ($request->expectsJson()) { + $response = json(trans('auth.check.banned'), -1); + $response->setStatusCode(403); + + return $response; + } else { + abort(403, trans('auth.check.banned')); + } + } + + return $next($request); + } +} diff --git a/app/Http/View/Composers/FootComposer.php b/app/Http/View/Composers/FootComposer.php new file mode 100755 index 0000000..3db0e81 --- /dev/null +++ b/app/Http/View/Composers/FootComposer.php @@ -0,0 +1,57 @@ +request = $request; + $this->javascript = $javascript; + $this->dispatcher = $dispatcher; + $this->filter = $filter; + } + + public function compose(View $view) + { + $this->injectJavaScript($view); + $this->addExtra($view); + } + + public function injectJavaScript(View $view) + { + $scripts = []; + $scripts = $this->filter->apply('scripts', $scripts); + + $view->with([ + 'i18n' => $this->javascript->generate(app()->getLocale()), + 'scripts' => $scripts, + 'inline_js' => option('custom_js'), + ]); + } + + public function addExtra(View $view) + { + $content = []; + $this->dispatcher->dispatch(new \App\Events\RenderingFooter($content)); + $view->with('extra_foot', $content); + } +} diff --git a/app/Http/View/Composers/HeadComposer.php b/app/Http/View/Composers/HeadComposer.php new file mode 100755 index 0000000..85c4da3 --- /dev/null +++ b/app/Http/View/Composers/HeadComposer.php @@ -0,0 +1,107 @@ +dispatcher = $dispatcher; + $this->request = $request; + $this->filter = $filter; + } + + public function compose(View $view) + { + $this->addFavicon($view); + $this->applyThemeColor($view); + $this->seo($view); + $this->injectStyles($view); + $this->addExtra($view); + $this->serializeGlobals($view); + } + + public function addFavicon(View $view) + { + $url = option('favicon_url', config('options.favicon_url')); + $url = Str::startsWith($url, 'http') ? $url : url($url); + $view->with('favicon', $url); + } + + public function applyThemeColor(View $view) + { + $colors = [ + 'primary' => '#007bff', + 'secondary' => '#6c757d', + 'success' => '#28a745', + 'warning' => '#ffc107', + 'danger' => '#dc3545', + 'navy' => '#001f3f', + 'olive' => '#3d9970', + 'lime' => '#01ff70', + 'fuchsia' => '#f012be', + 'maroon' => '#d81b60', + 'indigo' => '#6610f2', + 'purple' => '#6f42c1', + 'pink' => '#e83e8c', + 'orange' => '#fd7e14', + 'teal' => '#20c997', + 'cyan' => '#17a2b8', + 'gray' => '#6c757d', + ]; + $view->with('theme_color', Arr::get($colors, option('navbar_color'))); + } + + public function seo(View $view) + { + $view->with('seo', [ + 'keywords' => option('meta_keywords'), + 'description' => option('meta_description'), + 'extra' => option('meta_extras'), + ]); + } + + public function injectStyles(View $view) + { + $links = []; + $links = $this->filter->apply('head_links', $links); + $view->with('links', $links); + $view->with('inline_css', option('custom_css')); + $view->with('custom_cdn_host', option('cdn_address')); + } + + public function addExtra(View $view) + { + $content = []; + $this->dispatcher->dispatch(new \App\Events\RenderingHeader($content)); + $view->with('extra_head', $content); + } + + public function serializeGlobals(View $view) + { + $blessing = [ + 'version' => config('app.version'), + 'locale' => config('app.locale'), + 'base_url' => url('/'), + 'site_name' => option_localized('site_name'), + 'route' => request()->path(), + ]; + $view->with('blessing', $blessing); + } +} diff --git a/app/Http/View/Composers/LanguagesMenuComposer.php b/app/Http/View/Composers/LanguagesMenuComposer.php new file mode 100755 index 0000000..89b8049 --- /dev/null +++ b/app/Http/View/Composers/LanguagesMenuComposer.php @@ -0,0 +1,38 @@ +request = $request; + } + + public function compose(View $view) + { + $query = $this->request->query(); + $path = $this->request->path(); + + $langs = collect(config('locales')) + ->reject(fn ($locale) => Arr::has($locale, 'alias')) + ->map(function ($locale, $id) use ($query, $path) { + $query = array_merge($query, ['lang' => $id]); + $locale['url'] = url($path.'?'.http_build_query($query)); + + return $locale; + }); + + $current = 'locales.'.app()->getLocale(); + $view->with([ + 'current' => config($current.'.name'), + 'langs' => $langs, + ]); + } +} diff --git a/app/Http/View/Composers/SideMenuComposer.php b/app/Http/View/Composers/SideMenuComposer.php new file mode 100755 index 0000000..deb8d53 --- /dev/null +++ b/app/Http/View/Composers/SideMenuComposer.php @@ -0,0 +1,105 @@ +request = $request; + $this->filter = $filter; + } + + public function compose(View $view) + { + $type = $view->gatherData()['type']; + + $menu = config('menu'); + switch ($type) { + case 'user': + event(new Events\ConfigureUserMenu($menu)); + break; + case 'explore': + event(new Events\ConfigureExploreMenu($menu)); + break; + case 'admin': + event(new Events\ConfigureAdminMenu($menu)); + $menu['admin'] = $this->collectPluginConfigs($menu['admin']); + break; + } + + $menu = $menu[$type]; + $menu = $this->filter->apply('side_menu', $menu, [$type]); + + $view->with('items', array_map(fn ($item) => $this->transform($item), $menu)); + } + + public function transform(array $item): array + { + $isActive = $this->request->is(Arr::get($item, 'link')); + foreach (Arr::get($item, 'children', []) as $k => $v) { + if ($this->request->is(Arr::get($v, 'link'))) { + $isActive = true; + break; + } + } + + $classes = []; + if ($isActive) { + $item['active'] = true; + $classes[] = 'active menu-open'; + } + + if (Arr::has($item, 'children')) { + $item['children'] = array_map( + fn ($item) => $this->transform($item), + $item['children'], + ); + } + + $item['classes'] = $classes; + + return $item; + } + + public function collectPluginConfigs(array &$menu) + { + $menu = array_map(function ($item) { + if (Arr::get($item, 'id') === 'plugin-configs') { + $pluginConfigs = resolve(PluginManager::class) + ->getEnabledPlugins() + ->filter(fn (Plugin $plugin) => $plugin->hasConfig()) + ->map(function ($plugin) { + return [ + 'title' => trans($plugin->title), + 'link' => 'admin/plugins/config/'.$plugin->name, + 'icon' => 'fa-circle', + ]; + }); + + // Don't display this menu item when no plugin config is available + if ($pluginConfigs->isNotEmpty()) { + array_push($item['children'], ...$pluginConfigs->values()->all()); + + return $item; + } + } else { + return $item; + } + }, $menu); + + return array_filter($menu); // Remove empty items + } +} diff --git a/app/Http/View/Composers/UserMenuComposer.php b/app/Http/View/Composers/UserMenuComposer.php new file mode 100755 index 0000000..27fd199 --- /dev/null +++ b/app/Http/View/Composers/UserMenuComposer.php @@ -0,0 +1,41 @@ +request = $request; + $this->filter = $filter; + } + + public function compose(View $view) + { + $user = auth()->user(); + $avatarUrl = route('avatar.texture', ['tid' => $user->avatar, 'size' => 36], false); + $avatar = $this->filter->apply('user_avatar', $avatarUrl, [$user]); + $avatarPNG = route( + 'avatar.texture', + ['tid' => $user->avatar, 'size' => 36, 'png' => true], + false + ); + $avatarPNG = $this->filter->apply('user_avatar', $avatarPNG, [$user]); + $cli = $this->request->is('admin', 'admin/*'); + + $view->with([ + 'user' => $user, + 'avatar' => $avatar, + 'avatar_png' => $avatarPNG, + 'cli' => $cli, + ]); + } +} diff --git a/app/Http/View/Composers/UserPanelComposer.php b/app/Http/View/Composers/UserPanelComposer.php new file mode 100755 index 0000000..2ec2c56 --- /dev/null +++ b/app/Http/View/Composers/UserPanelComposer.php @@ -0,0 +1,49 @@ +dispatcher = $dispatcher; + $this->filter = $filter; + } + + public function compose(View $view) + { + /** @var User */ + $user = auth()->user(); + $avatarUrl = route('avatar.texture', ['tid' => $user->avatar, 'size' => 45], false); + $avatar = $this->filter->apply('user_avatar', $avatarUrl, [$user]); + $avatarPNG = route( + 'avatar.texture', + ['tid' => $user->avatar, 'size' => 45, 'png' => true], + false + ); + $avatarPNG = $this->filter->apply('user_avatar', $avatarPNG, [$user]); + + $badges = []; + if ($user->isAdmin()) { + $badges[] = ['text' => 'STAFF', 'color' => 'primary']; + } + $this->dispatcher->dispatch(new \App\Events\RenderingBadges($badges)); + $badges = $this->filter->apply('user_badges', $badges, [$user]); + + $view->with([ + 'user' => $user, + 'avatar' => $avatar, + 'avatar_png' => $avatarPNG, + 'badges' => $badges, + ]); + } +} diff --git a/app/Listeners/CleanUpCloset.php b/app/Listeners/CleanUpCloset.php new file mode 100755 index 0000000..8edb9c4 --- /dev/null +++ b/app/Listeners/CleanUpCloset.php @@ -0,0 +1,34 @@ +exists && $texture->public) { + return; + } + + $likers = $texture + ->likers() + ->where('user_uid', '!=', $texture->uploader) + ->get(); + $likers->each(function (User $user) use ($texture) { + $user->closet()->detach($texture->tid); + if (option('return_score')) { + $user->score += (int) option('score_per_closet_item'); + $user->save(); + } + }); + + if ($texture->exists) { + $texture->decrement('likes', $likers->count()); + } + } +} diff --git a/app/Listeners/CleanUpFrontEndLocaleFiles.php b/app/Listeners/CleanUpFrontEndLocaleFiles.php new file mode 100755 index 0000000..a645b86 --- /dev/null +++ b/app/Listeners/CleanUpFrontEndLocaleFiles.php @@ -0,0 +1,26 @@ +filesystem = $filesystem; + } + + public function handle() + { + $files = $this->filesystem->allFiles(public_path('lang')); + array_walk($files, function (SplFileInfo $file) { + if ($file->getExtension() === 'js') { + $this->filesystem->delete($file->getPathname()); + } + }); + } +} diff --git a/app/Listeners/CopyPluginAssets.php b/app/Listeners/CopyPluginAssets.php new file mode 100755 index 0000000..fb4e9e6 --- /dev/null +++ b/app/Listeners/CopyPluginAssets.php @@ -0,0 +1,28 @@ +filesystem = $filesystem; + } + + public function handle($event) + { + $plugin = $event instanceof Plugin ? $event : $event->plugin; + $dir = public_path('plugins/'.$plugin->name); + $this->filesystem->deleteDirectory($dir); + + $this->filesystem->copyDirectory( + $plugin->getPath().DIRECTORY_SEPARATOR.'assets', + $dir.'/assets' + ); + } +} diff --git a/app/Listeners/NotifyFailedPlugin.php b/app/Listeners/NotifyFailedPlugin.php new file mode 100755 index 0000000..2e9f32c --- /dev/null +++ b/app/Listeners/NotifyFailedPlugin.php @@ -0,0 +1,22 @@ +plugin; + Event::listen(\App\Events\RenderingFooter::class, function ($event) use ($plugin) { + /** @var User */ + $user = auth()->user(); + if ($user && $user->isAdmin()) { + $message = trans('errors.plugins.boot', ['plugin' => trans($plugin->title)]); + $event->addContent(""); + } + }); + } +} diff --git a/app/Listeners/ResetPlayerForRemovedClosetItem.php b/app/Listeners/ResetPlayerForRemovedClosetItem.php new file mode 100755 index 0000000..785f595 --- /dev/null +++ b/app/Listeners/ResetPlayerForRemovedClosetItem.php @@ -0,0 +1,16 @@ +type === 'cape' ? 'tid_cape' : 'tid_skin'; + + $user->players()->where($type, $texture->tid)->update([$type => 0]); + } +} diff --git a/app/Listeners/ResetPlayers.php b/app/Listeners/ResetPlayers.php new file mode 100755 index 0000000..74fd5aa --- /dev/null +++ b/app/Listeners/ResetPlayers.php @@ -0,0 +1,28 @@ +exists && $texture->public) { + return; + } + + $type = $texture->type == 'cape' ? 'tid_cape' : 'tid_skin'; + $query = Player::where($type, $texture->tid); + + // texture was switched from "private" to "public" + if ($texture->exists) { + $query = $query->where('uid', '<>', $texture->uploader); + } + + $query->update([$type => 0]); + } +} diff --git a/app/Listeners/SendEmailVerification.php b/app/Listeners/SendEmailVerification.php new file mode 100755 index 0000000..097fd16 --- /dev/null +++ b/app/Listeners/SendEmailVerification.php @@ -0,0 +1,24 @@ + $user->uid], null, false); + + try { + Mail::to($user->email)->send(new EmailVerification(url($url))); + } catch (\Exception $e) { + report($e); + } + } + } +} diff --git a/app/Listeners/SetAppLocale.php b/app/Listeners/SetAppLocale.php new file mode 100755 index 0000000..9391390 --- /dev/null +++ b/app/Listeners/SetAppLocale.php @@ -0,0 +1,34 @@ +request = $request; + } + + public function handle($event) + { + /** @var User */ + $user = $event->user; + + if ($this->request->has('lang')) { + $user->locale = $this->request->input('lang'); + $user->save(); + + return; + } + + $locale = $user->locale; + if ($locale) { + app()->setLocale($locale); + } + } +} diff --git a/app/Listeners/UpdateScoreForDeletedTexture.php b/app/Listeners/UpdateScoreForDeletedTexture.php new file mode 100755 index 0000000..84cc23a --- /dev/null +++ b/app/Listeners/UpdateScoreForDeletedTexture.php @@ -0,0 +1,28 @@ +owner; + if ($uploader) { + $ret = 0; + if (option('return_score')) { + $ret += $texture->size * ( + $texture->public + ? (int) option('score_per_storage') + : (int) option('private_score_per_storage') + ); + } + + if ($texture->public && option('take_back_scores_after_deletion', true)) { + $ret -= (int) option('score_award_per_texture', 0); + } + + $uploader->score += $ret; + $uploader->save(); + } + } +} diff --git a/app/Mail/EmailVerification.php b/app/Mail/EmailVerification.php new file mode 100755 index 0000000..43ec8cf --- /dev/null +++ b/app/Mail/EmailVerification.php @@ -0,0 +1,29 @@ +url = $url; + } + + public function build() + { + $site_name = option_localized('site_name'); + + return $this + ->subject(trans('user.verification.mail.title', ['sitename' => $site_name])) + ->view('mails.email-verification'); + } +} diff --git a/app/Mail/ForgotPassword.php b/app/Mail/ForgotPassword.php new file mode 100755 index 0000000..d9ff681 --- /dev/null +++ b/app/Mail/ForgotPassword.php @@ -0,0 +1,29 @@ +url = $url; + } + + public function build() + { + $site_name = option_localized('site_name'); + + return $this + ->subject(trans('auth.forgot.mail.title', ['sitename' => $site_name])) + ->view('mails.password-reset'); + } +} diff --git a/app/Models/Concerns/HasPassword.php b/app/Models/Concerns/HasPassword.php new file mode 100755 index 0000000..316e907 --- /dev/null +++ b/app/Models/Concerns/HasPassword.php @@ -0,0 +1,33 @@ +password; + $user = $this; + + $passed = $cipher->verify($raw, $password, config('secure.salt')); + $passed = $filter->apply('verify_password', $passed, [$raw, $user]); + + return $passed; + } + + public function changePassword(string $password): bool + { + $password = resolve('cipher')->hash($password, config('secure.salt')); + $password = resolve(Filter::class)->apply('user_password', $password); + $this->password = $password; + + return $this->save(); + } +} diff --git a/app/Models/Player.php b/app/Models/Player.php new file mode 100755 index 0000000..f716017 --- /dev/null +++ b/app/Models/Player.php @@ -0,0 +1,99 @@ + 'integer', + 'uid' => 'integer', + 'tid_skin' => 'integer', + 'tid_cape' => 'integer', + ]; + + protected $dispatchesEvents = [ + 'retrieved' => \App\Events\PlayerRetrieved::class, + 'updated' => PlayerProfileUpdated::class, + ]; + + protected $searchStringColumns = [ + 'pid', 'uid', + 'tid_skin' => '/^(?:tid_)?skin$/', + 'tid_cape' => '/^(?:tid_)?cape$/', + 'name' => ['searchable' => true], + 'last_modified' => ['date' => true], + ]; + + public function user() + { + return $this->belongsTo(Models\User::class, 'uid'); + } + + public function skin() + { + return $this->belongsTo(Models\Texture::class, 'tid_skin'); + } + + public function cape() + { + return $this->belongsTo(Models\Texture::class, 'tid_cape'); + } + + public function getModelAttribute() + { + return optional($this->skin)->model ?? 'default'; + } + + /** + * CustomSkinAPI R1. + */ + public function toJson($options = 0) + { + $model = $this->model; + $profile = [ + 'username' => $this->name, + 'skins' => [ + $model => optional($this->skin)->hash, + ], + 'cape' => optional($this->cape)->hash, + ]; + + return json_encode($profile, $options | JSON_UNESCAPED_UNICODE); + } + + protected function serializeDate(DateTimeInterface $date) + { + return $date->format('Y-m-d H:i:s'); + } +} diff --git a/app/Models/Report.php b/app/Models/Report.php new file mode 100755 index 0000000..5d28799 --- /dev/null +++ b/app/Models/Report.php @@ -0,0 +1,68 @@ + 'integer', + 'uploader' => 'integer', + 'reporter' => 'integer', + 'status' => 'integer', + ]; + + protected $searchStringColumns = [ + 'id', 'tid', 'uploader', 'reporter', + 'reason', 'status', + 'report_at' => ['date' => true], + ]; + + public function texture() + { + return $this->belongsTo(Texture::class, 'tid', 'tid'); + } + + public function textureUploader() + { + return $this->belongsTo(User::class, 'uploader', 'uid'); + } + + public function informer() + { + return $this->belongsTo(User::class, 'reporter', 'uid'); + } + + protected function serializeDate(DateTimeInterface $date) + { + return $date->format('Y-m-d H:i:s'); + } +} diff --git a/app/Models/Scope.php b/app/Models/Scope.php new file mode 100755 index 0000000..1f27892 --- /dev/null +++ b/app/Models/Scope.php @@ -0,0 +1,19 @@ + 'integer', + 'size' => 'integer', + 'uploader' => 'integer', + 'public' => 'boolean', + 'likes' => 'integer', + ]; + + protected $dispatchesEvents = [ + 'deleting' => \App\Events\TextureDeleting::class, + ]; + + public function getModelAttribute() + { + // Don't worry about cape... + return $this->type === 'alex' ? 'slim' : 'default'; + } + + public function scopeLike($query, $field, $value) + { + return $query->where($field, 'LIKE', "%$value%"); + } + + public function owner() + { + return $this->belongsTo(User::class, 'uploader'); + } + + public function likers() + { + return $this->belongsToMany(User::class, 'user_closet')->withPivot('item_name'); + } + + protected function serializeDate(DateTimeInterface $date) + { + return $date->format('Y-m-d H:i:s'); + } +} diff --git a/app/Models/User.php b/app/Models/User.php new file mode 100755 index 0000000..113314f --- /dev/null +++ b/app/Models/User.php @@ -0,0 +1,115 @@ + 'integer', + 'score' => 'integer', + 'avatar' => 'integer', + 'permission' => 'integer', + 'verified' => 'bool', + 'is_dark_mode' => 'bool', + ]; + + protected $hidden = ['password', 'remember_token']; + + protected $searchStringColumns = [ + 'uid', + 'email' => ['searchable' => true], + 'nickname' => ['searchable' => true], + 'avatar', 'score', 'permission', 'ip', + 'last_sign_at' => ['date' => true], + 'register_at' => ['date' => true], + 'verified' => ['boolean' => true], + 'is_dark_mode' => ['boolean' => true], + ]; + + public function isAdmin(): bool + { + return $this->permission >= static::ADMIN; + } + + public function closet() + { + return $this->belongsToMany(Texture::class, 'user_closet')->withPivot('item_name'); + } + + public function getPlayerNameAttribute() + { + $player = $this->players->first(); + + return $player ? $player->name : ''; + } + + public function setPlayerNameAttribute($value) + { + $player = $this->players->first(); + if ($player) { + $player->name = $value; + $player->save(); + } + } + + public function delete() + { + Player::where('uid', $this->uid)->delete(); + + return parent::delete(); + } + + public function players() + { + return $this->hasMany(Player::class, 'uid'); + } + + public function getAuthIdentifier() + { + return $this->uid; + } +} diff --git a/app/Notifications/SiteMessage.php b/app/Notifications/SiteMessage.php new file mode 100755 index 0000000..0f3a05f --- /dev/null +++ b/app/Notifications/SiteMessage.php @@ -0,0 +1,51 @@ +title = $title; + $this->content = $content; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * + * @return array + */ + public function via($notifiable) + { + return ['database']; + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * + * @return array + */ + public function toArray($notifiable) + { + return [ + 'title' => $this->title, + 'content' => $this->content, + ]; + } +} diff --git a/app/Observers/ScopeObserver.php b/app/Observers/ScopeObserver.php new file mode 100755 index 0000000..38b5256 --- /dev/null +++ b/app/Observers/ScopeObserver.php @@ -0,0 +1,37 @@ +refreshCachedScopes(); + } + + /** + * Handle the Scope "deleted" event. + * + * @return void + */ + public function deleted() + { + $this->refreshCachedScopes(); + } + + protected function refreshCachedScopes() + { + Cache::forget('scopes'); + Cache::rememberForever('scopes', function () { + return Scope::pluck('description', 'name')->toArray(); + }); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php new file mode 100755 index 0000000..219b480 --- /dev/null +++ b/app/Providers/AppServiceProvider.php @@ -0,0 +1,59 @@ +app->singleton('cipher', 'App\Services\Cipher\\'.config('secure.cipher')); + $this->app->singleton(Services\Option::class); + $this->app->alias(Services\Option::class, 'options'); + } + + public function boot(Request $request) + { + Paginator::useBootstrap(); + + $this->configureUrlGenerator($request); + } + + /** + * Control the URL generated by url() function. + * + * @codeCoverageIgnore + */ + protected function configureUrlGenerator(Request $request): void + { + if (!option('auto_detect_asset_url')) { + $rootUrl = option('site_url'); + + // Replace HTTP_HOST with site_url set in options, + // to prevent CDN source problems. + if (URL::isValidUrl($rootUrl)) { + URL::forceRootUrl($rootUrl); + } + } + + /** + * Check whether the request is secure or not. + * True is always returned when "X-Forwarded-Proto" header is set. + * + * We define this function because Symfony's "Request::isSecure()" method + * needs "setTrustedProxies()" which sucks when load balancer is enabled. + */ + $isRequestSecure = $request->server('HTTPS') === 'on' + || $request->server('HTTP_X_FORWARDED_PROTO') === 'https' + || $request->server('HTTP_X_FORWARDED_SSL') === 'on'; + + if (option('force_ssl') || $isRequestSecure) { + URL::forceScheme('https'); + } + } +} diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php new file mode 100755 index 0000000..64773c0 --- /dev/null +++ b/app/Providers/AuthServiceProvider.php @@ -0,0 +1,54 @@ +registerPolicies(); + + Passport::routes(); + + $defaultScopes = [ + 'User.Read' => 'auth.oauth.scope.user.read', + 'Notification.Read' => 'auth.oauth.scope.notification.read', + 'Notification.ReadWrite' => 'auth.oauth.scope.notification.readwrite', + 'Player.Read' => 'auth.oauth.scope.player.read', + 'Player.ReadWrite' => 'auth.oauth.scope.player.readwrite', + 'Closet.Read' => 'auth.oauth.scope.closet.read', + 'Closet.ReadWrtie' => 'auth.oauth.scope.closet.readwrite', + 'UsersManagement.Read' => 'auth.oauth.scope.users-management.read', + 'UsersManagement.ReadWrite' => 'auth.oauth.scope.users-management.readwrite', + 'PlayersManagement.Read' => 'auth.oauth.scope.players-management.read', + 'PlayersManagement.ReadWrite' => 'auth.oauth.scope.players-management.readwrite', + 'ClosetManagement.Read' => 'auth.oauth.scope.closet-management.read', + 'ClosetManagement.ReadWrite' => 'auth.oauth.scope.closet-management.readwrite', + 'ReportsManagement.Read' => 'auth.oauth.scope.reports-management.read', + 'ReportsManagement.ReadWrite' => 'auth.oauth.scope.reports-management.readwrite', + ]; + + $scopes = Cache::get('scopes', []); + + Passport::tokensCan(array_merge($defaultScopes, $scopes)); + + Passport::setDefaultScope(['User.Read']); + } +} diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php new file mode 100755 index 0000000..deda698 --- /dev/null +++ b/app/Providers/EventServiceProvider.php @@ -0,0 +1,54 @@ + [ + Listeners\CopyPluginAssets::class, + Listeners\CleanUpFrontEndLocaleFiles::class, + ], + 'plugin.versionChanged' => [ + Listeners\CopyPluginAssets::class, + Listeners\CleanUpFrontEndLocaleFiles::class, + ], + 'App\Events\PluginBootFailed' => [ + Listeners\NotifyFailedPlugin::class, + ], + 'auth.registration.completed' => [ + Listeners\SendEmailVerification::class, + ], + 'texture.privacy.updated' => [ + Listeners\ResetPlayers::class, + Listeners\CleanUpCloset::class, + ], + 'texture.deleted' => [ + Listeners\UpdateScoreForDeletedTexture::class, + Listeners\ResetPlayers::class, + Listeners\CleanUpCloset::class, + ], + 'closet.removed' => [ + Listeners\ResetPlayerForRemovedClosetItem::class, + ], + 'Illuminate\Auth\Events\Authenticated' => [ + Listeners\SetAppLocale::class, + ], + ]; + + /** + * Register any events for your application. + * + * @return void + */ + public function boot() + { + Scope::observe(ScopeObserver::class); + } +} diff --git a/app/Providers/PluginServiceProvider.php b/app/Providers/PluginServiceProvider.php new file mode 100755 index 0000000..68debc0 --- /dev/null +++ b/app/Providers/PluginServiceProvider.php @@ -0,0 +1,20 @@ +app->singleton(PluginManager::class); + $this->app->alias(PluginManager::class, 'plugins'); + } + + public function boot(PluginManager $plugins) + { + $plugins->boot(); + } +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php new file mode 100755 index 0000000..f237362 --- /dev/null +++ b/app/Providers/RouteServiceProvider.php @@ -0,0 +1,75 @@ +mapStaticRoutes($router); + + $this->mapWebRoutes($router); + + $this->mapApiRoutes(); + + Passport::routes(); + foreach ($router->getRoutes()->getRoutesByName() as $name => $route) { + if (Str::startsWith($name, ['passport.authorizations', 'passport.tokens', 'passport.clients'])) { + $route->middleware('verified'); + } + } + + event(new ConfigureRoutes($router)); + } + + /** + * Define the "web" routes for the application. + * These routes all receive session state, CSRF protection, etc. + */ + protected function mapWebRoutes(Router $router) + { + Route::middleware(['web']) + ->namespace($this->namespace) + ->group(base_path('routes/web.php')); + } + + /** + * Define the "static" routes for the application. + * These routes will not load session, etc. + */ + protected function mapStaticRoutes(Router $router) + { + Route::namespace($this->namespace) + ->group(base_path('routes/static.php')); + } + + /** + * Define the "api" routes for the application. + * These routes are typically stateless. + */ + protected function mapApiRoutes() + { + Route::prefix('api') + ->middleware( + config('app.env') == 'testing' ? ['api'] : ['api', 'throttle:60,1'] + ) + ->namespace($this->namespace) + ->group(base_path('routes/api.php')); + } +} diff --git a/app/Providers/ViewServiceProvider.php b/app/Providers/ViewServiceProvider.php new file mode 100755 index 0000000..3bec892 --- /dev/null +++ b/app/Providers/ViewServiceProvider.php @@ -0,0 +1,82 @@ +with([ + 'site_name' => option_localized('site_name'), + 'navbar_color' => $color, + 'color_mode' => in_array($color, $lightColors) ? 'light' : 'dark', + 'dark_mode' => (bool) optional(auth()->user())->is_dark_mode, + 'locale' => str_replace('_', '-', app()->getLocale()), + ]); + }); + + View::composer('shared.head', Composers\HeadComposer::class); + + View::composer('shared.notifications', function ($view) { + $notifications = auth()->user()->unreadNotifications->map(function ($notification) { + return [ + 'id' => $notification->id, + 'title' => $notification->data['title'], + ]; + }); + $view->with(['notifications' => $notifications]); + }); + + View::composer( + ['shared.languages', 'errors.*'], + Composers\LanguagesMenuComposer::class + ); + + View::composer('shared.user-menu', Composers\UserMenuComposer::class); + + View::composer('shared.sidebar', function ($view) { + $isDarkMode = (bool) optional(auth()->user())->is_dark_mode; + $color = option('sidebar_color'); + $color = $isDarkMode ? str_replace('light', 'dark', $color) : $color; + + $view->with('sidebar_color', $color); + }); + + View::composer('shared.side-menu', Composers\SideMenuComposer::class); + + View::composer('shared.user-panel', Composers\UserPanelComposer::class); + + View::composer('shared.copyright', function ($view) { + $view->with([ + 'copyright' => option_localized('copyright_prefer', 0), + 'custom_copyright' => option_localized('copyright_text'), + 'site_name' => option_localized('site_name'), + 'site_url' => option('site_url'), + ]); + }); + + View::composer('shared.foot', Composers\FootComposer::class); + + View::composer('shared.dark-mode', function ($view) { + $view->with([ + 'dark_mode' => (bool) optional(auth()->user())->is_dark_mode, + ]); + }); + + View::composer('assets.*', function ($view) { + $view->with('cdn_base', option('cdn_address', '')); + }); + } +} diff --git a/app/Rules/Captcha.php b/app/Rules/Captcha.php new file mode 100755 index 0000000..33e9954 --- /dev/null +++ b/app/Rules/Captcha.php @@ -0,0 +1,36 @@ +withOptions(['verify' => CaBundle::getSystemCaRootBundlePath()]) + ->post('https://www.recaptcha.net/recaptcha/api/siteverify', [ + 'secret' => $secretkey, + 'response' => $value, + ]) + ->json()['success']; + } + + $builder = new CaptchaBuilder(session()->pull('captcha')); + + return $builder->testPhrase($value); + } + + public function message() + { + return option('recaptcha_secretkey') + ? trans('validation.recaptcha') + : trans('validation.captcha'); + } +} diff --git a/app/Rules/PlayerName.php b/app/Rules/PlayerName.php new file mode 100755 index 0000000..10195c9 --- /dev/null +++ b/app/Rules/PlayerName.php @@ -0,0 +1,39 @@ +hash($password, $salt)); + } +} diff --git a/app/Services/Cipher/MD5.php b/app/Services/Cipher/MD5.php new file mode 100755 index 0000000..8404765 --- /dev/null +++ b/app/Services/Cipher/MD5.php @@ -0,0 +1,11 @@ + 'Title', # will be translated by translator + * 'link' => 'user/config', # route link + * 'icon' => 'fa-book', # font-awesome icon + * 'new-tab' => false, # open the link in new tab or not, false by default + * ] + */ + public static function addMenuItem(string $category, int $position, array $menu): void + { + $class = 'App\Events\Configure'.Str::title($category).'Menu'; + + Event::listen($class, function ($event) use ($menu, $position, $category) { + $new = []; + + $offset = 0; + foreach ($event->menu[$category] as $item) { + // Push new menu items at the given position + if ($offset == $position) { + $new[] = $menu; + } + + $new[] = $item; + $offset++; + } + + if ($position >= $offset) { + $new[] = $menu; + } + + $event->menu[$category] = $new; + }); + } + + public static function addRoute(Closure $callback): void + { + Event::listen(Events\ConfigureRoutes::class, function ($event) use ($callback) { + return call_user_func($callback, $event->router); + }); + } + + public static function addStyleFileToPage($urls, $pages = ['*']): void + { + $urls = collect($urls); + $pages = collect($pages); + resolve(Filter::class)->add('head_links', function ($links) use ($urls, $pages) { + $matched = $pages->some(fn ($page) => request()->is($page)); + if ($matched) { + $urls->each(function ($url) use (&$links) { + $links[] = [ + 'rel' => 'stylesheet', + 'href' => $url, + 'crossorigin' => 'anonymous', + ]; + }); + } + + return $links; + }); + } + + public static function addScriptFileToPage($urls, $pages = ['*']): void + { + $urls = collect($urls); + $pages = collect($pages); + resolve(Filter::class)->add('scripts', function ($scripts) use ($urls, $pages) { + $matched = $pages->some(fn ($page) => request()->is($page)); + if ($matched) { + $urls->each(function ($url) use (&$scripts) { + $scripts[] = ['src' => $url, 'crossorigin' => 'anonymous']; + }); + } + + return $scripts; + }); + } + + /** @deprecated */ + public static function addUserBadge(string $text, $color = 'primary'): void + { + resolve(Filter::class)->add('user_badges', function ($badges) use ($text, $color) { + $badges[] = ['text' => $text, 'color' => $color]; + + return $badges; + }); + } + + public static function sendNotification($users, string $title, $content = ''): void + { + Notification::send(Arr::wrap($users), new Notifications\SiteMessage($title, $content)); + } + + public static function pushMiddleware($middleware) + { + app()->make('Illuminate\Contracts\Http\Kernel')->pushMiddleware($middleware); + } +} diff --git a/app/Services/Option.php b/app/Services/Option.php new file mode 100755 index 0000000..79b3927 --- /dev/null +++ b/app/Services/Option.php @@ -0,0 +1,83 @@ +exists($cachePath)) { + $this->items = collect($filesystem->getRequire($cachePath)); + + return; + } + + try { + $this->items = DB::table('options') + ->get() + ->mapWithKeys(fn ($item) => [$item->option_name => $item->option_value]); + } catch (QueryException $e) { + $this->items = collect(); + } + } + + public function get($key, $default = null, $raw = false) + { + if (!$this->items->has($key) && Arr::has(config('options'), $key)) { + $this->set($key, config("options.$key")); + } + + $value = $this->items->get($key, $default); + if ($raw) { + return $value; + } + + switch (strtolower($value)) { + case 'true': + case '(true)': + return true; + + case 'false': + case '(false)': + return false; + + case 'null': + case '(null)': + return null; + + default: + return $value; + } + } + + public function set($key, $value = null) + { + if (is_array($key)) { + foreach ($key as $k => $v) { + $this->set($k, $v); + } + } else { + $this->items->put($key, $value); + try { + DB::table('options')->updateOrInsert( + ['option_name' => $key], + ['option_value' => $value] + ); + } catch (QueryException $e) { + } + } + } + + public function all(): array + { + return $this->items->all(); + } +} diff --git a/app/Services/OptionForm.php b/app/Services/OptionForm.php new file mode 100755 index 0000000..0e4484d --- /dev/null +++ b/app/Services/OptionForm.php @@ -0,0 +1,563 @@ +id = $id; + + if ($title == self::AUTO_DETECT) { + $this->title = trans("options.$id.title"); + } else { + $this->title = $title; + } + } + + /** + * @throws \BadMethodCallException + */ + public function __call(string $method, array $params): OptionFormItem + { + if (!in_array($method, ['text', 'checkbox', 'textarea', 'select', 'group'])) { + throw new BadMethodCallException("Method [$method] does not exist on option form."); + } + + // Assign name for option item + if (!isset($params[1]) || Arr::get($params, 1) == OptionForm::AUTO_DETECT) { + $params[1] = Arr::get(trans("options.$this->id.$params[0]"), 'title', trans("options.$this->id.$params[0]")); + } + + $class = new ReflectionClass('App\Services\OptionForm'.Str::title($method)); + // Use ReflectionClass to create a new OptionFormItem instance + $item = $class->newInstanceArgs($params); + $item->setParentId($this->id); + $this->items[] = $item; + + return $item; + } + + /** Set the box type of option form. */ + public function type(string $type): self + { + $this->type = $type; + + return $this; + } + + /** Add a hint to option form. */ + public function hint($hintContent = self::AUTO_DETECT): self + { + if ($hintContent == self::AUTO_DETECT) { + $hintContent = trans("options.$this->id.hint"); + } + + $this->hint = view('forms.hint')->with('hint', $hintContent)->render(); + + return $this; + } + + /** + * Add a piece of data to the option form. + * + * @param string|array $key + * @param mixed $value + */ + public function with($key, $value = null): self + { + if (is_array($key)) { + $this->values = array_merge($this->values, $key); + } else { + $this->values[$key] = $value; + } + + return $this; + } + + /** Add a button at the footer of option form. */ + public function addButton(array $info): self + { + $info = array_merge([ + 'style' => 'default', + 'class' => [], + 'href' => '', + 'text' => 'BUTTON', + 'type' => 'button', + 'name' => '', + ], $info); + + $info['class'] = array_merge( + ['btn', 'btn-'.$info['style']], + (array) Arr::get($info, 'class') + ); + $this->buttons[] = $info; + + return $this; + } + + /** + * Add a message to the top of option form. + * + * @param string $msg + */ + public function addMessage($msg = self::AUTO_DETECT, string $style = 'info'): self + { + if ($msg == self::AUTO_DETECT) { + $msg = trans("options.$this->id.message"); + } + + $this->messages[] = ['content' => $msg, 'type' => $style]; + + return $this; + } + + /** + * Add an alert to the top of option form. + * + * @param string $msg + */ + public function addAlert($msg = self::AUTO_DETECT, string $style = 'info'): self + { + if ($msg == self::AUTO_DETECT) { + $msg = trans("options.$this->id.alert"); + } + + $this->alerts[] = ['content' => $msg, 'type' => $style]; + + return $this; + } + + /** + * Add callback which will be executed before handling options. + */ + public function before(callable $callback): self + { + $this->hookBefore = $callback; + + return $this; + } + + /** + * Add callback which will be executed after handling options. + */ + public function after(callable $callback): self + { + $this->hookAfter = $callback; + + return $this; + } + + /** + * Add callback which will be always executed. + */ + public function always(callable $callback): self + { + $this->alwaysCallback = $callback; + + return $this; + } + + /** + * Handle the HTTP post request and update modified options. + */ + public function handle(callable $callback = null): self + { + $request = request(); + $allPostData = $request->all(); + + if ($request->isMethod('POST') && Arr::get($allPostData, 'option') == $this->id) { + if (!is_null($callback)) { + call_user_func($callback, $this); + } + + if (!is_null($this->hookBefore)) { + call_user_func($this->hookBefore, $this); + } + + $postOptionQueue = []; + + foreach ($this->items as $item) { + if ($item instanceof OptionFormGroup) { + foreach ($item->items as $innerItem) { + if ($innerItem['type'] == 'text') { + $postOptionQueue[] = new OptionFormText($innerItem['id']); + } + } + continue; + } + // Push item to the queue + $postOptionQueue[] = $item; + } + + foreach ($postOptionQueue as $item) { + if ($item instanceof OptionFormCheckbox && !isset($allPostData[$item->id])) { + // preset value for checkboxes which are not checked + $allPostData[$item->id] = false; + } + + // Compare with raw option value + if (($data = Arr::get($allPostData, $item->id)) != option($item->id, null, true)) { + $formatted = is_null($item->format) ? $data : call_user_func($item->format, $data); + Option::set($item->id, $formatted); + } + } + + if (!is_null($this->hookAfter)) { + call_user_func($this->hookAfter, $this); + } + + $this->addAlert(trans('options.option-saved'), 'success'); + } + + return $this; + } + + /** + * Load value from $this->values & options by given id. + */ + protected function getValueById(string $id) + { + return Arr::get($this->values, $id, option_localized($id)); + } + + /** + * Assign value for option items whose value haven't been set. + */ + protected function assignValues(): void + { + // Load values for items if not set manually + foreach ($this->items as $item) { + if ($item instanceof OptionFormGroup) { + foreach ($item->items as &$groupItem) { + if ($groupItem['id'] && is_null($groupItem['value'])) { + $groupItem['value'] = $this->getValueById($groupItem['id']); + } + } + continue; + } + + if (is_null($item->value)) { + $item->value = $this->getValueById($item->id); + } + } + } + + public function renderWithoutTable(): self + { + $this->renderWithoutTable = true; + + return $this; + } + + public function renderInputTagsOnly(): self + { + $this->renderInputTagsOnly = true; + + return $this; + } + + public function renderWithoutSubmitButton(): self + { + $this->renderWithoutSubmitButton = true; + + return $this; + } + + /** + * Get the string contents of the option form. + */ + public function render(): string + { + if (!is_null($this->alwaysCallback)) { + call_user_func($this->alwaysCallback, $this); + } + + // attach submit button to the form + if (!$this->renderWithoutSubmitButton) { + $this->addButton([ + 'style' => 'primary', + 'text' => trans('general.submit'), + 'type' => 'submit', + 'name' => 'submit_'.$this->id, + ]); + } + + $this->assignValues(); + + return view('forms.form') + ->with(get_object_vars($this)) + ->render(); + } + + /** + * Get the string contents of the option form. + */ + public function __toString(): string + { + return $this->render(); + } +} + +class OptionFormItem +{ + public $id; + + public $name; + + public $hint; + + public $format; + + public $value = null; + + public $disabled; + + public $description; + + protected $parentId; + + public function __construct(string $id, $name = null) + { + $this->id = $id; + $this->name = $name; + } + + public function setParentId($id) + { + $this->parentId = $id; + + return $this; + } + + public function value($value) + { + $this->value = $value; + + return $this; + } + + public function hint($hintContent = OptionForm::AUTO_DETECT) + { + if ($hintContent == OptionForm::AUTO_DETECT) { + $hintContent = trans("options.$this->parentId.$this->id.hint"); + } + + $this->hint = view('forms.hint')->with('hint', $hintContent)->render(); + + return $this; + } + + public function format(callable $callback) + { + $this->format = $callback; + + return $this; + } + + public function disabled($disabled = 'disabled') + { + $this->disabled = $disabled; + + return $this; + } + + public function description($description = OptionForm::AUTO_DETECT) + { + if ($description == OptionForm::AUTO_DETECT) { + $description = trans("options.$this->parentId.$this->id.description"); + } + + $this->description = $description; + + return $this; + } +} + +class OptionFormText extends OptionFormItem +{ + protected $placeholder = ''; + + public function placeholder($placeholder = OptionForm::AUTO_DETECT) + { + if ($placeholder == OptionForm::AUTO_DETECT) { + $key = "options.$this->parentId.$this->id.placeholder"; + $placeholder = trans()->has($key) ? trans($key) : ''; + } + + $this->placeholder = $placeholder; + + return $this; + } + + public function render() + { + return view('forms.text')->with([ + 'id' => $this->id, + 'value' => $this->value, + 'disabled' => $this->disabled, + 'placeholder' => $this->placeholder, + ]); + } +} + +class OptionFormCheckbox extends OptionFormItem +{ + protected $label; + + public function label($label = OptionForm::AUTO_DETECT) + { + if ($label == OptionForm::AUTO_DETECT) { + $label = trans("options.$this->parentId.$this->id.label"); + } + + $this->label = $label; + + return $this; + } + + public function render() + { + return view('forms.checkbox')->with([ + 'id' => $this->id, + 'value' => $this->value, + 'label' => $this->label, + 'disabled' => $this->disabled, + ]); + } +} + +class OptionFormTextarea extends OptionFormItem +{ + protected $rows = 3; + + public function rows($rows) + { + $this->rows = $rows; + + return $this; + } + + public function render() + { + return view('forms.textarea')->with([ + 'id' => $this->id, + 'rows' => $this->rows, + 'value' => $this->value, + 'disabled' => $this->disabled, + ]); + } +} + +class OptionFormSelect extends OptionFormItem +{ + protected $options; + + public function option($value, $name) + { + $this->options[] = compact('value', 'name'); + + return $this; + } + + public function render() + { + return view('forms.select')->with([ + 'id' => $this->id, + 'options' => (array) $this->options, + 'selected' => $this->value, + 'disabled' => $this->disabled, + ]); + } +} + +class OptionFormGroup extends OptionFormItem +{ + public $items = []; + + public function text($id, $value = null, $placeholder = OptionForm::AUTO_DETECT) + { + if ($placeholder == OptionForm::AUTO_DETECT) { + $key = "options.$this->parentId.$this->id.placeholder"; + $placeholder = trans()->has($key) ? trans($key) : ''; + } + + $this->items[] = [ + 'type' => 'text', + 'id' => $id, + 'value' => $value, + 'placeholder' => $placeholder, + ]; + + return $this; + } + + public function addon($value = OptionForm::AUTO_DETECT) + { + if ($value == OptionForm::AUTO_DETECT) { + $value = trans("options.$this->parentId.$this->id.addon"); + } + + $this->items[] = ['type' => 'addon', 'id' => null, 'value' => $value]; + + return $this; + } + + public function render() + { + $rendered = []; + + foreach ($this->items as $item) { + $rendered[] = view('forms.'.$item['type'])->with([ + 'id' => $item['id'], + 'value' => $item['value'], + 'placeholder' => Arr::get($item, 'placeholder'), + ]); + } + + return view('forms.group')->with('items', $rendered); + } +} diff --git a/app/Services/Plugin.php b/app/Services/Plugin.php new file mode 100755 index 0000000..70f1c90 --- /dev/null +++ b/app/Services/Plugin.php @@ -0,0 +1,114 @@ +path = $path; + $this->manifest = $manifest; + } + + public function __get(string $name) + { + return $this->getManifestAttr(Str::snake($name, '-')); + } + + public function getManifest() + { + return $this->manifest; + } + + public function getManifestAttr(string $name, $default = null) + { + return Arr::get($this->manifest, $name, $default); + } + + public function assets(string $relativeUri): string + { + $baseUrl = config('plugins.url') ?: url('plugins'); + + return "$baseUrl/{$this->name}/assets/$relativeUri?v=".$this->version; + } + + public function getReadme() + { + return Arr::first( + self::README_FILES, + fn ($filename) => file_exists($this->path.'/'.$filename) + ); + } + + public function hasConfig(): bool + { + return $this->hasConfigClass() || $this->hasConfigView(); + } + + public function hasConfigClass(): bool + { + return Arr::has($this->manifest, 'enchants.config'); + } + + public function getConfigClass() + { + $name = Arr::get($this->manifest, 'enchants.config'); + + return Str::start($name, $this->manifest['namespace'].'\\'); + } + + public function getViewPath(string $filename): string + { + return $this->path."/views/$filename"; + } + + public function getConfigView() + { + return $this->hasConfigView() + ? view()->file($this->getViewPath(Arr::get($this->manifest, 'config', 'config.blade.php'))) + : null; + } + + public function hasConfigView(): bool + { + $filename = Arr::get($this->manifest, 'config', 'config.blade.php'); + + return $filename && file_exists($this->getViewPath($filename)); + } + + public function setEnabled(bool $enabled): self + { + $this->enabled = $enabled; + + return $this; + } + + public function isEnabled(): bool + { + return $this->enabled; + } + + public function getPath(): string + { + return $this->path; + } +} diff --git a/app/Services/PluginManager.php b/app/Services/PluginManager.php new file mode 100755 index 0000000..0a68fe2 --- /dev/null +++ b/app/Services/PluginManager.php @@ -0,0 +1,407 @@ +app = $app; + $this->option = $option; + $this->dispatcher = $dispatcher; + $this->filesystem = $filesystem; + $this->enabled = collect(); + $this->loader = new ClassLoader(); + } + + public function all(): Collection + { + if (isset($this->plugins)) { + return $this->plugins; + } + + $this->enabled = collect(json_decode($this->option->get('plugins_enabled', '[]'), true)) + ->reject(fn ($item) => is_string($item)) + ->mapWithKeys(fn ($item) => [$item['name'] => ['version' => $item['version']]]); + $plugins = collect(); + $versionChanged = []; + + $this->getPluginsDirs() + ->flatMap(fn ($dir) => $this->filesystem->directories($dir)) + ->unique() + ->filter(fn ($dir) => $this->filesystem->exists($dir.DIRECTORY_SEPARATOR.'package.json')) + ->each(function ($directory) use (&$plugins, &$versionChanged) { + $manifest = json_decode( + $this->filesystem->get($directory.DIRECTORY_SEPARATOR.'package.json'), + true + ); + + $name = $manifest['name']; + if ($plugins->has($name)) { + throw new PrettyPageException(trans('errors.plugins.duplicate', ['dir1' => $plugins->get($name)->getPath(), 'dir2' => $directory]), 5); + } + + $plugin = new Plugin($directory, $manifest); + $plugins->put($name, $plugin); + if ($this->getUnsatisfied($plugin)->isNotEmpty() || $this->getConflicts($plugin)->isNotEmpty()) { + $this->disable($plugin); + } + if ($this->enabled->has($name)) { + $plugin->setEnabled(true); + if (Comparator::notEqualTo( + $manifest['version'], + $this->enabled->get($name)['version'] + )) { + $this->enabled->put($name, ['version' => $manifest['version']]); + $versionChanged[] = $plugin; + } + } + }); + + $this->plugins = $plugins; + if (count($versionChanged) > 0) { + $this->saveEnabled(); + } + array_walk($versionChanged, function ($plugin) { + $this->dispatcher->dispatch('plugin.versionChanged', [$plugin]); + }); + + return $plugins; + } + + /** + * Boot all enabled plugins. + */ + public function boot() + { + if ($this->booted) { + return; + } + + $this->all()->each(fn ($plugin) => $this->loadViewsAndTranslations($plugin)); + + $enabled = $this->getEnabledPlugins(); + $enabled->each(fn ($plugin) => $this->registerPlugin($plugin)); + $this->loader->register(); + $enabled->each(fn ($plugin) => $this->bootPlugin($plugin)); + $this->registerLifecycleHooks(); + + $this->booted = true; + } + + /** + * Register resources of a plugin. + */ + public function registerPlugin(Plugin $plugin) + { + $this->registerAutoload($plugin); + $this->loadVendor($plugin); + } + + /** + * Boot a plugin. + */ + public function bootPlugin(Plugin $plugin) + { + $this->registerServiceProviders($plugin); + $this->loadBootstrapper($plugin); + } + + /** + * Register classes autoloading. + */ + protected function registerAutoload(Plugin $plugin) + { + $this->loader->addPsr4( + Str::finish($plugin->namespace, '\\'), + $plugin->getPath().'/src' + ); + } + + /** + * Load Composer dumped autoload file. + */ + protected function loadVendor(Plugin $plugin) + { + $path = $plugin->getPath().'/vendor/autoload.php'; + if ($this->filesystem->exists($path)) { + $this->filesystem->getRequire($path); + } + } + + /** + * Load views and translations. + */ + protected function loadViewsAndTranslations(Plugin $plugin) + { + $namespace = $plugin->namespace; + $path = $plugin->getPath(); + + $translations = $this->app->make('translation.loader'); + $translations->addNamespace($namespace, $path.'/lang'); + + $view = $this->app->make('view'); + $view->addNamespace($namespace, $path.'/views'); + } + + protected function registerServiceProviders(Plugin $plugin) + { + $providers = Arr::get($plugin->getManifest(), 'enchants.providers', []); + array_walk($providers, function ($provider) use ($plugin) { + $class = (string) Str::of($provider) + ->finish('ServiceProvider') + ->start($plugin->namespace.'\\'); + if (class_exists($class)) { + $this->app->register($class); + } + }); + } + + /** + * Load plugin's bootstrapper. + */ + protected function loadBootstrapper(Plugin $plugin) + { + $path = $plugin->getPath().'/bootstrap.php'; + if ($this->filesystem->exists($path)) { + try { + $this->app->call($this->filesystem->getRequire($path), ['plugin' => $plugin]); + } catch (\Throwable $th) { + report($th); + $this->dispatcher->dispatch(new Events\PluginBootFailed($plugin)); + // @codeCoverageIgnoreStart + if (config('app.debug')) { + throw $th; + } + // @codeCoverageIgnoreEnd + if (is_a($th, \Exception::class)) { + $handler = $this->app->make(\App\Exceptions\Handler::class); + if (!$handler->shouldReport($th)) { + throw $th; + } + } + } + } + } + + protected function registerLifecycleHooks() + { + $this->dispatcher->listen([ + Events\PluginWasEnabled::class, + Events\PluginWasDisabled::class, + Events\PluginWasDeleted::class, + ], function ($event) { + $plugin = $event->plugin; + $path = $plugin->getPath().'/callbacks.php'; + if ($this->filesystem->exists($path)) { + $callbacks = $this->filesystem->getRequire($path); + $callback = Arr::get($callbacks, get_class($event)); + if ($callback) { + return $this->app->call($callback, ['plugin' => $plugin]); + } + } + }); + } + + public function get(string $name): ?Plugin + { + return $this->all()->get($name); + } + + /** + * @return bool|array return `true` if succeeded, or return information if failed + */ + public function enable($plugin) + { + /** @var Plugin|null */ + $plugin = is_string($plugin) ? $this->get($plugin) : $plugin; + if (empty($plugin)) { + return false; + } + + if ($plugin->isEnabled()) { + return true; + } + + $unsatisfied = $this->getUnsatisfied($plugin); + $conflicts = $this->getConflicts($plugin); + if ($unsatisfied->isNotEmpty() || $conflicts->isNotEmpty()) { + return compact('unsatisfied', 'conflicts'); + } + + $this->enabled->put($plugin->name, ['version' => $plugin->version]); + $this->saveEnabled(); + + $plugin->setEnabled(true); + + $this->dispatcher->dispatch(new Events\PluginWasEnabled($plugin)); + + return true; + } + + public function disable($plugin) + { + /** @var Plugin|null */ + $plugin = is_string($plugin) ? $this->get($plugin) : $plugin; + if ($plugin && $plugin->isEnabled()) { + $this->enabled->pull($plugin->name); + $this->saveEnabled(); + + $plugin->setEnabled(false); + + $this->dispatcher->dispatch(new Events\PluginWasDisabled($plugin)); + } + } + + public function delete($plugin) + { + $plugin = is_string($plugin) ? $this->get($plugin) : $plugin; + if ($plugin) { + $this->disable($plugin); + + // dispatch event before deleting plugin files + $this->dispatcher->dispatch(new Events\PluginWasDeleted($plugin)); + + $this->filesystem->deleteDirectory($plugin->getPath()); + + $this->plugins->pull($plugin->name); + } + } + + public function getEnabledPlugins(): Collection + { + return $this->all()->filter(fn ($plugin) => $plugin->isEnabled()); + } + + /** + * Persist the currently enabled plugins. + */ + protected function saveEnabled() + { + $this->option->set( + 'plugins_enabled', + $this->enabled + ->map(fn ($info, $name) => array_merge(['name' => $name], $info)) + ->values() + ->toJson() + ); + } + + public function getUnsatisfied(Plugin $plugin) + { + return collect(Arr::get($plugin->getManifest(), 'require', [])) + ->mapWithKeys(function ($constraint, $name) { + if ($name == 'blessing-skin-server') { + $version = config('app.version'); + + return (!Semver::satisfies($version, $constraint)) + ? [$name => compact('version', 'constraint')] + : []; + } elseif ($name == 'php') { + preg_match('/(\d+\.\d+\.\d+)/', PHP_VERSION, $matches); + $version = $matches[1]; + + return (!Semver::satisfies($version, $constraint)) + ? [$name => compact('version', 'constraint')] + : []; + } elseif (!$this->enabled->has($name)) { + return [$name => ['version' => null, 'constraint' => $constraint]]; + } else { + $version = $this->enabled->get($name)['version']; + + return (!Semver::satisfies($version, $constraint)) + ? [$name => compact('version', 'constraint')] + : []; + } + }); + } + + public function getConflicts(Plugin $plugin): Collection + { + return collect($plugin->getManifestAttr('enchants.conflicts', [])) + ->mapWithKeys(function ($constraint, $name) { + $info = $this->enabled->get($name); + if ($info && Semver::satisfies($info['version'], $constraint)) { + return [$name => ['version' => $info['version'], 'constraint' => $constraint]]; + } else { + return []; + } + }); + } + + /** + * Format the "unresolved" information into human-readable text. + */ + public function formatUnresolved( + Collection $unsatisfied, + Collection $conflicts + ): array { + $unsatisfied = $unsatisfied->map(function ($detail, $name) { + if ($name === 'blessing-skin-server') { + $title = 'Blessing Skin Server'; + } elseif ($name === 'php') { + $title = 'PHP'; + } else { + $plugin = $this->get($name); + $title = $plugin ? trans($plugin->title) : $name; + } + + $constraint = $detail['constraint']; + + return $detail['version'] + ? trans('admin.plugins.operations.unsatisfied.version', compact('title', 'constraint')) + : trans('admin.plugins.operations.unsatisfied.disabled', ['name' => $title]); + })->values()->all(); + + $conflicts = $conflicts->map(function ($detail, $name) { + $title = trans($this->get($name)->title); + + return trans('admin.plugins.operations.unsatisfied.conflict', compact('title')); + })->values()->all(); + + return array_merge($unsatisfied, $conflicts); + } + + public function getPluginsDirs(): Collection + { + $config = config('plugins.directory'); + if ($config) { + return collect(preg_split('/,\s*/', $config)) + ->map(fn ($directory) => realpath($directory) ?: $directory); + } else { + return collect([base_path('plugins')]); + } + } +} diff --git a/app/Services/Translations/JavaScript.php b/app/Services/Translations/JavaScript.php new file mode 100755 index 0000000..2495845 --- /dev/null +++ b/app/Services/Translations/JavaScript.php @@ -0,0 +1,62 @@ +filesystem = $filesystem; + $this->cache = $cache; + $this->plugins = $plugins; + } + + public function generate(string $locale): string + { + $plugins = $this->plugins->getEnabledPlugins(); + $sourceFiles = $plugins + ->map(fn (Plugin $plugin) => $plugin->getPath()."/lang/$locale/front-end.yml") + ->filter(fn ($path) => $this->filesystem->exists($path)); + $sourceFiles->push(resource_path("lang/$locale/front-end.yml")); + $sourceModified = $sourceFiles->max(fn ($path) => $this->filesystem->lastModified($path)); + + $compiled = public_path("lang/$locale.js"); + $compiledModified = (int) $this->cache->get($this->prefix.$locale, 0); + + if ($sourceModified > $compiledModified || !$this->filesystem->exists($compiled)) { + $translations = trans('front-end'); + foreach ($plugins as $plugin) { + $translations[$plugin->name] = trans($plugin->namespace.'::front-end'); + } + + $content = 'blessing.i18n = '.json_encode($translations, JSON_UNESCAPED_UNICODE); + $this->filesystem->put($compiled, $content); + $this->cache->put($this->prefix.$locale, $sourceModified); + + return url()->asset("lang/$locale.js?t=$sourceModified"); + } + + return url()->asset("lang/$locale.js?t=$compiledModified"); + } + + public function resetTime(string $locale): void + { + $this->cache->put($this->prefix.$locale, 0); + } +} diff --git a/app/Services/Translations/Loader.php b/app/Services/Translations/Loader.php new file mode 100755 index 0000000..0b6ddb4 --- /dev/null +++ b/app/Services/Translations/Loader.php @@ -0,0 +1,19 @@ +files->exists($full) + ? resolve(Yaml::class)->parse($full) + : []; + } +} diff --git a/app/Services/Translations/Yaml.php b/app/Services/Translations/Yaml.php new file mode 100755 index 0000000..457290e --- /dev/null +++ b/app/Services/Translations/Yaml.php @@ -0,0 +1,35 @@ +cache = $cache; + } + + public function parse(string $path) + { + $prefix = $this->prefix.md5($path).'-'; + $cacheTime = intval($this->cache->get($prefix.'time', 0)); + $fileTime = filemtime($path); + + if ($fileTime > $cacheTime) { + $content = YamlParser::parseFile($path); + $this->cache->put($prefix.'content', $content); + $this->cache->put($prefix.'time', $fileTime); + + return $content; + } + + return $this->cache->get($prefix.'content', []); + } +} diff --git a/app/Services/Unzip.php b/app/Services/Unzip.php new file mode 100755 index 0000000..7032493 --- /dev/null +++ b/app/Services/Unzip.php @@ -0,0 +1,35 @@ +filesystem = $filesystem; + $this->zipper = $zipper; + } + + public function extract(string $file, string $destination): void + { + $zip = $this->zipper; + $resource = $zip->open($file); + + if ($resource === true && $zip->extractTo($destination)) { + $zip->close(); + $this->filesystem->delete($file); + } else { + throw new Exception(trans('admin.download.errors.unzip')); + } + } +} diff --git a/app/helpers.php b/app/helpers.php new file mode 100755 index 0000000..0f9ba1e --- /dev/null +++ b/app/helpers.php @@ -0,0 +1,85 @@ +get($name); + } +} + +if (!function_exists('plugin_assets')) { + /** @deprecated */ + function plugin_assets(string $name, string $relativeUri): string + { + $plugin = plugin($name); + if ($plugin) { + return $plugin->assets($relativeUri); + } else { + throw new InvalidArgumentException('No such plugin.'); + } + } +} + +if (!function_exists('json')) { + function json() + { + $args = func_get_args(); + + if (count($args) === 1 && is_array($args[0])) { + return response()->json($args[0]); + } elseif (count($args) === 3 && is_array($args[2])) { + // The third argument is array of extra fields + return response()->json([ + 'code' => $args[1], + 'message' => $args[0], + 'data' => $args[2], + ]); + } else { + return response()->json([ + 'code' => Arr::get($args, 1, 1), + 'message' => $args[0], + ]); + } + } +} + +if (!function_exists('option')) { + /** + * Get / set the specified option value. + * + * If an array is passed as the key, we will assume you want to set an array of values. + * + * @param array|string $key + * @param mixed $default + * @param bool $raw return raw value without convertion + * + * @return mixed + */ + function option($key = null, $default = null, $raw = false) + { + $options = app('options'); + + if (is_null($key)) { + return $options; + } + + if (is_array($key)) { + $options->set($key); + + return; + } + + return $options->get($key, $default, $raw); + } +} + +if (!function_exists('option_localized')) { + function option_localized($key = null, $default = null, $raw = false) + { + return option($key.'_'.config('app.locale'), option($key, $default), $raw); + } +} diff --git a/artisan b/artisan new file mode 100755 index 0000000..5c23e2e --- /dev/null +++ b/artisan @@ -0,0 +1,53 @@ +#!/usr/bin/env php +make(Illuminate\Contracts\Console\Kernel::class); + +$status = $kernel->handle( + $input = new Symfony\Component\Console\Input\ArgvInput, + new Symfony\Component\Console\Output\ConsoleOutput +); + +/* +|-------------------------------------------------------------------------- +| Shutdown The Application +|-------------------------------------------------------------------------- +| +| Once Artisan has finished running, we will fire off the shutdown events +| so that any final work may be done by the application before we shut +| down the process. This is the last thing to happen to the request. +| +*/ + +$kernel->terminate($input, $status); + +exit($status); diff --git a/bootstrap/app.php b/bootstrap/app.php new file mode 100755 index 0000000..037e17d --- /dev/null +++ b/bootstrap/app.php @@ -0,0 +1,55 @@ +singleton( + Illuminate\Contracts\Http\Kernel::class, + App\Http\Kernel::class +); + +$app->singleton( + Illuminate\Contracts\Console\Kernel::class, + App\Console\Kernel::class +); + +$app->singleton( + Illuminate\Contracts\Debug\ExceptionHandler::class, + App\Exceptions\Handler::class +); + +/* +|-------------------------------------------------------------------------- +| Return The Application +|-------------------------------------------------------------------------- +| +| This script returns the application instance. The instance is given to +| the calling script so we can separate the building of the instances +| from the actual running of the application and sending responses. +| +*/ + +return $app; diff --git a/bootstrap/cache/.gitignore b/bootstrap/cache/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/bootstrap/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/bootstrap/chkenv.php b/bootstrap/chkenv.php new file mode 100755 index 0000000..f9f5c8d --- /dev/null +++ b/bootstrap/chkenv.php @@ -0,0 +1,109 @@ +'. + '[错误] 根目录下未发现 vendor 文件夹,请使用正式的已构建好的 release 包。' + ); + } + + $envPath = __DIR__.'/../.env'; + if (!file_exists($envPath)) { + copy(__DIR__.'/../.env.example', $envPath); + } + + $envFile = file_get_contents($envPath); + if (preg_match('/APP_KEY\s*=\s*\n/', $envFile)) { + $key = 'base64:'.base64_encode(Encrypter::generateKey('AES-256-CBC')); + file_put_contents($envPath, preg_replace('/APP_KEY\s*=\s*/', 'APP_KEY='.$key."\n\n", $envFile)); + } + + $requiredFunctions = ['symlink', 'readlink', 'putenv', 'realpath']; + $disabledFunctions = preg_split('/,\s*/', ini_get('disable_functions')); + foreach ($requiredFunctions as $fn) { + if (in_array($fn, $disabledFunctions)) { + die_with_utf8_encoding( + '[Error] Please don\'t disable built-in function "'.$fn.'", which is specified in "php.ini" file.
'. + "[错误] 请不要在 php.ini 中禁用 $fn 函数。". + '我们不建议使用您使用宝塔等面板软件,因为容易引起兼容性问题。' + ); + } + } + + if (!empty(ini_get('open_basedir'))) { + die_with_utf8_encoding( + '[Error] Please disable "open_basedir" option by editing "php.ini" file.
'. + '[错误] 请修改 php.ini 以关闭 "open_basedir" 选项。'. + '我们不建议使用您使用宝塔等面板软件,因为容易引起兼容性问题。' + ); + } + + $requiredVersion = '8.0.2'; + preg_match('/(\d+\.\d+\.\d+)/', PHP_VERSION, $matches); + $version = $matches[1]; + if (version_compare($version, $requiredVersion, '<')) { + die_with_utf8_encoding( + '[Error] Blessing Skin requires PHP version >= '.$requiredVersion.', you are now using '.$version.'
'. + '[错误] 你的 PHP 版本过低('.$version.'),Blessing Skin 要求至少为 '.$requiredVersion + ); + } + + $requirements = [ + 'extensions' => [ + 'pdo', + 'openssl', + 'gd', + 'mbstring', + 'tokenizer', + 'ctype', + 'xml', + 'json', + 'fileinfo', + 'zip', + ], + 'write_permission' => [ + 'bootstrap/cache', + 'storage', + 'plugins', + 'public', + ], + ]; + + foreach ($requirements['extensions'] as $extension) { + if (!extension_loaded($extension)) { + die_with_utf8_encoding( + "[Error] You have not installed the $extension extension
". + "[错误] 你尚未安装 $extension 扩展!安装方法请自行搜索。" + ); + } + } + + foreach ($requirements['write_permission'] as $dir) { + $realPath = realpath(__DIR__."/../$dir"); + + if (!is_writable($realPath)) { + die_with_utf8_encoding( + "[Error] The directory '$dir' is not writable.
". + "[错误] 目录 '$dir' 不可写,请检查该目录的权限。" + ); + } + + if (!is_writable($realPath)) { + die_with_utf8_encoding( + "[Error] The program lacks write permission to directory '$dir'
". + "[错误] 程序缺少对 '$dir' 目录的写权限,请手动授权。" + ); + } + } +})(); diff --git a/config/app.php b/config/app.php new file mode 100755 index 0000000..4b77856 --- /dev/null +++ b/config/app.php @@ -0,0 +1,233 @@ + '6.0.2', + + /* + |-------------------------------------------------------------------------- + | Update Source + |-------------------------------------------------------------------------- + | + | Where to get information of new versions. + | + */ + 'update_source' => env( + 'UPDATE_SOURCE', + 'https://dev.azure.com/blessing-skin/51010f6d-9f99-40f1-a262-0a67f788df32/_apis/git/'. + 'repositories/a9ff8df7-6dc3-4ff8-bb22-4871d3a43936/Items?path=%2Fupdate.json' + ), + + 'name' => env('APP_NAME', 'blessing_skin'), + + /* + |-------------------------------------------------------------------------- + | Application Environment + |-------------------------------------------------------------------------- + | + | This value determines the "environment" your application is currently + | running in. This may determine how you prefer to configure various + | services the application utilizes. Set this in your ".env" file. + | + */ + + 'env' => env('APP_ENV', 'production'), + + /* + |-------------------------------------------------------------------------- + | Application Debug Mode + |-------------------------------------------------------------------------- + | + | When your application is in debug mode, detailed error messages with + | stack traces will be shown on every error that occurs within your + | application. If disabled, a simple generic error page is shown. + | + */ + + 'debug' => (bool) env('APP_DEBUG', false), + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | your application so that it is used when running Artisan tasks. + | + */ + + 'url' => env('APP_URL', 'http://localhost'), + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. We have gone + | ahead and set this to a sensible default for you out of the box. + | + */ + + 'timezone' => 'Asia/Shanghai', + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by the translation service provider. You are free to set this value + | to any of the locales which will be supported by the application. + | + */ + + 'locale' => 'zh_CN', + + /* + |-------------------------------------------------------------------------- + | Application Fallback Locale + |-------------------------------------------------------------------------- + | + | The fallback locale determines the locale to use when the current one + | is not available. You may change the value to correspond to any of + | the language folders that are provided through your application. + | + */ + + 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), + + /* + |-------------------------------------------------------------------------- + | Faker Locale + |-------------------------------------------------------------------------- + | + | This locale will be used by the Faker PHP library when generating fake + | data for your database seeds. For example, this will be used to get + | localized telephone numbers, street address information and more. + | + */ + + 'faker_locale' => 'en_US', + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is used by the Illuminate encrypter service and should be set + | to a random, 32 character string, otherwise these encrypted strings + | will not be safe. Please do this before deploying an application! + | + */ + + 'key' => env('APP_KEY'), + + 'cipher' => 'AES-256-CBC', + + /* + |-------------------------------------------------------------------------- + | Autoloaded Service Providers + |-------------------------------------------------------------------------- + | + | The service providers listed here will be automatically loaded on the + | request to your application. Feel free to add your own services to + | this array to grant expanded functionality to your applications. + | + */ + + 'providers' => [ + + /* + * Laravel Framework Service Providers... + */ + Illuminate\Auth\AuthServiceProvider::class, + Illuminate\Bus\BusServiceProvider::class, + Illuminate\Cache\CacheServiceProvider::class, + Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, + Illuminate\Cookie\CookieServiceProvider::class, + Illuminate\Database\DatabaseServiceProvider::class, + Illuminate\Encryption\EncryptionServiceProvider::class, + Illuminate\Filesystem\FilesystemServiceProvider::class, + Illuminate\Foundation\Providers\FoundationServiceProvider::class, + Illuminate\Hashing\HashServiceProvider::class, + Illuminate\Mail\MailServiceProvider::class, + Illuminate\Notifications\NotificationServiceProvider::class, + Illuminate\Pagination\PaginationServiceProvider::class, + Illuminate\Queue\QueueServiceProvider::class, + Illuminate\Redis\RedisServiceProvider::class, + Illuminate\Session\SessionServiceProvider::class, + Illuminate\Validation\ValidationServiceProvider::class, + Illuminate\View\ViewServiceProvider::class, + + /* + * Application Service Providers... + */ + App\Providers\AppServiceProvider::class, + App\Providers\AuthServiceProvider::class, + App\Providers\EventServiceProvider::class, + App\Providers\PluginServiceProvider::class, + App\Providers\RouteServiceProvider::class, + App\Providers\ViewServiceProvider::class, + ], + + /* + |-------------------------------------------------------------------------- + | Class Aliases + |-------------------------------------------------------------------------- + | + | This array of class aliases will be registered when this application + | is started. However, feel free to register as many as you wish as + | the aliases are "lazy" loaded so they don't hinder performance. + | + */ + + 'aliases' => [ + + 'App' => Illuminate\Support\Facades\App::class, + 'Artisan' => Illuminate\Support\Facades\Artisan::class, + 'Auth' => Illuminate\Support\Facades\Auth::class, + 'Blade' => Illuminate\Support\Facades\Blade::class, + 'Cache' => Illuminate\Support\Facades\Cache::class, + 'Config' => Illuminate\Support\Facades\Config::class, + 'Cookie' => Illuminate\Support\Facades\Cookie::class, + 'Crypt' => Illuminate\Support\Facades\Crypt::class, + 'DB' => Illuminate\Support\Facades\DB::class, + 'Eloquent' => Illuminate\Database\Eloquent\Model::class, + 'Event' => Illuminate\Support\Facades\Event::class, + 'File' => Illuminate\Support\Facades\File::class, + 'Gate' => Illuminate\Support\Facades\Gate::class, + 'Hash' => Illuminate\Support\Facades\Hash::class, + 'Http' => Illuminate\Support\Facades\Http::class, + 'Lang' => Illuminate\Support\Facades\Lang::class, + 'Log' => Illuminate\Support\Facades\Log::class, + 'Mail' => Illuminate\Support\Facades\Mail::class, + 'Notification' => Illuminate\Support\Facades\Notification::class, + 'Password' => Illuminate\Support\Facades\Password::class, + 'Queue' => Illuminate\Support\Facades\Queue::class, + 'Redirect' => Illuminate\Support\Facades\Redirect::class, + 'Request' => Illuminate\Support\Facades\Request::class, + 'Response' => Illuminate\Support\Facades\Response::class, + 'Route' => Illuminate\Support\Facades\Route::class, + 'Schema' => Illuminate\Support\Facades\Schema::class, + 'Session' => Illuminate\Support\Facades\Session::class, + 'Storage' => Illuminate\Support\Facades\Storage::class, + 'URL' => Illuminate\Support\Facades\URL::class, + 'Validator' => Illuminate\Support\Facades\Validator::class, + 'View' => Illuminate\Support\Facades\View::class, + + /* + * Blessing Skin + */ + 'Option' => App\Services\Facades\Option::class, + ], + +]; diff --git a/config/auth.php b/config/auth.php new file mode 100755 index 0000000..19dd93c --- /dev/null +++ b/config/auth.php @@ -0,0 +1,107 @@ + [ + 'guard' => 'web', + 'passwords' => 'users', + ], + + /* + |-------------------------------------------------------------------------- + | Authentication Guards + |-------------------------------------------------------------------------- + | + | Next, you may define every authentication guard for your application. + | Of course, a great default configuration has been defined for you + | here which uses session storage and the Eloquent user provider. + | + | All authentication drivers have a user provider. This defines how the + | users are actually retrieved out of your database or other storage + | mechanisms used by this application to persist your user's data. + | + | Supported: "session", "token" + | + */ + + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + + 'jwt' => [ + 'driver' => 'jwt', + 'provider' => 'users', + ], + + 'oauth' => [ + 'driver' => 'passport', + 'provider' => 'users', + ], + ], + + /* + |-------------------------------------------------------------------------- + | User Providers + |-------------------------------------------------------------------------- + | + | All authentication drivers have a user provider. This defines how the + | users are actually retrieved out of your database or other storage + | mechanisms used by this application to persist your user's data. + | + | If you have multiple user tables or models you may configure multiple + | sources which represent each model / table. These sources may then + | be assigned to any extra authentication guards you have defined. + | + | Supported: "database", "eloquent" + | + */ + + 'providers' => [ + 'users' => [ + 'driver' => 'eloquent', + 'model' => App\Models\User::class, + ], + + // 'users' => [ + // 'driver' => 'database', + // 'table' => 'users', + // ], + ], + + /* + |-------------------------------------------------------------------------- + | Resetting Passwords + |-------------------------------------------------------------------------- + | + | You may specify multiple password reset configurations if you have more + | than one user table or model in the application and you want to have + | separate password reset settings based on the specific user types. + | + | The expire time is the number of minutes that the reset token should be + | considered valid. This security feature keeps tokens short-lived so + | they have less time to be guessed. You may change this as needed. + | + */ + + 'passwords' => [ + 'users' => [ + 'provider' => 'users', + 'table' => 'password_resets', + 'expire' => 60, + ], + ], + +]; diff --git a/config/broadcasting.php b/config/broadcasting.php new file mode 100755 index 0000000..3bba110 --- /dev/null +++ b/config/broadcasting.php @@ -0,0 +1,59 @@ + env('BROADCAST_DRIVER', 'null'), + + /* + |-------------------------------------------------------------------------- + | Broadcast Connections + |-------------------------------------------------------------------------- + | + | Here you may define all of the broadcast connections that will be used + | to broadcast events to other systems or over websockets. Samples of + | each available type of connection are provided inside this array. + | + */ + + 'connections' => [ + + 'pusher' => [ + 'driver' => 'pusher', + 'key' => env('PUSHER_APP_KEY'), + 'secret' => env('PUSHER_APP_SECRET'), + 'app_id' => env('PUSHER_APP_ID'), + 'options' => [ + 'cluster' => env('PUSHER_APP_CLUSTER'), + 'useTLS' => true, + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + ], + + 'log' => [ + 'driver' => 'log', + ], + + 'null' => [ + 'driver' => 'null', + ], + + ], + +]; diff --git a/config/cache.php b/config/cache.php new file mode 100755 index 0000000..34f171d --- /dev/null +++ b/config/cache.php @@ -0,0 +1,104 @@ + env('CACHE_DRIVER', 'file'), + + /* + |-------------------------------------------------------------------------- + | Cache Stores + |-------------------------------------------------------------------------- + | + | Here you may define all of the cache "stores" for your application as + | well as their drivers. You may even define multiple stores for the + | same cache driver to group types of items stored in your caches. + | + */ + + 'stores' => [ + + 'apc' => [ + 'driver' => 'apc', + ], + + 'array' => [ + 'driver' => 'array', + 'serialize' => false, + ], + + 'database' => [ + 'driver' => 'database', + 'table' => 'cache', + 'connection' => null, + ], + + 'file' => [ + 'driver' => 'file', + 'path' => storage_path('framework/cache/data'), + ], + + 'memcached' => [ + 'driver' => 'memcached', + 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), + 'sasl' => [ + env('MEMCACHED_USERNAME'), + env('MEMCACHED_PASSWORD'), + ], + 'options' => [ + // Memcached::OPT_CONNECT_TIMEOUT => 2000, + ], + 'servers' => [ + [ + 'host' => env('MEMCACHED_HOST', '127.0.0.1'), + 'port' => env('MEMCACHED_PORT', 11211), + 'weight' => 100, + ], + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'cache', + ], + + 'dynamodb' => [ + 'driver' => 'dynamodb', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), + 'endpoint' => env('DYNAMODB_ENDPOINT'), + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing a RAM based store such as APC or Memcached, there might + | be other applications utilizing the same cache. So, we'll specify a + | value to get prefixed to all our keys so we can avoid collisions. + | + */ + + 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'blessing_skin'), '_').'_cache'), + +]; diff --git a/config/database.php b/config/database.php new file mode 100755 index 0000000..f46b37b --- /dev/null +++ b/config/database.php @@ -0,0 +1,147 @@ + env('DB_CONNECTION', 'mysql'), + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Here are each of the database connections setup for your application. + | Of course, examples of configuring each database platform that is + | supported by Laravel is shown below to make development simple. + | + | + | All database work in Laravel is done through the PHP PDO facilities + | so make sure you have the driver for your particular database of + | choice installed on your machine before you begin development. + | + */ + + 'connections' => [ + + 'sqlite' => [ + 'driver' => 'sqlite', + 'url' => env('DATABASE_URL'), + 'database' => env('DB_DATABASE', database_path('database.sqlite')), + 'prefix' => env('DB_PREFIX', ''), + 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), + ], + + 'mysql' => [ + 'driver' => 'mysql', + 'url' => env('DATABASE_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => env('DB_PREFIX', ''), + 'prefix_indexes' => true, + 'strict' => false, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'pgsql' => [ + 'driver' => 'pgsql', + 'url' => env('DATABASE_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '5432'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8', + 'prefix' => env('DB_PREFIX', ''), + 'prefix_indexes' => true, + 'schema' => 'public', + 'sslmode' => 'prefer', + ], + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'url' => env('DATABASE_URL'), + 'host' => env('DB_HOST', 'localhost'), + 'port' => env('DB_PORT', '1433'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8', + 'prefix' => env('DB_PREFIX', ''), + 'prefix_indexes' => true, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run in the database. + | + */ + + 'migrations' => 'migrations', + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer body of commands than a typical key-value system + | such as APC or Memcached. Laravel makes it easy to dig right in. + | + */ + + 'redis' => [ + + 'client' => env('REDIS_CLIENT', 'phpredis'), + + 'options' => [ + 'cluster' => env('REDIS_CLUSTER', 'redis'), + 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'blessing_skin'), '_').'_database_'), + ], + + 'default' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_DB', '0'), + ], + + 'cache' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_CACHE_DB', '1'), + ], + + ], + +]; diff --git a/config/debugbar.php b/config/debugbar.php new file mode 100755 index 0000000..5e080d2 --- /dev/null +++ b/config/debugbar.php @@ -0,0 +1,201 @@ + env('DEBUGBAR_ENABLED', null), + 'except' => [ + // + ], + + /* + |-------------------------------------------------------------------------- + | Storage settings + |-------------------------------------------------------------------------- + | + | DebugBar stores data for session/ajax requests. + | You can disable this, so the debugbar stores data in headers/session, + | but this can cause problems with large data collectors. + | By default, file storage (in the storage folder) is used. Redis and PDO + | can also be used. For PDO, run the package migrations first. + | + */ + 'storage' => [ + 'enabled' => true, + 'driver' => 'file', // redis, file, pdo, custom + 'path' => storage_path('debugbar'), // For file driver + 'connection' => null, // Leave null for default connection (Redis/PDO) + 'provider' => '', // Instance of StorageInterface for custom driver + ], + + /* + |-------------------------------------------------------------------------- + | Vendors + |-------------------------------------------------------------------------- + | + | Vendor files are included by default, but can be set to false. + | This can also be set to 'js' or 'css', to only include javascript or css vendor files. + | Vendor files are for css: font-awesome (including fonts) and highlight.js (css files) + | and for js: jquery and and highlight.js + | So if you want syntax highlighting, set it to true. + | jQuery is set to not conflict with existing jQuery scripts. + | + */ + + 'include_vendors' => true, + + /* + |-------------------------------------------------------------------------- + | Capture Ajax Requests + |-------------------------------------------------------------------------- + | + | The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors), + | you can use this option to disable sending the data through the headers. + | + | Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools. + */ + + 'capture_ajax' => true, + 'add_ajax_timing' => false, + + /* + |-------------------------------------------------------------------------- + | Custom Error Handler for Deprecated warnings + |-------------------------------------------------------------------------- + | + | When enabled, the Debugbar shows deprecated warnings for Symfony components + | in the Messages tab. + | + */ + 'error_handler' => false, + + /* + |-------------------------------------------------------------------------- + | Clockwork integration + |-------------------------------------------------------------------------- + | + | The Debugbar can emulate the Clockwork headers, so you can use the Chrome + | Extension, without the server-side code. It uses Debugbar collectors instead. + | + */ + 'clockwork' => false, + + /* + |-------------------------------------------------------------------------- + | DataCollectors + |-------------------------------------------------------------------------- + | + | Enable/disable DataCollectors + | + */ + + 'collectors' => [ + 'phpinfo' => true, // Php version + 'messages' => true, // Messages + 'time' => true, // Time Datalogger + 'memory' => true, // Memory usage + 'exceptions' => true, // Exception displayer + 'log' => true, // Logs from Monolog (merged in messages if enabled) + 'db' => true, // Show database (PDO) queries and bindings + 'views' => true, // Views with their data + 'route' => true, // Current route information + 'auth' => true, // Display Laravel authentication status + 'gate' => false, // Display Laravel Gate checks + 'session' => true, // Display session data + 'symfony_request' => true, // Only one can be enabled.. + 'mail' => false, // Catch mail messages + 'laravel' => false, // Laravel version and environment + 'events' => true, // All events fired + 'default_request' => false, // Regular or special Symfony request logger + 'logs' => false, // Add the latest log messages + 'files' => false, // Show the included files + 'config' => false, // Display config settings + 'cache' => false, // Display cache events + ], + + /* + |-------------------------------------------------------------------------- + | Extra options + |-------------------------------------------------------------------------- + | + | Configure some DataCollectors + | + */ + + 'options' => [ + 'auth' => [ + 'show_name' => true, // Also show the users name/email in the debugbar + ], + 'db' => [ + 'with_params' => true, // Render SQL with the parameters substituted + 'backtrace' => true, // Use a backtrace to find the origin of the query in your files. + 'timeline' => false, // Add the queries to the timeline + 'explain' => [ // Show EXPLAIN output on queries + 'enabled' => false, + 'types' => ['SELECT'], // ['SELECT', 'INSERT', 'UPDATE', 'DELETE']; for MySQL 5.6.3+ + ], + 'hints' => true, // Show hints for common mistakes + ], + 'mail' => [ + 'full_log' => false, + ], + 'views' => [ + 'data' => false, //Note: Can slow down the application, because the data can be quite large.. + ], + 'route' => [ + 'label' => true, // show complete route on bar + ], + 'logs' => [ + 'file' => null, + ], + 'cache' => [ + 'values' => true, // collect cache values + ], + ], + + /* + |-------------------------------------------------------------------------- + | Inject Debugbar in Response + |-------------------------------------------------------------------------- + | + | Usually, the debugbar is added just before , by listening to the + | Response after the App is done. If you disable this, you have to add them + | in your template yourself. See http://phpdebugbar.com/docs/rendering.html + | + */ + + 'inject' => true, + + /* + |-------------------------------------------------------------------------- + | DebugBar route prefix + |-------------------------------------------------------------------------- + | + | Sometimes you want to set route prefix to be used by DebugBar to load + | its resources from. Usually the need comes from misconfigured web server or + | from trying to overcome bugs like this: http://trac.nginx.org/nginx/ticket/97 + | + */ + 'route_prefix' => '_debugbar', + + /* + |-------------------------------------------------------------------------- + | DebugBar route domain + |-------------------------------------------------------------------------- + | + | By default DebugBar route served from the same domain that request served. + | To override default domain, specify it as a non-empty value. + */ + 'route_domain' => null, +]; diff --git a/config/filesystems.php b/config/filesystems.php new file mode 100755 index 0000000..158a769 --- /dev/null +++ b/config/filesystems.php @@ -0,0 +1,67 @@ + env('FILESYSTEM_DRIVER', 'local'), + + /* + |-------------------------------------------------------------------------- + | Default Cloud Filesystem Disk + |-------------------------------------------------------------------------- + | + | Many applications store files both locally and in the cloud. For this + | reason, you may specify a default "cloud" driver here. This driver + | will be bound as the Cloud disk implementation in the container. + | + */ + + 'cloud' => env('FILESYSTEM_CLOUD', 's3'), + + /* + |-------------------------------------------------------------------------- + | Filesystem Disks + |-------------------------------------------------------------------------- + | + | Here you may configure as many filesystem "disks" as you wish, and you + | may even configure multiple disks of the same driver. Defaults have + | been setup for each driver as an example of the required options. + | + | Supported Drivers: "local", "ftp", "sftp", "s3" + | + */ + + 'disks' => [ + + 'local' => [ + 'driver' => 'local', + 'root' => storage_path('app'), + ], + + 'root' => [ + 'driver' => 'local', + 'root' => base_path(), + ], + + 'textures' => [ + 'driver' => env('FS_DRIVER', 'local'), + 'root' => env('TEXTURES_DIR', storage_path('textures')), + ], + + 'testing' => [ + 'driver' => 'memory', + ], + + ], + +]; diff --git a/config/hashing.php b/config/hashing.php new file mode 100755 index 0000000..8425770 --- /dev/null +++ b/config/hashing.php @@ -0,0 +1,52 @@ + 'bcrypt', + + /* + |-------------------------------------------------------------------------- + | Bcrypt Options + |-------------------------------------------------------------------------- + | + | Here you may specify the configuration options that should be used when + | passwords are hashed using the Bcrypt algorithm. This will allow you + | to control the amount of time it takes to hash the given password. + | + */ + + 'bcrypt' => [ + 'rounds' => env('BCRYPT_ROUNDS', 10), + ], + + /* + |-------------------------------------------------------------------------- + | Argon Options + |-------------------------------------------------------------------------- + | + | Here you may specify the configuration options that should be used when + | passwords are hashed using the Argon algorithm. These will allow you + | to control the amount of time it takes to hash the given password. + | + */ + + 'argon' => [ + 'memory' => 1024, + 'threads' => 2, + 'time' => 2, + ], + +]; diff --git a/config/jwt.php b/config/jwt.php new file mode 100755 index 0000000..900ce98 --- /dev/null +++ b/config/jwt.php @@ -0,0 +1,304 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + + /* + |-------------------------------------------------------------------------- + | JWT Authentication Secret + |-------------------------------------------------------------------------- + | + | Don't forget to set this in your .env file, as it will be used to sign + | your tokens. A helper command is provided for this: + | `php artisan jwt:secret` + | + | Note: This will be used for Symmetric algorithms only (HMAC), + | since RSA and ECDSA use a private/public key combo (See below). + | + */ + + 'secret' => env('JWT_SECRET'), + + /* + |-------------------------------------------------------------------------- + | JWT Authentication Keys + |-------------------------------------------------------------------------- + | + | The algorithm you are using, will determine whether your tokens are + | signed with a random string (defined in `JWT_SECRET`) or using the + | following public & private keys. + | + | Symmetric Algorithms: + | HS256, HS384 & HS512 will use `JWT_SECRET`. + | + | Asymmetric Algorithms: + | RS256, RS384 & RS512 / ES256, ES384 & ES512 will use the keys below. + | + */ + + 'keys' => [ + + /* + |-------------------------------------------------------------------------- + | Public Key + |-------------------------------------------------------------------------- + | + | A path or resource to your public key. + | + | E.g. 'file://path/to/public/key' + | + */ + + 'public' => env('JWT_PUBLIC_KEY'), + + /* + |-------------------------------------------------------------------------- + | Private Key + |-------------------------------------------------------------------------- + | + | A path or resource to your private key. + | + | E.g. 'file://path/to/private/key' + | + */ + + 'private' => env('JWT_PRIVATE_KEY'), + + /* + |-------------------------------------------------------------------------- + | Passphrase + |-------------------------------------------------------------------------- + | + | The passphrase for your private key. Can be null if none set. + | + */ + + 'passphrase' => env('JWT_PASSPHRASE'), + + ], + + /* + |-------------------------------------------------------------------------- + | JWT time to live + |-------------------------------------------------------------------------- + | + | Specify the length of time (in minutes) that the token will be valid for. + | Defaults to 1 hour. + | + | You can also set this to null, to yield a never expiring token. + | Some people may want this behaviour for e.g. a mobile app. + | This is not particularly recommended, so make sure you have appropriate + | systems in place to revoke the token if necessary. + | Notice: If you set this to null you should remove 'exp' element from 'required_claims' list. + | + */ + + 'ttl' => env('JWT_TTL', 60), + + /* + |-------------------------------------------------------------------------- + | Refresh time to live + |-------------------------------------------------------------------------- + | + | Specify the length of time (in minutes) that the token can be refreshed + | within. I.E. The user can refresh their token within a 2 week window of + | the original token being created until they must re-authenticate. + | Defaults to 2 weeks. + | + | You can also set this to null, to yield an infinite refresh time. + | Some may want this instead of never expiring tokens for e.g. a mobile app. + | This is not particularly recommended, so make sure you have appropriate + | systems in place to revoke the token if necessary. + | + */ + + 'refresh_ttl' => env('JWT_REFRESH_TTL', 20160), + + /* + |-------------------------------------------------------------------------- + | JWT hashing algorithm + |-------------------------------------------------------------------------- + | + | Specify the hashing algorithm that will be used to sign the token. + | + | See here: https://github.com/namshi/jose/tree/master/src/Namshi/JOSE/Signer/OpenSSL + | for possible values. + | + */ + + 'algo' => env('JWT_ALGO', 'HS256'), + + /* + |-------------------------------------------------------------------------- + | Required Claims + |-------------------------------------------------------------------------- + | + | Specify the required claims that must exist in any token. + | A TokenInvalidException will be thrown if any of these claims are not + | present in the payload. + | + */ + + 'required_claims' => [ + 'iss', + 'iat', + 'exp', + 'nbf', + 'sub', + 'jti', + ], + + /* + |-------------------------------------------------------------------------- + | Persistent Claims + |-------------------------------------------------------------------------- + | + | Specify the claim keys to be persisted when refreshing a token. + | `sub` and `iat` will automatically be persisted, in + | addition to the these claims. + | + | Note: If a claim does not exist then it will be ignored. + | + */ + + 'persistent_claims' => [ + // 'foo', + // 'bar', + ], + + /* + |-------------------------------------------------------------------------- + | Lock Subject + |-------------------------------------------------------------------------- + | + | This will determine whether a `prv` claim is automatically added to + | the token. The purpose of this is to ensure that if you have multiple + | authentication models e.g. `App\User` & `App\OtherPerson`, then we + | should prevent one authentication request from impersonating another, + | if 2 tokens happen to have the same id across the 2 different models. + | + | Under specific circumstances, you may want to disable this behaviour + | e.g. if you only have one authentication model, then you would save + | a little on token size. + | + */ + + 'lock_subject' => true, + + /* + |-------------------------------------------------------------------------- + | Leeway + |-------------------------------------------------------------------------- + | + | This property gives the jwt timestamp claims some "leeway". + | Meaning that if you have any unavoidable slight clock skew on + | any of your servers then this will afford you some level of cushioning. + | + | This applies to the claims `iat`, `nbf` and `exp`. + | + | Specify in seconds - only if you know you need it. + | + */ + + 'leeway' => env('JWT_LEEWAY', 0), + + /* + |-------------------------------------------------------------------------- + | Blacklist Enabled + |-------------------------------------------------------------------------- + | + | In order to invalidate tokens, you must have the blacklist enabled. + | If you do not want or need this functionality, then set this to false. + | + */ + + 'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true), + + /* + | ------------------------------------------------------------------------- + | Blacklist Grace Period + | ------------------------------------------------------------------------- + | + | When multiple concurrent requests are made with the same JWT, + | it is possible that some of them fail, due to token regeneration + | on every request. + | + | Set grace period in seconds to prevent parallel request failure. + | + */ + + 'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 0), + + /* + |-------------------------------------------------------------------------- + | Cookies encryption + |-------------------------------------------------------------------------- + | + | By default Laravel encrypt cookies for security reason. + | If you decide to not decrypt cookies, you will have to configure Laravel + | to not encrypt your cookie token by adding its name into the $except + | array available in the middleware "EncryptCookies" provided by Laravel. + | see https://laravel.com/docs/master/responses#cookies-and-encryption + | for details. + | + | Set it to true if you want to decrypt cookies. + | + */ + + 'decrypt_cookies' => false, + + /* + |-------------------------------------------------------------------------- + | Providers + |-------------------------------------------------------------------------- + | + | Specify the various providers used throughout the package. + | + */ + + 'providers' => [ + + /* + |-------------------------------------------------------------------------- + | JWT Provider + |-------------------------------------------------------------------------- + | + | Specify the provider that is used to create and decode the tokens. + | + */ + + 'jwt' => Tymon\JWTAuth\Providers\JWT\Namshi::class, + + /* + |-------------------------------------------------------------------------- + | Authentication Provider + |-------------------------------------------------------------------------- + | + | Specify the provider that is used to authenticate users. + | + */ + + 'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class, + + /* + |-------------------------------------------------------------------------- + | Storage Provider + |-------------------------------------------------------------------------- + | + | Specify the provider that is used to store tokens in the blacklist. + | + */ + + 'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class, + + ], + +]; diff --git a/config/locales.php b/config/locales.php new file mode 100755 index 0000000..5a77789 --- /dev/null +++ b/config/locales.php @@ -0,0 +1,41 @@ + [ + 'name' => '中文 (简体)', + 'short_name' => 'zh-CN', + ], + 'zh_HANS_CN' => [ + 'alias' => 'zh_CN', + ], + 'zh_TW' => [ + 'name' => '中文 (正體)', + 'short_name' => 'zh-TW', + ], + 'en' => [ + 'name' => 'English', + 'short_name' => 'en', + ], + 'en_US' => [ + 'alias' => 'en', + ], + 'es_ES' => [ + 'name' => 'Español', + 'short_name' => 'es' + ], + 'ru' => [ + 'alias' => 'ru_RU', + ], + 'ru_RU' => [ + 'name' => 'Русский язык', + 'short_name' => 'ru', + ], +]; diff --git a/config/logging.php b/config/logging.php new file mode 100755 index 0000000..1f06d5e --- /dev/null +++ b/config/logging.php @@ -0,0 +1,104 @@ + env('LOG_CHANNEL', 'daily'), + + /* + |-------------------------------------------------------------------------- + | Log Channels + |-------------------------------------------------------------------------- + | + | Here you may configure the log channels for your application. Out of + | the box, Laravel uses the Monolog PHP logging library. This gives + | you a variety of powerful log handlers / formatters to utilize. + | + | Available Drivers: "single", "daily", "slack", "syslog", + | "errorlog", "monolog", + | "custom", "stack" + | + */ + + 'channels' => [ + 'stack' => [ + 'driver' => 'stack', + 'channels' => ['single'], + 'ignore_exceptions' => false, + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel.log'), + 'level' => 'debug', + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/laravel.log'), + 'level' => 'debug', + 'days' => 14, + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => 'Laravel Log', + 'emoji' => ':boom:', + 'level' => 'critical', + ], + + 'papertrail' => [ + 'driver' => 'monolog', + 'level' => 'debug', + 'handler' => SyslogUdpHandler::class, + 'handler_with' => [ + 'host' => env('PAPERTRAIL_URL'), + 'port' => env('PAPERTRAIL_PORT'), + ], + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'handler' => StreamHandler::class, + 'formatter' => env('LOG_STDERR_FORMATTER'), + 'with' => [ + 'stream' => 'php://stderr', + ], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => 'debug', + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => 'debug', + ], + + 'null' => [ + 'driver' => 'monolog', + 'handler' => NullHandler::class, + ], + + 'emergency' => [ + 'path' => storage_path('logs/laravel.log'), + ], + ], + +]; diff --git a/config/mail.php b/config/mail.php new file mode 100755 index 0000000..cfef410 --- /dev/null +++ b/config/mail.php @@ -0,0 +1,108 @@ + env('MAIL_MAILER', 'smtp'), + + /* + |-------------------------------------------------------------------------- + | Mailer Configurations + |-------------------------------------------------------------------------- + | + | Here you may configure all of the mailers used by your application plus + | their respective settings. Several examples have been configured for + | you and you are free to add your own as your application requires. + | + | Laravel supports a variety of mail "transport" drivers to be used while + | sending an e-mail. You will specify which one you are using for your + | mailers below. You are free to add additional mailers as required. + | + | Supported: "smtp", "sendmail", "mailgun", "ses", + | "postmark", "log", "array" + | + */ + + 'mailers' => [ + 'smtp' => [ + 'transport' => 'smtp', + 'host' => env('MAIL_HOST', 'smtp.mailgun.org'), + 'port' => env('MAIL_PORT', 587), + 'encryption' => env('MAIL_ENCRYPTION', 'tls'), + 'username' => env('MAIL_USERNAME'), + 'password' => env('MAIL_PASSWORD'), + ], + + 'ses' => [ + 'transport' => 'ses', + ], + + 'mailgun' => [ + 'transport' => 'mailgun', + ], + + 'postmark' => [ + 'transport' => 'postmark', + ], + + 'sendmail' => [ + 'transport' => 'sendmail', + 'path' => '/usr/sbin/sendmail -bs', + ], + + 'log' => [ + 'transport' => 'log', + 'channel' => env('MAIL_LOG_CHANNEL'), + ], + + 'array' => [ + 'transport' => 'array', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all e-mails sent by your application to be sent from + | the same address. Here, you may specify a name and address that is + | used globally for all e-mails that are sent by your application. + | + */ + + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', 'Example'), + ], + + /* + |-------------------------------------------------------------------------- + | Markdown Mail Settings + |-------------------------------------------------------------------------- + | + | If you are using Markdown based email rendering, you may configure your + | theme and component paths here, allowing you to customize the design + | of the emails. Or, you may simply stick with the Laravel defaults! + | + */ + + 'markdown' => [ + 'theme' => 'default', + + 'paths' => [ + resource_path('views/vendor/mail'), + ], + ], + +]; diff --git a/config/menu.php b/config/menu.php new file mode 100755 index 0000000..38b4fe1 --- /dev/null +++ b/config/menu.php @@ -0,0 +1,47 @@ + 'general.dashboard', 'link' => 'user', 'icon' => 'fa-tachometer-alt'], + ['title' => 'general.my-closet', 'link' => 'user/closet', 'icon' => 'fa-star'], + ['title' => 'general.player-manage', 'link' => 'user/player', 'icon' => 'fa-users'], + ['title' => 'general.my-reports', 'link' => 'user/reports', 'icon' => 'fa-flag'], + ['title' => 'general.profile', 'link' => 'user/profile', 'icon' => 'fa-user'], + [ + 'title' => 'general.developer', + 'icon' => 'fa-code-branch', + 'children' => [ + ['title' => 'general.oauth-manage', 'link' => 'user/oauth/manage', 'icon' => 'fa-feather-alt'], + ], + ], +]; + +$menu['admin'] = [ + ['title' => 'general.dashboard', 'link' => 'admin', 'icon' => 'fa-tachometer-alt'], + ['title' => 'general.user-manage', 'link' => 'admin/users', 'icon' => 'fa-users'], + ['title' => 'general.player-manage', 'link' => 'admin/players', 'icon' => 'fa-gamepad'], + ['title' => 'general.report-manage', 'link' => 'admin/reports', 'icon' => 'fa-flag'], + ['title' => 'general.customize', 'link' => 'admin/customize', 'icon' => 'fa-paint-brush'], + ['title' => 'general.i18n', 'link' => 'admin/i18n', 'icon' => 'fa-globe'], + ['title' => 'general.score-options', 'link' => 'admin/score', 'icon' => 'fa-credit-card'], + ['title' => 'general.options', 'link' => 'admin/options', 'icon' => 'fa-cog'], + ['title' => 'general.res-options', 'link' => 'admin/resource', 'icon' => 'fa-atom'], + ['title' => 'general.status', 'link' => 'admin/status', 'icon' => 'fa-battery-three-quarters'], + ['title' => 'general.plugin-manage', 'link' => 'admin/plugins/manage', 'icon' => 'fa-plug'], + ['title' => 'general.plugin-market', 'link' => 'admin/plugins/market', 'icon' => 'fa-shopping-bag'], + ['title' => 'general.plugin-configs', 'id' => 'plugin-configs', 'icon' => 'fa-cogs', 'children' => []], + ['title' => 'general.check-update', 'link' => 'admin/update', 'icon' => 'fa-arrow-up'], +]; + +$menu['explore'] = [ + ['title' => 'general.skinlib', 'link' => 'skinlib', 'icon' => 'fa-archive'], +]; + +return $menu; diff --git a/config/options.php b/config/options.php new file mode 100755 index 0000000..4002cf6 --- /dev/null +++ b/config/options.php @@ -0,0 +1,56 @@ + '', + 'site_name' => 'Blessing Skin', + 'site_description' => 'Open-source PHP Minecraft Skin Hosting Service', + 'register_with_player_name' => 'true', + 'require_verification' => 'false', + 'regs_per_ip' => '3', + 'announcement' => 'Welcome to Blessing Skin {version}!', + 'home_pic_url' => './app/bg.webp', + 'custom_css' => '', + 'custom_js' => '', + 'player_name_rule' => 'official', + 'custom_player_name_regexp' => '', + 'player_name_length_min' => '3', + 'player_name_length_max' => '16', + 'user_initial_score' => '1000', + 'sign_gap_time' => '24', + 'sign_score' => '10,100', + 'score_per_storage' => 'true', + 'private_score_per_storage' => '10', + 'return_score' => 'true', + 'score_per_player' => '100', + 'sign_after_zero' => 'false', + 'version' => '', + 'copyright_text' => 'Copyright © {year} {site_name}. All rights reserved.', + 'auto_del_invalid_texture' => 'false', + 'allow_downloading_texture' => 'true', + 'texture_name_regexp' => '', + 'cache_expire_time' => '31536000', + 'max_upload_file_size' => '1024', + 'force_ssl' => 'false', + 'auto_detect_asset_url' => 'true', + 'plugins_enabled' => '', + 'copyright_prefer' => '0', + 'score_per_closet_item' => '0', + 'favicon_url' => 'app/favicon.ico', + 'score_award_per_texture' => '0', + 'take_back_scores_after_deletion' => 'true', + 'score_award_per_like' => '0', + 'meta_keywords' => '', + 'meta_description' => '', + 'meta_extras' => '', + 'cdn_address' => '', + 'recaptcha_sitekey' => '', + 'recaptcha_secretkey' => '', + 'recaptcha_invisible' => 'false', + 'reporter_score_modification' => '0', + 'reporter_reward_score' => '0', + 'content_policy' => '', + 'transparent_navbar' => 'false', + 'status_code_for_private' => '403', + 'navbar_color' => 'cyan', + 'sidebar_color' => 'dark-maroon', +]; diff --git a/config/plugins.php b/config/plugins.php new file mode 100755 index 0000000..c484114 --- /dev/null +++ b/config/plugins.php @@ -0,0 +1,48 @@ + env('PLUGINS_DIR'), + + /* + |-------------------------------------------------------------------------- + | Plugins Assets URL + |-------------------------------------------------------------------------- + | + | The URL to access plugin's assets (CSS, JavaScript etc.). + | Defaults to `http://site_url/plugins`. + | + */ + 'url' => env('PLUGINS_URL'), + + /* + |-------------------------------------------------------------------------- + | Plugins Market Source + |-------------------------------------------------------------------------- + | + | Specify where to get plugins' metadata for plugin market. + | + */ + 'registry' => env( + 'PLUGINS_REGISTRY', + 'https://gplane.coding.net/p/blessing-skin-plugins-dist/d/blessing-skin-plugins-dist/git/raw/master/registry_{lang}.json' + ), + + /* + |-------------------------------------------------------------------------- + | Plugins Market Localization + |-------------------------------------------------------------------------- + | + | Supported languages of plugins market registry will be listed here. + | + */ + 'locales' => ['en', 'zh_CN'], +]; diff --git a/config/queue.php b/config/queue.php new file mode 100755 index 0000000..00b76d6 --- /dev/null +++ b/config/queue.php @@ -0,0 +1,89 @@ + env('QUEUE_CONNECTION', 'sync'), + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection information for each server that + | is used by your application. A default configuration has been added + | for each back-end shipped with Laravel. You are free to add more. + | + | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" + | + */ + + 'connections' => [ + + 'sync' => [ + 'driver' => 'sync', + ], + + 'database' => [ + 'driver' => 'database', + 'table' => 'jobs', + 'queue' => 'default', + 'retry_after' => 90, + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => 'localhost', + 'queue' => 'default', + 'retry_after' => 90, + 'block_for' => 0, + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), + 'queue' => env('SQS_QUEUE', 'your-queue-name'), + 'suffix' => env('SQS_SUFFIX'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + 'queue' => env('REDIS_QUEUE', 'default'), + 'retry_after' => 90, + 'block_for' => null, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control which database and table are used to store the jobs that + | have failed. You may change them to any database / table you wish. + | + */ + + 'failed' => [ + 'driver' => env('QUEUE_FAILED_DRIVER', 'database'), + 'database' => env('DB_CONNECTION', 'mysql'), + 'table' => 'failed_jobs', + ], + +]; diff --git a/config/secure.php b/config/secure.php new file mode 100755 index 0000000..cf44729 --- /dev/null +++ b/config/secure.php @@ -0,0 +1,14 @@ + env('PWD_METHOD', 'BCRYPT'), + 'salt' => env('SALT', ''), +]; diff --git a/config/services.php b/config/services.php new file mode 100755 index 0000000..2a1d616 --- /dev/null +++ b/config/services.php @@ -0,0 +1,33 @@ + [ + 'domain' => env('MAILGUN_DOMAIN'), + 'secret' => env('MAILGUN_SECRET'), + 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), + ], + + 'postmark' => [ + 'token' => env('POSTMARK_TOKEN'), + ], + + 'ses' => [ + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + ], + +]; diff --git a/config/session.php b/config/session.php new file mode 100755 index 0000000..3b698da --- /dev/null +++ b/config/session.php @@ -0,0 +1,194 @@ + env('SESSION_DRIVER', 'file'), + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle before it expires. If you want them + | to immediately expire on the browser closing, set that option. + | + */ + + 'lifetime' => env('SESSION_LIFETIME', 120), + + 'expire_on_close' => false, + + /* + |-------------------------------------------------------------------------- + | Session Encryption + |-------------------------------------------------------------------------- + | + | This option allows you to easily specify that all of your session data + | should be encrypted before it is stored. All encryption will be run + | automatically by Laravel and you can use the Session like normal. + | + */ + + 'encrypt' => false, + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When using the native session driver, we need a location where session + | files may be stored. A default has been set for you but a different + | location may be specified. This is only needed for file sessions. + | + */ + + 'files' => storage_path('framework/sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => env('SESSION_CONNECTION', null), + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table we + | should use to manage the sessions. Of course, a sensible default is + | provided for you; however, you are free to change this as needed. + | + */ + + 'table' => 'sessions', + + /* + |-------------------------------------------------------------------------- + | Session Cache Store + |-------------------------------------------------------------------------- + | + | When using the "apc", "memcached", or "dynamodb" session drivers you may + | list a cache store that should be used for these sessions. This value + | must match with one of the application's configured cache "stores". + | + */ + + 'store' => env('SESSION_STORE', null), + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => [2, 100], + + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the cookie used to identify a session + | instance by ID. The name specified here will get used every time a + | new session cookie is created by the framework for every driver. + | + */ + + 'cookie' => env('SESSION_COOKIE', 'BS_SESSION'), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application but you are free to change this when necessary. + | + */ + + 'path' => '/', + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | Here you may change the domain of the cookie used to identify a session + | in your application. This will determine which domains the cookie is + | available to in your application. A sensible default has been set. + | + */ + + 'domain' => env('SESSION_DOMAIN', null), + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you if it can not be done securely. + | + */ + + 'secure' => env('SESSION_SECURE_COOKIE'), + + /* + |-------------------------------------------------------------------------- + | HTTP Access Only + |-------------------------------------------------------------------------- + | + | Setting this value to true will prevent JavaScript from accessing the + | value of the cookie and the cookie will only be accessible through + | the HTTP protocol. You are free to modify this option if needed. + | + */ + + 'http_only' => true, + + /* + |-------------------------------------------------------------------------- + | Same-Site Cookies + |-------------------------------------------------------------------------- + | + | This option determines how your cookies behave when cross-site requests + | take place, and can be used to mitigate CSRF attacks. By default, we + | do not enable this as other CSRF protection services are in place. + | + | Supported: "lax", "strict", "none" + | + */ + + 'same_site' => 'lax', + +]; diff --git a/config/translation-loader.php b/config/translation-loader.php new file mode 100755 index 0000000..50f5b9b --- /dev/null +++ b/config/translation-loader.php @@ -0,0 +1,24 @@ + [ + Spatie\TranslationLoader\TranslationLoaders\Db::class, + ], + + /* + * This is the model used by the Db Translation loader. You can put any model here + * that extends Spatie\TranslationLoader\LanguageLine. + */ + 'model' => Spatie\TranslationLoader\LanguageLine::class, + + /* + * This is the translation manager which overrides the default Laravel `translation.loader` + */ + 'translation_manager' => App\Services\Translations\Loader::class, + +]; diff --git a/config/twigbridge.php b/config/twigbridge.php new file mode 100755 index 0000000..c3cc931 --- /dev/null +++ b/config/twigbridge.php @@ -0,0 +1,214 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Configuration options for Twig. + */ +return [ + + 'twig' => [ + /* + |-------------------------------------------------------------------------- + | Extension + |-------------------------------------------------------------------------- + | + | File extension for Twig view files. + | + */ + 'extension' => 'twig', + + /* + |-------------------------------------------------------------------------- + | Accepts all Twig environment configuration options + |-------------------------------------------------------------------------- + | + | http://twig.sensiolabs.org/doc/api.html#environment-options + | + */ + 'environment' => [ + + // When set to true, the generated templates have a __toString() method + // that you can use to display the generated nodes. + // default: false + 'debug' => env('APP_DEBUG', false), + + // The charset used by the templates. + // default: utf-8 + 'charset' => 'utf-8', + + // The base template class to use for generated templates. + // default: TwigBridge\Twig\Template + 'base_template_class' => 'TwigBridge\Twig\Template', + + // An absolute path where to store the compiled templates, or false to disable caching. If null + // then the cache file path is used. + // default: cache file storage path + 'cache' => null, + + // When developing with Twig, it's useful to recompile the template + // whenever the source code changes. If you don't provide a value + // for the auto_reload option, it will be determined automatically based on the debug value. + 'auto_reload' => true, + + // If set to false, Twig will silently ignore invalid variables + // (variables and or attributes/methods that do not exist) and + // replace them with a null value. When set to true, Twig throws an exception instead. + // default: false + 'strict_variables' => false, + + // If set to true, auto-escaping will be enabled by default for all templates. + // default: 'html' + 'autoescape' => 'html', + + // A flag that indicates which optimizations to apply + // (default to -1 -- all optimizations are enabled; set it to 0 to disable) + 'optimizations' => -1, + ], + + /* + |-------------------------------------------------------------------------- + | Global variables + |-------------------------------------------------------------------------- + | + | These will always be passed in and can be accessed as Twig variables. + | NOTE: these will be overwritten if you pass data into the view with the same key. + | + */ + 'globals' => [], + ], + + 'extensions' => [ + + /* + |-------------------------------------------------------------------------- + | Extensions + |-------------------------------------------------------------------------- + | + | Enabled extensions. + | + | `Twig\Extension\DebugExtension` is enabled automatically if twig.debug is TRUE. + | + */ + 'enabled' => [ + 'Twig\Extension\StringLoaderExtension', + + 'TwigBridge\Extension\Loader\Facades', + 'TwigBridge\Extension\Loader\Filters', + 'TwigBridge\Extension\Loader\Functions', + + 'TwigBridge\Extension\Laravel\Auth', + 'TwigBridge\Extension\Laravel\Config', + 'TwigBridge\Extension\Laravel\Dump', + // 'TwigBridge\Extension\Laravel\Input', + 'TwigBridge\Extension\Laravel\Session', + // 'TwigBridge\Extension\Laravel\Str', + 'TwigBridge\Extension\Laravel\Translator', + 'TwigBridge\Extension\Laravel\Url', + // 'TwigBridge\Extension\Laravel\Model', + // 'TwigBridge\Extension\Laravel\Gate', + + // 'TwigBridge\Extension\Laravel\Form', + // 'TwigBridge\Extension\Laravel\Html', + // 'TwigBridge\Extension\Laravel\Legacy\Facades', + ], + + /* + |-------------------------------------------------------------------------- + | Facades + |-------------------------------------------------------------------------- + | + | Available facades. Access like `{{ Config.get('foo.bar') }}`. + | + | Each facade can take an optional array of options. To mark the whole facade + | as safe you can set the option `'is_safe' => true`. Setting the facade as + | safe means that any HTML returned will not be escaped. + | + | It is advisable to not set the whole facade as safe and instead mark the + | each appropriate method as safe for security reasons. You can do that with + | the following syntax: + | + | + | 'Form' => [ + | 'is_safe' => [ + | 'open' + | ] + | ] + | + | + | The values of the `is_safe` array must match the called method on the facade + | in order to be marked as safe. + | + */ + 'facades' => [], + + /* + |-------------------------------------------------------------------------- + | Functions + |-------------------------------------------------------------------------- + | + | Available functions. Access like `{{ secure_url(...) }}`. + | + | Each function can take an optional array of options. These options are + | passed directly to `Twig\TwigFunction`. + | + | So for example, to mark a function as safe you can do the following: + | + | + | 'link_to' => [ + | 'is_safe' => ['html'] + | ] + | + | + | The options array also takes a `callback` that allows you to name the + | function differently in your Twig templates than what it's actually called. + | + | + | 'link' => [ + | 'callback' => 'link_to' + | ] + | + | + */ + 'functions' => [], + + /* + |-------------------------------------------------------------------------- + | Filters + |-------------------------------------------------------------------------- + | + | Available filters. Access like `{{ variable|filter }}`. + | + | Each filter can take an optional array of options. These options are + | passed directly to `Twig\TwigFilter`. + | + | So for example, to mark a filter as safe you can do the following: + | + | + | 'studly_case' => [ + | 'is_safe' => ['html'] + | ] + | + | + | The options array also takes a `callback` that allows you to name the + | filter differently in your Twig templates than what is actually called. + | + | + | 'snake' => [ + | 'callback' => 'snake_case' + | ] + | + | + */ + 'filters' => [ + 'get' => 'data_get', + ], + ], +]; diff --git a/config/view.php b/config/view.php new file mode 100755 index 0000000..b0e29ae --- /dev/null +++ b/config/view.php @@ -0,0 +1,37 @@ + [ + resource_path('views/overrides'), + resource_path('views'), + ], + + /* + |-------------------------------------------------------------------------- + | Compiled View Path + |-------------------------------------------------------------------------- + | + | This option determines where all the compiled Blade templates will be + | stored for your application. Typically, this is within the storage + | directory. However, as usual, you are free to change this value. + | + */ + + 'compiled' => env( + 'VIEW_COMPILED_PATH', + realpath(storage_path('framework/views')) + ), + +]; diff --git a/database/factories/PlayerFactory.php b/database/factories/PlayerFactory.php new file mode 100755 index 0000000..23b6587 --- /dev/null +++ b/database/factories/PlayerFactory.php @@ -0,0 +1,21 @@ + User::factory(), + 'name' => $this->faker->firstName, + 'tid_skin' => 0, + ]; + } +} diff --git a/database/factories/TextureFactory.php b/database/factories/TextureFactory.php new file mode 100755 index 0000000..ceb90ad --- /dev/null +++ b/database/factories/TextureFactory.php @@ -0,0 +1,41 @@ + $this->faker->firstName, + 'type' => 'steve', + 'hash' => $this->faker->sha256, + 'size' => rand(1, 2048), + 'likes' => rand(1, 10), + 'uploader' => User::factory(), + 'public' => true, + 'upload_at' => $this->faker->dateTime, + ]; + } + + public function alex() + { + return $this->state(['type' => 'alex']); + } + + public function cape() + { + return $this->state(['type' => 'cape']); + } + + public function private() + { + return $this->state(['public' => false]); + } +} diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php new file mode 100755 index 0000000..6ecea60 --- /dev/null +++ b/database/factories/UserFactory.php @@ -0,0 +1,44 @@ + $this->faker->email, + 'nickname' => $this->faker->name, + 'locale' => null, + 'score' => 1000, + 'avatar' => 0, + 'password' => app('cipher')->hash(Str::random(10), config('secure.salt')), + 'ip' => $this->faker->ipv4, + 'permission' => 0, + 'verified' => true, + 'last_sign_at' => $this->faker->dateTime->format('d-M-Y H:i:s'), + 'register_at' => $this->faker->dateTime->format('d-M-Y H:i:s'), + ]; + } + + public function admin() + { + return $this->state(['permission' => 1]); + } + + public function superAdmin() + { + return $this->state(['permission' => 2]); + } + + public function banned() + { + return $this->state(['permission' => -1]); + } +} diff --git a/database/migrations/2016_11_18_133939_create_all_tables.php b/database/migrations/2016_11_18_133939_create_all_tables.php new file mode 100755 index 0000000..b2c3496 --- /dev/null +++ b/database/migrations/2016_11_18_133939_create_all_tables.php @@ -0,0 +1,56 @@ +increments('uid'); + $table->string('email', 100); + $table->string('nickname', 50)->default(''); + $table->integer('score'); + $table->integer('avatar')->default('0'); + $table->string('password', 255); + $table->string('ip', 32); + $table->integer('permission')->default('0'); + $table->dateTime('last_sign_at'); + $table->dateTime('register_at'); + }); + + Schema::create('players', function (Blueprint $table) { + $table->increments('pid'); + $table->integer('uid'); + $table->string('player_name', 50); + $table->integer('tid_cape')->default('0'); + $table->dateTime('last_modified'); + }); + + Schema::create('textures', function (Blueprint $table) { + $table->increments('tid'); + $table->string('name', 50); + $table->string('type', 10); + $table->string('hash', 64); + $table->integer('size'); + $table->integer('uploader'); + $table->tinyInteger('public'); + $table->dateTime('upload_at'); + }); + + Schema::create('options', function (Blueprint $table) { + $table->increments('id'); + $table->string('option_name', 50); + $table->longText('option_value'); + }); + } + + public function down() + { + Schema::drop('users'); + Schema::drop('players'); + Schema::drop('textures'); + Schema::drop('options'); + } +} diff --git a/database/migrations/2016_11_18_134542_import_options.php b/database/migrations/2016_11_18_134542_import_options.php new file mode 100755 index 0000000..b99d2df --- /dev/null +++ b/database/migrations/2016_11_18_134542_import_options.php @@ -0,0 +1,35 @@ +year, + $options['copyright_text'] + ); + + foreach ($options as $key => $value) { + Option::set($key, $value); + } + } + + public function down() + { + DB::table('options')->delete(); + } +} diff --git a/database/migrations/2018_07_26_130617_add_verification_to_users_table.php b/database/migrations/2018_07_26_130617_add_verification_to_users_table.php new file mode 100755 index 0000000..2d10ebd --- /dev/null +++ b/database/migrations/2018_07_26_130617_add_verification_to_users_table.php @@ -0,0 +1,22 @@ +boolean('verified')->default(false); + $table->string('verification_token')->default(''); + }); + } + + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn(['verified', 'verification_token']); + }); + } +} diff --git a/database/migrations/2018_08_21_105514_add_remember_token_to_users_table.php b/database/migrations/2018_08_21_105514_add_remember_token_to_users_table.php new file mode 100755 index 0000000..61e9d9e --- /dev/null +++ b/database/migrations/2018_08_21_105514_add_remember_token_to_users_table.php @@ -0,0 +1,22 @@ +rememberToken(); + }); + } + + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('remember_token'); + }); + } +} diff --git a/database/migrations/2019_03_01_131420_add_tid_skin.php b/database/migrations/2019_03_01_131420_add_tid_skin.php new file mode 100755 index 0000000..e79f1aa --- /dev/null +++ b/database/migrations/2019_03_01_131420_add_tid_skin.php @@ -0,0 +1,30 @@ +integer('tid_skin')->default(-1); + + if (Schema::hasColumn('players', 'preference')) { + $table->string('preference', 10)->nullable()->change(); + } + }); + } + + public function down() + { + Schema::table('players', function (Blueprint $table) { + $table->dropColumn('tid_skin'); + + if (Schema::hasColumn('players', 'preference')) { + $table->string('preference', 10)->nullable(false)->change(); + } + }); + } +} diff --git a/database/migrations/2019_03_13_130311_rename_players_table_columns.php b/database/migrations/2019_03_13_130311_rename_players_table_columns.php new file mode 100755 index 0000000..abbab18 --- /dev/null +++ b/database/migrations/2019_03_13_130311_rename_players_table_columns.php @@ -0,0 +1,22 @@ +renameColumn('player_name', 'name'); + }); + } + + public function down() + { + Schema::table('players', function (Blueprint $table) { + $table->renameColumn('name', 'player_name'); + }); + } +} diff --git a/database/migrations/2019_03_14_174727_create_closet.php b/database/migrations/2019_03_14_174727_create_closet.php new file mode 100755 index 0000000..12eafdd --- /dev/null +++ b/database/migrations/2019_03_14_174727_create_closet.php @@ -0,0 +1,22 @@ +integer('user_uid'); + $table->integer('texture_tid'); + $table->text('item_name')->nullable(); + }); + } + + public function down() + { + Schema::dropIfExists('user_closet'); + } +} diff --git a/database/migrations/2019_03_16_162603_remove_likes_field.php b/database/migrations/2019_03_16_162603_remove_likes_field.php new file mode 100755 index 0000000..94b9627 --- /dev/null +++ b/database/migrations/2019_03_16_162603_remove_likes_field.php @@ -0,0 +1,17 @@ +dropColumn('likes'); + }); + } + } +} diff --git a/database/migrations/2019_03_23_171728_create_report_table.php b/database/migrations/2019_03_23_171728_create_report_table.php new file mode 100755 index 0000000..d0c4f62 --- /dev/null +++ b/database/migrations/2019_03_23_171728_create_report_table.php @@ -0,0 +1,28 @@ +increments('id'); + $table->integer('tid'); + $table->integer('uploader'); + $table->integer('reporter'); + $table->longText('reason'); + $table->integer('status'); + $table->dateTime('report_at'); + }); + } + } + + public function down() + { + Schema::dropIfExists('reports'); + } +} diff --git a/database/migrations/2019_05_05_103143_add_likes_field.php b/database/migrations/2019_05_05_103143_add_likes_field.php new file mode 100755 index 0000000..462aadc --- /dev/null +++ b/database/migrations/2019_05_05_103143_add_likes_field.php @@ -0,0 +1,26 @@ +integer('likes')->unsigned()->default(0); + }); + } + } + + public function down() + { + if (Schema::hasColumn('textures', 'likes')) { + Schema::table('textures', function (Blueprint $table) { + $table->dropColumn('likes'); + }); + } + } +} diff --git a/database/migrations/2019_07_03_094434_create_notifications_table.php b/database/migrations/2019_07_03_094434_create_notifications_table.php new file mode 100755 index 0000000..3f953a9 --- /dev/null +++ b/database/migrations/2019_07_03_094434_create_notifications_table.php @@ -0,0 +1,25 @@ +uuid('id')->primary(); + $table->string('type'); + $table->morphs('notifiable'); + $table->text('data'); + $table->timestamp('read_at')->nullable(); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('notifications'); + } +} diff --git a/database/migrations/2019_07_05_222912_create_jobs_table.php b/database/migrations/2019_07_05_222912_create_jobs_table.php new file mode 100755 index 0000000..b24ba8d --- /dev/null +++ b/database/migrations/2019_07_05_222912_create_jobs_table.php @@ -0,0 +1,26 @@ +bigIncrements('id'); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + } + + public function down() + { + Schema::dropIfExists('jobs'); + } +} diff --git a/database/migrations/2019_09_05_130811_create_language_lines_table.php b/database/migrations/2019_09_05_130811_create_language_lines_table.php new file mode 100755 index 0000000..9d24bc7 --- /dev/null +++ b/database/migrations/2019_09_05_130811_create_language_lines_table.php @@ -0,0 +1,24 @@ +increments('id'); + $table->string('group'); + $table->index('group'); + $table->string('key'); + $table->text('text'); + $table->timestamps(); + }); + } + + public function down() + { + Schema::drop('language_lines'); + } +} diff --git a/database/migrations/2019_12_14_095751_update_ip_field.php b/database/migrations/2019_12_14_095751_update_ip_field.php new file mode 100755 index 0000000..d417981 --- /dev/null +++ b/database/migrations/2019_12_14_095751_update_ip_field.php @@ -0,0 +1,22 @@ +string('ip', 39)->change(); + }); + } + + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->string('ip', 32)->change(); + }); + } +} diff --git a/database/migrations/2020_03_10_145738_lengthen_ip_field.php b/database/migrations/2020_03_10_145738_lengthen_ip_field.php new file mode 100755 index 0000000..5173eaa --- /dev/null +++ b/database/migrations/2020_03_10_145738_lengthen_ip_field.php @@ -0,0 +1,22 @@ +string('ip', 45)->change(); + }); + } + + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->string('ip', 39)->change(); + }); + } +} diff --git a/database/migrations/2020_06_26_090510_add_o_auth_provider_field.php b/database/migrations/2020_06_26_090510_add_o_auth_provider_field.php new file mode 100755 index 0000000..5ea7edd --- /dev/null +++ b/database/migrations/2020_06_26_090510_add_o_auth_provider_field.php @@ -0,0 +1,17 @@ +string('provider')->after('secret')->nullable(); + }); + } + } +} diff --git a/database/migrations/2020_06_28_155519_add_user_locale_field.php b/database/migrations/2020_06_28_155519_add_user_locale_field.php new file mode 100755 index 0000000..b71b186 --- /dev/null +++ b/database/migrations/2020_06_28_155519_add_user_locale_field.php @@ -0,0 +1,22 @@ +string('locale')->nullable()->after('nickname'); + }); + } + + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->removeColumn('locale'); + }); + } +} diff --git a/database/migrations/2021_04_14_181300_create_scope_table.php b/database/migrations/2021_04_14_181300_create_scope_table.php new file mode 100755 index 0000000..166dca1 --- /dev/null +++ b/database/migrations/2021_04_14_181300_create_scope_table.php @@ -0,0 +1,34 @@ +increments('id'); + $table->string('name')->unique(); + $table->string('description'); + }); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('scopes'); + } +} diff --git a/database/migrations/2021_06_06_111049_add_is_dark_mode_field.php b/database/migrations/2021_06_06_111049_add_is_dark_mode_field.php new file mode 100755 index 0000000..3c2aa09 --- /dev/null +++ b/database/migrations/2021_06_06_111049_add_is_dark_mode_field.php @@ -0,0 +1,22 @@ +boolean('is_dark_mode')->after('ip')->default(false); + }); + } + + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('is_dark_mode'); + }); + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..a31f73b --- /dev/null +++ b/index.html @@ -0,0 +1,37 @@ + + + + + Error + + + +
+
请将 Web 根目录设为当前目录下的 public 目录。
+
+
+ Please define your web server root directory as the "public" directory under current directory. +
+
+ + diff --git a/plugins/.gitignore b/plugins/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/plugins/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/public/.gitignore b/public/.gitignore new file mode 100755 index 0000000..908f7bb --- /dev/null +++ b/public/.gitignore @@ -0,0 +1 @@ +app/ diff --git a/public/.htaccess b/public/.htaccess new file mode 100755 index 0000000..80307cf --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,34 @@ + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # You may need to uncomment the following line for some hosting environments, + # if you have installed to a subdirectory, enter the name here also. + # + # RewriteBase / + + # Black list protected files + RewriteRule (^\.|/\.) - [F] + RewriteRule ^storage/.* - [F] + + # Redirect trailing slashes if not a folder (behind a reverse proxy) + RewriteCond %{HTTP:X-Forwarded-Proto} ^https$ + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ "%{HTTP:X-Forwarded-Proto}://%{HTTP_HOST}%1" [L,R=301] + + # Redirect trailing slashes if not a folder + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Handle front controller + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + + +AddType application/wasm .wasm diff --git a/public/favicon.png b/public/favicon.png new file mode 100755 index 0000000..cf69a54 Binary files /dev/null and b/public/favicon.png differ diff --git a/public/index.php b/public/index.php new file mode 100755 index 0000000..54f3663 --- /dev/null +++ b/public/index.php @@ -0,0 +1,66 @@ +make(Illuminate\Contracts\Http\Kernel::class); + +$response = $kernel->handle( + $request = Illuminate\Http\Request::capture() +); + +$response->send(); + +$kernel->terminate($request, $response); diff --git a/public/lang/.gitignore b/public/lang/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/public/lang/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/public/meta.js b/public/meta.js new file mode 100755 index 0000000..7c0c6e8 --- /dev/null +++ b/public/meta.js @@ -0,0 +1 @@ +!function(){"use strict";const e=document.querySelector("#blessing-globals");window.blessing=JSON.parse(e.textContent),window.addEventListener("load",(()=>{navigator.serviceWorker.register("/sw.js?v6")}))}(); \ No newline at end of file diff --git a/public/plugins/.gitignore b/public/plugins/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/public/plugins/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/public/sw.js b/public/sw.js new file mode 100755 index 0000000..9359bda --- /dev/null +++ b/public/sw.js @@ -0,0 +1 @@ +!function(){"use strict";var e={913:function(){try{self["workbox:core:5.1.3"]&&_()}catch(e){}},550:function(){try{self["workbox:expiration:5.1.3"]&&_()}catch(e){}},80:function(){try{self["workbox:routing:5.1.3"]&&_()}catch(e){}},873:function(){try{self["workbox:strategies:5.1.3"]&&_()}catch(e){}}},t={};function s(n){var a=t[n];if(void 0!==a)return a.exports;var i=t[n]={exports:{}};return e[n](i,i.exports,s),i.exports}!function(){s(913);class e extends Error{constructor(e,t){super(((e,...t)=>{let s=e;return t.length>0&&(s+=` :: ${JSON.stringify(t)}`),s})(e,t)),this.name=e,this.details=t}}s(80);const t=e=>e&&"object"==typeof e?e:{handle:e};class n{constructor(e,s,n="GET"){this.handler=t(s),this.match=e,this.method=n}}class a extends n{constructor(e,t,s){super((({url:t})=>{const s=e.exec(t.href);if(s&&(t.origin===location.origin||0===s.index))return s.slice(1)}),t,s)}}class i{constructor(){this._routes=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener("fetch",(e=>{const{request:t}=e,s=this.handleRequest({request:t,event:e});s&&e.respondWith(s)}))}addCacheListener(){self.addEventListener("message",(e=>{if(e.data&&"CACHE_URLS"===e.data.type){const{payload:t}=e.data,s=Promise.all(t.urlsToCache.map((e=>{"string"==typeof e&&(e=[e]);const t=new Request(...e);return this.handleRequest({request:t})})));e.waitUntil(s),e.ports&&e.ports[0]&&s.then((()=>e.ports[0].postMessage(!0)))}}))}handleRequest({request:e,event:t}){const s=new URL(e.url,location.href);if(!s.protocol.startsWith("http"))return;const{params:n,route:a}=this.findMatchingRoute({url:s,request:e,event:t});let i,r=a&&a.handler;if(!r&&this._defaultHandler&&(r=this._defaultHandler),r){try{i=r.handle({url:s,request:e,event:t,params:n})}catch(e){i=Promise.reject(e)}return i instanceof Promise&&this._catchHandler&&(i=i.catch((n=>this._catchHandler.handle({url:s,request:e,event:t})))),i}}findMatchingRoute({url:e,request:t,event:s}){const n=this._routes.get(t.method)||[];for(const a of n){let n;const i=a.match({url:e,request:t,event:s});if(i)return n=i,(Array.isArray(i)&&0===i.length||i.constructor===Object&&0===Object.keys(i).length||"boolean"==typeof i)&&(n=void 0),{route:a,params:n}}return{}}setDefaultHandler(e){this._defaultHandler=t(e)}setCatchHandler(e){this._catchHandler=t(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(t){if(!this._routes.has(t.method))throw new e("unregister-route-but-not-found-with-method",{method:t.method});const s=this._routes.get(t.method).indexOf(t);if(!(s>-1))throw new e("unregister-route-route-not-registered");this._routes.get(t.method).splice(s,1)}}let r;function o(t,s,o){let c;if("string"==typeof t){const e=new URL(t,location.href);c=new n((({url:t})=>t.href===e.href),s,o)}else if(t instanceof RegExp)c=new a(t,s,o);else if("function"==typeof t)c=new n(t,s,o);else{if(!(t instanceof n))throw new e("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});c=t}return(r||(r=new i,r.addFetchListener(),r.addCacheListener()),r).registerRoute(c),c}const c={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},h=e=>{return e||(t=c.runtime,[c.prefix,t,c.suffix].filter((e=>e&&e.length>0)).join("-"));var t},u=new Set,l=(e,t)=>e.filter((e=>t in e)),p=async({request:e,mode:t,plugins:s=[]})=>{const n=l(s,"cacheKeyWillBeUsed");let a=e;for(const e of n)a=await e.cacheKeyWillBeUsed.call(e,{mode:t,request:a}),"string"==typeof a&&(a=new Request(a));return a},d=async({cacheName:e,request:t,event:s,matchOptions:n,plugins:a=[]})=>{const i=await self.caches.open(e),r=await p({plugins:a,request:t,mode:"read"});let o=await i.match(r,n);for(const t of a)if("cachedResponseWillBeUsed"in t){const a=t.cachedResponseWillBeUsed;o=await a.call(t,{cacheName:e,event:s,matchOptions:n,cachedResponse:o,request:r})}return o},m=async({cacheName:t,request:s,response:n,event:a,plugins:i=[],matchOptions:r})=>{const o=await p({plugins:i,request:s,mode:"write"});if(!n)throw new e("cache-put-with-no-response",{url:(c=o.url,new URL(String(c),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var c;const h=await(async({request:e,response:t,event:s,plugins:n=[]})=>{let a=t,i=!1;for(const t of n)if("cacheWillUpdate"in t){i=!0;const n=t.cacheWillUpdate;if(a=await n.call(t,{request:e,response:a,event:s}),!a)break}return i||(a=a&&200===a.status?a:void 0),a||null})({event:a,plugins:i,response:n,request:o});if(!h)return;const m=await self.caches.open(t),g=l(i,"cacheDidUpdate"),f=g.length>0?await d({cacheName:t,matchOptions:r,request:o}):null;try{await m.put(o,h)}catch(e){throw"QuotaExceededError"===e.name&&await async function(){for(const e of u)await e()}(),e}for(const e of g)await e.cacheDidUpdate.call(e,{cacheName:t,event:a,oldResponse:f,newResponse:h,request:o})},g=d,f=async({request:t,fetchOptions:s,event:n,plugins:a=[]})=>{if("string"==typeof t&&(t=new Request(t)),n instanceof FetchEvent&&n.preloadResponse){const e=await n.preloadResponse;if(e)return e}const i=l(a,"fetchDidFail"),r=i.length>0?t.clone():null;try{for(const e of a)if("requestWillFetch"in e){const s=e.requestWillFetch,a=t.clone();t=await s.call(e,{request:a,event:n})}}catch(t){throw new e("plugin-error-request-will-fetch",{thrownError:t})}const o=t.clone();try{let e;e="navigate"===t.mode?await fetch(t):await fetch(t,s);for(const t of a)"fetchDidSucceed"in t&&(e=await t.fetchDidSucceed.call(t,{event:n,request:o,response:e}));return e}catch(e){for(const t of i)await t.fetchDidFail.call(t,{error:e,event:n,originalRequest:r.clone(),request:o.clone()});throw e}};s(873);class w{constructor(e={}){this._cacheName=h(e.cacheName),this._plugins=e.plugins||[],this._fetchOptions=e.fetchOptions,this._matchOptions=e.matchOptions}async handle({event:t,request:s}){"string"==typeof s&&(s=new Request(s));let n,a=await g({cacheName:this._cacheName,request:s,event:t,matchOptions:this._matchOptions,plugins:this._plugins});if(a);else try{a=await this._getFromNetwork(s,t)}catch(e){n=e}if(!a)throw new e("no-response",{url:s.url,error:n});return a}async _getFromNetwork(e,t){const s=await f({request:e,event:t,fetchOptions:this._fetchOptions,plugins:this._plugins}),n=s.clone(),a=m({cacheName:this._cacheName,request:e,response:n,event:t,plugins:this._plugins});if(t)try{t.waitUntil(a)}catch(e){}return s}}const _={cacheWillUpdate:async({response:e})=>200===e.status||0===e.status?e:null};class y{constructor(e={}){if(this._cacheName=h(e.cacheName),this._plugins=e.plugins||[],e.plugins){const t=e.plugins.some((e=>!!e.cacheWillUpdate));this._plugins=t?e.plugins:[_,...e.plugins]}else this._plugins=[_];this._fetchOptions=e.fetchOptions,this._matchOptions=e.matchOptions}async handle({event:t,request:s}){"string"==typeof s&&(s=new Request(s));const n=this._getFromNetwork({request:s,event:t});let a,i=await g({cacheName:this._cacheName,request:s,event:t,matchOptions:this._matchOptions,plugins:this._plugins});if(i){if(t)try{t.waitUntil(n)}catch(a){}}else try{i=await n}catch(e){a=e}if(!i)throw new e("no-response",{url:s.url,error:a});return i}async _getFromNetwork({request:e,event:t}){const s=await f({request:e,event:t,fetchOptions:this._fetchOptions,plugins:this._plugins}),n=m({cacheName:this._cacheName,request:e,response:s.clone(),event:t,plugins:this._plugins});if(t)try{t.waitUntil(n)}catch(e){}return s}}function x(e){e.then((()=>{}))}class v{constructor(e,t,{onupgradeneeded:s,onversionchange:n}={}){this._db=null,this._name=e,this._version=t,this._onupgradeneeded=s,this._onversionchange=n||(()=>this.close())}get db(){return this._db}async open(){if(!this._db)return this._db=await new Promise(((e,t)=>{let s=!1;setTimeout((()=>{s=!0,t(new Error("The open request was blocked and timed out"))}),this.OPEN_TIMEOUT);const n=indexedDB.open(this._name,this._version);n.onerror=()=>t(n.error),n.onupgradeneeded=e=>{s?(n.transaction.abort(),n.result.close()):"function"==typeof this._onupgradeneeded&&this._onupgradeneeded(e)},n.onsuccess=()=>{const t=n.result;s?t.close():(t.onversionchange=this._onversionchange.bind(this),e(t))}})),this}async getKey(e,t){return(await this.getAllKeys(e,t,1))[0]}async getAll(e,t,s){return await this.getAllMatching(e,{query:t,count:s})}async getAllKeys(e,t,s){return(await this.getAllMatching(e,{query:t,count:s,includeKeys:!0})).map((e=>e.key))}async getAllMatching(e,{index:t,query:s=null,direction:n="next",count:a,includeKeys:i=!1}={}){return await this.transaction([e],"readonly",((r,o)=>{const c=r.objectStore(e),h=t?c.index(t):c,u=[],l=h.openCursor(s,n);l.onsuccess=()=>{const e=l.result;e?(u.push(i?e:e.value),a&&u.length>=a?o(u):e.continue()):o(u)}}))}async transaction(e,t,s){return await this.open(),await new Promise(((n,a)=>{const i=this._db.transaction(e,t);i.onabort=()=>a(i.error),i.oncomplete=()=>n(),s(i,(e=>n(e)))}))}async _call(e,t,s,...n){return await this.transaction([t],s,((s,a)=>{const i=s.objectStore(t),r=i[e].apply(i,n);r.onsuccess=()=>a(r.result)}))}close(){this._db&&(this._db.close(),this._db=null)}}v.prototype.OPEN_TIMEOUT=2e3;const q={readonly:["get","count","getKey","getAll","getAllKeys"],readwrite:["add","put","clear","delete"]};for(const[e,t]of Object.entries(q))for(const s of t)s in IDBObjectStore.prototype&&(v.prototype[s]=async function(t,...n){return await this._call(s,t,e,...n)});s(550);const N="cache-entries",O=e=>{const t=new URL(e,location.href);return t.hash="",t.href};class E{constructor(e){this._cacheName=e,this._db=new v("workbox-expiration",1,{onupgradeneeded:e=>this._handleUpgrade(e)})}_handleUpgrade(e){const t=e.target.result.createObjectStore(N,{keyPath:"id"});t.createIndex("cacheName","cacheName",{unique:!1}),t.createIndex("timestamp","timestamp",{unique:!1}),(async e=>{await new Promise(((t,s)=>{const n=indexedDB.deleteDatabase(e);n.onerror=()=>{s(n.error)},n.onblocked=()=>{s(new Error("Delete blocked"))},n.onsuccess=()=>{t()}}))})(this._cacheName)}async setTimestamp(e,t){const s={url:e=O(e),timestamp:t,cacheName:this._cacheName,id:this._getId(e)};await this._db.put(N,s)}async getTimestamp(e){return(await this._db.get(N,this._getId(e))).timestamp}async expireEntries(e,t){const s=await this._db.transaction(N,"readwrite",((s,n)=>{const a=s.objectStore(N).index("timestamp").openCursor(null,"prev"),i=[];let r=0;a.onsuccess=()=>{const s=a.result;if(s){const n=s.value;n.cacheName===this._cacheName&&(e&&n.timestamp=t?i.push(s.value):r++),s.continue()}else n(i)}})),n=[];for(const e of s)await this._db.delete(N,e.id),n.push(e.url);return n}_getId(e){return this._cacheName+"|"+O(e)}}class R{constructor(e,t={}){this._isRunning=!1,this._rerunRequested=!1,this._maxEntries=t.maxEntries,this._maxAgeSeconds=t.maxAgeSeconds,this._cacheName=e,this._timestampModel=new E(e)}async expireEntries(){if(this._isRunning)return void(this._rerunRequested=!0);this._isRunning=!0;const e=this._maxAgeSeconds?Date.now()-1e3*this._maxAgeSeconds:0,t=await this._timestampModel.expireEntries(e,this._maxEntries),s=await self.caches.open(this._cacheName);for(const e of t)await s.delete(e);this._isRunning=!1,this._rerunRequested&&(this._rerunRequested=!1,x(this.expireEntries()))}async updateTimestamp(e){await this._timestampModel.setTimestamp(e,Date.now())}async isURLExpired(e){return!!this._maxAgeSeconds&&await this._timestampModel.getTimestamp(e){if(!n)return null;const a=this._isResponseDateFresh(n),i=this._getCacheExpiration(s);x(i.expireEntries());const r=i.updateTimestamp(t.url);if(e)try{e.waitUntil(r)}catch(e){}return a?n:null},this.cacheDidUpdate=async({cacheName:e,request:t})=>{const s=this._getCacheExpiration(e);await s.updateTimestamp(t.url),await s.expireEntries()},this._config=e,this._maxAgeSeconds=e.maxAgeSeconds,this._cacheExpirations=new Map,e.purgeOnQuotaError&&(t=()=>this.deleteCacheAndMetadata(),u.add(t))}_getCacheExpiration(t){if(t===h())throw new e("expire-custom-caches-only");let s=this._cacheExpirations.get(t);return s||(s=new R(t,this._config),this._cacheExpirations.set(t,s)),s}_isResponseDateFresh(e){if(!this._maxAgeSeconds)return!0;const t=this._getDateHeaderTimestamp(e);return null===t||t>=Date.now()-1e3*this._maxAgeSeconds}_getDateHeaderTimestamp(e){if(!e.headers.has("date"))return null;const t=e.headers.get("date"),s=new Date(t).getTime();return isNaN(s)?null:s}async deleteCacheAndMetadata(){for(const[e,t]of this._cacheExpirations)await self.caches.delete(e),await t.delete();this._cacheExpirations=new Map}}const A=604800;o(/\/preview\/\d+/,new w({cacheName:"texture-preview-v2",fetchOptions:{credentials:"omit"},plugins:[new b({maxAgeSeconds:A,purgeOnQuotaError:!0})]})),o(/\/app\/.*\.webp/,new y({cacheName:"webp-resource-v1",fetchOptions:{credentials:"omit"}})),o(/\/avatar\/\d+/,new w({cacheName:"avatar-v2",fetchOptions:{credentials:"omit"},plugins:[new b({maxAgeSeconds:A})]})),o(/.+\/app\/\w{2,3}\.\w{7}\.js$/,new w({cacheName:"javascript-v1",fetchOptions:{credentials:"omit",mode:"cors"},plugins:[new b({maxAgeSeconds:A,purgeOnQuotaError:!0})]})),o(/.+\/plugins\/.+\.js$/,new y({cacheName:"javascript-v1",fetchOptions:{credentials:"omit",mode:"cors"},plugins:[new b({maxAgeSeconds:A,purgeOnQuotaError:!0})]})),o(/.+\/app\/.*\.css$/,new w({cacheName:"stylesheet-v1",fetchOptions:{credentials:"omit",mode:"cors"},plugins:[new b({maxAgeSeconds:A,purgeOnQuotaError:!0})]})),o(/.+\/plugins\/.+\.css$/,new y({cacheName:"stylesheet-v1",fetchOptions:{credentials:"omit",mode:"cors"},plugins:[new b({maxAgeSeconds:A,purgeOnQuotaError:!0})]})),o((({request:e})=>"font"===e.destination),new y({cacheName:"font-v1",fetchOptions:{credentials:"omit",mode:"cors"},plugins:[new b({maxEntries:12})]}))}()}(); \ No newline at end of file diff --git a/resources/lang/de_DE/admin.yml b/resources/lang/de_DE/admin.yml new file mode 100755 index 0000000..fe89396 --- /dev/null +++ b/resources/lang/de_DE/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: Registrierte Nutzer + total-players: Spieler + total-textures: Hochgeladene Texturen + disk-usage: Speichernutzung + overview: Übersicht + texture-uploads: Hochgeladene Texturen + user-registration: Benutzerregistrierungen +notifications: + send: + title: Nachricht verfassen + success: Erfolgreich versandt! + receiver: + title: EmpfängerIn + all: Alle Nutzer + normal: Einfache Benutzer + uid: Angegebene UID + email: Angegebene E-Mail + title: Betreff + content: Inhalt (Markdown wird unterstützt) +users: + operations: + non-existent: Benutzer nicht gefunden. + no-permission: Sie haben keine Berechtigung diesen Nutzer zu Löschen. + email: + success: Die E-Mail-Adresse wurde erfolgreich geändert. + verification: + success: Bestätigungsstatus wurde erfolgreich geändert. + nickname: + success: Benutzername erfolgreich geändert. + password: + success: Kennwort erfolgreich geändert. + score: + success: Punktestand erfolgreich geändert. + permission: Berechtigungen aktualisiert. + delete: + success: Das Konto wurde erfolgreich gelöscht. +players: + no-permission: Sie haben keine Berechtigung diesen Nutzer zu Löschen. + textures: + non-existent: Keine solche Textur tid.:tid + success: Die Texturen von :player wurden aktualisiert. + name: + success: Spielername wurde aktualisiert auf :player + owner: + success: Der Spieler :player wurde an den Benutzer :user übertragen. + delete: + success: Der Spieler wurde erfolgreich gelöscht. +customize: + change-color: + title: Designfarbe ändern + colors: + navbar: Navigationsleiste + sidebar: + dark: Seitenleiste (dunkel) + light: Seitenleiste (Licht) +i18n: + add: Neue Sprache hinzufügen + added: Sprache hinzugefügt + updated: Sprache aktualisiert + deleted: Sprache gelöscht + group: Gruppe + key: Schlüssel + text: Text + tip: Wie kann ich diese Seite benutzen? +status: + info: Information + health: Gesundheit + bs: + name: Blessing Skin + version: Version + env: Anwendungsumgebung + debug: Debuggen oder nicht? + commit: Änderung einreichen + laravel: Laravel Version + server: + name: Server + php: PHP Version + web: Webserver Software + os: Betriebssystem + db: + name: Datenbank + type: Server + host: Host + port: Port + username: DB-Benutzername + database: Datenbankstatus + prefix: Tabellen-Präfix + plugins: Aktivierte Plugins (:amount) +plugins: + readme: Anleitung + operations: + title: Aufgaben + enabled: ':plugin wurde aktiviert.' + unsatisfied: + notice: Es gibt Konflikte oder unzufriedene Abhängigkeiten im Plugin, daher können wir es nicht aktivieren. Bitte installieren oder aktualisieren Sie die unten aufgeführten Plugins und deaktivieren Sie diese Konflikte. + disabled: '":name" Plugin ist nicht aktiviert.' + version: 'Die Version von ":title" erfüllt nicht die Einschränkung ":constraint".' + conflict: 'Das Plugin ":title" kann nicht gleichzeitig mit diesem Plugin ausgeführt werden.' + disabled: ':plugin wurde deaktiviert.' + deleted: Das Plugin wurde erfolgreich gelöscht. + no-config-notice: Das Plugin ist nicht installiert oder bietet keine Konfigurationsseite. + no-readme-notice: Das Plugin enthält keine Readme-Datei. + not-found: Plugin existiert nicht. + market: + unresolved: Es gibt Konflikte oder unzufriedene Abhängigkeiten im Plugin, daher können wir es nicht aktivieren. Bitte installieren oder aktualisieren Sie die unten aufgeführten Plugins und deaktivieren Sie diese Konflikte. + connection-error: Keine Verbindung zur Registry der Plugins. :error + non-existent: Das Plugin :plugin existiert nicht. + install-success: Plugin installiert. +update: + complete: Aktualisierung abgeschlossen + info: + title: Update-Informationen + up-to-date: Bereits aktuell. + available: Neue Version verfügbar. + versions: + latest: "Neueste Version:" + current: "Aktuelle Version:" + check-github: GitHub Versionen prüfen + button: Jetzt aktualisieren + cautions: + title: Warnungen + link: schaue dir das an. + text: | + Bitte wählen Sie die Updatequelle entsprechend der Netzwerkumgebung Ihres Hosts aus. + Langsame Verbindungen zwischen Updatequelle und Ihrem Host verlangsamen das Überprüfen und Herunterladen der Seite. + Um die Standard-Updatequelle zu ändern, + errors: + connection: "Zugriff auf die aktuelle Updatequelle nicht möglich. Details: :error" + spec: Aktuelle Updatequelle wird nicht unterstützt. + php: Ihre PHP-Version ist zu niedrig zum Aktualisieren. Benötigt :version oder neuer. +download: + errors: + download: 'Download fehlgeschlagen. Fehler: :error' + shasum: Dateiüberprüfung fehlgeschlagen. Bitte erneut herunterladen. + unzip: Fehler beim Entpacken der Dateien. +invalid-action: Ungültiger Vorgang diff --git a/resources/lang/de_DE/auth.yml b/resources/lang/de_DE/auth.yml new file mode 100755 index 0000000..a3514f7 --- /dev/null +++ b/resources/lang/de_DE/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: Anmeldung + message: Melden Sie sich an, um Ihren Skin & Ihre Spieler zu verwalten + success: Erfolgreich angemeldet. +check: + anonymous: Ungültiger Zugriff. Bitte melden Sie sich zuerst an. + verified: Um auf diese Seite zuzugreifen, bitte zuerst E-Mail-Adresse bestätigen. + admin: Nur Administratoren dürfen auf diese Seite zugreifen. + banned: Du bist auf dieser Seite gebannt. Bitte kontaktiere den Administrator. +register: + title: Konto erstellen + message: Willkommen bei :sitename! + success: Konto wurde registriert. Weiterleitung... + max: Sie können nicht mehr als :regs Konten registrieren. +forgot: + title: Passwort vergessen + message: Wir senden Ihnen eine E-Mail zur Überprüfung. + disabled: Zurücksetzen des Passworts ist nicht verfügbar. + frequent-mail: Du klickst zu schnell auf den Senden-Button. Warte einige Minuten. + unregistered: Diese E-Mail-Adresse ist nicht registriert. + success: E-Mail gesendet, bitte überprüfen Sie Ihren Posteingang. Der Link wird in 1 Stunde abgelaufen. + failed: Verifizierungs-E-Mail konnte nicht versendet werden + ignore: Wenn Sie sich nicht auf unserer Seite angemeldet haben, ignorieren Sie bitte diese E-Mail. Es ist kein Abmelden erforderlich. + reset: Passwort zurücksetzen + notice: Diese E-Mail wurde automatisch gesendet. Bitte nicht antworten! + mail: + title: Passworts zurücksetzen auf :sitename + message: Sie erhalten diese E-Mail, weil jemand versucht hat, Ihr Passwort zurückzusetzen. + reset: 'Um Ihr Passwort zurückzusetzen, besuchen Sie bitte: :url' + ignore: Wenn Sie keine Passwortzurücksetzung angefordert haben, ist keine weitere Aktion erforderlich. +reset: + title: Passwort zurücksetzen + button: Zurücksetzen + invalid: Ungültiger Link. + expired: Dieser Link ist abgelaufen. + message: ':username, reset your password here.' + success: Passwort erfolgreich zurückgesetzt. +bind: + title: E-Mail verbinden + button: verbinden + message: Du musst deinen E-Mail-Addersse angeben, um fortfahren zu können. + introduction: Wir werden dir keinen Spam senden. + registered: Diese E-Mail-Adresse ist bereits vergeben. +verify: + title: E-Mail-Adresse bestätigen + invalid: Ungültiger Link. + not-matched: Die Email-Adresse stimmt nicht überein. +validation: + user: Benutzer nicht gefunden. + password: Falsches Passwort. +logout: + success: Du hast dich erfolgreich abgemeldet. +oauth: + authorization: + title: Autorisierung + introduction: Eine Drittanbieter-Anwendung ":name" bittet um Erlaubnis, auf Ihr Konto zuzugreifen. + button: Autorisieren + permissions: Berechtigungen + scope: + user: + read: Anmelden und Profil einstellen + notification: + read: Ermöglicht der App, Ihre Benachrichtigungen zu lesen. + readwrite: Ermöglicht der App, Benachrichtigungen zu senden. + player: + read: Ermöglicht der App, Benachrichtigungen zu lesen. + readwrite: Ermöglicht der App, Ihre Spieler zu erstellen, zu lesen, zu aktualisieren und zu löschen. + closet: + read: Ermöglicht der App, den Kleiderschrank zu sehen. + readwrite: Ermöglicht der App, den Kleiderschrank zu ändern. + users-management: + read: Ermöglicht der App, das Benutzerprofil zu lesen. + readwrite: Ermöglicht der App, das Benutzerprofil zu erstellen, zu lesen, zu aktualisieren und zu löschen. + players-management: + read: Ermöglicht der App, die hinzugefügten Spielerdaten zu lesen. + readwrite: Ermöglicht der App, Spielerdaten zu erstellen, zu lesen, zu aktualisieren und zu löschen. + closet-management: + read: Ermöglicht der App, den Kleiderschrank zu sehen. + readwrite: Ermöglicht der App, Skins hinzuzufügen, zu ändern, und zu löschen. + reports-management: + read: Ermöglicht der App, Meldungen zu lesen. + readwrite: Ermöglicht der App, Meldungen des Benutzers zu lesen und zu überprüfen. +email: E-Mail-Adresse +register-link: Registrieren diff --git a/resources/lang/de_DE/errors.yml b/resources/lang/de_DE/errors.yml new file mode 100755 index 0000000..e170858 --- /dev/null +++ b/resources/lang/de_DE/errors.yml @@ -0,0 +1,19 @@ +--- +http: + msg-403: Sie haben keine Zugriffsberechtigung für diese Seite. + msg-404: Hier ist nichts. + msg-500: Bitte später nochmal versuchen. + msg-503: Die Anwendung befindet sich jetzt im Wartungsmodus. + method-not-allowed: Methode ist nicht zulässig. + csrf-token-mismatch: Token stimmt nicht überein. Laden Sie die Seite neu. + ie: Ihr Browser wird nicht unterstützt. Bitte wechseln Sie zu anderen modernen Browsern wie Firefox oder Chrome. +general: + title: Fehler aufgetreten +exception: + code: 'Fehlercode: :code' + detail: 'Details: :msg' + message: | + Hoppla, sieht so aus, als ob etwas schief gelaufen ist. (Aktiviere APP_DEBUG in .env, um Details zu sehen) +plugins: + duplicate: Das Plugin [:dir1] hat eine doppelte Plugin-Namensdefinition, die mit Plugin [:dir2] identisch ist. Bitte überprüfen Sie Ihr Plugin-Verzeichnis, entfernen Sie eines davon oder verwenden Sie eine andere Namensdefinition. + boot: Es stimmt etwas mit dem Plugin ":plugin". diff --git a/resources/lang/de_DE/front-end.yml b/resources/lang/de_DE/front-end.yml new file mode 100755 index 0000000..8d37a6d --- /dev/null +++ b/resources/lang/de_DE/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: Anmeldung + loggingIn: Anmeldung erfolgt + tooManyFails: + captcha: Zu viele falsche Anmeldungen! Bitte gib das CAPTCHA ein. + recaptcha: Zu viele falsche Anmeldungen! Bitte gib das reCAPTCHA ein. + emptyEmail: Leere E-Mail-Adresse. + invalidConfirmPwd: Die Passwörter stimmen nicht überein. + emptyNickname: Empty nickname. + register: Registrieren + registering: Registrierung läuft + send: Senden + sending: Senden... + reset: Zurücksetzen + resetting: Wird zurückgesetzt... + nickname: Nickname + player-name: Minecraft-Spielername + email: E-Mail-Adresse + identification: E-Mail oder Spielername + password: Passwort + captcha: CAPTCHA + change-captcha: Klicken, für ein neues CAPTCHA-Bild. + login-link: Bereits registriert? Hier anmelden. + forgot-link: Passwort vergessen? + keep: Angemeldet bleiben + repeat-pwd: Passwort wiederholen + nickname-intro: Whatever you like expect special characters + player-name-intro: Player name in Minecraft, can be changed later + forgot: + login-link: Ich erinnere mich noch +skinlib: + private: Private + anonymous: Bitte zuerst anmelden. + reset: Filter zurücksetzen + addToCloset: Zum Kleiderschrank hinzufügen + removeFromCloset: Aus Kleiderschrank entfernen + setItemName: Benenne diese Textur + applyNotice: You can apply it to player at your closet + emptyItemName: Leerer Texturname. + setNewTextureName: 'Lege einen neuen Namen für diese Textur fest:' + emptyNewTextureName: Leerer Texturname. + seeMyUpload: Meine Uploads + apply: Anwenden + filter: + skin: (Automatisch) + steve: (Steve) + alex: (Alex) + cape: (Cape) + uploader: 'Benutzer (UID = :uid) hochgeladen' + allUsers: Alle Nutzer + sort: + title: Anordnen nach + time: Neueste + likes: Beliebteste + emptyTextureName: Leerer Texturname. + emptyUploadFile: Sie haben noch keine Dateien hochgeladen. + fileExtError: 'Fehler: Texturen sollten PNG-Dateien sein.' + uploading: Uploading + setAsPrivate: Auf Privat stellen + setAsPublic: Auf Öffentlich stellen + setPublicNotice: Sure to set this as public texture? + setPrivateNotice: Sure to set this as private texture? + deleteNotice: Are you sure to delete this texture? + setNewTextureModel: "Please select a new texture model:" + upload: + texture-name: Texture Name + texture-type: Texture Type + select-file: Datei auswählen + privacy-notice: Prevent it from being visible at skin library. + set-as-private: Make it Private + button: Hochladen + cost: Dies kostet dich :score Punkte. + award: You'll be awarded :score score(s) by uploading public texture. + show: + anonymous: Sie müssen sich anmelden, um den Kleiderschrank zu verwenden + likes: People who like this + detail: Details + name: Texturname + edit: bearbeiten + model: Modell + size: Dateigröße + uploader: Hochgeladen von + upload-at: Hochgeladen am + download: Herunterladen + delete-texture: Textur löschen + manage-notice: The texture which was deleted or setted to private will be removed from the closet of everyone who had favorited it. + report: + title: Melden + reason: Tell us reason please. + positive: To encourage positive contributions to the skinlib, we will reward who reported inappropriate content with :score scores. However, if any malicious reporting behaviors were found, all scores rewarded will be taken back. + negative: To mitigate the impact of malicious reports, we will require :score scores for submitting a texture report. Don't worry. The suspended scores and additional reward will be sent to your account after your report reviewed by administrators. +user: + signRemainingTime: 'Available after :time :unit' + timeUnitHour: h + timeUnitMin: min + emptyClosetMsg: >- +

Nothing in your closet...

Why not explore the Skin Library for a while?

+ renameItem: Eintrag umbenennen + removeItem: Aus Kleiderschrank entfernen + setAsAvatar: Als Avatar festlegen + viewInSkinlib: In der Skingallerie anzeigen + switch2dPreview: Zur 2D-Vorschau wechseln + switch3dPreview: Wechsel zur Vorschau + removeFromClosetNotice: Sure to remove this texture from your closet? + emptySelectedTexture: Kein Textur ausgewählt. + renameClosetItem: 'Gib einen neuen Namen für dieses Element ein:' + changePlayerName: 'Please enter the player name:' + emptyPlayerName: Empty player name. + deletePlayer: Sure to delete this player? + deletePlayerNotice: It's permanent. No backups. + chooseClearTexture: Choose texture types you want to clear + noClearChoice: Kein Typ ausgewählt + setAvatar: Sind Sie sicher, dies als Ihr Avatar zu setzen? + setAvatarNotice: Das Kopfsegment des Skins wird verwendet. + resetAvatarConfirm: Möchten Sie Ihren Avatar wirklich zurücksetzen? + typeToSearch: Suchen… + useAs: Anwenden... + resetSelected: Ausgewählte löschen + closet: + upload: Textur hochladen + use-as: + title: Which player should be applied to? + empty: It seems that you own no player... + used: + title: Verwendete Ressourcen + players: Registered players + storage: Speichernutzung + cur-score: Aktuelle Punktzahl + score-notice: Klicken Sie auf die Punktzahl, für weitere Informationen. + sign: Punkte einsammeln + player: + operation: Operations + edit-pname: Edit Name + delete-texture: Clear Textures + delete-player: Delete + add-player: Add new player + texture-empty: Nothing + verification: + title: Verifiziere dein Konto + message: Du musst deine E-Mail-Adresse verifizieren, bevor du den Skin Hosting-Dienst nutzen kannst. Du hast die E-Mail noch nicht erhalten? + resend: Klicke hier, um die Bestätigungsmail erneut zu senden. + sending: Wird gesendet... + oauth: + id: Client-ID + name: App-Name + secret: Client Secret + redirect: Callback URL + modifyName: Appnamen ändern. + modifyUrl: Callback URL ändern. + create: Neue Anwendung erstellen + confirmRemove: Sind Sie sicher, diese App löschen zu wollen? Sie können dies nicht rückgängig machen. +admin: + operationsTitle: Operations + permission: Berechtigung + deleteUser: Löschen + changeEmail: E-Mail-Adresse bearbeiten + newUserEmail: 'Bitte neue E-Mail Adresse eingeben:' + verification: E-Mail-Adresse bestätigen + toggleVerification: Bestätigungsstatus umschalten + changeNickName: Edit Nickname + newUserNickname: 'Please enter the new nickname:' + changePassword: Passwort ändern + newUserPassword: 'Bitte geben Sie ein neues Passwort ein:' + changeScore: Punktzahl bearbeiten + newScore: 'Bitte geben Sie eine neue Punktzahl ein:' + changePermission: Change permission + newPermission: 'Please select new permission:' + deleteUserNotice: Are you sure to delete this user? It' permanent. + banned: Gesperrt + normal: Normal + admin: Administrator + superAdmin: Super-Administrator + unverified: Unverifiziert + verified: Verifiziert + pidNotice: >- + Please enter the tid of texture. Inputing 0 can clear texture of this player. + changeTexture: Texturen ändern + changePlayerName: Spielernamen ändern + changeOwner: Besitzer ändern + textureType: Texturen-Typ + deletePlayer: Löschen + changePlayerOwner: 'Please enter the id of user which this player should be transferred to:' + deletePlayerNotice: Are you sure to delete this player? It' permanent. + changePlayerNameNotice: 'Bitte geben Sie einen neuen Spielernamen ein:' + emptyPlayerName: Spielername darf nicht leer sein. + configurePlugin: Konfigurieren + deletePlugin: Löschen + noDependencies: Keine Abhängigkeiten + pluginTitle: Plugin + pluginAuthor: Autor + pluginVersion: Version + pluginReadme: Anleitung + pluginDescription: Beschreibung + pluginDependencies: Abhängigkeiten + installPlugin: Installieren + pluginInstalling: Installiere... + updatePlugin: Akutalisieren + pluginUpdating: Aktualisierung läuft... + confirmUpdate: Möchten Sie ":plugin" von :old auf :new aktualisieren? + enablePlugin: Aktivieren + disablePlugin: Deaktivieren + confirmDeletion: Soll dieses Plugin wirklich gelöscht werden? + uploadArchive: Archiv hochladen + uploadArchiveNotice: Installieren Sie ein Plugin, indem Sie ein Zip-Archiv hochladen. + downloadRemote: Vom Server herunterladen + downloadRemoteNotice: Installieren Sie ein Plugin, indem Sie ein Zip-Archiv von einer entfernten URL herunterladen. + updateButton: Jetzt aktualisieren + downloading: Wird heruntergeladen... + i18n: + group: Gruppe + key: Schlüssel + text: Text + empty: (Leer) + modify: Ändern + delete: Löschen + updating: 'Bitte geben Sie einen neuen Text ein:' + confirmDelete: Sind Sie sicher? Diese Aktion ist unwiderruflich. +report: + tid: Textur ID + reporter: Gemeldet von + reason: Begründung + status-title: Status + status: + - Ausstehend + - Abgeschlossen + - Abgelehnt + time: Meldezeit + delete: Löschen + ban: Sperren + reject: Ablehnen +general: + skin: Skin + cape: Umhang + fatalError: Schwerer Fehler + confirmLogout: Wirklich abmelden? + confirm: OK + cancel: Abbrechen + submit: Speichern + close: Schließen + more: Mehr + tip: Hinweis + noResult: Keine Ergebnisse. + texturePreview: Texturvorschau + walk: Gehen + run: Laufen + rotation: Rotation + pause: Pausieren + reset: Zurücksetzen + skinlib: Gallerie + wait: Bitte warten... + csrf: Diese Seite ist veraltet. Bitte aktualisieren Sie sie. + user: + email: E-Mail-Adresse + nickname: Nick Name + score: Punkte + register-at: Registriert am + player: + owner: Besitzer + player-name: Spielername + previews: Texturvorschau + last-modified: Letzte Änderung +colors: + black: Schwarz + white: Weiß + gray: Grau + prev: Vorheriger Hintergrund + next: Nächster Hintergrund +vendor: + datatable: + search: Suchen + prev: Vorheriges + next: Nächstes diff --git a/resources/lang/de_DE/general.yml b/resources/lang/de_DE/general.yml new file mode 100755 index 0000000..443f4df --- /dev/null +++ b/resources/lang/de_DE/general.yml @@ -0,0 +1,59 @@ +--- +index: Startseite +skinlib: Gallerie +user-center: User Center +logout: Abmelden +login: Anmelden +register: Registrieren +profile: Kontoeinstellungen +admin-panel: Administration +explore: Entdecken +manage: Manage +anonymous: Guest +back: Back +dashboard: Übersicht +my-closet: Closet +my-reports: Reports +developer: Advanced +oauth-manage: OAuth2 Apps +player-manage: Players +user-manage: Users +report-manage: Reports +plugin-manage: Plugins +plugin-market: Plugin Market +plugin-configs: Plugin Configs +customize: Customize +i18n: Internationalization +options: Options +score-options: Score Options +res-options: Resource Options +status: Status +check-update: Nach Updates suchen +download-update: Aktualisierung herunterladen +close: Schließen +skin: Skin +cape: Umhang +submit: Speichern +cancel: Abbrechen +yes: true +no: false +op-success: Gespeichert. +unknown: Unknown +notice: Notice +illegal-parameters: Illegal parameters. +private: Private +public: Öffentlich +unexistent-user: Benutzer nicht gefunden. +player-banned: Das Konto dieses Spielers wurde gebannt. +texture-deleted: Die angeforderte Textur wurde gelöscht. +user: + email: E-Mail-Adresse + nickname: Benutzername + password: Passwort + score: Punkte + register-at: Registriert am +player: + owner: Besitzer + player-name: Player Name + previews: Texturvorschau + last-modified: Letzte Änderung diff --git a/resources/lang/de_DE/index.yml b/resources/lang/de_DE/index.yml new file mode 100755 index 0000000..96a1df8 --- /dev/null +++ b/resources/lang/de_DE/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: Funktionen + first: + icon: fa-users + name: Multi Accounts + desc: Verwalte alle Minecraft-Accounts mit nur einem LittleSkin-Konto. + second: + icon: fa-share-alt + name: Riesige Auswahl + desc: Erkunde die Skin Gallerie, entdecke deine Favoriten und teile sie mit deinen Freunden. + third: + icon: fa-cloud + name: Kostenlos + desc: Für immer kostenlos. Ohne Werbung. Ohne Abos. +introduction: ':sitename bietet einen Service zum Hochladen und Hosten von Minecraft-Skins. Durch die Installation von Skinmods (z.B. CustomSkinLoader), kannst du Skins und Capes für deinen Spielcharakter auswählen und andere Spieler können deinen Skin sehen.' +start: Registrieren diff --git a/resources/lang/de_DE/options.yml b/resources/lang/de_DE/options.yml new file mode 100755 index 0000000..0622286 --- /dev/null +++ b/resources/lang/de_DE/options.yml @@ -0,0 +1,180 @@ +--- +option-saved: Optionen gespeichert. +homepage: + title: Startseite + home_pic_url: + title: Bild-URL auf der Startseite + hint: Path relative to homepage or full URL, leave empty to use default image. + favicon_url: + title: Favicon + hint: Path relative to public/ or full URL. + description: The given image must have same width and height (leave blank to use default icon). + transparent_navbar: + title: Transparent Navigation Bar + label: This will enable transparent navigation bar of home page, but it will turn to be normal if page is scrolled to bottom. + hide_intro: + title: Hide Introduction at Bottom + label: Scroll bar will be disabled if this option is enabled, as version 2.x. + fixed_bg: + title: Fixed Background + label: This option will make background fixed, not scrolled with scroll bar. + copyright_prefer: + title: Program Copyright + description: "You can specify a different style of program copyright for each language. To edit a specific language's corresponding program copyright style, please switch to that language and submit your edit.
Warning: Any evil modification applied on the footer program copyright (including deleting, modifying author, changing link target) with out permission is FORBIDDEN. The author reserves the right to pursue relevant responsibilities." + copyright_text: + title: Custom Copyright Text + description: Placeholders are available in custom copyright text. e.g. {site_name} & {site_url}. You can also specify a different footer for each language. To edit a specific language's corresponding footer, please switch to that language and submit your edit. +customJsCss: + title: Custom CSS/JavaScript + message: | + The contents will be attached to <style> and <script> tags.
+ - Here are some useful examples: Examples of Custom CSS & JavaScript + custom_css: CSS + custom_js: JavaScript +rate: + title: Scores + score_per_storage: + title: Storage + addon: scores = 1 KB + private_score_per_storage: + title: Private Storage + addon: scores = 1 KB + hint: Uploading private textures will cost more scores. + score_per_closet_item: + title: Favorites + addon: score = 1 closet item + return_score: + title: Score Return + label: Return scores back to user after deleting players/textures/closet items. + score_per_player: + title: Players + addon: scores = 1 player + user_initial_score: User Initial Score +report: + title: Reporting Textures + reporter_score_modification: + title: Scores for Submitting an Report + description: Set a positive integer value to reward user who submits new reports. Set to a negative value will require scores for submitting reports, and the suspended scores will be available if user's report was resolved. Set to 0 to disable. + reporter_reward_score: + title: Reward the Reporter with Scores If Report Resolved +sign: + title: Signing + sign_score: + title: Score Granted + addon1: scores ~ + addon2: scores + sign_gap_time: + title: Gap Time + addon: hours + sign_after_zero: + title: Time + label: Users can sign in after 0 everyday. + hint: The above option will be ignored if this is checked. +sharing: + title: Awarding Sharing + score_award_per_texture: + title: Uploader will be rewarded for each uploading texture with + take_back_scores_after_deletion: + title: Return scores + label: Return scores if uploader setting private or deleting texture. + score_award_per_like: + title: Each time the texture is collected, uploader will be rewarded with +general: + title: General Options + site_name: Site Name + site_description: + title: Site Description + description: You can also specify a different site name and description for each language. To edit a specific language's corresponding site name or description text, please switch to that language and submit your edit. + site_url: + title: Site URL + hint: Begin with http(s)://, nerver ends with slash. + register_with_player_name: + title: Register with Player Name + label: Require Minecraft's player name when user register + require_verification: + title: Account Verification + label: Users must verify their email address first. + regs_per_ip: Max accounts of one IP + max_upload_file_size: + title: Max Upload Size + hint: "Limit specified in php.ini: :size" + player_name_rule: + title: Player Name Rule + official: Letters, numbers and underscores (Mojang's official rule) + cjk: Allow CJK Unified Ideographs + utf8: Allow all valid UTF-8 characters (excluding whitespaces) + custom: Use custom rules (regular expression) + custom_player_name_regexp: + title: Custom Player Name Rules + hint: Only takes effect when the above option is set to 'custom'. Leave empty to allow any character. + placeholder: Regular Expressions + player_name_length: + title: Player Name Length + suffix: characters + auto_del_invalid_texture: + title: Invalid Textures + label: Delete invalid textures automatically. + hint: Delete textures records whose file no longer exists from skinlib. + allow_downloading_texture: + title: Downloading Textures + label: Allow users to directly download the source file of a skinlib item. + status_code_for_private: + title: HTTP Code for Rejecting Accessing Private Textures + texture_name_regexp: + title: Texture Name Rules + hint: The RegExp for validating name of uploaded textures. Leave empty to allow any character except single, double quote and backslash. + placeholder: Regular Expressions + content_policy: + title: Content Policy + description: Display content policy at texture uploading page, supporting Markdown. To edit a specific language's corresponding content policy, please switch to that language and submit your edit. +announ: + title: Announcement + announcement: + description: Styling with Markdown is supported. You can also specify a different announcement for each language. To edit a specific language's corresponding announcement, please switch to that language and submit your edit. +meta: + title: SEO tags + meta_keywords: + title: Keywords + hint: Split with commas. + meta_description: + title: Description + hint: Description defined in "general options" will be used if you left it empty. + meta_extras: + title: Other Custom Tags +recaptcha: + recaptcha_invisible: + title: Invisible + label: Enable Invisible Mode +res-warning: This page is ONLY for advanced users. If you aren't familiar with these, please don't modify them! +resources: + title: Resource Files + hint: Please check these options if you enabled CDN for your site. + force_ssl: + title: Force SSL + label: Use HTTPS protocol to load all front-end assets. + hint: Please check if SSL really available before turning on. + auto_detect_asset_url: + title: Assets URL + label: Determine assets url automatically. + description: Please unable this if assets URLs are wrongly generated under a CDN. The site url will be used if this is not enabled. + cache_expire_time: + title: Cache Exipre Time + hint: In seconds, 86400 = one day, 31536000 = one year. + cdn_address: + title: Front-end Assets CDN + hint: Front-end files won't be loaded if URL is unavailable. + description: | + The CDN URL you give must refer to a mirror of /public directory, + all the files of that directory will be loaded as CDN.
+ How to verify? Verify if {Your CDN URL}/app/manifest.json can be accessed. +cache: + title: Cache Configuration + clear: Clear Cache + cleared: Cache has been cleared. + driver: Current cache driver is 「:driver」. + enable_avatar_cache: + title: Avatar + label: Enable caching avatar + enable_preview_cache: + title: Texture Preivew + label: Enable caching texture preivew diff --git a/resources/lang/de_DE/setup.yml b/resources/lang/de_DE/setup.yml new file mode 100755 index 0000000..dff74a3 --- /dev/null +++ b/resources/lang/de_DE/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "Unable to connect to the target :type database, please check your configuration. The server replied with: :msg" +locked: + title: Already installed + text: It appears that you have already installed Blessing Skin Server. To reinstall, please delete the "install.lock" file under "storage" directory. + button: Back to homepage +updates: + success: + title: Update complete +wizard: + master: + title: Install Wizard - Blessing Skin Server + welcome: + title: Welcome + button: Next + text: Welcome to Blessing Skin Server v:version! + database: + title: Database + text: The database is used for storing data of Blessing Skin. + type: Database Type + host: Database Host + port: Database Port + username: Database Username + password: Database Password + db: Database Name + db-notice: You should provide the path to SQLite file and there is no need to fill other blanks if you use SQLite. + prefix: Prefix of Database Table (Optional) + prefix-notice: You don't need to use this option unless you want to install multiple Blessing Skin Server into one database. + info: + title: Information needed + button: Run install + text: To proceed with the installation, please fill this form with the details of the initial admin account. Don't worry, you can always change these settings later. + admin-email: Admin Email + admin-notice: This is the UNIQUE super admin account who can GIVE or CANCEL other users' admin privilege. + nickname: Nickname + password: Password + pwd-notice: 'Attention: You will need the password to log in. Please keep it at a secure place.' + confirm-pwd: Confirm password + site-name: Site name + site-name-notice: This will be shown on every page. + finish: + title: Installation complete + text: Blessing Skin Server has been installed. Thank you, and enjoy! diff --git a/resources/lang/de_DE/skinlib.yml b/resources/lang/de_DE/skinlib.yml new file mode 100755 index 0000000..d4b4723 --- /dev/null +++ b/resources/lang/de_DE/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: Neuen Skin hochladen +show: + title: Texturdetails + deleted: Diese Textur wurde bereits gelöscht. + private: Die angeforderte Textur ist privat und nur für den Uploader sichtbar. +upload: + title: Textur hochladen + name-rule: Weniger als 32 Zeichen und darf keine Sonderzeichen enthalten. + name-rule-regexp: Benutzerdefinierte Namensregeln werden als :regexp angewendet + private-score-notice: Es kostet mehr Punkte, dies als privat zu setzen. Es werden dir :score Punkte pro KB-Speicher berechnet. + invalid-size: Ungültige :type Datei (Breite :width, Höhe :height) + invalid-hd-skin: Der HD-Skin hat die falsche Größe (Breite und Höhe müssen durch 32 teilbar sein) + lack-score: Du hast nicht genug Punkte, um diese Textur hochzuladen. + repeated: Die Textur wurde bereits von jemand anderem hochgeladen. Du kannst sie direkt zu deinem Kleiderschrank hinzufügen. + success: Die Texture :name wurde erfolgreich hochgeladen. +delete: + success: Die Textur wurde gelöscht. +privacy: + success: Die Textur ist auf :privacy gesetzt. +rename: + success: Die Textur wurde erfolgreich in :name umbenannt. +model: + success: Das Modell der Textur wurde erfolgreich in :model geändert. +no-permission: Sie haben keine Zugriffsberechtigung für diese Textur. +non-existent: Textur nicht gefunden. +report: + duplicate: Sie haben diese Textur bereits gemeldet. Die Administratoren werden sie so bald wie möglich überprüfen. Sie können auch den Status Ihres Berichts im User Center verfolgen. + success: Vielen Dank für Ihre Meldung! Die Administratoren werden sie so bald wie möglich überprüfen. diff --git a/resources/lang/de_DE/user.yml b/resources/lang/de_DE/user.yml new file mode 100755 index 0000000..cff23be --- /dev/null +++ b/resources/lang/de_DE/user.yml @@ -0,0 +1,101 @@ +--- +sign-success: Signed successfully. You got :score scores. +announcement: Announcement +no-unread: No new notifications. +verification: + disabled: Email verification is not available. + frequent-mail: You click the send button too fast. Wait for 60 secs, guy. + verified: Your account is already verified. + success: Verification link was sent, please check your inbox. + failed: We failed to send you the verification link. Detailed message :msg + mail: + title: Verify Your Account on :sitename + message: You are receiving this email because someone registered an account with this email address on :sitename. + reset: 'Click here to verify your account: :url' + ignore: If you did not register an account, no further action is required. +score-intro: + title: What is score? + introduction: | + We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually. + Either adding players, uplaoding textures or adding a skinlib item to your closet will consume scores. + :return-score + + New users will get :initial_score scores initially, and you can acquire :score-from ~ :score-to scores by daily signing in. + will-return-score: The score will be returned if you deleted players, uploaded textures or closet items. + no-return-score: The score will NOT be returned if you deleted players, uploaded textures or closet items. + rates: + storage: ':score scores = 1 KB storage' + player: ':score scores = 1 player' + closet: ':score socres = 1 closet item' +closet: + add: + success: Added :name to closet successfully. + repeated: You have already added this texture. + not-found: We cannot find this texture. + lack-score: You don't have enough score to add it to closet. + rename: + success: The item is successfully renamed to :name + remove: + success: The texture was removed from closet successfully. + non-existent: The texture does not exist in your closet. +player: + login-notice: Now you can log in with player names you owned instead email address. + player-name-rule: + official: Player name may only contains letters, numbers and underscores. + cjk: Player name may contains letters, numbers, underscores and CJK Unified Ideographs. + utf8: Player name must be a UTF-8 string. + custom: Custom player name rules are applied on this site. Please contact admins for further information. + player-name-length: The player name should be at least :min characters and not greater than :max characters. + add: + repeated: The player name is already registered. + lack-score: You don't have enough score to add a player. + success: Player :name was added successfully. + delete: + success: Player :name was deleted successfully. + rename: + repeated: This player name is occupied. Please choose another one. + success: Player :old was renamed to :new + set: + success: The texture was applied to player :name successfully. + clear: + success: The textures of player :name was resetted successfully. +profile: + avatar: + title: Change Avatar? + notice: Click the gear icon "" of any skin in your closet, then click "Set as avatar". We will cut the head segment of that skin for you. If there is no icon like this, please try to disable your ADs blocking extension. + wrong-type: You can't set a cape as avatar. + success: New avatar was set successfully. + reset: Reset Avatar + password: + title: Change Password + old: Old Password + new: New Password + confirm: Repeat Password + button: Change password + wrong-password: Wrong original password. + success: Password updated successfully, please log in again. + nickname: + title: Change Nickname + empty: No nickname is set now. + success: Nickname is successfully updated to :nickname + email: + title: Change Email + new: New Email + password: Current Password + button: Change email + wrong-password: Wrong password. + existed: This email address is occupied. + success: Email address updated successfully, please log in again. + delete: + title: Delete Account + notice: Sure to delete your account on :site? + admin: Admin account can not be deleted. + button: Delete my account + modal-title: You need to enter your password to continue + modal-notice: | + You're about to delete your account. + This is permanent! No backups, no restores, no magic undo button. + We warned you, ok? + password: Current Password + wrong-password: Wrong password. + success: Your account is deleted successfully. diff --git a/resources/lang/de_DE/validation.yml b/resources/lang/de_DE/validation.yml new file mode 100755 index 0000000..a2515bd --- /dev/null +++ b/resources/lang/de_DE/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: 'Das :attribute muss akzeptiert werden.' +active_url: ':attribute ist keine gültige URL.' +after: ':attribute muss ein Datum nach dem :date sein.' +after_or_equal: ':attribute muss ein Datum nach oder gleich :date sein.' +alpha: ':attribute darf nur Buchstaben enthalten.' +alpha_dash: ':attribute darf nur aus Buchstaben, Zahlen, Binde- und Unterstrichen bestehen.' +alpha_num: ':attribute darf nur aus Buchstaben und Zahlen bestehen.' +array: ':attribute muss ein Array sein.' +before: ':attribute muss ein Datum vor dem :date sein.' +before_or_equal: ':attribute muss ein Datum vor oder gleich :date sein.' +between: + numeric: ':attribute muss zwischen :min und :max liegen.' + file: ':attribute muss zwischen :min und :max kilobytes groß sein.' + string: ':attribute muss zwischen :min und :max Zeichen lang sein.' + array: ':attribute muss aus mindestens :min und maximal :max Elementen bestehen.' +boolean: 'Das Feld :attribute muss richtig oder falsch sein.' +captcha: 'Falsches Captcha.' +confirmed: ':attribute stimmt nicht mit der Bestätigung überein.' +date: ':attribute ist kein gültiges Datum.' +date_equals: ':attribute muss ein Datum sein, welches :date entspricht.' +date_format: ':attribute entspricht nicht dem Format :format.' +different: ':attribute und :other müssen unterschiedlich sein.' +digits: ':attribute müssen :digits Ziffern sein.' +digits_between: ':attribute muss zwischen :min und :max Zeichen haben.' +dimensions: ':attribute hat ungültige Bildabmessungen.' +distinct: 'Der Wert von :attribute existiert bereits.' +email: ':attribute muss eine gültige E-Mail-Ad­res­se sein.' +ends_with: ':attribute muss eine der folgenden Endungen aufweisen: :values.' +exists: 'Das ausgewählte :attribute ist ungültig.' +file: ':attribute muss eine Datei sein.' +filled: 'Das Feld :attribute muss einen Wert haben.' +gt: + numeric: ':attribute muss größer als :value sein.' + file: 'Das :attribute muss mindestens :min Kilobytes groß sein.' + string: ':attribute muss mehr als :value Zeichen haben.' + array: ':attribute muss mehr als :value Elemente haben.' +gte: + numeric: 'Das :attribute muss größer oder gleich :value sein.' + file: ':attribute muss größer oder gleich :value Kilobytes sein.' + string: ':attribute muss größer als oder gleich": Zeichen haben.' + array: ':attribute muss :value Elemente oder mehr haben.' +image: ':attribute muss ein Bild sein.' +in: 'Das ausgewählte :attribute ist ungültig.' +in_array: ':attribute existiert nicht in :other.' +integer: ':attribute muss eine ganze Zahl sein.' +ip: ':attribute muss eine gültige IP-Adresse sein.' +ipv4: ':attribute muss eine gültige IPv4-Adresse sein.' +ipv6: ':attribute muss eine gültige IPv6-Adresse sein.' +json: ':attribute muss ein gültiger JSON-String sein.' +lt: + numeric: ':attribute muss kleiner sein :value sein.' + file: 'Das :attribute muss kleiner als :value Kilobyte sein.' + string: ':attribute muss weniger als :value Zeichen haben.' + array: ':attribute muss weniger Elemente als :min haben.' +lte: + numeric: ':attribute muss kleiner oder gleich :value sein.' + file: 'Das :attribute darf nicht größer als :value Kilobytes sein.' + string: 'Das :attribute darf nicht größer als :value Zeichen sein.' + array: ':attribute darf nicht mehr als :value Elemente haben.' +max: + numeric: ':attribute darf nicht größer als :max sein.' + file: ':attribute darf nicht größer sein als :max kilobytes.' + string: ':attribute darf nicht mehr als :max Zeichen enthalten.' + array: 'Das :attribute darf nicht größer als :max Elemente sein.' +mimes: ':attribute muss den Dateityp :values haben.' +mimetypes: ':attribute muss den Dateityp :values haben.' +min: + numeric: ':attribute muss mindestens :min sein.' + file: ':attribute muss mindestens :min Kilobyte groß sein.' + string: ':attribute benötigt mindestens :min Zeichen.' + array: ':attribute muss mindestens :min Elemente enthalten.' +not_in: 'Das ausgewählte :attribute ist ungültig.' +not_regex: ':attribute Format ungültig.' +numeric: ':attribute muss eine Zahl sein.' +password: Das Passwort ist falsch. +present: ':attribute muss ausgefüllt sein.' +recaptcha: 'reCAPTCHA-Überprüfung fehlgeschlagen.' +regex: ':attribute Format ist ungültig.' +required: 'Das Feld :attribute muss ausgefüllt sein.' +required_if: ':attribute feld wird benötigt wenn :other :value entspricht.' +required_unless: 'Das Feld :attribute ist erforderlich, außer :other ist in :values enthalten.' +required_with: 'Das Feld :attribute ist erforderlich, wenn :values vorhanden sind.' +required_with_all: 'Die :Attribut Feld ist erforderlich, wenn :Werte vorhanden sind.' +required_without: 'Das :attribute Feld ist erforderlich, wenn :values nicht vorhanden sind.' +required_without_all: ':attribute ist erforderlich, wenn keine der :values vorhanden sind.' +same: ':attribute und :other müssen übereinstimmen.' +size: + numeric: ':attribute muss :size groß sein.' + file: ':attribute muss :size Kilobytes sein.' + string: ':attribute muss :size Zeichen lang sein.' + array: ':attribute muss genau :size Elemente haben.' +starts_with: ':attribute muss mit einem der folgenden Elemente beginnen: :values.' +string: ':attribute muss eine Zeichenfolge sein.' +timezone: ':attribute muss eine gültige Zeitzone sein.' +unique: ':attribute ist schon vergeben.' +uploaded: ':attribute konnte nicht hochgeladen werden.' +url: ':attribute Format ungültig.' +uuid: ':attribute muss eine gültige UUID sein.' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: Name + player_name: Spielername + identification: E-Mail oder Spielername + email: E-Mail + password: Passwort + password_confirmation: 'Passwort bestätigen' + title: Titel + content: Inhalt diff --git a/resources/lang/el_GR/admin.yml b/resources/lang/el_GR/admin.yml new file mode 100755 index 0000000..5cd4d2d --- /dev/null +++ b/resources/lang/el_GR/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: Registered Users + total-players: Players + total-textures: Uploaded Textures + disk-usage: Disk Usage + overview: Overview + texture-uploads: Texture Uploads + user-registration: User Registration +notifications: + send: + title: Send Notification + success: Sent successfully! + receiver: + title: Receiver + all: All Users + normal: Normal Users + uid: Specified UID + email: Specified Email + title: Title + content: Content (Markdown is supported.) +users: + operations: + non-existent: No such user. + no-permission: You have no permission to operate this user. + email: + success: Email changed successfully. + verification: + success: Account verification status toggled successfully. + nickname: + success: Nickname changed successfully. + password: + success: Password changed successfully. + score: + success: Score changed successfully. + permission: Permission updated. + delete: + success: The account has been deleted successfully. +players: + no-permission: You have no permission to operate this player. + textures: + non-existent: No such texture tid.:tid + success: The textures of :player has been updated. + name: + success: Player name has been updated to :player + owner: + success: The player :player was transferred to user :user. + delete: + success: The player has been deleted successfully. +customize: + change-color: + title: Change Theme Color + colors: + navbar: Top Navigation Bar + sidebar: + dark: Sidebar (Dark) + light: Sidebar (Light) +i18n: + add: Add New Language Line + added: Language line added. + updated: Language line updated. + deleted: Language line deleted. + group: Group + key: Key + text: Text + tip: How can I use this page? +status: + info: Information + health: Health + bs: + name: Blessing Skin + version: Version + env: Application Environment + debug: Debugging or Not? + commit: Commit + laravel: Laravel Version + server: + name: Server + php: PHP Version + web: Web Server Software + os: OS + db: + name: Database + type: Server + host: Host + port: Port + username: Username + database: Database + prefix: Table Prefix + plugins: Enabled Plugins (:amount) +plugins: + readme: Read Me + operations: + title: Operations + enabled: ':plugin has been enabled.' + unsatisfied: + notice: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't enable it. Please install or update the plugins listed below, and disable those have conflicts. + disabled: 'The ":name" plugin is not enabled.' + version: 'The version of ":title" does not satisfies the constraint ":constraint".' + conflict: 'The ":title" plugin cannot run with this plugin at the same time.' + disabled: ':plugin has been disabled.' + deleted: The plugin was deleted successfully. + no-config-notice: The plugin is not installed or doesn't provide a configuration page. + no-readme-notice: The plugin doesn't contain a readme file. + not-found: No such plugin. + market: + unresolved: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't download it. Please install or update the plugins listed below, and disable those have conflicts. + connection-error: Unable to connect to the plugins registry. :error + non-existent: The plugin :plugin does not exist. + install-success: Plugin was installed. +update: + complete: Update completed + info: + title: Update Information + up-to-date: Already up-to-date. + available: New version available. + versions: + latest: "Latest Version:" + current: "Current Version:" + check-github: Check GitHub Releases + button: Update Now + cautions: + title: Cautions + link: check out this. + text: | + Please choose update source according to your host's network environment. + Low-speed connection between update source and your host will cause long-time loading at checking and downloading page. + To change the default update source, + errors: + connection: "Unable to access to current update source. Details: :error" + spec: Current update source is not supported. + php: Your PHP version is too low to update. Requires :version or later. +download: + errors: + download: 'Failed to download. Error: :error' + shasum: File validation failed. Please download again. + unzip: Failed to unpack files. +invalid-action: Invalid action diff --git a/resources/lang/el_GR/auth.yml b/resources/lang/el_GR/auth.yml new file mode 100755 index 0000000..99d54ee --- /dev/null +++ b/resources/lang/el_GR/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: Log In + message: Log in to manage your skin & players + success: Logged in successfully. +check: + anonymous: Illegal access. Please log in first. + verified: To access this page, you should verify your email address first. + admin: Only admins are permitted to access this page. + banned: You are banned on this site. Please contact the admin. +register: + title: Register + message: Welcome to :sitename! + success: Your account was registered. Redirecting... + max: You can't register more than :regs accounts. +forgot: + title: Forgot Password + message: We will send you an E-mail to verify. + disabled: Password resetting is not available. + frequent-mail: You click the send button too fast. Wait for some minutes. + unregistered: The email address is not registered. + success: Mail sent, please check your inbox. The link will be expired in 1 hour. + failed: Failed to send verification mail. :msg + ignore: If you haven't signed up on our site, please ignore this email. No unsubscribing is required. + reset: Reset your password + notice: This mail is sending automatically, no reponses will be sent if you reply. + mail: + title: Reset your password on :sitename + message: You are receiving this email because we received a password reset request for your account on :sitename. + reset: 'To reset your password, please visit: :url' + ignore: If you did not request a password reset, no further action is required. +reset: + title: Reset Password + button: Reset + invalid: Invalid link. + expired: This link is expired. + message: ':username, reset your password here.' + success: Password resetted successfully. +bind: + title: Bind Email + button: Bind + message: You need to provide your email adderss to continue. + introduction: We won't send you any spam. + registered: The email address was already taken. +verify: + title: Email Verification + invalid: Invalid link. + not-matched: Email doesn't match. +validation: + user: No such user. + password: Wrong password. +logout: + success: You are now logged out. +oauth: + authorization: + title: Authorization + introduction: A 3rd-party application ":name" is requesting permission to access your account. + button: Authorize + permissions: Permissions + scope: + user: + read: Sign you in and read your profile + notification: + read: Allows the app to read your notifications. + readwrite: Allows the app to send notifications. + player: + read: Allows the app to read your players. + readwrite: Allows the app to create, read, update and delete your players. + closet: + read: Allows the app to read your closet items. + readwrite: Allows the app to create, read, update and delete your closet items. + users-management: + read: Allows the app to read site's users. + readwrite: Allows the app to create, read, update and delete site's users. + players-management: + read: Allows the app to read site's players. + readwrite: Allows the app to create, read, update and delete site's players. + closet-management: + read: Allows the app to read user's of your site closet items. + readwrite: Allows the app to create, read, update and delete user's closet items. + reports-management: + read: Allows the app to read user's reports. + readwrite: Allows the app to read and review user's reports. +email: Email +register-link: Register a new account diff --git a/resources/lang/el_GR/errors.yml b/resources/lang/el_GR/errors.yml new file mode 100755 index 0000000..2bc388c --- /dev/null +++ b/resources/lang/el_GR/errors.yml @@ -0,0 +1,19 @@ +--- +http: + msg-403: You have no permission to access this page. + msg-404: Nothing here. + msg-500: Please try again later. + msg-503: The application is now in maintenance mode. + method-not-allowed: Method not allowed. + csrf-token-mismatch: Token does not match, try reloading the page. + ie: Your browser isn't supported. Please switch to other modern browsers, such as Firefox or Chrome. +general: + title: Error occurred +exception: + code: 'Error code: :code' + detail: 'Details: :msg' + message: | + Whoops, looks like something went wrong. (enable APP_DEBUG in .env to see details) +plugins: + duplicate: The plugin [:dir1] has a duplicated plugin name definition which is same to plugin [:dir2]. Please check your plugins directory, remove one of them or use another name definition. + boot: There is something wrong with plugin ":plugin". diff --git a/resources/lang/el_GR/front-end.yml b/resources/lang/el_GR/front-end.yml new file mode 100755 index 0000000..0438480 --- /dev/null +++ b/resources/lang/el_GR/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: Log In + loggingIn: Logging In + tooManyFails: + captcha: You fails too many times! Please enter the CAPTCHA. + recaptcha: You fails too many times! Please pass the reCAPTCHA challenge. + emptyEmail: Empty email address. + invalidConfirmPwd: Confirming password is not equal with password. + emptyNickname: Empty nickname. + register: Register + registering: Registering + send: Send + sending: Sending + reset: Reset + resetting: Resetting + nickname: Nickname + player-name: Minecraft player name + email: Email + identification: Email or player name + password: Password + captcha: CAPTCHA + change-captcha: Click to change CAPTCHA image. + login-link: Already registered? Log in here. + forgot-link: Forgot password? + keep: Remember me + repeat-pwd: Repeat your password + nickname-intro: Whatever you like expect special characters + player-name-intro: Player name in Minecraft, can be changed later + forgot: + login-link: I do remember it +skinlib: + private: Private + anonymous: Please login first. + reset: Reset Filter + addToCloset: Add to closet + removeFromCloset: Remove from closet + setItemName: Set a name for this texture + applyNotice: You can apply it to player at your closet + emptyItemName: Empty texture name. + setNewTextureName: 'Please enter the new texture name:' + emptyNewTextureName: Empty new texture name. + seeMyUpload: My Uploads + apply: Apply + filter: + skin: (Any Model) + steve: (Steve) + alex: (Alex) + cape: (Cape) + uploader: 'User (UID = :uid) Uploaded' + allUsers: All Users + sort: + title: Sort + time: Latest + likes: Most Likes + emptyTextureName: Empty texture name. + emptyUploadFile: You have not uploaded any file. + fileExtError: 'Error: Textures should be PNG files.' + uploading: Uploading + setAsPrivate: Set as Private + setAsPublic: Set as Public + setPublicNotice: Sure to set this as public texture? + setPrivateNotice: Sure to set this as private texture? + deleteNotice: Are you sure to delete this texture? + setNewTextureModel: "Please select a new texture model:" + upload: + texture-name: Texture Name + texture-type: Texture Type + select-file: Select File + privacy-notice: Prevent it from being visible at skin library. + set-as-private: Make it Private + button: Upload + cost: It costs you about :score score. + award: You'll be awarded :score score(s) by uploading public texture. + show: + anonymous: You must login to use closets + likes: People who like this + detail: Details + name: Texture Name + edit: Edit + model: Applicable Model + size: File Size + uploader: Uploader + upload-at: Upload At + download: Download + delete-texture: Delete Texture + manage-notice: The texture which was deleted or setted to private will be removed from the closet of everyone who had favorited it. + report: + title: Report + reason: Tell us reason please. + positive: To encourage positive contributions to the skinlib, we will reward who reported inappropriate content with :score scores. However, if any malicious reporting behaviors were found, all scores rewarded will be taken back. + negative: To mitigate the impact of malicious reports, we will require :score scores for submitting a texture report. Don't worry. The suspended scores and additional reward will be sent to your account after your report reviewed by administrators. +user: + signRemainingTime: 'Available after :time :unit' + timeUnitHour: h + timeUnitMin: min + emptyClosetMsg: >- +

Nothing in your closet...

Why not explore the Skin Library for a while?

+ renameItem: Rename item + removeItem: Remove from closet + setAsAvatar: Set as avatar + viewInSkinlib: View in skin library + switch2dPreview: Switch to 2D Preview + switch3dPreview: Switch to 3D Preview + removeFromClosetNotice: Sure to remove this texture from your closet? + emptySelectedTexture: No texture is selected. + renameClosetItem: 'Set a new name for this item:' + changePlayerName: 'Please enter the player name:' + emptyPlayerName: Empty player name. + deletePlayer: Sure to delete this player? + deletePlayerNotice: It's permanent. No backups. + chooseClearTexture: Choose texture types you want to clear + noClearChoice: You haven't choose any types + setAvatar: Sure to set this as your avatar? + setAvatarNotice: The head segment of skin will bu used. + resetAvatarConfirm: Are you sure to reset your avatar? + typeToSearch: Type to search + useAs: Apply... + resetSelected: Clear selected + closet: + upload: Upload Texture + use-as: + title: Which player should be applied to? + empty: It seems that you own no player... + used: + title: Resources Used + players: Registered players + storage: Storage used + cur-score: Current Score + score-notice: Click the score to show introduction. + sign: Sign + player: + operation: Operations + edit-pname: Edit Name + delete-texture: Clear Textures + delete-player: Delete + add-player: Add new player + texture-empty: Nothing + verification: + title: Verify Your Account + message: You must verify your email address before using the skin hosting service. Haven't received the email? + resend: Click here to send again. + sending: Sending... + oauth: + id: Client ID + name: App Name + secret: Client Secret + redirect: Callback URL + modifyName: Modify app name. + modifyUrl: Modify callback URL. + create: Create New App + confirmRemove: Are you sure to delete this app? You won't be able to undo this. +admin: + operationsTitle: Operations + permission: Permission + deleteUser: Delete + changeEmail: Edit Email + newUserEmail: 'Please enter the new email:' + verification: Email Verification + toggleVerification: Toggle Verification Status + changeNickName: Edit Nickname + newUserNickname: 'Please enter the new nickname:' + changePassword: Edit Password + newUserPassword: 'Please enter the new password:' + changeScore: Edit Score + newScore: 'Please enter the new score:' + changePermission: Change permission + newPermission: 'Please select new permission:' + deleteUserNotice: Are you sure to delete this user? It' permanent. + banned: Banned + normal: Normal + admin: Admin + superAdmin: Super Admin + unverified: Unverified + verified: Verified + pidNotice: >- + Please enter the tid of texture. Inputing 0 can clear texture of this player. + changeTexture: Change Textures + changePlayerName: Change Player Name + changeOwner: Change Owner + textureType: Texture Type + deletePlayer: Delete + changePlayerOwner: 'Please enter the id of user which this player should be transferred to:' + deletePlayerNotice: Are you sure to delete this player? It' permanent. + changePlayerNameNotice: 'Please input new player name:' + emptyPlayerName: Player name cannot be empty. + configurePlugin: Configure + deletePlugin: Delete + noDependencies: No Dependencies + pluginTitle: Plugin + pluginAuthor: Author + pluginVersion: Version + pluginReadme: Read Me + pluginDescription: Description + pluginDependencies: Dependencies + installPlugin: Install + pluginInstalling: Installing... + updatePlugin: Update + pluginUpdating: Updating... + confirmUpdate: Are you sure to update ":plugin" from :old to :new? + enablePlugin: Enable + disablePlugin: Disable + confirmDeletion: Are you sure to delete this plugin? + uploadArchive: Upload Archive + uploadArchiveNotice: Install a plugin by uploading a Zip archive. + downloadRemote: Download From Remote + downloadRemoteNotice: Install a plugin by downloading a Zip archive from remote URL. + updateButton: Update Now + downloading: Downloading... + i18n: + group: Group + key: Key + text: Text + empty: (Empty) + modify: Modify + delete: Delete + updating: 'Please type new text:' + confirmDelete: Are you sure? This is irreversible. +report: + tid: Texture ID + reporter: Reporter + reason: Reason + status-title: Status + status: + - Pending + - Resolved + - Rejected + time: Report Time + delete: Delete + ban: Ban + reject: Reject +general: + skin: Skin + cape: Cape + fatalError: Fatal Error + confirmLogout: Sure to log out? + confirm: OK + cancel: Cancel + submit: Submit + close: Close + more: More + tip: Tip + noResult: No result. + texturePreview: Texture Preview + walk: Walk + run: Run + rotation: Rotation + pause: Pause + reset: Reset + skinlib: Skin Library + wait: Please wait... + csrf: This page is out-dated. Please refresh it. + user: + email: Email + nickname: Nick Name + score: Score + register-at: Registered At + player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified +colors: + black: Black + white: White + gray: Gray + prev: Previous Background + next: Next Background +vendor: + datatable: + search: Search + prev: Prev + next: Next diff --git a/resources/lang/el_GR/general.yml b/resources/lang/el_GR/general.yml new file mode 100755 index 0000000..1fe8c6a --- /dev/null +++ b/resources/lang/el_GR/general.yml @@ -0,0 +1,59 @@ +--- +index: Homepage +skinlib: Skin Library +user-center: User Center +logout: Log Out +login: Log In +register: Register Now +profile: User Profile +admin-panel: Admin Panel +explore: Explore +manage: Manage +anonymous: Guest +back: Back +dashboard: Dashboard +my-closet: Closet +my-reports: Reports +developer: Advanced +oauth-manage: OAuth2 Apps +player-manage: Players +user-manage: Users +report-manage: Reports +plugin-manage: Plugins +plugin-market: Plugin Market +plugin-configs: Plugin Configs +customize: Customize +i18n: Internationalization +options: Options +score-options: Score Options +res-options: Resource Options +status: Status +check-update: Check Update +download-update: Download Updates +close: Close +skin: Skin +cape: Cape +submit: Submit +cancel: Cancel +yes: true +no: false +op-success: Operated successfully. +unknown: Unknown +notice: Notice +illegal-parameters: Illegal parameters. +private: Private +public: Public +unexistent-user: No such user. +player-banned: The owner of this player has been banned. +texture-deleted: The requested texture has been deleted. +user: + email: Email + nickname: Nickname + password: Password + score: Score + register-at: Registered At +player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified diff --git a/resources/lang/el_GR/index.yml b/resources/lang/el_GR/index.yml new file mode 100755 index 0000000..bba2e21 --- /dev/null +++ b/resources/lang/el_GR/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: Features + first: + icon: fa-users + name: Multi Player + desc: You can add multiple players within one registered account. + second: + icon: fa-share-alt + name: Sharing + desc: Explore the skin library, send a "like" and share them with your friends. + third: + icon: fa-cloud + name: Free + desc: It is free forever. No ads. No subscription fees. +introduction: ':sitename provides the service of uploading and hosting Minecraft skins. By coordinating with skin mods (e.g. CustomSkinLoader), you can choose skin and cape for your game character, and make it visible to other players in Minecraft.' +start: Join Us diff --git a/resources/lang/el_GR/options.yml b/resources/lang/el_GR/options.yml new file mode 100755 index 0000000..76c6421 --- /dev/null +++ b/resources/lang/el_GR/options.yml @@ -0,0 +1,180 @@ +--- +option-saved: Option saved. +homepage: + title: Homepage + home_pic_url: + title: Picture URL at Homepage + hint: Path relative to homepage or full URL, leave empty to use default image. + favicon_url: + title: Website Icon + hint: Path relative to public/ or full URL. + description: The given image must have same width and height (leave blank to use default icon). + transparent_navbar: + title: Transparent Navigation Bar + label: This will enable transparent navigation bar of home page, but it will turn to be normal if page is scrolled to bottom. + hide_intro: + title: Hide Introduction at Bottom + label: Scroll bar will be disabled if this option is enabled, as version 2.x. + fixed_bg: + title: Fixed Background + label: This option will make background fixed, not scrolled with scroll bar. + copyright_prefer: + title: Program Copyright + description: "You can specify a different style of program copyright for each language. To edit a specific language's corresponding program copyright style, please switch to that language and submit your edit.
Warning: Any evil modification applied on the footer program copyright (including deleting, modifying author, changing link target) with out permission is FORBIDDEN. The author reserves the right to pursue relevant responsibilities." + copyright_text: + title: Custom Copyright Text + description: Placeholders are available in custom copyright text. e.g. {site_name} & {site_url}. You can also specify a different footer for each language. To edit a specific language's corresponding footer, please switch to that language and submit your edit. +customJsCss: + title: Custom CSS/JavaScript + message: | + The contents will be attached to <style> and <script> tags.
+ - Here are some useful examples: Examples of Custom CSS & JavaScript + custom_css: CSS + custom_js: JavaScript +rate: + title: Scores + score_per_storage: + title: Storage + addon: scores = 1 KB + private_score_per_storage: + title: Private Storage + addon: scores = 1 KB + hint: Uploading private textures will cost more scores. + score_per_closet_item: + title: Favorites + addon: score = 1 closet item + return_score: + title: Score Return + label: Return scores back to user after deleting players/textures/closet items. + score_per_player: + title: Players + addon: scores = 1 player + user_initial_score: User Initial Score +report: + title: Reporting Textures + reporter_score_modification: + title: Scores for Submitting an Report + description: Set a positive integer value to reward user who submits new reports. Set to a negative value will require scores for submitting reports, and the suspended scores will be available if user's report was resolved. Set to 0 to disable. + reporter_reward_score: + title: Reward the Reporter with Scores If Report Resolved +sign: + title: Signing + sign_score: + title: Score Granted + addon1: scores ~ + addon2: scores + sign_gap_time: + title: Gap Time + addon: hours + sign_after_zero: + title: Time + label: Users can sign in after 0 everyday. + hint: The above option will be ignored if this is checked. +sharing: + title: Awarding Sharing + score_award_per_texture: + title: Uploader will be rewarded for each uploading texture with + take_back_scores_after_deletion: + title: Return scores + label: Return scores if uploader setting private or deleting texture. + score_award_per_like: + title: Each time the texture is collected, uploader will be rewarded with +general: + title: General Options + site_name: Site Name + site_description: + title: Site Description + description: You can also specify a different site name and description for each language. To edit a specific language's corresponding site name or description text, please switch to that language and submit your edit. + site_url: + title: Site URL + hint: Begin with http(s)://, nerver ends with slash. + register_with_player_name: + title: Register with Player Name + label: Require Minecraft's player name when user register + require_verification: + title: Account Verification + label: Users must verify their email address first. + regs_per_ip: Max accounts of one IP + max_upload_file_size: + title: Max Upload Size + hint: "Limit specified in php.ini: :size" + player_name_rule: + title: Player Name Rule + official: Letters, numbers and underscores (Mojang's official rule) + cjk: Allow CJK Unified Ideographs + utf8: Allow all valid UTF-8 characters (excluding whitespaces) + custom: Use custom rules (regular expression) + custom_player_name_regexp: + title: Custom Player Name Rules + hint: Only takes effect when the above option is set to 'custom'. Leave empty to allow any character. + placeholder: Regular Expressions + player_name_length: + title: Player Name Length + suffix: characters + auto_del_invalid_texture: + title: Invalid Textures + label: Delete invalid textures automatically. + hint: Delete textures records whose file no longer exists from skinlib. + allow_downloading_texture: + title: Downloading Textures + label: Allow users to directly download the source file of a skinlib item. + status_code_for_private: + title: HTTP Code for Rejecting Accessing Private Textures + texture_name_regexp: + title: Texture Name Rules + hint: The RegExp for validating name of uploaded textures. Leave empty to allow any character except single, double quote and backslash. + placeholder: Regular Expressions + content_policy: + title: Content Policy + description: Display content policy at texture uploading page, supporting Markdown. To edit a specific language's corresponding content policy, please switch to that language and submit your edit. +announ: + title: Announcement + announcement: + description: Styling with Markdown is supported. You can also specify a different announcement for each language. To edit a specific language's corresponding announcement, please switch to that language and submit your edit. +meta: + title: SEO tags + meta_keywords: + title: Keywords + hint: Split with commas. + meta_description: + title: Description + hint: Description defined in "general options" will be used if you left it empty. + meta_extras: + title: Other Custom Tags +recaptcha: + recaptcha_invisible: + title: Invisible + label: Enable Invisible Mode +res-warning: This page is ONLY for advanced users. If you aren't familiar with these, please don't modify them! +resources: + title: Resource Files + hint: Please check these options if you enabled CDN for your site. + force_ssl: + title: Force SSL + label: Use HTTPS protocol to load all front-end assets. + hint: Please check if SSL really available before turning on. + auto_detect_asset_url: + title: Assets URL + label: Determine assets url automatically. + description: Please unable this if assets URLs are wrongly generated under a CDN. The site url will be used if this is not enabled. + cache_expire_time: + title: Cache Exipre Time + hint: In seconds, 86400 = one day, 31536000 = one year. + cdn_address: + title: Front-end Assets CDN + hint: Front-end files won't be loaded if URL is unavailable. + description: | + The CDN URL you give must refer to a mirror of /public directory, + all the files of that directory will be loaded as CDN.
+ How to verify? Verify if {Your CDN URL}/app/manifest.json can be accessed. +cache: + title: Cache Configuration + clear: Clear Cache + cleared: Cache has been cleared. + driver: Current cache driver is 「:driver」. + enable_avatar_cache: + title: Avatar + label: Enable caching avatar + enable_preview_cache: + title: Texture Preivew + label: Enable caching texture preivew diff --git a/resources/lang/el_GR/setup.yml b/resources/lang/el_GR/setup.yml new file mode 100755 index 0000000..dff74a3 --- /dev/null +++ b/resources/lang/el_GR/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "Unable to connect to the target :type database, please check your configuration. The server replied with: :msg" +locked: + title: Already installed + text: It appears that you have already installed Blessing Skin Server. To reinstall, please delete the "install.lock" file under "storage" directory. + button: Back to homepage +updates: + success: + title: Update complete +wizard: + master: + title: Install Wizard - Blessing Skin Server + welcome: + title: Welcome + button: Next + text: Welcome to Blessing Skin Server v:version! + database: + title: Database + text: The database is used for storing data of Blessing Skin. + type: Database Type + host: Database Host + port: Database Port + username: Database Username + password: Database Password + db: Database Name + db-notice: You should provide the path to SQLite file and there is no need to fill other blanks if you use SQLite. + prefix: Prefix of Database Table (Optional) + prefix-notice: You don't need to use this option unless you want to install multiple Blessing Skin Server into one database. + info: + title: Information needed + button: Run install + text: To proceed with the installation, please fill this form with the details of the initial admin account. Don't worry, you can always change these settings later. + admin-email: Admin Email + admin-notice: This is the UNIQUE super admin account who can GIVE or CANCEL other users' admin privilege. + nickname: Nickname + password: Password + pwd-notice: 'Attention: You will need the password to log in. Please keep it at a secure place.' + confirm-pwd: Confirm password + site-name: Site name + site-name-notice: This will be shown on every page. + finish: + title: Installation complete + text: Blessing Skin Server has been installed. Thank you, and enjoy! diff --git a/resources/lang/el_GR/skinlib.yml b/resources/lang/el_GR/skinlib.yml new file mode 100755 index 0000000..2fc935a --- /dev/null +++ b/resources/lang/el_GR/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: Upload new skin +show: + title: Texture Details + deleted: The requested texture was already deleted. + private: The requested texture is private and only visible to the uploader and admins. +upload: + title: Upload Texture + name-rule: Less than 32 characters and must not contain any special one. + name-rule-regexp: Custom name rules are applied as :regexp + private-score-notice: It will spend you more scores for setting it as private. You will be charged :score scores for per KB storage. + invalid-size: Invalid :type file (width :width, height :height) + invalid-hd-skin: Invalid HD skin (width and height should be divisible by 32) + lack-score: You don't have enough score to upload this texture. + repeated: The texture is already uploaded by someone else. You can add it to your closet directly. + success: Texture :name was uploaded successfully. +delete: + success: The texture was deleted successfully. +privacy: + success: The texture was set to :privacy successfully. +rename: + success: The texture was renamed to :name successfully. +model: + success: The texture's model was changed to :model successfully. +no-permission: You have no permission to moderate this texture. +non-existent: No such texture. +report: + duplicate: You have already reported this texture. The administrators will review it as soon as possible. You can also track the status of your report at User Center. + success: Thanks for reporting! The administrators will review it as soon as possible. diff --git a/resources/lang/el_GR/user.yml b/resources/lang/el_GR/user.yml new file mode 100755 index 0000000..cff23be --- /dev/null +++ b/resources/lang/el_GR/user.yml @@ -0,0 +1,101 @@ +--- +sign-success: Signed successfully. You got :score scores. +announcement: Announcement +no-unread: No new notifications. +verification: + disabled: Email verification is not available. + frequent-mail: You click the send button too fast. Wait for 60 secs, guy. + verified: Your account is already verified. + success: Verification link was sent, please check your inbox. + failed: We failed to send you the verification link. Detailed message :msg + mail: + title: Verify Your Account on :sitename + message: You are receiving this email because someone registered an account with this email address on :sitename. + reset: 'Click here to verify your account: :url' + ignore: If you did not register an account, no further action is required. +score-intro: + title: What is score? + introduction: | + We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually. + Either adding players, uplaoding textures or adding a skinlib item to your closet will consume scores. + :return-score + + New users will get :initial_score scores initially, and you can acquire :score-from ~ :score-to scores by daily signing in. + will-return-score: The score will be returned if you deleted players, uploaded textures or closet items. + no-return-score: The score will NOT be returned if you deleted players, uploaded textures or closet items. + rates: + storage: ':score scores = 1 KB storage' + player: ':score scores = 1 player' + closet: ':score socres = 1 closet item' +closet: + add: + success: Added :name to closet successfully. + repeated: You have already added this texture. + not-found: We cannot find this texture. + lack-score: You don't have enough score to add it to closet. + rename: + success: The item is successfully renamed to :name + remove: + success: The texture was removed from closet successfully. + non-existent: The texture does not exist in your closet. +player: + login-notice: Now you can log in with player names you owned instead email address. + player-name-rule: + official: Player name may only contains letters, numbers and underscores. + cjk: Player name may contains letters, numbers, underscores and CJK Unified Ideographs. + utf8: Player name must be a UTF-8 string. + custom: Custom player name rules are applied on this site. Please contact admins for further information. + player-name-length: The player name should be at least :min characters and not greater than :max characters. + add: + repeated: The player name is already registered. + lack-score: You don't have enough score to add a player. + success: Player :name was added successfully. + delete: + success: Player :name was deleted successfully. + rename: + repeated: This player name is occupied. Please choose another one. + success: Player :old was renamed to :new + set: + success: The texture was applied to player :name successfully. + clear: + success: The textures of player :name was resetted successfully. +profile: + avatar: + title: Change Avatar? + notice: Click the gear icon "" of any skin in your closet, then click "Set as avatar". We will cut the head segment of that skin for you. If there is no icon like this, please try to disable your ADs blocking extension. + wrong-type: You can't set a cape as avatar. + success: New avatar was set successfully. + reset: Reset Avatar + password: + title: Change Password + old: Old Password + new: New Password + confirm: Repeat Password + button: Change password + wrong-password: Wrong original password. + success: Password updated successfully, please log in again. + nickname: + title: Change Nickname + empty: No nickname is set now. + success: Nickname is successfully updated to :nickname + email: + title: Change Email + new: New Email + password: Current Password + button: Change email + wrong-password: Wrong password. + existed: This email address is occupied. + success: Email address updated successfully, please log in again. + delete: + title: Delete Account + notice: Sure to delete your account on :site? + admin: Admin account can not be deleted. + button: Delete my account + modal-title: You need to enter your password to continue + modal-notice: | + You're about to delete your account. + This is permanent! No backups, no restores, no magic undo button. + We warned you, ok? + password: Current Password + wrong-password: Wrong password. + success: Your account is deleted successfully. diff --git a/resources/lang/el_GR/validation.yml b/resources/lang/el_GR/validation.yml new file mode 100755 index 0000000..58a423e --- /dev/null +++ b/resources/lang/el_GR/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: 'The :attribute must be accepted.' +active_url: 'The :attribute is not a valid URL.' +after: 'The :attribute must be a date after :date.' +after_or_equal: 'The :attribute must be a date after or equal to :date.' +alpha: 'The :attribute may only contain letters.' +alpha_dash: 'The :attribute may only contain letters, numbers, dashes and underscores.' +alpha_num: 'The :attribute may only contain letters and numbers.' +array: 'The :attribute must be an array.' +before: 'The :attribute must be a date before :date.' +before_or_equal: 'The :attribute must be a date before or equal to :date.' +between: + numeric: 'The :attribute must be between :min and :max.' + file: 'The :attribute must be between :min and :max kilobytes.' + string: 'The :attribute must be between :min and :max characters.' + array: 'The :attribute must have between :min and :max items.' +boolean: 'The :attribute field must be true or false.' +captcha: 'Incorrect captcha.' +confirmed: 'The :attribute confirmation does not match.' +date: 'The :attribute is not a valid date.' +date_equals: 'The :attribute must be a date equal to :date.' +date_format: 'The :attribute does not match the format :format.' +different: 'The :attribute and :other must be different.' +digits: 'The :attribute must be :digits digits.' +digits_between: 'The :attribute must be between :min and :max digits.' +dimensions: 'The :attribute has invalid image dimensions.' +distinct: 'The :attribute field has a duplicate value.' +email: 'The :attribute must be a valid email address.' +ends_with: 'The :attribute must end with one of the following: :values.' +exists: 'The selected :attribute is invalid.' +file: 'The :attribute must be a file.' +filled: 'The :attribute field must have a value.' +gt: + numeric: 'The :attribute must be greater than :value.' + file: 'The :attribute must be greater than :value kilobytes.' + string: 'The :attribute must be greater than :value characters.' + array: 'The :attribute must have more than :value items.' +gte: + numeric: 'The :attribute must be greater than or equal :value.' + file: 'The :attribute must be greater than or equal :value kilobytes.' + string: 'The :attribute must be greater than or equal :value characters.' + array: 'The :attribute must have :value items or more.' +image: 'The :attribute must be an image.' +in: 'The selected :attribute is invalid.' +in_array: 'The :attribute field does not exist in :other.' +integer: 'The :attribute must be an integer.' +ip: 'The :attribute must be a valid IP address.' +ipv4: 'The :attribute must be a valid IPv4 address.' +ipv6: 'The :attribute must be a valid IPv6 address.' +json: 'The :attribute must be a valid JSON string.' +lt: + numeric: 'The :attribute must be less than :value.' + file: 'The :attribute must be less than :value kilobytes.' + string: 'The :attribute must be less than :value characters.' + array: 'The :attribute must have less than :value items.' +lte: + numeric: 'The :attribute must be less than or equal :value.' + file: 'The :attribute must be less than or equal :value kilobytes.' + string: 'The :attribute must be less than or equal :value characters.' + array: 'The :attribute must not have more than :value items.' +max: + numeric: 'The :attribute may not be greater than :max.' + file: 'The :attribute may not be greater than :max kilobytes.' + string: 'The :attribute may not be greater than :max characters.' + array: 'The :attribute may not have more than :max items.' +mimes: 'The :attribute must be a file of type: :values.' +mimetypes: 'The :attribute must be a file of type: :values.' +min: + numeric: 'The :attribute must be at least :min.' + file: 'The :attribute must be at least :min kilobytes.' + string: 'The :attribute must be at least :min characters.' + array: 'The :attribute must have at least :min items.' +not_in: 'The selected :attribute is invalid.' +not_regex: 'The :attribute format is invalid.' +numeric: 'The :attribute must be a number.' +password: The password is incorrect. +present: 'The :attribute field must be present.' +recaptcha: 'reCAPTCHA validation failed.' +regex: 'The :attribute format is invalid.' +required: 'The :attribute field is required.' +required_if: 'The :attribute field is required when :other is :value.' +required_unless: 'The :attribute field is required unless :other is in :values.' +required_with: 'The :attribute field is required when :values is present.' +required_with_all: 'The :attribute field is required when :values are present.' +required_without: 'The :attribute field is required when :values is not present.' +required_without_all: 'The :attribute field is required when none of :values are present.' +same: 'The :attribute and :other must match.' +size: + numeric: 'The :attribute must be :size.' + file: 'The :attribute must be :size kilobytes.' + string: 'The :attribute must be :size characters.' + array: 'The :attribute must contain :size items.' +starts_with: 'The :attribute must start with one of the following: :values.' +string: 'The :attribute must be a string.' +timezone: 'The :attribute must be a valid zone.' +unique: 'The :attribute has already been taken.' +uploaded: 'The :attribute failed to upload.' +url: 'The :attribute format is invalid.' +uuid: 'The :attribute must be a valid UUID.' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: name + player_name: player name + identification: email or player name + email: email + password: password + password_confirmation: 'password confirmation' + title: title + content: content diff --git a/resources/lang/en/admin.yml b/resources/lang/en/admin.yml new file mode 100755 index 0000000..c440f98 --- /dev/null +++ b/resources/lang/en/admin.yml @@ -0,0 +1,155 @@ +index: + total-users: Registered Users + total-players: Players + total-textures: Uploaded Textures + disk-usage: Disk Usage + overview: Overview + texture-uploads: Texture Uploads + user-registration: User Registration + +notifications: + send: + title: Send Notification + success: Sent successfully! + receiver: + title: Receiver + all: All Users + normal: Normal Users + uid: Specified UID + email: Specified Email + title: Title + content: Content (Markdown is supported.) + +users: + operations: + non-existent: No such user. + no-permission: You have no permission to operate this user. + email: + success: Email changed successfully. + verification: + success: Account verification status toggled successfully. + nickname: + success: Nickname changed successfully. + password: + success: Password changed successfully. + score: + success: Score changed successfully. + permission: Permission updated. + delete: + success: The account has been deleted successfully. + +players: + no-permission: You have no permission to operate this player. + textures: + non-existent: No such texture tid.:tid + success: The textures of :player has been updated. + name: + success: Player name has been updated to :player + owner: + success: The player :player was transferred to user :user. + delete: + success: The player has been deleted successfully. + +customize: + change-color: + title: Change Theme Color + colors: + navbar: Top Navigation Bar + sidebar: + dark: Sidebar (Dark) + light: Sidebar (Light) + +i18n: + add: Add New Language Line + added: Language line added. + updated: Language line updated. + deleted: Language line deleted. + group: Group + key: Key + text: Text + tip: How can I use this page? + +status: + info: Information + health: Health + bs: + name: Blessing Skin + version: Version + env: Application Environment + debug: Debugging or Not? + commit: Commit + laravel: Laravel Version + server: + name: Server + php: PHP Version + web: Web Server Software + os: OS + db: + name: Database + type: Server + host: Host + port: Port + username: Username + database: Database + prefix: Table Prefix + plugins: Enabled Plugins (:amount) + +plugins: + readme: Read Me + + operations: + title: Operations + enabled: :plugin has been enabled. + unsatisfied: + notice: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't enable it. Please install or update the plugins listed below, and disable those have conflicts. + disabled: 'The ":name" plugin is not enabled.' + version: 'The version of ":title" does not satisfies the constraint ":constraint".' + conflict: 'The ":title" plugin cannot run with this plugin at the same time.' + disabled: :plugin has been disabled. + deleted: The plugin was deleted successfully. + no-config-notice: The plugin is not installed or doesn't provide a configuration page. + no-readme-notice: The plugin doesn't contain a readme file. + not-found: No such plugin. + + market: + unresolved: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't download it. Please install or update the plugins listed below, and disable those have conflicts. + connection-error: Unable to connect to the plugins registry. :error + non-existent: The plugin :plugin does not exist. + install-success: Plugin was installed. + +update: + complete: Update completed + + info: + title: Update Information + + up-to-date: Already up-to-date. + available: New version available. + + versions: + latest: "Latest Version:" + current: "Current Version:" + + check-github: Check GitHub Releases + button: Update Now + + cautions: + title: Cautions + link: check out this. + text: | + Please choose update source according to your host's network environment. + Low-speed connection between update source and your host will cause long-time loading at checking and downloading page. + To change the default update source, + + errors: + connection: "Unable to access to current update source. Details: :error" + spec: Current update source is not supported. + php: Your PHP version is too low to update. Requires :version or later. + +download: + errors: + download: 'Failed to download. Error: :error' + shasum: File validation failed. Please download again. + unzip: Failed to unpack files. + +invalid-action: Invalid action diff --git a/resources/lang/en/auth.yml b/resources/lang/en/auth.yml new file mode 100755 index 0000000..be83b21 --- /dev/null +++ b/resources/lang/en/auth.yml @@ -0,0 +1,94 @@ +login: + title: Log In + message: Log in to manage your skin & players + success: Logged in successfully. + +check: + anonymous: Illegal access. Please log in first. + verified: To access this page, you should verify your email address first. + admin: Only admins are permitted to access this page. + banned: You are banned on this site. Please contact the admin. + +register: + title: Register + message: Welcome to :sitename! + success: Your account was registered. Redirecting... + max: You can't register more than :regs accounts. + +forgot: + title: Forgot Password + message: We will send you an E-mail to verify. + disabled: Password resetting is not available. + frequent-mail: You click the send button too fast. Wait for some minutes. + unregistered: The email address is not registered. + success: Mail sent, please check your inbox. The link will be expired in 1 hour. + failed: Failed to send verification mail. :msg + ignore: If you haven't signed up on our site, please ignore this email. No unsubscribing is required. + reset: Reset your password + notice: This mail is sending automatically, no reponses will be sent if you reply. + mail: + title: Reset your password on :sitename + message: You are receiving this email because we received a password reset request for your account on :sitename. + reset: 'To reset your password, please visit: :url' + ignore: If you did not request a password reset, no further action is required. + +reset: + title: Reset Password + button: Reset + invalid: Invalid link. + expired: This link is expired. + message: :username, reset your password here. + success: Password resetted successfully. + +bind: + title: Bind Email + button: Bind + message: You need to provide your email adderss to continue. + introduction: We won't send you any spam. + registered: The email address was already taken. + +verify: + title: Email Verification + invalid: Invalid link. + not-matched: Email doesn't match. + +validation: + user: No such user. + password: Wrong password. + +logout: + success: You are now logged out. + +oauth: + authorization: + title: Authorization + introduction: A 3rd-party application ":name" is requesting permission to access your account. + button: Authorize + permissions: Permissions + scope: + user: + read: Sign you in and read your profile + notification: + read: Allows the app to read your notifications. + readwrite: Allows the app to send notifications. + player: + read: Allows the app to read your players. + readwrite: Allows the app to create, read, update and delete your players. + closet: + read: Allows the app to read your closet items. + readwrite: Allows the app to create, read, update and delete your closet items. + users-management: + read: Allows the app to read site's users. + readwrite: Allows the app to create, read, update and delete site's users. + players-management: + read: Allows the app to read site's players. + readwrite: Allows the app to create, read, update and delete site's players. + closet-management: + read: Allows the app to read user's of your site closet items. + readwrite: Allows the app to create, read, update and delete user's closet items. + reports-management: + read: Allows the app to read user's reports. + readwrite: Allows the app to read and review user's reports. + +email: Email +register-link: Register a new account diff --git a/resources/lang/en/errors.yml b/resources/lang/en/errors.yml new file mode 100755 index 0000000..ea507be --- /dev/null +++ b/resources/lang/en/errors.yml @@ -0,0 +1,21 @@ +http: + msg-403: You have no permission to access this page. + msg-404: Nothing here. + msg-500: Please try again later. + msg-503: The application is now in maintenance mode. + method-not-allowed: Method not allowed. + csrf-token-mismatch: Token does not match, try reloading the page. + ie: Your browser isn't supported. Please switch to other modern browsers, such as Firefox or Chrome. + +general: + title: Error occurred + +exception: + code: 'Error code: :code' + detail: 'Details: :msg' + message: | + Whoops, looks like something went wrong. (enable APP_DEBUG in .env to see details) + +plugins: + duplicate: The plugin [:dir1] has a duplicated plugin name definition which is same to plugin [:dir2]. Please check your plugins directory, remove one of them or use another name definition. + boot: There is something wrong with plugin ":plugin". diff --git a/resources/lang/en/front-end.yml b/resources/lang/en/front-end.yml new file mode 100755 index 0000000..9808ea7 --- /dev/null +++ b/resources/lang/en/front-end.yml @@ -0,0 +1,281 @@ +auth: + login: Log In + loggingIn: Logging In + tooManyFails: + captcha: You fails too many times! Please enter the CAPTCHA. + recaptcha: You fails too many times! Please pass the reCAPTCHA challenge. + emptyEmail: Empty email address. + invalidConfirmPwd: Confirming password is not equal with password. + emptyNickname: Empty nickname. + register: Register + registering: Registering + send: Send + sending: Sending + reset: Reset + resetting: Resetting + nickname: Nickname + player-name: Minecraft player name + email: Email + identification: Email or player name + password: Password + captcha: CAPTCHA + change-captcha: Click to change CAPTCHA image. + login-link: Already registered? Log in here. + forgot-link: Forgot password? + keep: Remember me + repeat-pwd: Repeat your password + nickname-intro: Whatever you like expect special characters + player-name-intro: Player name in Minecraft, can be changed later + forgot: + login-link: I do remember it + +skinlib: + private: Private + anonymous: Please login first. + reset: Reset Filter + addToCloset: Add to closet + removeFromCloset: Remove from closet + setItemName: Set a name for this texture + applyNotice: You can apply it to player at your closet + emptyItemName: Empty texture name. + setNewTextureName: 'Please enter the new texture name:' + emptyNewTextureName: Empty new texture name. + seeMyUpload: My Uploads + apply: Apply + filter: + skin: (Any Model) + steve: (Steve) + alex: (Alex) + cape: (Cape) + uploader: 'User (UID = :uid) Uploaded' + allUsers: All Users + sort: + title: Sort + time: Latest + likes: Most Likes + emptyTextureName: Empty texture name. + emptyUploadFile: You have not uploaded any file. + fileExtError: 'Error: Textures should be PNG files.' + uploading: Uploading + setAsPrivate: Set as Private + setAsPublic: Set as Public + setPublicNotice: Sure to set this as public texture? + setPrivateNotice: Sure to set this as private texture? + deleteNotice: Are you sure to delete this texture? + setNewTextureModel: "Please select a new texture model:" + upload: + texture-name: Texture Name + texture-type: Texture Type + select-file: Select File + privacy-notice: Prevent it from being visible at skin library. + set-as-private: Make it Private + button: Upload + cost: It costs you about :score score. + award: You'll be awarded :score score(s) by uploading public texture. + show: + anonymous: You must login to use closets + likes: People who like this + detail: Details + name: Texture Name + edit: Edit + model: Applicable Model + size: File Size + uploader: Uploader + upload-at: Upload At + download: Download + delete-texture: Delete Texture + manage-notice: The texture which was deleted or setted to private will be removed from the closet of everyone who had favorited it. + report: + title: Report + reason: Tell us reason please. + positive: To encourage positive contributions to the skinlib, we will reward who reported inappropriate content with :score scores. However, if any malicious reporting behaviors were found, all scores rewarded will be taken back. + negative: To mitigate the impact of malicious reports, we will require :score scores for submitting a texture report. Don't worry. The suspended scores and additional reward will be sent to your account after your report reviewed by administrators. + +user: + signRemainingTime: 'Available after :time :unit' + timeUnitHour: h + timeUnitMin: min + emptyClosetMsg: >- +

Nothing in your closet...

Why not explore the Skin + Library for a while?

+ renameItem: Rename item + removeItem: Remove from closet + setAsAvatar: Set as avatar + viewInSkinlib: View in skin library + switch2dPreview: Switch to 2D Preview + switch3dPreview: Switch to 3D Preview + removeFromClosetNotice: Sure to remove this texture from your closet? + emptySelectedTexture: No texture is selected. + renameClosetItem: 'Set a new name for this item:' + changePlayerName: 'Please enter the player name:' + emptyPlayerName: Empty player name. + deletePlayer: Sure to delete this player? + deletePlayerNotice: It's permanent. No backups. + chooseClearTexture: Choose texture types you want to clear + noClearChoice: You haven't choose any types + setAvatar: Sure to set this as your avatar? + setAvatarNotice: The head segment of skin will bu used. + resetAvatarConfirm: Are you sure to reset your avatar? + typeToSearch: Type to search + useAs: Apply... + resetSelected: Clear selected + closet: + upload: Upload Texture + use-as: + title: Which player should be applied to? + empty: It seems that you own no player... + used: + title: Resources Used + players: Registered players + storage: Storage used + cur-score: Current Score + score-notice: Click the score to show introduction. + sign: Sign + player: + operation: Operations + edit-pname: Edit Name + delete-texture: Clear Textures + delete-player: Delete + add-player: Add new player + texture-empty: Nothing + verification: + title: Verify Your Account + message: You must verify your email address before using the skin hosting service. Haven't received the email? + resend: Click here to send again. + sending: Sending... + oauth: + id: Client ID + name: App Name + secret: Client Secret + redirect: Callback URL + modifyName: Modify app name. + modifyUrl: Modify callback URL. + create: Create New App + confirmRemove: Are you sure to delete this app? You won't be able to undo this. + +admin: + operationsTitle: Operations + permission: Permission + deleteUser: Delete + changeEmail: Edit Email + newUserEmail: 'Please enter the new email:' + verification: Email Verification + toggleVerification: Toggle Verification Status + changeNickName: Edit Nickname + newUserNickname: 'Please enter the new nickname:' + changePassword: Edit Password + newUserPassword: 'Please enter the new password:' + changeScore: Edit Score + newScore: 'Please enter the new score:' + changePermission: Change permission + newPermission: 'Please select new permission:' + deleteUserNotice: Are you sure to delete this user? It' permanent. + banned: Banned + normal: Normal + admin: Admin + superAdmin: Super Admin + unverified: Unverified + verified: Verified + pidNotice: >- + Please enter the tid of texture. Inputing 0 can clear texture of this + player. + changeTexture: Change Textures + changePlayerName: Change Player Name + changeOwner: Change Owner + textureType: Texture Type + deletePlayer: Delete + changePlayerOwner: 'Please enter the id of user which this player should be transferred to:' + deletePlayerNotice: Are you sure to delete this player? It' permanent. + changePlayerNameNotice: 'Please input new player name:' + emptyPlayerName: Player name cannot be empty. + configurePlugin: Configure + deletePlugin: Delete + noDependencies: No Dependencies + pluginTitle: Plugin + pluginAuthor: Author + pluginVersion: Version + pluginReadme: Read Me + pluginDescription: Description + pluginDependencies: Dependencies + installPlugin: Install + pluginInstalling: Installing... + updatePlugin: Update + pluginUpdating: Updating... + confirmUpdate: Are you sure to update ":plugin" from :old to :new? + enablePlugin: Enable + disablePlugin: Disable + confirmDeletion: Are you sure to delete this plugin? + uploadArchive: Upload Archive + uploadArchiveNotice: Install a plugin by uploading a Zip archive. + downloadRemote: Download From Remote + downloadRemoteNotice: Install a plugin by downloading a Zip archive from remote URL. + updateButton: Update Now + downloading: Downloading... + i18n: + group: Group + key: Key + text: Text + empty: (Empty) + modify: Modify + delete: Delete + updating: 'Please type new text:' + confirmDelete: Are you sure? This is irreversible. + +report: + tid: Texture ID + reporter: Reporter + reason: Reason + status-title: Status + status: + - Pending + - Resolved + - Rejected + time: Report Time + delete: Delete + ban: Ban + reject: Reject + +general: + skin: Skin + cape: Cape + fatalError: Fatal Error + confirmLogout: Sure to log out? + confirm: OK + cancel: Cancel + submit: Submit + close: Close + more: More + tip: Tip + noResult: No result. + texturePreview: Texture Preview + walk: Walk + run: Run + rotation: Rotation + pause: Pause + reset: Reset + skinlib: Skin Library + wait: Please wait... + csrf: This page is out-dated. Please refresh it. + user: + email: Email + nickname: Nick Name + score: Score + register-at: Registered At + player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified + +colors: + black: Black + white: White + gray: Gray + prev: Previous Background + next: Next Background + +vendor: + datatable: + search: Search + prev: Prev + next: Next diff --git a/resources/lang/en/general.yml b/resources/lang/en/general.yml new file mode 100755 index 0000000..9bf361a --- /dev/null +++ b/resources/lang/en/general.yml @@ -0,0 +1,66 @@ +index: Homepage +skinlib: Skin Library +user-center: User Center +logout: Log Out +login: Log In +register: Register Now +profile: User Profile +admin-panel: Admin Panel +explore: Explore +manage: Manage +anonymous: Guest +back: Back +dashboard: Dashboard +my-closet: Closet +my-reports: Reports +developer: Advanced +oauth-manage: OAuth2 Apps +player-manage: Players +user-manage: Users +report-manage: Reports +plugin-manage: Plugins +plugin-market: Plugin Market +plugin-configs: Plugin Configs +customize: Customize +i18n: Internationalization +options: Options +score-options: Score Options +res-options: Resource Options +status: Status +check-update: Check Update +download-update: Download Updates +close: Close +skin: Skin +cape: Cape + +submit: Submit +cancel: Cancel +yes: Yes +no: No +op-success: Operated successfully. +unknown: Unknown + +notice: Notice + +illegal-parameters: Illegal parameters. + +private: Private +public: Public + +unexistent-user: No such user. +player-banned: The owner of this player has been banned. + +texture-deleted: The requested texture has been deleted. + +user: + email: Email + nickname: Nickname + password: Password + score: Score + register-at: Registered At + +player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified diff --git a/resources/lang/en/index.yml b/resources/lang/en/index.yml new file mode 100755 index 0000000..ff5f216 --- /dev/null +++ b/resources/lang/en/index.yml @@ -0,0 +1,21 @@ +features: + title: Features + + first: + icon: fa-users + name: Multi Player + desc: You can add multiple players within one registered account. + + second: + icon: fa-share-alt + name: Sharing + desc: Explore the skin library, send a "like" and share them with your friends. + + third: + icon: fa-cloud + name: Free + desc: It is free forever. No ads. No subscription fees. + +introduction: :sitename provides the service of uploading and hosting Minecraft skins. By coordinating with skin mods (e.g. CustomSkinLoader), you can choose skin and cape for your game character, and make it visible to other players in Minecraft. + +start: Join Us diff --git a/resources/lang/en/options.yml b/resources/lang/en/options.yml new file mode 100755 index 0000000..76da38c --- /dev/null +++ b/resources/lang/en/options.yml @@ -0,0 +1,202 @@ +option-saved: Option saved. + +homepage: + title: Homepage + + home_pic_url: + title: Picture URL at Homepage + hint: Path relative to homepage or full URL, leave empty to use default image. + favicon_url: + title: Website Icon + hint: Path relative to public/ or full URL. + description: The given image must have same width and height (leave blank to use default icon). + transparent_navbar: + title: Transparent Navigation Bar + label: This will enable transparent navigation bar of home page, but it will turn to be normal if page is scrolled to bottom. + hide_intro: + title: Hide Introduction at Bottom + label: Scroll bar will be disabled if this option is enabled, as version 2.x. + fixed_bg: + title: Fixed Background + label: This option will make background fixed, not scrolled with scroll bar. + copyright_prefer: + title: Program Copyright + description: "You can specify a different style of program copyright for each language. To edit a specific language's corresponding program copyright style, please switch to that language and submit your edit.
Warning: Any evil modification applied on the footer program copyright (including deleting, modifying author, changing link target) with out permission is FORBIDDEN. The author reserves the right to pursue relevant responsibilities." + copyright_text: + title: Custom Copyright Text + description: Placeholders are available in custom copyright text. e.g. {site_name} & {site_url}. You can also specify a different footer for each language. To edit a specific language's corresponding footer, please switch to that language and submit your edit. + +customJsCss: + title: Custom CSS/JavaScript + message: | + The contents will be attached to <style> and <script> tags.
+ - Here are some useful examples: Examples of Custom CSS & JavaScript + + custom_css: CSS + custom_js: JavaScript + +rate: + title: Scores + + score_per_storage: + title: Storage + addon: scores = 1 KB + private_score_per_storage: + title: Private Storage + addon: scores = 1 KB + hint: Uploading private textures will cost more scores. + score_per_closet_item: + title: Favorites + addon: score = 1 closet item + return_score: + title: Score Return + label: Return scores back to user after deleting players/textures/closet items. + score_per_player: + title: Players + addon: scores = 1 player + user_initial_score: User Initial Score + +report: + title: Reporting Textures + + reporter_score_modification: + title: Scores for Submitting an Report + description: Set a positive integer value to reward user who submits new reports. Set to a negative value will require scores for submitting reports, and the suspended scores will be available if user's report was resolved. Set to 0 to disable. + reporter_reward_score: + title: Reward the Reporter with Scores If Report Resolved + +sign: + title: Signing + + sign_score: + title: Score Granted + addon1: scores ~ + addon2: scores + sign_gap_time: + title: Gap Time + addon: hours + sign_after_zero: + title: Time + label: Users can sign in after 0 everyday. + hint: The above option will be ignored if this is checked. + +sharing: + title: Awarding Sharing + + score_award_per_texture: + title: Uploader will be rewarded for each uploading texture with + take_back_scores_after_deletion: + title: Return scores + label: Return scores if uploader setting private or deleting texture. + score_award_per_like: + title: Each time the texture is collected, uploader will be rewarded with + +general: + title: General Options + + site_name: Site Name + site_description: + title: Site Description + description: You can also specify a different site name and description for each language. To edit a specific language's corresponding site name or description text, please switch to that language and submit your edit. + site_url: + title: Site URL + hint: Begin with http(s)://, nerver ends with slash. + register_with_player_name: + title: Register with Player Name + label: Require Minecraft's player name when user register + require_verification: + title: Account Verification + label: Users must verify their email address first. + regs_per_ip: Max accounts of one IP + max_upload_file_size: + title: Max Upload Size + hint: "Limit specified in php.ini: :size" + player_name_rule: + title: Player Name Rule + official: Letters, numbers and underscores (Mojang's official rule) + cjk: Allow CJK Unified Ideographs + utf8: Allow all valid UTF-8 characters (excluding whitespaces) + custom: Use custom rules (regular expression) + custom_player_name_regexp: + title: Custom Player Name Rules + hint: Only takes effect when the above option is set to 'custom'. Leave empty to allow any character. + placeholder: Regular Expressions + player_name_length: + title: Player Name Length + suffix: characters + auto_del_invalid_texture: + title: Invalid Textures + label: Delete invalid textures automatically. + hint: Delete textures records whose file no longer exists from skinlib. + allow_downloading_texture: + title: Downloading Textures + label: Allow users to directly download the source file of a skinlib item. + status_code_for_private: + title: HTTP Code for Rejecting Accessing Private Textures + texture_name_regexp: + title: Texture Name Rules + hint: The RegExp for validating name of uploaded textures. Leave empty to allow any character except single, double quote and backslash. + placeholder: Regular Expressions + content_policy: + title: Content Policy + description: Display content policy at texture uploading page, supporting Markdown. To edit a specific language's corresponding content policy, please switch to that language and submit your edit. + +announ: + title: Announcement + + announcement: + description: Styling with Markdown is supported. You can also specify a different announcement for each language. To edit a specific language's corresponding announcement, please switch to that language and submit your edit. + +meta: + title: SEO tags + meta_keywords: + title: Keywords + hint: Split with commas. + meta_description: + title: Description + hint: Description defined in "general options" will be used if you left it empty. + meta_extras: + title: Other Custom Tags + +recaptcha: + recaptcha_invisible: + title: Invisible + label: Enable Invisible Mode + +res-warning: This page is ONLY for advanced users. If you aren't familiar with these, please don't modify them! + +resources: + title: Resource Files + hint: Please check these options if you enabled CDN for your site. + + force_ssl: + title: Force SSL + label: Use HTTPS protocol to load all front-end assets. + hint: Please check if SSL really available before turning on. + auto_detect_asset_url: + title: Assets URL + label: Determine assets url automatically. + description: Please unable this if assets URLs are wrongly generated under a CDN. The site url will be used if this is not enabled. + cache_expire_time: + title: Cache Exipre Time + hint: In seconds, 86400 = one day, 31536000 = one year. + cdn_address: + title: Front-end Assets CDN + hint: Front-end files won't be loaded if URL is unavailable. + description: | + The CDN URL you give must refer to a mirror of /public directory, + all the files of that directory will be loaded as CDN.
+ How to verify? Verify if {Your CDN URL}/app/manifest.json can be accessed. + +cache: + title: Cache Configuration + clear: Clear Cache + cleared: Cache has been cleared. + driver: Current cache driver is 「:driver」. + + enable_avatar_cache: + title: Avatar + label: Enable caching avatar + enable_preview_cache: + title: Texture Preivew + label: Enable caching texture preivew diff --git a/resources/lang/en/setup.yml b/resources/lang/en/setup.yml new file mode 100755 index 0000000..f05d813 --- /dev/null +++ b/resources/lang/en/setup.yml @@ -0,0 +1,52 @@ +database: + connection-error: "Unable to connect to the target :type database, please check your configuration. The server replied with: :msg" + +locked: + title: Already installed + text: It appears that you have already installed Blessing Skin Server. To reinstall, please delete the "install.lock" file under "storage" directory. + button: Back to homepage + +updates: + success: + title: Update complete + +wizard: + master: + title: Install Wizard - Blessing Skin Server + + welcome: + title: Welcome + button: Next + text: Welcome to Blessing Skin Server v:version! + + database: + title: Database + text: The database is used for storing data of Blessing Skin. + + type: Database Type + host: Database Host + port: Database Port + username: Database Username + password: Database Password + db: Database Name + db-notice: You should provide the path to SQLite file and there is no need to fill other blanks if you use SQLite. + prefix: Prefix of Database Table (Optional) + prefix-notice: You don't need to use this option unless you want to install multiple Blessing Skin Server into one database. + + info: + title: Information needed + button: Run install + text: To proceed with the installation, please fill this form with the details of the initial admin account. Don't worry, you can always change these settings later. + + admin-email: Admin Email + admin-notice: This is the UNIQUE super admin account who can GIVE or CANCEL other users' admin privilege. + nickname: Nickname + password: Password + pwd-notice: 'Attention: You will need the password to log in. Please keep it at a secure place.' + confirm-pwd: Confirm password + site-name: Site name + site-name-notice: This will be shown on every page. + + finish: + title: Installation complete + text: Blessing Skin Server has been installed. Thank you, and enjoy! diff --git a/resources/lang/en/skinlib.yml b/resources/lang/en/skinlib.yml new file mode 100755 index 0000000..1ca467a --- /dev/null +++ b/resources/lang/en/skinlib.yml @@ -0,0 +1,37 @@ +general: + upload-new-skin: Upload new skin + +show: + title: Texture Details + deleted: The requested texture was already deleted. + private: The requested texture is private and only visible to the uploader and admins. + +upload: + title: Upload Texture + name-rule: Less than 32 characters and must not contain any special one. + name-rule-regexp: Custom name rules are applied as :regexp + private-score-notice: It will spend you more scores for setting it as private. You will be charged :score scores for per KB storage. + invalid-size: Invalid :type file (width :width, height :height) + invalid-hd-skin: Invalid HD skin (width and height should be divisible by 32) + lack-score: You don't have enough score to upload this texture. + repeated: The texture is already uploaded by someone else. You can add it to your closet directly. + success: Texture :name was uploaded successfully. + +delete: + success: The texture was deleted successfully. + +privacy: + success: The texture was set to :privacy successfully. + +rename: + success: The texture was renamed to :name successfully. + +model: + success: The texture's model was changed to :model successfully. + +no-permission: You have no permission to moderate this texture. +non-existent: No such texture. + +report: + duplicate: You have already reported this texture. The administrators will review it as soon as possible. You can also track the status of your report at User Center. + success: Thanks for reporting! The administrators will review it as soon as possible. diff --git a/resources/lang/en/user.yml b/resources/lang/en/user.yml new file mode 100755 index 0000000..9d89ebb --- /dev/null +++ b/resources/lang/en/user.yml @@ -0,0 +1,120 @@ +sign-success: Signed successfully. You got :score scores. +announcement: Announcement +no-unread: No new notifications. + +verification: + disabled: Email verification is not available. + frequent-mail: You click the send button too fast. Wait for 60 secs, guy. + verified: Your account is already verified. + success: Verification link was sent, please check your inbox. + failed: We failed to send you the verification link. Detailed message :msg + mail: + title: Verify Your Account on :sitename + message: You are receiving this email because someone registered an account with this email address on :sitename. + reset: 'Click here to verify your account: :url' + ignore: If you did not register an account, no further action is required. + +score-intro: + title: What is score? + introduction: | + We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually. + Either adding players, uplaoding textures or adding a skinlib item to your closet will consume scores. + :return-score + + New users will get :initial_score scores initially, and you can acquire :score-from ~ :score-to scores by daily signing in. + will-return-score: The score will be returned if you deleted players, uploaded textures or closet items. + no-return-score: The score will NOT be returned if you deleted players, uploaded textures or closet items. + rates: + storage: :score scores = 1 KB storage + player: :score scores = 1 player + closet: :score socres = 1 closet item + +closet: + add: + success: Added :name to closet successfully. + repeated: You have already added this texture. + not-found: We cannot find this texture. + lack-score: You don't have enough score to add it to closet. + + rename: + success: The item is successfully renamed to :name + + remove: + success: The texture was removed from closet successfully. + non-existent: The texture does not exist in your closet. + +player: + login-notice: Now you can log in with player names you owned instead email address. + + player-name-rule: + official: Player name may only contains letters, numbers and underscores. + cjk: Player name may contains letters, numbers, underscores and CJK Unified Ideographs. + utf8: Player name must be a UTF-8 string. + custom: Custom player name rules are applied on this site. Please contact admins for further information. + + player-name-length: The player name should be at least :min characters and not greater than :max characters. + + add: + repeated: The player name is already registered. + lack-score: You don't have enough score to add a player. + success: Player :name was added successfully. + + delete: + success: Player :name was deleted successfully. + + rename: + repeated: This player name is occupied. Please choose another one. + success: Player :old was renamed to :new + + set: + success: The texture was applied to player :name successfully. + + clear: + success: The textures of player :name was resetted successfully. + +profile: + avatar: + title: Change Avatar? + notice: Click the gear icon "" of any skin in your closet, then click "Set as avatar". We will cut the head segment of that skin for you. If there is no icon like this, please try to disable your ADs blocking extension. + wrong-type: You can't set a cape as avatar. + success: New avatar was set successfully. + reset: Reset Avatar + + password: + title: Change Password + old: Old Password + new: New Password + confirm: Repeat Password + button: Change password + wrong-password: Wrong original password. + success: Password updated successfully, please log in again. + + nickname: + title: Change Nickname + empty: No nickname is set now. + success: Nickname is successfully updated to :nickname + + email: + title: Change Email + new: New Email + password: Current Password + button: Change email + wrong-password: Wrong password. + existed: This email address is occupied. + success: Email address updated successfully, please log in again. + + delete: + title: Delete Account + notice: Sure to delete your account on :site? + admin: Admin account can not be deleted. + button: Delete my account + + modal-title: You need to enter your password to continue + modal-notice: | + You're about to delete your account. + This is permanent! No backups, no restores, no magic undo button. + We warned you, ok? + password: Current Password + + wrong-password: Wrong password. + success: Your account is deleted successfully. diff --git a/resources/lang/en/validation.yml b/resources/lang/en/validation.yml new file mode 100755 index 0000000..fd9ed64 --- /dev/null +++ b/resources/lang/en/validation.yml @@ -0,0 +1,128 @@ +accepted: 'The :attribute must be accepted.' +active_url: 'The :attribute is not a valid URL.' +after: 'The :attribute must be a date after :date.' +after_or_equal: 'The :attribute must be a date after or equal to :date.' +alpha: 'The :attribute may only contain letters.' +alpha_dash: 'The :attribute may only contain letters, numbers, dashes and underscores.' +alpha_num: 'The :attribute may only contain letters and numbers.' +array: 'The :attribute must be an array.' +before: 'The :attribute must be a date before :date.' +before_or_equal: 'The :attribute must be a date before or equal to :date.' +between: + numeric: 'The :attribute must be between :min and :max.' + file: 'The :attribute must be between :min and :max kilobytes.' + string: 'The :attribute must be between :min and :max characters.' + array: 'The :attribute must have between :min and :max items.' +boolean: 'The :attribute field must be true or false.' +captcha: 'Incorrect captcha.' +confirmed: 'The :attribute confirmation does not match.' +date: 'The :attribute is not a valid date.' +date_equals: 'The :attribute must be a date equal to :date.' +date_format: 'The :attribute does not match the format :format.' +different: 'The :attribute and :other must be different.' +digits: 'The :attribute must be :digits digits.' +digits_between: 'The :attribute must be between :min and :max digits.' +dimensions: 'The :attribute has invalid image dimensions.' +distinct: 'The :attribute field has a duplicate value.' +email: 'The :attribute must be a valid email address.' +ends_with: 'The :attribute must end with one of the following: :values.' +exists: 'The selected :attribute is invalid.' +file: 'The :attribute must be a file.' +filled: 'The :attribute field must have a value.' +gt: + numeric: 'The :attribute must be greater than :value.' + file: 'The :attribute must be greater than :value kilobytes.' + string: 'The :attribute must be greater than :value characters.' + array: 'The :attribute must have more than :value items.' +gte: + numeric: 'The :attribute must be greater than or equal :value.' + file: 'The :attribute must be greater than or equal :value kilobytes.' + string: 'The :attribute must be greater than or equal :value characters.' + array: 'The :attribute must have :value items or more.' +image: 'The :attribute must be an image.' +in: 'The selected :attribute is invalid.' +in_array: 'The :attribute field does not exist in :other.' +integer: 'The :attribute must be an integer.' +ip: 'The :attribute must be a valid IP address.' +ipv4: 'The :attribute must be a valid IPv4 address.' +ipv6: 'The :attribute must be a valid IPv6 address.' +json: 'The :attribute must be a valid JSON string.' +lt: + numeric: 'The :attribute must be less than :value.' + file: 'The :attribute must be less than :value kilobytes.' + string: 'The :attribute must be less than :value characters.' + array: 'The :attribute must have less than :value items.' +lte: + numeric: 'The :attribute must be less than or equal :value.' + file: 'The :attribute must be less than or equal :value kilobytes.' + string: 'The :attribute must be less than or equal :value characters.' + array: 'The :attribute must not have more than :value items.' +max: + numeric: 'The :attribute may not be greater than :max.' + file: 'The :attribute may not be greater than :max kilobytes.' + string: 'The :attribute may not be greater than :max characters.' + array: 'The :attribute may not have more than :max items.' +mimes: 'The :attribute must be a file of type: :values.' +mimetypes: 'The :attribute must be a file of type: :values.' +min: + numeric: 'The :attribute must be at least :min.' + file: 'The :attribute must be at least :min kilobytes.' + string: 'The :attribute must be at least :min characters.' + array: 'The :attribute must have at least :min items.' +not_in: 'The selected :attribute is invalid.' +not_regex: 'The :attribute format is invalid.' +numeric: 'The :attribute must be a number.' +password: The password is incorrect. +present: 'The :attribute field must be present.' +recaptcha: 'reCAPTCHA validation failed.' +regex: 'The :attribute format is invalid.' +required: 'The :attribute field is required.' +required_if: 'The :attribute field is required when :other is :value.' +required_unless: 'The :attribute field is required unless :other is in :values.' +required_with: 'The :attribute field is required when :values is present.' +required_with_all: 'The :attribute field is required when :values are present.' +required_without: 'The :attribute field is required when :values is not present.' +required_without_all: 'The :attribute field is required when none of :values are present.' +same: 'The :attribute and :other must match.' +size: + numeric: 'The :attribute must be :size.' + file: 'The :attribute must be :size kilobytes.' + string: 'The :attribute must be :size characters.' + array: 'The :attribute must contain :size items.' +starts_with: 'The :attribute must start with one of the following: :values.' +string: 'The :attribute must be a string.' +timezone: 'The :attribute must be a valid zone.' +unique: 'The :attribute has already been taken.' +uploaded: 'The :attribute failed to upload.' +url: 'The :attribute format is invalid.' +uuid: 'The :attribute must be a valid UUID.' + +# -------------------------------------------------------------------------- +# Custom Validation Language Lines +# -------------------------------------------------------------------------- +# +# Here you may specify custom validation messages for attributes using the +# convention "attribute.rule" to name the lines. This makes it quick to +# specify a specific custom language line for a given attribute rule. +# +# custom: +# attribute-name: +# rule-name: custom-message + +# -------------------------------------------------------------------------- +# Custom Validation Attributes +# -------------------------------------------------------------------------- +# +# The following language lines are used to swap attribute place-holders +# with something more reader friendly such as E-Mail Address instead +# of "email". This simply helps us make messages a little cleaner. +# +attributes: + name: name + player_name: player name + identification: email or player name + email: email + password: password + password_confirmation: 'password confirmation' + title: title + content: content diff --git a/resources/lang/es_ES/admin.yml b/resources/lang/es_ES/admin.yml new file mode 100755 index 0000000..b72d9bb --- /dev/null +++ b/resources/lang/es_ES/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: Usuarios Registrados + total-players: Jugadores + total-textures: Texturas Subidas + disk-usage: Uso del Disco + overview: Resumen + texture-uploads: Subidas de Texturas + user-registration: Registro de Usuario +notifications: + send: + title: Enviar Notificación + success: '¡Enviado con éxito!' + receiver: + title: Receptor + all: Todos los Usuarios + normal: Usuarios Normales + uid: UID especificado + email: Email especificado + title: Título + content: Contenido (Markdown está soportado). +users: + operations: + non-existent: No existe ese usuario. + no-permission: No tienes permiso para operar este usuario. + email: + success: Email cambiado con éxito. + verification: + success: Estado de verificación de la cuenta cambiado con éxito. + nickname: + success: El apodo se ha modificado con éxito. + password: + success: Contraseña cambiada con éxito. + score: + success: Puntuación cambiada con éxito. + permission: Permiso actualizado. + delete: + success: La cuenta ha sido eliminada con éxito. +players: + no-permission: No tienes permiso para operar este jugador. + textures: + non-existent: Textura Inexistente tid.:tid + success: Las texturas de :player han sido actualizadas. + name: + success: El nombre del jugador ha sido actualizado a :player + owner: + success: El jugador :player fue transferido al usuario :user. + delete: + success: El jugador ha sido eliminado correctamente. +customize: + change-color: + title: Cambiar color del tema + colors: + navbar: Barra Superior de Navegación + sidebar: + dark: Barra Lateral (oscuro) + light: Barra Lateral (claro) +i18n: + add: Añadir nueva línea de idioma + added: Línea de idioma añadida. + updated: Línea de idioma actualizada. + deleted: Línea de idioma eliminada. + group: Grupo + key: Clave + text: Texto + tip: '¿Cómo puedo usar esta página?' +status: + info: Información + health: Salud + bs: + name: Blessing Skin + version: Versión + env: Entorno de aplicación + debug: '¿Depurar o no?' + commit: Commit + laravel: Versión de Laravel + server: + name: Servidor + php: Versión de PHP + web: Software del servidor web + os: SO + db: + name: Base de datos + type: Servidor + host: Host + port: Puerto + username: Usuario + database: Base de datos + prefix: Prefijo de tabla + plugins: Plugins habilitados (:amount) +plugins: + readme: Leéme + operations: + title: Operaciones + enabled: ':plugin ha sido habilitado.' + unsatisfied: + notice: Hay conflictos o dependencias insatisfechas en el plugin, por lo tanto no podemos activarlo. Por favor, instale o actualice los plugins listados a continuación, y desactive los que tienen conflictos. + disabled: 'El plugin ":name" no está habilitado.' + version: 'La versión de ":title" no satisface la restricción ":constraint".' + conflict: 'El plugin ":title" no puede ejecutarse con este plugin al mismo tiempo.' + disabled: ':plugin ha sido deshabilitado.' + deleted: El plugin se eliminó con éxito. + no-config-notice: El plugin no está instalado o no proporciona una página de configuración. + no-readme-notice: El plugin no dispone de un archivo de lectura. + not-found: No existe dicho plugin. + market: + unresolved: Hay conflictos o dependencias insatisfechas en el plugin, por lo tanto no podemos descargar. Por favor, instale o actualice los plugins listados a continuación, y desactive los que tienen conflictos. + connection-error: No se puede conectar al registro de plugins. :error + non-existent: El plugin :plugin no existe. + install-success: Se instaló el plugin. +update: + complete: Actualización completada + info: + title: Actualizar información + up-to-date: Ya está actualizado. + available: Nueva versión disponible. + versions: + latest: "Última versión:" + current: "Versión actual:" + check-github: Comprobar versiones de GitHub + button: Actualizar ahora + cautions: + title: Precauciones + link: compruebe esto. + text: | + Por favor, elija la fuente de actualización según el entorno de red de su host. + La conexión de baja velocidad entre la fuente de actualización y su host causará una carga lenta a la hora de comprobar y descargar la página. + Para cambiar la fuente de actualización por defecto, + errors: + connection: "No se puede acceder a la fuente de actualización actual. Detalles: :error" + spec: La fuente de actualización actual no está soportada. + php: Tu versión de PHP es demasiado baja para actualizar. Requiere :version o posterior. +download: + errors: + download: 'Error al descargar. Error: :error' + shasum: La validación del archivo ha fallado. Por favor, descargue de nuevo. + unzip: Error al desempaquetar archivos. +invalid-action: Acción inválida diff --git a/resources/lang/es_ES/auth.yml b/resources/lang/es_ES/auth.yml new file mode 100755 index 0000000..cc4c0f2 --- /dev/null +++ b/resources/lang/es_ES/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: Iniciar sesión + message: Iniciar sesión para gestionar tu skin y jugadores + success: Iniciado exitosamente. +check: + anonymous: Acceso ilegal. Favor iniciarse primero. + verified: Debes verificar su correo electrónico para accesar esta página. + admin: Sólo administradores están permitidos accesar esta página. + banned: Estás baneado. Favor contactar el administrador. +register: + title: Crear cuenta + message: '¡Bienvenidos a :sitename!' + success: Su cuenta fue creada. Redirigiendo... + max: No puede registrar más de :regs cuentas. +forgot: + title: Olvidó la contraseña + message: Le enviaremos un correo electrónico para verificar. + disabled: El restablecimiento de contraseña no está disponible. + frequent-mail: Haz hecho clic en el botón de enviar demasiado rápido. Espera unos minutos. + unregistered: La dirección de correo electrónico no está registrada. + success: Correo enviado, por favor comprueba tu bandeja de entrada. El enlace expirará en 1 hora. + failed: Se ha producido un error al enviar el correo electrónico de verificación. :msg + ignore: Si no solicitó un restablecimiento de contraseña, no se requiere ninguna acción adicional. + reset: Restablezca su contraseña + notice: Este correo electrónico se envía automáticamente, no se enviará ninguna respuesta si responde. + mail: + title: Restablezca su contraseña en :sitename + message: Está recibiendo este correo electrónico porque solicitó restablecer la contraseña de su cuenta de usuario en :sitename. + reset: 'Para restablecer su contraseña, por favor visite: :url' + ignore: Si no solicitó un restablecimiento de contraseña, no se requiere ninguna acción adicional. +reset: + title: Restablecer contraseña + button: Restablecer + invalid: Enlace inválido. + expired: Este enlace ha caducado. + message: ':username, reset your password here.' + success: Contraseña restablecida con éxito. +bind: + title: Enlazar email + button: Enlazar + message: Necesitas proporcionar su dirección de correo electrónico para continuar. + introduction: No te enviaremos ningún correo spam. + registered: Esta dirección de correo electrónico ya está en uso. +verify: + title: Verificación de correo electrónico + invalid: Enlace inválido. + not-matched: El Email no coincide. +validation: + user: No existe tal usuario. + password: Contraseña incorrecta. +logout: + success: Ha cerrado su sesión. +oauth: + authorization: + title: Autorización + introduction: Una aplicación de terceros ":name" está solicitando permiso para acceder a su cuenta. + button: Autorizar + permissions: Permissions + scope: + user: + read: Sign you in and read your profile + notification: + read: Allows the app to read your notifications. + readwrite: Allows the app to send notifications. + player: + read: Allows the app to read your players. + readwrite: Allows the app to create, read, update and delete your players. + closet: + read: Allows the app to read your closet items. + readwrite: Allows the app to create, read, update and delete your closet items. + users-management: + read: Allows the app to read site's users. + readwrite: Allows the app to create, read, update and delete site's users. + players-management: + read: Allows the app to read site's players. + readwrite: Allows the app to create, read, update and delete site's players. + closet-management: + read: Allows the app to read user's of your site closet items. + readwrite: Allows the app to create, read, update and delete user's closet items. + reports-management: + read: Allows the app to read user's reports. + readwrite: Allows the app to read and review user's reports. +email: Email +register-link: Registrar una nueva cuenta diff --git a/resources/lang/es_ES/errors.yml b/resources/lang/es_ES/errors.yml new file mode 100755 index 0000000..2bf0d8b --- /dev/null +++ b/resources/lang/es_ES/errors.yml @@ -0,0 +1,19 @@ +--- +http: + msg-403: No tiene permiso para accesar esta página. + msg-404: No hay nada. + msg-500: Por favor intente más tarde. + msg-503: La aplicación está ahora en modo de mantenimiento. + method-not-allowed: Método no permitido. + csrf-token-mismatch: El token no coincide, intente recargar la página. + ie: Tu navegador no es compatible. Por favor, cambie a otros navegadores modernos, como Firefox o Chrome. +general: + title: Se produjo un error +exception: + code: 'Código de error: :code' + detail: 'Detalles: :msg' + message: | + Ups, parece que algo salió mal. (habilita APP_DEBUG en .env para ver detalles) +plugins: + duplicate: El plugin [:dir1] tiene una definición de nombre de plugin duplicado que es igual al plugin [:dir2]. Por favor, comprueba tu directorio de plugins, elimina uno de ellos o usa otra definición de nombre. + boot: Hay algo mal con el plugin ":plugin". diff --git a/resources/lang/es_ES/front-end.yml b/resources/lang/es_ES/front-end.yml new file mode 100755 index 0000000..06cf04d --- /dev/null +++ b/resources/lang/es_ES/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: Iniciar sesión + loggingIn: Iniciando sesión + tooManyFails: + captcha: '¡Fallo demasiadas veces! Por favor, introduzca el CAPTCHA.' + recaptcha: '¡Fallo demasiadas veces! Por favor, pase el desafío de reCAPTCHA.' + emptyEmail: Dirección de email vacía. + invalidConfirmPwd: Confirmación contraseña no es igual a la original. + emptyNickname: Apodo vacío. + register: Crear cuenta + registering: Registrando + send: Enviar + sending: Enviando + reset: Restablecer + resetting: Reseteando + nickname: Apodo + player-name: Nombre del jugador de Minecraft + email: Email + identification: Email o nombre del jugador + password: Contraseña + captcha: CAPTCHA + change-captcha: Haga clic para cambiar la imagen CAPTCHA. + login-link: '¿Ya está registrado? Inicie su sesión aquí.' + forgot-link: '¿Olvidó su contraseña?' + keep: Recuérdame + repeat-pwd: Repita su contraseña + nickname-intro: Lo que quieras excepto caracteres especiales + player-name-intro: Nombre del jugador en Minecraft, puede cambiarse más tarde + forgot: + login-link: Lo recuerdo +skinlib: + private: Privado + anonymous: Inicie sesión primero. + reset: Restablecer filtro + addToCloset: Añadir al armario + removeFromCloset: Retirar de armario + setItemName: Establecer un nombre para esta textura + applyNotice: Puede aplicarlo al jugador en su armario + emptyItemName: Nombre de textura vacío. + setNewTextureName: 'Por favor, introduzca el nuevo nombre de la textura:' + emptyNewTextureName: Nuevo nombre de textura vacío. + seeMyUpload: Mis subidas + apply: Aplicar + filter: + skin: (Cualquier modelo) + steve: (Steve) + alex: (Alex) + cape: (Cape) + uploader: 'Subido por usuario (UID = :uid)' + allUsers: Todos los usuarios + sort: + title: Ordenar + time: Últimas + likes: Más popular + emptyTextureName: Nombre de textura vacío. + emptyUploadFile: No ha subido ningún archivo. + fileExtError: 'Error: Las texturas deben ser archivos PNG.' + uploading: Subiendo + setAsPrivate: Establecer como privado + setAsPublic: Establecer como público + setPublicNotice: '¿Seguro que quieres establecer esto como textura pública?' + setPrivateNotice: '¿Seguro que quieres establecer esto como textura privada?' + deleteNotice: '¿Seguro que desea eliminar esta textura?' + setNewTextureModel: "Por favor, seleccione un nuevo modelo de textura:" + upload: + texture-name: Nombre de textura + texture-type: Tipo de textura + select-file: Seleccionar archivo + privacy-notice: Evitar que sea visible en la colección de skins. + set-as-private: Marcar privado + button: Subir + cost: Te cuesta alrededor de :score puntuaciones. + award: Serás galardonado :punta(s) de puntuación subiendo textura pública. + show: + anonymous: Debe iniciar sesión para usar armarios + likes: Gente a la que le gusta esto + detail: Detalles + name: Nombre de textura + edit: Editar + model: Modelo aplicable + size: Tamaño de archivo + uploader: Subidor + upload-at: Subido el + download: Descargar + delete-texture: Borrar textura + manage-notice: La textura que fue eliminada o marcada como privada será eliminada del armario de todos los que la habían favorecido. + report: + title: Reportar + reason: Díganos la razón por favor. + positive: Para alentar contribuciones positivas a la skinlib, recompensaremos a quienes informen de contenido inapropiado con :score puntuaciones. Sin embargo, si se encontró algún comportamiento de reporte malicioso, todas las puntuaciones recompensadas serán retiradas. + negative: Para mitigar el impacto de informes maliciosos, necesitaremos :score para enviar un informe de textura. No te preocupes. Las puntuaciones suspendidas y recompensas adicionales serán enviadas a tu cuenta después de que tu informe sea revisado por los administradores. +user: + signRemainingTime: 'Disponible después de :time :unit' + timeUnitHour: h + timeUnitMin: min + emptyClosetMsg: >- +

Nada en tu armario...

¿Por qué no explorar la colección de skins durante un tiempo?

+ renameItem: Renombrar elemento + removeItem: Retirar de armario + setAsAvatar: Establecer como avatar + viewInSkinlib: Ver en la colección de skins + switch2dPreview: Cambiar a preestreno 2D + switch3dPreview: Cambiar a preestreno 3D + removeFromClosetNotice: '¿Seguro que quiere eliminar esta textura de su armario?' + emptySelectedTexture: No hay textura seleccionada. + renameClosetItem: 'Establecer un nuevo nombre para este elemento:' + changePlayerName: 'Por favor, introduzca el nombre del jugador:' + emptyPlayerName: Nombre de jugador vacío. + deletePlayer: '¿Seguro que quiere eliminar este jugador?' + deletePlayerNotice: Es permanente. No hay copias de seguridad. + chooseClearTexture: Elige los tipos de texturas que quiera borrar + noClearChoice: No ha elegido ningún tipo + setAvatar: '¿Seguro que quiere establecer esto como su avatar?' + setAvatarNotice: El segmento de cabeza del skin se usará. + resetAvatarConfirm: '¿Está seguro que quiere restablecer su avatar?' + typeToSearch: Escriba para buscar + useAs: Aplicar... + resetSelected: Borrar seleccionado + closet: + upload: Subir textura + use-as: + title: '¿A qué jugador se debe aplicar?' + empty: Parece que no tienes jugador... + used: + title: Recursos usados + players: Jugadores registrados + storage: Almacenamiento usado + cur-score: Puntuación actual + score-notice: Haga clic en la puntuación para mostrar la introducción. + sign: Firmar + player: + operation: Operaciones + edit-pname: Editar nombre + delete-texture: Borrar texturas + delete-player: Eliminar + add-player: Añadir nuevo jugador + texture-empty: Nada + verification: + title: Verifica su cuenta + message: Debe verificar su dirección de correo electrónico antes de usar el servicio de alojamiento de skins. ¿No ha recibido el correo electrónico? + resend: Haga clic aquí para enviar de nuevo. + sending: Enviando... + oauth: + id: ID de cliente + name: Nombre de app + secret: Secreto de cliente + redirect: Callback URL + modifyName: Modificar el nombre de la aplicación. + modifyUrl: Modificar callback URL. + create: Crear nueva app + confirmRemove: '¿Estás seguro de eliminar esta aplicación? No podrás deshacer esto.' +admin: + operationsTitle: Operaciones + permission: Permiso + deleteUser: Eliminar + changeEmail: Modificar email + newUserEmail: 'Por favor, introduzca el nuevo email:' + verification: Verificación de email + toggleVerification: Cambiar estado de verificación + changeNickName: Editar apodo + newUserNickname: 'Por favor, introduzca el nuevo apodo:' + changePassword: Editar contraseña + newUserPassword: 'Por favor, introduzca la nueva contraseña:' + changeScore: Editar puntuación + newScore: 'Por favor, introduzca la nueva puntuación:' + changePermission: Cambiar permiso + newPermission: 'Por favor, seleccione un nuevo permiso:' + deleteUserNotice: '¿Está seguro de eliminar este usuario? Es permanente.' + banned: Baneado + normal: Normal + admin: Admin + superAdmin: Superadmin + unverified: No verificado + verified: Verificado + pidNotice: >- + Por favor, introduzca la tid de la textura. Introduciendo 0 puede borrar la textura de este jugador. + changeTexture: Cambiar texturas + changePlayerName: Cambiar nombre de jugador + changeOwner: Cambiar dueño + textureType: Tipo de textura + deletePlayer: Eliminar + changePlayerOwner: 'Por favor, introduzca el id del usuario al que este jugador debe ser transferido:' + deletePlayerNotice: '¿Está seguro de eliminar este jugador? Es permanente.' + changePlayerNameNotice: 'Por favor, introduce un nuevo nombre de jugador:' + emptyPlayerName: El nombre del jugador no puede estar vacío. + configurePlugin: Configurar + deletePlugin: Eliminar + noDependencies: No hay dependencias + pluginTitle: Plugin + pluginAuthor: Autor + pluginVersion: Versión + pluginReadme: Readme + pluginDescription: Descripción + pluginDependencies: Dependencias + installPlugin: Instalar + pluginInstalling: Instalando... + updatePlugin: Actualizar + pluginUpdating: Actualizando... + confirmUpdate: '¿Estás seguro de actualizar ":plugin" de :old a :new?' + enablePlugin: Habilitar + disablePlugin: Deshabilitar + confirmDeletion: '¿Seguro que desea eliminar este plugin?' + uploadArchive: Subir archivo + uploadArchiveNotice: Instalar un plugin subiendo un archivo zip. + downloadRemote: Descargar desde remoto + downloadRemoteNotice: Instalar un plugin descargando un archivo zip desde la URL remota. + updateButton: Actualizar ahora + downloading: Descargando... + i18n: + group: Grupo + key: Clave + text: Texto + empty: (Vacío) + modify: Modificar + delete: Eliminar + updating: 'Por favor, escribe un nuevo texto:' + confirmDelete: '¿Está seguro? Esto es irreversible.' +report: + tid: ID de textura + reporter: Informante + reason: Razón + status-title: Status + status: + - Pendiente + - Resuelto + - Rechazado + time: Hora de reporte + delete: Eliminar + ban: Banear + reject: Rechazar +general: + skin: Skin + cape: Capa + fatalError: Error fatal + confirmLogout: '¿Seguro que quiere cerrar sesión?' + confirm: OK + cancel: Cancelar + submit: Someter + close: Cerrar + more: Más + tip: Consejo + noResult: Sin resultados. + texturePreview: Preestreno de textura + walk: Caminar + run: Correr + rotation: Girar + pause: Pausar + reset: Restablecer + skinlib: Colección de skins + wait: Por favor, espere... + csrf: Esta página está desactualizada. Por favor refrescar. + user: + email: Email + nickname: Apodo + score: Puntuación + register-at: Registrado el + player: + owner: Dueño + player-name: Nombre del jugador + previews: Preestrenos de textura + last-modified: Últim actualiz +colors: + black: Negro + white: Blanco + gray: Gris + prev: Fondo anterior + next: Siguiente fondo +vendor: + datatable: + search: Buscar + prev: Anterior + next: Siguiente diff --git a/resources/lang/es_ES/general.yml b/resources/lang/es_ES/general.yml new file mode 100755 index 0000000..e5e54c4 --- /dev/null +++ b/resources/lang/es_ES/general.yml @@ -0,0 +1,59 @@ +--- +index: Inicio +skinlib: Colección de skins +user-center: Centro de usuario +logout: Cerrar sesión +login: Iniciar sesión +register: Crear cuenta +profile: Perfil de usuario +admin-panel: Panel de administración +explore: Explorar +manage: Gestionar +anonymous: Visitante +back: Volver +dashboard: Cuadro de mandos +my-closet: Armario +my-reports: Informes +developer: Avanzado +oauth-manage: Aplicaciones OAuth2 +player-manage: Jugadores +user-manage: Usuarios +report-manage: Informes +plugin-manage: Plugins +plugin-market: Mercado de plugins +plugin-configs: Configs de plugins +customize: Personalizar +i18n: Internacionalización +options: Opciones +score-options: Opciones de puntaje +res-options: Opciones de recursos +status: Estado +check-update: Comprobar actualización +download-update: Descargar actualizaciones +close: Cerrar +skin: Skin +cape: Capa +submit: Aceptar +cancel: Cancelar +yes: true +no: false +op-success: Operado con éxito. +unknown: Desconocido +notice: Aviso +illegal-parameters: Parámetros ilegales. +private: Privado +public: Público +unexistent-user: No existe este usuario. +player-banned: El dueño de este jugador ha sido baneado. +texture-deleted: La textura solicitada ha sido borrada. +user: + email: Email + nickname: Apodo + password: Contraseña + score: Puntuación + register-at: Registrado el +player: + owner: Dueño + player-name: Nombre de jugador + previews: Preestreno de textura + last-modified: Últim actualiz diff --git a/resources/lang/es_ES/index.yml b/resources/lang/es_ES/index.yml new file mode 100755 index 0000000..7b67a14 --- /dev/null +++ b/resources/lang/es_ES/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: Funciones + first: + icon: fa-users + name: Multijugador + desc: Puedes añadir multiples jugadores con sólo una cuenta. + second: + icon: fa-share-alt + name: Compartido + desc: Explora la colección de skins, deja un "like" y compártelos con tus amigos. + third: + icon: fa-cloud + name: Gratis + desc: Es gratis para para siempre. No hay anuncios. Tampoco suscripciones. +introduction: ':sitename provee el servicio de subida y alojamiente de skins de Minecraft. Coordenando con skin mods (como CustomSkinLoader), puedes escoger skins y capas para tu personaje, y hacerlo visible para otros jugadores.' +start: Únete a nosotros diff --git a/resources/lang/es_ES/options.yml b/resources/lang/es_ES/options.yml new file mode 100755 index 0000000..2450457 --- /dev/null +++ b/resources/lang/es_ES/options.yml @@ -0,0 +1,180 @@ +--- +option-saved: Opción guardada. +homepage: + title: Inicio + home_pic_url: + title: URL de la imagen en la página de inicio + hint: Ruta relativa a la página de inicio o URL completa, dejar en blanco para usar la imagen por defecto. + favicon_url: + title: Icono del sitio web + hint: Ruta relativa a public/ o URL completa. + description: La imagen dada debe tener el mismo ancho y altura (dejar en blanco para usar el icono por defecto). + transparent_navbar: + title: Barra de navegación transparente + label: Esto activará la barra de navegación transparente de la página de inicio, pero se convertirá en normal si la página se desplaza hacia abajo. + hide_intro: + title: Ocultar introducción en la parte inferior + label: La barra de desplazamiento se desactivará si esta opción está activada, desde versión 2.x. + fixed_bg: + title: Fondo fijo + label: Esta opción hará que el fondo sea fijo, no desplazado con la barra de desplazamiento. + copyright_prefer: + title: Copyright del programa + description: "Puede especificar un estilo diferente de copyright del programa para cada idioma. Para editar el correspondiente estilo de copyright de un idioma específico, por favor cambie a ese idioma y someta su edición.
Advertencia: Cualquier modificación mala aplicada al copyright del programa de pie de página (incluyendo eliminación, modificando el autor, cambiando el destino del enlace) sin permiso es FORBIDO. El autor se reserva el derecho a asumir las responsabilidades pertinentes." + copyright_text: + title: Texto personalizado de copyright + description: Los marcadores de posición están disponibles en el texto de copyright personalizado. ej. {site_name} & {site_url}. También puedes especificar un pie de página diferente para cada idioma. Para editar el pie de página de un idioma específico, por favor cambie a ese idioma y someta su edición. +customJsCss: + title: CSS/JavaScript personalizado + message: | + El contenido se adjuntará a etiquetas <style> y <script>.
+ - Aquí hay algunos ejemplos útiles: Ejemplos de JavaScript y CSS personalizado + custom_css: CSS + custom_js: JavaScript +rate: + title: Puntuaciones + score_per_storage: + title: Almacenamiento + addon: puntuaciones = 1 KB + private_score_per_storage: + title: Almacenamiento privado + addon: puntuaciones = 1 KB + hint: Subir texturas privadas costará más puntuaciones. + score_per_closet_item: + title: Favoritos + addon: puntuación = 1 elemento de armario + return_score: + title: Puntuación de retorno + label: Devuelve las puntuaciones al usuario después de eliminar jugadores/texturas/elementos de armario. + score_per_player: + title: Jugadores + addon: puntuaciones = 1 jugador + user_initial_score: Puntuación inicial del usuario +report: + title: Reportando texturas + reporter_score_modification: + title: Puntuaciones para enviar un informe + description: Establece un valor entero positivo para recompensar al usuario que envía nuevos informes. Establecer a un valor negativo requerirá puntuaciones para enviar informes, y las puntuaciones suspendidas estarán disponibles si el informe del usuario fue resuelto. Establecer a 0 para desactivar. + reporter_reward_score: + title: Recompensa al reportador con puntuaciones si el informe se resuelve +sign: + title: Firmando + sign_score: + title: Puntuación concedida + addon1: puntuaciones ~ + addon2: puntuaciones + sign_gap_time: + title: Tiempo de hueco + addon: horas + sign_after_zero: + title: Hora + label: Los usuarios pueden iniciar sesión después de 0 todos los días. + hint: La opción anterior será ignorada si esto está marcado. +sharing: + title: Concesionando el compartir + score_award_per_texture: + title: El cargador será recompensado por cada textura cargada con + take_back_scores_after_deletion: + title: Retornación de puntuaciones + label: Devolver puntuaciones si la configuración del cargador es privada o si se elimina la textura. + score_award_per_like: + title: Cada vez que la textura es recolectada, el cargador será recompensado con +general: + title: Opciones generales + site_name: Nombre del sitio + site_description: + title: Descripción del sitio + description: También puede especificar un nombre y una descripción del sitio para cada idioma. Para editar el nombre o la descripción del sitio web de un idioma específico, por favor cambie a ese idioma y someta su edición. + site_url: + title: URL del sitio + hint: Comienza con http(s)://, nunca termina con una barra. + register_with_player_name: + title: Registrar con el nombre del jugador + label: Requerir el nombre del jugador de Minecraft cuando el usuario se registre + require_verification: + title: Verificación de cuenta + label: Los usuarios primero deben verificar su dirección de correo electrónico. + regs_per_ip: Cuentas máximas de un IP + max_upload_file_size: + title: Tamaño máximo de subida + hint: "Límite especificado en php.ini: :size" + player_name_rule: + title: Regla de nombre de jugador + official: Letras, números y guiones bajos (regla oficial de Mojang) + cjk: Permitir Ideografías unificadas CJK + utf8: Allow all valid UTF-8 characters (excluding whitespaces) + custom: Usar reglas personalizadas (expresión regular) + custom_player_name_regexp: + title: Reglas de nombre de jugador personalizadas + hint: Sólo tiene efecto cuando la opción anterior se establece en 'personalizar'. Dejar en blanco para permitir cualquier carácter. + placeholder: Expresiones regulares + player_name_length: + title: Longitud del nombre de jugador + suffix: caracteres + auto_del_invalid_texture: + title: Texturas no válidas + label: Borrar texturas no válidas automáticamente. + hint: Eliminar registros de texturas cuyos archivos ya no existen en skinlib. + allow_downloading_texture: + title: Descargando texturas + label: Permite a los usuarios descargar directamente el archivo fuente de un elemento skinlib. + status_code_for_private: + title: Código HTTP para rechazar el acceso a texturas privadas + texture_name_regexp: + title: Reglas de nombre de textura + hint: RegExp para validar el nombre de las texturas subidas. Dejar en blanco para permitir cualquier carácter excepto una comilla individual, doble y barra invertida. + placeholder: Expresiones regulares + content_policy: + title: Política de contenido + description: Muestra la política de contenido en la página de subida de texturas, apoyando a Markdown. Para editar la correspondiente política de contenido de un idioma específico, por favor cambie a ese idioma y someta su edición. +announ: + title: Anuncio + announcement: + description: El estilo con Markdown es compatible. También puedes especificar un anuncio diferente para cada idioma. Para editar el anuncio correspondiente de un idioma específico, por favor cambie a ese idioma y someta su edición. +meta: + title: Etiquetas SEO + meta_keywords: + title: Palabras clave + hint: Dividir con comas. + meta_description: + title: Descripción + hint: Descripción definida en "Opciones generales" se utilizará si la deja vacía. + meta_extras: + title: Otras etiquetas personalizadas +recaptcha: + recaptcha_invisible: + title: Invisible + label: Activar modo invisible +res-warning: Esta página es SOLO para usuarios avanzados. Si no estás familiarizado con estos, ¡por favor no las modifiques! +resources: + title: Archivos de recursos + hint: Por favor, compruebe estas opciones si ha habilitado CDN para su sitio. + force_ssl: + title: Forzar SSL + label: Utilizar el protocolo HTTPS para cargar todos los assets del front-end. + hint: Por favor, compruebe si SSL está realmente disponible antes de activar. + auto_detect_asset_url: + title: URL de assets + label: Determinar la url de assets automáticamente. + description: Por favor, deshabilite esto si las URL de los assets se generan incorrectamente bajo un CDN. Se utilizará la url del sitio si esto no está habilitado. + cache_expire_time: + title: Tiempo de expiración caché + hint: En segundos, 86400 = un día, 31536000 = un año. + cdn_address: + title: CDN de assets de front-end + hint: Los archivos front-end no se cargarán si la URL no está disponible. + description: | + La URL del CDN debe referirse a una réplica del directorio /public, + todos los archivos de ese directorio se cargarán como CDN.
+ ¿Cómo verificar? Verifica si {Your CDN URL}/app/manifest.json puede ser accedido. +cache: + title: Configuración de caché + clear: Limpiar caché + cleared: La caché ha sido borrada. + driver: El controlador de caché actual es :driver. + enable_avatar_cache: + title: Avatar + label: Habilitar avatar de caché + enable_preview_cache: + title: Preestreno de textura + label: Habilitar el preestreno de textura en caché diff --git a/resources/lang/es_ES/setup.yml b/resources/lang/es_ES/setup.yml new file mode 100755 index 0000000..cd5c89d --- /dev/null +++ b/resources/lang/es_ES/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "No se puede conectar a la base de datos :type, favor comprobar su configuración. El servidor respondió con: :msg" +locked: + title: Ya instalado + text: Parece que ya tienes instalado Blessing Skin Server. Para reinstalar, por favor elimine primero las tablas en su base de datos, o use un nuevo prefijo de tabla. + button: Volver al inicio +updates: + success: + title: Actualización finalizada +wizard: + master: + title: Asistente de actualizacones - Blessing Skin Server + welcome: + title: Bienvenido + button: Siguiente + text: Bienvenido a Blessing Skin Server v:version! + database: + title: Base de datos + text: La base de datos se utiliza para almacenar datos de Blessing Skin. + type: Tipo de base de datos + host: Host de base de datos + port: Puerto de base de datos + username: Usuario de base de datos + password: Contraseña de base de datos + db: Nombre de base de datos + db-notice: Debería proporcionar la ruta al archivo SQLite; no hay necesidad de llenar otros espacios en blanco si lo usa. + prefix: Prefijo de tabla de base de datos (opcional) + prefix-notice: No necesita utilizar esta opción a menos que desee instalar múltiples instancias de Blessing Skin Server en una base de datos. + info: + title: Información necesaria + button: Ejecutar instalación + text: Para continuar con la instalación, por favor rellene este formulario con los detalles de la cuenta de administrador inicial. No te preocupes, siempre puedes cambiar estos ajustes más tarde. + admin-email: Correo del administrador + admin-notice: Esta es la cuenta de super administrador ÚNICA que puede DAR o CANCELAR los privilegios de administrador de otros usuarios. + nickname: Apodo + password: Contraseña + pwd-notice: 'Atención: Necesitará la contraseña para iniciar sesión. Por favor, guárdelo en un lugar seguro.' + confirm-pwd: Confirmar contraseña + site-name: Nombre del sitio + site-name-notice: Esto se mostrará en todas las páginas. + finish: + title: Instalación completada + text: Blessing Skin Server ha sido instalado. ¡Gracias y disfrútalo! diff --git a/resources/lang/es_ES/skinlib.yml b/resources/lang/es_ES/skinlib.yml new file mode 100755 index 0000000..2d30b24 --- /dev/null +++ b/resources/lang/es_ES/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: Subir nuevo skin +show: + title: Detalles de textura + deleted: La textura solicitada ya ha sido eliminada. + private: La textura solicitada es privada y sólo visible para el subidor y los administradores. +upload: + title: Subir textura + name-rule: Menos de 32 caracteres y no debe contener ninguno especial. + name-rule-regexp: Las reglas de nombre personalizado se aplican como :regexp + private-score-notice: Se gastarán más puntuaciones por configurarlo como privado. Se le cobrará :score por cada almacenamiento KB. + invalid-size: Archivo :type no válido (ancho :width, altura :height) + invalid-hd-skin: Skin HD inválida (ancho y altura debe ser divisible por 32) + lack-score: No tienes suficiente puntuación para subir esta textura. + repeated: La textura ya está cargada por otra persona. Puede añadirla a su armario directamente. + success: Textura :name se ha subido exitosamente. +delete: + success: La textura se eliminó con éxito. +privacy: + success: La textura se estableció como :privacy con éxito. +rename: + success: La textura fue renombrada a :name con éxito. +model: + success: El modelo de la textura se cambió a :model con éxito. +no-permission: No tienes permiso para moderar esta textura. +non-existent: No existe la textura. +report: + duplicate: Ya ha reportado esta textura. Los administradores la revisarán tan pronto sea posible. También puede rastrear el estado de su informe en el Centro de usuarios. + success: '¡Gracias por reportar! Los administradores lo revisarán tan pronto sea posible.' diff --git a/resources/lang/es_ES/user.yml b/resources/lang/es_ES/user.yml new file mode 100755 index 0000000..d5bb1e2 --- /dev/null +++ b/resources/lang/es_ES/user.yml @@ -0,0 +1,101 @@ +--- +sign-success: Firmado con éxito. Obtuviste :score puntuaciones. +announcement: Anuncio +no-unread: No hay notificaciones nuevas. +verification: + disabled: La verificación del correo electrónico no está disponible. + frequent-mail: Haces clic en el botón de enviar demasiado rápido. Espera 60 segundos, tío. + verified: Tu cuenta ya está verificada. + success: El enlace de verificación fue enviado, por favor comprueba tu bandeja de entrada. + failed: No hemos podido enviarte el enlace de verificación. Mensaje detallado :msg + mail: + title: Verifique su cuenta en :sitename + message: Está recibiendo este correo electrónico porque alguien registró una cuenta con esta dirección en :sitename. + reset: 'Haga clic aquí para verificar su cuenta: :url' + ignore: Si no registraste una cuenta, no se requiere ninguna acción adicional. +score-intro: + title: '¿Qué es la puntuación?' + introduction: | + Utilizamos el sistema de puntuación para prevenir comportamientos como la subida de gran cantidades de texturas y el registro de jugadores casualmente. + Agregando jugadores, subiendo texturas o añadiendo un elemento skinlib a tu armario consumirá puntuaciones. + :return-score + + Nuevos usuarios obtendrán :initial_score inicialmente, y puedes adquirir puntajes :score-from ~ :score-to iniciando su sesión diariamente. + will-return-score: La puntuación se devolverá si eliminas jugadores, texturas subidas o elementos de armario. + no-return-score: La puntuación NO se devolverá si eliminas jugadores, texturas subidas o elementos de armario. + rates: + storage: ':score puntajes = 1 KB de almacenamiento' + player: ':score puntajes = 1 jugador' + closet: ':score puntajes = 1 elemento de armario' +closet: + add: + success: Añadido :name al armario con éxito. + repeated: Ya has añadido esta textura. + not-found: No podemos encontrar esta textura. + lack-score: No tienes suficiente puntuación para añadirlo al armario. + rename: + success: El elemento se renombró correctamente a :name + remove: + success: La textura se ha retirado del armario con éxito. + non-existent: La textura no existe en su armario. +player: + login-notice: Ahora puede iniciar su sesión con los nombres de jugadores que posees en el lugar de una dirección de correo electrónico. + player-name-rule: + official: El nombre del jugador sólo puede contener letras, números y guiones bajos. + cjk: El nombre del jugador puede contener letras, números, guiones bajos e ideógrafos unificados de CJK. + utf8: Player name must be a UTF-8 string. + custom: Las reglas de nombre del jugador personalizadas se aplican en este sitio Por favor, contacte a los administradores para obtener más información. + player-name-length: El nombre del jugador debe tener al menos :min caracteres y no más de :max caracteres. + add: + repeated: El nombre del jugador ya está registrado. + lack-score: No tienes suficiente puntuación para añadir un jugador. + success: Jugador :name se agregó exitosamente. + delete: + success: Jugador :name fue eliminado exitosamente. + rename: + repeated: Este nombre de jugador está ocupado. Por favor, elija otro. + success: Jugador :old fue renombrado a :new + set: + success: La textura se aplicó al jugador :name con éxito. + clear: + success: Las texturas del jugador :name se restablecieron con éxito. +profile: + avatar: + title: '¿Cambiar avatar?' + notice: Haz clic en el icono del engranaje "" de cualquier aspecto de tu armario, luego haz clic en "Establecer como avatar". Cortaremos el segmento de cabeza de ese skin para ti. Si no hay ningún icono como este, por favor intenta desabilitando su bloqueador de anuncios. + wrong-type: No puedes establecer una capa como avatar. + success: Nuevo avatar se ha establecido correctamente. + reset: Restablecer avatar + password: + title: Cambiar contraseña + old: Contraseña antigua + new: Contraseña nueva + confirm: Repetir contraseña + button: Cambiar contraseña + wrong-password: Contraseña original incorrecta. + success: Contraseña actualizada con éxito, por favor inicie sesión de nuevo. + nickname: + title: Cambiar apodo + empty: No se hay apodo asignado ahora. + success: Apodo actualizado correctamente a :nickname + email: + title: Cambiar email + new: Nuevo email + password: Contraseña actual + button: Cambiar email + wrong-password: Contraseña incorrecta. + existed: Esta dirección de correo electrónico está ocupada. + success: Dirección de correo electrónico actualizada con éxito, por favor inicie sesión de nuevo. + delete: + title: Eliminar cuenta + notice: '¿Seguro que quieres eliminar su cuenta en :site?' + admin: La cuenta de administrador no puede ser eliminada. + button: Borrar mi cuenta + modal-title: Necesita introducir su contraseña para continuar + modal-notice: | + Está a punto de eliminar su cuenta. + ¡Esto es permanente! Sin copias de seguridad, sin restauraciones, sin botón mágico. + Le advertimos, ¿bien? + password: Contraseña actual + wrong-password: Contraseña incorrecta. + success: Su cuenta se ha eliminado con éxito. diff --git a/resources/lang/es_ES/validation.yml b/resources/lang/es_ES/validation.yml new file mode 100755 index 0000000..51b6d07 --- /dev/null +++ b/resources/lang/es_ES/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: ':attribute debe ser aceptado.' +active_url: ':attribute no es una URL válida.' +after: ':attribute debe ser una fecha posterior a :date.' +after_or_equal: ':attribute debe ser una fecha posterior o igual a :date.' +alpha: ':attribute sólo debe contener letras.' +alpha_dash: ':attribute sólo debe contener letras, números, guiones y guiones bajos.' +alpha_num: ':attribute sólo debe contener letras y números.' +array: ':attribute debe ser un conjunto.' +before: ':attribute debe ser una fecha anterior a :date.' +before_or_equal: ':attribute debe ser una fecha anterior o igual a :date.' +between: + numeric: ':attribute tiene que estar entre :min - :max.' + file: ':attribute debe pesar entre :min - :max kilobytes.' + string: ':attribute tiene que tener entre :min - :max caracteres.' + array: ':attribute tiene que tener entre :min - :max elementos.' +boolean: 'El campo :attribute debe tener un valor verdadero o falso.' +captcha: 'Captcha incorrecta.' +confirmed: 'La confirmación de :attribute no coincide.' +date: ':attribute no es una fecha válida.' +date_equals: ':attribute debe ser una fecha igual a :date.' +date_format: ':attribute no corresponde al formato :format.' +different: ':attribute y :other deben ser diferentes.' +digits: ':attribute debe tener :digits dígitos.' +digits_between: ':attribute debe tener entre :min y :max dígitos.' +dimensions: 'Las dimensiones de la imagen :attribute no son válidas.' +distinct: 'El campo :attribute contiene un valor duplicado.' +email: ':attribute no es un correo válido.' +ends_with: 'El campo :attribute debe finalizar con uno de los siguientes valores: :values' +exists: ':attribute es inválido.' +file: 'El campo :attribute debe ser un archivo.' +filled: 'El campo :attribute es obligatorio.' +gt: + numeric: 'El campo :attribute debe ser mayor que :value.' + file: 'El campo :attribute debe tener más de :value kilobytes.' + string: 'El campo :attribute debe tener más de :value caracteres.' + array: 'El campo :attribute debe tener más de :value elementos.' +gte: + numeric: 'El campo :attribute debe ser como mínimo :value.' + file: 'El campo :attribute debe tener como mínimo :value kilobytes.' + string: 'El campo :attribute debe tener como mínimo :value caracteres.' + array: 'El campo :attribute debe tener como mínimo :value elementos.' +image: ':attribute debe ser una imagen.' +in: ':attribute es inválido.' +in_array: 'El campo :attribute no existe en :other.' +integer: ':attribute debe ser un número entero.' +ip: ':attribute debe ser una dirección IP válida.' +ipv4: ':attribute debe ser un dirección IPv4 válida.' +ipv6: ':attribute debe ser un dirección IPv6 válida.' +json: 'El campo :attribute debe ser una cadena JSON válida.' +lt: + numeric: 'El campo :attribute debe ser menor que :value.' + file: 'El campo :attribute debe tener menos de :value kilobytes.' + string: 'El campo :attribute debe tener menos de :value caracteres.' + array: 'El campo :attribute debe tener menos de :value elementos.' +lte: + numeric: 'El campo :attribute debe ser como máximo :value.' + file: 'El campo :attribute debe tener como máximo :value kilobytes.' + string: 'El campo :attribute debe tener como máximo :value caracteres.' + array: 'El campo :attribute debe tener como máximo :value elementos.' +max: + numeric: ':attribute no debe ser mayor que :max.' + file: ':attribute no debe ser mayor que :max kilobytes.' + string: ':attribute no debe ser mayor que :max caracteres.' + array: ':attribute no debe tener más de :max elementos.' +mimes: ':attribute debe ser un archivo con formato: :values.' +mimetypes: ':attribute debe ser un archivo con formato: :values.' +min: + numeric: 'El tamaño de :attribute debe ser de al menos :min.' + file: 'El tamaño de :attribute debe ser de al menos :min kilobytes.' + string: ':attribute debe contener al menos :min caracteres.' + array: ':attribute debe tener al menos :min elementos.' +not_in: ':attribute es inválido.' +not_regex: 'El formato del campo :attribute no es válido.' +numeric: ':attribute debe ser numérico.' +password: La contraseña es incorrecta. +present: 'El campo :attribute debe estar presente.' +recaptcha: 'Falló la validación de reCAPTCHA.' +regex: 'El formato de :attribute es inválido.' +required: 'El campo :attribute es obligatorio.' +required_if: 'El campo :attribute es obligatorio cuando :other es :value.' +required_unless: 'El campo :attribute es obligatorio a menos que :other esté en :values.' +required_with: 'El campo :attribute es obligatorio cuando :values está presente.' +required_with_all: 'El campo :attribute es obligatorio cuando :values están presentes.' +required_without: 'El campo :attribute es obligatorio cuando :values no está presente.' +required_without_all: 'El campo :attribute es obligatorio cuando ninguno de :values está presente.' +same: ':attribute y :other deben coincidir.' +size: + numeric: 'El tamaño de :attribute debe ser :size.' + file: 'El tamaño de :attribute debe ser :size kilobytes.' + string: ':attribute debe contener :size caracteres.' + array: ':attribute debe contener :size elementos.' +starts_with: 'El campo :attribute debe comenzar con uno de los siguientes valores: :values' +string: 'El campo :attribute debe ser una cadena de caracteres.' +timezone: 'El :attribute debe ser una zona válida.' +unique: 'El campo :attribute ya ha sido registrado.' +uploaded: 'Subir :attribute ha fallado.' +url: 'El formato :attribute es inválido.' +uuid: 'El campo :attribute debe ser un UUID válido.' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: nombre + player_name: nombre del jugador + identification: email o nombre del jugador + email: correo electrónico + password: contraseña + password_confirmation: 'confirmación de la contraseña' + title: título + content: contenido diff --git a/resources/lang/fr_FR/admin.yml b/resources/lang/fr_FR/admin.yml new file mode 100755 index 0000000..9a42006 --- /dev/null +++ b/resources/lang/fr_FR/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: Utilisateurs inscrits + total-players: Joueurs + total-textures: Textures chargées + disk-usage: Utilisation du disque + overview: Aperçu + texture-uploads: Chargements de textures + user-registration: Enregister un utilisateur +notifications: + send: + title: Envoyer une notification + success: Envoyée avec succès ! + receiver: + title: Destinataire + all: Tous les utilisateurs + normal: Utilisateurs normaux + uid: UID spécifié + email: Adresse e-mail spécifiée + title: Titre + content: Contenu (Markdown est supporté) +users: + operations: + non-existent: Cet utilisateur n'existe pas. + no-permission: Vous n'avez pas la permission de gérer cet utilisateur. + email: + success: Adresse e-mail changée avec succès. + verification: + success: Statut de vérification du compte activé avec succès. + nickname: + success: Pseudonyme changé avec succès. + password: + success: Mot de passe changé avec succès. + score: + success: Score changé avec succès. + permission: Permission mise à jour. + delete: + success: Le compte a été supprimé avec succès. +players: + no-permission: Vous n'avez pas la permission de gérer ce joueur. + textures: + non-existent: Cette texture n'existes pas tid.:tid + success: Les textures de :player ont été mises à jour. + name: + success: Le nom d'utilisateur à bien été mis à jour pour :player + owner: + success: Le joueur :player a été transféré vers l'utilisateur :user. + delete: + success: Le joueur a été supprimé avec succès. +customize: + change-color: + title: Changer la couleur du thème + colors: + navbar: Barre de navigation du haut + sidebar: + dark: Barre latérale (sombre) + light: Barre latérale (claire) +i18n: + add: Ajouter une nouvelle langue + added: Language ajouté. + updated: Langage mis à jour. + deleted: Langage supprimé. + group: Groupe + key: Clé + text: Texte + tip: Comment puis-je utiliser cette page ? +status: + info: Information + health: Santé + bs: + name: Blessing Skin + version: Version + env: Environnement d'application + debug: Débogage ou pas ? + commit: Révision + laravel: Version de Laravel + server: + name: Serveur + php: Version de PHP + web: Logiciel de serveur Web + os: OS + db: + name: Base de données + type: Serveur + host: Hôte + port: Port + username: Nom d'utilisateur + database: Base de données + prefix: Préfixe de table + plugins: Plugins activés (:amount) +plugins: + readme: Lisez-moi + operations: + title: Actions + enabled: ':plugin a été activé.' + unsatisfied: + notice: Il y a des conflits ou des dépendances insatisfaisantes dans le plugin, nous ne pouvons donc pas l'activer. Veuillez installer ou mettre à jour les plugins listés ci-dessous, et désactiver ceux qui ont des conflits. + disabled: 'Le plugin ":name" n''est pas activé.' + version: 'La version de ":title" ne satisfait pas la contrainte ":constraint".' + conflict: 'Le plugin ":title" ne peut pas être exécuté avec ce plugin en même temps.' + disabled: ':plugin a été désactivé.' + deleted: Le plugin a été supprimé avec succès. + no-config-notice: Le plugin n'est pas installé ou ne fournit pas de page de configuration. + no-readme-notice: Le plugin ne contient pas de fichier "readme". + not-found: Ce plugin n'existe pas. + market: + unresolved: Il y a des conflits ou des dépendances insatisfaisantes dans le plugin, nous ne pouvons donc pas le télécharger. Veuillez installer ou mettre à jour les plugins listés ci-dessous, et désactiver ceux qui ont des conflits. + connection-error: Impossible de se connecter au registre des plugins. :error + non-existent: Le plugin :plugin n'existe pas. + install-success: Plugin installé avec succès. +update: + complete: Mise à jour terminée + info: + title: Mettre à jour les informations + up-to-date: Déjà mis à jour. + available: Nouvelle version disponible. + versions: + latest: "Dernière version :" + current: "Version actuelle :" + check-github: Consulter les versions de GitHub + button: Mettre à jour maintenant + cautions: + title: Avertissement + link: jetez-y un coup d'œil. + text: | + Veuillez choisir la source de mise à jour en fonction de l'environnement réseau de votre hôte. + La connexion à faible vitesse entre la source de mise à jour et votre hôte provoquera un chargement prolongé lors de la vérification et du téléchargement de la page. + Pour modifier la source de mise à jour par défaut, + errors: + connection: "Impossible d'accéder à la source de la mise à jour actuelle. Détails : :error" + spec: La source de la mise à jour actuelle n'est pas prise en charge. + php: Votre version de PHP est trop faible pour être mise à jour. Nécessite :version ou supérieure. +download: + errors: + download: 'Échec du téléchargement. Erreur : :error' + shasum: Échec de la validation du fichier. Veuillez recommencer le telechargement. + unzip: Impossible de dézipper les fichiers. +invalid-action: Action invalide diff --git a/resources/lang/fr_FR/auth.yml b/resources/lang/fr_FR/auth.yml new file mode 100755 index 0000000..6ce56bf --- /dev/null +++ b/resources/lang/fr_FR/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: Se connecter + message: Connectez-vous pour gérer vos skins et joueurs + success: Authentification réussie. +check: + anonymous: Accès illégal. Veuillez vous connecter d'abord. + verified: Pour accéder à cette page, vous devez d'abord vérifier votre adresse e-mail. + admin: Seuls les administrateurs ont la permission d'accéder à cette page. + banned: Vous êtes banni de ce site. Veuillez contacter l'administrateur. +register: + title: S'inscrire + message: Bienvenue sur :sitename ! + success: Votre compte a été créé. Redirection... + max: Vous ne pouvez pas créer plus de :regs comptes. +forgot: + title: Mot de passe oublié ? + message: Nous vous enverrons un e-mail de vérification. + disabled: La réinitialisation de mot de passe n'est pas disponible. + frequent-mail: Vous avez cliqué trop rapidement sur le bouton d'envoi. Patientez quelques minutes. + unregistered: L'adresse e-mail n'est pas enregistrée. + success: L'e-mail a été envoyé, consultez votre boîte de réception. Le lien expirera dans 1 heure. + failed: Erreur lors de l'envoi de l'e-mail de vérification. :msg + ignore: Si vous ne vous êtes pas inscrit sur notre site, veuillez ignorer cet e-mail. Aucune désinscription n'est requise. + reset: Réinitialisez votre mot de passe + notice: Ce courrier est envoyé automatiquement, aucune réponse ne sera envoyée si vous y répondez. + mail: + title: Réinitialiser votre mot de passe sur :sitename + message: Vous recevez cet e-mail car nous avons reçu une demande de réinitialisation de mot de passe pour votre compte sur :sitename. + reset: 'Pour réinitialiser votre mot de passe, veuillez visiter : :url' + ignore: Si vous n’avez pas demandé de réinitialisation du mot de passe, aucune autre action n’est requise. +reset: + title: Réinitialiser le mot de passe + button: Réinitialiser + invalid: Lien invalide. + expired: Le lien a expiré. + message: ':username, réinitialisez votre mot de passe ici.' + success: Mot de passe réinitialisé avec succès. +bind: + title: Lier l'adresse e-mail + button: Lier + message: Vous devez fournir votre adresse e-mail pour continuer. + introduction: Nous ne vous enverrons aucun spam. + registered: Cette adresse e-mail est déjà utilisée. +verify: + title: Vérification de l'adresse e-mail + invalid: Lien invalide. + not-matched: Le nom de courriel ne correspond pas. +validation: + user: Cet utilisateur n'existe pas. + password: Mot de passe incorrect. +logout: + success: Vous êtes maintenant déconnecté. +oauth: + authorization: + title: Autorisation + introduction: Une application tierce ":name" demande l'autorisation d'accéder à votre compte. + button: Autoriser + permissions: Permissions + scope: + user: + read: Connectez-vous et lisez votre profil + notification: + read: Autoriser l'application à accéder à vos notifications. + readwrite: Autoriser l'application à envoyer des notifications. + player: + read: Autoriser l'application à lire vos joueurs. + readwrite: Permet à l'application de créer, lire, mettre à jour et supprimer des joueurs. + closet: + read: Autoriser l'application à lire les éléments de votre placard. + readwrite: Autoriser l'application à créer, lire, mettre à jour et supprimer les éléments de votre placard. + users-management: + read: Autoriser l'application à lire les rapports de l'utilisateur. + readwrite: Autoriser l'application à créer, lire, mettre à jour et supprimer les utilisateurs du site. + players-management: + read: Autoriser l'application à lire vos joueurs. + readwrite: Permet à l'application de créer, lire, mettre à jour et supprimer des joueurs. + closet-management: + read: Autoriser l'application à lire les éléments de votre placard. + readwrite: Autoriser l'application à créer, lire, mettre à jour et supprimer les éléments du placard de l'utilisateur. + reports-management: + read: Autoriser l'application à lire les rapports de l'utilisateur. + readwrite: Autoriser l'application à lire et à examiner les rapports des utilisateurs. +email: Adresse e-mail +register-link: Créer un nouveau compte diff --git a/resources/lang/fr_FR/errors.yml b/resources/lang/fr_FR/errors.yml new file mode 100755 index 0000000..f473029 --- /dev/null +++ b/resources/lang/fr_FR/errors.yml @@ -0,0 +1,19 @@ +--- +http: + msg-403: Vous n'avez pas la permission d'accéder à cette page. + msg-404: Il n'y a rien ici. + msg-500: Veuillez réessayer plus tard. + msg-503: L'application est maintenant en mode maintenance. + method-not-allowed: Méthode non autorisée. + csrf-token-mismatch: Le jeton ne correspond pas, essayez de recharger la page. + ie: Votre navigateur n'est pas pris en charge. Veuillez passer à d'autres navigateurs modernes, tels que Firefox ou Chrome. +general: + title: Une erreur s'est produite +exception: + code: 'Code d''erreur : :code' + detail: 'Détails : :msg' + message: | + Oups, on dirait qu'une erreur s'est produite. (activez APP_DEBUG dans .env pour voir les détails) +plugins: + duplicate: Le plugin [:dir1] a un nom de plugin dupliqué qui est identique au plugin [:dir2]. Veuillez vérifier le répertoire de vos plugins, supprimer l'un d'eux ou utiliser une autre définition de nom. + boot: Il y a un problème avec le plugin ":plugin". diff --git a/resources/lang/fr_FR/front-end.yml b/resources/lang/fr_FR/front-end.yml new file mode 100755 index 0000000..c15c7d4 --- /dev/null +++ b/resources/lang/fr_FR/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: Se connecter + loggingIn: Authentification + tooManyFails: + captcha: Vous avez échoué trop de fois! Veuillez passer le reCAPTCHA. + recaptcha: Vous avez échoué trop de fois! Veuillez passer le reCAPTCHA. + emptyEmail: Adresse e-mail vide. + invalidConfirmPwd: Le mot de passe de confirmation n'est pas le meme que le mot de passe original. + emptyNickname: Pseudonyme vide. + register: S'inscrire + registering: Inscription + send: Envoyer + sending: Envoi en cours + reset: Réinitialiser + resetting: Réinitialisation + nickname: Pseudonyme + player-name: Nom du joueur dans Minecraft + email: Adresse e-mail + identification: Adresse e-mail ou nom du joueur + password: Mot de passe + captcha: CAPTCHA + change-captcha: Cliquez pour changer l'image du CAPTCHA. + login-link: Déjà inscrit? Connectez-vous ici. + forgot-link: Mot de passe oublié ? + keep: Se souvenir de moi + repeat-pwd: Répétez votre mot de passe + nickname-intro: Tout ce que vous voulez sauf des caractères spéciaux + player-name-intro: Le nom du joueur dans Minecraft, peut être modifié plus tard + forgot: + login-link: Je m'en souviens +skinlib: + private: Privé + anonymous: Connectez-vous d'abord. + reset: Réinitialiser le filtre + addToCloset: Ajouter à la garde-robe + removeFromCloset: Retirer de la garde-robe + setItemName: Définir un nom pour cette texture + applyNotice: Vous pouvez l'appliquer au joueur dans votre garde-robe + emptyItemName: Nom de texture vide. + setNewTextureName: 'Veuillez entrer le nouveau nom de texture :' + emptyNewTextureName: Nom de nouvelle texture vide. + seeMyUpload: Mes téléversements + apply: Appliquer + filter: + skin: (N'importe quel modèle) + steve: (Steve) + alex: (Alex) + cape: (Cape) + uploader: 'Utilisateur (UID = :uid) téléchargé' + allUsers: Tous les utilisateurs + sort: + title: Trier + time: Récents + likes: Le plus populaire + emptyTextureName: Nom de texture vide. + emptyUploadFile: Vous n'avez pas encore téléchargé de fichiers. + fileExtError: 'Erreur: Les textures doivent être des fichiers PNG.' + uploading: Transfert en cours… + setAsPrivate: Rendre privé + setAsPublic: Rendre public + setPublicNotice: Êtes-vous sûr de vouloir définir ceci comme texture public ? + setPrivateNotice: Êtes-vous sûr de vouloir définir ceci comme texture public ? + deleteNotice: Êtes-vous sûr de vouloir supprimer cette texture? + setNewTextureModel: "Veuillez sélectionner un nouveau modèle de texture:" + upload: + texture-name: Nom de la texture + texture-type: Type de texture + select-file: Sélectionner un fichier + privacy-notice: Empêche l'affichage dans la bibliothèque de skins. + set-as-private: Rendre privé + button: Téléverser + cost: Cela vous coûte environ :score . + award: Vous serez récompensé de :score score(s) en téléchargeant des textures publiques. + show: + anonymous: Vous devez vous connecter pour utiliser votre garde-robe + likes: Personnes qui ont aimé + detail: Détails + name: Nom de la texture + edit: Modifier + model: Modèle applicable + size: Taille du fichier + uploader: Auteur + upload-at: Téléchargé le + download: Télécharger + delete-texture: Supprimer la texture + manage-notice: La texture, une fois supprimée ou réglée en privé sera retirée de la garde-robe de tous ceux qui l'y ont ajoutée. + report: + title: Signaler + reason: Dites-nous la raison s'il vous plaît. + positive: Pour encourager les contributions positives à la bibliothèque de skins, nous récompenserons ceux qui ont signalé un contenu inapproprié avec :score scores. Cependant, si des signalement abusifs ont été trouvés, toutes les récompenses seront récupérés. + negative: Pour atténuer l'impact des rapports abusifs, nous aurons besoin de :score pour envoyer votre rapport. Ne vous inquiétez pas. Les scores suspendus et les récompenses supplémentaires seront envoyés à votre compte après examen de votre rapport par les administrateurs. +user: + signRemainingTime: 'Disponible après :time :unit' + timeUnitHour: h + timeUnitMin: min + emptyClosetMsg: >- +

Rien dans votre garde-robe...

Pourquoi ne pas explorer la bibliothèque de Skin ?

+ renameItem: Renommer l'élément + removeItem: Retirer de la garde-robe + setAsAvatar: Utiliser en tant qu'avatar + viewInSkinlib: Voir dans la bibliothèque de skins + switch2dPreview: Passer à l'aperçu 2D + switch3dPreview: Passer à l'aperçu 3D + removeFromClosetNotice: Êtes-vous sûr de vouloir retirer cette texture de votre garde-robe ? + emptySelectedTexture: Aucune texture n'est sélectionnée. + renameClosetItem: 'Set a new name for this item:' + changePlayerName: 'Veuillez entrer le nom du joueur:' + emptyPlayerName: Nom du joueur vide. + deletePlayer: Êtes-vous sûr de vouloir supprimer ce joueur? + deletePlayerNotice: C'est permanent. Aucune restauration possible. + chooseClearTexture: Choisissez les types de texture que vous voulez effacer + noClearChoice: You haven't choose any types + setAvatar: Êtes-vous sûr de vouloir définir ceci comme votre avatar ? + setAvatarNotice: Le segment de tête de votre skin sera utilisé. + resetAvatarConfirm: Êtes-vous sûr de vouloir réinitialiser votre avatar ? + typeToSearch: Tapez pour rechercher + useAs: Appliquer... + resetSelected: Effacer la sélection + closet: + upload: Upload Texture + use-as: + title: À quel joueur faut-il appliquer ? + empty: Il semble que vous ne possédiez aucun joueur... + used: + title: Ressources utilisées + players: Joueurs inscrits + storage: Espace utilisé + cur-score: Score actuel + score-notice: Cliquez sur le score pour afficher l'introduction. + sign: Sign + player: + operation: Actions + edit-pname: Modifier le nom + delete-texture: Effacer les textures + delete-player: Supprimer + add-player: Ajouter un nouveau joueur + texture-empty: Rien + verification: + title: Vérifiez votre compte + message: Vous devez vérifier votre adresse e-mail avant d'utiliser le service d'hébergement de skin. Vous n'avez pas reçu l'e-mail ? + resend: Cliquez ici pour renvoyer. + sending: Envoi... + oauth: + id: Client ID + name: Nom de l'application + secret: Client Secret + redirect: URL de callback + modifyName: Modifier le nom de l'application. + modifyUrl: Modifier l'URL de callback. + create: Créer une nouvelle appli + confirmRemove: Êtes-vous sûr de vouloir supprimer cette application ? Vous ne pourrez pas annuler cette action. +admin: + operationsTitle: Actions + permission: Permission + deleteUser: Supprimer + changeEmail: Modifier l'adresse e-mail + newUserEmail: 'Veuillez entrer le nouvel e-mail :' + verification: Vérification de l'adresse e-mail + toggleVerification: Activer/désactiver le statut de vérification + changeNickName: Modifier le pseudonyme + newUserNickname: 'Veuillez entrer le nouveau pseudonyme :' + changePassword: Modifier le mot de passe + newUserPassword: 'Veuillez entrer le nouveau mot de passe :' + changeScore: Modifier le score + newScore: 'Veuillez entrer le nouveau score:' + changePermission: Modifier la permission + newPermission: 'Veuillez sélectionner une nouvelle permission :' + deleteUserNotice: Êtes-vous sûr de vouloir supprimer cet utilisateur ? Cela est définitif. + banned: Banni + normal: Normal + admin: Administrateur + superAdmin: Super administrateur + unverified: Non vérifié + verified: Vérifié + pidNotice: >- + Please enter the tid of texture. Inputing 0 can clear texture of this player. + changeTexture: Changer les textures + changePlayerName: Changer le nom du joueur + changeOwner: Changer de propriétaire + textureType: Type de texture + deletePlayer: Supprimer + changePlayerOwner: 'Please enter the id of user which this player should be transferred to:' + deletePlayerNotice: Êtes-vous sûr de vouloir supprimer cet utilisateur ? Cela est définitif. + changePlayerNameNotice: 'Veuillez entrer un nouveau nom de joueur:' + emptyPlayerName: Le nom du joueur ne peut pas être vide. + configurePlugin: Configurer + deletePlugin: Supprimer + noDependencies: Aucune dépendance + pluginTitle: Plugin + pluginAuthor: Auteur + pluginVersion: Version + pluginReadme: Lisez-moi + pluginDescription: Description + pluginDependencies: Dépendances + installPlugin: Installer + pluginInstalling: Installation... + updatePlugin: Mettre à jour + pluginUpdating: Mise à jour... + confirmUpdate: Êtes-vous sûr de vouloir mettre à jour ":plugin" de :old à :new? + enablePlugin: Activer + disablePlugin: Désactiver + confirmDeletion: Êtes-vous sûr de vouloir supprimer ce plugin ? + uploadArchive: Mettre en ligne une archive + uploadArchiveNotice: Installez un plugin en envoyant une archive ZIP. + downloadRemote: Installez un plugin à partir d'une URL distante + downloadRemoteNotice: Installez un plugin en téléchargeant une archive ZIP à partir d'une URL distante. + updateButton: Mettre à jour maintenant + downloading: Téléchargement... + i18n: + group: Groupe + key: Clé + text: Texte + empty: (Vide) + modify: Modifier + delete: Supprimer + updating: 'Veuillez saisir un nouveau texte :' + confirmDelete: Êtes-vous sûr ? C'est irréversible. +report: + tid: ID de texture + reporter: Auteur du signalement + reason: Raison + status-title: Statut + status: + - Suspendu + - Résolu + - Rejeté + time: Heure du signalement + delete: Supprimer + ban: Bannir + reject: Rejeter +general: + skin: Skin + cape: Cape + fatalError: Erreur fatale + confirmLogout: Voulez-vous vraiment vous déconnecter ? + confirm: OK + cancel: Annuler + submit: Envoyer + close: Fermer + more: Plus + tip: Conseil + noResult: Aucun résultat. + texturePreview: Aperçu de la texture + walk: Marcher + run: Courir + rotation: Rotation + pause: Suspendre + reset: Réinitialiser + skinlib: Bibliothèque de skins + wait: Veuillez patienter... + csrf: Cette page est obsolète. Veuillez la rafraîchir. + user: + email: Adresse e-mail + nickname: Pseudonyme + score: Score + register-at: Inscrit à + player: + owner: Propriétaire + player-name: Nom du joueur + previews: Aperçu de la texture + last-modified: Dernière modification +colors: + black: Noir + white: Blanc + gray: Gris + prev: Arrière-plan précédent + next: Prochain arrière-plan +vendor: + datatable: + search: Rechercher + prev: Précédent + next: Suivant diff --git a/resources/lang/fr_FR/general.yml b/resources/lang/fr_FR/general.yml new file mode 100755 index 0000000..19fb271 --- /dev/null +++ b/resources/lang/fr_FR/general.yml @@ -0,0 +1,59 @@ +--- +index: Page d'accueil +skinlib: Bibliothèque de skins +user-center: Centre utilisateur +logout: Se déconnecter +login: Se connecter +register: S'inscrire maintenant +profile: Profil utilisateur +admin-panel: Panneau d'administration +explore: Explorer +manage: Gérer +anonymous: Invité +back: Retour +dashboard: Tableau de bord +my-closet: Garde-robe +my-reports: Rapports +developer: Avancé +oauth-manage: Applications OAuth2 +player-manage: Joueurs +user-manage: Utilisateurs +report-manage: Rapports +plugin-manage: Plugins +plugin-market: Marché des plugins +plugin-configs: Configuration des plugins +customize: Personnaliser +i18n: Internationalisation +options: Options +score-options: Options de score +res-options: Options de ressources +status: Statut +check-update: Recherche de mises à jour +download-update: Télécharger les mises à jour +close: Fermer +skin: Skin +cape: Cape +submit: Soumettre +cancel: Annuler +yes: true +no: false +op-success: Opération terminée. +unknown: Inconnu +notice: Notice +illegal-parameters: Paramètres illégaux. +private: Privé +public: Public +unexistent-user: Cet utilisateur n'existe pas. +player-banned: Le propriétaire de ce joueur a été banni. +texture-deleted: La texture demandée a été supprimée. +user: + email: Adresse e-mail + nickname: Pseudonyme + password: Mot de passe + score: Score + register-at: Inscrit à +player: + owner: Propriétaire + player-name: Nom du joueur + previews: Aperçu de la texture + last-modified: Dernière modification diff --git a/resources/lang/fr_FR/index.yml b/resources/lang/fr_FR/index.yml new file mode 100755 index 0000000..2db7c54 --- /dev/null +++ b/resources/lang/fr_FR/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: Fonctionnalités + first: + icon: fa-users + name: Multijoueur + desc: Vous pouvez ajouter plusieurs joueurs dans un même compte enregistré. + second: + icon: fa-share-alt + name: Partage + desc: Explorez la bibliothèque de skins, mettez des "j'aime" et partagez-les avec vos amis. + third: + icon: fa-cloud + name: Gratuit + desc: Gratuit à vie. Pas de pub. Pas de frais d'abonnement. +introduction: ':sitename fournit un service de chargement et d''hébergement de skins Minecraft. En coordination avec des mods de skins (comme CustomSkinLoader), vous pouvez choisir un skin et une cape pour votre personnage et le rendre visible pour les autres joueurs dans le jeu.' +start: Rejoignez-nous diff --git a/resources/lang/fr_FR/options.yml b/resources/lang/fr_FR/options.yml new file mode 100755 index 0000000..89eb3cc --- /dev/null +++ b/resources/lang/fr_FR/options.yml @@ -0,0 +1,180 @@ +--- +option-saved: Option enregistrée. +homepage: + title: Page d'accueil + home_pic_url: + title: URL de l'image sur la page d'accueil + hint: Chemin relatif à la page d'accueil ou à l'URL complète, laisser vide pour utiliser l'image par défaut. + favicon_url: + title: Icône du site web + hint: Chemin relatif au public/ou à l'URL complète. + description: L'image donnée doit avoir la même largeur et la même hauteur (laissez vide pour utiliser l'icône par défaut). + transparent_navbar: + title: Barre de navigation transparente + label: Cela activera la barre de navigation transparente de la page d'accueil, mais cela deviendra normal si la page est défilée vers le bas. + hide_intro: + title: Masquer l'introduction en bas + label: La barre de défilement sera désactivée si cette option est activée, comme la version 2.x. + fixed_bg: + title: Arrière-plan fixe + label: Cette option permet de rendre l'arrière-plan fixe et de ne pas défiler avec la barre de défilement. + copyright_prefer: + title: Copyright du programme + description: "Vous pouvez spécifier un style différent de copyright pour chaque langue. Pour modifier le style de copyright correspondant à une langue donnée, veuillez basculer vers cette langue et envoyer votre modification.
Avertissement : Toute modification malveillante appliquée sur le copyright du programme dans le pied de page (y compris la suppression, modifier l'auteur, changer la cible du lien) sans la permission est INTERDIT. L'auteur se réserve le droit de poursuivre les responsabilités." + copyright_text: + title: Texte de copyright personnalisé + description: Placeholders are available in custom copyright text. e.g. {site_name} & {site_url}. You can also specify a different footer for each language. To edit a specific language's corresponding footer, please switch to that language and submit your edit. +customJsCss: + title: CSS/JavaScript personnalisés + message: | + Le contenu sera attaché aux balises <style> et <script> .
+ - Voici quelques exemples utiles : Exemples de CSS et JavaScript personnalisés + custom_css: CSS + custom_js: JavaScript +rate: + title: Scores + score_per_storage: + title: Espace disque + addon: scores = 1 KB + private_score_per_storage: + title: Private Storage + addon: scores = 1 KB + hint: Uploading private textures will cost more scores. + score_per_closet_item: + title: Favoris + addon: score = 1 closet item + return_score: + title: Score Return + label: Return scores back to user after deleting players/textures/closet items. + score_per_player: + title: Joueurs + addon: scores = 1 player + user_initial_score: User Initial Score +report: + title: Reporting Textures + reporter_score_modification: + title: Scores for Submitting an Report + description: Set a positive integer value to reward user who submits new reports. Set to a negative value will require scores for submitting reports, and the suspended scores will be available if user's report was resolved. Set to 0 to disable. + reporter_reward_score: + title: Reward the Reporter with Scores If Report Resolved +sign: + title: Signing + sign_score: + title: Score Granted + addon1: scores ~ + addon2: scores + sign_gap_time: + title: Gap Time + addon: heures + sign_after_zero: + title: Temps + label: Users can sign in after 0 everyday. + hint: The above option will be ignored if this is checked. +sharing: + title: Awarding Sharing + score_award_per_texture: + title: Uploader will be rewarded for each uploading texture with + take_back_scores_after_deletion: + title: Return scores + label: Return scores if uploader setting private or deleting texture. + score_award_per_like: + title: Chaque fois que la texture est envoyée, l'uploader sera récompensé avec +general: + title: Options générales + site_name: Nom du site + site_description: + title: Description du site + description: Vous pouvez également spécifier un nom de site et une description différents pour chaque langue. Pour modifier le nom du site ou le texte de description correspondant à une langue spécifique, veuillez basculer vers cette langue et appliquer votre modification. + site_url: + title: URL du site + hint: Commencer par http(s)://, et ne se termine jamais avec un slash. + register_with_player_name: + title: S'inscrire avec le nom du joueur + label: Require Minecraft's player name when user register + require_verification: + title: Vérification du compte + label: Les utilisateurs doivent d'abord vérifier leur adresse e-mail. + regs_per_ip: Comptes maximum par IP + max_upload_file_size: + title: Taille maximale d'envoie + hint: "Limite spécifiée dans php.ini : :size" + player_name_rule: + title: Player Name Rule + official: Letters, numbers and underscores (Mojang's official rule) + cjk: Autoriser les idéographes unifiés CJK + utf8: Allow all valid UTF-8 characters (excluding whitespaces) + custom: Use custom rules (regular expression) + custom_player_name_regexp: + title: Custom Player Name Rules + hint: Ne prend effet que lorsque l'option ci-dessus est définie sur "personnalisé". Laisser vide pour autoriser n'importe quel caractère. + placeholder: Expressions regulières + player_name_length: + title: Longueur du nom du joueur + suffix: caractères + auto_del_invalid_texture: + title: Textes invalides + label: Delete invalid textures automatically. + hint: Retirer les textures dont les fichiers n'existent plus dans la bibliothèque de skins. + allow_downloading_texture: + title: Téléchargement des textures + label: Permettre aux utilisateurs de télécharger directement le fichier source d'un élément de la bibliothèque de skins. + status_code_for_private: + title: Code HTTP pour rejeter l'accès aux textures privées + texture_name_regexp: + title: Règles de nom de texture + hint: Le RegExp pour valider le nom des textures téléchargées. Laissez vide pour autoriser n'importe quel caractère, sauf les guillemets simples, doubles et antislash. + placeholder: Expressions regulières + content_policy: + title: Politique de contenu + description: Afficher la politique de contenu à la page de téléchargement de textures, en prenant en charge Markdown. Pour modifier la politique de contenu correspondant à une langue spécifique, veuillez basculer vers cette langue et soumettre votre modification. +announ: + title: Annonce + announcement: + description: Le style avec Markdown est pris en charge. Vous pouvez également spécifier une annonce différente pour chaque langue. Pour modifier l'annonce correspondante d'une langue spécifique, veuillez basculer vers cette langue et soumettre votre modification. +meta: + title: Balises SEO + meta_keywords: + title: Mots-clés + hint: Diviser avec des virgules. + meta_description: + title: Description + hint: La description définie dans "options générales" sera utilisée si vous la laissez vide. + meta_extras: + title: Autres tags personnalisés +recaptcha: + recaptcha_invisible: + title: Invisible + label: Activer le mode invisible +res-warning: Cette page est UNIQUEMENT destinée aux utilisateurs avancés. Si vous ne savez pas ce que vous faites, ne modifiez rien ! +resources: + title: Fichiers de ressources + hint: Veuillez vérifier ces options si vous avez activé le CDN pour votre site. + force_ssl: + title: Forcer SSL + label: Utiliser le protocole HTTPS pour charger tous les assets. + hint: Please check if SSL really available before turning on. + auto_detect_asset_url: + title: URL des assets + label: Déterminer l'url des assets automatiquement. + description: Please unable this if assets URLs are wrongly generated under a CDN. The site url will be used if this is not enabled. + cache_expire_time: + title: Temps de validité du cache + hint: En secondes, 86400 = un jour, 31536000 = un an. + cdn_address: + title: CDN des assets + hint: Les fichiers front-end ne seront pas chargés si l'URL n'est pas disponible. + description: | + L'URL du CDN que vous donnez doit se référer à un miroir du répertoire /public , + tous les fichiers de ce répertoire seront chargés en tant que CDN.
+ Comment vérifier ? Vérifiez si {CDN URL}/app/manifest.json peut être accédé. +cache: + title: Configuration du cache + clear: Vider le cache + cleared: Le cache a été vidé. + driver: Current cache driver is 「:driver」. + enable_avatar_cache: + title: Avatar + label: Enable caching avatar + enable_preview_cache: + title: Aperçu de la texture + label: Activer le cache des texture de prévisualisation diff --git a/resources/lang/fr_FR/setup.yml b/resources/lang/fr_FR/setup.yml new file mode 100755 index 0000000..d0170df --- /dev/null +++ b/resources/lang/fr_FR/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "Impossible de se connecter à la base de données cible :type, veuillez vérifier votre configuration. Le serveur a répondu avec: :msg" +locked: + title: Déjà installé + text: Il semble que vous ayez déjà installé Blessing Skin Server. Pour le réinstaller, veuillez supprimer le fichier "install.lock" dans le répertoire "storage". + button: Retour à la page d'accueil +updates: + success: + title: Mise à jour terminée +wizard: + master: + title: Assistant d'installation - Blessing Skin Server + welcome: + title: Bienvenue + button: Suivant + text: Bienvenue sur Blessing Skin Server v:version ! + database: + title: Base de données + text: La base de données est utilisée pour stocker les données de Blessing Skin. + type: Type de base de données + host: Hôte de la base de données + port: Port de la base de données + username: Nom d'utilisateur de la base de données + password: Mot de passe de la base de données + db: Nom de la base de données + db-notice: Vous devez fournir le chemin d'accès au fichier SQLite et il n'est pas nécessaire de remplir les autres champs si vous utilisez SQLite. + prefix: Préfixe des tables dans la base de données (facultatif) + prefix-notice: Vous n'avez pas besoin d'utiliser cette option à moins que vous ne vouliez installer plusieurs Blessing Skin Server depuis une seule base de données. + info: + title: Information requise + button: Lancer l'installation + text: Pour procéder à l'installation, veuillez remplir ce formulaire avec les détails du compte administrateur initial. Ne vous inquiétez pas, vous pourrez toujours modifier ces paramètres plus tard. + admin-email: Adresse e-mail de l'administrateur + admin-notice: Ceci est le compte super-administrateur UNIQUE qui peut donner ou ANNULER les privilèges d'administration des autres utilisateurs. + nickname: Pseudonyme + password: Mot de passe + pwd-notice: 'Attention: Vous aurez besoin du mot de passe pour vous connecter.' + confirm-pwd: Confirmer le mot de passe + site-name: Nom du site + site-name-notice: Ceci sera affiché sur chaque page. + finish: + title: Installation terminée + text: Blessing Skin Server a été installé. Merci, et profitez-en ! diff --git a/resources/lang/fr_FR/skinlib.yml b/resources/lang/fr_FR/skinlib.yml new file mode 100755 index 0000000..82a7fcb --- /dev/null +++ b/resources/lang/fr_FR/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: Ajouter un nouveau skin +show: + title: Détails de la texture + deleted: La texture demandée a déjà été supprimée supprimée. + private: La texture demandée est privée et visible uniquement par le chargeur et les administrateurs. +upload: + title: Ajouter la texture + name-rule: Moins de 32 caractères et ne doit pas contenir de caractères spéciaux. + name-rule-regexp: Les règles de noms personnalisés sont appliquées en tant que :regexp + private-score-notice: It will spend you more scores for setting it as private. You will be charged :score scores for per KB storage. + invalid-size: Fichier :type invalide (largeur :width, hauteur :height) + invalid-hd-skin: Skin HD invalide (la largeur et la hauteur doivent être divisibles par 32) + lack-score: You don't have enough score to upload this texture. + repeated: La texture est déjà mis en ligne par quelqu'un d'autre. Vous pouvez l'ajouter directement à votre placard. + success: La texture :name a été ajouté avec succès. +delete: + success: La texture a été supprimée avec succès. +privacy: + success: La texture a été définie sur :privacy avec succès. +rename: + success: La texture a été renommée en :name avec succès. +model: + success: The texture's model was changed to :model successfully. +no-permission: Vous n'avez pas la permission de modérer cette texture. +non-existent: Cette texture n'existe pas. +report: + duplicate: Vous avez déjà signalé cette texture. Les administrateurs la vérifieront dès que possible. Vous pouvez également suivre l'état de votre signalement au Centre d'utilisateurs. + success: Merci pour votre signalement ! Les administrateurs vont le vérifier dès que possible. diff --git a/resources/lang/fr_FR/user.yml b/resources/lang/fr_FR/user.yml new file mode 100755 index 0000000..c3b90a5 --- /dev/null +++ b/resources/lang/fr_FR/user.yml @@ -0,0 +1,101 @@ +--- +sign-success: Signed successfully. You got :score scores. +announcement: Annonce +no-unread: Aucune nouvelle notification. +verification: + disabled: La vérification de l'adresse e-mail n'est pas disponible. + frequent-mail: Vous avez cliqué trop rapidement sur le bouton d'envoi. Patientez quelques minutes. + verified: Votre compte est déjà vérifié. + success: Le lien de vérification a été envoyé. Veuillez vérifier votre boîte de réception. + failed: 'Nous n''avons pas pu vous envoyer le lien de vérification. Info: :msg' + mail: + title: Vérifiez votre compte sur :sitename + message: Vous recevez cet e-mail parce que quelqu'un a créer un compte avec cette adresse e-mail sur :sitename. + reset: 'Cliquez ici pour vérifier votre compte : :url' + ignore: Si vous n'avez pas créé de compte, vous pouvez ignorer ce message. +score-intro: + title: Qu'est-ce que le score ? + introduction: | + We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually. + Either adding players, uplaoding textures or adding a skinlib item to your closet will consume scores. + :return-score + + New users will get :initial_score scores initially, and you can acquire :score-from ~ :score-to scores by daily signing in. + will-return-score: Le score sera remboursée si vous avez supprimé des joueurs, des textures ou des éléments de placard. + no-return-score: Le score ne sera PAS remboursée si vous avez supprimé des joueurs, des textures ou des éléments de placard. + rates: + storage: ':score scores = 1 KB storage' + player: ':score scores = 1 player' + closet: ':score socres = 1 closet item' +closet: + add: + success: ':name a été ajouté avec succès.' + repeated: Vous avez déjà ajouté cette texture. + not-found: Nous n'avons pas pu trouver cette texture. + lack-score: Vous n'avez pas assez de score pour l'ajouter dans votre placard. + rename: + success: L'élément a été renommé avec succès en :name + remove: + success: La texture a été retirée de l'armoire avec succès. + non-existent: La texture n'existe pas dans votre placard. +player: + login-notice: Vous pouvez maintenant vous connecter avec les noms de joueurs que vous possédez à la place de votre adresse e-mail. + player-name-rule: + official: Le nom du joueur ne peut contenir que des lettres, des chiffres et des tirets bas. + cjk: Le nom du joueur peut contenir des lettres, des chiffres, des tirets bas et des idéographes unifiés CJK. + utf8: Le nom du joueur doit être une chaîne UTF-8. + custom: Custom player name rules are applied on this site. Please contact admins for further information. + player-name-length: Le nom du joueur doit contenir au moins :min caractères et ne doit pas dépasser :max caractères. + add: + repeated: Ce nom d'utilisateur est déjà enregistré. + lack-score: You don't have enough score to add a player. + success: Le joueur :name a été ajouté avec succès. + delete: + success: Le joueur :name a été supprimé avec succès. + rename: + repeated: Ce pseudonyme est déjà utilisé. Veuillez en choisir un autre. + success: Le joueur :old a été renommé en :new + set: + success: La texture a été appliquée au joueur :name avec succès. + clear: + success: Les textures du joueur :name ont été réinitialisées avec succès. +profile: + avatar: + title: Changer d'avatar ? + notice: Click the gear icon "" of any skin in your closet, then click "Set as avatar". We will cut the head segment of that skin for you. If there is no icon like this, please try to disable your ADs blocking extension. + wrong-type: Vous ne pouvez pas utiliser une cape en tant qu'avatar. + success: Le nouvel avatar a été défini avec succès. + reset: Réinitialiser l'avatar + password: + title: Changer le mot de passe + old: Ancien mot de passe + new: Nouveau mot de passe + confirm: Répétez le mot de passe + button: Changer le mot de passe + wrong-password: Mot de passe d'origine incorrect. + success: Mot de passe mis à jour avec succès, veuillez vous reconnecter. + nickname: + title: Changer le pseudonyme + empty: Aucun pseudo n'a été défini. + success: Pseudo mis à jour avec succès à :nickname + email: + title: Changer l'adresse e-mail + new: Nouvelle adresse e-mail + password: Mot de passe actuel + button: Changer l'adresse e-mail + wrong-password: Mot de passe incorrect. + existed: Cette adresse e-mail est déjà enregistrée. + success: Adresse e-mail mise à jour avec succès, veuillez vous reconnecter. + delete: + title: Supprimer le compte + notice: Voulez-vous vraiment supprimer votre compte sur :site ? + admin: Le compte d'un administrateur ne peut pas être supprimé. + button: Supprimer mon compte + modal-title: Vous devez entrer votre mot de passe pour continuer + modal-notice: | + Vous êtes sur le point de supprimer votre compte. + Ceci est permanent ! Aucune restauration sera possible. + Vous êtes prévenu! + password: Mot de passe actuel + wrong-password: Mot de passe incorrect. + success: Votre compte a été supprimé avec succès. diff --git a/resources/lang/fr_FR/validation.yml b/resources/lang/fr_FR/validation.yml new file mode 100755 index 0000000..897da71 --- /dev/null +++ b/resources/lang/fr_FR/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: 'Le champ :attribute doit être accepté.' +active_url: 'Le champ :attribute n''est pas une URL valide.' +after: 'Le champ :attribute doit être une date postérieure au :date.' +after_or_equal: 'Le champ :attribute doit être une date postérieure ou égale au :date.' +alpha: 'Le champ :attribute doit contenir uniquement des lettres.' +alpha_dash: 'Le champ :attribute doit contenir uniquement des lettres, des chiffres et des tirets.' +alpha_num: 'Le champ :attribute doit contenir uniquement des chiffres et des lettres.' +array: 'Le champ :attribute doit être un tableau.' +before: 'Le champ :attribute doit être une date antérieure au :date.' +before_or_equal: 'Le champ :attribute doit être une date antérieure ou égale au :date.' +between: + numeric: 'La valeur de :attribute doit être comprise entre :min et :max.' + file: 'La taille du fichier de :attribute doit être comprise entre :min et :max kilo-octets.' + string: 'Le texte :attribute doit contenir entre :min et :max caractères.' + array: 'Le tableau :attribute doit contenir entre :min et :max éléments.' +boolean: 'Le champ :attribute doit être vrai ou faux.' +captcha: 'Captcha incorrect.' +confirmed: 'Le champ de confirmation :attribute ne correspond pas.' +date: 'Le champ :attribute n''est pas une date valide.' +date_equals: 'Le champ :attribute doit être une date égale à :date.' +date_format: 'Le champ :attribute ne correspond pas au format :format.' +different: 'Les champs :attribute et :other doivent être différents.' +digits: 'Le champ :attribute doit contenir :digits chiffres.' +digits_between: 'Le champ :attribute doit contenir entre :min et :max chiffres.' +dimensions: 'La taille de l''image :attribute n''est pas conforme.' +distinct: 'Le champ :attribute a une valeur en double.' +email: 'Le champ :attribute doit être une adresse email valide.' +ends_with: 'Le champ :attribute doit se terminer par une des valeurs suivantes : :values' +exists: 'Le champ :attribute sélectionné est invalide.' +file: 'Le champ :attribute doit être un fichier.' +filled: 'Le champ :attribute doit avoir une valeur.' +gt: + numeric: 'La valeur de :attribute doit être supérieure à :value.' + file: 'La taille du fichier de :attribute doit être supérieure à :value kilo-octets.' + string: 'Le texte :attribute doit contenir plus de :value caractères.' + array: 'Le tableau :attribute doit contenir plus de :value éléments.' +gte: + numeric: 'La valeur de :attribute doit être supérieure ou égale à :value.' + file: 'La taille du fichier de :attribute doit être supérieure ou égale à :value kilo-octets.' + string: 'Le texte :attribute doit contenir au moins :value caractères.' + array: 'Le tableau :attribute doit contenir au moins :value éléments.' +image: 'Le champ :attribute doit être une image.' +in: 'Le champ :attribute est invalide.' +in_array: 'Le champ :attribute n''existe pas dans :other.' +integer: 'Le champ :attribute doit être un entier.' +ip: 'Le champ :attribute doit être une adresse IP valide.' +ipv4: 'Le champ :attribute doit être une adresse IPv4 valide.' +ipv6: 'Le champ :attribute doit être une adresse IPv6 valide.' +json: 'Le champ :attribute doit être un document JSON valide.' +lt: + numeric: 'La valeur de :attribute doit être inférieure à :value.' + file: 'La taille du fichier de :attribute doit être inférieure à :value kilo-octets.' + string: 'Le texte :attribute doit contenir moins de :value caractères.' + array: 'Le tableau :attribute doit contenir moins de :value éléments.' +lte: + numeric: 'La valeur de :attribute doit être inférieure ou égale à :value.' + file: 'La taille du fichier de :attribute doit être inférieure ou égale à :value kilo-octets.' + string: 'Le texte :attribute doit contenir au plus :value caractères.' + array: 'Le tableau :attribute doit contenir au plus :value éléments.' +max: + numeric: 'La valeur de :attribute ne peut être supérieure à :max.' + file: 'La taille du fichier de :attribute ne peut pas dépasser :max kilo-octets.' + string: 'Le texte de :attribute ne peut contenir plus de :max caractères.' + array: 'Le tableau :attribute ne peut contenir plus de :max éléments.' +mimes: 'Le champ :attribute doit être un fichier de type : :values.' +mimetypes: 'Le champ :attribute doit être un fichier de type : :values.' +min: + numeric: 'La valeur de :attribute doit être supérieure ou égale à :min.' + file: 'La taille du fichier de :attribute doit être supérieure à :min kilo-octets.' + string: 'Le texte :attribute doit contenir au moins :min caractères.' + array: 'Le tableau :attribute doit contenir au moins :min éléments.' +not_in: 'Le champ :attribute sélectionné n''est pas valide.' +not_regex: 'Le format du champ :attribute n''est pas valide.' +numeric: 'Le champ :attribute doit contenir un nombre.' +password: Le mot de passe est incorrect +present: 'Le champ :attribute doit être présent.' +recaptcha: 'la verification reCAPTCHA a échoué.' +regex: 'Le format du champ :attribute est invalide.' +required: 'Le champ :attribute est obligatoire.' +required_if: 'Le champ :attribute est obligatoire quand la valeur de :other est :value.' +required_unless: 'Le champ :attribute est obligatoire sauf si :other est :values.' +required_with: 'Le champ :attribute est obligatoire quand :values est présent.' +required_with_all: 'Le champ :attribute est obligatoire quand :values sont présents.' +required_without: 'Le champ :attribute est obligatoire quand :values n''est pas présent.' +required_without_all: 'Le champ :attribute est requis quand aucun de :values n''est présent.' +same: 'Les champs :attribute et :other doivent être identiques.' +size: + numeric: 'La valeur de :attribute doit être :size.' + file: 'La taille du fichier de :attribute doit être de :size kilo-octets.' + string: 'Le texte de :attribute doit contenir :size caractères.' + array: 'Le tableau :attribute doit contenir :size éléments.' +starts_with: 'Le champ :attribute doit commencer avec une des valeurs suivantes : :values' +string: 'Le champ :attribute doit être une chaîne de caractères.' +timezone: 'Le champ :attribute doit être un fuseau horaire valide.' +unique: 'La valeur du champ :attribute est déjà utilisée.' +uploaded: 'Le fichier du champ :attribute n''a pu être téléversé.' +url: 'Le format de l''URL de :attribute n''est pas valide.' +uuid: 'Le champ :attribute doit être un UUID valide' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: nom + player_name: nom d'utilisateur + identification: adresse e-mail ou nom d'utilisateur + email: adresse email + password: mot de passe + password_confirmation: 'confirmation du mot de passe' + title: titre + content: contenu diff --git a/resources/lang/it_IT/admin.yml b/resources/lang/it_IT/admin.yml new file mode 100755 index 0000000..5cd4d2d --- /dev/null +++ b/resources/lang/it_IT/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: Registered Users + total-players: Players + total-textures: Uploaded Textures + disk-usage: Disk Usage + overview: Overview + texture-uploads: Texture Uploads + user-registration: User Registration +notifications: + send: + title: Send Notification + success: Sent successfully! + receiver: + title: Receiver + all: All Users + normal: Normal Users + uid: Specified UID + email: Specified Email + title: Title + content: Content (Markdown is supported.) +users: + operations: + non-existent: No such user. + no-permission: You have no permission to operate this user. + email: + success: Email changed successfully. + verification: + success: Account verification status toggled successfully. + nickname: + success: Nickname changed successfully. + password: + success: Password changed successfully. + score: + success: Score changed successfully. + permission: Permission updated. + delete: + success: The account has been deleted successfully. +players: + no-permission: You have no permission to operate this player. + textures: + non-existent: No such texture tid.:tid + success: The textures of :player has been updated. + name: + success: Player name has been updated to :player + owner: + success: The player :player was transferred to user :user. + delete: + success: The player has been deleted successfully. +customize: + change-color: + title: Change Theme Color + colors: + navbar: Top Navigation Bar + sidebar: + dark: Sidebar (Dark) + light: Sidebar (Light) +i18n: + add: Add New Language Line + added: Language line added. + updated: Language line updated. + deleted: Language line deleted. + group: Group + key: Key + text: Text + tip: How can I use this page? +status: + info: Information + health: Health + bs: + name: Blessing Skin + version: Version + env: Application Environment + debug: Debugging or Not? + commit: Commit + laravel: Laravel Version + server: + name: Server + php: PHP Version + web: Web Server Software + os: OS + db: + name: Database + type: Server + host: Host + port: Port + username: Username + database: Database + prefix: Table Prefix + plugins: Enabled Plugins (:amount) +plugins: + readme: Read Me + operations: + title: Operations + enabled: ':plugin has been enabled.' + unsatisfied: + notice: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't enable it. Please install or update the plugins listed below, and disable those have conflicts. + disabled: 'The ":name" plugin is not enabled.' + version: 'The version of ":title" does not satisfies the constraint ":constraint".' + conflict: 'The ":title" plugin cannot run with this plugin at the same time.' + disabled: ':plugin has been disabled.' + deleted: The plugin was deleted successfully. + no-config-notice: The plugin is not installed or doesn't provide a configuration page. + no-readme-notice: The plugin doesn't contain a readme file. + not-found: No such plugin. + market: + unresolved: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't download it. Please install or update the plugins listed below, and disable those have conflicts. + connection-error: Unable to connect to the plugins registry. :error + non-existent: The plugin :plugin does not exist. + install-success: Plugin was installed. +update: + complete: Update completed + info: + title: Update Information + up-to-date: Already up-to-date. + available: New version available. + versions: + latest: "Latest Version:" + current: "Current Version:" + check-github: Check GitHub Releases + button: Update Now + cautions: + title: Cautions + link: check out this. + text: | + Please choose update source according to your host's network environment. + Low-speed connection between update source and your host will cause long-time loading at checking and downloading page. + To change the default update source, + errors: + connection: "Unable to access to current update source. Details: :error" + spec: Current update source is not supported. + php: Your PHP version is too low to update. Requires :version or later. +download: + errors: + download: 'Failed to download. Error: :error' + shasum: File validation failed. Please download again. + unzip: Failed to unpack files. +invalid-action: Invalid action diff --git a/resources/lang/it_IT/auth.yml b/resources/lang/it_IT/auth.yml new file mode 100755 index 0000000..99d54ee --- /dev/null +++ b/resources/lang/it_IT/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: Log In + message: Log in to manage your skin & players + success: Logged in successfully. +check: + anonymous: Illegal access. Please log in first. + verified: To access this page, you should verify your email address first. + admin: Only admins are permitted to access this page. + banned: You are banned on this site. Please contact the admin. +register: + title: Register + message: Welcome to :sitename! + success: Your account was registered. Redirecting... + max: You can't register more than :regs accounts. +forgot: + title: Forgot Password + message: We will send you an E-mail to verify. + disabled: Password resetting is not available. + frequent-mail: You click the send button too fast. Wait for some minutes. + unregistered: The email address is not registered. + success: Mail sent, please check your inbox. The link will be expired in 1 hour. + failed: Failed to send verification mail. :msg + ignore: If you haven't signed up on our site, please ignore this email. No unsubscribing is required. + reset: Reset your password + notice: This mail is sending automatically, no reponses will be sent if you reply. + mail: + title: Reset your password on :sitename + message: You are receiving this email because we received a password reset request for your account on :sitename. + reset: 'To reset your password, please visit: :url' + ignore: If you did not request a password reset, no further action is required. +reset: + title: Reset Password + button: Reset + invalid: Invalid link. + expired: This link is expired. + message: ':username, reset your password here.' + success: Password resetted successfully. +bind: + title: Bind Email + button: Bind + message: You need to provide your email adderss to continue. + introduction: We won't send you any spam. + registered: The email address was already taken. +verify: + title: Email Verification + invalid: Invalid link. + not-matched: Email doesn't match. +validation: + user: No such user. + password: Wrong password. +logout: + success: You are now logged out. +oauth: + authorization: + title: Authorization + introduction: A 3rd-party application ":name" is requesting permission to access your account. + button: Authorize + permissions: Permissions + scope: + user: + read: Sign you in and read your profile + notification: + read: Allows the app to read your notifications. + readwrite: Allows the app to send notifications. + player: + read: Allows the app to read your players. + readwrite: Allows the app to create, read, update and delete your players. + closet: + read: Allows the app to read your closet items. + readwrite: Allows the app to create, read, update and delete your closet items. + users-management: + read: Allows the app to read site's users. + readwrite: Allows the app to create, read, update and delete site's users. + players-management: + read: Allows the app to read site's players. + readwrite: Allows the app to create, read, update and delete site's players. + closet-management: + read: Allows the app to read user's of your site closet items. + readwrite: Allows the app to create, read, update and delete user's closet items. + reports-management: + read: Allows the app to read user's reports. + readwrite: Allows the app to read and review user's reports. +email: Email +register-link: Register a new account diff --git a/resources/lang/it_IT/errors.yml b/resources/lang/it_IT/errors.yml new file mode 100755 index 0000000..2bc388c --- /dev/null +++ b/resources/lang/it_IT/errors.yml @@ -0,0 +1,19 @@ +--- +http: + msg-403: You have no permission to access this page. + msg-404: Nothing here. + msg-500: Please try again later. + msg-503: The application is now in maintenance mode. + method-not-allowed: Method not allowed. + csrf-token-mismatch: Token does not match, try reloading the page. + ie: Your browser isn't supported. Please switch to other modern browsers, such as Firefox or Chrome. +general: + title: Error occurred +exception: + code: 'Error code: :code' + detail: 'Details: :msg' + message: | + Whoops, looks like something went wrong. (enable APP_DEBUG in .env to see details) +plugins: + duplicate: The plugin [:dir1] has a duplicated plugin name definition which is same to plugin [:dir2]. Please check your plugins directory, remove one of them or use another name definition. + boot: There is something wrong with plugin ":plugin". diff --git a/resources/lang/it_IT/front-end.yml b/resources/lang/it_IT/front-end.yml new file mode 100755 index 0000000..0438480 --- /dev/null +++ b/resources/lang/it_IT/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: Log In + loggingIn: Logging In + tooManyFails: + captcha: You fails too many times! Please enter the CAPTCHA. + recaptcha: You fails too many times! Please pass the reCAPTCHA challenge. + emptyEmail: Empty email address. + invalidConfirmPwd: Confirming password is not equal with password. + emptyNickname: Empty nickname. + register: Register + registering: Registering + send: Send + sending: Sending + reset: Reset + resetting: Resetting + nickname: Nickname + player-name: Minecraft player name + email: Email + identification: Email or player name + password: Password + captcha: CAPTCHA + change-captcha: Click to change CAPTCHA image. + login-link: Already registered? Log in here. + forgot-link: Forgot password? + keep: Remember me + repeat-pwd: Repeat your password + nickname-intro: Whatever you like expect special characters + player-name-intro: Player name in Minecraft, can be changed later + forgot: + login-link: I do remember it +skinlib: + private: Private + anonymous: Please login first. + reset: Reset Filter + addToCloset: Add to closet + removeFromCloset: Remove from closet + setItemName: Set a name for this texture + applyNotice: You can apply it to player at your closet + emptyItemName: Empty texture name. + setNewTextureName: 'Please enter the new texture name:' + emptyNewTextureName: Empty new texture name. + seeMyUpload: My Uploads + apply: Apply + filter: + skin: (Any Model) + steve: (Steve) + alex: (Alex) + cape: (Cape) + uploader: 'User (UID = :uid) Uploaded' + allUsers: All Users + sort: + title: Sort + time: Latest + likes: Most Likes + emptyTextureName: Empty texture name. + emptyUploadFile: You have not uploaded any file. + fileExtError: 'Error: Textures should be PNG files.' + uploading: Uploading + setAsPrivate: Set as Private + setAsPublic: Set as Public + setPublicNotice: Sure to set this as public texture? + setPrivateNotice: Sure to set this as private texture? + deleteNotice: Are you sure to delete this texture? + setNewTextureModel: "Please select a new texture model:" + upload: + texture-name: Texture Name + texture-type: Texture Type + select-file: Select File + privacy-notice: Prevent it from being visible at skin library. + set-as-private: Make it Private + button: Upload + cost: It costs you about :score score. + award: You'll be awarded :score score(s) by uploading public texture. + show: + anonymous: You must login to use closets + likes: People who like this + detail: Details + name: Texture Name + edit: Edit + model: Applicable Model + size: File Size + uploader: Uploader + upload-at: Upload At + download: Download + delete-texture: Delete Texture + manage-notice: The texture which was deleted or setted to private will be removed from the closet of everyone who had favorited it. + report: + title: Report + reason: Tell us reason please. + positive: To encourage positive contributions to the skinlib, we will reward who reported inappropriate content with :score scores. However, if any malicious reporting behaviors were found, all scores rewarded will be taken back. + negative: To mitigate the impact of malicious reports, we will require :score scores for submitting a texture report. Don't worry. The suspended scores and additional reward will be sent to your account after your report reviewed by administrators. +user: + signRemainingTime: 'Available after :time :unit' + timeUnitHour: h + timeUnitMin: min + emptyClosetMsg: >- +

Nothing in your closet...

Why not explore the Skin Library for a while?

+ renameItem: Rename item + removeItem: Remove from closet + setAsAvatar: Set as avatar + viewInSkinlib: View in skin library + switch2dPreview: Switch to 2D Preview + switch3dPreview: Switch to 3D Preview + removeFromClosetNotice: Sure to remove this texture from your closet? + emptySelectedTexture: No texture is selected. + renameClosetItem: 'Set a new name for this item:' + changePlayerName: 'Please enter the player name:' + emptyPlayerName: Empty player name. + deletePlayer: Sure to delete this player? + deletePlayerNotice: It's permanent. No backups. + chooseClearTexture: Choose texture types you want to clear + noClearChoice: You haven't choose any types + setAvatar: Sure to set this as your avatar? + setAvatarNotice: The head segment of skin will bu used. + resetAvatarConfirm: Are you sure to reset your avatar? + typeToSearch: Type to search + useAs: Apply... + resetSelected: Clear selected + closet: + upload: Upload Texture + use-as: + title: Which player should be applied to? + empty: It seems that you own no player... + used: + title: Resources Used + players: Registered players + storage: Storage used + cur-score: Current Score + score-notice: Click the score to show introduction. + sign: Sign + player: + operation: Operations + edit-pname: Edit Name + delete-texture: Clear Textures + delete-player: Delete + add-player: Add new player + texture-empty: Nothing + verification: + title: Verify Your Account + message: You must verify your email address before using the skin hosting service. Haven't received the email? + resend: Click here to send again. + sending: Sending... + oauth: + id: Client ID + name: App Name + secret: Client Secret + redirect: Callback URL + modifyName: Modify app name. + modifyUrl: Modify callback URL. + create: Create New App + confirmRemove: Are you sure to delete this app? You won't be able to undo this. +admin: + operationsTitle: Operations + permission: Permission + deleteUser: Delete + changeEmail: Edit Email + newUserEmail: 'Please enter the new email:' + verification: Email Verification + toggleVerification: Toggle Verification Status + changeNickName: Edit Nickname + newUserNickname: 'Please enter the new nickname:' + changePassword: Edit Password + newUserPassword: 'Please enter the new password:' + changeScore: Edit Score + newScore: 'Please enter the new score:' + changePermission: Change permission + newPermission: 'Please select new permission:' + deleteUserNotice: Are you sure to delete this user? It' permanent. + banned: Banned + normal: Normal + admin: Admin + superAdmin: Super Admin + unverified: Unverified + verified: Verified + pidNotice: >- + Please enter the tid of texture. Inputing 0 can clear texture of this player. + changeTexture: Change Textures + changePlayerName: Change Player Name + changeOwner: Change Owner + textureType: Texture Type + deletePlayer: Delete + changePlayerOwner: 'Please enter the id of user which this player should be transferred to:' + deletePlayerNotice: Are you sure to delete this player? It' permanent. + changePlayerNameNotice: 'Please input new player name:' + emptyPlayerName: Player name cannot be empty. + configurePlugin: Configure + deletePlugin: Delete + noDependencies: No Dependencies + pluginTitle: Plugin + pluginAuthor: Author + pluginVersion: Version + pluginReadme: Read Me + pluginDescription: Description + pluginDependencies: Dependencies + installPlugin: Install + pluginInstalling: Installing... + updatePlugin: Update + pluginUpdating: Updating... + confirmUpdate: Are you sure to update ":plugin" from :old to :new? + enablePlugin: Enable + disablePlugin: Disable + confirmDeletion: Are you sure to delete this plugin? + uploadArchive: Upload Archive + uploadArchiveNotice: Install a plugin by uploading a Zip archive. + downloadRemote: Download From Remote + downloadRemoteNotice: Install a plugin by downloading a Zip archive from remote URL. + updateButton: Update Now + downloading: Downloading... + i18n: + group: Group + key: Key + text: Text + empty: (Empty) + modify: Modify + delete: Delete + updating: 'Please type new text:' + confirmDelete: Are you sure? This is irreversible. +report: + tid: Texture ID + reporter: Reporter + reason: Reason + status-title: Status + status: + - Pending + - Resolved + - Rejected + time: Report Time + delete: Delete + ban: Ban + reject: Reject +general: + skin: Skin + cape: Cape + fatalError: Fatal Error + confirmLogout: Sure to log out? + confirm: OK + cancel: Cancel + submit: Submit + close: Close + more: More + tip: Tip + noResult: No result. + texturePreview: Texture Preview + walk: Walk + run: Run + rotation: Rotation + pause: Pause + reset: Reset + skinlib: Skin Library + wait: Please wait... + csrf: This page is out-dated. Please refresh it. + user: + email: Email + nickname: Nick Name + score: Score + register-at: Registered At + player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified +colors: + black: Black + white: White + gray: Gray + prev: Previous Background + next: Next Background +vendor: + datatable: + search: Search + prev: Prev + next: Next diff --git a/resources/lang/it_IT/general.yml b/resources/lang/it_IT/general.yml new file mode 100755 index 0000000..1fe8c6a --- /dev/null +++ b/resources/lang/it_IT/general.yml @@ -0,0 +1,59 @@ +--- +index: Homepage +skinlib: Skin Library +user-center: User Center +logout: Log Out +login: Log In +register: Register Now +profile: User Profile +admin-panel: Admin Panel +explore: Explore +manage: Manage +anonymous: Guest +back: Back +dashboard: Dashboard +my-closet: Closet +my-reports: Reports +developer: Advanced +oauth-manage: OAuth2 Apps +player-manage: Players +user-manage: Users +report-manage: Reports +plugin-manage: Plugins +plugin-market: Plugin Market +plugin-configs: Plugin Configs +customize: Customize +i18n: Internationalization +options: Options +score-options: Score Options +res-options: Resource Options +status: Status +check-update: Check Update +download-update: Download Updates +close: Close +skin: Skin +cape: Cape +submit: Submit +cancel: Cancel +yes: true +no: false +op-success: Operated successfully. +unknown: Unknown +notice: Notice +illegal-parameters: Illegal parameters. +private: Private +public: Public +unexistent-user: No such user. +player-banned: The owner of this player has been banned. +texture-deleted: The requested texture has been deleted. +user: + email: Email + nickname: Nickname + password: Password + score: Score + register-at: Registered At +player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified diff --git a/resources/lang/it_IT/index.yml b/resources/lang/it_IT/index.yml new file mode 100755 index 0000000..bba2e21 --- /dev/null +++ b/resources/lang/it_IT/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: Features + first: + icon: fa-users + name: Multi Player + desc: You can add multiple players within one registered account. + second: + icon: fa-share-alt + name: Sharing + desc: Explore the skin library, send a "like" and share them with your friends. + third: + icon: fa-cloud + name: Free + desc: It is free forever. No ads. No subscription fees. +introduction: ':sitename provides the service of uploading and hosting Minecraft skins. By coordinating with skin mods (e.g. CustomSkinLoader), you can choose skin and cape for your game character, and make it visible to other players in Minecraft.' +start: Join Us diff --git a/resources/lang/it_IT/options.yml b/resources/lang/it_IT/options.yml new file mode 100755 index 0000000..76c6421 --- /dev/null +++ b/resources/lang/it_IT/options.yml @@ -0,0 +1,180 @@ +--- +option-saved: Option saved. +homepage: + title: Homepage + home_pic_url: + title: Picture URL at Homepage + hint: Path relative to homepage or full URL, leave empty to use default image. + favicon_url: + title: Website Icon + hint: Path relative to public/ or full URL. + description: The given image must have same width and height (leave blank to use default icon). + transparent_navbar: + title: Transparent Navigation Bar + label: This will enable transparent navigation bar of home page, but it will turn to be normal if page is scrolled to bottom. + hide_intro: + title: Hide Introduction at Bottom + label: Scroll bar will be disabled if this option is enabled, as version 2.x. + fixed_bg: + title: Fixed Background + label: This option will make background fixed, not scrolled with scroll bar. + copyright_prefer: + title: Program Copyright + description: "You can specify a different style of program copyright for each language. To edit a specific language's corresponding program copyright style, please switch to that language and submit your edit.
Warning: Any evil modification applied on the footer program copyright (including deleting, modifying author, changing link target) with out permission is FORBIDDEN. The author reserves the right to pursue relevant responsibilities." + copyright_text: + title: Custom Copyright Text + description: Placeholders are available in custom copyright text. e.g. {site_name} & {site_url}. You can also specify a different footer for each language. To edit a specific language's corresponding footer, please switch to that language and submit your edit. +customJsCss: + title: Custom CSS/JavaScript + message: | + The contents will be attached to <style> and <script> tags.
+ - Here are some useful examples: Examples of Custom CSS & JavaScript + custom_css: CSS + custom_js: JavaScript +rate: + title: Scores + score_per_storage: + title: Storage + addon: scores = 1 KB + private_score_per_storage: + title: Private Storage + addon: scores = 1 KB + hint: Uploading private textures will cost more scores. + score_per_closet_item: + title: Favorites + addon: score = 1 closet item + return_score: + title: Score Return + label: Return scores back to user after deleting players/textures/closet items. + score_per_player: + title: Players + addon: scores = 1 player + user_initial_score: User Initial Score +report: + title: Reporting Textures + reporter_score_modification: + title: Scores for Submitting an Report + description: Set a positive integer value to reward user who submits new reports. Set to a negative value will require scores for submitting reports, and the suspended scores will be available if user's report was resolved. Set to 0 to disable. + reporter_reward_score: + title: Reward the Reporter with Scores If Report Resolved +sign: + title: Signing + sign_score: + title: Score Granted + addon1: scores ~ + addon2: scores + sign_gap_time: + title: Gap Time + addon: hours + sign_after_zero: + title: Time + label: Users can sign in after 0 everyday. + hint: The above option will be ignored if this is checked. +sharing: + title: Awarding Sharing + score_award_per_texture: + title: Uploader will be rewarded for each uploading texture with + take_back_scores_after_deletion: + title: Return scores + label: Return scores if uploader setting private or deleting texture. + score_award_per_like: + title: Each time the texture is collected, uploader will be rewarded with +general: + title: General Options + site_name: Site Name + site_description: + title: Site Description + description: You can also specify a different site name and description for each language. To edit a specific language's corresponding site name or description text, please switch to that language and submit your edit. + site_url: + title: Site URL + hint: Begin with http(s)://, nerver ends with slash. + register_with_player_name: + title: Register with Player Name + label: Require Minecraft's player name when user register + require_verification: + title: Account Verification + label: Users must verify their email address first. + regs_per_ip: Max accounts of one IP + max_upload_file_size: + title: Max Upload Size + hint: "Limit specified in php.ini: :size" + player_name_rule: + title: Player Name Rule + official: Letters, numbers and underscores (Mojang's official rule) + cjk: Allow CJK Unified Ideographs + utf8: Allow all valid UTF-8 characters (excluding whitespaces) + custom: Use custom rules (regular expression) + custom_player_name_regexp: + title: Custom Player Name Rules + hint: Only takes effect when the above option is set to 'custom'. Leave empty to allow any character. + placeholder: Regular Expressions + player_name_length: + title: Player Name Length + suffix: characters + auto_del_invalid_texture: + title: Invalid Textures + label: Delete invalid textures automatically. + hint: Delete textures records whose file no longer exists from skinlib. + allow_downloading_texture: + title: Downloading Textures + label: Allow users to directly download the source file of a skinlib item. + status_code_for_private: + title: HTTP Code for Rejecting Accessing Private Textures + texture_name_regexp: + title: Texture Name Rules + hint: The RegExp for validating name of uploaded textures. Leave empty to allow any character except single, double quote and backslash. + placeholder: Regular Expressions + content_policy: + title: Content Policy + description: Display content policy at texture uploading page, supporting Markdown. To edit a specific language's corresponding content policy, please switch to that language and submit your edit. +announ: + title: Announcement + announcement: + description: Styling with Markdown is supported. You can also specify a different announcement for each language. To edit a specific language's corresponding announcement, please switch to that language and submit your edit. +meta: + title: SEO tags + meta_keywords: + title: Keywords + hint: Split with commas. + meta_description: + title: Description + hint: Description defined in "general options" will be used if you left it empty. + meta_extras: + title: Other Custom Tags +recaptcha: + recaptcha_invisible: + title: Invisible + label: Enable Invisible Mode +res-warning: This page is ONLY for advanced users. If you aren't familiar with these, please don't modify them! +resources: + title: Resource Files + hint: Please check these options if you enabled CDN for your site. + force_ssl: + title: Force SSL + label: Use HTTPS protocol to load all front-end assets. + hint: Please check if SSL really available before turning on. + auto_detect_asset_url: + title: Assets URL + label: Determine assets url automatically. + description: Please unable this if assets URLs are wrongly generated under a CDN. The site url will be used if this is not enabled. + cache_expire_time: + title: Cache Exipre Time + hint: In seconds, 86400 = one day, 31536000 = one year. + cdn_address: + title: Front-end Assets CDN + hint: Front-end files won't be loaded if URL is unavailable. + description: | + The CDN URL you give must refer to a mirror of /public directory, + all the files of that directory will be loaded as CDN.
+ How to verify? Verify if {Your CDN URL}/app/manifest.json can be accessed. +cache: + title: Cache Configuration + clear: Clear Cache + cleared: Cache has been cleared. + driver: Current cache driver is 「:driver」. + enable_avatar_cache: + title: Avatar + label: Enable caching avatar + enable_preview_cache: + title: Texture Preivew + label: Enable caching texture preivew diff --git a/resources/lang/it_IT/setup.yml b/resources/lang/it_IT/setup.yml new file mode 100755 index 0000000..dff74a3 --- /dev/null +++ b/resources/lang/it_IT/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "Unable to connect to the target :type database, please check your configuration. The server replied with: :msg" +locked: + title: Already installed + text: It appears that you have already installed Blessing Skin Server. To reinstall, please delete the "install.lock" file under "storage" directory. + button: Back to homepage +updates: + success: + title: Update complete +wizard: + master: + title: Install Wizard - Blessing Skin Server + welcome: + title: Welcome + button: Next + text: Welcome to Blessing Skin Server v:version! + database: + title: Database + text: The database is used for storing data of Blessing Skin. + type: Database Type + host: Database Host + port: Database Port + username: Database Username + password: Database Password + db: Database Name + db-notice: You should provide the path to SQLite file and there is no need to fill other blanks if you use SQLite. + prefix: Prefix of Database Table (Optional) + prefix-notice: You don't need to use this option unless you want to install multiple Blessing Skin Server into one database. + info: + title: Information needed + button: Run install + text: To proceed with the installation, please fill this form with the details of the initial admin account. Don't worry, you can always change these settings later. + admin-email: Admin Email + admin-notice: This is the UNIQUE super admin account who can GIVE or CANCEL other users' admin privilege. + nickname: Nickname + password: Password + pwd-notice: 'Attention: You will need the password to log in. Please keep it at a secure place.' + confirm-pwd: Confirm password + site-name: Site name + site-name-notice: This will be shown on every page. + finish: + title: Installation complete + text: Blessing Skin Server has been installed. Thank you, and enjoy! diff --git a/resources/lang/it_IT/skinlib.yml b/resources/lang/it_IT/skinlib.yml new file mode 100755 index 0000000..2fc935a --- /dev/null +++ b/resources/lang/it_IT/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: Upload new skin +show: + title: Texture Details + deleted: The requested texture was already deleted. + private: The requested texture is private and only visible to the uploader and admins. +upload: + title: Upload Texture + name-rule: Less than 32 characters and must not contain any special one. + name-rule-regexp: Custom name rules are applied as :regexp + private-score-notice: It will spend you more scores for setting it as private. You will be charged :score scores for per KB storage. + invalid-size: Invalid :type file (width :width, height :height) + invalid-hd-skin: Invalid HD skin (width and height should be divisible by 32) + lack-score: You don't have enough score to upload this texture. + repeated: The texture is already uploaded by someone else. You can add it to your closet directly. + success: Texture :name was uploaded successfully. +delete: + success: The texture was deleted successfully. +privacy: + success: The texture was set to :privacy successfully. +rename: + success: The texture was renamed to :name successfully. +model: + success: The texture's model was changed to :model successfully. +no-permission: You have no permission to moderate this texture. +non-existent: No such texture. +report: + duplicate: You have already reported this texture. The administrators will review it as soon as possible. You can also track the status of your report at User Center. + success: Thanks for reporting! The administrators will review it as soon as possible. diff --git a/resources/lang/it_IT/user.yml b/resources/lang/it_IT/user.yml new file mode 100755 index 0000000..cff23be --- /dev/null +++ b/resources/lang/it_IT/user.yml @@ -0,0 +1,101 @@ +--- +sign-success: Signed successfully. You got :score scores. +announcement: Announcement +no-unread: No new notifications. +verification: + disabled: Email verification is not available. + frequent-mail: You click the send button too fast. Wait for 60 secs, guy. + verified: Your account is already verified. + success: Verification link was sent, please check your inbox. + failed: We failed to send you the verification link. Detailed message :msg + mail: + title: Verify Your Account on :sitename + message: You are receiving this email because someone registered an account with this email address on :sitename. + reset: 'Click here to verify your account: :url' + ignore: If you did not register an account, no further action is required. +score-intro: + title: What is score? + introduction: | + We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually. + Either adding players, uplaoding textures or adding a skinlib item to your closet will consume scores. + :return-score + + New users will get :initial_score scores initially, and you can acquire :score-from ~ :score-to scores by daily signing in. + will-return-score: The score will be returned if you deleted players, uploaded textures or closet items. + no-return-score: The score will NOT be returned if you deleted players, uploaded textures or closet items. + rates: + storage: ':score scores = 1 KB storage' + player: ':score scores = 1 player' + closet: ':score socres = 1 closet item' +closet: + add: + success: Added :name to closet successfully. + repeated: You have already added this texture. + not-found: We cannot find this texture. + lack-score: You don't have enough score to add it to closet. + rename: + success: The item is successfully renamed to :name + remove: + success: The texture was removed from closet successfully. + non-existent: The texture does not exist in your closet. +player: + login-notice: Now you can log in with player names you owned instead email address. + player-name-rule: + official: Player name may only contains letters, numbers and underscores. + cjk: Player name may contains letters, numbers, underscores and CJK Unified Ideographs. + utf8: Player name must be a UTF-8 string. + custom: Custom player name rules are applied on this site. Please contact admins for further information. + player-name-length: The player name should be at least :min characters and not greater than :max characters. + add: + repeated: The player name is already registered. + lack-score: You don't have enough score to add a player. + success: Player :name was added successfully. + delete: + success: Player :name was deleted successfully. + rename: + repeated: This player name is occupied. Please choose another one. + success: Player :old was renamed to :new + set: + success: The texture was applied to player :name successfully. + clear: + success: The textures of player :name was resetted successfully. +profile: + avatar: + title: Change Avatar? + notice: Click the gear icon "" of any skin in your closet, then click "Set as avatar". We will cut the head segment of that skin for you. If there is no icon like this, please try to disable your ADs blocking extension. + wrong-type: You can't set a cape as avatar. + success: New avatar was set successfully. + reset: Reset Avatar + password: + title: Change Password + old: Old Password + new: New Password + confirm: Repeat Password + button: Change password + wrong-password: Wrong original password. + success: Password updated successfully, please log in again. + nickname: + title: Change Nickname + empty: No nickname is set now. + success: Nickname is successfully updated to :nickname + email: + title: Change Email + new: New Email + password: Current Password + button: Change email + wrong-password: Wrong password. + existed: This email address is occupied. + success: Email address updated successfully, please log in again. + delete: + title: Delete Account + notice: Sure to delete your account on :site? + admin: Admin account can not be deleted. + button: Delete my account + modal-title: You need to enter your password to continue + modal-notice: | + You're about to delete your account. + This is permanent! No backups, no restores, no magic undo button. + We warned you, ok? + password: Current Password + wrong-password: Wrong password. + success: Your account is deleted successfully. diff --git a/resources/lang/it_IT/validation.yml b/resources/lang/it_IT/validation.yml new file mode 100755 index 0000000..58a423e --- /dev/null +++ b/resources/lang/it_IT/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: 'The :attribute must be accepted.' +active_url: 'The :attribute is not a valid URL.' +after: 'The :attribute must be a date after :date.' +after_or_equal: 'The :attribute must be a date after or equal to :date.' +alpha: 'The :attribute may only contain letters.' +alpha_dash: 'The :attribute may only contain letters, numbers, dashes and underscores.' +alpha_num: 'The :attribute may only contain letters and numbers.' +array: 'The :attribute must be an array.' +before: 'The :attribute must be a date before :date.' +before_or_equal: 'The :attribute must be a date before or equal to :date.' +between: + numeric: 'The :attribute must be between :min and :max.' + file: 'The :attribute must be between :min and :max kilobytes.' + string: 'The :attribute must be between :min and :max characters.' + array: 'The :attribute must have between :min and :max items.' +boolean: 'The :attribute field must be true or false.' +captcha: 'Incorrect captcha.' +confirmed: 'The :attribute confirmation does not match.' +date: 'The :attribute is not a valid date.' +date_equals: 'The :attribute must be a date equal to :date.' +date_format: 'The :attribute does not match the format :format.' +different: 'The :attribute and :other must be different.' +digits: 'The :attribute must be :digits digits.' +digits_between: 'The :attribute must be between :min and :max digits.' +dimensions: 'The :attribute has invalid image dimensions.' +distinct: 'The :attribute field has a duplicate value.' +email: 'The :attribute must be a valid email address.' +ends_with: 'The :attribute must end with one of the following: :values.' +exists: 'The selected :attribute is invalid.' +file: 'The :attribute must be a file.' +filled: 'The :attribute field must have a value.' +gt: + numeric: 'The :attribute must be greater than :value.' + file: 'The :attribute must be greater than :value kilobytes.' + string: 'The :attribute must be greater than :value characters.' + array: 'The :attribute must have more than :value items.' +gte: + numeric: 'The :attribute must be greater than or equal :value.' + file: 'The :attribute must be greater than or equal :value kilobytes.' + string: 'The :attribute must be greater than or equal :value characters.' + array: 'The :attribute must have :value items or more.' +image: 'The :attribute must be an image.' +in: 'The selected :attribute is invalid.' +in_array: 'The :attribute field does not exist in :other.' +integer: 'The :attribute must be an integer.' +ip: 'The :attribute must be a valid IP address.' +ipv4: 'The :attribute must be a valid IPv4 address.' +ipv6: 'The :attribute must be a valid IPv6 address.' +json: 'The :attribute must be a valid JSON string.' +lt: + numeric: 'The :attribute must be less than :value.' + file: 'The :attribute must be less than :value kilobytes.' + string: 'The :attribute must be less than :value characters.' + array: 'The :attribute must have less than :value items.' +lte: + numeric: 'The :attribute must be less than or equal :value.' + file: 'The :attribute must be less than or equal :value kilobytes.' + string: 'The :attribute must be less than or equal :value characters.' + array: 'The :attribute must not have more than :value items.' +max: + numeric: 'The :attribute may not be greater than :max.' + file: 'The :attribute may not be greater than :max kilobytes.' + string: 'The :attribute may not be greater than :max characters.' + array: 'The :attribute may not have more than :max items.' +mimes: 'The :attribute must be a file of type: :values.' +mimetypes: 'The :attribute must be a file of type: :values.' +min: + numeric: 'The :attribute must be at least :min.' + file: 'The :attribute must be at least :min kilobytes.' + string: 'The :attribute must be at least :min characters.' + array: 'The :attribute must have at least :min items.' +not_in: 'The selected :attribute is invalid.' +not_regex: 'The :attribute format is invalid.' +numeric: 'The :attribute must be a number.' +password: The password is incorrect. +present: 'The :attribute field must be present.' +recaptcha: 'reCAPTCHA validation failed.' +regex: 'The :attribute format is invalid.' +required: 'The :attribute field is required.' +required_if: 'The :attribute field is required when :other is :value.' +required_unless: 'The :attribute field is required unless :other is in :values.' +required_with: 'The :attribute field is required when :values is present.' +required_with_all: 'The :attribute field is required when :values are present.' +required_without: 'The :attribute field is required when :values is not present.' +required_without_all: 'The :attribute field is required when none of :values are present.' +same: 'The :attribute and :other must match.' +size: + numeric: 'The :attribute must be :size.' + file: 'The :attribute must be :size kilobytes.' + string: 'The :attribute must be :size characters.' + array: 'The :attribute must contain :size items.' +starts_with: 'The :attribute must start with one of the following: :values.' +string: 'The :attribute must be a string.' +timezone: 'The :attribute must be a valid zone.' +unique: 'The :attribute has already been taken.' +uploaded: 'The :attribute failed to upload.' +url: 'The :attribute format is invalid.' +uuid: 'The :attribute must be a valid UUID.' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: name + player_name: player name + identification: email or player name + email: email + password: password + password_confirmation: 'password confirmation' + title: title + content: content diff --git a/resources/lang/ja_JP/admin.yml b/resources/lang/ja_JP/admin.yml new file mode 100755 index 0000000..d275246 --- /dev/null +++ b/resources/lang/ja_JP/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: 登録ユーザー数 + total-players: プレイヤー数 + total-textures: 登録したスキン数 + disk-usage: ディスク使用量 + overview: 概要 + texture-uploads: スキンのアップロード + user-registration: ユーザー登録 +notifications: + send: + title: 通知を送信 + success: 送信に成功しました. + receiver: + title: 受信者 + all: 全てのユーザ + normal: 一般ユーザー + uid: UIDを指定 + email: メールアドレスを指定 + title: トップ + content: コンテンツ (Markdown サポート されて いませ) +users: + operations: + non-existent: ユーザーが存在しません。 + no-permission: このユーザーを操作する権限がありません。 + email: + success: メールの変更が済みました。 + verification: + success: アカウントの確認ステータスが正常に切り替わりました。 + nickname: + success: ニックネームの変更が済みました。 + password: + success: パスワードの変更が済みました。 + score: + success: スコアの変更が済みました。 + permission: アクセス許可が更新されました。 + delete: + success: The account has been deleted successfully. +players: + no-permission: You have no permission to operate this player. + textures: + non-existent: No such texture tid.:tid + success: The textures of :player has been updated. + name: + success: Player name has been updated to :player + owner: + success: The player :player was transferred to user :user. + delete: + success: The player has been deleted successfully. +customize: + change-color: + title: Change Theme Color + colors: + navbar: Top Navigation Bar + sidebar: + dark: Sidebar (Dark) + light: Sidebar (Light) +i18n: + add: Add New Language Line + added: Language line added. + updated: Language line updated. + deleted: Language line deleted. + group: グループ + key: 鍵 + text: テキスト + tip: How can I use this page? +status: + info: Information + health: Health + bs: + name: Blessing Skin + version: バージョン + env: Application Environment + debug: Debugging or Not? + commit: Commit + laravel: Laravel Version + server: + name: サーバー + php: PHP バージョン + web: Web サーバーソフトウェア + os: オペレーティングシステム + db: + name: データベース + type: サーバー + host: ホスト + port: ポート + username: Username + database: Database + prefix: Table Prefix + plugins: Enabled Plugins (:amount) +plugins: + readme: Read Me + operations: + title: Operations + enabled: ':plugin has been enabled.' + unsatisfied: + notice: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't enable it. Please install or update the plugins listed below, and disable those have conflicts. + disabled: 'The ":name" plugin is not enabled.' + version: 'The version of ":title" does not satisfies the constraint ":constraint".' + conflict: 'The ":title" plugin cannot run with this plugin at the same time.' + disabled: ':plugin has been disabled.' + deleted: The plugin was deleted successfully. + no-config-notice: The plugin is not installed or doesn't provide a configuration page. + no-readme-notice: The plugin doesn't contain a readme file. + not-found: No such plugin. + market: + unresolved: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't download it. Please install or update the plugins listed below, and disable those have conflicts. + connection-error: Unable to connect to the plugins registry. :error + non-existent: The plugin :plugin does not exist. + install-success: Plugin was installed. +update: + complete: Update completed + info: + title: Update Information + up-to-date: Already up-to-date. + available: New version available. + versions: + latest: "Latest Version:" + current: "Current Version:" + check-github: Check GitHub Releases + button: Update Now + cautions: + title: Cautions + link: check out this. + text: | + Please choose update source according to your host's network environment. + Low-speed connection between update source and your host will cause long-time loading at checking and downloading page. + To change the default update source, + errors: + connection: "Unable to access to current update source. Details: :error" + spec: Current update source is not supported. + php: Your PHP version is too low to update. Requires :version or later. +download: + errors: + download: 'Failed to download. Error: :error' + shasum: File validation failed. Please download again. + unzip: Failed to unpack files. +invalid-action: Invalid action diff --git a/resources/lang/ja_JP/auth.yml b/resources/lang/ja_JP/auth.yml new file mode 100755 index 0000000..99d54ee --- /dev/null +++ b/resources/lang/ja_JP/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: Log In + message: Log in to manage your skin & players + success: Logged in successfully. +check: + anonymous: Illegal access. Please log in first. + verified: To access this page, you should verify your email address first. + admin: Only admins are permitted to access this page. + banned: You are banned on this site. Please contact the admin. +register: + title: Register + message: Welcome to :sitename! + success: Your account was registered. Redirecting... + max: You can't register more than :regs accounts. +forgot: + title: Forgot Password + message: We will send you an E-mail to verify. + disabled: Password resetting is not available. + frequent-mail: You click the send button too fast. Wait for some minutes. + unregistered: The email address is not registered. + success: Mail sent, please check your inbox. The link will be expired in 1 hour. + failed: Failed to send verification mail. :msg + ignore: If you haven't signed up on our site, please ignore this email. No unsubscribing is required. + reset: Reset your password + notice: This mail is sending automatically, no reponses will be sent if you reply. + mail: + title: Reset your password on :sitename + message: You are receiving this email because we received a password reset request for your account on :sitename. + reset: 'To reset your password, please visit: :url' + ignore: If you did not request a password reset, no further action is required. +reset: + title: Reset Password + button: Reset + invalid: Invalid link. + expired: This link is expired. + message: ':username, reset your password here.' + success: Password resetted successfully. +bind: + title: Bind Email + button: Bind + message: You need to provide your email adderss to continue. + introduction: We won't send you any spam. + registered: The email address was already taken. +verify: + title: Email Verification + invalid: Invalid link. + not-matched: Email doesn't match. +validation: + user: No such user. + password: Wrong password. +logout: + success: You are now logged out. +oauth: + authorization: + title: Authorization + introduction: A 3rd-party application ":name" is requesting permission to access your account. + button: Authorize + permissions: Permissions + scope: + user: + read: Sign you in and read your profile + notification: + read: Allows the app to read your notifications. + readwrite: Allows the app to send notifications. + player: + read: Allows the app to read your players. + readwrite: Allows the app to create, read, update and delete your players. + closet: + read: Allows the app to read your closet items. + readwrite: Allows the app to create, read, update and delete your closet items. + users-management: + read: Allows the app to read site's users. + readwrite: Allows the app to create, read, update and delete site's users. + players-management: + read: Allows the app to read site's players. + readwrite: Allows the app to create, read, update and delete site's players. + closet-management: + read: Allows the app to read user's of your site closet items. + readwrite: Allows the app to create, read, update and delete user's closet items. + reports-management: + read: Allows the app to read user's reports. + readwrite: Allows the app to read and review user's reports. +email: Email +register-link: Register a new account diff --git a/resources/lang/ja_JP/errors.yml b/resources/lang/ja_JP/errors.yml new file mode 100755 index 0000000..2bc388c --- /dev/null +++ b/resources/lang/ja_JP/errors.yml @@ -0,0 +1,19 @@ +--- +http: + msg-403: You have no permission to access this page. + msg-404: Nothing here. + msg-500: Please try again later. + msg-503: The application is now in maintenance mode. + method-not-allowed: Method not allowed. + csrf-token-mismatch: Token does not match, try reloading the page. + ie: Your browser isn't supported. Please switch to other modern browsers, such as Firefox or Chrome. +general: + title: Error occurred +exception: + code: 'Error code: :code' + detail: 'Details: :msg' + message: | + Whoops, looks like something went wrong. (enable APP_DEBUG in .env to see details) +plugins: + duplicate: The plugin [:dir1] has a duplicated plugin name definition which is same to plugin [:dir2]. Please check your plugins directory, remove one of them or use another name definition. + boot: There is something wrong with plugin ":plugin". diff --git a/resources/lang/ja_JP/front-end.yml b/resources/lang/ja_JP/front-end.yml new file mode 100755 index 0000000..bceba0b --- /dev/null +++ b/resources/lang/ja_JP/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: ログイン + loggingIn: ログイン中 + tooManyFails: + captcha: 失敗回数が多すぎます!CAPTCHAを入力してください。 + recaptcha: 失敗回数が多すぎます!reCAPTCHAチャレンジに合格してください。 + emptyEmail: メールアドレスが空です。 + invalidConfirmPwd: パスワード確認とパスワードが一致していません + emptyNickname: 空っぽのニックネーム。 + register: 新規登録 + registering: 登録中 + send: 送信 + sending: 送信中 + reset: 再設定 + resetting: リセット中 + nickname: ニックネーム + player-name: Minecraft プレイヤー名 + email: メール + identification: 電子メールまたはプレイヤー名 + password: パスワード + captcha: CAPTCHA + change-captcha: CAPTCHA画像を変更するにはクリックしてください。 + login-link: すでに登録している方はこちらからログイン + forgot-link: パスワードを忘れましたか? + keep: パスワードを記録する + repeat-pwd: パスワードを再度入力 + nickname-intro: 特殊文字を除く + player-name-intro: Minecraftでのプレイヤー名、後で変更可能 + forgot: + login-link: それを覚えています +skinlib: + private: 非公開 + anonymous: まずはログインしてください + reset: リセット + addToCloset: クローゼットに追加 + removeFromCloset: クローゼットから削除 + setItemName: このテクスチャの名前を設定 + applyNotice: クローゼットでプレイヤーに適用することができます + emptyItemName: テクスチャ名が空です。 + setNewTextureName: '新しいテクスチャ名を入力してください。' + emptyNewTextureName: 新しいテクスチャ名を空にします。 + seeMyUpload: 自分の投稿 + apply: 適用 + filter: + skin: (任意のモデル) + steve: (スティーブ) + alex: (アレックス) + cape: (ケープ) + uploader: 'ユーザー (UID = :uid) がアップロードされました' + allUsers: 全てのユーザ + sort: + title: 並び替え + time: 最新 + likes: 最もいいねが多い + emptyTextureName: テクスチャ名が空です。 + emptyUploadFile: ファイルがアップロードされていません。 + fileExtError: 'Error: Textures should be PNG files.' + uploading: Uploading + setAsPrivate: Set as Private + setAsPublic: Set as Public + setPublicNotice: Sure to set this as public texture? + setPrivateNotice: Sure to set this as private texture? + deleteNotice: Are you sure to delete this texture? + setNewTextureModel: "Please select a new texture model:" + upload: + texture-name: Texture Name + texture-type: Texture Type + select-file: Select File + privacy-notice: Prevent it from being visible at skin library. + set-as-private: Make it Private + button: Upload + cost: It costs you about :score score. + award: You'll be awarded :score score(s) by uploading public texture. + show: + anonymous: You must login to use closets + likes: People who like this + detail: Details + name: Texture Name + edit: Edit + model: Applicable Model + size: File Size + uploader: Uploader + upload-at: Upload At + download: Download + delete-texture: Delete Texture + manage-notice: The texture which was deleted or setted to private will be removed from the closet of everyone who had favorited it. + report: + title: Report + reason: Tell us reason please. + positive: To encourage positive contributions to the skinlib, we will reward who reported inappropriate content with :score scores. However, if any malicious reporting behaviors were found, all scores rewarded will be taken back. + negative: To mitigate the impact of malicious reports, we will require :score scores for submitting a texture report. Don't worry. The suspended scores and additional reward will be sent to your account after your report reviewed by administrators. +user: + signRemainingTime: 'Available after :time :unit' + timeUnitHour: h + timeUnitMin: min + emptyClosetMsg: >- +

Nothing in your closet...

Why not explore the Skin Library for a while?

+ renameItem: Rename item + removeItem: Remove from closet + setAsAvatar: Set as avatar + viewInSkinlib: View in skin library + switch2dPreview: Switch to 2D Preview + switch3dPreview: Switch to 3D Preview + removeFromClosetNotice: Sure to remove this texture from your closet? + emptySelectedTexture: No texture is selected. + renameClosetItem: 'Set a new name for this item:' + changePlayerName: 'Please enter the player name:' + emptyPlayerName: Empty player name. + deletePlayer: Sure to delete this player? + deletePlayerNotice: It's permanent. No backups. + chooseClearTexture: Choose texture types you want to clear + noClearChoice: タイプが選択されていません + setAvatar: 本当にあなたのアバターに設定しますか? + setAvatarNotice: 皮の頭部部分は、使用されます。 + resetAvatarConfirm: アバターをリセットしてもよろしいですか? + typeToSearch: 入力して検索 + useAs: 適用... + resetSelected: クリアを選択 + closet: + upload: 登録したスキン数 + use-as: + title: どのプレーヤーに適用する必要がありますか? + empty: あなたはプレイヤーを所有していないようです。 + used: + title: 使用済みリソース + players: 登録済みプレイヤー + storage: 使用している容量 + cur-score: 現在の得点 + score-notice: 導入を表示するスコアをクリックします。 + sign: 署名 + player: + operation: Operations + edit-pname: Edit Name + delete-texture: Clear Textures + delete-player: Delete + add-player: Add new player + texture-empty: Nothing + verification: + title: Verify Your Account + message: You must verify your email address before using the skin hosting service. Haven't received the email? + resend: Click here to send again. + sending: Sending... + oauth: + id: Client ID + name: App Name + secret: Client Secret + redirect: Callback URL + modifyName: Modify app name. + modifyUrl: Modify callback URL. + create: Create New App + confirmRemove: Are you sure to delete this app? You won't be able to undo this. +admin: + operationsTitle: Operations + permission: Permission + deleteUser: Delete + changeEmail: Edit Email + newUserEmail: 'Please enter the new email:' + verification: Email Verification + toggleVerification: Toggle Verification Status + changeNickName: Edit Nickname + newUserNickname: 'Please enter the new nickname:' + changePassword: Edit Password + newUserPassword: 'Please enter the new password:' + changeScore: Edit Score + newScore: 'Please enter the new score:' + changePermission: Change permission + newPermission: 'Please select new permission:' + deleteUserNotice: Are you sure to delete this user? It' permanent. + banned: Banned + normal: Normal + admin: Admin + superAdmin: Super Admin + unverified: Unverified + verified: Verified + pidNotice: >- + Please enter the tid of texture. Inputing 0 can clear texture of this player. + changeTexture: Change Textures + changePlayerName: Change Player Name + changeOwner: Change Owner + textureType: Texture Type + deletePlayer: Delete + changePlayerOwner: 'Please enter the id of user which this player should be transferred to:' + deletePlayerNotice: Are you sure to delete this player? It' permanent. + changePlayerNameNotice: 'Please input new player name:' + emptyPlayerName: Player name cannot be empty. + configurePlugin: Configure + deletePlugin: Delete + noDependencies: No Dependencies + pluginTitle: Plugin + pluginAuthor: Author + pluginVersion: Version + pluginReadme: Read Me + pluginDescription: Description + pluginDependencies: Dependencies + installPlugin: Install + pluginInstalling: Installing... + updatePlugin: Update + pluginUpdating: Updating... + confirmUpdate: Are you sure to update ":plugin" from :old to :new? + enablePlugin: Enable + disablePlugin: Disable + confirmDeletion: Are you sure to delete this plugin? + uploadArchive: Upload Archive + uploadArchiveNotice: Install a plugin by uploading a Zip archive. + downloadRemote: Download From Remote + downloadRemoteNotice: Install a plugin by downloading a Zip archive from remote URL. + updateButton: Update Now + downloading: Downloading... + i18n: + group: Group + key: Key + text: Text + empty: (Empty) + modify: Modify + delete: Delete + updating: 'Please type new text:' + confirmDelete: Are you sure? This is irreversible. +report: + tid: Texture ID + reporter: Reporter + reason: Reason + status-title: 状態 + status: + - Pending + - Resolved + - Rejected + time: Report Time + delete: Delete + ban: Ban + reject: Reject +general: + skin: Skin + cape: Cape + fatalError: Fatal Error + confirmLogout: Sure to log out? + confirm: OK + cancel: Cancel + submit: Submit + close: Close + more: More + tip: Tip + noResult: No result. + texturePreview: Texture Preview + walk: Walk + run: Run + rotation: Rotation + pause: Pause + reset: Reset + skinlib: Skin Library + wait: Please wait... + csrf: This page is out-dated. Please refresh it. + user: + email: Email + nickname: Nick Name + score: Score + register-at: Registered At + player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified +colors: + black: Black + white: White + gray: Gray + prev: Previous Background + next: Next Background +vendor: + datatable: + search: Search + prev: Prev + next: Next diff --git a/resources/lang/ja_JP/general.yml b/resources/lang/ja_JP/general.yml new file mode 100755 index 0000000..1fe8c6a --- /dev/null +++ b/resources/lang/ja_JP/general.yml @@ -0,0 +1,59 @@ +--- +index: Homepage +skinlib: Skin Library +user-center: User Center +logout: Log Out +login: Log In +register: Register Now +profile: User Profile +admin-panel: Admin Panel +explore: Explore +manage: Manage +anonymous: Guest +back: Back +dashboard: Dashboard +my-closet: Closet +my-reports: Reports +developer: Advanced +oauth-manage: OAuth2 Apps +player-manage: Players +user-manage: Users +report-manage: Reports +plugin-manage: Plugins +plugin-market: Plugin Market +plugin-configs: Plugin Configs +customize: Customize +i18n: Internationalization +options: Options +score-options: Score Options +res-options: Resource Options +status: Status +check-update: Check Update +download-update: Download Updates +close: Close +skin: Skin +cape: Cape +submit: Submit +cancel: Cancel +yes: true +no: false +op-success: Operated successfully. +unknown: Unknown +notice: Notice +illegal-parameters: Illegal parameters. +private: Private +public: Public +unexistent-user: No such user. +player-banned: The owner of this player has been banned. +texture-deleted: The requested texture has been deleted. +user: + email: Email + nickname: Nickname + password: Password + score: Score + register-at: Registered At +player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified diff --git a/resources/lang/ja_JP/index.yml b/resources/lang/ja_JP/index.yml new file mode 100755 index 0000000..1f3ec7f --- /dev/null +++ b/resources/lang/ja_JP/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: 機能 + first: + icon: fa-users + name: マルチプレイヤー + desc: 1つのアカウントに複数のプレイヤーを追加できます。 + second: + icon: fa-share-alt + name: シェア + desc: スキンライブラリを探索し、「いいね」を送り、友達と共有しましょう。 + third: + icon: fa-cloud + name: 無料! + desc: それは永久に無料です。広告なし、サブスクリプション料金はありません。 +introduction: ':sitename はマインクラフトスキンのアップロードとホスティングサービスを提供します。スキンの Mod などと連携しています。 (e.g. CustomSkinLoader)、ゲームキャラクターのスキンとマントを選択し、Minecraft で他のプレイヤーに表示させることができます。' +start: 参加する diff --git a/resources/lang/ja_JP/options.yml b/resources/lang/ja_JP/options.yml new file mode 100755 index 0000000..76c6421 --- /dev/null +++ b/resources/lang/ja_JP/options.yml @@ -0,0 +1,180 @@ +--- +option-saved: Option saved. +homepage: + title: Homepage + home_pic_url: + title: Picture URL at Homepage + hint: Path relative to homepage or full URL, leave empty to use default image. + favicon_url: + title: Website Icon + hint: Path relative to public/ or full URL. + description: The given image must have same width and height (leave blank to use default icon). + transparent_navbar: + title: Transparent Navigation Bar + label: This will enable transparent navigation bar of home page, but it will turn to be normal if page is scrolled to bottom. + hide_intro: + title: Hide Introduction at Bottom + label: Scroll bar will be disabled if this option is enabled, as version 2.x. + fixed_bg: + title: Fixed Background + label: This option will make background fixed, not scrolled with scroll bar. + copyright_prefer: + title: Program Copyright + description: "You can specify a different style of program copyright for each language. To edit a specific language's corresponding program copyright style, please switch to that language and submit your edit.
Warning: Any evil modification applied on the footer program copyright (including deleting, modifying author, changing link target) with out permission is FORBIDDEN. The author reserves the right to pursue relevant responsibilities." + copyright_text: + title: Custom Copyright Text + description: Placeholders are available in custom copyright text. e.g. {site_name} & {site_url}. You can also specify a different footer for each language. To edit a specific language's corresponding footer, please switch to that language and submit your edit. +customJsCss: + title: Custom CSS/JavaScript + message: | + The contents will be attached to <style> and <script> tags.
+ - Here are some useful examples: Examples of Custom CSS & JavaScript + custom_css: CSS + custom_js: JavaScript +rate: + title: Scores + score_per_storage: + title: Storage + addon: scores = 1 KB + private_score_per_storage: + title: Private Storage + addon: scores = 1 KB + hint: Uploading private textures will cost more scores. + score_per_closet_item: + title: Favorites + addon: score = 1 closet item + return_score: + title: Score Return + label: Return scores back to user after deleting players/textures/closet items. + score_per_player: + title: Players + addon: scores = 1 player + user_initial_score: User Initial Score +report: + title: Reporting Textures + reporter_score_modification: + title: Scores for Submitting an Report + description: Set a positive integer value to reward user who submits new reports. Set to a negative value will require scores for submitting reports, and the suspended scores will be available if user's report was resolved. Set to 0 to disable. + reporter_reward_score: + title: Reward the Reporter with Scores If Report Resolved +sign: + title: Signing + sign_score: + title: Score Granted + addon1: scores ~ + addon2: scores + sign_gap_time: + title: Gap Time + addon: hours + sign_after_zero: + title: Time + label: Users can sign in after 0 everyday. + hint: The above option will be ignored if this is checked. +sharing: + title: Awarding Sharing + score_award_per_texture: + title: Uploader will be rewarded for each uploading texture with + take_back_scores_after_deletion: + title: Return scores + label: Return scores if uploader setting private or deleting texture. + score_award_per_like: + title: Each time the texture is collected, uploader will be rewarded with +general: + title: General Options + site_name: Site Name + site_description: + title: Site Description + description: You can also specify a different site name and description for each language. To edit a specific language's corresponding site name or description text, please switch to that language and submit your edit. + site_url: + title: Site URL + hint: Begin with http(s)://, nerver ends with slash. + register_with_player_name: + title: Register with Player Name + label: Require Minecraft's player name when user register + require_verification: + title: Account Verification + label: Users must verify their email address first. + regs_per_ip: Max accounts of one IP + max_upload_file_size: + title: Max Upload Size + hint: "Limit specified in php.ini: :size" + player_name_rule: + title: Player Name Rule + official: Letters, numbers and underscores (Mojang's official rule) + cjk: Allow CJK Unified Ideographs + utf8: Allow all valid UTF-8 characters (excluding whitespaces) + custom: Use custom rules (regular expression) + custom_player_name_regexp: + title: Custom Player Name Rules + hint: Only takes effect when the above option is set to 'custom'. Leave empty to allow any character. + placeholder: Regular Expressions + player_name_length: + title: Player Name Length + suffix: characters + auto_del_invalid_texture: + title: Invalid Textures + label: Delete invalid textures automatically. + hint: Delete textures records whose file no longer exists from skinlib. + allow_downloading_texture: + title: Downloading Textures + label: Allow users to directly download the source file of a skinlib item. + status_code_for_private: + title: HTTP Code for Rejecting Accessing Private Textures + texture_name_regexp: + title: Texture Name Rules + hint: The RegExp for validating name of uploaded textures. Leave empty to allow any character except single, double quote and backslash. + placeholder: Regular Expressions + content_policy: + title: Content Policy + description: Display content policy at texture uploading page, supporting Markdown. To edit a specific language's corresponding content policy, please switch to that language and submit your edit. +announ: + title: Announcement + announcement: + description: Styling with Markdown is supported. You can also specify a different announcement for each language. To edit a specific language's corresponding announcement, please switch to that language and submit your edit. +meta: + title: SEO tags + meta_keywords: + title: Keywords + hint: Split with commas. + meta_description: + title: Description + hint: Description defined in "general options" will be used if you left it empty. + meta_extras: + title: Other Custom Tags +recaptcha: + recaptcha_invisible: + title: Invisible + label: Enable Invisible Mode +res-warning: This page is ONLY for advanced users. If you aren't familiar with these, please don't modify them! +resources: + title: Resource Files + hint: Please check these options if you enabled CDN for your site. + force_ssl: + title: Force SSL + label: Use HTTPS protocol to load all front-end assets. + hint: Please check if SSL really available before turning on. + auto_detect_asset_url: + title: Assets URL + label: Determine assets url automatically. + description: Please unable this if assets URLs are wrongly generated under a CDN. The site url will be used if this is not enabled. + cache_expire_time: + title: Cache Exipre Time + hint: In seconds, 86400 = one day, 31536000 = one year. + cdn_address: + title: Front-end Assets CDN + hint: Front-end files won't be loaded if URL is unavailable. + description: | + The CDN URL you give must refer to a mirror of /public directory, + all the files of that directory will be loaded as CDN.
+ How to verify? Verify if {Your CDN URL}/app/manifest.json can be accessed. +cache: + title: Cache Configuration + clear: Clear Cache + cleared: Cache has been cleared. + driver: Current cache driver is 「:driver」. + enable_avatar_cache: + title: Avatar + label: Enable caching avatar + enable_preview_cache: + title: Texture Preivew + label: Enable caching texture preivew diff --git a/resources/lang/ja_JP/setup.yml b/resources/lang/ja_JP/setup.yml new file mode 100755 index 0000000..efe1e69 --- /dev/null +++ b/resources/lang/ja_JP/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "ターゲット :type データベースに接続できません。設定を確認してください。サーバーが以下の返信を受けました: :msg" +locked: + title: すでにインストールされています + text: Blessing Skin Serverがインストールされているようです。再インストールするには、"storage"ディレクトリの下にある"install.lock"ファイルを削除してください。 + button: ホームページに戻る +updates: + success: + title: 更新完了 +wizard: + master: + title: インストールウィザード - Blessing Skin Server + welcome: + title: ようこそ + button: 次へ + text: Blessing Skin Server v:version へようこそ! + database: + title: データベース + text: Blessing Skinのデータを格納するためのデータベースです。 + type: データベース種別 + host: データベースホスト + port: データベースポート + username: データベース名 + password: データベースパスワード + db: データベース名 + db-notice: SQLiteファイルのパスを指定し、SQLiteを使用する場合はその他の空白を埋める必要はありません。 + prefix: データベーステーブルのプレフィックス(オプション) + prefix-notice: 複数のBlessing Skin Serverを1つのデータベースにインストールする場合を除き、このオプションを使用する必要はありません。 + info: + title: 必要な情報 + button: インストールを実行 + text: インストールを続行するには、このフォームに初期管理者アカウントの詳細を記入してください。 心配しないで、これらの設定は後でいつでも変更できます。 + admin-email: 管理者メールアドレス + admin-notice: このアカウントは、他のユーザーの管理者権限を与えたり、取り消したりすることができる、ユニークなスーパー管理者アカウントです。 + nickname: ニックネーム + password: パスワード + pwd-notice: '注意: ログインするにはパスワードが必要です。安全な場所に保管してください。' + confirm-pwd: パスワードの確認 + site-name: サイト名 + site-name-notice: これはすべてのページに表示されます。 + finish: + title: インストール完了 + text: Blessing Skin Serverがインストールされました。ありがとうございました。 diff --git a/resources/lang/ja_JP/skinlib.yml b/resources/lang/ja_JP/skinlib.yml new file mode 100755 index 0000000..2fc935a --- /dev/null +++ b/resources/lang/ja_JP/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: Upload new skin +show: + title: Texture Details + deleted: The requested texture was already deleted. + private: The requested texture is private and only visible to the uploader and admins. +upload: + title: Upload Texture + name-rule: Less than 32 characters and must not contain any special one. + name-rule-regexp: Custom name rules are applied as :regexp + private-score-notice: It will spend you more scores for setting it as private. You will be charged :score scores for per KB storage. + invalid-size: Invalid :type file (width :width, height :height) + invalid-hd-skin: Invalid HD skin (width and height should be divisible by 32) + lack-score: You don't have enough score to upload this texture. + repeated: The texture is already uploaded by someone else. You can add it to your closet directly. + success: Texture :name was uploaded successfully. +delete: + success: The texture was deleted successfully. +privacy: + success: The texture was set to :privacy successfully. +rename: + success: The texture was renamed to :name successfully. +model: + success: The texture's model was changed to :model successfully. +no-permission: You have no permission to moderate this texture. +non-existent: No such texture. +report: + duplicate: You have already reported this texture. The administrators will review it as soon as possible. You can also track the status of your report at User Center. + success: Thanks for reporting! The administrators will review it as soon as possible. diff --git a/resources/lang/ja_JP/user.yml b/resources/lang/ja_JP/user.yml new file mode 100755 index 0000000..cff23be --- /dev/null +++ b/resources/lang/ja_JP/user.yml @@ -0,0 +1,101 @@ +--- +sign-success: Signed successfully. You got :score scores. +announcement: Announcement +no-unread: No new notifications. +verification: + disabled: Email verification is not available. + frequent-mail: You click the send button too fast. Wait for 60 secs, guy. + verified: Your account is already verified. + success: Verification link was sent, please check your inbox. + failed: We failed to send you the verification link. Detailed message :msg + mail: + title: Verify Your Account on :sitename + message: You are receiving this email because someone registered an account with this email address on :sitename. + reset: 'Click here to verify your account: :url' + ignore: If you did not register an account, no further action is required. +score-intro: + title: What is score? + introduction: | + We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually. + Either adding players, uplaoding textures or adding a skinlib item to your closet will consume scores. + :return-score + + New users will get :initial_score scores initially, and you can acquire :score-from ~ :score-to scores by daily signing in. + will-return-score: The score will be returned if you deleted players, uploaded textures or closet items. + no-return-score: The score will NOT be returned if you deleted players, uploaded textures or closet items. + rates: + storage: ':score scores = 1 KB storage' + player: ':score scores = 1 player' + closet: ':score socres = 1 closet item' +closet: + add: + success: Added :name to closet successfully. + repeated: You have already added this texture. + not-found: We cannot find this texture. + lack-score: You don't have enough score to add it to closet. + rename: + success: The item is successfully renamed to :name + remove: + success: The texture was removed from closet successfully. + non-existent: The texture does not exist in your closet. +player: + login-notice: Now you can log in with player names you owned instead email address. + player-name-rule: + official: Player name may only contains letters, numbers and underscores. + cjk: Player name may contains letters, numbers, underscores and CJK Unified Ideographs. + utf8: Player name must be a UTF-8 string. + custom: Custom player name rules are applied on this site. Please contact admins for further information. + player-name-length: The player name should be at least :min characters and not greater than :max characters. + add: + repeated: The player name is already registered. + lack-score: You don't have enough score to add a player. + success: Player :name was added successfully. + delete: + success: Player :name was deleted successfully. + rename: + repeated: This player name is occupied. Please choose another one. + success: Player :old was renamed to :new + set: + success: The texture was applied to player :name successfully. + clear: + success: The textures of player :name was resetted successfully. +profile: + avatar: + title: Change Avatar? + notice: Click the gear icon "" of any skin in your closet, then click "Set as avatar". We will cut the head segment of that skin for you. If there is no icon like this, please try to disable your ADs blocking extension. + wrong-type: You can't set a cape as avatar. + success: New avatar was set successfully. + reset: Reset Avatar + password: + title: Change Password + old: Old Password + new: New Password + confirm: Repeat Password + button: Change password + wrong-password: Wrong original password. + success: Password updated successfully, please log in again. + nickname: + title: Change Nickname + empty: No nickname is set now. + success: Nickname is successfully updated to :nickname + email: + title: Change Email + new: New Email + password: Current Password + button: Change email + wrong-password: Wrong password. + existed: This email address is occupied. + success: Email address updated successfully, please log in again. + delete: + title: Delete Account + notice: Sure to delete your account on :site? + admin: Admin account can not be deleted. + button: Delete my account + modal-title: You need to enter your password to continue + modal-notice: | + You're about to delete your account. + This is permanent! No backups, no restores, no magic undo button. + We warned you, ok? + password: Current Password + wrong-password: Wrong password. + success: Your account is deleted successfully. diff --git a/resources/lang/ja_JP/validation.yml b/resources/lang/ja_JP/validation.yml new file mode 100755 index 0000000..b4dd2d4 --- /dev/null +++ b/resources/lang/ja_JP/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: ':attributeを承認してください。' +active_url: ':attributeは、有効なURLではありません。' +after: ':attributeには、:dateより後の日付を指定してください。' +after_or_equal: ':attributeには、:date以降の日付を指定してください。' +alpha: ':attributeには、アルファベッドのみ使用できます。' +alpha_dash: ':attributeには、英数字(''A-Z'',''a-z'',''0-9'')とハイフンと下線(''-'',''_'')が使用できます。' +alpha_num: ':attributeには、英数字(''A-Z'',''a-z'',''0-9'')が使用できます。' +array: ':attributeには、配列を指定してください。' +before: ':attributeには、:dateより前の日付を指定してください。' +before_or_equal: ':attributeには、:date以前の日付を指定してください。' +between: + numeric: ':attributeには、:minから、:maxまでの数字を指定してください。' + file: ':attributeには、:min KBから:max KBまでのサイズのファイルを指定してください。' + string: ':attributeは、:min文字から:max文字にしてください。' + array: ':attributeの項目は、:min個から:max個にしてください。' +boolean: ':attributeには、''true''か''false''を指定してください。' +captcha: '正しくありませんのCaptcha' +confirmed: ':attributeと:attribute確認が一致しません。' +date: ':attributeは、正しい日付ではありません。' +date_equals: ':attributeは:dateに等しい日付でなければなりません。' +date_format: ':attributeの形式は、'':format''と合いません。' +different: ':attributeと:otherには、異なるものを指定してください。' +digits: ':attributeは、:digits桁にしてください。' +digits_between: ':attributeは、:min桁から:max桁にしてください。' +dimensions: ':attributeの画像サイズが無効です' +distinct: ':attributeの値が重複しています。' +email: ':attributeは、有効なメールアドレス形式で指定してください。' +ends_with: ':attributeは、次のうちのいずれかで終わらなければなりません。: :values' +exists: '選択された:attributeは、有効ではありません。' +file: ':attributeはファイルでなければいけません。' +filled: ':attributeは必須です。' +gt: + numeric: ':attributeは、:valueより大きくなければなりません。' + file: ':attributeは、:value KBより大きくなければなりません。' + string: ':attributeは、:value文字より大きくなければなりません。' + array: ':attributeの項目数は、:value個より大きくなければなりません。' +gte: + numeric: ':attributeは、:value以上でなければなりません。' + file: ':attributeは、:value KB以上でなければなりません。' + string: ':attributeは、:value文字以上でなければなりません。' + array: ':attributeの項目数は、:value個以上でなければなりません。' +image: ':attributeには、画像を指定してください。' +in: '選択された:attributeは、有効ではありません。' +in_array: ':attributeが:otherに存在しません。' +integer: ':attributeには、整数を指定してください。' +ip: ':attributeには、有効なIPアドレスを指定してください。' +ipv4: ':attributeはIPv4アドレスを指定してください。' +ipv6: ':attributeはIPv6アドレスを指定してください。' +json: ':attributeには、有効なJSON文字列を指定してください。' +lt: + numeric: ':attributeは、:valueより小さくなければなりません。' + file: ':attributeは、:value KBより小さくなければなりません。' + string: ':attributeは、:value文字より小さくなければなりません。' + array: ':attributeの項目数は、:value個より小さくなければなりません。' +lte: + numeric: ':attributeは、:value以下でなければなりません。' + file: ':attributeは、:value KB以下でなければなりません。' + string: ':attributeは、:value文字以下でなければなりません。' + array: ':attributeの項目数は、:value個以下でなければなりません。' +max: + numeric: ':attributeには、:max以下の数字を指定してください。' + file: ':attributeには、:max KB以下のファイルを指定してください。' + string: ':attributeは、:max文字以下にしてください。' + array: ':attributeの項目は、:max個以下にしてください。' +mimes: ':attributeには、:valuesタイプのファイルを指定してください。' +mimetypes: ':attributeには、:valuesタイプのファイルを指定してください。' +min: + numeric: ':attributeには、:min以上の数字を指定してください。' + file: ':attributeには、:min KB以上のファイルを指定してください。' + string: ':attributeは、:min文字以上にしてください。' + array: ':attributeの項目は、:min個以上にしてください。' +not_in: '選択された:attributeは、有効ではありません。' +not_regex: ':attributeの形式が無効です。' +numeric: ':attributeには、数字を指定してください。' +password: パスワードが正しくありません。 +present: ':attributeが存在している必要があります。' +recaptcha: 'reCAPTCHA 認証に失敗しました' +regex: ':attributeには、有効な正規表現を指定してください。' +required: ':attributeは、必ず指定してください。' +required_if: ':otherが:valueの場合、:attributeを指定してください。' +required_unless: ':otherが:values以外の場合、:attributeを指定してください。' +required_with: ':valuesが指定されている場合、:attributeも指定してください。' +required_with_all: ':valuesが全て指定されている場合、:attributeも指定してください。' +required_without: ':valuesが指定されていない場合、:attributeを指定してください。' +required_without_all: ':valuesが全て指定されていない場合、:attributeを指定してください。' +same: ':attributeと:otherが一致しません。' +size: + numeric: ':attributeには、:sizeを指定してください。' + file: ':attributeには、:size KBのファイルを指定してください。' + string: ':attributeは、:size文字にしてください。' + array: ':attributeの項目は、:size個にしてください。' +starts_with: ':attributeは、次のいずれかで始まる必要があります。:values' +string: ':attributeには、文字を指定してください。' +timezone: ':attributeには、有効なタイムゾーンを指定してください。' +unique: '指定の:attributeは既に使用されています。' +uploaded: ':attributeのアップロードに失敗しました。' +url: ':attributeは、有効なURL形式で指定してください。' +uuid: ':attributeは、有効なUUIDでなければなりません。' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: 名前 + player_name: プレイヤーの名前 + identification: メール と プレイヤー名。 + email: メール + password: パスワード + password_confirmation: 'パスワードの確認' + title: イベント概要 + content: 内容 diff --git a/resources/lang/ko_KR/admin.yml b/resources/lang/ko_KR/admin.yml new file mode 100755 index 0000000..04736c5 --- /dev/null +++ b/resources/lang/ko_KR/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: 등록된 사용자 + total-players: 플레이어 + total-textures: 택스쳐 업로드됨 + disk-usage: 디스크 사용량 + overview: 개요(Overview) + texture-uploads: 택스쳐 업로드 + user-registration: 사용자 등록 +notifications: + send: + title: 알림 보내기 + success: 성공적으로 전송되었습니다! + receiver: + title: 받는 수량 + all: 모든 사용자 + normal: 일반 유저 + uid: 지정된 UID + email: 지정된 이메일 + title: 제목 + content: 내용(Markdown 지원) +users: + operations: + non-existent: 그런 사용자가 없습니다. + no-permission: 권한이 없습니다. + email: + success: 성공적으로 이메일 주소가 변경되었습니다 + verification: + success: Account verification status toggled successfully. + nickname: + success: 닉네임이 성공적으로 변경되었습니다. + password: + success: 비밀번호 변경에 성공했습니다 + score: + success: 수정 성공 + permission: 권한이 업데이트 되었습니다! + delete: + success: 계정이 성공적으로 삭제되었습니다. +players: + no-permission: 이 사용자을 설정하는 권한이 없습니다. + textures: + non-existent: 텍스처 tid.:tid 가 존재하지 않음 + success: The textures of :player has been updated. + name: + success: Player name has been updated to :player + owner: + success: The player :player was transferred to user :user. + delete: + success: 플레이어를 성공적으로 삭제되었습니다. +customize: + change-color: + title: 태마 색상변경 + colors: + navbar: 탑 내비게이션 바 + sidebar: + dark: 사이드바 (다크) + light: 사이드바 (라이트) +i18n: + add: Add New Language Line + added: Language line added. + updated: Language line updated. + deleted: Language line deleted. + group: 그룹 + key: 키 + text: 텍스트 + tip: 본 패이지의 사용 방법 +status: + info: 정보 + health: 상태 + bs: + name: Blessing Skin + version: 버전 + env: 앱플리케이션 환경 + debug: Debugging or Not? + commit: 재출 + laravel: Laravel 버전 + server: + name: 서버 + php: PHP 버전 + web: 웹 서버 소프트웨어 + os: 운영 체제 + db: + name: 데이터베이스 + type: 서버 + host: 호스트 + port: 포트 + username: 사용자명 + database: 데이터베이스 + prefix: 테이블 접두사 + plugins: 활성화된 플러그인 수 (:amount) +plugins: + readme: Read Me + operations: + title: 동작 + enabled: 플러그인이 활성화되었습니다. + unsatisfied: + notice: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't enable it. Please install or update the plugins listed below, and disable those have conflicts. + disabled: '":name" 플러그인을 활성화 상태가 안닙니다' + version: '":title" 의 버전이 ":constraint"에 비준수합니다' + conflict: '":title" 플러그인와 본 플러그인이 동시에 사용할수없음.' + disabled: 플러그인이 비활성화되었습니다. + deleted: 플러그인이 삭제되었습니다. + no-config-notice: 플러그인이 설정패이지를 재공하지않음 또는 설치하지않음 + no-readme-notice: The plugin doesn't contain a readme file. + not-found: No such plugin. + market: + unresolved: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't download it. Please install or update the plugins listed below, and disable those have conflicts. + connection-error: Unable to connect to the plugins registry. :error + non-existent: The plugin :plugin does not exist. + install-success: Plugin was installed. +update: + complete: Update completed + info: + title: Update Information + up-to-date: Already up-to-date. + available: New version available. + versions: + latest: "Latest Version:" + current: "Current Version:" + check-github: Check GitHub Releases + button: Update Now + cautions: + title: Cautions + link: check out this. + text: | + Please choose update source according to your host's network environment. + Low-speed connection between update source and your host will cause long-time loading at checking and downloading page. + To change the default update source, + errors: + connection: "Unable to access to current update source. Details: :error" + spec: Current update source is not supported. + php: Your PHP version is too low to update. Requires :version or later. +download: + errors: + download: 'Failed to download. Error: :error' + shasum: File validation failed. Please download again. + unzip: Failed to unpack files. +invalid-action: Invalid action diff --git a/resources/lang/ko_KR/auth.yml b/resources/lang/ko_KR/auth.yml new file mode 100755 index 0000000..acaacc0 --- /dev/null +++ b/resources/lang/ko_KR/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: 로그인 + message: Log in to manage your skin & players + success: 로그인 성공 +check: + anonymous: Illegal access. Please log in first. + verified: To access this page, you should verify your email address first. + admin: Only admins are permitted to access this page. + banned: You are banned on this site. Please contact the admin. +register: + title: 회원가입 + message: Welcome to :sitename! + success: Your account was registered. Redirecting... + max: You can't register more than :regs accounts. +forgot: + title: 비밀번호를 잊으셨나요 + message: We will send you an E-mail to verify. + disabled: Password resetting is not available. + frequent-mail: You click the send button too fast. Wait for some minutes. + unregistered: 이 이메일 주소는 등록되지 않았습니다. + success: Mail sent, please check your inbox. The link will be expired in 1 hour. + failed: Failed to send verification mail. :msg + ignore: If you haven't signed up on our site, please ignore this email. No unsubscribing is required. + reset: 비밀번호 재설정 + notice: This mail is sending automatically, no reponses will be sent if you reply. + mail: + title: ':sitename 에서 비밀번호 재설정하기' + message: ':sitename 의 사용자 계정 비밀번호 재설정을 요청 하셨기 때문에 이메일이 전송되었습니다.' + reset: 'To reset your password, please visit: :url' + ignore: 암호 재설정을 요청하지 않은 경우 추가 조치가 필요하지 않습니다. +reset: + title: 비밀번호 초기화 + button: 재설정 + invalid: 유효하지 않은 링크 + expired: 이 링크는 만료 되었습니다. + message: ':username, reset your password here.' + success: 비밀번호 변경에 성공했습니다 +bind: + title: Bind Email + button: Bind + message: You need to provide your email adderss to continue. + introduction: We won't send you any spam. + registered: 이미 사용 중인 이메일 주소입니다. +verify: + title: Email Verification + invalid: 유효하지 않은 링크 + not-matched: 이메일 주소가 일치하지 않습니다. +validation: + user: 해당 유저를 찾을 수 없습니다. + password: Wrong password. +logout: + success: 로그아웃 됐습니다 +oauth: + authorization: + title: 인증 + introduction: A 3rd-party application ":name" is requesting permission to access your account. + button: 승인 + permissions: 권한 + scope: + user: + read: Sign you in and read your profile + notification: + read: Allows the app to read your notifications. + readwrite: Allows the app to send notifications. + player: + read: Allows the app to read your players. + readwrite: Allows the app to create, read, update and delete your players. + closet: + read: Allows the app to read your closet items. + readwrite: Allows the app to create, read, update and delete your closet items. + users-management: + read: Allows the app to read site's users. + readwrite: Allows the app to create, read, update and delete site's users. + players-management: + read: Allows the app to read site's players. + readwrite: Allows the app to create, read, update and delete site's players. + closet-management: + read: Allows the app to read user's of your site closet items. + readwrite: Allows the app to create, read, update and delete user's closet items. + reports-management: + read: Allows the app to read user's reports. + readwrite: Allows the app to read and review user's reports. +email: Email +register-link: Register a new account diff --git a/resources/lang/ko_KR/errors.yml b/resources/lang/ko_KR/errors.yml new file mode 100755 index 0000000..281f8ed --- /dev/null +++ b/resources/lang/ko_KR/errors.yml @@ -0,0 +1,19 @@ +--- +http: + msg-403: 이 페이지의 액세스 권한이 없습니다. + msg-404: 여기에 아무것도 없어! + msg-500: 나중에 다시 시도해주십시오. + msg-503: The application is now in maintenance mode. + method-not-allowed: 지원되지 않는 방법입니다. + csrf-token-mismatch: Token does not match, try reloading the page. + ie: Your browser isn't supported. Please switch to other modern browsers, such as Firefox or Chrome. +general: + title: 오류가 발생했습니다 +exception: + code: '오류 코드: :code' + detail: 'Details: :msg' + message: | + Whoops, looks like something went wrong. (enable APP_DEBUG in .env to see details) +plugins: + duplicate: The plugin [:dir1] has a duplicated plugin name definition which is same to plugin [:dir2]. Please check your plugins directory, remove one of them or use another name definition. + boot: There is something wrong with plugin ":plugin". diff --git a/resources/lang/ko_KR/front-end.yml b/resources/lang/ko_KR/front-end.yml new file mode 100755 index 0000000..69755ea --- /dev/null +++ b/resources/lang/ko_KR/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: 로그인 + loggingIn: 로그인 중 + tooManyFails: + captcha: 시도 회수 초과! CAPTCHA인증를 해주세요. + recaptcha: 시도 회수 초과! reCAPTCHA인증를 해주세요. + emptyEmail: 이메일주소를 입력해주세요. + invalidConfirmPwd: 비밀번호가 일치하지 않음. + emptyNickname: 닉네임을 입력해 주세요. + register: 회원가입 + registering: 등록하는 중... + send: 전송 + sending: 전송 중... + reset: 재설정 + resetting: 재설정 중... + nickname: 닉네임 + player-name: Minecraft 사용자명 + email: 이메일 + identification: 이메일 또는 플레이어명 + password: 비밀번호 + captcha: CAPTCHA 보안 문자 + change-captcha: Click to change CAPTCHA image. + login-link: 이미 등록했다면 나를 클릭해서 로그인하세요. + forgot-link: 비밀번호를 잊으셨나요? + keep: 로그인 상태 기억하기 + repeat-pwd: 비밀번호를 재입력하세요 + nickname-intro: 특수문자 외의 문자 사용가능 + player-name-intro: 인게임 닉네임은 나중에도 변경 가능 합니다 + forgot: + login-link: 오잉? 기억난 네요 +skinlib: + private: 비공개 + anonymous: 우선 로그인하십시오. + reset: 필터 초기화 + addToCloset: 스킨 옷장에 추가 + removeFromCloset: 스킨 옷장에 삭제 + setItemName: Set a name for this texture + applyNotice: You can apply it to player at your closet + emptyItemName: Empty texture name. + setNewTextureName: 'Please enter the new texture name:' + emptyNewTextureName: Empty new texture name. + seeMyUpload: 나의 업로드 + apply: 적용하기 + filter: + skin: (Any Model) + steve: (Steve) + alex: (Alex) + cape: (Cape) + uploader: '사용자 (UID = :uid) 가 업로드함' + allUsers: 모든 사용자 + sort: + title: 정렬 + time: 최신 항목 + likes: 좋아요순 + emptyTextureName: Empty texture name. + emptyUploadFile: 아직 파일을 업로드하지 않았습니다! + fileExtError: 'PNG 형식의 파일이어야 합니다.' + uploading: 업로드 중... + setAsPrivate: Set as Private + setAsPublic: Set as Public + setPublicNotice: Sure to set this as public texture? + setPrivateNotice: Sure to set this as private texture? + deleteNotice: Are you sure to delete this texture? + setNewTextureModel: "Please select a new texture model:" + upload: + texture-name: Texture Name + texture-type: Texture Type + select-file: Select File + privacy-notice: Prevent it from being visible at skin library. + set-as-private: Make it Private + button: Upload + cost: It costs you about :score score. + award: You'll be awarded :score score(s) by uploading public texture. + show: + anonymous: You must login to use closets + likes: People who like this + detail: Details + name: Texture Name + edit: Edit + model: Applicable Model + size: File Size + uploader: Uploader + upload-at: Upload At + download: Download + delete-texture: Delete Texture + manage-notice: The texture which was deleted or setted to private will be removed from the closet of everyone who had favorited it. + report: + title: Report + reason: Tell us reason please. + positive: To encourage positive contributions to the skinlib, we will reward who reported inappropriate content with :score scores. However, if any malicious reporting behaviors were found, all scores rewarded will be taken back. + negative: To mitigate the impact of malicious reports, we will require :score scores for submitting a texture report. Don't worry. The suspended scores and additional reward will be sent to your account after your report reviewed by administrators. +user: + signRemainingTime: 'Available after :time :unit' + timeUnitHour: h + timeUnitMin: min + emptyClosetMsg: >- +

Nothing in your closet...

Why not explore the Skin Library for a while?

+ renameItem: Rename item + removeItem: Remove from closet + setAsAvatar: Set as avatar + viewInSkinlib: View in skin library + switch2dPreview: Switch to 2D Preview + switch3dPreview: Switch to 3D Preview + removeFromClosetNotice: Sure to remove this texture from your closet? + emptySelectedTexture: No texture is selected. + renameClosetItem: 'Set a new name for this item:' + changePlayerName: 'Please enter the player name:' + emptyPlayerName: Empty player name. + deletePlayer: Sure to delete this player? + deletePlayerNotice: It's permanent. No backups. + chooseClearTexture: Choose texture types you want to clear + noClearChoice: You haven't choose any types + setAvatar: Sure to set this as your avatar? + setAvatarNotice: The head segment of skin will bu used. + resetAvatarConfirm: Are you sure to reset your avatar? + typeToSearch: Type to search + useAs: Apply... + resetSelected: Clear selected + closet: + upload: Upload Texture + use-as: + title: Which player should be applied to? + empty: It seems that you own no player... + used: + title: Resources Used + players: Registered players + storage: Storage used + cur-score: Current Score + score-notice: Click the score to show introduction. + sign: Sign + player: + operation: Operations + edit-pname: Edit Name + delete-texture: Clear Textures + delete-player: Delete + add-player: Add new player + texture-empty: Nothing + verification: + title: Verify Your Account + message: You must verify your email address before using the skin hosting service. Haven't received the email? + resend: Click here to send again. + sending: Sending... + oauth: + id: Client ID + name: App Name + secret: Client Secret + redirect: Callback URL + modifyName: Modify app name. + modifyUrl: Modify callback URL. + create: Create New App + confirmRemove: Are you sure to delete this app? You won't be able to undo this. +admin: + operationsTitle: Operations + permission: Permission + deleteUser: Delete + changeEmail: Edit Email + newUserEmail: 'Please enter the new email:' + verification: Email Verification + toggleVerification: Toggle Verification Status + changeNickName: Edit Nickname + newUserNickname: 'Please enter the new nickname:' + changePassword: Edit Password + newUserPassword: 'Please enter the new password:' + changeScore: Edit Score + newScore: 'Please enter the new score:' + changePermission: Change permission + newPermission: 'Please select new permission:' + deleteUserNotice: Are you sure to delete this user? It' permanent. + banned: Banned + normal: Normal + admin: Admin + superAdmin: Super Admin + unverified: Unverified + verified: Verified + pidNotice: >- + Please enter the tid of texture. Inputing 0 can clear texture of this player. + changeTexture: Change Textures + changePlayerName: Change Player Name + changeOwner: Change Owner + textureType: Texture Type + deletePlayer: Delete + changePlayerOwner: 'Please enter the id of user which this player should be transferred to:' + deletePlayerNotice: Are you sure to delete this player? It' permanent. + changePlayerNameNotice: 'Please input new player name:' + emptyPlayerName: Player name cannot be empty. + configurePlugin: Configure + deletePlugin: Delete + noDependencies: No Dependencies + pluginTitle: Plugin + pluginAuthor: Author + pluginVersion: Version + pluginReadme: Read Me + pluginDescription: Description + pluginDependencies: Dependencies + installPlugin: Install + pluginInstalling: Installing... + updatePlugin: Update + pluginUpdating: Updating... + confirmUpdate: Are you sure to update ":plugin" from :old to :new? + enablePlugin: Enable + disablePlugin: Disable + confirmDeletion: Are you sure to delete this plugin? + uploadArchive: Upload Archive + uploadArchiveNotice: Install a plugin by uploading a Zip archive. + downloadRemote: Download From Remote + downloadRemoteNotice: Install a plugin by downloading a Zip archive from remote URL. + updateButton: Update Now + downloading: Downloading... + i18n: + group: Group + key: Key + text: Text + empty: (Empty) + modify: Modify + delete: Delete + updating: 'Please type new text:' + confirmDelete: Are you sure? This is irreversible. +report: + tid: Texture ID + reporter: Reporter + reason: Reason + status-title: Status + status: + - Pending + - Resolved + - Rejected + time: Report Time + delete: Delete + ban: Ban + reject: Reject +general: + skin: Skin + cape: Cape + fatalError: Fatal Error + confirmLogout: Sure to log out? + confirm: OK + cancel: Cancel + submit: Submit + close: Close + more: More + tip: Tip + noResult: No result. + texturePreview: Texture Preview + walk: Walk + run: Run + rotation: Rotation + pause: Pause + reset: Reset + skinlib: Skin Library + wait: Please wait... + csrf: This page is out-dated. Please refresh it. + user: + email: Email + nickname: Nick Name + score: Score + register-at: Registered At + player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified +colors: + black: Black + white: White + gray: Gray + prev: Previous Background + next: Next Background +vendor: + datatable: + search: Search + prev: Prev + next: Next diff --git a/resources/lang/ko_KR/general.yml b/resources/lang/ko_KR/general.yml new file mode 100755 index 0000000..036fbb1 --- /dev/null +++ b/resources/lang/ko_KR/general.yml @@ -0,0 +1,59 @@ +--- +index: 홈페이지 +skinlib: Skin Library +user-center: 사용자 센터 +logout: 로그아웃 +login: 로그인 +register: 지금 가입하기 +profile: 사용자 프로파일 +admin-panel: 관리자 패널 +explore: 둘러보기 +manage: 관리 +anonymous: 비회원 +back: 뒤로가기 +dashboard: 대시보드 +my-closet: 나의 옷장 +my-reports: 신고내역 +developer: 고급설정 +oauth-manage: OAuth2 앱 +player-manage: 플레이어 +user-manage: 사용자 +report-manage: 신고관리 +plugin-manage: 플러그인 관리 +plugin-market: 플러그인 마켓 +plugin-configs: 플러그인 설정 +customize: 사용자 정의 +i18n: 다국어 +options: 설정 +score-options: Score Options +res-options: 자원설정 +status: 상태 +check-update: 업데이트 확인 +download-update: 업데이트 다운로드 +close: 닫기 +skin: 스킨 +cape: 케이프 +submit: 제출 +cancel: 취소 +yes: true +no: false +op-success: 작업이 완료됨 +unknown: 알 수 없음 +notice: 공지 +illegal-parameters: 파라미터 정확하지 않음 +private: 비공개 +public: 공개 +unexistent-user: 해당 유저를 찾을 수 없습니다. +player-banned: 본 사용자가 정지되었습니다. +texture-deleted: 요청한 택스쳐가 삭재되었습니다 +user: + email: 이메일 + nickname: 닉네임 + password: 비밀번호 + score: Score + register-at: 등록 날짜 +player: + owner: 소유자 + player-name: 플레이어 이름 + previews: Texture Previews + last-modified: 마지막 수정 시간 diff --git a/resources/lang/ko_KR/index.yml b/resources/lang/ko_KR/index.yml new file mode 100755 index 0000000..3f179ae --- /dev/null +++ b/resources/lang/ko_KR/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: 특징 + first: + icon: fa-users + name: Multi-Accounts + desc: 한 이미 가입된 계정에서 여러 유저파일를 만들수있읍니다 + second: + icon: fa-share-alt + name: 공유 + desc: Explore the skin library, send a "like" and share them with your friends. + third: + icon: fa-cloud + name: 무료 + desc: 영원히 무료입니다. 광고도 없고 이용료도 없습니다. +introduction: ':sitename provides the service of uploading and hosting Minecraft skins. By coordinating with skin mods (e.g. CustomSkinLoader), you can choose skin and cape for your game character, and make it visible to other players in Minecraft.' +start: 가입하기 diff --git a/resources/lang/ko_KR/options.yml b/resources/lang/ko_KR/options.yml new file mode 100755 index 0000000..f1a57fa --- /dev/null +++ b/resources/lang/ko_KR/options.yml @@ -0,0 +1,180 @@ +--- +option-saved: Option saved. +homepage: + title: Homepage + home_pic_url: + title: Picture URL at Homepage + hint: Path relative to homepage or full URL, leave empty to use default image. + favicon_url: + title: Website Icon + hint: Path relative to public/ or full URL. + description: The given image must have same width and height (leave blank to use default icon). + transparent_navbar: + title: Transparent Navigation Bar + label: This will enable transparent navigation bar of home page, but it will turn to be normal if page is scrolled to bottom. + hide_intro: + title: Hide Introduction at Bottom + label: Scroll bar will be disabled if this option is enabled, as version 2.x. + fixed_bg: + title: Fixed Background + label: This option will make background fixed, not scrolled with scroll bar. + copyright_prefer: + title: Program Copyright + description: "You can specify a different style of program copyright for each language. To edit a specific language's corresponding program copyright style, please switch to that language and submit your edit.
Warning: Any evil modification applied on the footer program copyright (including deleting, modifying author, changing link target) with out permission is FORBIDDEN. The author reserves the right to pursue relevant responsibilities." + copyright_text: + title: Custom Copyright Text + description: Placeholders are available in custom copyright text. e.g. {site_name} & {site_url}. You can also specify a different footer for each language. To edit a specific language's corresponding footer, please switch to that language and submit your edit. +customJsCss: + title: Custom CSS/JavaScript + message: | + The contents will be attached to <style> and <script> tags.
+ - Here are some useful examples: Examples of Custom CSS & JavaScript + custom_css: CSS + custom_js: JavaScript +rate: + title: Scores + score_per_storage: + title: Storage + addon: scores = 1 KB + private_score_per_storage: + title: Private Storage + addon: scores = 1 KB + hint: Uploading private textures will cost more scores. + score_per_closet_item: + title: Favorites + addon: score = 1 closet item + return_score: + title: Score Return + label: Return scores back to user after deleting players/textures/closet items. + score_per_player: + title: Players + addon: scores = 1 player + user_initial_score: User Initial Score +report: + title: Reporting Textures + reporter_score_modification: + title: Scores for Submitting an Report + description: Set a positive integer value to reward user who submits new reports. Set to a negative value will require scores for submitting reports, and the suspended scores will be available if user's report was resolved. Set to 0 to disable. + reporter_reward_score: + title: Reward the Reporter with Scores If Report Resolved +sign: + title: 체크인 + sign_score: + title: Score Granted + addon1: scores ~ + addon2: scores + sign_gap_time: + title: 체크인 간격시간 + addon: 시 + sign_after_zero: + title: 시각 + label: Users can sign in after 0 everyday. + hint: The above option will be ignored if this is checked. +sharing: + title: Awarding Sharing + score_award_per_texture: + title: Uploader will be rewarded for each uploading texture with + take_back_scores_after_deletion: + title: Return scores + label: Return scores if uploader setting private or deleting texture. + score_award_per_like: + title: Each time the texture is collected, uploader will be rewarded with +general: + title: General Options + site_name: Site Name + site_description: + title: Site Description + description: You can also specify a different site name and description for each language. To edit a specific language's corresponding site name or description text, please switch to that language and submit your edit. + site_url: + title: Site URL + hint: Begin with http(s)://, nerver ends with slash. + register_with_player_name: + title: Register with Player Name + label: Require Minecraft's player name when user register + require_verification: + title: Account Verification + label: Users must verify their email address first. + regs_per_ip: Max accounts of one IP + max_upload_file_size: + title: Max Upload Size + hint: "Limit specified in php.ini: :size" + player_name_rule: + title: Player Name Rule + official: Letters, numbers and underscores (Mojang's official rule) + cjk: Allow CJK Unified Ideographs + utf8: Allow all valid UTF-8 characters (excluding whitespaces) + custom: Use custom rules (regular expression) + custom_player_name_regexp: + title: Custom Player Name Rules + hint: Only takes effect when the above option is set to 'custom'. Leave empty to allow any character. + placeholder: Regular Expressions + player_name_length: + title: Player Name Length + suffix: characters + auto_del_invalid_texture: + title: Invalid Textures + label: Delete invalid textures automatically. + hint: Delete textures records whose file no longer exists from skinlib. + allow_downloading_texture: + title: Downloading Textures + label: Allow users to directly download the source file of a skinlib item. + status_code_for_private: + title: HTTP Code for Rejecting Accessing Private Textures + texture_name_regexp: + title: Texture Name Rules + hint: The RegExp for validating name of uploaded textures. Leave empty to allow any character except single, double quote and backslash. + placeholder: Regular Expressions + content_policy: + title: Content Policy + description: Display content policy at texture uploading page, supporting Markdown. To edit a specific language's corresponding content policy, please switch to that language and submit your edit. +announ: + title: Announcement + announcement: + description: Styling with Markdown is supported. You can also specify a different announcement for each language. To edit a specific language's corresponding announcement, please switch to that language and submit your edit. +meta: + title: SEO tags + meta_keywords: + title: Keywords + hint: Split with commas. + meta_description: + title: Description + hint: Description defined in "general options" will be used if you left it empty. + meta_extras: + title: Other Custom Tags +recaptcha: + recaptcha_invisible: + title: Invisible + label: Enable Invisible Mode +res-warning: This page is ONLY for advanced users. If you aren't familiar with these, please don't modify them! +resources: + title: Resource Files + hint: Please check these options if you enabled CDN for your site. + force_ssl: + title: Force SSL + label: Use HTTPS protocol to load all front-end assets. + hint: Please check if SSL really available before turning on. + auto_detect_asset_url: + title: Assets URL + label: Determine assets url automatically. + description: Please unable this if assets URLs are wrongly generated under a CDN. The site url will be used if this is not enabled. + cache_expire_time: + title: Cache Exipre Time + hint: In seconds, 86400 = one day, 31536000 = one year. + cdn_address: + title: Front-end Assets CDN + hint: Front-end files won't be loaded if URL is unavailable. + description: | + The CDN URL you give must refer to a mirror of /public directory, + all the files of that directory will be loaded as CDN.
+ How to verify? Verify if {Your CDN URL}/app/manifest.json can be accessed. +cache: + title: Cache Configuration + clear: Clear Cache + cleared: Cache has been cleared. + driver: Current cache driver is 「:driver」. + enable_avatar_cache: + title: Avatar + label: Enable caching avatar + enable_preview_cache: + title: Texture Preivew + label: Enable caching texture preivew diff --git a/resources/lang/ko_KR/setup.yml b/resources/lang/ko_KR/setup.yml new file mode 100755 index 0000000..99c3115 --- /dev/null +++ b/resources/lang/ko_KR/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "목표 :type 데이터배이스를 연결할 수 없으니다. 설정를 확인하세요. 서버가 전송된 메세지: :msg" +locked: + title: 이미 설치됨 + text: Blessing Skin Server가 이미 설치 된 겄을 확인되었습니다. 다시 설치하고 싶으면, storage 목록에 있는 install.lock 파일을 삭재하세요. + button: 홈페이지로 돌아가기 +updates: + success: + title: 업데이트 완료 +wizard: + master: + title: Blessing Skin Server 설치 프로그램 + welcome: + title: 환영합니다! + button: 다음 + text: Blessing Skin Server v:version 를 사용 하는겄을 환영합니다! + database: + title: 데이터베이스 + text: The database is used for storing data of Blessing Skin. + type: 데이터베이스 유형 + host: 데이터베이스 주소 + port: 데이터베이스 포트 + username: 데이터베이스 사용자명 + password: 데이터베이스 비밀번호 + db: 데이터베이스 이름 + db-notice: 만약 SQLite를 사용하신다면, SQLite 데이터베이스파일 위치만 입력하고, 따른 데이터베이스 설정가 필요없읍니다. + prefix: Prefix of Database Table (Optional) + prefix-notice: 다른 Blessing Skin서버를 같은 데이터베이스에 설치하지 않은 경우, 본 옵션을 필요없읍니다. + info: + title: Information needed + button: 설치 시작하기 + text: 기본적인 내용이 필요합니다. 잘못 입력한 걱정 필요없어요, 나중에 수정이 가능 하니까요. + admin-email: 관리자의 이메일주소 + admin-notice: 이것은 슈퍼관리자 계정입니다, 따른 관리자를 추가 또는 제거 가능합니다. + nickname: 닉네임 + password: 비밀번호 + pwd-notice: '주의: 본 비밀번호로 로그인이 가능합니다, 안전한 곳으로 저장해주세요.' + confirm-pwd: 암호 확인 + site-name: 사이트명 + site-name-notice: This will be shown on every page. + finish: + title: 설치가 완료되었습니다 + text: Blessing Skin Server가 설치완료됬읍니다! Blessing Skin Sevrer를 이용하는것 감사합니다! diff --git a/resources/lang/ko_KR/skinlib.yml b/resources/lang/ko_KR/skinlib.yml new file mode 100755 index 0000000..2fc935a --- /dev/null +++ b/resources/lang/ko_KR/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: Upload new skin +show: + title: Texture Details + deleted: The requested texture was already deleted. + private: The requested texture is private and only visible to the uploader and admins. +upload: + title: Upload Texture + name-rule: Less than 32 characters and must not contain any special one. + name-rule-regexp: Custom name rules are applied as :regexp + private-score-notice: It will spend you more scores for setting it as private. You will be charged :score scores for per KB storage. + invalid-size: Invalid :type file (width :width, height :height) + invalid-hd-skin: Invalid HD skin (width and height should be divisible by 32) + lack-score: You don't have enough score to upload this texture. + repeated: The texture is already uploaded by someone else. You can add it to your closet directly. + success: Texture :name was uploaded successfully. +delete: + success: The texture was deleted successfully. +privacy: + success: The texture was set to :privacy successfully. +rename: + success: The texture was renamed to :name successfully. +model: + success: The texture's model was changed to :model successfully. +no-permission: You have no permission to moderate this texture. +non-existent: No such texture. +report: + duplicate: You have already reported this texture. The administrators will review it as soon as possible. You can also track the status of your report at User Center. + success: Thanks for reporting! The administrators will review it as soon as possible. diff --git a/resources/lang/ko_KR/user.yml b/resources/lang/ko_KR/user.yml new file mode 100755 index 0000000..cff23be --- /dev/null +++ b/resources/lang/ko_KR/user.yml @@ -0,0 +1,101 @@ +--- +sign-success: Signed successfully. You got :score scores. +announcement: Announcement +no-unread: No new notifications. +verification: + disabled: Email verification is not available. + frequent-mail: You click the send button too fast. Wait for 60 secs, guy. + verified: Your account is already verified. + success: Verification link was sent, please check your inbox. + failed: We failed to send you the verification link. Detailed message :msg + mail: + title: Verify Your Account on :sitename + message: You are receiving this email because someone registered an account with this email address on :sitename. + reset: 'Click here to verify your account: :url' + ignore: If you did not register an account, no further action is required. +score-intro: + title: What is score? + introduction: | + We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually. + Either adding players, uplaoding textures or adding a skinlib item to your closet will consume scores. + :return-score + + New users will get :initial_score scores initially, and you can acquire :score-from ~ :score-to scores by daily signing in. + will-return-score: The score will be returned if you deleted players, uploaded textures or closet items. + no-return-score: The score will NOT be returned if you deleted players, uploaded textures or closet items. + rates: + storage: ':score scores = 1 KB storage' + player: ':score scores = 1 player' + closet: ':score socres = 1 closet item' +closet: + add: + success: Added :name to closet successfully. + repeated: You have already added this texture. + not-found: We cannot find this texture. + lack-score: You don't have enough score to add it to closet. + rename: + success: The item is successfully renamed to :name + remove: + success: The texture was removed from closet successfully. + non-existent: The texture does not exist in your closet. +player: + login-notice: Now you can log in with player names you owned instead email address. + player-name-rule: + official: Player name may only contains letters, numbers and underscores. + cjk: Player name may contains letters, numbers, underscores and CJK Unified Ideographs. + utf8: Player name must be a UTF-8 string. + custom: Custom player name rules are applied on this site. Please contact admins for further information. + player-name-length: The player name should be at least :min characters and not greater than :max characters. + add: + repeated: The player name is already registered. + lack-score: You don't have enough score to add a player. + success: Player :name was added successfully. + delete: + success: Player :name was deleted successfully. + rename: + repeated: This player name is occupied. Please choose another one. + success: Player :old was renamed to :new + set: + success: The texture was applied to player :name successfully. + clear: + success: The textures of player :name was resetted successfully. +profile: + avatar: + title: Change Avatar? + notice: Click the gear icon "" of any skin in your closet, then click "Set as avatar". We will cut the head segment of that skin for you. If there is no icon like this, please try to disable your ADs blocking extension. + wrong-type: You can't set a cape as avatar. + success: New avatar was set successfully. + reset: Reset Avatar + password: + title: Change Password + old: Old Password + new: New Password + confirm: Repeat Password + button: Change password + wrong-password: Wrong original password. + success: Password updated successfully, please log in again. + nickname: + title: Change Nickname + empty: No nickname is set now. + success: Nickname is successfully updated to :nickname + email: + title: Change Email + new: New Email + password: Current Password + button: Change email + wrong-password: Wrong password. + existed: This email address is occupied. + success: Email address updated successfully, please log in again. + delete: + title: Delete Account + notice: Sure to delete your account on :site? + admin: Admin account can not be deleted. + button: Delete my account + modal-title: You need to enter your password to continue + modal-notice: | + You're about to delete your account. + This is permanent! No backups, no restores, no magic undo button. + We warned you, ok? + password: Current Password + wrong-password: Wrong password. + success: Your account is deleted successfully. diff --git a/resources/lang/ko_KR/validation.yml b/resources/lang/ko_KR/validation.yml new file mode 100755 index 0000000..537025d --- /dev/null +++ b/resources/lang/ko_KR/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: ':attribute "을/를" 반드시 동의해야 합니다.' +active_url: ':attribute 은/는 유효한 URL이 아닙니다.' +after: ':attribute "은/는" 반드시 :date 이후 날짜여야 합니다.' +after_or_equal: ':attribute "은/는" :date 이후 날짜이거나 같은 날짜여야 합니다.' +alpha: ':attribute "은/는" 영어로만 입력하실 수 있습니다.' +alpha_dash: ':attribute "을/를" 문자, 숫자, -, _로만 구성하세요.' +alpha_num: ':attribute "은/는" 문자와 숫자만 포함할 수 있습니다.' +array: ':attribute 는 배열이어야 합니다.' +before: ':attribute "은/는" 반드시 :date 이전 날짜여야 합니다.' +before_or_equal: ':attribute "은/는" :date 이전 날짜이거나 같은 날짜여야 합니다.' +between: + numeric: ':attribute "은/는" 반드시 :min에서 :max 사이여야 합니다.' + file: ':attribute 을/를 :min - :max KB로 구성하세요.' + string: ':attribute "은/는" 최소 :min에서 최대 :max까지 입력하실 수 있습니다.' + array: ':attribute "은/는" 반드시 :min에서 :max 사이여야 합니다.' +boolean: ':attribute 은/는 true 또는 false 이어야 합니다.' +captcha: 'Captcha가 틀렸습니다' +confirmed: ':attribute 일치하지 않습니다.' +date: ':attribute 는 잘못된 날짜 입니다.' +date_equals: ':attribute는 :date 와 동일한 날짜여야합니다.' +date_format: ':attribute 은/는 :format 형식과 일치하지 않습니다.' +different: ':attribute 와 :other 는 서로 달라야 합니다.' +digits: ':attribute 는 :digits 자리수여야 합니다.' +digits_between: ':attribute 은/는 반드시 :min에서 :max 사이여야 합니다.' +dimensions: ':attribute의 이미지 크기가 올바르지 않습니다.' +distinct: ':attribute 항목은 중복된 값입니다.' +email: ':attribute 는 유효한 이메일 주소이여야 합니다.' +ends_with: ':attribute 은/는 다음 중 하나로 끝나야 합니다: :values.' +exists: ':attribute 가 유효하지 않습니다.' +file: ':attribute는 파일이어야 합니다.' +filled: ':attribute 항목은 값이 있어야 합니다.' +gt: + numeric: ':attribute의 값은 :value보다 커야 합니다.' + file: ':attribute의 용량은 :value KB 보다 커야 합니다.' + string: ':attribute는 :value자 이상이어야합니다.' + array: ':attribute는 :value개 이상이어야합니다.' +gte: + numeric: ':attribute의 값은 :value보다 같거나 커야 합니다.' + file: ':attribute의 용량은 :value KB 보다 같거나 커야 합니다.' + string: ':attribute의 글자수는 :value 보다 같거나 커야 합니다.' + array: ':attribute의 항목 수는 :value개 보다 같거나 많아야 합니다.' +image: ':attribute 반드시 이미지여야 합니다.' +in: '선택된 :attribute 은/는 올바르지 않습니다.' +in_array: ':other 에 :attribute 가 존재하지 않습니다.' +integer: ':attribute 는 정수이어야 합니다.' +ip: ':attribute은 반드시 유효한 IP 주소여야 합니다.' +ipv4: ':attribute는 유효한 IPv4 주소여야 합니다.' +ipv6: ':attribute는 유효한 IPv6 주소여야 합니다.' +json: ':attribute는 유효한 JSON 문자값이어야 합니다.' +lt: + numeric: ':attribute는 :value 미만이어야합니다.' + file: ':attribute의 용량은 :value kb보다 작아야 합니다.' + string: ':attribute는 :value자 미만이어야합니다.' + array: ':attribute의 항목 수는 :value 개 보다 작아야 합니다.' +lte: + numeric: 'The :attribute must be less than or equal :value.' + file: 'The :attribute must be less than or equal :value kilobytes.' + string: 'The :attribute must be less than or equal :value characters.' + array: 'The :attribute must not have more than :value items.' +max: + numeric: 'The :attribute may not be greater than :max.' + file: 'The :attribute may not be greater than :max kilobytes.' + string: 'The :attribute may not be greater than :max characters.' + array: 'The :attribute may not have more than :max items.' +mimes: 'The :attribute must be a file of type: :values.' +mimetypes: 'The :attribute must be a file of type: :values.' +min: + numeric: 'The :attribute must be at least :min.' + file: 'The :attribute must be at least :min kilobytes.' + string: 'The :attribute must be at least :min characters.' + array: 'The :attribute must have at least :min items.' +not_in: 'The selected :attribute is invalid.' +not_regex: 'The :attribute format is invalid.' +numeric: 'The :attribute must be a number.' +password: The password is incorrect. +present: 'The :attribute field must be present.' +recaptcha: 'reCAPTCHA validation failed.' +regex: 'The :attribute format is invalid.' +required: 'The :attribute field is required.' +required_if: 'The :attribute field is required when :other is :value.' +required_unless: 'The :attribute field is required unless :other is in :values.' +required_with: 'The :attribute field is required when :values is present.' +required_with_all: 'The :attribute field is required when :values are present.' +required_without: 'The :attribute field is required when :values is not present.' +required_without_all: 'The :attribute field is required when none of :values are present.' +same: 'The :attribute and :other must match.' +size: + numeric: 'The :attribute must be :size.' + file: 'The :attribute must be :size kilobytes.' + string: 'The :attribute must be :size characters.' + array: 'The :attribute must contain :size items.' +starts_with: 'The :attribute must start with one of the following: :values.' +string: 'The :attribute must be a string.' +timezone: 'The :attribute must be a valid zone.' +unique: 'The :attribute has already been taken.' +uploaded: 'The :attribute failed to upload.' +url: 'The :attribute format is invalid.' +uuid: 'The :attribute must be a valid UUID.' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: name + player_name: player name + identification: email or player name + email: email + password: password + password_confirmation: 'password confirmation' + title: title + content: content diff --git a/resources/lang/nl_NL/admin.yml b/resources/lang/nl_NL/admin.yml new file mode 100755 index 0000000..2a830f4 --- /dev/null +++ b/resources/lang/nl_NL/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: Regregistreerde Gebruikers + total-players: Spelers + total-textures: Geüploade Textures + disk-usage: Schijfgebruik + overview: Overzicht + texture-uploads: Texture Uploads + user-registration: Gebruikers Registratie +notifications: + send: + title: Verstuur Notificatie + success: Succesvol verzonden! + receiver: + title: Ontvanger + all: Alle Gebruikers + normal: Normale Gebruikers + uid: Opgegeven UID + email: Opgegeven Email + title: Titel + content: Inhoud (Markdown wordt ondersteund.) +users: + operations: + non-existent: Deze gebruiker bestaat niet. + no-permission: Je hebt geen permissie om deze speler te bewerken. + email: + success: E-mail succesvol gewijzigd. + verification: + success: Account verificatiestatus succesvol ingevuld. + nickname: + success: Naam succesvol aangepast. + password: + success: Wachtwoord succesvol gewijzigd. + score: + success: Score succesvol aangepast. + permission: Toestemming bijgewerkt. + delete: + success: Het account is succesvol verwijderd. +players: + no-permission: Je hebt niet langer meer permissie om deze speler te beheersen. + textures: + non-existent: Geen van deze tekstuur tid.:tid + success: De tekstuur van :speler is bijgewerkt. + name: + success: Spelernaam is veranderd naar :player + owner: + success: De speler :player was getransporteerd naar speler :user. + delete: + success: The player has been deleted successfully. +customize: + change-color: + title: Change Theme Color + colors: + navbar: Top Navigation Bar + sidebar: + dark: Sidebar (Dark) + light: Sidebar (Light) +i18n: + add: Add New Language Line + added: Language line added. + updated: Language line updated. + deleted: Language line deleted. + group: Group + key: Key + text: Text + tip: How can I use this page? +status: + info: Information + health: Health + bs: + name: Blessing Skin + version: Version + env: Application Environment + debug: Debugging or Not? + commit: Commit + laravel: Laravel Version + server: + name: Server + php: PHP Version + web: Web Server Software + os: OS + db: + name: Database + type: Server + host: Host + port: Port + username: Username + database: Database + prefix: Table Prefix + plugins: Enabled Plugins (:amount) +plugins: + readme: Read Me + operations: + title: Operations + enabled: ':plugin has been enabled.' + unsatisfied: + notice: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't enable it. Please install or update the plugins listed below, and disable those have conflicts. + disabled: 'The ":name" plugin is not enabled.' + version: 'The version of ":title" does not satisfies the constraint ":constraint".' + conflict: 'The ":title" plugin cannot run with this plugin at the same time.' + disabled: ':plugin has been disabled.' + deleted: The plugin was deleted successfully. + no-config-notice: The plugin is not installed or doesn't provide a configuration page. + no-readme-notice: The plugin doesn't contain a readme file. + not-found: No such plugin. + market: + unresolved: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't download it. Please install or update the plugins listed below, and disable those have conflicts. + connection-error: Unable to connect to the plugins registry. :error + non-existent: The plugin :plugin does not exist. + install-success: Plugin was installed. +update: + complete: Update completed + info: + title: Update Information + up-to-date: Already up-to-date. + available: New version available. + versions: + latest: "Latest Version:" + current: "Current Version:" + check-github: Check GitHub Releases + button: Update Now + cautions: + title: Cautions + link: check out this. + text: | + Please choose update source according to your host's network environment. + Low-speed connection between update source and your host will cause long-time loading at checking and downloading page. + To change the default update source, + errors: + connection: "Unable to access to current update source. Details: :error" + spec: Current update source is not supported. + php: Your PHP version is too low to update. Requires :version or later. +download: + errors: + download: 'Failed to download. Error: :error' + shasum: File validation failed. Please download again. + unzip: Failed to unpack files. +invalid-action: Invalid action diff --git a/resources/lang/nl_NL/auth.yml b/resources/lang/nl_NL/auth.yml new file mode 100755 index 0000000..99d54ee --- /dev/null +++ b/resources/lang/nl_NL/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: Log In + message: Log in to manage your skin & players + success: Logged in successfully. +check: + anonymous: Illegal access. Please log in first. + verified: To access this page, you should verify your email address first. + admin: Only admins are permitted to access this page. + banned: You are banned on this site. Please contact the admin. +register: + title: Register + message: Welcome to :sitename! + success: Your account was registered. Redirecting... + max: You can't register more than :regs accounts. +forgot: + title: Forgot Password + message: We will send you an E-mail to verify. + disabled: Password resetting is not available. + frequent-mail: You click the send button too fast. Wait for some minutes. + unregistered: The email address is not registered. + success: Mail sent, please check your inbox. The link will be expired in 1 hour. + failed: Failed to send verification mail. :msg + ignore: If you haven't signed up on our site, please ignore this email. No unsubscribing is required. + reset: Reset your password + notice: This mail is sending automatically, no reponses will be sent if you reply. + mail: + title: Reset your password on :sitename + message: You are receiving this email because we received a password reset request for your account on :sitename. + reset: 'To reset your password, please visit: :url' + ignore: If you did not request a password reset, no further action is required. +reset: + title: Reset Password + button: Reset + invalid: Invalid link. + expired: This link is expired. + message: ':username, reset your password here.' + success: Password resetted successfully. +bind: + title: Bind Email + button: Bind + message: You need to provide your email adderss to continue. + introduction: We won't send you any spam. + registered: The email address was already taken. +verify: + title: Email Verification + invalid: Invalid link. + not-matched: Email doesn't match. +validation: + user: No such user. + password: Wrong password. +logout: + success: You are now logged out. +oauth: + authorization: + title: Authorization + introduction: A 3rd-party application ":name" is requesting permission to access your account. + button: Authorize + permissions: Permissions + scope: + user: + read: Sign you in and read your profile + notification: + read: Allows the app to read your notifications. + readwrite: Allows the app to send notifications. + player: + read: Allows the app to read your players. + readwrite: Allows the app to create, read, update and delete your players. + closet: + read: Allows the app to read your closet items. + readwrite: Allows the app to create, read, update and delete your closet items. + users-management: + read: Allows the app to read site's users. + readwrite: Allows the app to create, read, update and delete site's users. + players-management: + read: Allows the app to read site's players. + readwrite: Allows the app to create, read, update and delete site's players. + closet-management: + read: Allows the app to read user's of your site closet items. + readwrite: Allows the app to create, read, update and delete user's closet items. + reports-management: + read: Allows the app to read user's reports. + readwrite: Allows the app to read and review user's reports. +email: Email +register-link: Register a new account diff --git a/resources/lang/nl_NL/errors.yml b/resources/lang/nl_NL/errors.yml new file mode 100755 index 0000000..2bc388c --- /dev/null +++ b/resources/lang/nl_NL/errors.yml @@ -0,0 +1,19 @@ +--- +http: + msg-403: You have no permission to access this page. + msg-404: Nothing here. + msg-500: Please try again later. + msg-503: The application is now in maintenance mode. + method-not-allowed: Method not allowed. + csrf-token-mismatch: Token does not match, try reloading the page. + ie: Your browser isn't supported. Please switch to other modern browsers, such as Firefox or Chrome. +general: + title: Error occurred +exception: + code: 'Error code: :code' + detail: 'Details: :msg' + message: | + Whoops, looks like something went wrong. (enable APP_DEBUG in .env to see details) +plugins: + duplicate: The plugin [:dir1] has a duplicated plugin name definition which is same to plugin [:dir2]. Please check your plugins directory, remove one of them or use another name definition. + boot: There is something wrong with plugin ":plugin". diff --git a/resources/lang/nl_NL/front-end.yml b/resources/lang/nl_NL/front-end.yml new file mode 100755 index 0000000..0438480 --- /dev/null +++ b/resources/lang/nl_NL/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: Log In + loggingIn: Logging In + tooManyFails: + captcha: You fails too many times! Please enter the CAPTCHA. + recaptcha: You fails too many times! Please pass the reCAPTCHA challenge. + emptyEmail: Empty email address. + invalidConfirmPwd: Confirming password is not equal with password. + emptyNickname: Empty nickname. + register: Register + registering: Registering + send: Send + sending: Sending + reset: Reset + resetting: Resetting + nickname: Nickname + player-name: Minecraft player name + email: Email + identification: Email or player name + password: Password + captcha: CAPTCHA + change-captcha: Click to change CAPTCHA image. + login-link: Already registered? Log in here. + forgot-link: Forgot password? + keep: Remember me + repeat-pwd: Repeat your password + nickname-intro: Whatever you like expect special characters + player-name-intro: Player name in Minecraft, can be changed later + forgot: + login-link: I do remember it +skinlib: + private: Private + anonymous: Please login first. + reset: Reset Filter + addToCloset: Add to closet + removeFromCloset: Remove from closet + setItemName: Set a name for this texture + applyNotice: You can apply it to player at your closet + emptyItemName: Empty texture name. + setNewTextureName: 'Please enter the new texture name:' + emptyNewTextureName: Empty new texture name. + seeMyUpload: My Uploads + apply: Apply + filter: + skin: (Any Model) + steve: (Steve) + alex: (Alex) + cape: (Cape) + uploader: 'User (UID = :uid) Uploaded' + allUsers: All Users + sort: + title: Sort + time: Latest + likes: Most Likes + emptyTextureName: Empty texture name. + emptyUploadFile: You have not uploaded any file. + fileExtError: 'Error: Textures should be PNG files.' + uploading: Uploading + setAsPrivate: Set as Private + setAsPublic: Set as Public + setPublicNotice: Sure to set this as public texture? + setPrivateNotice: Sure to set this as private texture? + deleteNotice: Are you sure to delete this texture? + setNewTextureModel: "Please select a new texture model:" + upload: + texture-name: Texture Name + texture-type: Texture Type + select-file: Select File + privacy-notice: Prevent it from being visible at skin library. + set-as-private: Make it Private + button: Upload + cost: It costs you about :score score. + award: You'll be awarded :score score(s) by uploading public texture. + show: + anonymous: You must login to use closets + likes: People who like this + detail: Details + name: Texture Name + edit: Edit + model: Applicable Model + size: File Size + uploader: Uploader + upload-at: Upload At + download: Download + delete-texture: Delete Texture + manage-notice: The texture which was deleted or setted to private will be removed from the closet of everyone who had favorited it. + report: + title: Report + reason: Tell us reason please. + positive: To encourage positive contributions to the skinlib, we will reward who reported inappropriate content with :score scores. However, if any malicious reporting behaviors were found, all scores rewarded will be taken back. + negative: To mitigate the impact of malicious reports, we will require :score scores for submitting a texture report. Don't worry. The suspended scores and additional reward will be sent to your account after your report reviewed by administrators. +user: + signRemainingTime: 'Available after :time :unit' + timeUnitHour: h + timeUnitMin: min + emptyClosetMsg: >- +

Nothing in your closet...

Why not explore the Skin Library for a while?

+ renameItem: Rename item + removeItem: Remove from closet + setAsAvatar: Set as avatar + viewInSkinlib: View in skin library + switch2dPreview: Switch to 2D Preview + switch3dPreview: Switch to 3D Preview + removeFromClosetNotice: Sure to remove this texture from your closet? + emptySelectedTexture: No texture is selected. + renameClosetItem: 'Set a new name for this item:' + changePlayerName: 'Please enter the player name:' + emptyPlayerName: Empty player name. + deletePlayer: Sure to delete this player? + deletePlayerNotice: It's permanent. No backups. + chooseClearTexture: Choose texture types you want to clear + noClearChoice: You haven't choose any types + setAvatar: Sure to set this as your avatar? + setAvatarNotice: The head segment of skin will bu used. + resetAvatarConfirm: Are you sure to reset your avatar? + typeToSearch: Type to search + useAs: Apply... + resetSelected: Clear selected + closet: + upload: Upload Texture + use-as: + title: Which player should be applied to? + empty: It seems that you own no player... + used: + title: Resources Used + players: Registered players + storage: Storage used + cur-score: Current Score + score-notice: Click the score to show introduction. + sign: Sign + player: + operation: Operations + edit-pname: Edit Name + delete-texture: Clear Textures + delete-player: Delete + add-player: Add new player + texture-empty: Nothing + verification: + title: Verify Your Account + message: You must verify your email address before using the skin hosting service. Haven't received the email? + resend: Click here to send again. + sending: Sending... + oauth: + id: Client ID + name: App Name + secret: Client Secret + redirect: Callback URL + modifyName: Modify app name. + modifyUrl: Modify callback URL. + create: Create New App + confirmRemove: Are you sure to delete this app? You won't be able to undo this. +admin: + operationsTitle: Operations + permission: Permission + deleteUser: Delete + changeEmail: Edit Email + newUserEmail: 'Please enter the new email:' + verification: Email Verification + toggleVerification: Toggle Verification Status + changeNickName: Edit Nickname + newUserNickname: 'Please enter the new nickname:' + changePassword: Edit Password + newUserPassword: 'Please enter the new password:' + changeScore: Edit Score + newScore: 'Please enter the new score:' + changePermission: Change permission + newPermission: 'Please select new permission:' + deleteUserNotice: Are you sure to delete this user? It' permanent. + banned: Banned + normal: Normal + admin: Admin + superAdmin: Super Admin + unverified: Unverified + verified: Verified + pidNotice: >- + Please enter the tid of texture. Inputing 0 can clear texture of this player. + changeTexture: Change Textures + changePlayerName: Change Player Name + changeOwner: Change Owner + textureType: Texture Type + deletePlayer: Delete + changePlayerOwner: 'Please enter the id of user which this player should be transferred to:' + deletePlayerNotice: Are you sure to delete this player? It' permanent. + changePlayerNameNotice: 'Please input new player name:' + emptyPlayerName: Player name cannot be empty. + configurePlugin: Configure + deletePlugin: Delete + noDependencies: No Dependencies + pluginTitle: Plugin + pluginAuthor: Author + pluginVersion: Version + pluginReadme: Read Me + pluginDescription: Description + pluginDependencies: Dependencies + installPlugin: Install + pluginInstalling: Installing... + updatePlugin: Update + pluginUpdating: Updating... + confirmUpdate: Are you sure to update ":plugin" from :old to :new? + enablePlugin: Enable + disablePlugin: Disable + confirmDeletion: Are you sure to delete this plugin? + uploadArchive: Upload Archive + uploadArchiveNotice: Install a plugin by uploading a Zip archive. + downloadRemote: Download From Remote + downloadRemoteNotice: Install a plugin by downloading a Zip archive from remote URL. + updateButton: Update Now + downloading: Downloading... + i18n: + group: Group + key: Key + text: Text + empty: (Empty) + modify: Modify + delete: Delete + updating: 'Please type new text:' + confirmDelete: Are you sure? This is irreversible. +report: + tid: Texture ID + reporter: Reporter + reason: Reason + status-title: Status + status: + - Pending + - Resolved + - Rejected + time: Report Time + delete: Delete + ban: Ban + reject: Reject +general: + skin: Skin + cape: Cape + fatalError: Fatal Error + confirmLogout: Sure to log out? + confirm: OK + cancel: Cancel + submit: Submit + close: Close + more: More + tip: Tip + noResult: No result. + texturePreview: Texture Preview + walk: Walk + run: Run + rotation: Rotation + pause: Pause + reset: Reset + skinlib: Skin Library + wait: Please wait... + csrf: This page is out-dated. Please refresh it. + user: + email: Email + nickname: Nick Name + score: Score + register-at: Registered At + player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified +colors: + black: Black + white: White + gray: Gray + prev: Previous Background + next: Next Background +vendor: + datatable: + search: Search + prev: Prev + next: Next diff --git a/resources/lang/nl_NL/general.yml b/resources/lang/nl_NL/general.yml new file mode 100755 index 0000000..1fe8c6a --- /dev/null +++ b/resources/lang/nl_NL/general.yml @@ -0,0 +1,59 @@ +--- +index: Homepage +skinlib: Skin Library +user-center: User Center +logout: Log Out +login: Log In +register: Register Now +profile: User Profile +admin-panel: Admin Panel +explore: Explore +manage: Manage +anonymous: Guest +back: Back +dashboard: Dashboard +my-closet: Closet +my-reports: Reports +developer: Advanced +oauth-manage: OAuth2 Apps +player-manage: Players +user-manage: Users +report-manage: Reports +plugin-manage: Plugins +plugin-market: Plugin Market +plugin-configs: Plugin Configs +customize: Customize +i18n: Internationalization +options: Options +score-options: Score Options +res-options: Resource Options +status: Status +check-update: Check Update +download-update: Download Updates +close: Close +skin: Skin +cape: Cape +submit: Submit +cancel: Cancel +yes: true +no: false +op-success: Operated successfully. +unknown: Unknown +notice: Notice +illegal-parameters: Illegal parameters. +private: Private +public: Public +unexistent-user: No such user. +player-banned: The owner of this player has been banned. +texture-deleted: The requested texture has been deleted. +user: + email: Email + nickname: Nickname + password: Password + score: Score + register-at: Registered At +player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified diff --git a/resources/lang/nl_NL/index.yml b/resources/lang/nl_NL/index.yml new file mode 100755 index 0000000..bba2e21 --- /dev/null +++ b/resources/lang/nl_NL/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: Features + first: + icon: fa-users + name: Multi Player + desc: You can add multiple players within one registered account. + second: + icon: fa-share-alt + name: Sharing + desc: Explore the skin library, send a "like" and share them with your friends. + third: + icon: fa-cloud + name: Free + desc: It is free forever. No ads. No subscription fees. +introduction: ':sitename provides the service of uploading and hosting Minecraft skins. By coordinating with skin mods (e.g. CustomSkinLoader), you can choose skin and cape for your game character, and make it visible to other players in Minecraft.' +start: Join Us diff --git a/resources/lang/nl_NL/options.yml b/resources/lang/nl_NL/options.yml new file mode 100755 index 0000000..76c6421 --- /dev/null +++ b/resources/lang/nl_NL/options.yml @@ -0,0 +1,180 @@ +--- +option-saved: Option saved. +homepage: + title: Homepage + home_pic_url: + title: Picture URL at Homepage + hint: Path relative to homepage or full URL, leave empty to use default image. + favicon_url: + title: Website Icon + hint: Path relative to public/ or full URL. + description: The given image must have same width and height (leave blank to use default icon). + transparent_navbar: + title: Transparent Navigation Bar + label: This will enable transparent navigation bar of home page, but it will turn to be normal if page is scrolled to bottom. + hide_intro: + title: Hide Introduction at Bottom + label: Scroll bar will be disabled if this option is enabled, as version 2.x. + fixed_bg: + title: Fixed Background + label: This option will make background fixed, not scrolled with scroll bar. + copyright_prefer: + title: Program Copyright + description: "You can specify a different style of program copyright for each language. To edit a specific language's corresponding program copyright style, please switch to that language and submit your edit.
Warning: Any evil modification applied on the footer program copyright (including deleting, modifying author, changing link target) with out permission is FORBIDDEN. The author reserves the right to pursue relevant responsibilities." + copyright_text: + title: Custom Copyright Text + description: Placeholders are available in custom copyright text. e.g. {site_name} & {site_url}. You can also specify a different footer for each language. To edit a specific language's corresponding footer, please switch to that language and submit your edit. +customJsCss: + title: Custom CSS/JavaScript + message: | + The contents will be attached to <style> and <script> tags.
+ - Here are some useful examples: Examples of Custom CSS & JavaScript + custom_css: CSS + custom_js: JavaScript +rate: + title: Scores + score_per_storage: + title: Storage + addon: scores = 1 KB + private_score_per_storage: + title: Private Storage + addon: scores = 1 KB + hint: Uploading private textures will cost more scores. + score_per_closet_item: + title: Favorites + addon: score = 1 closet item + return_score: + title: Score Return + label: Return scores back to user after deleting players/textures/closet items. + score_per_player: + title: Players + addon: scores = 1 player + user_initial_score: User Initial Score +report: + title: Reporting Textures + reporter_score_modification: + title: Scores for Submitting an Report + description: Set a positive integer value to reward user who submits new reports. Set to a negative value will require scores for submitting reports, and the suspended scores will be available if user's report was resolved. Set to 0 to disable. + reporter_reward_score: + title: Reward the Reporter with Scores If Report Resolved +sign: + title: Signing + sign_score: + title: Score Granted + addon1: scores ~ + addon2: scores + sign_gap_time: + title: Gap Time + addon: hours + sign_after_zero: + title: Time + label: Users can sign in after 0 everyday. + hint: The above option will be ignored if this is checked. +sharing: + title: Awarding Sharing + score_award_per_texture: + title: Uploader will be rewarded for each uploading texture with + take_back_scores_after_deletion: + title: Return scores + label: Return scores if uploader setting private or deleting texture. + score_award_per_like: + title: Each time the texture is collected, uploader will be rewarded with +general: + title: General Options + site_name: Site Name + site_description: + title: Site Description + description: You can also specify a different site name and description for each language. To edit a specific language's corresponding site name or description text, please switch to that language and submit your edit. + site_url: + title: Site URL + hint: Begin with http(s)://, nerver ends with slash. + register_with_player_name: + title: Register with Player Name + label: Require Minecraft's player name when user register + require_verification: + title: Account Verification + label: Users must verify their email address first. + regs_per_ip: Max accounts of one IP + max_upload_file_size: + title: Max Upload Size + hint: "Limit specified in php.ini: :size" + player_name_rule: + title: Player Name Rule + official: Letters, numbers and underscores (Mojang's official rule) + cjk: Allow CJK Unified Ideographs + utf8: Allow all valid UTF-8 characters (excluding whitespaces) + custom: Use custom rules (regular expression) + custom_player_name_regexp: + title: Custom Player Name Rules + hint: Only takes effect when the above option is set to 'custom'. Leave empty to allow any character. + placeholder: Regular Expressions + player_name_length: + title: Player Name Length + suffix: characters + auto_del_invalid_texture: + title: Invalid Textures + label: Delete invalid textures automatically. + hint: Delete textures records whose file no longer exists from skinlib. + allow_downloading_texture: + title: Downloading Textures + label: Allow users to directly download the source file of a skinlib item. + status_code_for_private: + title: HTTP Code for Rejecting Accessing Private Textures + texture_name_regexp: + title: Texture Name Rules + hint: The RegExp for validating name of uploaded textures. Leave empty to allow any character except single, double quote and backslash. + placeholder: Regular Expressions + content_policy: + title: Content Policy + description: Display content policy at texture uploading page, supporting Markdown. To edit a specific language's corresponding content policy, please switch to that language and submit your edit. +announ: + title: Announcement + announcement: + description: Styling with Markdown is supported. You can also specify a different announcement for each language. To edit a specific language's corresponding announcement, please switch to that language and submit your edit. +meta: + title: SEO tags + meta_keywords: + title: Keywords + hint: Split with commas. + meta_description: + title: Description + hint: Description defined in "general options" will be used if you left it empty. + meta_extras: + title: Other Custom Tags +recaptcha: + recaptcha_invisible: + title: Invisible + label: Enable Invisible Mode +res-warning: This page is ONLY for advanced users. If you aren't familiar with these, please don't modify them! +resources: + title: Resource Files + hint: Please check these options if you enabled CDN for your site. + force_ssl: + title: Force SSL + label: Use HTTPS protocol to load all front-end assets. + hint: Please check if SSL really available before turning on. + auto_detect_asset_url: + title: Assets URL + label: Determine assets url automatically. + description: Please unable this if assets URLs are wrongly generated under a CDN. The site url will be used if this is not enabled. + cache_expire_time: + title: Cache Exipre Time + hint: In seconds, 86400 = one day, 31536000 = one year. + cdn_address: + title: Front-end Assets CDN + hint: Front-end files won't be loaded if URL is unavailable. + description: | + The CDN URL you give must refer to a mirror of /public directory, + all the files of that directory will be loaded as CDN.
+ How to verify? Verify if {Your CDN URL}/app/manifest.json can be accessed. +cache: + title: Cache Configuration + clear: Clear Cache + cleared: Cache has been cleared. + driver: Current cache driver is 「:driver」. + enable_avatar_cache: + title: Avatar + label: Enable caching avatar + enable_preview_cache: + title: Texture Preivew + label: Enable caching texture preivew diff --git a/resources/lang/nl_NL/setup.yml b/resources/lang/nl_NL/setup.yml new file mode 100755 index 0000000..dff74a3 --- /dev/null +++ b/resources/lang/nl_NL/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "Unable to connect to the target :type database, please check your configuration. The server replied with: :msg" +locked: + title: Already installed + text: It appears that you have already installed Blessing Skin Server. To reinstall, please delete the "install.lock" file under "storage" directory. + button: Back to homepage +updates: + success: + title: Update complete +wizard: + master: + title: Install Wizard - Blessing Skin Server + welcome: + title: Welcome + button: Next + text: Welcome to Blessing Skin Server v:version! + database: + title: Database + text: The database is used for storing data of Blessing Skin. + type: Database Type + host: Database Host + port: Database Port + username: Database Username + password: Database Password + db: Database Name + db-notice: You should provide the path to SQLite file and there is no need to fill other blanks if you use SQLite. + prefix: Prefix of Database Table (Optional) + prefix-notice: You don't need to use this option unless you want to install multiple Blessing Skin Server into one database. + info: + title: Information needed + button: Run install + text: To proceed with the installation, please fill this form with the details of the initial admin account. Don't worry, you can always change these settings later. + admin-email: Admin Email + admin-notice: This is the UNIQUE super admin account who can GIVE or CANCEL other users' admin privilege. + nickname: Nickname + password: Password + pwd-notice: 'Attention: You will need the password to log in. Please keep it at a secure place.' + confirm-pwd: Confirm password + site-name: Site name + site-name-notice: This will be shown on every page. + finish: + title: Installation complete + text: Blessing Skin Server has been installed. Thank you, and enjoy! diff --git a/resources/lang/nl_NL/skinlib.yml b/resources/lang/nl_NL/skinlib.yml new file mode 100755 index 0000000..2fc935a --- /dev/null +++ b/resources/lang/nl_NL/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: Upload new skin +show: + title: Texture Details + deleted: The requested texture was already deleted. + private: The requested texture is private and only visible to the uploader and admins. +upload: + title: Upload Texture + name-rule: Less than 32 characters and must not contain any special one. + name-rule-regexp: Custom name rules are applied as :regexp + private-score-notice: It will spend you more scores for setting it as private. You will be charged :score scores for per KB storage. + invalid-size: Invalid :type file (width :width, height :height) + invalid-hd-skin: Invalid HD skin (width and height should be divisible by 32) + lack-score: You don't have enough score to upload this texture. + repeated: The texture is already uploaded by someone else. You can add it to your closet directly. + success: Texture :name was uploaded successfully. +delete: + success: The texture was deleted successfully. +privacy: + success: The texture was set to :privacy successfully. +rename: + success: The texture was renamed to :name successfully. +model: + success: The texture's model was changed to :model successfully. +no-permission: You have no permission to moderate this texture. +non-existent: No such texture. +report: + duplicate: You have already reported this texture. The administrators will review it as soon as possible. You can also track the status of your report at User Center. + success: Thanks for reporting! The administrators will review it as soon as possible. diff --git a/resources/lang/nl_NL/user.yml b/resources/lang/nl_NL/user.yml new file mode 100755 index 0000000..cff23be --- /dev/null +++ b/resources/lang/nl_NL/user.yml @@ -0,0 +1,101 @@ +--- +sign-success: Signed successfully. You got :score scores. +announcement: Announcement +no-unread: No new notifications. +verification: + disabled: Email verification is not available. + frequent-mail: You click the send button too fast. Wait for 60 secs, guy. + verified: Your account is already verified. + success: Verification link was sent, please check your inbox. + failed: We failed to send you the verification link. Detailed message :msg + mail: + title: Verify Your Account on :sitename + message: You are receiving this email because someone registered an account with this email address on :sitename. + reset: 'Click here to verify your account: :url' + ignore: If you did not register an account, no further action is required. +score-intro: + title: What is score? + introduction: | + We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually. + Either adding players, uplaoding textures or adding a skinlib item to your closet will consume scores. + :return-score + + New users will get :initial_score scores initially, and you can acquire :score-from ~ :score-to scores by daily signing in. + will-return-score: The score will be returned if you deleted players, uploaded textures or closet items. + no-return-score: The score will NOT be returned if you deleted players, uploaded textures or closet items. + rates: + storage: ':score scores = 1 KB storage' + player: ':score scores = 1 player' + closet: ':score socres = 1 closet item' +closet: + add: + success: Added :name to closet successfully. + repeated: You have already added this texture. + not-found: We cannot find this texture. + lack-score: You don't have enough score to add it to closet. + rename: + success: The item is successfully renamed to :name + remove: + success: The texture was removed from closet successfully. + non-existent: The texture does not exist in your closet. +player: + login-notice: Now you can log in with player names you owned instead email address. + player-name-rule: + official: Player name may only contains letters, numbers and underscores. + cjk: Player name may contains letters, numbers, underscores and CJK Unified Ideographs. + utf8: Player name must be a UTF-8 string. + custom: Custom player name rules are applied on this site. Please contact admins for further information. + player-name-length: The player name should be at least :min characters and not greater than :max characters. + add: + repeated: The player name is already registered. + lack-score: You don't have enough score to add a player. + success: Player :name was added successfully. + delete: + success: Player :name was deleted successfully. + rename: + repeated: This player name is occupied. Please choose another one. + success: Player :old was renamed to :new + set: + success: The texture was applied to player :name successfully. + clear: + success: The textures of player :name was resetted successfully. +profile: + avatar: + title: Change Avatar? + notice: Click the gear icon "" of any skin in your closet, then click "Set as avatar". We will cut the head segment of that skin for you. If there is no icon like this, please try to disable your ADs blocking extension. + wrong-type: You can't set a cape as avatar. + success: New avatar was set successfully. + reset: Reset Avatar + password: + title: Change Password + old: Old Password + new: New Password + confirm: Repeat Password + button: Change password + wrong-password: Wrong original password. + success: Password updated successfully, please log in again. + nickname: + title: Change Nickname + empty: No nickname is set now. + success: Nickname is successfully updated to :nickname + email: + title: Change Email + new: New Email + password: Current Password + button: Change email + wrong-password: Wrong password. + existed: This email address is occupied. + success: Email address updated successfully, please log in again. + delete: + title: Delete Account + notice: Sure to delete your account on :site? + admin: Admin account can not be deleted. + button: Delete my account + modal-title: You need to enter your password to continue + modal-notice: | + You're about to delete your account. + This is permanent! No backups, no restores, no magic undo button. + We warned you, ok? + password: Current Password + wrong-password: Wrong password. + success: Your account is deleted successfully. diff --git a/resources/lang/nl_NL/validation.yml b/resources/lang/nl_NL/validation.yml new file mode 100755 index 0000000..53214af --- /dev/null +++ b/resources/lang/nl_NL/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: ':Attribute moet geaccepteerd zijn.' +active_url: ':Attribute is geen geldige URL.' +after: ':Attribute moet een datum na :date zijn.' +after_or_equal: ':Attribute moet een datum na of gelijk aan :date zijn.' +alpha: ':Attribute mag alleen letters bevatten.' +alpha_dash: ':Attribute mag alleen letters, nummers, underscores (_) en streepjes (-) bevatten.' +alpha_num: ':Attribute mag alleen letters en nummers bevatten.' +array: ':Attribute moet geselecteerde elementen bevatten.' +before: ':Attribute moet een datum voor :date zijn.' +before_or_equal: ':Attribute moet een datum voor of gelijk aan :date zijn.' +between: + numeric: ':Attribute moet tussen :min en :max zijn.' + file: ':Attribute moet tussen :min en :max kilobytes zijn.' + string: ':Attribute moet tussen :min en :max karakters zijn.' + array: ':Attribute moet tussen :min en :max items bevatten.' +boolean: ':Attribute moet ja of nee zijn.' +captcha: 'Ongeldige captcha.' +confirmed: ':Attribute bevestiging komt niet overeen.' +date: ':Attribute moet een datum bevatten.' +date_equals: ':Attribute moet een datum gelijk aan :date zijn.' +date_format: ':Attribute moet een geldig datum formaat bevatten.' +different: ':Attribute en :other moeten verschillend zijn.' +digits: ':Attribute moet bestaan uit :digits cijfers.' +digits_between: ':Attribute moet bestaan uit minimaal :min en maximaal :max cijfers.' +dimensions: ':Attribute heeft geen geldige afmetingen voor afbeeldingen.' +distinct: ':Attribute heeft een dubbele waarde.' +email: ':Attribute is geen geldig e-mailadres.' +ends_with: ':Attribute moet met één van de volgende waarden eindigen: :values' +exists: ':Attribute bestaat niet.' +file: ':Attribute moet een bestand zijn.' +filled: ':Attribute is verplicht.' +gt: + numeric: 'De :attribute moet groter zijn dan :value.' + file: 'De :attribute moet groter zijn dan :value kilobytes.' + string: 'De :attribute moet meer dan :value tekens bevatten.' + array: 'De :attribute moet meer dan :value waardes bevatten.' +gte: + numeric: 'De :attribute moet groter of gelijk zijn aan :value.' + file: 'De :attribute moet groter of gelijk zijn aan :value kilobytes.' + string: 'De :attribute moet minimaal :value tekens bevatten.' + array: 'De :attribute moet :value waardes of meer bevatten.' +image: ':Attribute moet een afbeelding zijn.' +in: ':Attribute is ongeldig.' +in_array: ':Attribute bestaat niet in :other.' +integer: ':Attribute moet een getal zijn.' +ip: ':Attribute moet een geldig IP-adres zijn.' +ipv4: ':Attribute moet een geldig IPv4-adres zijn.' +ipv6: ':Attribute moet een geldig IPv6-adres zijn.' +json: ':Attribute moet een geldige JSON-string zijn.' +lt: + numeric: 'De :attribute moet kleiner zijn dan :value.' + file: 'De :attribute moet kleiner zijn dan :value kilobytes.' + string: 'De :attribute moet minder dan :value tekens bevatten.' + array: 'De :attribute moet minder dan :value waardes bevatten.' +lte: + numeric: 'De :attribute moet kleiner of gelijk zijn aan :value.' + file: 'De :attribute moet kleiner of gelijk zijn aan :value kilobytes.' + string: 'De :attribute moet maximaal :value tekens bevatten.' + array: 'De :attribute moet :value waardes of minder bevatten.' +max: + numeric: ':Attribute mag niet hoger dan :max zijn.' + file: ':Attribute mag niet meer dan :max kilobytes zijn.' + string: ':Attribute mag niet uit meer dan :max tekens bestaan.' + array: ':Attribute mag niet meer dan :max items bevatten.' +mimes: ':Attribute moet een bestand zijn van het bestandstype :values.' +mimetypes: ':Attribute moet een bestand zijn van het bestandstype :values.' +min: + numeric: ':Attribute moet minimaal :min zijn.' + file: ':Attribute moet minimaal :min kilobytes zijn.' + string: ':Attribute moet minimaal :min tekens zijn.' + array: ':Attribute moet minimaal :min items bevatten.' +not_in: 'Het formaat van :attribute is ongeldig.' +not_regex: 'De :attribute formaat is ongeldig.' +numeric: ':Attribute moet een nummer zijn.' +password: Wachtwoord is onjuist. +present: ':Attribute moet bestaan.' +recaptcha: 'reCAPATCHA verificatie mislukt.' +regex: ':Attribute formaat is ongeldig.' +required: ':Attribute is verplicht.' +required_if: ':Attribute is verplicht indien :other gelijk is aan :value.' +required_unless: ':Attribute is verplicht tenzij :other gelijk is aan :values.' +required_with: ':Attribute is verplicht i.c.m. :values' +required_with_all: ':Attribute is verplicht i.c.m. :values' +required_without: ':Attribute is verplicht als :values niet ingevuld is.' +required_without_all: ':Attribute is verplicht als :values niet ingevuld zijn.' +same: ':Attribute en :other moeten overeenkomen.' +size: + numeric: ':Attribute moet :size zijn.' + file: ':Attribute moet :size kilobyte zijn.' + string: ':Attribute moet :size tekens zijn.' + array: ':Attribute moet :size items bevatten.' +starts_with: ':Attribute moet starten met een van de volgende: :values' +string: ':Attribute moet een tekst zijn.' +timezone: ':Attribute moet een geldige tijdzone zijn.' +unique: ':Attribute is al in gebruik.' +uploaded: 'Het uploaden van :attribute is mislukt.' +url: ':Attribute moet een geldig URL zijn.' +uuid: ':Attribute moet een geldig UUID zijn.' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: naam + player_name: spelernaam + identification: email of spelernaam + email: e-mailadres + password: wachtwoord + password_confirmation: 'wachtwoordbevestiging' + title: titel + content: inhoud diff --git a/resources/lang/overrides/.gitignore b/resources/lang/overrides/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/resources/lang/overrides/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/resources/lang/pt_PT/admin.yml b/resources/lang/pt_PT/admin.yml new file mode 100755 index 0000000..5cd4d2d --- /dev/null +++ b/resources/lang/pt_PT/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: Registered Users + total-players: Players + total-textures: Uploaded Textures + disk-usage: Disk Usage + overview: Overview + texture-uploads: Texture Uploads + user-registration: User Registration +notifications: + send: + title: Send Notification + success: Sent successfully! + receiver: + title: Receiver + all: All Users + normal: Normal Users + uid: Specified UID + email: Specified Email + title: Title + content: Content (Markdown is supported.) +users: + operations: + non-existent: No such user. + no-permission: You have no permission to operate this user. + email: + success: Email changed successfully. + verification: + success: Account verification status toggled successfully. + nickname: + success: Nickname changed successfully. + password: + success: Password changed successfully. + score: + success: Score changed successfully. + permission: Permission updated. + delete: + success: The account has been deleted successfully. +players: + no-permission: You have no permission to operate this player. + textures: + non-existent: No such texture tid.:tid + success: The textures of :player has been updated. + name: + success: Player name has been updated to :player + owner: + success: The player :player was transferred to user :user. + delete: + success: The player has been deleted successfully. +customize: + change-color: + title: Change Theme Color + colors: + navbar: Top Navigation Bar + sidebar: + dark: Sidebar (Dark) + light: Sidebar (Light) +i18n: + add: Add New Language Line + added: Language line added. + updated: Language line updated. + deleted: Language line deleted. + group: Group + key: Key + text: Text + tip: How can I use this page? +status: + info: Information + health: Health + bs: + name: Blessing Skin + version: Version + env: Application Environment + debug: Debugging or Not? + commit: Commit + laravel: Laravel Version + server: + name: Server + php: PHP Version + web: Web Server Software + os: OS + db: + name: Database + type: Server + host: Host + port: Port + username: Username + database: Database + prefix: Table Prefix + plugins: Enabled Plugins (:amount) +plugins: + readme: Read Me + operations: + title: Operations + enabled: ':plugin has been enabled.' + unsatisfied: + notice: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't enable it. Please install or update the plugins listed below, and disable those have conflicts. + disabled: 'The ":name" plugin is not enabled.' + version: 'The version of ":title" does not satisfies the constraint ":constraint".' + conflict: 'The ":title" plugin cannot run with this plugin at the same time.' + disabled: ':plugin has been disabled.' + deleted: The plugin was deleted successfully. + no-config-notice: The plugin is not installed or doesn't provide a configuration page. + no-readme-notice: The plugin doesn't contain a readme file. + not-found: No such plugin. + market: + unresolved: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't download it. Please install or update the plugins listed below, and disable those have conflicts. + connection-error: Unable to connect to the plugins registry. :error + non-existent: The plugin :plugin does not exist. + install-success: Plugin was installed. +update: + complete: Update completed + info: + title: Update Information + up-to-date: Already up-to-date. + available: New version available. + versions: + latest: "Latest Version:" + current: "Current Version:" + check-github: Check GitHub Releases + button: Update Now + cautions: + title: Cautions + link: check out this. + text: | + Please choose update source according to your host's network environment. + Low-speed connection between update source and your host will cause long-time loading at checking and downloading page. + To change the default update source, + errors: + connection: "Unable to access to current update source. Details: :error" + spec: Current update source is not supported. + php: Your PHP version is too low to update. Requires :version or later. +download: + errors: + download: 'Failed to download. Error: :error' + shasum: File validation failed. Please download again. + unzip: Failed to unpack files. +invalid-action: Invalid action diff --git a/resources/lang/pt_PT/auth.yml b/resources/lang/pt_PT/auth.yml new file mode 100755 index 0000000..99d54ee --- /dev/null +++ b/resources/lang/pt_PT/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: Log In + message: Log in to manage your skin & players + success: Logged in successfully. +check: + anonymous: Illegal access. Please log in first. + verified: To access this page, you should verify your email address first. + admin: Only admins are permitted to access this page. + banned: You are banned on this site. Please contact the admin. +register: + title: Register + message: Welcome to :sitename! + success: Your account was registered. Redirecting... + max: You can't register more than :regs accounts. +forgot: + title: Forgot Password + message: We will send you an E-mail to verify. + disabled: Password resetting is not available. + frequent-mail: You click the send button too fast. Wait for some minutes. + unregistered: The email address is not registered. + success: Mail sent, please check your inbox. The link will be expired in 1 hour. + failed: Failed to send verification mail. :msg + ignore: If you haven't signed up on our site, please ignore this email. No unsubscribing is required. + reset: Reset your password + notice: This mail is sending automatically, no reponses will be sent if you reply. + mail: + title: Reset your password on :sitename + message: You are receiving this email because we received a password reset request for your account on :sitename. + reset: 'To reset your password, please visit: :url' + ignore: If you did not request a password reset, no further action is required. +reset: + title: Reset Password + button: Reset + invalid: Invalid link. + expired: This link is expired. + message: ':username, reset your password here.' + success: Password resetted successfully. +bind: + title: Bind Email + button: Bind + message: You need to provide your email adderss to continue. + introduction: We won't send you any spam. + registered: The email address was already taken. +verify: + title: Email Verification + invalid: Invalid link. + not-matched: Email doesn't match. +validation: + user: No such user. + password: Wrong password. +logout: + success: You are now logged out. +oauth: + authorization: + title: Authorization + introduction: A 3rd-party application ":name" is requesting permission to access your account. + button: Authorize + permissions: Permissions + scope: + user: + read: Sign you in and read your profile + notification: + read: Allows the app to read your notifications. + readwrite: Allows the app to send notifications. + player: + read: Allows the app to read your players. + readwrite: Allows the app to create, read, update and delete your players. + closet: + read: Allows the app to read your closet items. + readwrite: Allows the app to create, read, update and delete your closet items. + users-management: + read: Allows the app to read site's users. + readwrite: Allows the app to create, read, update and delete site's users. + players-management: + read: Allows the app to read site's players. + readwrite: Allows the app to create, read, update and delete site's players. + closet-management: + read: Allows the app to read user's of your site closet items. + readwrite: Allows the app to create, read, update and delete user's closet items. + reports-management: + read: Allows the app to read user's reports. + readwrite: Allows the app to read and review user's reports. +email: Email +register-link: Register a new account diff --git a/resources/lang/pt_PT/errors.yml b/resources/lang/pt_PT/errors.yml new file mode 100755 index 0000000..2bc388c --- /dev/null +++ b/resources/lang/pt_PT/errors.yml @@ -0,0 +1,19 @@ +--- +http: + msg-403: You have no permission to access this page. + msg-404: Nothing here. + msg-500: Please try again later. + msg-503: The application is now in maintenance mode. + method-not-allowed: Method not allowed. + csrf-token-mismatch: Token does not match, try reloading the page. + ie: Your browser isn't supported. Please switch to other modern browsers, such as Firefox or Chrome. +general: + title: Error occurred +exception: + code: 'Error code: :code' + detail: 'Details: :msg' + message: | + Whoops, looks like something went wrong. (enable APP_DEBUG in .env to see details) +plugins: + duplicate: The plugin [:dir1] has a duplicated plugin name definition which is same to plugin [:dir2]. Please check your plugins directory, remove one of them or use another name definition. + boot: There is something wrong with plugin ":plugin". diff --git a/resources/lang/pt_PT/front-end.yml b/resources/lang/pt_PT/front-end.yml new file mode 100755 index 0000000..0438480 --- /dev/null +++ b/resources/lang/pt_PT/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: Log In + loggingIn: Logging In + tooManyFails: + captcha: You fails too many times! Please enter the CAPTCHA. + recaptcha: You fails too many times! Please pass the reCAPTCHA challenge. + emptyEmail: Empty email address. + invalidConfirmPwd: Confirming password is not equal with password. + emptyNickname: Empty nickname. + register: Register + registering: Registering + send: Send + sending: Sending + reset: Reset + resetting: Resetting + nickname: Nickname + player-name: Minecraft player name + email: Email + identification: Email or player name + password: Password + captcha: CAPTCHA + change-captcha: Click to change CAPTCHA image. + login-link: Already registered? Log in here. + forgot-link: Forgot password? + keep: Remember me + repeat-pwd: Repeat your password + nickname-intro: Whatever you like expect special characters + player-name-intro: Player name in Minecraft, can be changed later + forgot: + login-link: I do remember it +skinlib: + private: Private + anonymous: Please login first. + reset: Reset Filter + addToCloset: Add to closet + removeFromCloset: Remove from closet + setItemName: Set a name for this texture + applyNotice: You can apply it to player at your closet + emptyItemName: Empty texture name. + setNewTextureName: 'Please enter the new texture name:' + emptyNewTextureName: Empty new texture name. + seeMyUpload: My Uploads + apply: Apply + filter: + skin: (Any Model) + steve: (Steve) + alex: (Alex) + cape: (Cape) + uploader: 'User (UID = :uid) Uploaded' + allUsers: All Users + sort: + title: Sort + time: Latest + likes: Most Likes + emptyTextureName: Empty texture name. + emptyUploadFile: You have not uploaded any file. + fileExtError: 'Error: Textures should be PNG files.' + uploading: Uploading + setAsPrivate: Set as Private + setAsPublic: Set as Public + setPublicNotice: Sure to set this as public texture? + setPrivateNotice: Sure to set this as private texture? + deleteNotice: Are you sure to delete this texture? + setNewTextureModel: "Please select a new texture model:" + upload: + texture-name: Texture Name + texture-type: Texture Type + select-file: Select File + privacy-notice: Prevent it from being visible at skin library. + set-as-private: Make it Private + button: Upload + cost: It costs you about :score score. + award: You'll be awarded :score score(s) by uploading public texture. + show: + anonymous: You must login to use closets + likes: People who like this + detail: Details + name: Texture Name + edit: Edit + model: Applicable Model + size: File Size + uploader: Uploader + upload-at: Upload At + download: Download + delete-texture: Delete Texture + manage-notice: The texture which was deleted or setted to private will be removed from the closet of everyone who had favorited it. + report: + title: Report + reason: Tell us reason please. + positive: To encourage positive contributions to the skinlib, we will reward who reported inappropriate content with :score scores. However, if any malicious reporting behaviors were found, all scores rewarded will be taken back. + negative: To mitigate the impact of malicious reports, we will require :score scores for submitting a texture report. Don't worry. The suspended scores and additional reward will be sent to your account after your report reviewed by administrators. +user: + signRemainingTime: 'Available after :time :unit' + timeUnitHour: h + timeUnitMin: min + emptyClosetMsg: >- +

Nothing in your closet...

Why not explore the Skin Library for a while?

+ renameItem: Rename item + removeItem: Remove from closet + setAsAvatar: Set as avatar + viewInSkinlib: View in skin library + switch2dPreview: Switch to 2D Preview + switch3dPreview: Switch to 3D Preview + removeFromClosetNotice: Sure to remove this texture from your closet? + emptySelectedTexture: No texture is selected. + renameClosetItem: 'Set a new name for this item:' + changePlayerName: 'Please enter the player name:' + emptyPlayerName: Empty player name. + deletePlayer: Sure to delete this player? + deletePlayerNotice: It's permanent. No backups. + chooseClearTexture: Choose texture types you want to clear + noClearChoice: You haven't choose any types + setAvatar: Sure to set this as your avatar? + setAvatarNotice: The head segment of skin will bu used. + resetAvatarConfirm: Are you sure to reset your avatar? + typeToSearch: Type to search + useAs: Apply... + resetSelected: Clear selected + closet: + upload: Upload Texture + use-as: + title: Which player should be applied to? + empty: It seems that you own no player... + used: + title: Resources Used + players: Registered players + storage: Storage used + cur-score: Current Score + score-notice: Click the score to show introduction. + sign: Sign + player: + operation: Operations + edit-pname: Edit Name + delete-texture: Clear Textures + delete-player: Delete + add-player: Add new player + texture-empty: Nothing + verification: + title: Verify Your Account + message: You must verify your email address before using the skin hosting service. Haven't received the email? + resend: Click here to send again. + sending: Sending... + oauth: + id: Client ID + name: App Name + secret: Client Secret + redirect: Callback URL + modifyName: Modify app name. + modifyUrl: Modify callback URL. + create: Create New App + confirmRemove: Are you sure to delete this app? You won't be able to undo this. +admin: + operationsTitle: Operations + permission: Permission + deleteUser: Delete + changeEmail: Edit Email + newUserEmail: 'Please enter the new email:' + verification: Email Verification + toggleVerification: Toggle Verification Status + changeNickName: Edit Nickname + newUserNickname: 'Please enter the new nickname:' + changePassword: Edit Password + newUserPassword: 'Please enter the new password:' + changeScore: Edit Score + newScore: 'Please enter the new score:' + changePermission: Change permission + newPermission: 'Please select new permission:' + deleteUserNotice: Are you sure to delete this user? It' permanent. + banned: Banned + normal: Normal + admin: Admin + superAdmin: Super Admin + unverified: Unverified + verified: Verified + pidNotice: >- + Please enter the tid of texture. Inputing 0 can clear texture of this player. + changeTexture: Change Textures + changePlayerName: Change Player Name + changeOwner: Change Owner + textureType: Texture Type + deletePlayer: Delete + changePlayerOwner: 'Please enter the id of user which this player should be transferred to:' + deletePlayerNotice: Are you sure to delete this player? It' permanent. + changePlayerNameNotice: 'Please input new player name:' + emptyPlayerName: Player name cannot be empty. + configurePlugin: Configure + deletePlugin: Delete + noDependencies: No Dependencies + pluginTitle: Plugin + pluginAuthor: Author + pluginVersion: Version + pluginReadme: Read Me + pluginDescription: Description + pluginDependencies: Dependencies + installPlugin: Install + pluginInstalling: Installing... + updatePlugin: Update + pluginUpdating: Updating... + confirmUpdate: Are you sure to update ":plugin" from :old to :new? + enablePlugin: Enable + disablePlugin: Disable + confirmDeletion: Are you sure to delete this plugin? + uploadArchive: Upload Archive + uploadArchiveNotice: Install a plugin by uploading a Zip archive. + downloadRemote: Download From Remote + downloadRemoteNotice: Install a plugin by downloading a Zip archive from remote URL. + updateButton: Update Now + downloading: Downloading... + i18n: + group: Group + key: Key + text: Text + empty: (Empty) + modify: Modify + delete: Delete + updating: 'Please type new text:' + confirmDelete: Are you sure? This is irreversible. +report: + tid: Texture ID + reporter: Reporter + reason: Reason + status-title: Status + status: + - Pending + - Resolved + - Rejected + time: Report Time + delete: Delete + ban: Ban + reject: Reject +general: + skin: Skin + cape: Cape + fatalError: Fatal Error + confirmLogout: Sure to log out? + confirm: OK + cancel: Cancel + submit: Submit + close: Close + more: More + tip: Tip + noResult: No result. + texturePreview: Texture Preview + walk: Walk + run: Run + rotation: Rotation + pause: Pause + reset: Reset + skinlib: Skin Library + wait: Please wait... + csrf: This page is out-dated. Please refresh it. + user: + email: Email + nickname: Nick Name + score: Score + register-at: Registered At + player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified +colors: + black: Black + white: White + gray: Gray + prev: Previous Background + next: Next Background +vendor: + datatable: + search: Search + prev: Prev + next: Next diff --git a/resources/lang/pt_PT/general.yml b/resources/lang/pt_PT/general.yml new file mode 100755 index 0000000..1fe8c6a --- /dev/null +++ b/resources/lang/pt_PT/general.yml @@ -0,0 +1,59 @@ +--- +index: Homepage +skinlib: Skin Library +user-center: User Center +logout: Log Out +login: Log In +register: Register Now +profile: User Profile +admin-panel: Admin Panel +explore: Explore +manage: Manage +anonymous: Guest +back: Back +dashboard: Dashboard +my-closet: Closet +my-reports: Reports +developer: Advanced +oauth-manage: OAuth2 Apps +player-manage: Players +user-manage: Users +report-manage: Reports +plugin-manage: Plugins +plugin-market: Plugin Market +plugin-configs: Plugin Configs +customize: Customize +i18n: Internationalization +options: Options +score-options: Score Options +res-options: Resource Options +status: Status +check-update: Check Update +download-update: Download Updates +close: Close +skin: Skin +cape: Cape +submit: Submit +cancel: Cancel +yes: true +no: false +op-success: Operated successfully. +unknown: Unknown +notice: Notice +illegal-parameters: Illegal parameters. +private: Private +public: Public +unexistent-user: No such user. +player-banned: The owner of this player has been banned. +texture-deleted: The requested texture has been deleted. +user: + email: Email + nickname: Nickname + password: Password + score: Score + register-at: Registered At +player: + owner: Owner + player-name: Player Name + previews: Texture Previews + last-modified: Last Modified diff --git a/resources/lang/pt_PT/index.yml b/resources/lang/pt_PT/index.yml new file mode 100755 index 0000000..bba2e21 --- /dev/null +++ b/resources/lang/pt_PT/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: Features + first: + icon: fa-users + name: Multi Player + desc: You can add multiple players within one registered account. + second: + icon: fa-share-alt + name: Sharing + desc: Explore the skin library, send a "like" and share them with your friends. + third: + icon: fa-cloud + name: Free + desc: It is free forever. No ads. No subscription fees. +introduction: ':sitename provides the service of uploading and hosting Minecraft skins. By coordinating with skin mods (e.g. CustomSkinLoader), you can choose skin and cape for your game character, and make it visible to other players in Minecraft.' +start: Join Us diff --git a/resources/lang/pt_PT/options.yml b/resources/lang/pt_PT/options.yml new file mode 100755 index 0000000..76c6421 --- /dev/null +++ b/resources/lang/pt_PT/options.yml @@ -0,0 +1,180 @@ +--- +option-saved: Option saved. +homepage: + title: Homepage + home_pic_url: + title: Picture URL at Homepage + hint: Path relative to homepage or full URL, leave empty to use default image. + favicon_url: + title: Website Icon + hint: Path relative to public/ or full URL. + description: The given image must have same width and height (leave blank to use default icon). + transparent_navbar: + title: Transparent Navigation Bar + label: This will enable transparent navigation bar of home page, but it will turn to be normal if page is scrolled to bottom. + hide_intro: + title: Hide Introduction at Bottom + label: Scroll bar will be disabled if this option is enabled, as version 2.x. + fixed_bg: + title: Fixed Background + label: This option will make background fixed, not scrolled with scroll bar. + copyright_prefer: + title: Program Copyright + description: "You can specify a different style of program copyright for each language. To edit a specific language's corresponding program copyright style, please switch to that language and submit your edit.
Warning: Any evil modification applied on the footer program copyright (including deleting, modifying author, changing link target) with out permission is FORBIDDEN. The author reserves the right to pursue relevant responsibilities." + copyright_text: + title: Custom Copyright Text + description: Placeholders are available in custom copyright text. e.g. {site_name} & {site_url}. You can also specify a different footer for each language. To edit a specific language's corresponding footer, please switch to that language and submit your edit. +customJsCss: + title: Custom CSS/JavaScript + message: | + The contents will be attached to <style> and <script> tags.
+ - Here are some useful examples: Examples of Custom CSS & JavaScript + custom_css: CSS + custom_js: JavaScript +rate: + title: Scores + score_per_storage: + title: Storage + addon: scores = 1 KB + private_score_per_storage: + title: Private Storage + addon: scores = 1 KB + hint: Uploading private textures will cost more scores. + score_per_closet_item: + title: Favorites + addon: score = 1 closet item + return_score: + title: Score Return + label: Return scores back to user after deleting players/textures/closet items. + score_per_player: + title: Players + addon: scores = 1 player + user_initial_score: User Initial Score +report: + title: Reporting Textures + reporter_score_modification: + title: Scores for Submitting an Report + description: Set a positive integer value to reward user who submits new reports. Set to a negative value will require scores for submitting reports, and the suspended scores will be available if user's report was resolved. Set to 0 to disable. + reporter_reward_score: + title: Reward the Reporter with Scores If Report Resolved +sign: + title: Signing + sign_score: + title: Score Granted + addon1: scores ~ + addon2: scores + sign_gap_time: + title: Gap Time + addon: hours + sign_after_zero: + title: Time + label: Users can sign in after 0 everyday. + hint: The above option will be ignored if this is checked. +sharing: + title: Awarding Sharing + score_award_per_texture: + title: Uploader will be rewarded for each uploading texture with + take_back_scores_after_deletion: + title: Return scores + label: Return scores if uploader setting private or deleting texture. + score_award_per_like: + title: Each time the texture is collected, uploader will be rewarded with +general: + title: General Options + site_name: Site Name + site_description: + title: Site Description + description: You can also specify a different site name and description for each language. To edit a specific language's corresponding site name or description text, please switch to that language and submit your edit. + site_url: + title: Site URL + hint: Begin with http(s)://, nerver ends with slash. + register_with_player_name: + title: Register with Player Name + label: Require Minecraft's player name when user register + require_verification: + title: Account Verification + label: Users must verify their email address first. + regs_per_ip: Max accounts of one IP + max_upload_file_size: + title: Max Upload Size + hint: "Limit specified in php.ini: :size" + player_name_rule: + title: Player Name Rule + official: Letters, numbers and underscores (Mojang's official rule) + cjk: Allow CJK Unified Ideographs + utf8: Allow all valid UTF-8 characters (excluding whitespaces) + custom: Use custom rules (regular expression) + custom_player_name_regexp: + title: Custom Player Name Rules + hint: Only takes effect when the above option is set to 'custom'. Leave empty to allow any character. + placeholder: Regular Expressions + player_name_length: + title: Player Name Length + suffix: characters + auto_del_invalid_texture: + title: Invalid Textures + label: Delete invalid textures automatically. + hint: Delete textures records whose file no longer exists from skinlib. + allow_downloading_texture: + title: Downloading Textures + label: Allow users to directly download the source file of a skinlib item. + status_code_for_private: + title: HTTP Code for Rejecting Accessing Private Textures + texture_name_regexp: + title: Texture Name Rules + hint: The RegExp for validating name of uploaded textures. Leave empty to allow any character except single, double quote and backslash. + placeholder: Regular Expressions + content_policy: + title: Content Policy + description: Display content policy at texture uploading page, supporting Markdown. To edit a specific language's corresponding content policy, please switch to that language and submit your edit. +announ: + title: Announcement + announcement: + description: Styling with Markdown is supported. You can also specify a different announcement for each language. To edit a specific language's corresponding announcement, please switch to that language and submit your edit. +meta: + title: SEO tags + meta_keywords: + title: Keywords + hint: Split with commas. + meta_description: + title: Description + hint: Description defined in "general options" will be used if you left it empty. + meta_extras: + title: Other Custom Tags +recaptcha: + recaptcha_invisible: + title: Invisible + label: Enable Invisible Mode +res-warning: This page is ONLY for advanced users. If you aren't familiar with these, please don't modify them! +resources: + title: Resource Files + hint: Please check these options if you enabled CDN for your site. + force_ssl: + title: Force SSL + label: Use HTTPS protocol to load all front-end assets. + hint: Please check if SSL really available before turning on. + auto_detect_asset_url: + title: Assets URL + label: Determine assets url automatically. + description: Please unable this if assets URLs are wrongly generated under a CDN. The site url will be used if this is not enabled. + cache_expire_time: + title: Cache Exipre Time + hint: In seconds, 86400 = one day, 31536000 = one year. + cdn_address: + title: Front-end Assets CDN + hint: Front-end files won't be loaded if URL is unavailable. + description: | + The CDN URL you give must refer to a mirror of /public directory, + all the files of that directory will be loaded as CDN.
+ How to verify? Verify if {Your CDN URL}/app/manifest.json can be accessed. +cache: + title: Cache Configuration + clear: Clear Cache + cleared: Cache has been cleared. + driver: Current cache driver is 「:driver」. + enable_avatar_cache: + title: Avatar + label: Enable caching avatar + enable_preview_cache: + title: Texture Preivew + label: Enable caching texture preivew diff --git a/resources/lang/pt_PT/setup.yml b/resources/lang/pt_PT/setup.yml new file mode 100755 index 0000000..dff74a3 --- /dev/null +++ b/resources/lang/pt_PT/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "Unable to connect to the target :type database, please check your configuration. The server replied with: :msg" +locked: + title: Already installed + text: It appears that you have already installed Blessing Skin Server. To reinstall, please delete the "install.lock" file under "storage" directory. + button: Back to homepage +updates: + success: + title: Update complete +wizard: + master: + title: Install Wizard - Blessing Skin Server + welcome: + title: Welcome + button: Next + text: Welcome to Blessing Skin Server v:version! + database: + title: Database + text: The database is used for storing data of Blessing Skin. + type: Database Type + host: Database Host + port: Database Port + username: Database Username + password: Database Password + db: Database Name + db-notice: You should provide the path to SQLite file and there is no need to fill other blanks if you use SQLite. + prefix: Prefix of Database Table (Optional) + prefix-notice: You don't need to use this option unless you want to install multiple Blessing Skin Server into one database. + info: + title: Information needed + button: Run install + text: To proceed with the installation, please fill this form with the details of the initial admin account. Don't worry, you can always change these settings later. + admin-email: Admin Email + admin-notice: This is the UNIQUE super admin account who can GIVE or CANCEL other users' admin privilege. + nickname: Nickname + password: Password + pwd-notice: 'Attention: You will need the password to log in. Please keep it at a secure place.' + confirm-pwd: Confirm password + site-name: Site name + site-name-notice: This will be shown on every page. + finish: + title: Installation complete + text: Blessing Skin Server has been installed. Thank you, and enjoy! diff --git a/resources/lang/pt_PT/skinlib.yml b/resources/lang/pt_PT/skinlib.yml new file mode 100755 index 0000000..2fc935a --- /dev/null +++ b/resources/lang/pt_PT/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: Upload new skin +show: + title: Texture Details + deleted: The requested texture was already deleted. + private: The requested texture is private and only visible to the uploader and admins. +upload: + title: Upload Texture + name-rule: Less than 32 characters and must not contain any special one. + name-rule-regexp: Custom name rules are applied as :regexp + private-score-notice: It will spend you more scores for setting it as private. You will be charged :score scores for per KB storage. + invalid-size: Invalid :type file (width :width, height :height) + invalid-hd-skin: Invalid HD skin (width and height should be divisible by 32) + lack-score: You don't have enough score to upload this texture. + repeated: The texture is already uploaded by someone else. You can add it to your closet directly. + success: Texture :name was uploaded successfully. +delete: + success: The texture was deleted successfully. +privacy: + success: The texture was set to :privacy successfully. +rename: + success: The texture was renamed to :name successfully. +model: + success: The texture's model was changed to :model successfully. +no-permission: You have no permission to moderate this texture. +non-existent: No such texture. +report: + duplicate: You have already reported this texture. The administrators will review it as soon as possible. You can also track the status of your report at User Center. + success: Thanks for reporting! The administrators will review it as soon as possible. diff --git a/resources/lang/pt_PT/user.yml b/resources/lang/pt_PT/user.yml new file mode 100755 index 0000000..cff23be --- /dev/null +++ b/resources/lang/pt_PT/user.yml @@ -0,0 +1,101 @@ +--- +sign-success: Signed successfully. You got :score scores. +announcement: Announcement +no-unread: No new notifications. +verification: + disabled: Email verification is not available. + frequent-mail: You click the send button too fast. Wait for 60 secs, guy. + verified: Your account is already verified. + success: Verification link was sent, please check your inbox. + failed: We failed to send you the verification link. Detailed message :msg + mail: + title: Verify Your Account on :sitename + message: You are receiving this email because someone registered an account with this email address on :sitename. + reset: 'Click here to verify your account: :url' + ignore: If you did not register an account, no further action is required. +score-intro: + title: What is score? + introduction: | + We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually. + Either adding players, uplaoding textures or adding a skinlib item to your closet will consume scores. + :return-score + + New users will get :initial_score scores initially, and you can acquire :score-from ~ :score-to scores by daily signing in. + will-return-score: The score will be returned if you deleted players, uploaded textures or closet items. + no-return-score: The score will NOT be returned if you deleted players, uploaded textures or closet items. + rates: + storage: ':score scores = 1 KB storage' + player: ':score scores = 1 player' + closet: ':score socres = 1 closet item' +closet: + add: + success: Added :name to closet successfully. + repeated: You have already added this texture. + not-found: We cannot find this texture. + lack-score: You don't have enough score to add it to closet. + rename: + success: The item is successfully renamed to :name + remove: + success: The texture was removed from closet successfully. + non-existent: The texture does not exist in your closet. +player: + login-notice: Now you can log in with player names you owned instead email address. + player-name-rule: + official: Player name may only contains letters, numbers and underscores. + cjk: Player name may contains letters, numbers, underscores and CJK Unified Ideographs. + utf8: Player name must be a UTF-8 string. + custom: Custom player name rules are applied on this site. Please contact admins for further information. + player-name-length: The player name should be at least :min characters and not greater than :max characters. + add: + repeated: The player name is already registered. + lack-score: You don't have enough score to add a player. + success: Player :name was added successfully. + delete: + success: Player :name was deleted successfully. + rename: + repeated: This player name is occupied. Please choose another one. + success: Player :old was renamed to :new + set: + success: The texture was applied to player :name successfully. + clear: + success: The textures of player :name was resetted successfully. +profile: + avatar: + title: Change Avatar? + notice: Click the gear icon "" of any skin in your closet, then click "Set as avatar". We will cut the head segment of that skin for you. If there is no icon like this, please try to disable your ADs blocking extension. + wrong-type: You can't set a cape as avatar. + success: New avatar was set successfully. + reset: Reset Avatar + password: + title: Change Password + old: Old Password + new: New Password + confirm: Repeat Password + button: Change password + wrong-password: Wrong original password. + success: Password updated successfully, please log in again. + nickname: + title: Change Nickname + empty: No nickname is set now. + success: Nickname is successfully updated to :nickname + email: + title: Change Email + new: New Email + password: Current Password + button: Change email + wrong-password: Wrong password. + existed: This email address is occupied. + success: Email address updated successfully, please log in again. + delete: + title: Delete Account + notice: Sure to delete your account on :site? + admin: Admin account can not be deleted. + button: Delete my account + modal-title: You need to enter your password to continue + modal-notice: | + You're about to delete your account. + This is permanent! No backups, no restores, no magic undo button. + We warned you, ok? + password: Current Password + wrong-password: Wrong password. + success: Your account is deleted successfully. diff --git a/resources/lang/pt_PT/validation.yml b/resources/lang/pt_PT/validation.yml new file mode 100755 index 0000000..58a423e --- /dev/null +++ b/resources/lang/pt_PT/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: 'The :attribute must be accepted.' +active_url: 'The :attribute is not a valid URL.' +after: 'The :attribute must be a date after :date.' +after_or_equal: 'The :attribute must be a date after or equal to :date.' +alpha: 'The :attribute may only contain letters.' +alpha_dash: 'The :attribute may only contain letters, numbers, dashes and underscores.' +alpha_num: 'The :attribute may only contain letters and numbers.' +array: 'The :attribute must be an array.' +before: 'The :attribute must be a date before :date.' +before_or_equal: 'The :attribute must be a date before or equal to :date.' +between: + numeric: 'The :attribute must be between :min and :max.' + file: 'The :attribute must be between :min and :max kilobytes.' + string: 'The :attribute must be between :min and :max characters.' + array: 'The :attribute must have between :min and :max items.' +boolean: 'The :attribute field must be true or false.' +captcha: 'Incorrect captcha.' +confirmed: 'The :attribute confirmation does not match.' +date: 'The :attribute is not a valid date.' +date_equals: 'The :attribute must be a date equal to :date.' +date_format: 'The :attribute does not match the format :format.' +different: 'The :attribute and :other must be different.' +digits: 'The :attribute must be :digits digits.' +digits_between: 'The :attribute must be between :min and :max digits.' +dimensions: 'The :attribute has invalid image dimensions.' +distinct: 'The :attribute field has a duplicate value.' +email: 'The :attribute must be a valid email address.' +ends_with: 'The :attribute must end with one of the following: :values.' +exists: 'The selected :attribute is invalid.' +file: 'The :attribute must be a file.' +filled: 'The :attribute field must have a value.' +gt: + numeric: 'The :attribute must be greater than :value.' + file: 'The :attribute must be greater than :value kilobytes.' + string: 'The :attribute must be greater than :value characters.' + array: 'The :attribute must have more than :value items.' +gte: + numeric: 'The :attribute must be greater than or equal :value.' + file: 'The :attribute must be greater than or equal :value kilobytes.' + string: 'The :attribute must be greater than or equal :value characters.' + array: 'The :attribute must have :value items or more.' +image: 'The :attribute must be an image.' +in: 'The selected :attribute is invalid.' +in_array: 'The :attribute field does not exist in :other.' +integer: 'The :attribute must be an integer.' +ip: 'The :attribute must be a valid IP address.' +ipv4: 'The :attribute must be a valid IPv4 address.' +ipv6: 'The :attribute must be a valid IPv6 address.' +json: 'The :attribute must be a valid JSON string.' +lt: + numeric: 'The :attribute must be less than :value.' + file: 'The :attribute must be less than :value kilobytes.' + string: 'The :attribute must be less than :value characters.' + array: 'The :attribute must have less than :value items.' +lte: + numeric: 'The :attribute must be less than or equal :value.' + file: 'The :attribute must be less than or equal :value kilobytes.' + string: 'The :attribute must be less than or equal :value characters.' + array: 'The :attribute must not have more than :value items.' +max: + numeric: 'The :attribute may not be greater than :max.' + file: 'The :attribute may not be greater than :max kilobytes.' + string: 'The :attribute may not be greater than :max characters.' + array: 'The :attribute may not have more than :max items.' +mimes: 'The :attribute must be a file of type: :values.' +mimetypes: 'The :attribute must be a file of type: :values.' +min: + numeric: 'The :attribute must be at least :min.' + file: 'The :attribute must be at least :min kilobytes.' + string: 'The :attribute must be at least :min characters.' + array: 'The :attribute must have at least :min items.' +not_in: 'The selected :attribute is invalid.' +not_regex: 'The :attribute format is invalid.' +numeric: 'The :attribute must be a number.' +password: The password is incorrect. +present: 'The :attribute field must be present.' +recaptcha: 'reCAPTCHA validation failed.' +regex: 'The :attribute format is invalid.' +required: 'The :attribute field is required.' +required_if: 'The :attribute field is required when :other is :value.' +required_unless: 'The :attribute field is required unless :other is in :values.' +required_with: 'The :attribute field is required when :values is present.' +required_with_all: 'The :attribute field is required when :values are present.' +required_without: 'The :attribute field is required when :values is not present.' +required_without_all: 'The :attribute field is required when none of :values are present.' +same: 'The :attribute and :other must match.' +size: + numeric: 'The :attribute must be :size.' + file: 'The :attribute must be :size kilobytes.' + string: 'The :attribute must be :size characters.' + array: 'The :attribute must contain :size items.' +starts_with: 'The :attribute must start with one of the following: :values.' +string: 'The :attribute must be a string.' +timezone: 'The :attribute must be a valid zone.' +unique: 'The :attribute has already been taken.' +uploaded: 'The :attribute failed to upload.' +url: 'The :attribute format is invalid.' +uuid: 'The :attribute must be a valid UUID.' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: name + player_name: player name + identification: email or player name + email: email + password: password + password_confirmation: 'password confirmation' + title: title + content: content diff --git a/resources/lang/ru_RU/admin.yml b/resources/lang/ru_RU/admin.yml new file mode 100755 index 0000000..c8d83a8 --- /dev/null +++ b/resources/lang/ru_RU/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: Зарегистрированные пользователи + total-players: Игроки + total-textures: Загруженные текстуры + disk-usage: Использование диска + overview: Обзор + texture-uploads: Загрузки текстур + user-registration: Регистрация пользователя +notifications: + send: + title: Отправить уведомление + success: Успешно отправлено! + receiver: + title: Получатель + all: Все пользователи + normal: Обычные пользователи + uid: Указанный UID + email: Указанный адрес электронной почты + title: Заголовок + content: Содержимое (поддерживается язык разметки Markdown) +users: + operations: + non-existent: Пользователь не существует. + no-permission: У вас нет прав доступа для управления этим пользователем. + email: + success: Адрес электронной почты успешно изменен. + verification: + success: Статус подтверждения учетной записи успешно изменён. + nickname: + success: Ник успешно изменён. + password: + success: Пароль успешно изменён. + score: + success: Счёт успешно изменён. + permission: Разрешение обновлено. + delete: + success: Учетная запись успешно удалена. +players: + no-permission: У вас нет прав доступа для управления этим игроком. + textures: + non-existent: Текстуры tid:tid не существует + success: Текстуры :player обновлены. + name: + success: Имя игрока обновлено до :player + owner: + success: Игрок :player был передан пользователю :user. + delete: + success: Игрок был успешно удалён. +customize: + change-color: + title: Изменить цвет темы + colors: + navbar: Верхняя панель навигации + sidebar: + dark: Боковая панель (темная) + light: Боковая панель (светлая) +i18n: + add: Добавить новую языковую строку + added: Языковая строка добавлена. + updated: Языковая строка обновлена. + deleted: Языковая строка удалена. + group: Группа + key: Ключ + text: Текст + tip: Как я могу использовать эту страницу? +status: + info: Информация + health: Здоровье + bs: + name: Blessing Skin + version: Версия + env: Окружение приложения + debug: Отладка или нет? + commit: Утвердить + laravel: Версия Laravel + server: + name: Сервер + php: Версия PHP + web: Программное обеспечение веб-сервера + os: OS + db: + name: База данных + type: Сервер + host: Хост + port: Порт + username: Имя пользователя + database: База данных + prefix: Префикс таблиц + plugins: Включены плагины (:amount) +plugins: + readme: Прочти меня + operations: + title: Операции + enabled: ':plugin был включен.' + unsatisfied: + notice: В плагине есть конфликты или неудовлетворенные зависимости, поэтому мы не можем включить его. Пожалуйста, установите или обновите плагины, перечисленные ниже, и отключите те, которые имеют конфликты. + disabled: 'Плагин ":name" не включен.' + version: 'Версия ":title" не удовлетворяет ограничениям ":constraint".' + conflict: 'Плагин ":title" не может работать с этим плагином одновременно.' + disabled: ':plugin был отключен.' + deleted: Плагин был успешно удален. + no-config-notice: Плагин не установлен или не предоставляет страницу конфигурации. + no-readme-notice: Плагин не содержит файл readme. + not-found: Нет такого плагина. + market: + unresolved: В плагине есть конфликты или неудовлетворенные зависимости, поэтому мы не можем его скачать. Пожалуйста, установите или обновите плагины, перечисленные ниже, и отключите те, которые имеют конфликты. + connection-error: Невозможно подключиться к реестру плагинов. :error + non-existent: Плагин :plugin не существует. + install-success: Плагин установлен. +update: + complete: Обновление завершено + info: + title: Обновить информацию + up-to-date: Обновлено до последней версии. + available: Доступна новая версия. + versions: + latest: "Последняя версия:" + current: "Текущая версия:" + check-github: Проверить релизы GitHub + button: Обновить сейчас + cautions: + title: Предостережения + link: проверьте это. + text: | + Пожалуйста, выберите источник обновления в соответствии с сетевой средой вашего узла. + При низкой скорости соединения между источником обновлений и вашим хостом вызовет длительную загрузку на странице проверки и загрузки. + Чтобы изменить источник обновлений по умолчанию, + errors: + connection: "Не удается получить доступ к текущему источнику обновления. Подробности: :error" + spec: Текущий источник обновлений не поддерживается. + php: Ваша версия PHP слишком низкая для обновления. Требуется :version или более поздней версии. +download: + errors: + download: 'Не удалось загрузить. Ошибка: :error' + shasum: Ошибка проверки файла. Пожалуйста, загрузите снова. + unzip: Не удалось распаковать файлы. +invalid-action: Неверное действие diff --git a/resources/lang/ru_RU/auth.yml b/resources/lang/ru_RU/auth.yml new file mode 100755 index 0000000..dc3f463 --- /dev/null +++ b/resources/lang/ru_RU/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: Вход + message: Войдите, чтобы управлять скином и игроками + success: Вход в систему выполнен успешно. +check: + anonymous: Неправомерный доступ. Пожалуйста, выполните вход. + verified: Чтобы получить доступ к этой странице, вы должны сначала подтвердить свой адрес электронной почты. + admin: Доступ к этой странице разрешен только администраторам. + banned: Вы забанены на этом сайте. Пожалуйста, свяжитесь с администратором. +register: + title: Регистрация + message: Добро пожаловать на :sitename! + success: Ваша учетная запись зарегистрирована. Перенаправление... + max: Вы не можете зарегистрироваться более чем :regs аккаунтов. +forgot: + title: Забыли пароль? + message: Мы вышлем вам электронное письмо для подтверждения. + disabled: Сброс пароля недоступен. + frequent-mail: Вы слишком быстро нажимаете на кнопку отправки. Подождите несколько минут. + unregistered: Данный E-mail адрес не зарегистрирован. + success: Письмо отправлено, пожалуйста, проверьте ваш почтовый ящик. Срок действия ссылки истекает через 1 час. + failed: Не удалось отправить письмо с подтверждением. :msg + ignore: Если вы не зарегистрировались на нашем сайте, пожалуйста, проигнорируйте это письмо. Отписка не требуется. + reset: Восстановление пароля + notice: Это сообщение отправляется автоматически, никакие ответы не будут отправлены, если вы ответите. + mail: + title: Сброс пароля на :sitename + message: Вы получаете это письмо, потому что мы получили запрос на сброс пароля для вашей учетной записи на :sitename. + reset: 'Чтобы сбросить пароль, пожалуйста, посетите: :url' + ignore: Если вы не запрашивали сброс пароля, никаких дальнейших действий не требуется. +reset: + title: Сброс пароля + button: Сброс + invalid: Неверная ссылка. + expired: Срок действия ссылки истёк. + message: ':username, сбросить пароль здесь.' + success: Пароль успешно сброшен. +bind: + title: Привязка электронной почты + button: Привязать + message: Для продолжения работы вам необходимо предоставить адрес электронной почты. + introduction: Мы не будем отправлять вам спам. + registered: Адрес электронной почты уже занят. +verify: + title: Подтверждение адреса электронной почты + invalid: Неверная ссылка. + not-matched: Адрес электронной почты не совпадает. +validation: + user: Такого пользователя нет. + password: Неверный пароль. +logout: + success: Вы вышли из системы. +oauth: + authorization: + title: Авторизация + introduction: Стороннее приложение ":name" запрашивает разрешение на доступ к вашей учетной записи. + button: Авторизироваться + permissions: Права доступа + scope: + user: + read: Войдите и прочтите свой профиль + notification: + read: Приложение сможет читать ваши уведомления. + readwrite: Приложение сможет отправлять уведомления. + player: + read: Приложение сможет читать ваших игроков. + readwrite: Приложение сможет создавать, читать, обновлять и удалять ваших игроков. + closet: + read: Приложение сможет читать ваши предметы в шкафу. + readwrite: Приложение сможет создавать, читать, обновлять и удалять предметы из шкафа. + users-management: + read: Приложение сможет читать пользователей сайта. + readwrite: Приложение сможет создавать, читать, обновлять и удалять пользователей сайта. + players-management: + read: Приложение сможет читать игроков на сайте. + readwrite: Приложение сможет создавать, читать, обновлять и удалять игроков на сайте. + closet-management: + read: Позволяет приложению читать пользовательские предметы в шкафу на вашем сайте. + readwrite: Приложение сможет создавать, читать, обновлять и удалять предметы гардероба пользователя. + reports-management: + read: Приложение сможет читать отчеты пользователей. + readwrite: Приложение сможет читать и просматривать отчеты пользователей. +email: Адрес электронной почты +register-link: Зарегистрировать новый аккаунт diff --git a/resources/lang/ru_RU/errors.yml b/resources/lang/ru_RU/errors.yml new file mode 100755 index 0000000..51333b6 --- /dev/null +++ b/resources/lang/ru_RU/errors.yml @@ -0,0 +1,19 @@ +--- +http: + msg-403: У вас нет прав доступа для этой страницы. + msg-404: Здесь пусто. + msg-500: Пожалуйста, повторите попытку позже. + msg-503: В настоящее время приложение находится в режиме обслуживания. + method-not-allowed: Метод не поддерживается. + csrf-token-mismatch: Токен не совпадает, попробуйте перезагрузить страницу. + ie: Ваш браузер не поддерживается. Пожалуйста, используйте другие современные браузеры, такие как Firefox или Chrome. +general: + title: Произошла ошибка +exception: + code: 'Код ошибки: :code' + detail: 'Подробнее: :msg' + message: | + Упс, кажется, что-то пошло не так. (включите APP_DEBUG в .env чтобы увидеть подробности) +plugins: + duplicate: Имя плагина [:dir1] совпадает с именем плагина [:dir2]. Пожалуйста, проверьте вашу папку с плагинами, удалите один из них или используйте другое имя. + boot: Что-то не так с плагином ":plugin". diff --git a/resources/lang/ru_RU/front-end.yml b/resources/lang/ru_RU/front-end.yml new file mode 100755 index 0000000..6fefd43 --- /dev/null +++ b/resources/lang/ru_RU/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: Войти + loggingIn: Вход в систему + tooManyFails: + captcha: Слишком много попыток! Пожалуйста, введите CAPTCHA. + recaptcha: Слишком много неудачных попыток! Пройдите проверку reCAPTCHA. + emptyEmail: Не указан адрес электронной почты. + invalidConfirmPwd: Подтверждение пароля не совпадает с паролем. + emptyNickname: Не указан никнейм. + register: Зарегистрироваться + registering: Регистрация + send: Отправить + sending: Отправка + reset: Сброс + resetting: Сбрасывается + nickname: Ник + player-name: Имя игрока Minecraft + email: Почта + identification: Адрес электронной почты или имя игрока + password: Пароль + captcha: CAPTCHA + change-captcha: Нажмите, чтобы изменить изображение CAPTCHA. + login-link: Уже зарегистрированы? Войдите здесь. + forgot-link: Забыли пароль? + keep: Запомнить меня + repeat-pwd: Повторите ваш пароль + nickname-intro: Всё, что вам угодно, кроме специальных символов + player-name-intro: Имя игрока в Minecraft, может быть изменено позже + forgot: + login-link: Я помню это +skinlib: + private: Приватный + anonymous: Пожалуйста, войдите сначала. + reset: Сбросить фильтр + addToCloset: Добавить в шкаф + removeFromCloset: Удалить из шкафа + setItemName: Установите имя для этой текстуры + applyNotice: Вы можете применить его к игроку в вашем шкафу + emptyItemName: Не указано название текстуры. + setNewTextureName: 'Пожалуйста, введите название новой текстуры:' + emptyNewTextureName: Пустое имя новой текстуры. + seeMyUpload: Мои загрузки + apply: Применить + filter: + skin: (Любая модель) + steve: (Стив) + alex: (Алекс) + cape: (Плащ) + uploader: 'Пользователь (UID = :uid) загружен' + allUsers: Все пользователи + sort: + title: Сортировать + time: Последние + likes: Популярные + emptyTextureName: Не указано название текстуры. + emptyUploadFile: Вы не загрузили ни одного файла. + fileExtError: 'Ошибка: Текстуры должны быть в PNG формате.' + uploading: Загружается + setAsPrivate: Сделать приватным + setAsPublic: Сделать общедоступным + setPublicNotice: Вы уверены, что хотите установить это как публичную текстуру? + setPrivateNotice: Вы уверены, что хотите установить это как приватную текстуру? + deleteNotice: Вы уверены, что хотите удалить эту текстуру? + setNewTextureModel: "Пожалуйста, выберите новую модель текстуры:" + upload: + texture-name: Название текстуры + texture-type: Тип текстуры + select-file: Выбрать файл + privacy-notice: Предотвратите его видимость в библиотеке скинов. + set-as-private: Сделать его приватным + button: Загрузить + cost: Это будет стоить вам :score очков. + award: Загрузив публичную текстуру, вас наградят :score оч. + show: + anonymous: Вы должны войти в систему, чтобы использовать шкафы + likes: Люди, которым это нравится + detail: Детали + name: Название текстуры + edit: Редактировать + model: Применимая модель + size: Размер файла + uploader: Загрузчик + upload-at: Загрузить в + download: Скачать + delete-texture: Удалить текстуру + manage-notice: Текстура, которая была удалена или установлена как приватная, будет удалена из шкафа всех, кто ее добавил в избранное. + report: + title: Пожаловаться + reason: Скажите нам причину, пожалуйста. + positive: 'Чтобы поощрить положительный вклад в skinlib, мы вознаградим тех, кто сообщил о недопустимом контенте: :score оч. Однако, если было обнаружено какое-либо вредоносное поведение при составлении отчётов, все вознаграждения будут возвращены.' + negative: Чтобы смягчить влияние вредоносных отчётов, нам потребуется :score оч. за отправку отчёта о текстуре. Не беспокойтесь. Приостановленные баллы и дополнительное вознаграждение будут отправлены на ваш счёт после проверки вашего отчёта администраторами. +user: + signRemainingTime: 'Доступно после :time :unit' + timeUnitHour: ч + timeUnitMin: мин + emptyClosetMsg: >- +

В вашем шкафу ничего нет...

Почему бы вам не исследовать библиотеку скинов?

+ renameItem: Переименовать элемент + removeItem: Удалить из шкафа + setAsAvatar: Установить как аватар + viewInSkinlib: Открыть в библиотеке скинов + switch2dPreview: Переключить предпросмотр в 2D режим + switch3dPreview: Переключить предпросмотр в 3D режим + removeFromClosetNotice: Удалить эту текстуру из шкафа? + emptySelectedTexture: Текстура не выбрана. + renameClosetItem: 'Задать новое имя для этого элемента:' + changePlayerName: 'Введите имя игрока:' + emptyPlayerName: Пустое имя игрока. + deletePlayer: Удалить этого игрока? + deletePlayerNotice: Это навсегда. Без резервных копий. + chooseClearTexture: Выберите типы текстур, которые вы хотите очистить + noClearChoice: Вы не выбрали ни одного типа + setAvatar: Установить этот как ваш аватар? + setAvatarNotice: Будет использован сегмент кожи головы. + resetAvatarConfirm: Выполнить сброс вашего аватара? + typeToSearch: Введите для поиска + useAs: Применить... + resetSelected: Очистить выбранное + closet: + upload: Загрузить текстуру + use-as: + title: К какому игроку следует применить? + empty: Кажется, у вас нет игрока... + used: + title: Используемые ресурсы + players: Зарегистрированные игроки + storage: Использовано памяти + cur-score: 'Очки:' + score-notice: Нажмите на очки для просмотра информации. + sign: Отметиться + player: + operation: Операции + edit-pname: Изменить имя + delete-texture: Очистить текстуры + delete-player: Удалить + add-player: Добавить нового игрока + texture-empty: Ничего + verification: + title: Подтвердите свой аккаунт + message: Вы должны подтвердить свой адрес электронной почты, прежде чем использовать сервис хостинга скинов. Не получили письмо? + resend: Нажмите здесь, чтобы отправить снова. + sending: Отправка... + oauth: + id: ID клиента + name: Имя приложения + secret: Пароль клиента + redirect: URL обратного вызова + modifyName: Изменить имя приложения. + modifyUrl: Измените URL-адрес обратного вызова. + create: Создать новое приложение + confirmRemove: Вы уверены, что хотите удалить это приложение? Вы не сможете отменить это действие. +admin: + operationsTitle: Операции + permission: Разрешение + deleteUser: Удалить + changeEmail: Редактировать электронную почту + newUserEmail: 'Пожалуйста, введите новый адрес электронной почты:' + verification: Подтверждение адреса электронной почты + toggleVerification: Переключить статус проверки + changeNickName: Изменить ник + newUserNickname: 'Пожалуйста, введите новый ник:' + changePassword: Изменить пароль + newUserPassword: 'Пожалуйста, введите новый пароль:' + changeScore: Изменить балл + newScore: 'Пожалуйста, введите новый балл:' + changePermission: Изменить разрешение + newPermission: 'Пожалуйста, выберите новое разрешение:' + deleteUserNotice: Вы уверены, что хотите удалить этого пользователя? Это действие необратимо. + banned: Забанен + normal: Обычный + admin: Админ + superAdmin: Супер админ + unverified: Не подтверждено + verified: Подтверждено + pidNotice: >- + Пожалуйста, введите диапазон текстуры. Ввод 0 может очистить текстуру этого игрока. + changeTexture: Изменить текстуры + changePlayerName: Изменить имя игрока + changeOwner: Изменить владельца + textureType: Тип текстуры + deletePlayer: Удалить + changePlayerOwner: 'Пожалуйста, введите идентификатор пользователя, которому этот игрок должен быть переведен:' + deletePlayerNotice: Вы уверены, что хотите удалить этого игрока? Это навсегда. + changePlayerNameNotice: 'Пожалуйста, введите новое имя игрока:' + emptyPlayerName: Имя игрока не может быть пустым. + configurePlugin: Настройка + deletePlugin: Удалить + noDependencies: Нет зависимостей + pluginTitle: Плагин + pluginAuthor: Автор + pluginVersion: Версия + pluginReadme: Прочти меня + pluginDescription: Описание + pluginDependencies: Зависимости + installPlugin: Установить + pluginInstalling: Установка... + updatePlugin: Обновить + pluginUpdating: Обновление... + confirmUpdate: Вы уверены, что хотите обновить ":plugin" с :old на :new? + enablePlugin: Включить + disablePlugin: Отключить + confirmDeletion: Вы уверены, что хотите удалить этот плагин? + uploadArchive: Загрузить архив + uploadArchiveNotice: Установите плагин загрузив архив Zip. + downloadRemote: Загрузить удалённо + downloadRemoteNotice: Установите плагин, загрузив Zip-архив с удалённого URL. + updateButton: Обновить сейчас + downloading: Загрузка... + i18n: + group: Группа + key: Ключ + text: Текст + empty: (Пусто) + modify: Изменить + delete: Удалить + updating: 'Пожалуйста, введите новый текст:' + confirmDelete: Вы уверены? Это необратимо. +report: + tid: ID текстуры + reporter: Жалуется + reason: Причина + status-title: Статус + status: + - В ожидании + - Решена + - Отклонено + time: Время отчета + delete: Удалить + ban: Заблокировать + reject: Отклонить +general: + skin: Скин + cape: Плащ + fatalError: Критическая ошибка + confirmLogout: Выйти? + confirm: OK + cancel: Отмена + submit: Подтвердить + close: Закрыть + more: Ещё + tip: Совет + noResult: По запросу ничего не найдено. + texturePreview: Предпросмотр текстуры + walk: Ходьба + run: Бег + rotation: Вращение + pause: Приостановить + reset: Сброс + skinlib: Библиотека скинов + wait: Подождите... + csrf: Страница устарела. Обновите её. + user: + email: Адрес электронной почты + nickname: Никнейм + score: Очки + register-at: Дата регистрации + player: + owner: Владелец + player-name: Имя игрока + previews: Предпросмотр текстур + last-modified: Последнее изменение +colors: + black: Чёрный + white: Белый + gray: Серый + prev: Предыдущий фон + next: Следующий фон +vendor: + datatable: + search: Поиск + prev: Назад + next: Вперед diff --git a/resources/lang/ru_RU/general.yml b/resources/lang/ru_RU/general.yml new file mode 100755 index 0000000..cb662ac --- /dev/null +++ b/resources/lang/ru_RU/general.yml @@ -0,0 +1,59 @@ +--- +index: Домашняя страница +skinlib: Библиотека скинов +user-center: Меню пользователя +logout: Выйти +login: Войти +register: Зарегистрироваться +profile: Профиль +admin-panel: Панель администратора +explore: Обзор +manage: Управлeние +anonymous: Гость +back: Назад +dashboard: Главная страница +my-closet: Гардероб +my-reports: Отчёты +developer: Дополнительные параметры +oauth-manage: OAuth2 приложения +player-manage: Игроки +user-manage: Пользователи +report-manage: Отчёты +plugin-manage: Плагины +plugin-market: Магазин плагинов +plugin-configs: Конфигурации плагинов +customize: Настроить +i18n: Локализация +options: Параметры +score-options: Параметры счёта +res-options: Параметры ресурсов +status: Статус +check-update: Проверить обновления +download-update: Загрузить обновление +close: Закрыть +skin: Скин +cape: Плащ +submit: Подтвердить +cancel: Отмена +yes: true +no: false +op-success: Успешно выполнено. +unknown: Неизвестно +notice: Примечание +illegal-parameters: Недопустимые параметры. +private: Приватный +public: Публичный +unexistent-user: Пользователь не существует. +player-banned: Владелец этого игрока был заблокирован. +texture-deleted: Запрашиваемая текстура удалена. +user: + email: Адрес электронной почты + nickname: Ник + password: Пароль + score: Счёт + register-at: Дата регистрации +player: + owner: Владелец + player-name: Имя игрока + previews: Предпросмотр текстуры + last-modified: Последнее изменение diff --git a/resources/lang/ru_RU/index.yml b/resources/lang/ru_RU/index.yml new file mode 100755 index 0000000..52fd838 --- /dev/null +++ b/resources/lang/ru_RU/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: Особенности + first: + icon: fa-users + name: Мультиплеер + desc: Вы можете добавить несколько игроков на один аккаунт. + second: + icon: fa-share-alt + name: Публикация + desc: Просматривайте библиотеку скинов, ставьте лайки и делитесь скинами с друзьями. + third: + icon: fa-cloud + name: Это бесплатно + desc: Сервис навсегда бесплатный. Без рекламы. Без платной подписки. +introduction: ':sitename предоставляет возможность загрузки и хранения скинов для Minecraft. Используя сервис совместно с модами для скинов (например, CustomSkinLoader), вы можете выбрать скин и плащ для вашего персонажа и сделать их видимыми для других игроков.' +start: Присоединяйтесь diff --git a/resources/lang/ru_RU/options.yml b/resources/lang/ru_RU/options.yml new file mode 100755 index 0000000..fae619d --- /dev/null +++ b/resources/lang/ru_RU/options.yml @@ -0,0 +1,180 @@ +--- +option-saved: Опция сохранена. +homepage: + title: Домашняя страница + home_pic_url: + title: URL изображения на главной странице + hint: Путь относительно главной страницы или полной URL, оставьте пустым, чтобы использовать изображение по умолчанию. + favicon_url: + title: Иконка сайта + hint: Путь относительно публичного или полного URL. + description: Данное изображение должно иметь одинаковую ширину и высоту (оставьте пустым, чтобы использовать стандартную иконку). + transparent_navbar: + title: Прозрачная панель навигации + label: Это включит прозрачную панель навигации на главной странице, но она будет нормальной, если страница прокручивается вниз. + hide_intro: + title: Скрыть введение в низу + label: Строка прокрутки будет отключена, если эта опция включена, как версия 2.x. + fixed_bg: + title: Фиксированный фон + label: Эта опция сделает фон фиксированным, а не прокрутится с помощью полосы прокрутки. + copyright_prefer: + title: Авторские права + description: "Вы можете указать разные стили авторских прав для каждого языка. Чтобы отредактировать соответствующий стиль авторских прав для определенного языка, переключитесь на этот язык и отправьте свои изменения.
Предупреждение: Любое злое изменение, примененное к авторскому праву программы нижнего колонтитула (включая удаление, изменение автора, изменение цели ссылки) без разрешения ЗАПРЕЩЕНО . Автор оставляет за собой право выполнять соответствующие обязанности." + copyright_text: + title: Пользовательский текст авторского права + description: Заполнители доступны в пользовательском тексте авторских прав. Например {site_name} & {site_url}. Кроме того, для каждого языка можно указать свой нижний колонтитул. Чтобы отредактировать соответствующий нижний колонтитул определенного языка, переключитесь на этот язык и отправьте свое редактирование. +customJsCss: + title: Пользовательские CSS/JavaScript + message: | + Содержимое будет прикреплено к тегам <style> и <script>
+ - Вот несколько полезных примеров: Примеры пользовательских CSS & JavaScript + custom_css: CSS + custom_js: JavaScript +rate: + title: Очки + score_per_storage: + title: Хранилище + addon: очки = 1 КБ + private_score_per_storage: + title: Приватное хранилище + addon: очки = 1 КБ + hint: Загрузка приватных текстур будет стоить больше очков. + score_per_closet_item: + title: Избранное + addon: очки = 1 элемент шкафа + return_score: + title: Возврат очков + label: Возврат очков обратно пользователю после удаления игроков/текстур/элементов шкафа. + score_per_player: + title: Игроки + addon: очки = 1 игрок + user_initial_score: Начальные очки пользователя +report: + title: Отчет о текстурах + reporter_score_modification: + title: Очки за отправку отчёта + description: Установите положительное целое значение для поощрения пользователя, который отправляет новые отчеты. Если задано отрицательное значение, то для отправки отчетов потребуются баллы за отправку отчетов, а если отчёт пользователя будет решен, то баллы будут доступны. 0 для отключения. + reporter_reward_score: + title: Награды за отчёт с баллами если отчёт Решен +sign: + title: Подпись + sign_score: + title: Очки предоставлены + addon1: очки ~ + addon2: очки + sign_gap_time: + title: Промежуток времени + addon: часов + sign_after_zero: + title: Время + label: Пользователи могут войти после 0 ежедневно. + hint: Вышеуказанная опция будет проигнорирована, если этот флажок установлен. +sharing: + title: Распределение наград + score_award_per_texture: + title: Загрузчик будет вознагражден за каждую загружаемую текстуру + take_back_scores_after_deletion: + title: Возврат очков + label: Возвращает баллы, если загрузчик установит приватный доступ или удалит текстуру. + score_award_per_like: + title: Каждый раз при сборе текстуры отправитель получает вознаграждение +general: + title: Основные параметры + site_name: Название сайта + site_description: + title: Описание сайта + description: Вы также можете указать другое имя сайта и описание для каждого языка. Чтобы изменить название сайта или текст описания соответствующего языка, переключитесь на этот язык и отправьте свои изменения. + site_url: + title: Адрес сайта + hint: Начинайте с http(s)://, никогда не заканчивайте косой чертой. + register_with_player_name: + title: Регистрация с именем игрока + label: Требовать имя игрока Minecraft при регистрации пользователя + require_verification: + title: Подтверждение аккаунта + label: Пользователи должны сначала подтвердить свой адрес электронной почты. + regs_per_ip: Максимум аккаунтов с одним IP + max_upload_file_size: + title: Максимальный размер загрузки + hint: "Ограничение, указанное в файле php.ini: :size" + player_name_rule: + title: Правило имени игрока + official: Буквы, цифры и подчеркивание (официальное правило Mojang) + cjk: Разрешить унифицированные идеографы CJK + utf8: Разрешить все допустимые символы UTF-8 (кроме пробелов) + custom: Использовать пользовательские правила (регулярное выражение) + custom_player_name_regexp: + title: Пользовательские правила имени игрока + hint: Применяется только когда опция выше имеет значение 'custom'. Оставьте пустым, чтобы разрешить любой символ. + placeholder: Регулярные выражения + player_name_length: + title: Длина имени игрока + suffix: символы + auto_del_invalid_texture: + title: Неправильные текстуры + label: Удалить недействительные текстуры автоматически. + hint: Удалить записи текстур, файл которых больше не существует из skinlib. + allow_downloading_texture: + title: Загрузка текстур + label: Разрешить пользователям напрямую скачивать исходный файл элемента skinlib. + status_code_for_private: + title: HTTP-код для отказа в доступе к приватным текстурам + texture_name_regexp: + title: Правила имени текстуры + hint: RegExp нужен для проверки имени загруженных текстур. Оставьте пустым, чтобы разрешить любой символ, кроме одинарных, двойных кавычек и обратной косой черты. + placeholder: Регулярные выражения + content_policy: + title: Политика в отношении содержания + description: Отобразить контентную политику на странице загрузки текстур с поддержкой Markdown. Чтобы отредактировать соответствующую политику в отношении определенного языка, переключитесь на этот язык и отправьте свое изменение. +announ: + title: Объявление + announcement: + description: Стилизация с Markdown поддерживается. Вы также можете указать разные объявления для каждого языка. Чтобы отредактировать соответствующее объявление определенного языка, пожалуйста, переключитесь на этот язык и отправьте свою правку. +meta: + title: SEO тэги + meta_keywords: + title: Ключевые слова + hint: Разделить запятыми. + meta_description: + title: Описание + hint: Описание, определенное в "Общие настройки", будет использоваться, если вы оставите его пустым. + meta_extras: + title: Другие пользовательские теги +recaptcha: + recaptcha_invisible: + title: Не виден + label: Включить невидимый режим +res-warning: Эта страница ТОЛЬКО для продвинутых пользователей. Если вы не знакомы с этим, то не трогайте это! +resources: + title: Файлы ресурсов + hint: Пожалуйста, проверьте эти опции, если вы включили CDN для вашего сайта. + force_ssl: + title: Принудительно использовать SSL + label: Используйте протокол HTTPS для загрузки всех клиентских ресурсов. + hint: Пожалуйста, проверьте, действительно ли SSL доступен перед включением. + auto_detect_asset_url: + title: URL медиафайлов + label: Определить адрес ресурса автоматически. + description: Пожалуйста, не удается это если URL-адреса активов создаются неправильно под CDN. URL сайта будет использован, если он не включен. + cache_expire_time: + title: Время кеширования + hint: В секундах, 86400 = один день, 31536000 = один год. + cdn_address: + title: Личный актив CDN + hint: Файлы интерфейса не загружаются, если URL-адрес недоступен. + description: | + CDN URL, который вы указываете, должен ссылаться на зеркало /public каталога, + все файлы этого каталога будут загружены как CDN.
+ Как проверить? Проверьте доступность {Your CDN URL}/app/manifest.json. +cache: + title: Конфигурация кэша + clear: Очистить кэш + cleared: Кэш был очищен. + driver: Текущий драйвер кэша :driver . + enable_avatar_cache: + title: Аватар + label: Включить кэширование аватара + enable_preview_cache: + title: Предварительный просмотр текстур + label: Включить кэширование текстур diff --git a/resources/lang/ru_RU/setup.yml b/resources/lang/ru_RU/setup.yml new file mode 100755 index 0000000..a1946e2 --- /dev/null +++ b/resources/lang/ru_RU/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "Не удается подключиться к базе данных :type, проверьте свою конфигурацию. Сервер ответил: :msg" +locked: + title: Уже установлено + text: Похоже, вы уже установили сервер Blessing Skin. Чтобы переустановить, удалите файл "install.lock" в каталоге "storage". + button: Вернуться на главную страницу +updates: + success: + title: Обновление завершено +wizard: + master: + title: Мастер установки - Сервер Blessing Skin + welcome: + title: Добро пожаловать + button: Далее + text: Добро пожаловать в Blessing Skin Server v:version! + database: + title: База данных + text: База данных используется для хранения данных Blessing Skin. + type: Тип базы данных + host: Сервер базы данных + port: Порт базы данных + username: Имя пользователя базы данных + password: Пароль базы данных + db: Имя базы данных + db-notice: Вы должны указать путь к файлу SQLite, и нет необходимости заполнять другие пробелы, если вы используете SQLite. + prefix: Префикс таблицы базы данных (необязательно) + prefix-notice: Вам не нужно использовать эту опцию, если вы не хотите устанавливать несколько серверов Blessing Skin в одну базу данных. + info: + title: Необходимая информация + button: Запустить установку + text: Чтобы продолжить установку, пожалуйста, заполните эту форму с данными начальной учетной записи администратора. Не волнуйтесь, вы всегда можете изменить эти настройки позже. + admin-email: E-mail Администратора + admin-notice: Это УНИКАЛЬНАЯ учетная запись супер-администратора, которая может ДАТЬ или ОТМЕНИТЬ привилегии администратора других пользователей. + nickname: Ник + password: Пароль + pwd-notice: 'Внимание: вам понадобится пароль для входа в систему. Пожалуйста, храните его в надежном месте.' + confirm-pwd: Подтвердите пароль + site-name: Название сайта + site-name-notice: Это будет показано на каждой странице. + finish: + title: Установка завершена + text: Blessing Skin Server был установлен. Спасибо, наслаждайтесь! diff --git a/resources/lang/ru_RU/skinlib.yml b/resources/lang/ru_RU/skinlib.yml new file mode 100755 index 0000000..7ba5dfc --- /dev/null +++ b/resources/lang/ru_RU/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: Загрузить новый скин +show: + title: Детали текстур + deleted: Запрашиваемая текстура уже удалена. + private: Запрашиваемая текстура является приватной и видимой только для администраторов и пользователя который её загрузил. +upload: + title: Загрузить текстуру + name-rule: Менее 32-х символов и не должно содержать специальных символов. + name-rule-regexp: Пользовательские правила имен применяются как :regexp + private-score-notice: Будет потрачено больше очков, чтобы установить его приватно. С вас будет взиматься плата :scores очков за килобайт. + invalid-size: Недопустимый файл :type (ширина :width, высота :height) + invalid-hd-skin: Недопустимый HD скин (ширина и высота должны делиться на 32) + lack-score: У вас недостаточно очков для загрузки этой текстуры. + repeated: Текстура уже загружена кем-то другим. Вы можете добавить её в свой шкаф напрямую. + success: Текстура :name была успешно загружена. +delete: + success: Текстура успешно удалена. +privacy: + success: Текстура была успешно изменена на :privacy . +rename: + success: Текстура успешно переименована в :name. +model: + success: Модель текстуры была изменена на :model успешно. +no-permission: У вас нет разрешения на модерирование этой текстуры. +non-existent: Нет такой текстуры. +report: + duplicate: Вы уже пожаловались на эту текстуру. Администраторы будут проверять ее как можно скорее. Вы также можете отслеживать состояние вашего отчета в Центре пользователей. + success: Спасибо за сообщение! Администраторы рассмотрят его как можно скорее. diff --git a/resources/lang/ru_RU/user.yml b/resources/lang/ru_RU/user.yml new file mode 100755 index 0000000..07d0c50 --- /dev/null +++ b/resources/lang/ru_RU/user.yml @@ -0,0 +1,101 @@ +--- +sign-success: Подписано успешно. Вы получили :score оч. +announcement: Объявление +no-unread: Нет новых уведомлений. +verification: + disabled: Подтверждение по электронной почте недоступно. + frequent-mail: Вы нажимаете кнопку отправки слишком быстро. Подождите 60 секунд. + verified: Ваша учетная запись уже подтверждена. + success: Ссылка для подтверждения была отправлена, пожалуйста, проверьте свой почтовый ящик. + failed: Мы не смогли отправить вам ссылку для подтверждения. Подробное сообщение :msg + mail: + title: Подтвердите ваш аккаунт на :sitename + message: Вы получили это письмо, потому что кто-то зарегистрировал аккаунт с этим адресом электронной почты на :sitename. + reset: 'Нажмите здесь, чтобы подтвердить ваш аккаунт: :url' + ignore: Если вы не регистрировали аккаунт, никаких дальнейших действий не требуется. +score-intro: + title: Что такое очки? + introduction: | + Мы используем систему подсчета очков, чтобы предотвратить такие действия, как выгрузка огромного количества текстур и случайная регистрация игроков. + Иначе добавление игроков, загрузка текстур или добавление элемента skinlib в ваш шкаф будет потреблять очки. + :return-score + + Сначала новые пользователи получат очков: :initial_scores, и вы можете получить очков: :score-from ~ :score-to, ежедневно выполняя вход в систему. + will-return-score: Очки будут возвращены, если вы удалили игроков, загруженные текстуры или элементы шкафа. + no-return-score: Баллы НЕ будут возвращены, если вы удалили игроков, загруженные текстуры или элементы гардероба. + rates: + storage: ':scores = 1 KB хранилище' + player: ':scores = 1 игрок' + closet: ':score = 1 предмет в шкафу' +closet: + add: + success: ':name успешно добавлен в гардероб.' + repeated: Вы уже добавили эту текстуру. + not-found: Мы не можем найти эту текстуру. + lack-score: У вас недостаточно баллов, чтобы положить его в гардероб. + rename: + success: Элемент успешно переименован в :name + remove: + success: Текстура была успешно удалена из шкафа. + non-existent: Текстура не существует в шкафу. +player: + login-notice: Теперь вы можете войти в систему с именем игрока, которым вы владеете вместо адреса электронной почты. + player-name-rule: + official: Имя игрока может содержать только буквы, цифры и подчеркивания. + cjk: Имя игрока может содержать буквы, цифры, подчеркивания и унифицированные идеографии CJK. + utf8: Имя игрока должно быть строкой UTF-8. + custom: Пользовательские правила имен игроков применяются на этом сайте. Пожалуйста, свяжитесь с администраторами для получения дополнительной информации. + player-name-length: Имя игрока должно быть не менее :min символов и не более :max символов. + add: + repeated: Имя игрока уже зарегистрировано. + lack-score: У вас недостаточно баллов, чтобы добавить его в гардероб. + success: Игрок :name успешно добавлен! + delete: + success: Игрок :name успешно удалён. + rename: + repeated: Это имя игрока занято. Пожалуйста, выберите другое. + success: Игрок :old был переименован на :new + set: + success: Текстура была успешно применена на игроке :name. + clear: + success: Текстуры игрока :name были успешно сброшены. +profile: + avatar: + title: Изменить аватар? + notice: Нажмите на иконку шестерёнки "" на любом скине в гардеробе, затем нажмите "Установить как аватар". Мы изменим вашу голову, текстурой этого скина. Если такой иконки нет, попробуйте отключить блокирующее расширение для рекламы. + wrong-type: Вы не можете установить плащ в качестве аватара. + success: Новый аватар успешно установлен. + reset: Сбросить аватар + password: + title: Изменить пароль + old: Старый пароль + new: Новый пароль + confirm: Повторите пароль + button: Сменить пароль + wrong-password: Неверный исходный пароль. + success: Пароль успешно обновлен, пожалуйста, войдите снова. + nickname: + title: Изменить никнейм + empty: На данный момент, никнейм не установлен. + success: Ник успешно обновлен на :nickname + email: + title: Изменить e-mail + new: Новый E-mail + password: Текущий пароль + button: Изменить e-mail + wrong-password: Неверный пароль. + existed: Этот адрес электронной почты занят. + success: Адрес электронной почты успешно обновлен, пожалуйста, войдите снова. + delete: + title: Удалить аккаунт + notice: Вы уверены, что хотите удалить учетную запись на :site? + admin: Аккаунт администратора не может быть удален. + button: Удалить мой аккаунт + modal-title: Вам необходимо ввести пароль, чтобы продолжить + modal-notice: | + Вы собираетесь удалить свой аккаунт. + Это навсегда! Нет резервных копий, нет восстановлений, нет волшебной кнопки отмены. + Мы предупреждали вас, хорошо? + password: Текущий пароль + wrong-password: Неверный пароль. + success: Ваша учетная запись успешно удалена. diff --git a/resources/lang/ru_RU/validation.yml b/resources/lang/ru_RU/validation.yml new file mode 100755 index 0000000..7e39aad --- /dev/null +++ b/resources/lang/ru_RU/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: 'Вы должны принять :attribute.' +active_url: 'Поле :attribute содержит недействительный URL.' +after: 'В поле :attribute должна быть дата после :date.' +after_or_equal: 'В поле :attribute должна быть дата после или равняться :date.' +alpha: 'Поле :attribute может содержать только буквы.' +alpha_dash: 'Поле :attribute может содержать только буквы, цифры, дефис и нижнее подчеркивание.' +alpha_num: 'Поле :attribute может содержать только буквы и цифры.' +array: 'Поле :attribute должно быть массивом.' +before: 'В поле :attribute должна быть дата до :date.' +before_or_equal: 'В поле :attribute должна быть дата до или равняться :date.' +between: + numeric: 'Поле :attribute должно быть между :min и :max.' + file: 'Размер файла в поле :attribute должен быть между :min и :max Килобайт(а).' + string: 'Количество символов в поле :attribute должно быть между :min и :max.' + array: 'Количество элементов в поле :attribute должно быть между :min и :max.' +boolean: 'Поле :attribute должно иметь значение логического типа.' +captcha: 'Некорректная капча.' +confirmed: 'Поле :attribute не совпадает с подтверждением.' +date: 'Поле :attribute не является датой.' +date_equals: 'Поле :attribute должно быть датой равной :date.' +date_format: 'Поле :attribute не соответствует формату :format.' +different: 'Поля :attribute и :other должны различаться.' +digits: 'Длина цифрового поля :attribute должна быть :digits.' +digits_between: 'Длина цифрового поля :attribute должна быть между :min и :max.' +dimensions: 'Поле :attribute имеет недопустимые размеры изображения.' +distinct: 'Поле :attribute содержит повторяющееся значение.' +email: 'Поле :attribute должно быть действительным электронным адресом.' +ends_with: 'Поле :attribute должно заканчиваться одним из следующих значений: :values' +exists: 'Выбранное значение для :attribute некорректно.' +file: 'Поле :attribute должно быть файлом.' +filled: 'Поле :attribute обязательно для заполнения.' +gt: + numeric: 'Поле :attribute должно быть больше :value.' + file: 'Размер файла в поле :attribute должен быть больше :value Килобайт(а).' + string: 'Количество символов в поле :attribute должно быть больше :value.' + array: 'Количество элементов в поле :attribute должно быть больше :value.' +gte: + numeric: 'Поле :attribute должно быть больше или равно :value.' + file: 'Размер файла в поле :attribute должен быть больше или равен :value Килобайт(а).' + string: 'Количество символов в поле :attribute должно быть больше или равно :value.' + array: 'Количество элементов в поле :attribute должно быть больше или равно :value.' +image: 'Поле :attribute должно быть изображением.' +in: 'Выбранное значение для :attribute ошибочно.' +in_array: 'Поле :attribute не существует в :other.' +integer: 'Поле :attribute должно быть целым числом.' +ip: 'Поле :attribute должно быть действительным IP-адресом.' +ipv4: 'Поле :attribute должно быть действительным IPv4-адресом.' +ipv6: 'Поле :attribute должно быть действительным IPv6-адресом.' +json: 'Поле :attribute должно быть JSON строкой.' +lt: + numeric: 'Поле :attribute должно быть меньше :value.' + file: 'Размер файла в поле :attribute должен быть меньше :value Килобайт(а).' + string: 'Количество символов в поле :attribute должно быть меньше :value.' + array: 'Количество элементов в поле :attribute должно быть меньше :value.' +lte: + numeric: 'Поле :attribute должно быть меньше или равно :value.' + file: 'Размер файла в поле :attribute должен быть меньше или равен :value Килобайт(а).' + string: 'Количество символов в поле :attribute должно быть меньше или равно :value.' + array: 'Количество элементов в поле :attribute должно быть меньше или равно :value.' +max: + numeric: 'Поле :attribute не может быть более :max.' + file: 'Размер файла в поле :attribute не может быть более :max Килобайт(а).' + string: 'Количество символов в поле :attribute не может превышать :max.' + array: 'Количество элементов в поле :attribute не может превышать :max.' +mimes: 'Поле :attribute должно быть файлом одного из следующих типов: :values.' +mimetypes: 'Поле :attribute должно быть файлом одного из следующих типов: :values.' +min: + numeric: 'Поле :attribute должно быть не менее :min.' + file: 'Размер файла в поле :attribute должен быть не менее :min Килобайт(а).' + string: 'Количество символов в поле :attribute должно быть не менее :min.' + array: 'Количество элементов в поле :attribute должно быть не менее :min.' +not_in: 'Выбранное значение для :attribute ошибочно.' +not_regex: 'Выбранный формат для :attribute ошибочный.' +numeric: 'Поле :attribute должно быть числом.' +password: Неверный пароль. +present: 'Поле :attribute должно присутствовать.' +recaptcha: 'Проверка reCAPTCHA не удалась.' +regex: 'Поле :attribute имеет ошибочный формат.' +required: 'Поле :attribute обязательно для заполнения.' +required_if: 'Поле :attribute обязательно для заполнения, когда :other равно :value.' +required_unless: 'Поле :attribute обязательно для заполнения, когда :other не равно :values.' +required_with: 'Поле :attribute обязательно для заполнения, когда :values указано.' +required_with_all: 'Поле :attribute обязательно для заполнения, когда :values указано.' +required_without: 'Поле :attribute обязательно для заполнения, когда :values не указано.' +required_without_all: 'Поле :attribute обязательно для заполнения, когда ни одно из :values не указано.' +same: 'Значения полей :attribute и :other должны совпадать.' +size: + numeric: 'Поле :attribute должно быть равным :size.' + file: 'Размер файла в поле :attribute должен быть равен :size Килобайт(а).' + string: 'Количество символов в поле :attribute должно быть равным :size.' + array: 'Количество элементов в поле :attribute должно быть равным :size.' +starts_with: 'Поле :attribute должно начинаться из одного из следующих значений: :values' +string: 'Поле :attribute должно быть строкой.' +timezone: 'Поле :attribute должно быть действительным часовым поясом.' +unique: 'Такое значение поля :attribute уже существует.' +uploaded: 'Загрузка поля :attribute не удалась.' +url: 'Поле :attribute имеет ошибочный формат.' +uuid: 'Поле :attribute должно быть корректным UUID.' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: Имя + player_name: имя игрока + identification: адрес электронной почты или имя игрока + email: E-Mail адрес + password: Пароль + password_confirmation: 'Подтверждение пароля' + title: Наименование + content: Контент diff --git a/resources/lang/zh_CN/admin.yml b/resources/lang/zh_CN/admin.yml new file mode 100755 index 0000000..bb99c36 --- /dev/null +++ b/resources/lang/zh_CN/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: 注册用户 + total-players: 角色总数 + total-textures: 上传材质总数 + disk-usage: 占用空间大小 + overview: 概览 + texture-uploads: 材质上传 + user-registration: 用户注册 +notifications: + send: + title: 发送通知 + success: 发送成功 + receiver: + title: 接收者 + all: 所有用户 + normal: 普通用户 + uid: 指定 UID + email: 指定邮箱 + title: 标题 + content: 内容(可使用 Markdown) +users: + operations: + non-existent: 用户不存在 + no-permission: 你无权操作此用户 + email: + success: 邮箱修改成功 + verification: + success: 用户的邮箱验证状态已修改 + nickname: + success: 昵称已成功设置为 :new + password: + success: 密码修改成功 + score: + success: 积分修改成功 + permission: 权限已更改 + delete: + success: 账号已被成功删除 +players: + no-permission: 你无权操作此角色 + textures: + non-existent: 材质 tid.:tid 不存在 + success: 角色 :player 的材质修改成功 + name: + success: 角色名成功更改为 :player + owner: + success: 角色 :player 已被转给用户 :user 。 + delete: + success: 角色已被成功删除 +customize: + change-color: + title: 更改配色 + colors: + navbar: 顶部导航栏 + sidebar: + dark: 侧栏(暗) + light: 侧栏(亮) +i18n: + add: 添加新条目 + added: 条目增加成功 + updated: 条目更新成功 + deleted: 条目已删除 + group: 分组 + key: 键 + text: 文本 + tip: 如何使用本页面的功能? +status: + info: 信息 + health: 健康 + bs: + name: Blessing Skin + version: 版本 + env: 应用环境 + debug: 是否处于调试状态 + commit: 提交 + laravel: Laravel 版本 + server: + name: 服务器 + php: PHP 版本 + web: Web 服务软件 + os: 操作系统 + db: + name: 数据库 + type: 服务器类型 + host: 主机 + port: 端口 + username: 用户名 + database: 数据库 + prefix: 数据表前缀 + plugins: 已开启的插件 (:amount) +plugins: + readme: 说明 + operations: + title: 操作 + enabled: ':plugin 已启用' + unsatisfied: + notice: 无法启用此插件,因为其仍有冲突或未满足的依赖关系。请检查以下插件的版本,更新或安装它们并禁用存在冲突的插件: + disabled: '「:name」插件未启用' + version: '「:title」的版本不符合要求 ":constraint"' + conflict: '「:title」插件与此插件不能同时运行' + disabled: ':plugin 已禁用' + deleted: 插件已被成功删除 + no-config-notice: 插件未安装或未提供配置页面 + no-readme-notice: 这个插件没有说明文件。 + not-found: 插件不存在 + market: + unresolved: 无法下载此插件,因为其仍有冲突或未满足的依赖关系。请检查以下插件的版本,更新或安装它们并禁用存在冲突的插件: + connection-error: 无法连接至插件市场源,错误信息::error + non-existent: 插件 :plugin 不存在 + install-success: 插件安装成功 +update: + complete: 更新完成 + info: + title: 更新信息 + up-to-date: 已更新至最新版本。 + available: 有更新可用。 + versions: + latest: "最新版本:" + current: "当前版本:" + check-github: 查看 GitHub Releases + button: 马上升级 + cautions: + title: 注意事项 + link: 点击了解详情 + text: | + 请根据你的主机所在位置(国内/国外)选择更新源。 + 如错选至相对于你的主机速度较慢的源,可能会造成检查与下载更新页面长时间无响应。 + 如何更换更新源? + errors: + connection: "无法访问当前更新源。详细信息::error" + spec: 不支持当前的更新源。 + php: PHP 版本过低,至少需要 :version。 +download: + errors: + download: '下载失败。原因::error' + shasum: 文件校验失败,请重新下载。 + unzip: 解压失败。 +invalid-action: 无效的操作名 diff --git a/resources/lang/zh_CN/auth.yml b/resources/lang/zh_CN/auth.yml new file mode 100755 index 0000000..bda65c0 --- /dev/null +++ b/resources/lang/zh_CN/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: 登录 + message: 登录以管理您的角色与皮肤 + success: 登录成功,欢迎回来 +check: + anonymous: 未授权的访问,请先登录 + verified: 你必须验证邮箱后才能访问此页面 + admin: 只有管理员才能访问此页面 + banned: 你已被本站封禁,详情请联系站点管理员 +register: + title: 注册 + message: 欢迎使用 :sitename! + success: 注册成功,正在跳转... + max: 你在本站注册的账号已达到上限 :regs 个,无法继续注册 +forgot: + title: 忘记密码 + message: 我们将会向您发送一封验证邮件 + disabled: 本站已关闭重置密码功能 + frequent-mail: 你邮件发送得太频繁啦,过会儿再点发送吧 + unregistered: 该邮箱尚未注册 + success: 邮件已发送,一小时内有效,请注意查收。 + failed: 邮件发送失败,详细信息::msg + ignore: 如果您并没有访问过我们的网站,或没有进行上述操作,请忽略这封邮件。 您不需要退订或进行其他进一步的操作。 + reset: 重置密码 + notice: 本邮件由系统自动发送,就算你回复了我们也不会回复你哦 + mail: + title: 重置您在 :sitename 上的账户密码 + message: 您收到这封邮件,是因为有人在 :sitename 的密码重置功能中使用了您的地址。 + reset: '点击此链接重置您的密码::url' + ignore: 如果您并没有访问过我们的网站,或没有进行上述操作,请忽略这封邮件。 +reset: + title: 重置密码 + button: 重置 + invalid: 无效的链接 + expired: 链接已过期 + message: ':username,在这里重置你的密码' + success: 密码重置成功 +bind: + title: 绑定邮箱 + button: 绑定 + message: 你需要绑定邮箱地址以继续使用本站 + introduction: 邮箱地址仅用于重置密码,我们不会向您发送任何垃圾邮件 + registered: 此邮箱已被占用 +verify: + title: 邮箱验证 + invalid: 无效的链接 + not-matched: 邮箱不匹配。 +validation: + user: 用户不存在 + password: 密码错误 +logout: + success: 登出成功 +oauth: + authorization: + title: 授权 + introduction: 第三方应用 :name 正在向您请求获取权限。 + button: 授权 + permissions: 权限 + scope: + user: + read: 登录并读取您的个人信息 + notification: + read: 允许应用读取您的通知 + readwrite: 允许应用发送通知 + player: + read: 允许应用读取您的角色 + readwrite: 允许应用创建、读取、更改和删除您的角色 + closet: + read: 允许应用读取您的衣柜物品 + readwrite: 允许应用创建、读取、更改和删除您的衣柜物品 + users-management: + read: 允许应用读取皮肤站的用户 + readwrite: 允许应用创建、读取、更改和删除皮肤站的用户 + players-management: + read: 允许应用读取皮肤站的角色 + readwrite: 允许应用创建、读取、更改和删除皮肤站的角色 + closet-management: + read: 允许应用读取您的皮肤站内用户的衣柜物品 + readwrite: 允许应用创建、读取、更改和删除用户的衣柜物品 + reports-management: + read: 允许应用读取用户的举报 + readwrite: 允许应用读取和处理用户的举报 +email: 电子邮箱 +register-link: 注册新账号 diff --git a/resources/lang/zh_CN/errors.yml b/resources/lang/zh_CN/errors.yml new file mode 100755 index 0000000..549ad75 --- /dev/null +++ b/resources/lang/zh_CN/errors.yml @@ -0,0 +1,20 @@ +--- +http: + msg-403: 您无权访问此页面。 + msg-404: 这里什么都没有哦 + msg-500: 服务器内部错误,请稍后再试。 + msg-503: 网站维护中 + method-not-allowed: 不允许的 HTTP 请求方法 + csrf-token-mismatch: Token 不正确,请尝试刷新页面 + ie: 不支持此浏览器,请使用其它现代浏览器(如 Firefox 或 Chrome)。 +general: + title: 出现错误 +exception: + code: '错误码::code' + detail: '详细信息::msg' + message: | + 如果你是访客,这说明网站程序出现了一些错误,请稍后再试或者联系站长。 + 如果你是站长,那么请开启 .env 中的 APP_DEBUG 查看详细信息。 +plugins: + duplicate: '【插件定义重复】:dir1 目录下的插件与 :dir2 目录下的插件使用了相同的 name 定义并造成了冲突。请检查你的插件目录,移除其中一个插件或者使用不同的 name 属性。' + boot: '「:plugin」插件存在错误,无法加载。' diff --git a/resources/lang/zh_CN/front-end.yml b/resources/lang/zh_CN/front-end.yml new file mode 100755 index 0000000..f00bd74 --- /dev/null +++ b/resources/lang/zh_CN/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: 登录 + loggingIn: 登录中 + tooManyFails: + captcha: 你尝试的次数太多啦,请输入验证码 + recaptcha: 你尝试的次数太多啦,请通过 reCAPTCHA 人机验证 + emptyEmail: 你还没有填写邮箱哦 + invalidConfirmPwd: 密码和确认的密码不一样诶? + emptyNickname: 你还没有填写昵称哦 + register: 注册 + registering: 注册中 + send: 发送 + sending: 发送中 + reset: 重置 + resetting: 重置中 + nickname: 昵称 + player-name: 游戏内角色名 + email: 电子邮箱 + identification: Email 或角色名 + password: 密码 + captcha: 请输入验证码 + change-captcha: 点击以更换图片 + login-link: 已经有账号了?登录 + forgot-link: 忘记密码? + keep: 记住我 + repeat-pwd: 重复密码 + nickname-intro: 昵称可使用汉字,不可包含特殊字符 + player-name-intro: 游戏内的角色名,注册后可修改 + forgot: + login-link: 我又想起来了 +skinlib: + private: 私密 + anonymous: 请先登录 + reset: 清除筛选 + addToCloset: 添加至衣柜 + removeFromCloset: 从衣柜中移除 + setItemName: 给你的皮肤起个名字吧~ + applyNotice: 收藏后可以在我的衣柜里将皮肤应用至角色 + emptyItemName: 你还没有填写要收藏的材质名称啊 + setNewTextureName: '请输入新的材质名称:' + emptyNewTextureName: 你还没有输入新名称啊 + seeMyUpload: 我上传的 + apply: 立即使用 + filter: + skin: '(任意模型)' + steve: '(Steve)' + alex: '(Alex)' + cape: '(披风)' + uploader: '用户(UID = :uid)上传' + allUsers: 所有用户 + sort: + title: 排序 + time: 最新上传 + likes: 最多收藏 + emptyTextureName: 给你的材质起个名字吧 + emptyUploadFile: 你还没有上传任何文件哦 + fileExtError: '错误:皮肤文件必须为 PNG 格式' + uploading: 上传中 + setAsPrivate: 设为隐私 + setAsPublic: 设为公开 + setPublicNotice: 要将此材质设置为公开吗? + setPrivateNotice: 要将此材质设置为私有吗? + deleteNotice: 真的要删除此材质吗? + setNewTextureModel: "请选择新的材质适用模型:" + upload: + texture-name: 材质名称 + texture-type: 材质类型 + select-file: 选择文件 + privacy-notice: 其他人将不会在皮肤库中看到此材质 + set-as-private: 设置为私密材质 + button: 确认上传 + cost: 这会消耗您约 :score 积分。 + award: 上传公开材质至皮肤库可以获得 :score 积分奖励。 + show: + anonymous: 登录后才能使用衣柜哦 + likes: 收藏人数 + detail: 详细信息 + name: 名称 + edit: 修改 + model: 适用模型 + size: 文件大小 + uploader: 上传者 + upload-at: 上传日期 + download: 下载 + delete-texture: 删除材质 + manage-notice: 材质设为隐私或被删除后将会从每一个收藏者的衣柜中移除。 + report: + title: 举报 + reason: 请填写举报原因 + positive: 为鼓励用户积极维护皮肤库的环境,每举报一个材质你可以获得 :score 积分的奖励。但是,如果被发现有恶意举报等行为,奖励的积分将会被全部收回,并且有可能受到额外的惩罚。 + negative: 为了减轻恶意举报带来的工作量,我们会在你提交举报时扣除 :score 积分。不用担心,举报通过后暂扣的积分将会全部返还,并且可以获得额外的积分奖励。 +user: + signRemainingTime: ':time :unit 后可签到' + timeUnitHour: 小时 + timeUnitMin: 分钟 + emptyClosetMsg: >- +

衣柜里啥都没有哦~

皮肤库看看吧~

+ renameItem: 重命名物品 + removeItem: 从衣柜中移除 + setAsAvatar: 设为头像 + viewInSkinlib: 在皮肤库中查看 + switch2dPreview: 切换 2D 预览 + switch3dPreview: 切换 3D 预览 + removeFromClosetNotice: 确定要从衣柜中移除此材质吗? + emptySelectedTexture: 你还没有选择要应用的材质哦 + renameClosetItem: '请输入此衣柜物品的新名称:' + changePlayerName: '请输入角色名:' + emptyPlayerName: 你还没有填写名称哦 + deletePlayer: 真的要删除该玩家吗? + deletePlayerNotice: 这将是永久性的删除 + chooseClearTexture: 选择要删除的材质类型 + noClearChoice: 您还没选择要删除的材质类型 + setAvatar: 确定要将此材质设置为用户头像吗? + setAvatarNotice: 将会自动截取皮肤头部 + resetAvatarConfirm: 确定要重置头像吗? + typeToSearch: 输入即搜索 + useAs: 使用... + resetSelected: 重置已选材质 + closet: + upload: 上传材质 + use-as: + title: 要给哪个角色使用呢? + empty: 你好像还没有添加任何角色哦 + used: + title: 使用情况 + players: 角色数量 + storage: 存储空间 + cur-score: 当前积分 + score-notice: 点击积分查看说明 + sign: 签到 + player: + operation: 操作 + edit-pname: 修改角色名 + delete-texture: 删除材质 + delete-player: 删除角色 + add-player: 添加新角色 + texture-empty: 未上传 + verification: + title: 验证你的邮箱地址 + message: 你必须验证你的邮箱才能正常使用本站的皮肤托管等功能。没有收到验证邮件? + resend: 点击这里再次发送。 + sending: 正在发送…… + oauth: + id: 客户端 ID + name: 应用名 + secret: 客户端 Secret + redirect: 回调 URL + modifyName: 更改应用名 + modifyUrl: 更改回调 URL + create: 创建应用 + confirmRemove: 确认要删除这个应用吗?此操作不可撤销。 +admin: + operationsTitle: 更多操作 + permission: 权限 + deleteUser: 删除 + changeEmail: 修改邮箱 + newUserEmail: '请输入新邮箱:' + verification: 邮箱验证 + toggleVerification: 修改邮箱验证状态 + changeNickName: 修改昵称 + newUserNickname: '请输入新昵称:' + changePassword: 更改密码 + newUserPassword: '请输入新密码:' + changeScore: 更改积分 + newScore: '请输入积分值:' + changePermission: 更改权限 + newPermission: '请选择新的权限:' + deleteUserNotice: 真的要删除此用户吗?此操作不可恢复 + banned: 封禁 + normal: 普通用户 + admin: 管理员 + superAdmin: 超级管理员 + unverified: 未验证 + verified: 已验证 + pidNotice: >- + 输入要更换的材质的 ID,输入 0 即可清除该角色的材质 + changeTexture: 更换材质 + changePlayerName: 更改角色名 + changeOwner: 更换角色拥有者 + textureType: 材质类型 + deletePlayer: 删除 + changePlayerOwner: '请输入此角色要让渡至的用户 ID:' + deletePlayerNotice: 真的要删除此角色吗?此操作不可恢复 + changePlayerNameNotice: '请输入新的角色名:' + emptyPlayerName: 您还没填写角色名呢 + configurePlugin: 配置 + deletePlugin: 删除 + noDependencies: 无要求 + pluginTitle: 插件 + pluginAuthor: 作者 + pluginVersion: 版本 + pluginReadme: 说明 + pluginDescription: 描述 + pluginDependencies: 依赖关系 + installPlugin: 安装 + pluginInstalling: 正在安装... + updatePlugin: 更新 + pluginUpdating: 正在更新... + confirmUpdate: 确定将「:plugin」从 :old 升级至 :new? + enablePlugin: 启用 + disablePlugin: 禁用 + confirmDeletion: 真的要删除这个插件吗? + uploadArchive: 上传压缩包 + uploadArchiveNotice: 通过上传 Zip 压缩包来安装插件。 + downloadRemote: 从远程下载 + downloadRemoteNotice: 通过远程 URL 来下载 Zip 压缩包并安装插件。 + updateButton: 马上升级 + downloading: 正在下载更新包 + i18n: + group: 分组 + key: 键 + text: 文本 + empty: '(空)' + modify: 修改 + delete: 删除 + updating: '请输入新的文本内容:' + confirmDelete: 确认删除吗?此操作不可恢复。 +report: + tid: 材质 ID + reporter: 举报人 + reason: 举报原因 + status-title: 状态 + status: + - 正在处理 + - 处理完成 + - 已被拒绝 + time: 举报时间 + delete: 删除 + ban: 封禁 + reject: 拒绝举报 +general: + skin: 皮肤 + cape: 披风 + fatalError: 严重错误 + confirmLogout: 确定要登出吗? + confirm: 确定 + cancel: 取消 + submit: 提交 + close: 关闭 + more: 更多 + tip: 提示 + noResult: 无结果 + texturePreview: 材质预览 + walk: 行走 + run: 奔跑 + rotation: 旋转 + pause: 暂停 + reset: 重置 + skinlib: 皮肤库 + wait: 请稍等... + csrf: 页面已过期,请刷新页面。 + user: + email: 邮箱 + nickname: 昵称 + score: 积分 + register-at: 注册时间 + player: + owner: 拥有者 + player-name: 角色名 + previews: 预览材质 + last-modified: 修改时间 +colors: + black: 黑色 + white: 白色 + gray: 灰色 + prev: 上个背景 + next: 下个背景 +vendor: + datatable: + search: 搜索 + prev: 上一页 + next: 下一页 diff --git a/resources/lang/zh_CN/general.yml b/resources/lang/zh_CN/general.yml new file mode 100755 index 0000000..94d7595 --- /dev/null +++ b/resources/lang/zh_CN/general.yml @@ -0,0 +1,59 @@ +--- +index: 首页 +skinlib: 皮肤库 +user-center: 用户中心 +logout: 登出 +login: 登录 +register: 现在注册 +profile: 个人资料 +admin-panel: 管理面板 +explore: 浏览 +manage: 管理 +anonymous: 未登录 +back: 返回 +dashboard: 仪表盘 +my-closet: 我的衣柜 +my-reports: 我的举报 +developer: 高级功能 +oauth-manage: OAuth2 应用 +player-manage: 角色管理 +user-manage: 用户管理 +report-manage: 举报管理 +plugin-manage: 插件管理 +plugin-market: 插件市场 +plugin-configs: 插件配置 +customize: 个性化 +i18n: 多语言 +options: 站点配置 +score-options: 积分配置 +res-options: 资源配置 +status: 运行状态 +check-update: 检查更新 +download-update: 下载更新 +close: 关闭 +skin: 皮肤 +cape: 披风 +submit: 提交 +cancel: 取消 +yes: true +no: false +op-success: 操作成功 +unknown: 未知 +notice: 提示 +illegal-parameters: 非法参数 +private: 私密 +public: 公开 +unexistent-user: 不存在的用户 +player-banned: 该角色拥有者已被本站封禁 +texture-deleted: 请求的材质已被删除 +user: + email: 邮箱 + nickname: 昵称 + password: 密码 + score: 积分 + register-at: 注册时间 +player: + owner: 拥有者 + player-name: 角色名 + previews: 预览材质 + last-modified: 修改时间 diff --git a/resources/lang/zh_CN/index.yml b/resources/lang/zh_CN/index.yml new file mode 100755 index 0000000..309f5df --- /dev/null +++ b/resources/lang/zh_CN/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: 优势 + first: + icon: fa-users + name: 多角色 + desc: 一个账户可绑定多个游戏角色 + second: + icon: fa-share-alt + name: 分享 + desc: 浏览皮肤库,添加喜爱的皮肤并与好友分享 + third: + icon: fa-cloud + name: 腾讯云CDN + desc: 全国嗖嗖飞快!! +introduction: ':sitename 提供 Minecraft 角色皮肤的上传以及托管服务。配合 CustomSkinLoader 等换肤 Mod,你可以为你的游戏角色设置皮肤与披风,并让其他玩家在游戏中看到。' +start: 开始使用 diff --git a/resources/lang/zh_CN/options.yml b/resources/lang/zh_CN/options.yml new file mode 100755 index 0000000..d1d6a8d --- /dev/null +++ b/resources/lang/zh_CN/options.yml @@ -0,0 +1,179 @@ +--- +option-saved: 设置已保存。 +homepage: + title: 首页配置 + home_pic_url: + title: 首页图片地址 + hint: 相对于首页的路径或者完整的 URL,留空以使用默认背景 + favicon_url: + title: 网站图标 + hint: 相对 public/ 的路径或者完整的 URL + description: 所使用的图像必须具有相同的宽度和高度(留空以使用默认图标) + transparent_navbar: + title: 首页导航栏透明 + label: 开启后首页顶部的导航栏将透明化,但页面滚动到底部时会变为不透明 + hide_intro: + title: 隐藏底部的网站介绍 + label: 开启后页面将不再需要滚动条,就像 2.x 版本中的首页那样 + fixed_bg: + title: 固定首页背景 + label: 开启后背景不会随页面滚动而滚动 + copyright_prefer: + title: 程序版权信息 + description: "每种支持的语言都可以对应不同的程序版权信息,如果想要编辑某种特定语言下的版权信息,请在右上角切换至该语言后再提交修改。对于任何恶意修改页面右下角的版权信息(包括不限于删除、修改作者信息、修改链接指向)的用户,作者保留对其追究责任的权利。" + copyright_text: + title: 自定义版权文字 + description: 自定义版权文字内可使用占位符,{site_name} 将会被自动替换为站点名称,{site_url} 会被替换为站点地址。每种支持的语言都可以对应不同的自定义版权文字,如果想要编辑某种特定语言下的版权文字,请在右上角切换至该语言后再提交修改。 +customJsCss: + title: 自定义 CSS/JavaScript + message: | + 内容将会被追加至每个页面的 <style> 和 <script> 标签中。
+ - 这里有一些有用的示例:「自定义 CSS JavaScript」功能的一些实例 + custom_css: CSS + custom_js: JavaScript +rate: + title: 积分换算 + score_per_storage: + title: 存储 + addon: 积分 = 1 KB + private_score_per_storage: + title: 私密材质存储 + addon: 积分 = 1 KB + hint: 上传私密材质将消耗更多积分 + score_per_closet_item: + title: 收藏消耗积分 + addon: 积分 = 一个衣柜物品 + return_score: + title: 积分返还 + label: 用户删除角色/材质/收藏时返还积分 + score_per_player: + title: 角色 + addon: 积分 = 一个角色 + user_initial_score: 新用户默认积分 +report: + title: 材质举报 + reporter_score_modification: + title: 提交举报所需积分 + description: 举报材质时【奖励】或者【扣除】举报者一定的积分。设置为正数表示奖励相应积分,设置为负数时表示扣除相应积分,设置为 0 可关闭本功能。举报时扣除积分可以一定程度上减少恶意举报,如果举报通过后,扣除的积分将会被返还。 + reporter_reward_score: + title: 举报通过后奖励积分 +sign: + title: 签到配置 + sign_score: + title: 签到获得积分 + addon1: 积分 ~ + addon2: 积分 + sign_gap_time: + title: 签到间隔时间 + addon: 小时 + sign_after_zero: + title: 签到时间 + label: 每天零点后可签到 + hint: 勾选后将无视上一条,每天零时后均可签到 +sharing: + title: 奖励分享 + score_award_per_texture: + title: 每上传一个材质奖励 + take_back_scores_after_deletion: + title: 回收积分 + label: 改为私有或删除上传的材质后收回奖励积分 + score_award_per_like: + title: 材质每被收藏一次奖励上传者 +general: + title: 常规选项 + site_name: 站点标题 + site_description: + title: 站点描述 + description: 每种支持的语言都可以对应不同的站点标题与站点描述文本,如果想要编辑某种特定语言下的站点标题与描述,请在右上角切换至该语言后再提交修改。 + site_url: + title: 站点地址(URL) + hint: 以 http(s):// 开头,不要以 / 结尾 + register_with_player_name: + title: 使用角色名注册 + label: 注册时要求填写游戏内角色名 + require_verification: + title: 邮箱验证 + label: 用户必须验证邮箱后才能使用皮肤托管等功能 + regs_per_ip: 每个 IP 限制注册数 + max_upload_file_size: + title: 最大允许上传大小 + hint: "PHP 限制::size,定义在 php.ini 中。" + player_name_rule: + title: 角色名规则 + official: 大小写字母数字下划线(Mojang 官方的用户名规则) + cjk: 允许中文字符(中日韩统一表意文字) + utf8: 允许所有有效的 UTF-8 字符(不包括空格) + custom: 自定义(使用下方设置的正则表达式) + custom_player_name_regexp: + title: 自定义角色名规则 + hint: 正则表达式,仅当上一选项为「自定义」时生效。留空表示允许使用任意字符。 + placeholder: 正则表达式,不懂别乱填 + player_name_length: + title: 角色名长度 + suffix: 个字符 + auto_del_invalid_texture: + title: 失效材质 + label: 自动删除失效材质 + hint: 自动从皮肤库中删除文件不存在的材质记录 + allow_downloading_texture: + title: 直接下载材质 + label: 允许用户直接下载皮肤库中材质的原始文件 + status_code_for_private: + title: 拒绝访问私密材质时的 HTTP 代码 + texture_name_regexp: + title: 材质名称规则 + hint: 皮肤库上传材质时名称的正则表达式。留空表示允许使用除半角单双引号、反斜杠以外的任意字符。 + placeholder: 正则表达式,不懂别乱填 + content_policy: + title: 材质内容策略 + description: 在材质上传页面将会显示此内容,支持 Markdown。如果想要编辑某种特定语言下的内容政策,请在右上角切换至该语言后再提交修改。 +announ: + title: 站点公告 + announcement: + description: 可使用 Markdown 进行排版。每种支持的语言都可以对应不同的站点公告,如果想要编辑某种特定语言下的公告,请在右上角切换至该语言后再提交修改。 +meta: + title: SEO 标签 + meta_keywords: + title: 关键词 + hint: 使用半角逗号分隔 + meta_description: + title: 描述 + hint: 留空以使用 站点配置 中的站点描述 + meta_extras: + title: 其它自定义 标签 +recaptcha: + recaptcha_invisible: + title: 隐藏 + label: 开启隐藏式人机验证模式 +res-warning: 本页面仅供高级用户使用。如果您不清楚这些设置的含义,请不要随意修改它们! +resources: + title: 资源文件配置 + hint: 如果启用了 CDN 缓存请适当修改这些配置 + force_ssl: + title: 强制 SSL + label: 强制使用 HTTPS 协议加载资源 + hint: 请确认 SSL 可用后再开启 + auto_detect_asset_url: + title: 资源地址 + label: 自动判断资源文件地址 + description: 根据当前 URL 自动加载资源文件,如果关闭则将根据「站点地址」填写的内容加载。如果出现 CDN 回源问题请关闭 + cache_expire_time: + title: 缓存失效时间 + hint: 秒数,86400 = 一天,31536000 = 一年 + cdn_address: + title: 前端资源文件 CDN + hint: 如果地址不对将导致前端文件无法加载 + description: | + 填写的 CDN 地址必须是 /public 目录的镜像,此目录下的所有文件都将会从 CDN 加载。
+ 测试方法:检查 {填写的地址}/app/manifest.json 是否能够访问。 +cache: + title: 缓存配置 + clear: 清除缓存 + cleared: 缓存已清除。 + driver: 当前缓存驱动为 「:driver」 + enable_avatar_cache: + title: 头像 + label: 启用头像缓存 + enable_preview_cache: + title: 材质预览 + label: 启用材质预览缓存 diff --git a/resources/lang/zh_CN/setup.yml b/resources/lang/zh_CN/setup.yml new file mode 100755 index 0000000..43333b2 --- /dev/null +++ b/resources/lang/zh_CN/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "无法连接至 :type 服务器,请检查你的配置。服务器返回的信息::msg" +locked: + title: 已安装过 + text: Blessing Skin Server 看起来已经安装妥当。如果想重新安装,请删除 storage 目录下的 install.lock 文件。 + button: 返回首页 +updates: + success: + title: 升级成功 +wizard: + master: + title: Blessing Skin Server 安装程序 + welcome: + title: 欢迎 + button: 下一步 + text: 欢迎使用 Blessing Skin Server v:version! + database: + title: 填写数据库信息 + text: 您提供的数据库将用于存储 Blessing Skin 的数据 + type: 数据库类型 + host: 数据库服务器地址 + port: 端口 + username: 数据库用户名 + password: 数据库密码 + db: 数据库名称 + db-notice: 如果您使用 SQLite,那么您应该填写 SQLite 数据库文件的路径,并且无需填写其它信息 + prefix: 数据表前缀(可选) + prefix-notice: 通常您不需要填写此项,除非您有向同一数据库安装多个 Blessing Skin 的需要 + info: + title: 填写信息 + button: 开始安装 + text: 你需要填写一些基本信息。无需担心填错,这些信息以后可以再次修改。 + admin-email: 管理员邮箱 + admin-notice: 这是唯一的超级管理员账号,可添加或移除其他管理员。 + nickname: 昵称 + password: 密码 + pwd-notice: '重要:你将需要此密码来登录管理皮肤站,请将其保存在安全的位置。' + confirm-pwd: 重复密码 + site-name: 站点名称 + site-name-notice: 将会显示在首页以及标题栏 + finish: + title: 安装成功! + text: Blessing Skin Server 安装完成。你是否还沉浸在愉悦的安装过程中?很遗憾,一切皆已完成! :) diff --git a/resources/lang/zh_CN/skinlib.yml b/resources/lang/zh_CN/skinlib.yml new file mode 100755 index 0000000..d1b7051 --- /dev/null +++ b/resources/lang/zh_CN/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: 上传新皮肤 +show: + title: 材质详情 + deleted: 请求的材质文件已经被删除 + private: 请求的材质已经设为私密,仅上传者和管理员可查看 +upload: + title: 上传材质 + name-rule: 材质名称应该小于 32 个字节且不能包含奇怪的符号 + name-rule-regexp: 本站已应用特殊的名称规则::regexp + private-score-notice: 私密材质将会消耗更多的积分:每 KB 存储空间 :score 积分 + invalid-size: 不是有效的 :type 文件(宽 :width,高 :height) + invalid-hd-skin: 不是有效的高清皮肤(宽和高不是 32 的整数倍) + lack-score: 积分不足 + repeated: 已经有人上传过这个材质了,直接添加到衣柜使用吧~ + success: 材质 :name 上传成功 +delete: + success: 材质已被成功删除 +privacy: + success: 材质已被设为 :privacy +rename: + success: 材质名称已被成功设置为 :name +model: + success: 材质的适用模型已被修改为 :model +no-permission: 你没有权限修改此材质 +non-existent: 材质不存在 +report: + duplicate: 您已经举报过该材质了,请耐心等待管理员处理。您可以在用户中心查看举报的处理进度。 + success: 举报已提交,请等待管理员处理 diff --git a/resources/lang/zh_CN/user.yml b/resources/lang/zh_CN/user.yml new file mode 100755 index 0000000..69ddc86 --- /dev/null +++ b/resources/lang/zh_CN/user.yml @@ -0,0 +1,102 @@ +--- +sign-success: 签到成功,获得了 :score 积分 +announcement: 公告 +no-unread: 无未读通知 +verification: + disabled: 本站已关闭邮箱验证功能 + frequent-mail: 你邮件发送得太频繁啦,过 60 秒后再点发送吧 + verified: 你已经验证过邮箱了 + success: 验证邮件已发送,请检查你的收件箱。 + failed: 邮件发送失败,详细信息::msg + mail: + title: 验证您在 :sitename 上的账户邮箱 + message: 您收到这封邮件,是因为有人在 :sitename 注册时使用了本邮箱地址。 + reset: '点击此链接验证您的邮箱::url' + ignore: 如果您并没有访问过我们的网站,或没有进行上述操作,请忽略这封邮件。 +score-intro: + title: 积分是什么? + introduction: | + 为了防止用户滥用材质上传功能导致占用过多的存储空间,本站已启用积分系统。 + 添加角色、上传材质,以及添加皮肤库里的材质到衣柜等操作均会消耗积分。 + :return-score + + 本站用户初始积分为 :initial_score,每日签到可以随机获得 :score-from ~ :score-to 积分。 + will-return-score: 删除已经添加的角色、已上传的材质、衣柜中的收藏物品时将会返还相应积分。 + no-return-score: 删除已经添加的角色、已上传的材质、衣柜中的收藏物品时不会返还相应积分。 + rates: + storage: ':score 积分 = 1 KB 存储空间' + player: ':score 积分 = 1 个角色' + closet: ':score 积分 = 1 个衣柜收藏' +closet: + add: + success: 材质 :name 收藏成功 + repeated: 你已经收藏过这个材质啦 + not-found: 该材质不存在 + lack-score: 收藏失败,积分不足 + rename: + success: 衣柜物品成功重命名至 :name + remove: + success: 材质已从衣柜中移除 + non-existent: 衣柜中不存在此材质 +player: + login-notice: 你可以使用你所拥有的角色名来登录皮肤站。 + player-name-rule: + official: 角色名只能包含拉丁字母、数字以及下划线。 + cjk: 角色名可使用拉丁字母、数字、下划线以及汉字(中日韩统一表意文字)。 + utf8: 角色名必须是 UTF-8 字符串。 + custom: 本站使用了自定义的角色名规则,详情请咨询站点管理员。 + player-name-length: 角色名最少要求 :min 个字符,最多不超过 :max 个字符。 + add: + repeated: 该角色名已被占用 + lack-score: 添加角色失败,积分不足 + success: 成功添加了角色 :name + delete: + success: 角色 :name 已被删除 + rename: + repeated: 该角色名已被占用 + success: 角色 :old 已更名为 :new + set: + success: 材质已成功应用至角色 :name + clear: + success: 角色 :name 的材质已被成功重置 +profile: + avatar: + title: 更改头像? + notice: 在衣柜中任意皮肤的右下角「」图标处点击「设为头像」,即可自动截取该皮肤的头部作为头像。如果看不到这个图标,请尝试关闭你的广告过滤扩展。 + wrong-type: 披风不能被设置为头像 + success: 设置成功 + reset: 重置头像 + password: + title: 更改密码 + old: 原密码(若使用其他登录方式注册则为空) + new: 新密码 + confirm: 确认密码 + button: 修改密码 + wrong-password: 原密码错误 + success: 密码修改成功,请重新登录 + nickname: + title: 更改昵称 + empty: 当前未设置昵称, + success: 昵称已成功设置为 :nickname + email: + title: 更改邮箱 + new: 新邮箱 + password: 当前密码 + button: 修改邮箱 + wrong-password: 密码错误 + existed: 此邮箱已被占用 + success: 邮箱修改成功,请重新登录 + delete: + title: 删除账号 + notice: 确定要删除你在 :site 上的账号吗? + admin: 拥有管理员权限的账号不能被删除 + button: 删除我的账号 + modal-title: 这是危险操作,输入密码以继续 + modal-notice: | + 此操作不可恢复! + 你所上传至皮肤库的材质仍会被保留,但你的角色将被永久删除。 + 我们不提供任何备份,或者神奇的撤销按钮。 + 我们警告过你了,确定要这样做吗? + password: 当前密码 + wrong-password: 密码错误 + success: 账号已被成功删除 diff --git a/resources/lang/zh_CN/validation.yml b/resources/lang/zh_CN/validation.yml new file mode 100755 index 0000000..d5daedc --- /dev/null +++ b/resources/lang/zh_CN/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: '您必须接受 :attribute。' +active_url: ':attribute 不是一个有效的网址。' +after: ':attribute 必须要晚于 :date。' +after_or_equal: ':attribute 必须要等于 :date 或更晚。' +alpha: ':attribute 只能由字母组成。' +alpha_dash: ':attribute 只能由字母、数字、短划线(-)和下划线(_)组成。' +alpha_num: ':attribute 只能由字母和数字组成。' +array: ':attribute 必须是一个数组。' +before: ':attribute 必须要早于 :date。' +before_or_equal: ':attribute 必须要等于 :date 或更早。' +between: + numeric: ':attribute 必须介于 :min - :max 之间。' + file: ':attribute 必须介于 :min - :max KB 之间。' + string: ':attribute 必须介于 :min - :max 个字符之间。' + array: ':attribute 必须只有 :min - :max 个单元。' +boolean: ':attribute 必须为布尔值。' +captcha: '验证码不正确。' +confirmed: ':attribute 两次输入不一致。' +date: ':attribute 不是一个有效的日期。' +date_equals: ':attribute 必须要等于 :date。' +date_format: ':attribute 的格式必须为 :format。' +different: ':attribute 和 :other 必须不同。' +digits: ':attribute 必须是 :digits 位的数字。' +digits_between: ':attribute 必须是介于 :min 和 :max 位的数字。' +dimensions: ':attribute 图片尺寸不正确。' +distinct: ':attribute 已经存在。' +email: ':attribute 不是一个合法的邮箱。' +ends_with: ':attribute 必须以 :values 为结尾。' +exists: ':attribute 不存在。' +file: ':attribute 必须是文件。' +filled: ':attribute 不能为空。' +gt: + numeric: ':attribute 必须大于 :value。' + file: ':attribute 必须大于 :value KB。' + string: ':attribute 必须多于 :value 个字符。' + array: ':attribute 必须多于 :value 个元素。' +gte: + numeric: ':attribute 必须大于或等于 :value。' + file: ':attribute 必须大于或等于 :value KB。' + string: ':attribute 必须多于或等于 :value 个字符。' + array: ':attribute 必须多于或等于 :value 个元素。' +image: ':attribute 必须是图片。' +in: '已选的属性 :attribute 非法。' +in_array: ':attribute 没有在 :other 中。' +integer: ':attribute 必须是整数。' +ip: ':attribute 必须是有效的 IP 地址。' +ipv4: ':attribute 必须是有效的 IPv4 地址。' +ipv6: ':attribute 必须是有效的 IPv6 地址。' +json: ':attribute 必须是正确的 JSON 格式。' +lt: + numeric: ':attribute 必须小于 :value。' + file: ':attribute 必须小于 :value KB。' + string: ':attribute 必须少于 :value 个字符。' + array: ':attribute 必须少于 :value 个元素。' +lte: + numeric: ':attribute 必须小于或等于 :value。' + file: ':attribute 必须小于或等于 :value KB。' + string: ':attribute 必须少于或等于 :value 个字符。' + array: ':attribute 必须少于或等于 :value 个元素。' +max: + numeric: ':attribute 不能大于 :max。' + file: ':attribute 不能大于 :max KB。' + string: ':attribute 不能大于 :max 个字符。' + array: ':attribute 最多只有 :max 个单元。' +mimes: ':attribute 必须是一个 :values 类型的文件。' +mimetypes: ':attribute 必须是一个 :values 类型的文件。' +min: + numeric: ':attribute 必须大于等于 :min。' + file: ':attribute 大小不能小于 :min KB。' + string: ':attribute 至少为 :min 个字符。' + array: ':attribute 至少有 :min 个单元。' +not_in: '已选的属性 :attribute 非法。' +not_regex: ':attribute 的格式错误。' +numeric: ':attribute 必须是一个数字。' +password: 密码错误 +present: ':attribute 必须存在。' +recaptcha: '未能通过 reCAPTCHA 的验证。' +regex: ':attribute 格式不正确。' +required: ':attribute 不能为空。' +required_if: '当 :other 为 :value 时 :attribute 不能为空。' +required_unless: '当 :other 不为 :values 时 :attribute 不能为空。' +required_with: '当 :values 存在时 :attribute 不能为空。' +required_with_all: '当 :values 存在时 :attribute 不能为空。' +required_without: '当 :values 不存在时 :attribute 不能为空。' +required_without_all: '当 :values 都不存在时 :attribute 不能为空。' +same: ':attribute 和 :other 必须相同。' +size: + numeric: ':attribute 大小必须为 :size。' + file: ':attribute 大小必须为 :size KB。' + string: ':attribute 必须是 :size 个字符。' + array: ':attribute 必须为 :size 个单元。' +starts_with: ':attribute 必须以 :values 为开头。' +string: ':attribute 必须是一个字符串。' +timezone: ':attribute 必须是一个合法的时区值。' +unique: ':attribute 已经被占用。' +uploaded: ':attribute 上传失败。' +url: ':attribute 格式不正确。' +uuid: ':attribute 必须是有效的 UUID。' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: 名称 + player_name: 角色名 + identification: 邮箱或角色名 + email: 邮箱 + password: 密码 + password_confirmation: '确认密码' + title: 标题 + content: 内容 diff --git a/resources/lang/zh_TW/admin.yml b/resources/lang/zh_TW/admin.yml new file mode 100755 index 0000000..a8264d7 --- /dev/null +++ b/resources/lang/zh_TW/admin.yml @@ -0,0 +1,138 @@ +--- +index: + total-users: 已註冊用戶 + total-players: 角色 + total-textures: 已上載的材質 + disk-usage: 磁碟利用情況 + overview: 概覽 + texture-uploads: 材質上載 + user-registration: 使用者註冊 +notifications: + send: + title: 發送通知 + success: 發送成功 + receiver: + title: 接收人 + all: 所有用戶 + normal: 常規用戶 + uid: 指定用戶 ID + email: 指定電子郵件地址 + title: 標題 + content: 內容(支援 Markdown 語法) +users: + operations: + non-existent: 沒有這個用戶。 + no-permission: 您沒有權限操作此用戶。 + email: + success: 電子郵件地址變更成功。 + verification: + success: 用戶電子郵件驗證狀態修改成功。 + nickname: + success: 暱稱已成功修改。 + password: + success: 密碼已成功修改。 + score: + success: 積分已成功修改。 + permission: 權限已更新。 + delete: + success: 這個賬戶已成功刪除。 +players: + no-permission: 您沒有權限操作此玩家。 + textures: + non-existent: 材質 tid :tid 不存在 + success: 玩家 :player 的材質已更新。 + name: + success: 玩家名稱已更新為 :player。 + owner: + success: 玩家 :player 的所有權已讓渡至用戶 :user。 + delete: + success: 角色已成功刪除。 +customize: + change-color: + title: 更換主題色 + colors: + navbar: 頂部導覽欄 + sidebar: + dark: 側邊欄(暗) + light: 側邊欄(亮) +i18n: + add: 添加新語言文本 + added: 語言文本已添加 + updated: 語言文本已更新 + deleted: 語言文本已刪除 + group: 分組 + key: 鍵 + text: 文本 + tip: 如何使用這個頁面? +status: + info: 資訊 + health: 運行狀態 + bs: + name: Blessing Skin + version: 版本號 + env: 應用運行環境 + debug: 是否處於除錯狀態? + commit: 提交 + laravel: Laravel 版本號 + server: + name: 伺服器 + php: PHP 版本 + web: 網站伺服器軟體 + os: 作業系統 + db: + name: 資料庫 + type: 伺服器 + host: 主機 + port: 連接埠 + username: 用戶名 + database: 資料庫 + prefix: 資料庫表前綴 + plugins: 已啟用插件(:amount) +plugins: + readme: 自述 + operations: + title: 操作 + enabled: ':plugin 已被啓用' + unsatisfied: + notice: 插件中存在不成立的依賴關係,因此我們無法啟用它。請安裝或更新下述的所有插件,並禁用那些不可用的依賴關係。 + disabled: '":name" 插件未啟用。' + version: '「:title」的版本不符合要求 ":constraint"' + conflict: '「:title」插件与此插件不能同时运行。' + disabled: ':plugin 已被禁用。' + deleted: 成功刪除插件。 + no-config-notice: 插件未安裝或未提供配置頁。 + no-readme-notice: 這個插件沒有說明文檔。 + not-found: 沒有這樣的插件。 + market: + unresolved: 插件中存在不成立的依賴關係,因此我們無法啟用它。請安裝或更新下述的所有插件,並禁用那些不可用的依賴關係。 + connection-error: 无法鏈接到插件市场源,错误訊息::error + non-existent: 插件 :plugin 不存在。 + install-success: 插件已安裝。 +update: + complete: 更新完成。 + info: + title: 更新訊息 + up-to-date: 已經為最新版本。 + available: 已有新的更新版本。 + versions: + latest: "最新版本:" + current: "當前版本:" + check-github: 去查看 GitHub Releases + button: 立即更新 + cautions: + title: 警告 + link: 点击來了解更多訊息。 + text: | + 请根据你的伺服器所在位置(国内/国外)选择更新源。 + 如錯誤选至相对于你的伺服器速度较慢的源,可能会造成检查与下载更新页面长时间无响应。 + 如何更换更新源? + errors: + connection: "無法訪問當前更新源。 細節::error" + spec: 不支援当前更新源。 + php: PHP 版本过低,至少需要 :version。 +download: + errors: + download: '下載失敗。原因::error' + shasum: 文件驗證失敗。 請重新下載。 + unzip: 解壓檔案失敗。 +invalid-action: 非法的操作 diff --git a/resources/lang/zh_TW/auth.yml b/resources/lang/zh_TW/auth.yml new file mode 100755 index 0000000..831bb82 --- /dev/null +++ b/resources/lang/zh_TW/auth.yml @@ -0,0 +1,85 @@ +--- +login: + title: 登入 + message: 登入以管理您的皮膚和角色 + success: 登入成功。 +check: + anonymous: 非法訪問。請先登入。 + verified: 要訪問此頁面, 請先驗證您的電子郵件地址。 + admin: 只有管理員可訪問此頁。 + banned: 您在此站点被查禁。請與管理員聯繫。 +register: + title: 註冊 + message: 歡迎来到 :sitename! + success: 您的賬戶已注冊. 跳轉中... + max: 您無法注冊 :regs 個以上賬戶. +forgot: + title: 我忘記密碼了 + message: 我們將向您發送一封驗證郵件 + disabled: 重置密碼暫不可用. + frequent-mail: 您點擊 "發送" 按鈕的速度過快. 請等幾分鐘。 + unregistered: 该電郵地址沒有註冊。 + success: 郵件已發送, 請檢查您的收件匣. 連結將在1小時內過期. + failed: 未能送達驗證郵件. :msg + ignore: 如果您並沒有訪問過我們的站點,或沒有進行上述操作,請忽略這封郵件。您無需進行退訂或者進行其他進一步的操作。 + reset: 重設您的密碼 + notice: 本郵件由系統自動發送,就算你回復了我們也不會回復你 + mail: + title: 重設您在 :sitename 的密碼 + message: 您之所以收到此電子郵件, 是因為我們在 :sitename 上收到了關於您賬戶的重設密碼請求. + reset: '要重置密碼, 請訪問: :url' + ignore: 如果您沒有請求重置密碼,請忽略這封郵件。 +reset: + title: 重設密碼 + button: 重設 + invalid: 無效的鏈接。 + expired: 此連結已過期。 + message: ':username,請在此處重置密碼。' + success: 密碼已成功重置。 +bind: + title: 綁定電郵地址 + button: 綁定 + message: 您需要提供您的電子郵件地址以繼續. + introduction: 我們不會向您發送任何垃圾郵件. + registered: 電郵地址已被使用。 +verify: + title: 電子信箱驗證 + invalid: 無效的鏈接。 + not-matched: 電子郵件地址不匹配。 +validation: + user: 沒有這個用戶。 + password: 錯誤的密碼。 +logout: + success: 您現在已登出 +oauth: + authorization: + title: 身份認証 + introduction: 第三方軟體 :name 正在向你請求獲取權限。 + button: 認證 + permissions: 權限 + scope: + user: + read: 登錄並讀取您的個人資料 + notification: + read: 允許應用讀取您的通知 + readwrite: 允許應用發送通知 + player: + read: 允許應用讀取您的角色 + readwrite: 允許應用創建、讀取、修改、刪除您的角色 + closet: + read: 允許應用讀取您的衣櫃物品 + readwrite: 允許應用創建、讀取、修改、刪除您的衣櫃物品 + users-management: + read: 允許應用讀取網站上的使用者 + readwrite: 允許應用創建、讀取、修改、刪除您網站上的使用者 + players-management: + read: 允許應用讀取網站上的角色 + readwrite: 允許應用創建、讀取、修改、刪除您網站上的角色 + closet-management: + read: 允許應用讀取使用者的衣櫃物品 + readwrite: 允許應用創建、讀取、修改、刪除使用者的衣櫃物品 + reports-management: + read: 允許應用讀取用戶的舉報 + readwrite: 允許應用讀取並處理用戶的舉報 +email: 電子郵件 +register-link: 註冊新帳戶 diff --git a/resources/lang/zh_TW/errors.yml b/resources/lang/zh_TW/errors.yml new file mode 100755 index 0000000..931e500 --- /dev/null +++ b/resources/lang/zh_TW/errors.yml @@ -0,0 +1,19 @@ +--- +http: + msg-403: 您無權使用這個頁面。 + msg-404: 這裡甚麼都沒有。 + msg-500: 請稍後再試一次。 + msg-503: 網站現在正在維護中。 + method-not-allowed: 請求不被允許。 + csrf-token-mismatch: Token 不匹配,請嘗試重新載入該頁。 + ie: 你的瀏覽器不被支援。請使用現代瀏覽器(例如 Firefox 或者 Chrome)。 +general: + title: 發生錯誤 +exception: + code: '錯誤代碼: :code' + detail: '詳細内容: :msg' + message: | + 哎呀, 好像出了錯誤。(請在 .env 文件中啓用 APP_DEBUG 查看詳細訊息) +plugins: + duplicate: 插件 [:dir1] 有一個和插件 [:dir2] 重複的名稱. 請檢查插件地址, 刪除其中的一項或使用另一個名稱定義. + boot: '「:plugin」插件存在错误,无法加载。' diff --git a/resources/lang/zh_TW/front-end.yml b/resources/lang/zh_TW/front-end.yml new file mode 100755 index 0000000..7d2ece9 --- /dev/null +++ b/resources/lang/zh_TW/front-end.yml @@ -0,0 +1,273 @@ +--- +auth: + login: 登入 + loggingIn: 正在登入 + tooManyFails: + captcha: 嘗試次數過多,請輸入驗證碼。 + recaptcha: 嘗試次數過多,請輸入驗證碼。 + emptyEmail: 請輸入電子郵箱地址。 + invalidConfirmPwd: 兩次輸入的密碼不一致。 + emptyNickname: 請輸入昵稱。 + register: 註冊帳號 + registering: 送出註冊資料中... + send: 發送 + sending: 發送中... + reset: 重置 + resetting: 重置中 + nickname: 昵稱 + player-name: Minecraft 角色名 + email: 電子郵件 + identification: 電子郵件地址或玩家名 + password: 密碼 + captcha: CAPTCHA 驗證碼 + change-captcha: 點擊以改變 CAPTCHA 驗證圖片 + login-link: 已經註冊了?從這裡登錄。 + forgot-link: 忘記密碼了? + keep: 記住我 + repeat-pwd: 重複輸入密碼 + nickname-intro: 除特殊字符外的任意内容 + player-name-intro: Minecraft 的玩家名稱,以後可以更改 + forgot: + login-link: 我又想起來了。 +skinlib: + private: 非公開 + anonymous: 請先登錄 + reset: 重置過濾器 + addToCloset: 添加到“衣櫃“ + removeFromCloset: 從“衣櫃”中移除 + setItemName: 為這件材質設置名稱 + applyNotice: 你可以在“衣櫃”中將這件材質設置到你的角色上。 + emptyItemName: 請輸入材質名稱。 + setNewTextureName: '請輸入新的材質名稱' + emptyNewTextureName: 請輸入新的材質名稱。 + seeMyUpload: 我的上傳 + apply: 應用 + filter: + skin: (任何模型) + steve: (史蒂夫) + alex: (艾利克斯) + cape: (披風) + uploader: '由用戶 (UID = :uid) 上傳' + allUsers: 所有用戶 + sort: + title: 排序 + time: 最新上傳 + likes: 最多收藏 + emptyTextureName: 請輸入材質名稱。 + emptyUploadFile: 未上傳任何文件。 + fileExtError: '材質應該是 PNG 文件。' + uploading: 正在上傳 + setAsPrivate: 設為隱私 + setAsPublic: 設為公開 + setPublicNotice: 確定要把這個材質設爲公開嗎? + setPrivateNotice: 確定要把這個材質設爲隱私嗎? + deleteNotice: 確定要刪除此材質嗎? + setNewTextureModel: "請為材質選擇新的模型:" + upload: + texture-name: 材質名稱 + texture-type: 材質種類 + select-file: 選取檔案 + privacy-notice: 避免其在皮膚庫中可見。 + set-as-private: 將其設為隱私 + button: 上傳 + cost: 將花費 :score 積分。 + award: 您上傳材質得到 :score 積分獎勵。 + show: + anonymous: 您必須登入以使用衣櫃。 + likes: 收藏的用戶 + detail: 詳細資訊 + name: 材質名稱 + edit: 編輯 + model: 適用模型 + size: 檔案大小 + uploader: 上載者 + upload-at: 上傳于 + download: 下載 + delete-texture: 刪除材質 + manage-notice: 被刪除或者設爲隱私的材質將從所有人的衣櫃收藏中刪除。 + report: + title: 報告 + reason: 請向我們說明原因。 + positive: 為激勵用戶對皮膚庫做出貢獻,我們將用 :score 的積分激勵報告非法内容的用戶。但是,非法的報告請求一經發現,您的積分將被扣除。 + negative: 爲了降低非法報告的壓力,我們向您收取 :score 的積分以提交報告。不過您無需擔憂,在管理員復查過後,被收取的積分將與獎勵一并返還。 +user: + signRemainingTime: '在 :time :unit 后可用' + timeUnitHour: 時 + timeUnitMin: 分鐘 + emptyClosetMsg: >- +

衣櫃什麽都沒有......

爲何不前去 皮膚庫 一探究竟呢?

+ renameItem: 重命名材質 + removeItem: 從衣櫃移除 + setAsAvatar: 設爲頭像 + viewInSkinlib: 在皮膚庫中瀏覽 + switch2dPreview: 切換至 2D 預覽 + switch3dPreview: 切換至 3D 預覽 + removeFromClosetNotice: 確定要將這個材質從你的衣櫃中移除嗎? + emptySelectedTexture: 未選擇任何材質。 + renameClosetItem: '為這個材質設置新的名稱:' + changePlayerName: '請輸入角色名稱。' + emptyPlayerName: 請輸入角色名。 + deletePlayer: 確定要刪除此角色? + deletePlayerNotice: 這是永久的,沒有備份。 + chooseClearTexture: 選取您欲重置的材質類型 + noClearChoice: 您沒有選取任何類型。 + setAvatar: 確定將此材質設為頭像嗎? + setAvatarNotice: 皮膚材質的頭部將被使用。 + resetAvatarConfirm: 確定重設您的頭像? + typeToSearch: 輸入來搜尋 + useAs: 應用 + resetSelected: 清空選擇 + closet: + upload: 上載材質 + use-as: + title: 欲將材質應用與哪一個角色? + empty: 您似乎沒有可用的角色... + used: + title: 資源使用情況 + players: 已註冊用戶 + storage: 存儲空間佔用 + cur-score: 當前積分 + score-notice: 點擊積分以顯示詳細訊息。 + sign: 簽到 + player: + operation: 操作 + edit-pname: 編輯名稱 + delete-texture: 清空材質 + delete-player: 刪除 + add-player: 添加新角色 + texture-empty: 沒有材質 + verification: + title: 驗證您的賬戶 + message: 您必須驗證您的電子郵件地址后才能使用皮膚材質儲存服務。還沒有收到電子郵件? + resend: 點擊此處以重新發送。 + sending: 發送中... + oauth: + id: 客戶端 ID + name: 應用程式名稱 + secret: 客戶端密令 + redirect: 回傳網址 + modifyName: 變更應用程式名稱 + modifyUrl: 自訂回傳網址 + create: 創建新應用 + confirmRemove: 確定刪除此應用?此操作無法撤銷。 +admin: + operationsTitle: 操作 + permission: 權限 + deleteUser: 刪除 + changeEmail: 編輯電子郵件地址 + newUserEmail: '請輸入新的電子郵件地址' + verification: 電子郵件驗證 + toggleVerification: 檢查驗證狀態 + changeNickName: 編輯暱稱 + newUserNickname: '請輸入新的昵稱:' + changePassword: 編輯密碼 + newUserPassword: '請輸入新密碼:' + changeScore: 編輯積分 + newScore: '請輸入新的積分數目:' + changePermission: 變更權限 + newPermission: '請選擇新的權限:' + deleteUserNotice: 確定刪除此用戶?此操作無法撤銷。 + banned: 封禁 + normal: 普通用戶 + admin: 管理員 + superAdmin: 超級管理員 + unverified: 未驗證 + verified: 已驗證 + pidNotice: >- + 請輸入應用材質的編號。留空以清空該角色的材質。 + changeTexture: 更換材質 + changePlayerName: 變更角色名 + changeOwner: 變更所有者 + textureType: 材質種類 + deletePlayer: 刪除 + changePlayerOwner: '請輸入欲讓渡角色的用戶編號:' + deletePlayerNotice: 確定刪除此角色?此操作無法撤銷。 + changePlayerNameNotice: '請輸入新的角色名稱:' + emptyPlayerName: 角色名不能為空。 + configurePlugin: 配置 + deletePlugin: 刪除 + noDependencies: 沒有依賴項 + pluginTitle: 擴展軟體 + pluginAuthor: 作者 + pluginVersion: 版本號 + pluginReadme: 自述 + pluginDescription: 描述資訊 + pluginDependencies: 依賴項 + installPlugin: 安裝 + pluginInstalling: 安裝中... + updatePlugin: 更新 + pluginUpdating: 更新中... + confirmUpdate: 確定升級 ":plugin" 由 :old 至 :new ? + enablePlugin: 啟用 + disablePlugin: 停用 + confirmDeletion: 你確定要刪除這個擴展軟體嗎? + uploadArchive: 上載壓縮包 + uploadArchiveNotice: 上載壓縮包來安裝擴展軟體。 + downloadRemote: 從遠端下載 + downloadRemoteNotice: 藉由遠端 URL 下載壓縮包來安裝擴展軟體。 + updateButton: 立即更新 + downloading: 正在下載... + i18n: + group: 分組 + key: 鍵 + text: 文本 + empty: '(空)' + modify: 修改 + delete: 刪除 + updating: '請輸入新的文字:' + confirmDelete: 確定執行此操作?這無法恢復。 +report: + tid: 材質 ID + reporter: 舉報者 + reason: 原因 + status-title: 狀態 + status: + - 待處理 + - 已解決 + - 已拒絕 + time: 舉報時間 + delete: 刪除 + ban: 封禁 + reject: 駁回 +general: + skin: 皮膚 + cape: 披風 + fatalError: 嚴重錯誤 + confirmLogout: 確定登出嗎? + confirm: 確定 + cancel: 取消 + submit: 提交 + close: 關閉 + more: 更多 + tip: 提示 + noResult: 無結果. + texturePreview: 材質預覽 + walk: 行走 + run: 奔跑 + rotation: 旋轉 + pause: 暫停 + reset: 重置 + skinlib: 皮膚庫 + wait: 請稍等... + csrf: 此頁面已過期。請刷新頁面。 + user: + email: 電子郵件 + nickname: 暱稱 + score: 積分 + register-at: 註冊於 + player: + owner: 所有者 + player-name: 角色名 + previews: 材質預覽 + last-modified: 最近一次修改 +colors: + black: 黑色 + white: 白色 + gray: 灰色 + prev: 上一個背景 + next: 下一個背景 +vendor: + datatable: + search: 搜索 + prev: 上一頁 + next: 下一頁 diff --git a/resources/lang/zh_TW/general.yml b/resources/lang/zh_TW/general.yml new file mode 100755 index 0000000..0c3feb1 --- /dev/null +++ b/resources/lang/zh_TW/general.yml @@ -0,0 +1,59 @@ +--- +index: 首頁 +skinlib: 皮膚庫 +user-center: 用戶中心 +logout: 登出 +login: 登入 +register: 立刻註冊 +profile: 個人設定檔 +admin-panel: 管理面板 +explore: 進一步瞭解 +manage: 管理 +anonymous: 訪客 +back: 返回 +dashboard: 儀錶板 +my-closet: 皮膚櫃 +my-reports: 舉報 +developer: 進階 +oauth-manage: OAuth2 應用程式 +player-manage: 角色 +user-manage: 用戶 +report-manage: 舉報 +plugin-manage: 擴展軟體 +plugin-market: 擴展軟體商店 +plugin-configs: 擴展軟體設定 +customize: 自訂 +i18n: 多語言 +options: 選項 +score-options: 積分設定 +res-options: 元素設定 +status: 狀態 +check-update: 檢查更新 +download-update: 下載更新 +close: 關閉 +skin: 皮膚 +cape: 披風 +submit: 提交 +cancel: 取消 +yes: true +no: false +op-success: 操作成功 +unknown: 未知 +notice: 告示欄 +illegal-parameters: 非法參數。 +private: 隱私 +public: 公開 +unexistent-user: 此用戶不存在。 +player-banned: 該角色的所有者已被封禁。 +texture-deleted: 請求的材質已被刪除。 +user: + email: 電子郵件 + nickname: 暱稱 + password: 密碼 + score: 積分 + register-at: 註冊於 +player: + owner: 所有者 + player-name: 角色名 + previews: 材質預覽 + last-modified: 最近一次修改 diff --git a/resources/lang/zh_TW/index.yml b/resources/lang/zh_TW/index.yml new file mode 100755 index 0000000..06bcff3 --- /dev/null +++ b/resources/lang/zh_TW/index.yml @@ -0,0 +1,17 @@ +--- +features: + title: 特性 + first: + icon: fa-users + name: 多角色 + desc: 您可以在一個已註冊賬戶上增加多個角色 + second: + icon: fa-share-alt + name: 分享 + desc: 探索皮膚庫,收藏並與您的朋友分享。 + third: + icon: fa-cloud + name: 免費 + desc: 永久免費。沒有廣告。絕不收費。 +introduction: ':sitename 提供了一個上傳 Minecraft 皮膚的平台。藉由皮膚mod(諸如 CustomSkinLoader),您可以在 Minecraft 中選取皮膚並運用於您的角色,並使其對其他玩家可見。' +start: 加入我們 diff --git a/resources/lang/zh_TW/options.yml b/resources/lang/zh_TW/options.yml new file mode 100755 index 0000000..19dc2bc --- /dev/null +++ b/resources/lang/zh_TW/options.yml @@ -0,0 +1,179 @@ +--- +option-saved: 設置已保存。 +homepage: + title: 主頁 + home_pic_url: + title: 主頁圖片 URL + hint: 主頁的相對路徑或者完整 URL,留空以使用預設圖像。 + favicon_url: + title: 網站圖標 + hint: 相對於 public/ 的路徑或者完整 URL 。 + description: 提供的圖片必須是寬度和高度相同(留空以應用預設圖標) + transparent_navbar: + title: 透明導航欄 + label: 這將在主頁啓用透明導航欄,但當頁面滾動至底部時將恢復正常。 + hide_intro: + title: 隱藏底部介紹 + label: 頁面滾動條將被禁用,和2.x版本一樣。 + fixed_bg: + title: 固定背景圖 + label: 此選項將使背景圖固定,不再滾動。 + copyright_prefer: + title: 軟體版權 + description: "您可以為每種語言指定不同形式的軟體版權。若要編輯它們,請切換到該語言並提交您的編輯訊息。
警告: 禁止對頁脚軟體版權進行任何惡意的修改 (包括刪除, 修改作者, 更改連結對象)。相關作者保留追究相關責任的權利。" + copyright_text: + title: 自訂版權文字 + description: 自訂版權文字中允許使用形如{site_name} & {site_url}的佔位符。您也可以為每一種顯示語言自訂不同的文字。如欲編輯不同語言的文字,請切換到對應語言並提交修改。 +customJsCss: + title: 自訂 CSS/JavaScript + message: | + 此處的内容將被追加至每個頁面的 <style> 和 <script> 標簽之中。
+ - 以下是有用的示範:自訂 CSS & JavaScript 示範 + custom_css: CSS + custom_js: JavaScript +rate: + title: 積分 + score_per_storage: + title: 存儲空間 + addon: 積分 = 1KB + private_score_per_storage: + title: 私有材質存儲 + addon: 積分 = 1KB + hint: 上載私密材質消耗更多積分。 + score_per_closet_item: + title: 收藏 + addon: 積分 = 1個衣櫃物品 + return_score: + title: 積分返還 + label: 在用戶刪除角色、材質或衣櫃物品時退還積分。 + score_per_player: + title: 角色 + addon: 積分 = 1 個角色 + user_initial_score: 用戶初始積分 +report: + title: 舉報材質 + reporter_score_modification: + title: 提交舉報所需積分 + description: 設置正整數值以獎勵提交舉報的用戶。 設置為負值將在用戶提交舉報時消耗積分,如果采納了用戶的舉報,則收取的積分將退還。 設置為0禁用此設定。 + reporter_reward_score: + title: 舉報采納時獎勵舉報用戶 +sign: + title: 簽到 + sign_score: + title: 獲得積分 + addon1: 積分 ~ + addon2: 積分 + sign_gap_time: + title: 間隔時間 + addon: 小時 + sign_after_zero: + title: 時間 + label: 用戶每天僅可在零時后簽到。 + hint: 若此選項選中,上述的設定將被忽略。 +sharing: + title: 獎勵分享 + score_award_per_texture: + title: 上傳材質的用戶將被獎勵 + take_back_scores_after_deletion: + title: 返還積分 + label: 儅上傳用戶將材質設定為私有或刪除材質時返還積分 + score_award_per_like: + title: 每次材質被收集時,上傳用戶將被獎勵 +general: + title: 一般設定 + site_name: 網站名稱 + site_description: + title: 網站訊息描述 + description: 您也可以為每一種語言自訂描述文字。如欲編輯每一種語言下的描述文字,請切換到對應語言編輯並保存。 + site_url: + title: 網站 URL + hint: 以 http(s):// 開頭,不能以斜杠結尾。 + register_with_player_name: + title: 以角色名注冊 + label: 注冊時需要 Minecraft 角色名稱 + require_verification: + title: 賬戶驗證 + label: 用戶必須首先驗證其電子郵件地址。 + regs_per_ip: 同一個 IP 的最大賬戶數 + max_upload_file_size: + title: 最大檔案上傳大小 + hint: "php.ini 設定的最大上傳大小: :size" + player_name_rule: + title: 角色名規則 + official: 字元、數字和下劃綫(Mojang 官方角色名規則) + cjk: 允許中日韓統一表意字元 + utf8: 允許所有有效的 UTF-8 字元(不包括空白) + custom: 使用自訂規則(正則表達式) + custom_player_name_regexp: + title: 自訂角色名規則 + hint: 只有在上述設定為“自訂”時才會生效。留空以允許任何字元。 + placeholder: 正則表達式 + player_name_length: + title: 角色名長度 + suffix: 字元 + auto_del_invalid_texture: + title: 不可用的材質 + label: 自動刪除不可用的材質 + hint: 刪除不在皮膚庫中存在的材質記錄 + allow_downloading_texture: + title: 下載材質 + label: 允許用戶從皮膚庫中下載材質源文件 + status_code_for_private: + title: 拒絕私有材質的 HTTP 響應碼 + texture_name_regexp: + title: 材質名規則 + hint: 正則表達式用於驗證上載材質的名稱。 留空以允許除單引號,雙引號和反斜杠之外的任何字元。 + placeholder: 正則表達式 + content_policy: + title: 内容策略 + description: 在材質上載頁上顯示內容策略,支持 Markdown 語法。 要編輯特定語言的相應內容政策,請切換到該語言並提交您的修改。 +announ: + title: 公告欄 + announcement: + description: 支持 Markdown 語法。 您可以為每種語言指定不同的公告。 要編輯特定語言的公告,請切換到該語言並提交您的公告文字。 +meta: + title: SEO 標簽 + meta_keywords: + title: 關鍵字 + hint: 使用逗號分隔。 + meta_description: + title: 描述資訊 + hint: 留空使用“網站描述”中的文字。 + meta_extras: + title: 其他自訂標簽 +recaptcha: + recaptcha_invisible: + title: 隱式驗證 + label: 啓用隱式 reCAPTCHA 驗證 +res-warning: 本頁面僅供高級用戶使用。如果您不熟悉請勿修改此頁面! +resources: + title: 資源檔案 + hint: 如果您爲您的網站啓用了CDN,請在此選項打勾。 + force_ssl: + title: 強制應用 SSL + label: 使用 HTTPS 協議加載所有前端資源。 + hint: 請在應用 SSL 之前確定其可用。 + auto_detect_asset_url: + title: 資源 URL + label: 自動判斷資源 URL + description: 如果 CDN 資源地址生成錯誤請禁用。禁用時從網站 URL 加載資源。 + cache_expire_time: + title: 緩存刷新時間 + hint: 以秒計。86400 = 一天,31536000 = 一年。 + cdn_address: + title: 前端資源 CDN + hint: 前端資源 URL 不可用時將不從該處加載資源文件。 + description: | + 您所輸入的 CDN URL 必須是指向 /public 目錄的鏡像資源,該目錄的所有檔案都將由 CDN 加載。
+ 如何驗證? 請驗證 {您的 CDN 地址}/app/manifest.json 是否可訪問。 +cache: + title: 緩存選項 + clear: 清除緩存 + cleared: 緩存已清除。 + driver: 當前緩存驅動是 「:driver」。 + enable_avatar_cache: + title: 頭像 + label: 啓用頭像緩存 + enable_preview_cache: + title: 材質預覽 + label: 啓用材質預覽緩存 diff --git a/resources/lang/zh_TW/setup.yml b/resources/lang/zh_TW/setup.yml new file mode 100755 index 0000000..3b7e4df --- /dev/null +++ b/resources/lang/zh_TW/setup.yml @@ -0,0 +1,44 @@ +--- +database: + connection-error: "無法連接到目標 :type 數據庫,請檢查您的配置。伺服器返回的信息::msg" +locked: + title: 已安裝 + text: 看來您已經安裝了 Blessing Skin Server。 要重新安裝,請刪除 storage 目錄下的 install.lock 文件。 + button: 回到主頁 +updates: + success: + title: 更新完成 +wizard: + master: + title: Blessing Skin Server 升级程式 + welcome: + title: 歡迎使用 + button: 下一步 + text: 欢迎使用 Blessing Skin Server v:version! + database: + title: 資料庫 + text: 該數據庫用於存儲 Blessing Skin 的數據。 + type: 數據庫類型 + host: 數據庫伺服器地址 + port: 數據庫伺服器端口 + username: 數據庫用戶名 + password: 數據庫密碼 + db: 數據庫名称 + db-notice: 如果您使用 SQLite,那麼您應該填寫 SQLite 數據庫文件的路徑,並且無需填寫其它信息。 + prefix: 數據表前缀(可选) + prefix-notice: 除非要將多個 Blessing Skin 安裝到一個數據庫中,否則不需要填寫此選項。 + info: + title: 填寫信息 + button: 开始安装 + text: 你需要填写一些基本訊息。无需担心填错,这些訊息以后可以再次修改。 + admin-email: 管理員信箱 + admin-notice: 這是唯一可以授予或取消其他用戶的管理員權限的超級管理員帳戶。 + nickname: 昵稱 + password: 密碼 + pwd-notice: '注意:您將需要密碼才能登錄。請妥善保管。' + confirm-pwd: 確認密碼 + site-name: 站點名称 + site-name-notice: 將會顯示在首頁以及標題欄。 + finish: + title: 安裝完成 + text: Blessing Skin Server 安装完成。你是否还沉浸在愉悦的安装过程中?很遗憾,一切皆已完成! :) diff --git a/resources/lang/zh_TW/skinlib.yml b/resources/lang/zh_TW/skinlib.yml new file mode 100755 index 0000000..ac42c21 --- /dev/null +++ b/resources/lang/zh_TW/skinlib.yml @@ -0,0 +1,30 @@ +--- +general: + upload-new-skin: 上載新皮膚 +show: + title: 材質詳細訊息 + deleted: 請求的材質已被刪除。 + private: 請求的材質為私有材質,僅擁有者與管理員可見。 +upload: + title: 上載材質 + name-rule: 少於32個字元,且不包含特殊字元。 + name-rule-regexp: 自訂名稱規則為 :regexp + private-score-notice: 將材質設爲私有將花費更多積分。您將為每一 KB 花費 :score 積分。 + invalid-size: 無效的 :type 文件(寬度 :width,高度 :height) + invalid-hd-skin: 無效的皮膚(寬度與高度應爲 32 的整倍數) + lack-score: 您沒有足夠的積分上載材質。 + repeated: 材質已被其他人上載過。您可以直接將其添加到衣櫃。 + success: 材質 :name 上載成功。 +delete: + success: 成功刪除材質。 +privacy: + success: 將材質設定爲 :privacy 成功。 +rename: + success: 材質重命名爲 :name 成功。 +model: + success: 材質模型已成功變更為 :model。 +no-permission: 您沒有權限操作此材質。 +non-existent: 無此材質。 +report: + duplicate: 您已成功舉報此材質。管理員將速即審閲。您可以同時在“用戶中心”追蹤舉報進展。 + success: 感謝您的舉報!管理員將速即審閲。 diff --git a/resources/lang/zh_TW/user.yml b/resources/lang/zh_TW/user.yml new file mode 100755 index 0000000..32b79e1 --- /dev/null +++ b/resources/lang/zh_TW/user.yml @@ -0,0 +1,101 @@ +--- +sign-success: 簽到成功,獲得 :score 積分。 +announcement: 公告 +no-unread: 沒有新通知。 +verification: + disabled: 電子郵件驗證不可用。 + frequent-mail: 您點擊 "發送" 按鈕的速度過快, 請稍等1分鐘。 + verified: 您的賬戶已經過驗證。 + success: 驗證鏈接已發送。請檢查您的郵箱。 + failed: 我們未能向您發送驗證鏈接。以下是詳細訊息 :msg + mail: + title: 在 :sitename 上驗證您的電子郵件地址 + message: 您因有人在 :sitename 上使用此電子郵件地址注冊賬戶而收到此電子郵件。 + reset: '點擊以驗證您的賬戶::url' + ignore: 如果您未注冊賬戶,請忽略這封郵件。 +score-intro: + title: 什麼是積分? + introduction: | + 我們使用積分系統來阻止濫發巨大材質和濫用角色注冊的行爲。 + 添加角色,上載材質或從皮膚庫中添加材質均消耗積分。 + :return-score + + 新用戶將得到 :initial_score 積分,且您可以通過每日簽到獲得 :score-from ~ :score-to 的積分。 + will-return-score: 如果您刪除角色、材質或衣櫃物品,積分將返還。 + no-return-score: 如果您刪除角色、材質或衣櫃物品,積分將不會返還。 + rates: + storage: ':score 積分 = 1KB 存儲空間' + player: ':score 積分 = 1 個角色' + closet: ':score 積分 = 1個衣櫃物品' +closet: + add: + success: 成功將 :name 添加到衣櫃。 + repeated: 您已經添加了這個材質。 + not-found: 無法找到這個材質。 + lack-score: 您沒有足夠的積分將其添加至衣櫃。 + rename: + success: 物品重命名為 :name 成功。 + remove: + success: 材質已成功從衣櫃移除。 + non-existent: 您的衣櫃沒有這個材質。 +player: + login-notice: 現在您可以使用您的角色名登入,而無需電子郵件地址。 + player-name-rule: + official: 角色名稱只能由字母、數字或下劃綫組成。 + cjk: 角色名應包含字元、數字、下劃綫和中日韓統一表意字元。 + utf8: 角色名必須是 UTF-8 字串。 + custom: 自訂角色名規則已啓用。請聯係管理員獲取詳細訊息。 + player-name-length: 角色名長度至少爲 :min 個字元,並不得超過 :max 個字元。 + add: + repeated: 角色名已被注冊。 + lack-score: 您沒有足夠的積分添加角色。 + success: 角色名 :name 修改成功。 + delete: + success: 角色名 :name 刪除成功。 + rename: + repeated: 這個角色名已被占用。請選用另一個。 + success: 角色名 :old 已更改爲 :new 。 + set: + success: 材質成功應用於 :name 角色。 + clear: + success: 角色 :name 的材質重設成功。 +profile: + avatar: + title: 修改頭像? + notice: 在您的衣櫃的任何材質中點擊齒輪圖標"",隨後點擊“設爲頭像”。我們將爲您擷取皮膚頭部。如果您未能看到頭像,請嘗試禁用您的廣告攔截軟體。 + wrong-type: 您不能將披風設置爲頭像。 + success: 新的頭像設置成功。 + reset: 重設頭像 + password: + title: 修改密碼 + old: 舊密碼 + new: 新密碼 + confirm: 重複新密碼 + button: 修改密碼 + wrong-password: 舊密碼錯誤。 + success: 密碼已更新,請重新登入。 + nickname: + title: 更改暱稱 + empty: 現在未設置昵稱。 + success: 昵稱已更新爲 :nickname + email: + title: 更改電子郵件地址 + new: 新電子郵件地址 + password: 當前密碼 + button: 更改電子郵件地址 + wrong-password: 錯誤的密碼。 + existed: 這個電子郵件地址已被佔用。 + success: 電子郵件地址已更新,請重新登入。 + delete: + title: 刪除賬戶 + notice: 確認在 :site 上刪除您的賬戶? + admin: 管理員賬戶不能被刪除。 + button: 刪除我的賬戶 + modal-title: 您需要輸入密碼來繼續 + modal-notice: | + 您將要刪除您的賬戶。 + 此操作無法撤銷!站點不會備份、恢復或者撤銷您的操作。 + 這是我們最後一次提示,繼續嗎? + password: 當前密碼 + wrong-password: 錯誤的密碼。 + success: 您的賬戶已成功刪除。 diff --git a/resources/lang/zh_TW/validation.yml b/resources/lang/zh_TW/validation.yml new file mode 100755 index 0000000..40221c8 --- /dev/null +++ b/resources/lang/zh_TW/validation.yml @@ -0,0 +1,123 @@ +--- +accepted: '必須接受 :attribute。' +active_url: ':attribute 不是有效的網址。' +after: ':attribute 必須要晚於 :date。' +after_or_equal: ':attribute 必須要等於 :date 或更晚。' +alpha: ':attribute 只能以字母組成。' +alpha_dash: ':attribute 只能以字母、數字、連接線(-)及底線(_)組成。' +alpha_num: ':attribute 只能以字母及數字組成。' +array: ':attribute 必須為陣列。' +before: ':attribute 必須要早於 :date。' +before_or_equal: ':attribute 必須要等於 :date 或更早。' +between: + numeric: ':attribute 必須介於 :min 至 :max 之間。' + file: ':attribute 必須介於 :min 至 :max KB 之間。 ' + string: ':attribute 必須介於 :min 至 :max 個字元之間。' + array: ':attribute: 必須有 :min - :max 個元素。' +boolean: ':attribute 必須為布林值。' +captcha: '不正確的 captcha。' +confirmed: ':attribute 確認欄位的輸入不一致。' +date: ':attribute 不是有效的日期。' +date_equals: ':attribute 必須等於 :date。' +date_format: ':attribute 不符合 :format 的格式。' +different: ':attribute 與 :other 必須不同。' +digits: ':attribute 必須是 :digits 位數字。' +digits_between: ':attribute 必須介於 :min 至 :max 位數字。' +dimensions: ':attribute 圖片尺寸不正確。' +distinct: ':attribute 已經存在。' +email: ':attribute 必須是有效的 E-mail。' +ends_with: ':attribute 結尾必須包含下列之一::values' +exists: ':attribute 不存在。' +file: ':attribute 必須是有效的檔案。' +filled: ':attribute 不能留空。' +gt: + numeric: ':attribute 必須大於 :value。' + file: ':attribute 必須大於 :value KB。' + string: ':attribute 必須多於 :value 個字元。' + array: ':attribute 必須多於 :value 個元素。' +gte: + numeric: ':attribute 必須大於或等於 :value。' + file: ':attribute 必須大於或等於 :value KB。' + string: ':attribute 必須多於或等於 :value 個字元。' + array: ':attribute 必須多於或等於 :value 個元素。' +image: ':attribute 必須是一張圖片。' +in: '所選擇的 :attribute 選項無效。' +in_array: ':attribute 沒有在 :other 中。' +integer: ':attribute 必須是一個整數。' +ip: ':attribute 必須是一個有效的 IP 位址。' +ipv4: ':attribute 必須是一個有效的 IPv4 位址。' +ipv6: ':attribute 必須是一個有效的 IPv6 位址。' +json: ':attribute 必須是正確的 JSON 字串。' +lt: + numeric: ':attribute 必須小於 :value。' + file: ':attribute 必須小於 :value KB。' + string: ':attribute 必須少於 :value 個字元。' + array: ':attribute 必須少於 :value 個元素。' +lte: + numeric: ':attribute 必須小於或等於 :value。' + file: ':attribute 必須小於或等於 :value KB。' + string: ':attribute 必須少於或等於 :value 個字元。' + array: ':attribute 必須少於或等於 :value 個元素。' +max: + numeric: ':attribute 不能大於 :max。' + file: ':attribute 不能大於 :max KB。' + string: ':attribute 不能多於 :max 個字元。' + array: ':attribute 最多有 :max 個元素。' +mimes: ':attribute 必須為 :values 的檔案。' +mimetypes: ':attribute 必須為 :values 的檔案。' +min: + numeric: ':attribute 不能小於 :min。' + file: ':attribute 不能小於 :min KB。' + string: ':attribute 不能小於 :min 個字元。' + array: ':attribute 至少有 :min 個元素。' +not_in: '所選擇的 :attribute 選項無效。' +not_regex: ':attribute 的格式錯誤。' +numeric: ':attribute 必須為一個數字。' +password: 密碼錯誤 +present: ':attribute 必須存在。' +recaptcha: 'reCAPTCHA 認證失敗。' +regex: ':attribute 的格式錯誤。' +required: ':attribute 不能留空。' +required_if: '當 :other 是 :value 時 :attribute 不能留空。' +required_unless: '當 :other 不是 :values 時 :attribute 不能留空。' +required_with: '當 :values 出現時 :attribute 不能留空。' +required_with_all: '當 :values 出現時 :attribute 不能為空。' +required_without: '當 :values 留空時 :attribute field 不能留空。' +required_without_all: '當 :values 都不出現時 :attribute 不能留空。' +same: ':attribute 與 :other 必須相同。' +size: + numeric: ':attribute 的大小必須是 :size。' + file: ':attribute 的大小必須是 :size KB。' + string: ':attribute 必須是 :size 個字元。' + array: ':attribute 必須是 :size 個元素。' +starts_with: ':attribute 開頭必須包含下列之一::values' +string: ':attribute 必須是一個字串。' +timezone: ':attribute 必須是一個正確的時區值。' +unique: ':attribute 已經存在。' +uploaded: ':attribute 上傳失敗。' +url: ':attribute 的格式錯誤。' +uuid: ':attribute 必須是有效的 UUID。' +#-------------------------------------------------------------------------- +#Custom Validation Language Lines +#-------------------------------------------------------------------------- +#Here you may specify custom validation messages for attributes using the +#convention "attribute.rule" to name the lines. This makes it quick to +#specify a specific custom language line for a given attribute rule. +#custom: +#attribute-name: +#rule-name: custom-message +#-------------------------------------------------------------------------- +#Custom Validation Attributes +#-------------------------------------------------------------------------- +#The following language lines are used to swap attribute place-holders +#with something more reader friendly such as E-Mail Address instead +#of "email". This simply helps us make messages a little cleaner. +attributes: + name: 名稱 + player_name: 玩家名稱 + identification: 電子郵件地址或玩家名 + email: E-mail + password: 密碼 + password_confirmation: '確認密碼' + title: 標題 + content: 內容 diff --git a/resources/misc/textures/avatar2d.png b/resources/misc/textures/avatar2d.png new file mode 100755 index 0000000..582197c Binary files /dev/null and b/resources/misc/textures/avatar2d.png differ diff --git a/resources/misc/textures/avatar3d.png b/resources/misc/textures/avatar3d.png new file mode 100755 index 0000000..af77267 Binary files /dev/null and b/resources/misc/textures/avatar3d.png differ diff --git a/resources/misc/textures/steve.png b/resources/misc/textures/steve.png new file mode 100755 index 0000000..90d4fa2 Binary files /dev/null and b/resources/misc/textures/steve.png differ diff --git a/resources/views/admin/base.twig b/resources/views/admin/base.twig new file mode 100755 index 0000000..be6e0e6 --- /dev/null +++ b/resources/views/admin/base.twig @@ -0,0 +1,38 @@ + + + + {{ include('shared.head') }} + {% block title %}{% endblock %} - {{ site_name }} + + + +
+ {{ include('shared.header') }} + {{ include('shared.sidebar', {scope: 'admin'}) }} +
+
+
+
+
+

{{ block('title') }}

+
+
+ +
+
+
+
+
+
+ {% block content %}{% endblock %} +
+
+
+
+ {{ include('shared.copyright') }} +
+
+ {% block before_foot %}{% endblock %} + {{ include('shared.foot') }} + + diff --git a/resources/views/admin/customize.twig b/resources/views/admin/customize.twig new file mode 100755 index 0000000..b51e2bb --- /dev/null +++ b/resources/views/admin/customize.twig @@ -0,0 +1,77 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.customize') }}{% endblock %} + +{% block content %} +
+
+
+ {{ csrf_field() }} +
+

+ {{ trans('admin.customize.change-color.title') }} +

+
+
+ + + +
+ +
+
+
+ {{ forms.homepage|raw }} + {{ forms.custom_js_css|raw }} +
+
+{% endblock %} + +{% block before_foot %} + +{% endblock %} diff --git a/resources/views/admin/i18n.twig b/resources/views/admin/i18n.twig new file mode 100755 index 0000000..544f623 --- /dev/null +++ b/resources/views/admin/i18n.twig @@ -0,0 +1,62 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.i18n') }}{% endblock %} + +{% block content %} +
+
+
+
+
+
+

{{ trans('admin.i18n.add') }}

+
+
+ {% if errors.any %} +
+ + {{ errors.first }} +
+ {% elseif session_pull('success') %} +
+ + {{ trans('admin.i18n.added') }} +
+ {% endif %} + {{ csrf_field() }} +
+
+
{{ trans('admin.i18n.group') }}
+
+ +
+
+
+
{{ trans('admin.i18n.key') }}
+
+ +
+
+
+
{{ trans('admin.i18n.text') }}
+
+ +
+
+
+
+ +
+
+ + {{ trans('admin.i18n.tip') }} + +
+
+{% endblock %} diff --git a/resources/views/admin/index.twig b/resources/views/admin/index.twig new file mode 100755 index 0000000..cdf93ce --- /dev/null +++ b/resources/views/admin/index.twig @@ -0,0 +1,7 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.dashboard') }}{% endblock %} + +{% block content %} + {{ include('shared.grid') }} +{% endblock %} diff --git a/resources/views/admin/market.twig b/resources/views/admin/market.twig new file mode 100755 index 0000000..5313a77 --- /dev/null +++ b/resources/views/admin/market.twig @@ -0,0 +1,3 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.plugin-market') }}{% endblock %} diff --git a/resources/views/admin/master.blade.php b/resources/views/admin/master.blade.php new file mode 100755 index 0000000..eecd38e --- /dev/null +++ b/resources/views/admin/master.blade.php @@ -0,0 +1,20 @@ + + + + @include('shared.head') + @yield('title') - {{ option_localized('site_name') }} + @yield('style') + + + +
+ @include('shared.header') + @include('shared.sidebar', ['scope' => 'admin']) + @yield('content') + @include('shared.footer') +
+ + @include('shared.foot') + @yield('script') + + diff --git a/resources/views/admin/options.twig b/resources/views/admin/options.twig new file mode 100755 index 0000000..2edf9ce --- /dev/null +++ b/resources/views/admin/options.twig @@ -0,0 +1,16 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.options') }}{% endblock %} + +{% block content %} +
+
+ {{ forms.general.render()|raw }} +
+
+ {{ forms.announ.render()|raw }} + {{ forms.meta.render()|raw }} + {{ forms.recaptcha.render()|raw }} +
+
+{% endblock %} diff --git a/resources/views/admin/players.twig b/resources/views/admin/players.twig new file mode 100755 index 0000000..1c9d505 --- /dev/null +++ b/resources/views/admin/players.twig @@ -0,0 +1,3 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.player-manage') }}{% endblock %} diff --git a/resources/views/admin/plugin/readme.twig b/resources/views/admin/plugin/readme.twig new file mode 100755 index 0000000..474de4c --- /dev/null +++ b/resources/views/admin/plugin/readme.twig @@ -0,0 +1,17 @@ +{% extends 'admin.base' %} + +{% block title %}{{ title }}{% endblock %} + +{% block content %} +
+
+

{{ trans('admin.plugins.readme') }}

+
+
{{ content|raw }}
+ +
+{% endblock %} diff --git a/resources/views/admin/plugins.twig b/resources/views/admin/plugins.twig new file mode 100755 index 0000000..a1b3883 --- /dev/null +++ b/resources/views/admin/plugins.twig @@ -0,0 +1,3 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.plugin-manage') }}{% endblock %} diff --git a/resources/views/admin/reports.twig b/resources/views/admin/reports.twig new file mode 100755 index 0000000..e81ce86 --- /dev/null +++ b/resources/views/admin/reports.twig @@ -0,0 +1,3 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.report-manage') }}{% endblock %} diff --git a/resources/views/admin/resource.twig b/resources/views/admin/resource.twig new file mode 100755 index 0000000..88d367a --- /dev/null +++ b/resources/views/admin/resource.twig @@ -0,0 +1,22 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.res-options') }}{% endblock %} + +{% block content %} +
+
+
+ {{ trans('options.res-warning') }} +
+
+
+ +
+
+ {{ forms.resources.render()|raw }} +
+
+ {{ forms.cache.render()|raw }} +
+
+{% endblock %} diff --git a/resources/views/admin/score.twig b/resources/views/admin/score.twig new file mode 100755 index 0000000..ae67cd7 --- /dev/null +++ b/resources/views/admin/score.twig @@ -0,0 +1,16 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.score-options') }}{% endblock %} + +{% block content %} +
+
+ {{ forms.rate.render()|raw }} + {{ forms.report.render()|raw }} +
+
+ {{ forms.sign.render()|raw }} + {{ forms.sharing.render()|raw }} +
+
+{% endblock %} diff --git a/resources/views/admin/status.twig b/resources/views/admin/status.twig new file mode 100755 index 0000000..1caefb1 --- /dev/null +++ b/resources/views/admin/status.twig @@ -0,0 +1,7 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.status') }}{% endblock %} + +{% block content %} + {{ include('shared.grid') }} +{% endblock %} diff --git a/resources/views/admin/update.twig b/resources/views/admin/update.twig new file mode 100755 index 0000000..2f530f5 --- /dev/null +++ b/resources/views/admin/update.twig @@ -0,0 +1,93 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.check-update') }}{% endblock %} + +{% block content %} +
+
+
+
+

{{ trans('admin.update.info.title') }}

+
+
+ {% if can_update %} +
+ {{ trans('admin.update.info.available') }} +
+
+
+
+ {{ trans('admin.update.info.versions.latest') }} +
+
+ v{{ info.latest }} +
+
+
+
+ {{ trans('admin.update.info.versions.current') }} +
+
+ v{{ info.current }} +
+
+
+ {% else %} + {% if error %} +
+ {{ trans('admin.update.errors.connection', {error: error}) }} +
+ {% else %} +
+ {{ trans('admin.update.info.up-to-date') }} +
+ {% endif %} +
+
+
+ {{ trans('admin.update.info.versions.current') }} +
+
+ v{{ info.current }} +
+
+
+ {% endif %} +
+ +
+
+
+
+
+

+ {{ trans('admin.update.cautions.title') }} +

+
+
+ {{ trans('admin.update.cautions.text')|nl2br }} + + {{ trans('admin.update.cautions.link') }} + +
+
+
+
+{% endblock %} diff --git a/resources/views/admin/users.twig b/resources/views/admin/users.twig new file mode 100755 index 0000000..4f711a5 --- /dev/null +++ b/resources/views/admin/users.twig @@ -0,0 +1,10 @@ +{% extends 'admin.base' %} + +{% block title %}{{ trans('general.user-manage') }}{% endblock %} + +{% block before_foot %} + {% set extra = {'currentUser': auth_user()} %} + +{% endblock %} diff --git a/resources/views/admin/widgets/dashboard/chart.twig b/resources/views/admin/widgets/dashboard/chart.twig new file mode 100755 index 0000000..482b5f4 --- /dev/null +++ b/resources/views/admin/widgets/dashboard/chart.twig @@ -0,0 +1,9 @@ +
+
+

{{ trans('admin.index.overview') }}

+
+
+
+
+
+
diff --git a/resources/views/admin/widgets/dashboard/notification.twig b/resources/views/admin/widgets/dashboard/notification.twig new file mode 100755 index 0000000..4ea8233 --- /dev/null +++ b/resources/views/admin/widgets/dashboard/notification.twig @@ -0,0 +1,61 @@ +
+
+

{{ trans('admin.notifications.send.title') }}

+
+
+ {{ csrf_field() }} +
+ {% if errors.any %} +
{{ errors.first }}
+ {% endif %} + {% set sent_result = session_pull('sentResult') %} + {% if sent_result %} +
{{ sent_result }}
+ {% endif %} +
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+
+ + +
+
+ + +
+
+ +
+
diff --git a/resources/views/admin/widgets/dashboard/usage.twig b/resources/views/admin/widgets/dashboard/usage.twig new file mode 100755 index 0000000..051ab3d --- /dev/null +++ b/resources/views/admin/widgets/dashboard/usage.twig @@ -0,0 +1,55 @@ +
+
+
+
+

{{ sum.users }}

+

{{ trans('admin.index.total-users') }}

+
+
+ + {{ trans('general.user-manage') }}  + + +
+
+ +
+
+
+

{{ sum.players }}

+

{{ trans('admin.index.total-players') }}

+
+
+ + {{ trans('general.player-manage') }}  + + +
+
+
+ +
+
+
+
+

{{ sum.textures }}

+

{{ trans('admin.index.total-textures') }}

+
+
+
+
+ +
+
+
+ {% if sum.storage > 1024 %} +

{{ (sum.storage / 1024)|round(1) }}MB

+ {% else %} +

{{ sum.storage }}KB

+ {% endif %} +

{{ trans('admin.index.disk-usage') }}

+
+
+
+
+
diff --git a/resources/views/admin/widgets/status/info.twig b/resources/views/admin/widgets/status/info.twig new file mode 100755 index 0000000..bda2447 --- /dev/null +++ b/resources/views/admin/widgets/status/info.twig @@ -0,0 +1,22 @@ +
+
+

{{ trans('admin.status.info') }}

+
+
+ + + {% for category, info in detail %} + + + + {% for key, value in info %} + + + + + {% endfor %} + {% endfor %} + +
{{ trans("admin.status.#{category}.name") }}
{{ trans("admin.status.#{category}.#{key}") }}{{ value }}
+
+
diff --git a/resources/views/admin/widgets/status/plugins.twig b/resources/views/admin/widgets/status/plugins.twig new file mode 100755 index 0000000..c6776d7 --- /dev/null +++ b/resources/views/admin/widgets/status/plugins.twig @@ -0,0 +1,19 @@ +
+
+

+ {{ trans('admin.status.plugins', {amount: plugins|length}) }} +

+
+
+ + + {% for plugin in plugins %} + + + + + {% endfor %} + +
{{ plugin.title }}{{ plugin.version }}
+
+
diff --git a/resources/views/assets/.gitignore b/resources/views/assets/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/resources/views/assets/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/resources/views/auth/base.twig b/resources/views/auth/base.twig new file mode 100755 index 0000000..e26be33 --- /dev/null +++ b/resources/views/auth/base.twig @@ -0,0 +1,24 @@ + + + + {{ include('shared.head') }} + {% block title %}{% endblock %} - {{ site_name }} + + + + + + {% block before_foot %}{% endblock %} + {{ include('shared.foot') }} + + diff --git a/resources/views/auth/bind.twig b/resources/views/auth/bind.twig new file mode 100755 index 0000000..bdc511c --- /dev/null +++ b/resources/views/auth/bind.twig @@ -0,0 +1,36 @@ +{% extends 'auth.base' %} + +{% block title %}{{ trans('auth.bind.title') }}{% endblock %} + +{% block content %} + +
+ {{ csrf_field() }} +
+ +
+
+ +
+
+
+ +

{{ trans('auth.bind.introduction') }}

+ + {% if errors.any %} +
+ + {{ errors.first }} +
+ {% endif %} + + + +{% endblock %} diff --git a/resources/views/auth/forgot.twig b/resources/views/auth/forgot.twig new file mode 100755 index 0000000..141f296 --- /dev/null +++ b/resources/views/auth/forgot.twig @@ -0,0 +1,19 @@ +{% extends 'auth.base' %} + +{% block title %}{{ trans('auth.forgot.title') }}{% endblock %} + +{% block content %} + + {% if session_has('msg') %} +
+ {{ session_pull('msg') }} +
+ {% endif %} +
+{% endblock %} + +{% block before_foot %} + +{% endblock %} diff --git a/resources/views/auth/login.twig b/resources/views/auth/login.twig new file mode 100755 index 0000000..a032bbc --- /dev/null +++ b/resources/views/auth/login.twig @@ -0,0 +1,15 @@ +{% extends 'auth.base' %} + +{% block title %}{{ trans('auth.login.title') }}{% endblock %} + +{% block content %} + {% for row in rows %} + {{ include(row) }} + {% endfor %} +{% endblock %} + +{% block before_foot %} + +{% endblock %} diff --git a/resources/views/auth/register.twig b/resources/views/auth/register.twig new file mode 100755 index 0000000..0fbcc18 --- /dev/null +++ b/resources/views/auth/register.twig @@ -0,0 +1,15 @@ +{% extends 'auth.base' %} + +{% block title %}{{ trans('auth.register.title') }}{% endblock %} + +{% block content %} + {% for row in rows %} + {{ include(row) }} + {% endfor %} +{% endblock %} + +{% block before_foot %} + +{% endblock %} diff --git a/resources/views/auth/reset.twig b/resources/views/auth/reset.twig new file mode 100755 index 0000000..fecbd54 --- /dev/null +++ b/resources/views/auth/reset.twig @@ -0,0 +1,10 @@ +{% extends 'auth.base' %} + +{% block title %}{{ trans('auth.reset.title') }}{% endblock %} + +{% block content %} + +
+{% endblock %} diff --git a/resources/views/auth/rows/login/form.twig b/resources/views/auth/rows/login/form.twig new file mode 100755 index 0000000..7daf4c0 --- /dev/null +++ b/resources/views/auth/rows/login/form.twig @@ -0,0 +1 @@ +
diff --git a/resources/views/auth/rows/login/message.twig b/resources/views/auth/rows/login/message.twig new file mode 100755 index 0000000..9b0234e --- /dev/null +++ b/resources/views/auth/rows/login/message.twig @@ -0,0 +1,5 @@ +{% if session_has('msg') %} +
+ {{ session_pull('msg') }} +
+{% endif %} diff --git a/resources/views/auth/rows/login/notice.twig b/resources/views/auth/rows/login/notice.twig new file mode 100755 index 0000000..d27d6a0 --- /dev/null +++ b/resources/views/auth/rows/login/notice.twig @@ -0,0 +1 @@ + diff --git a/resources/views/auth/rows/login/registration-link.twig b/resources/views/auth/rows/login/registration-link.twig new file mode 100755 index 0000000..f2962e3 --- /dev/null +++ b/resources/views/auth/rows/login/registration-link.twig @@ -0,0 +1,3 @@ + diff --git a/resources/views/auth/rows/register/form.twig b/resources/views/auth/rows/register/form.twig new file mode 100755 index 0000000..7daf4c0 --- /dev/null +++ b/resources/views/auth/rows/register/form.twig @@ -0,0 +1 @@ +
diff --git a/resources/views/auth/rows/register/notice.twig b/resources/views/auth/rows/register/notice.twig new file mode 100755 index 0000000..cfbe275 --- /dev/null +++ b/resources/views/auth/rows/register/notice.twig @@ -0,0 +1,3 @@ + diff --git a/resources/views/auth/verify.twig b/resources/views/auth/verify.twig new file mode 100755 index 0000000..c7af493 --- /dev/null +++ b/resources/views/auth/verify.twig @@ -0,0 +1,34 @@ +{% extends 'auth.base' %} + +{% block title %}{{ trans('auth.verify.title') }}{% endblock %} + +{% block content %} + +
+ {{ csrf_field() }} +
+ +
+
+ +
+
+
+ {% if errors.any %} +
+ + {{ errors.first }} +
+ {% elseif session_has('errorMessage') %} +
+ + {{ session_pull('errorMessage') }} +
+ {% endif %} + +
+{% endblock %} diff --git a/resources/views/errors/403.twig b/resources/views/errors/403.twig new file mode 100755 index 0000000..799c03c --- /dev/null +++ b/resources/views/errors/403.twig @@ -0,0 +1,9 @@ +{% extends 'errors.base' %} + +{% block title %}403 Forbidden{% endblock %} + +{% block message %} +

+ {{ trans('errors.exception.detail', {msg: exception.message ?: trans('errors.http.msg-403')}) }} +

+{% endblock %} diff --git a/resources/views/errors/404.twig b/resources/views/errors/404.twig new file mode 100755 index 0000000..e3ecce8 --- /dev/null +++ b/resources/views/errors/404.twig @@ -0,0 +1,9 @@ +{% extends 'errors.base' %} + +{% block title %}404 Not Found{% endblock %} + +{% block message %} +

+ {{ trans('errors.exception.detail', {msg: exception.message ?: trans('errors.http.msg-404')}) }} +

+{% endblock %} diff --git a/resources/views/errors/500.twig b/resources/views/errors/500.twig new file mode 100755 index 0000000..0a53179 --- /dev/null +++ b/resources/views/errors/500.twig @@ -0,0 +1,9 @@ +{% extends 'errors.base' %} + +{% block title %}500 Internal Server Error{% endblock %} + +{% block message %} +

+ {{ trans('errors.exception.detail', {msg: exception.message ?: trans('errors.http.msg-500')}) }} +

+{% endblock %} diff --git a/resources/views/errors/503.twig b/resources/views/errors/503.twig new file mode 100755 index 0000000..13df13f --- /dev/null +++ b/resources/views/errors/503.twig @@ -0,0 +1,9 @@ +{% extends 'errors.base' %} + +{% block title %}503 Service Unavailable{% endblock %} + +{% block message %} +

+ {{ trans('errors.exception.detail', {msg: exception.message ?: trans('errors.http.msg-503')}) }} +

+{% endblock %} diff --git a/resources/views/errors/base.twig b/resources/views/errors/base.twig new file mode 100755 index 0000000..bca2db1 --- /dev/null +++ b/resources/views/errors/base.twig @@ -0,0 +1,33 @@ + + + + + + + + {% block title %}{% endblock %} - {{ site_name }} + {{ include('assets.spectre', ignore_missing = true) }} + {% for style in styles %} + + {% endfor %} + + + + {{ include('errors.languages') }} +
+
+

{{ site_name }}

+
+

{% block subtitle %}{{ block('title') }}{% endblock %}

+ {% block message %}{% endblock %} +
+ {% if auth_user().admin %} + FAQ + {% endif %} +
+
+ {% for script in scripts %} + + {% endfor %} + + diff --git a/resources/views/errors/exception.twig b/resources/views/errors/exception.twig new file mode 100755 index 0000000..ac89d51 --- /dev/null +++ b/resources/views/errors/exception.twig @@ -0,0 +1,8 @@ +{% extends 'errors.base' %} + +{% block title %}{{ trans('errors.general.title') }}{% endblock %} + +{% block message %} +

{{ message }}

+

{{ trans('errors.exception.message')|nl2br }}

+{% endblock %} diff --git a/resources/views/errors/languages.twig b/resources/views/errors/languages.twig new file mode 100755 index 0000000..33cf484 --- /dev/null +++ b/resources/views/errors/languages.twig @@ -0,0 +1,7 @@ +
+ {% for lang in langs %} + {{ lang.name }} + {% endfor %} +
diff --git a/resources/views/errors/pretty.twig b/resources/views/errors/pretty.twig new file mode 100755 index 0000000..10e8558 --- /dev/null +++ b/resources/views/errors/pretty.twig @@ -0,0 +1,8 @@ +{% extends 'errors.base' %} + +{% block title %}{{ trans('errors.general.title') }}{% endblock %} + +{% block message %} +

{{ trans('errors.exception.code', {code: code}) }}

+

{{ trans('errors.exception.detail', {msg: message})|nl2br }}

+{% endblock %} diff --git a/resources/views/forms/addon.twig b/resources/views/forms/addon.twig new file mode 100755 index 0000000..111033d --- /dev/null +++ b/resources/views/forms/addon.twig @@ -0,0 +1,3 @@ +
+ {{ value }} +
diff --git a/resources/views/forms/checkbox.twig b/resources/views/forms/checkbox.twig new file mode 100755 index 0000000..9f43b39 --- /dev/null +++ b/resources/views/forms/checkbox.twig @@ -0,0 +1,10 @@ + diff --git a/resources/views/forms/form.twig b/resources/views/forms/form.twig new file mode 100755 index 0000000..428cea7 --- /dev/null +++ b/resources/views/forms/form.twig @@ -0,0 +1,75 @@ +
+
+

{{ title }} {{ hint|raw }}

+
+
+ {{ csrf_field() }} + +
+ {% for message in messages %} +
+ {{ message.content|raw }} +
+ {% endfor %} + + {% for alert in alerts %} +
+ {% if alert.type == 'success' %} + + {% elseif alert.type == 'info' %} + + {% elseif alert.type == 'warning' %} + + {% elseif alert.type == 'danger' %} + + {% endif %} + {{ alert.content }} +
+ {% endfor %} + + {% if renderWithoutTable %} + {% for item in items %} + {{ item.render()|raw }} + {% if item.description %} +

{{ item.description|raw }}

+ {% endif %} + {% endfor %} + {% else %} +
+ {% for item in items %} +
+ {% if not renderInputTagsOnly %} +
+ {{ item.name }} {{ item.hint|raw }} +
+ {% endif %} +
+ {{ item.render()|raw }} + {% if item.description %} +

{{ item.description|raw }}

+ {% endif %} +
+
+ {% endfor %} +
+ {% endif %} +
+ +
+
diff --git a/resources/views/forms/group.twig b/resources/views/forms/group.twig new file mode 100755 index 0000000..ab7f5d6 --- /dev/null +++ b/resources/views/forms/group.twig @@ -0,0 +1,5 @@ +
+ {% for item in items %} + {{ item.render()|raw }} + {% endfor %} +
diff --git a/resources/views/forms/hint.twig b/resources/views/forms/hint.twig new file mode 100755 index 0000000..81a290a --- /dev/null +++ b/resources/views/forms/hint.twig @@ -0,0 +1 @@ + diff --git a/resources/views/forms/select.twig b/resources/views/forms/select.twig new file mode 100755 index 0000000..6bdb9ce --- /dev/null +++ b/resources/views/forms/select.twig @@ -0,0 +1,10 @@ + diff --git a/resources/views/forms/text.twig b/resources/views/forms/text.twig new file mode 100755 index 0000000..c0a55af --- /dev/null +++ b/resources/views/forms/text.twig @@ -0,0 +1,8 @@ + diff --git a/resources/views/forms/textarea.twig b/resources/views/forms/textarea.twig new file mode 100755 index 0000000..42a905b --- /dev/null +++ b/resources/views/forms/textarea.twig @@ -0,0 +1,6 @@ + diff --git a/resources/views/home.twig b/resources/views/home.twig new file mode 100755 index 0000000..a3a0543 --- /dev/null +++ b/resources/views/home.twig @@ -0,0 +1,135 @@ + + + + {{ include('shared.head') }} + + {{ site_name }} + + {{ include('assets.home-css', ignore_missing = true) }} + + + +
+ {% if fixed_bg %} +
+ {% endif %} + + + +
+
+

{{ site_name }}

+

+ {{ site_description }} +

+

+ {% if auth_check() %} + + {{ trans('general.user-center') }} + + {% else %} + + {{ trans('general.register') }} + + {% endif %} +

+
+
+ + {% if hide_intro %} + + {% endif %} +
+ + {% if not hide_intro %} +
+
+
+

{{ trans('index.features.title') }}

+
+
+
+
+ {% for item in ['first', 'second', 'third'] %} +
+ +

{{ trans("index.features.#{item}.name") }}

+

{{ trans("index.features.#{item}.desc")|raw }}

+
+ {% endfor %} +
+
+
+
+
+
+ + + {% endif %} + + + {{ include('assets.home', ignore_missing = true) }} + {{ include('shared.foot') }} + + diff --git a/resources/views/mails/email-verification.blade.php b/resources/views/mails/email-verification.blade.php new file mode 100755 index 0000000..345cf1e --- /dev/null +++ b/resources/views/mails/email-verification.blade.php @@ -0,0 +1,3 @@ +

{!! trans('user.verification.mail.message', ['sitename' => option_localized('site_name')]) !!}

+

{!! trans('user.verification.mail.reset', ['url' => $url]) !!}

+

{!! trans('user.verification.mail.ignore') !!}

diff --git a/resources/views/mails/password-reset.blade.php b/resources/views/mails/password-reset.blade.php new file mode 100755 index 0000000..5541800 --- /dev/null +++ b/resources/views/mails/password-reset.blade.php @@ -0,0 +1,3 @@ +

{!! trans('auth.forgot.mail.message', ['sitename' => option_localized('site_name')]) !!}

+

{!! trans('auth.forgot.mail.reset', ['url' => $url]) !!}

+

{!! trans('auth.forgot.mail.ignore') !!}

diff --git a/resources/views/setup/base.twig b/resources/views/setup/base.twig new file mode 100755 index 0000000..499bf3e --- /dev/null +++ b/resources/views/setup/base.twig @@ -0,0 +1,34 @@ + + + + + + + + {% block title %}{{ trans('setup.wizard.master.title') }}{% endblock %} + {{ include('assets.spectre', ignore_missing = true) }} + {% for style in styles %} + + {% endfor %} + + + + {{ include('errors.languages') }} +
+
+

+ + Blessing Skin Server + +

+
+

{% block subtitle %}{{ block('title') }}{% endblock %}

+
+ {% block content %}{% endblock %} +
+
+ {% for script in scripts %} + + {% endfor %} + + diff --git a/resources/views/setup/locked.twig b/resources/views/setup/locked.twig new file mode 100755 index 0000000..6d81f75 --- /dev/null +++ b/resources/views/setup/locked.twig @@ -0,0 +1,12 @@ +{% extends 'setup.base' %} + +{% block subtitle %}{{ trans('setup.locked.title') }}{% endblock %} + +{% block content %} +

{{ trans('setup.locked.text') }}

+

+ + {{ trans('setup.locked.button') }} + +

+{% endblock %} diff --git a/resources/views/setup/wizard/database.twig b/resources/views/setup/wizard/database.twig new file mode 100755 index 0000000..5fb0e7d --- /dev/null +++ b/resources/views/setup/wizard/database.twig @@ -0,0 +1,153 @@ +{% extends 'setup.base' %} + +{% block subtitle %}{{ trans('setup.wizard.database.title') }}{% endblock %} + +{% block content %} +

{{ trans('setup.wizard.database.text') }}

+
+ {{ csrf_field() }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +

{{ trans('setup.wizard.database.db-notice') }}

+ + + +

{{ trans('setup.wizard.database.prefix-notice') }}

+ + {% if errors.any %} + + {% endif %} + +

+ +

+
+{% endblock %} diff --git a/resources/views/setup/wizard/finish.twig b/resources/views/setup/wizard/finish.twig new file mode 100755 index 0000000..7f54d52 --- /dev/null +++ b/resources/views/setup/wizard/finish.twig @@ -0,0 +1,12 @@ +{% extends 'setup.base' %} + +{% block subtitle %}{{ trans('setup.wizard.finish.title') }}{% endblock %} + +{% block content %} +

{{ trans('setup.wizard.finish.text') }}

+

+ + {{ trans('general.index') }} + +

+{% endblock %} diff --git a/resources/views/setup/wizard/info.twig b/resources/views/setup/wizard/info.twig new file mode 100755 index 0000000..7ad281a --- /dev/null +++ b/resources/views/setup/wizard/info.twig @@ -0,0 +1,105 @@ +{% extends 'setup.base' %} + +{% block subtitle %}{{ trans('setup.wizard.info.title') }}{% endblock %} + +{% block content %} +

{{ trans('setup.wizard.info.text') }}

+
+ {{ csrf_field() }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +

{{ trans('setup.wizard.info.admin-notice') }}

+ + + +
+ + + +

{{ trans('setup.wizard.info.pwd-notice') }}

+ + + +
+ + + +

{{ trans('setup.wizard.info.site-name-notice') }}

+ + {% if errors.any %} + + {% endif %} + +

+ +

+
+{% endblock %} diff --git a/resources/views/setup/wizard/welcome.twig b/resources/views/setup/wizard/welcome.twig new file mode 100755 index 0000000..6ca25ca --- /dev/null +++ b/resources/views/setup/wizard/welcome.twig @@ -0,0 +1,12 @@ +{% extends 'setup.base' %} + +{% block subtitle %}{{ trans('setup.wizard.welcome.title') }}{% endblock %} + +{% block content %} +

{{ trans('setup.wizard.welcome.text', {version: config('app.version')}) }}

+

+ + {{ trans('setup.wizard.welcome.button') }} + +

+{% endblock %} diff --git a/resources/views/shared/copyright.twig b/resources/views/shared/copyright.twig new file mode 100755 index 0000000..239e236 --- /dev/null +++ b/resources/views/shared/copyright.twig @@ -0,0 +1,23 @@ +{% set repo = 'https://github.com/bs-community/blessing-skin-server' %} + + + + +{% set rules = {'{site_name}': site_name, '{site_url}': site_url} %} +{{ custom_copyright|replace(rules)|raw }} diff --git a/resources/views/shared/dark-mode.twig b/resources/views/shared/dark-mode.twig new file mode 100755 index 0000000..fe843d9 --- /dev/null +++ b/resources/views/shared/dark-mode.twig @@ -0,0 +1,7 @@ +{% if auth_check() %} + +{% endif %} diff --git a/resources/views/shared/foot.twig b/resources/views/shared/foot.twig new file mode 100755 index 0000000..6b14ce4 --- /dev/null +++ b/resources/views/shared/foot.twig @@ -0,0 +1,11 @@ + +{{ include('assets.app', ignore_missing = true) }} +{% for script in scripts %} + +{% endfor %} +{% if inline_js %} + +{% endif %} +{{ extra_foot|join('\n')|raw }} diff --git a/resources/views/shared/footer.twig b/resources/views/shared/footer.twig new file mode 100755 index 0000000..d340d9c --- /dev/null +++ b/resources/views/shared/footer.twig @@ -0,0 +1,3 @@ +
+ {{ include('shared.copyright') }} +
diff --git a/resources/views/shared/grid.twig b/resources/views/shared/grid.twig new file mode 100755 index 0000000..db412d9 --- /dev/null +++ b/resources/views/shared/grid.twig @@ -0,0 +1,12 @@ +{% for row in grid.widgets %} +
+ {% set layout = grid.layout[loop.index0] %} + {% for col in row %} +
+ {% for widget in col %} + {{ include(widget) }} + {% endfor %} +
+ {% endfor %} +
+{% endfor %} diff --git a/resources/views/shared/head.twig b/resources/views/shared/head.twig new file mode 100755 index 0000000..c3d1950 --- /dev/null +++ b/resources/views/shared/head.twig @@ -0,0 +1,26 @@ + + + + + + + +{{ seo.extra|striptags('')|raw }} + +{% if custom_cdn_host %} + +{% endif %} + + + +{{ include('assets.style', ignore_missing = true) }} +{% for link in links %} + +{% endfor %} + + + +{% if inline_css %} + +{% endif %} +{{ extra_head|join('\n')|raw }} diff --git a/resources/views/shared/header.twig b/resources/views/shared/header.twig new file mode 100755 index 0000000..33270ff --- /dev/null +++ b/resources/views/shared/header.twig @@ -0,0 +1,16 @@ + diff --git a/resources/views/shared/languages.twig b/resources/views/shared/languages.twig new file mode 100755 index 0000000..d2d3bb9 --- /dev/null +++ b/resources/views/shared/languages.twig @@ -0,0 +1,14 @@ + diff --git a/resources/views/shared/notifications.twig b/resources/views/shared/notifications.twig new file mode 100755 index 0000000..bd7c561 --- /dev/null +++ b/resources/views/shared/notifications.twig @@ -0,0 +1,6 @@ + diff --git a/resources/views/shared/previewer.twig b/resources/views/shared/previewer.twig new file mode 100755 index 0000000..ba4eb4a --- /dev/null +++ b/resources/views/shared/previewer.twig @@ -0,0 +1 @@ +
diff --git a/resources/views/shared/side-menu-item.twig b/resources/views/shared/side-menu-item.twig new file mode 100755 index 0000000..945d989 --- /dev/null +++ b/resources/views/shared/side-menu-item.twig @@ -0,0 +1,26 @@ + diff --git a/resources/views/shared/side-menu.twig b/resources/views/shared/side-menu.twig new file mode 100755 index 0000000..9a1388b --- /dev/null +++ b/resources/views/shared/side-menu.twig @@ -0,0 +1,3 @@ +{% for item in items %} + {{ include('shared.side-menu-item', {item: item}) }} +{% endfor %} diff --git a/resources/views/shared/sidebar.twig b/resources/views/shared/sidebar.twig new file mode 100755 index 0000000..e333347 --- /dev/null +++ b/resources/views/shared/sidebar.twig @@ -0,0 +1,53 @@ + diff --git a/resources/views/shared/user-menu.twig b/resources/views/shared/user-menu.twig new file mode 100755 index 0000000..170ca81 --- /dev/null +++ b/resources/views/shared/user-menu.twig @@ -0,0 +1,41 @@ + diff --git a/resources/views/shared/user-panel.twig b/resources/views/shared/user-panel.twig new file mode 100755 index 0000000..8990fd1 --- /dev/null +++ b/resources/views/shared/user-panel.twig @@ -0,0 +1,19 @@ +
+
+
+ + + User Image + +
+ +
+ +
+ {% for badge in badges %} + {{ badge.text }} + {% endfor %} +
+
diff --git a/resources/views/skinlib/base.twig b/resources/views/skinlib/base.twig new file mode 100755 index 0000000..638042f --- /dev/null +++ b/resources/views/skinlib/base.twig @@ -0,0 +1,75 @@ + + + + {{ include('shared.head') }} + {% block title %}{% endblock %} - {{ site_name }} + + + +
+ + + {% block content %}{% endblock %} + +
+
+ {{ include('shared.copyright') }} +
+
+
+ {% block before_foot %}{% endblock %} + {{ include('shared.foot') }} + + diff --git a/resources/views/skinlib/index.twig b/resources/views/skinlib/index.twig new file mode 100755 index 0000000..47bc857 --- /dev/null +++ b/resources/views/skinlib/index.twig @@ -0,0 +1,13 @@ +{% extends 'skinlib.base' %} + +{% block title %}{{ trans('general.skinlib') }}{% endblock %} + +{% block content %} +
+{% endblock %} + +{% block before_foot %} + +{% endblock %} diff --git a/resources/views/skinlib/show.twig b/resources/views/skinlib/show.twig new file mode 100755 index 0000000..c79e94d --- /dev/null +++ b/resources/views/skinlib/show.twig @@ -0,0 +1,36 @@ +{% extends 'skinlib.base' %} + +{% block title %}{{ texture.name }}{% endblock %} + +{% block content %} +
+
+
+
+
+
+

{{ trans('skinlib.show.title') }}

+
+
+ +
+
+
+
+ +
+
+ {{ include('shared.grid') }} +
+
+
+
+ +
+{% endblock %} + +{% block before_foot %} + +{% endblock %} diff --git a/resources/views/skinlib/upload.twig b/resources/views/skinlib/upload.twig new file mode 100755 index 0000000..0e9b6dd --- /dev/null +++ b/resources/views/skinlib/upload.twig @@ -0,0 +1,33 @@ +{% extends 'skinlib.base' %} + +{% block title %}{{ trans('skinlib.upload.title') }}{% endblock %} + +{% block content %} +
+
+
+
+
+
+

{{ block('title') }}

+
+
+ +
+
+
+
+
+
+ {{ include('shared.grid') }} +
+
+
+
+{% endblock %} + +{% block before_foot %} + +{% endblock %} diff --git a/resources/views/skinlib/widgets/show/side.twig b/resources/views/skinlib/widgets/show/side.twig new file mode 100755 index 0000000..8e6ec8f --- /dev/null +++ b/resources/views/skinlib/widgets/show/side.twig @@ -0,0 +1 @@ +
diff --git a/resources/views/skinlib/widgets/upload/input.twig b/resources/views/skinlib/widgets/upload/input.twig new file mode 100755 index 0000000..817852f --- /dev/null +++ b/resources/views/skinlib/widgets/upload/input.twig @@ -0,0 +1 @@ +
diff --git a/resources/views/user/base.twig b/resources/views/user/base.twig new file mode 100755 index 0000000..37f026c --- /dev/null +++ b/resources/views/user/base.twig @@ -0,0 +1,38 @@ + + + + {{ include('shared.head') }} + {% block title %}{% endblock %} - {{ site_name }} + + + +
+ {{ include('shared.header') }} + {{ include('shared.sidebar', {scope: 'user'}) }} +
+
+
+
+
+

{{ block('title') }}

+
+
+ +
+
+
+
+
+
+ {% block content %}{% endblock %} +
+
+
+
+ {{ include('shared.copyright') }} +
+
+ {% block before_foot %}{% endblock %} + {{ include('shared.foot') }} + + diff --git a/resources/views/user/closet.twig b/resources/views/user/closet.twig new file mode 100755 index 0000000..19dc3b2 --- /dev/null +++ b/resources/views/user/closet.twig @@ -0,0 +1,15 @@ +{% extends 'user.base' %} + +{% block title %}{{ trans('general.my-closet') }}{% endblock %} + +{% block content %} + {{ include('shared.grid') }} + +
+{% endblock %} + +{% block before_foot %} + +{% endblock %} diff --git a/resources/views/user/index.twig b/resources/views/user/index.twig new file mode 100755 index 0000000..a298e43 --- /dev/null +++ b/resources/views/user/index.twig @@ -0,0 +1,42 @@ +{% extends 'user.base' %} + +{% block title %}{{ trans('general.dashboard') }}{% endblock %} + +{% block content %} + {{ include('shared.grid') }} + + +{% endblock %} + +{% block before_foot %} + +{% endblock %} diff --git a/resources/views/user/master.blade.php b/resources/views/user/master.blade.php new file mode 100755 index 0000000..5425b39 --- /dev/null +++ b/resources/views/user/master.blade.php @@ -0,0 +1,20 @@ + + + + @include('shared.head') + @yield('title') - {{ option_localized('site_name') }} + @yield('style') + + + +
+ @include('shared.header') + @include('shared.sidebar', ['scope' => 'user']) + @yield('content') + @include('shared.footer') +
+ + @include('shared.foot') + @yield('script') + + diff --git a/resources/views/user/oauth.twig b/resources/views/user/oauth.twig new file mode 100755 index 0000000..d4e8ee8 --- /dev/null +++ b/resources/views/user/oauth.twig @@ -0,0 +1,3 @@ +{% extends 'user.base' %} + +{% block title %}{{ trans('general.oauth-manage') }}{% endblock %} diff --git a/resources/views/user/player.twig b/resources/views/user/player.twig new file mode 100755 index 0000000..6ed8f4e --- /dev/null +++ b/resources/views/user/player.twig @@ -0,0 +1,15 @@ +{% extends 'user.base' %} + +{% block title %}{{ trans('general.player-manage') }}{% endblock %} + +{% block content %} + {{ include('shared.grid') }} + +
+{% endblock %} + +{% block before_foot %} + +{% endblock %} diff --git a/resources/views/user/profile.twig b/resources/views/user/profile.twig new file mode 100755 index 0000000..07025d7 --- /dev/null +++ b/resources/views/user/profile.twig @@ -0,0 +1,36 @@ +{% extends 'user.base' %} + +{% block title %}{{ trans('general.profile') }}{% endblock %} + +{% block content %} + {{ include('shared.grid') }} + + +{% endblock %} diff --git a/resources/views/user/report.twig b/resources/views/user/report.twig new file mode 100755 index 0000000..e5d3399 --- /dev/null +++ b/resources/views/user/report.twig @@ -0,0 +1,40 @@ +{% extends 'user.base' %} + +{% block title %}{{ trans('general.my-reports') }}{% endblock %} + +{% block content %} +
+
+ + + + + + + + + + + {% for report in reports %} + + + + + + + {% endfor %} + +
{{ trans('front-end.report.tid') }}{{ trans('front-end.report.reason') }}{{ trans('front-end.report.status-title') }}{{ trans('front-end.report.time') }}
+ {{ report.tid }}  + + + + {{ report.reason }}{{ trans('front-end.report.status')[report.status] }}{{ report.report_at }}
+
+ +
+{% endblock %} diff --git a/resources/views/user/widgets/closet/list.twig b/resources/views/user/widgets/closet/list.twig new file mode 100755 index 0000000..617cf23 --- /dev/null +++ b/resources/views/user/widgets/closet/list.twig @@ -0,0 +1 @@ +
diff --git a/resources/views/user/widgets/dashboard/announcement.twig b/resources/views/user/widgets/dashboard/announcement.twig new file mode 100755 index 0000000..a50665f --- /dev/null +++ b/resources/views/user/widgets/dashboard/announcement.twig @@ -0,0 +1,14 @@ +
+
+

{{ trans('user.announcement') }}

+ {% if auth_user().admin %} +   + + + + {% endif %} +
+
+ {{ announcement|raw }} +
+
diff --git a/resources/views/user/widgets/dashboard/usage.twig b/resources/views/user/widgets/dashboard/usage.twig new file mode 100755 index 0000000..169c123 --- /dev/null +++ b/resources/views/user/widgets/dashboard/usage.twig @@ -0,0 +1 @@ +
diff --git a/resources/views/user/widgets/email-verification.twig b/resources/views/user/widgets/email-verification.twig new file mode 100755 index 0000000..18065c8 --- /dev/null +++ b/resources/views/user/widgets/email-verification.twig @@ -0,0 +1 @@ +
diff --git a/resources/views/user/widgets/players/list.twig b/resources/views/user/widgets/players/list.twig new file mode 100755 index 0000000..2ad82db --- /dev/null +++ b/resources/views/user/widgets/players/list.twig @@ -0,0 +1 @@ +
diff --git a/resources/views/user/widgets/players/notice.twig b/resources/views/user/widgets/players/notice.twig new file mode 100755 index 0000000..5b9c59a --- /dev/null +++ b/resources/views/user/widgets/players/notice.twig @@ -0,0 +1,10 @@ +
+
+

+ {{ trans('general.notice') }} +

+
+
+ {{ trans('user.player.login-notice') }} +
+
diff --git a/resources/views/user/widgets/profile/avatar.twig b/resources/views/user/widgets/profile/avatar.twig new file mode 100755 index 0000000..595bc9b --- /dev/null +++ b/resources/views/user/widgets/profile/avatar.twig @@ -0,0 +1,15 @@ +
+
+

+ {{ trans('user.profile.avatar.title') }} +

+
+
+ {{ trans('user.profile.avatar.notice')|raw }} +
+ +
diff --git a/resources/views/user/widgets/profile/delete-account.twig b/resources/views/user/widgets/profile/delete-account.twig new file mode 100755 index 0000000..e8ebec6 --- /dev/null +++ b/resources/views/user/widgets/profile/delete-account.twig @@ -0,0 +1,24 @@ +
+
+

+ {{ trans('user.profile.delete.title') }} +

+
+
+ {% if user.admin %} +

{{ trans('user.profile.delete.admin') }}

+ + {% else %} +

{{ trans('user.profile.delete.notice', { site: site_name }) }}

+ + {% endif %} +
+
diff --git a/resources/views/user/widgets/profile/email.twig b/resources/views/user/widgets/profile/email.twig new file mode 100755 index 0000000..4735344 --- /dev/null +++ b/resources/views/user/widgets/profile/email.twig @@ -0,0 +1,23 @@ +
+
+

+ {{ trans('user.profile.email.title') }} +

+
+
+
+ +
+
+ +
+
+ +
diff --git a/resources/views/user/widgets/profile/nickname.twig b/resources/views/user/widgets/profile/nickname.twig new file mode 100755 index 0000000..b718a18 --- /dev/null +++ b/resources/views/user/widgets/profile/nickname.twig @@ -0,0 +1,18 @@ +
+
+

+ {{ trans('user.profile.nickname.title') }} +

+
+
+
+ +
+
+ +
diff --git a/resources/views/user/widgets/profile/password.twig b/resources/views/user/widgets/profile/password.twig new file mode 100755 index 0000000..55aa59d --- /dev/null +++ b/resources/views/user/widgets/profile/password.twig @@ -0,0 +1,31 @@ +
+
+

+ {{ trans('user.profile.password.title') }} +

+
+
+
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
diff --git a/resources/views/vendor/passport/authorize.twig b/resources/views/vendor/passport/authorize.twig new file mode 100755 index 0000000..8a5ce25 --- /dev/null +++ b/resources/views/vendor/passport/authorize.twig @@ -0,0 +1,43 @@ +{% extends 'auth.base' %} + +{% block title %} + {{ trans('auth.oauth.authorization.title') }} +{% endblock %} + +{% block content %} + + {% if scopes %} +
+

+ {{ trans('auth.oauth.authorization.permissions') }} +

+
    + {% for scope in scopes %} +
  • {{ trans(scope.description) }}
  • + {% endfor %} +
+
+ {% endif %} +
+
+ {{ csrf_field() }} + + + +
+ +
+ {{ csrf_field() }} + {{ method_field('DELETE') }} + + + +
+
+{% endblock %} diff --git a/routes/api.php b/routes/api.php new file mode 100755 index 0000000..1048559 --- /dev/null +++ b/routes/api.php @@ -0,0 +1,77 @@ +middleware('auth:oauth')->group(function () { + Route::get('', 'UserController@user')->middleware(['scope:User.Read']); + + Route::middleware(['scope:Notification.Read'])->group(function () { + Route::get('notifications', 'NotificationsController@all'); + Route::post('notifications/{id}', 'NotificationsController@read'); + }); +}); + +Route::prefix('players')->middleware('auth:oauth')->group(function () { + Route::get('', 'PlayerController@list')->middleware(['scope:Player.Read,Player.ReadWrite']); + + Route::middleware(['scope:Player.ReadWrite'])->group(function () { + Route::post('', 'PlayerController@add'); + Route::delete('{player}', 'PlayerController@delete'); + Route::put('{player}/name', 'PlayerController@rename'); + Route::put('{player}/textures', 'PlayerController@setTexture'); + Route::delete('{player}/textures', 'PlayerController@clearTexture'); + }); +}); + +Route::prefix('closet')->middleware('auth:oauth')->group(function () { + Route::get('', 'ClosetController@getClosetData')->middleware(['scope:Closet.Read,Closet.ReadWrite']); + + Route::middleware(['scope:Closet.ReadWrite'])->group(function () { + Route::post('', 'ClosetController@add'); + Route::put('{tid}', 'ClosetController@rename'); + Route::delete('{tid}', 'ClosetController@remove'); + }); +}); + +Route::prefix('admin') + ->middleware(['auth:oauth', 'role:admin']) + ->group(function () { + Route::prefix('users')->group(function () { + Route::get('', 'UsersManagementController@list')->name('list')->middleware(['scope:UsersManagement.Read,UsersManagement.ReadWrite']); + Route::prefix('{user}')->middleware(['scope:UsersManagement.ReadWrite'])->group(function () { + Route::put('email', 'UsersManagementController@email')->name('email'); + Route::put('verification', 'UsersManagementController@verification')->name('verification'); + Route::put('nickname', 'UsersManagementController@nickname')->name('nickname'); + Route::put('password', 'UsersManagementController@password')->name('password'); + Route::put('score', 'UsersManagementController@score')->name('score'); + Route::put('permission', 'UsersManagementController@permission')->name('permission'); + Route::delete('', 'UsersManagementController@delete')->name('delete'); + }); + }); + + Route::prefix('players')->group(function () { + Route::get('', 'PlayersManagementController@list')->middleware(['scope:PlayersManagement.Read,PlayersManagement.ReadWrite']); + + Route::middleware(['scope:PlayersManagement.ReadWrite'])->group(function () { + Route::put('{player}/name', 'PlayersManagementController@name'); + Route::put('{player}/owner', 'PlayersManagementController@owner'); + Route::put('{player}/textures', 'PlayersManagementController@texture'); + Route::delete('{player}', 'PlayersManagementController@delete'); + }); + }); + + Route::prefix('closet')->group(function () { + Route::get('{user}', 'ClosetManagementController@list')->middleware(['scope:ClosetManagement.Read,ClosetManagement.ReadWrite']); + Route::middleware(['scope:ClosetManagement.ReadWrite'])->group(function () { + Route::post('{user}', 'ClosetManagementController@add'); + Route::delete('{user}', 'ClosetManagementController@remove'); + }); + }); + + Route::prefix('reports')->group(function () { + Route::get('', 'ReportController@manage')->middleware(['scope:ReportsManagement.Read,ReportsManagement.ReadWrite']); + Route::put('{report}', 'ReportController@review')->middleware(['scope:ReportsManagement.ReadWrite']); + }); + + Route::post('notifications', 'NotificationsController@send')->middleware(['scope:Notification.ReadWrite']); + }); diff --git a/routes/static.php b/routes/static.php new file mode 100755 index 0000000..45091ce --- /dev/null +++ b/routes/static.php @@ -0,0 +1,21 @@ +name('avatar.')->group(function () { + Route::get('player/{name}', 'TextureController@avatarByPlayer')->name('player'); + Route::get('user/{uid}', 'TextureController@avatarByUser')->name('user'); + Route::get('hash/{hash}', 'TextureController@avatarByHash')->name('hash'); + Route::get('{tid}', 'TextureController@avatarByTexture')->name('texture'); +}); + +Route::prefix('preview')->name('preview.')->group(function () { + Route::get('{texture}', 'TextureController@preview')->name('texture') + ->middleware(Illuminate\Routing\Middleware\SubstituteBindings::class); + Route::get('hash/{hash}', 'TextureController@previewByHash')->name('hash'); +}); diff --git a/routes/web.php b/routes/web.php new file mode 100755 index 0000000..cc1e005 --- /dev/null +++ b/routes/web.php @@ -0,0 +1,213 @@ +name('auth.')->group(function () { + Route::middleware('guest')->group(function () { + Route::get('login', 'AuthController@login')->name('login'); + Route::post('login', 'AuthController@handleLogin'); + + Route::get('register', 'AuthController@register')->name('register'); + Route::post('register', 'AuthController@handleRegister'); + + Route::get('forgot', 'AuthController@forgot')->name('forgot'); + Route::post('forgot', 'AuthController@handleForgot'); + + Route::get('reset/{uid}', 'AuthController@reset')->name('reset'); + Route::post('reset/{uid}', 'AuthController@handleReset'); + }); + + Route::post('logout', 'AuthController@logout')->name('logout')->middleware('authorize'); + Route::any('captcha', 'AuthController@captcha'); + + Route::middleware(['authorize', Middleware\EnsureEmailFilled::class]) + ->group(function () { + Route::view('bind', 'auth.bind'); + Route::post('bind', 'AuthController@fillEmail'); + }); + + Route::get('verify/{user}', 'AuthController@verify')->name('verify'); + Route::post('verify/{user}', 'AuthController@handleVerify'); +}); + +Route::prefix('user') + ->name('user.') + ->middleware(['authorize']) + ->group(function () { + Route::get('', 'UserController@index')->name('home'); + Route::post('notifications/{id}', 'NotificationsController@read')->name('notification'); + Route::get('score-info', 'UserController@scoreInfo')->name('score'); + Route::post('sign', 'UserController@sign')->name('sign'); + + Route::get('reports', 'ReportController@track'); + + Route::prefix('profile')->name('profile.')->group(function () { + Route::get('', 'UserController@profile'); + Route::post('', 'UserController@handleProfile'); + Route::post('avatar', 'UserController@setAvatar')->name('avatar'); + }); + + Route::post('email-verification', 'UserController@sendVerificationEmail'); + + Route::put('dark-mode', 'UserController@toggleDarkMode'); + + Route::prefix('player') + ->name('player.') + ->middleware('verified') + ->group(function () { + Route::get('', 'PlayerController@index')->name('page'); + Route::get('list', 'PlayerController@list')->name('list'); + Route::post('', 'PlayerController@add')->name('add'); + Route::put('{player}/textures', 'PlayerController@setTexture')->name('set'); + Route::delete('{player}/textures', 'PlayerController@clearTexture')->name('clear'); + Route::put('{player}/name', 'PlayerController@rename')->name('rename'); + Route::delete('{player}', 'PlayerController@delete')->name('delete'); + }); + + Route::prefix('closet')->name('closet.')->group(function () { + Route::get('', 'ClosetController@index')->name('page'); + Route::get('list', 'ClosetController@getClosetData')->name('list'); + Route::get('ids', 'ClosetController@allIds')->name('ids'); + Route::post('', 'ClosetController@add')->name('add'); + Route::put('{tid}', 'ClosetController@rename')->name('rename'); + Route::delete('{tid}', 'ClosetController@remove')->name('remove'); + }); + + // OAuth2 Management + Route::view('oauth/manage', 'user.oauth')->middleware('verified'); + }); + +Route::prefix('texture')->name('texture.')->group(function () { + Route::get('{texture}', 'SkinlibController@info')->name('info'); + Route::middleware(['authorize', 'verified'])->group(function () { + Route::post('', 'SkinlibController@handleUpload')->name('upload'); + Route::prefix('{texture}')->group(function () { + Route::put('type', 'SkinlibController@type')->name('type'); + Route::put('name', 'SkinlibController@rename')->name('name'); + Route::put('privacy', 'SkinlibController@privacy')->name('privacy'); + Route::delete('', 'SkinlibController@delete')->name('delete'); + }); + }); +}); + +Route::prefix('skinlib')->name('skinlib.')->group(function () { + Route::view('', 'skinlib.index')->name('home'); + Route::get('info/{texture}', 'SkinlibController@info')->name('info'); + Route::get('show/{texture}', 'SkinlibController@show')->name('show'); + Route::get('list', 'SkinlibController@library')->name('list'); + + Route::middleware(['authorize', 'verified'])->group(function () { + Route::get('upload', 'SkinlibController@upload'); + Route::post('report', 'ReportController@submit'); + }); +}); + +Route::prefix('admin') + ->name('admin.') + ->middleware(['authorize', 'role:admin']) + ->group(function () { + Route::get('', 'AdminController@index'); + Route::get('chart', 'AdminController@chartData'); + Route::post('notifications/send', 'NotificationsController@send'); + + Route::any('customize', 'OptionsController@customize'); + Route::any('score', 'OptionsController@score'); + Route::any('options', 'OptionsController@options'); + Route::any('resource', 'OptionsController@resource'); + + Route::get('status', 'AdminController@status'); + + Route::prefix('users')->name('users.')->group(function () { + Route::view('', 'admin.users'); + Route::get('list', 'UsersManagementController@list')->name('list'); + Route::prefix('{user}')->group(function () { + Route::put('email', 'UsersManagementController@email')->name('email'); + Route::put('verification', 'UsersManagementController@verification')->name('verification'); + Route::put('nickname', 'UsersManagementController@nickname')->name('nickname'); + Route::put('password', 'UsersManagementController@password')->name('password'); + Route::put('score', 'UsersManagementController@score')->name('score'); + Route::put('permission', 'UsersManagementController@permission')->name('permission'); + Route::delete('', 'UsersManagementController@delete')->name('delete'); + }); + }); + + Route::prefix('players')->name('players.')->group(function () { + Route::view('', 'admin.players'); + Route::get('list', 'PlayersManagementController@list')->name('list'); + Route::prefix('{player}')->group(function () { + Route::put('name', 'PlayersManagementController@name')->name('name'); + Route::put('owner', 'PlayersManagementController@owner')->name('owner'); + Route::put('textures', 'PlayersManagementController@texture')->name('texture'); + Route::delete('', 'PlayersManagementController@delete')->name('delete'); + }); + }); + + Route::prefix('closet')->group(function () { + Route::post('{user}', 'ClosetManagementController@add'); + Route::delete('{user}', 'ClosetManagementController@remove'); + }); + + Route::prefix('reports')->group(function () { + Route::view('', 'admin.reports'); + Route::put('{report}', 'ReportController@review'); + Route::get('list', 'ReportController@manage'); + }); + + Route::prefix('i18n')->group(function () { + Route::view('', 'admin.i18n'); + Route::get('list', 'TranslationsController@list'); + Route::post('', 'TranslationsController@create'); + Route::put('{line}', 'TranslationsController@update'); + Route::delete('{line}', 'TranslationsController@delete'); + }); + + Route::prefix('plugins')->group(function () { + Route::get('data', 'PluginController@getPluginData'); + + Route::view('manage', 'admin.plugins'); + Route::post('manage', 'PluginController@manage'); + Route::any('config/{name}', 'PluginController@config'); + Route::get('readme/{name}', 'PluginController@readme'); + Route::middleware('role:super-admin')->group(function () { + Route::post('upload', 'PluginController@upload'); + Route::post('wget', 'PluginController@wget'); + }); + + Route::prefix('market')->group(function () { + Route::view('', 'admin.market'); + Route::get('list', 'MarketController@marketData'); + Route::post('download', 'MarketController@download'); + }); + }); + + Route::prefix('update')->middleware('role:super-admin')->group(function () { + Route::get('', 'UpdateController@showUpdatePage'); + Route::post('download', 'UpdateController@download'); + }); + }); + +Route::prefix('setup')->group(function () { + Route::middleware('setup')->group(function () { + Route::view('', 'setup.wizard.welcome'); + Route::any('database', 'SetupController@database'); + Route::view('info', 'setup.wizard.info'); + Route::post('finish', 'SetupController@finish'); + }); +}); + +Route::prefix('.well-known')->group(function () { + Route::redirect('change-password', '/user/profile'); +}); diff --git a/storage/app/.gitignore b/storage/app/.gitignore new file mode 100755 index 0000000..8f4803c --- /dev/null +++ b/storage/app/.gitignore @@ -0,0 +1,3 @@ +* +!public/ +!.gitignore diff --git a/storage/app/public/.gitignore b/storage/app/public/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/app/public/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/debugbar/.gitignore b/storage/debugbar/.gitignore new file mode 100755 index 0000000..c96a04f --- /dev/null +++ b/storage/debugbar/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/storage/framework/.gitignore b/storage/framework/.gitignore new file mode 100755 index 0000000..5da0f8e --- /dev/null +++ b/storage/framework/.gitignore @@ -0,0 +1,9 @@ +config.php +routes.php +schedule-* +compiled.php +services.json +events.scanned.php +routes.scanned.php +down +testing/ diff --git a/storage/framework/cache/.gitignore b/storage/framework/cache/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/sessions/.gitignore b/storage/framework/sessions/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/sessions/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/install.lock b/storage/install.lock new file mode 100644 index 0000000..e69de29 diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/oauth-private.key b/storage/oauth-private.key new file mode 100755 index 0000000..5bc6f64 --- /dev/null +++ b/storage/oauth-private.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCbAill8d+W4B2I +qUHfxPow0DtLf3g+5cMTDnZXOTkNpuErVErBr4Qs3ZspJL4yaWonBPCYNNUELoD/ +X+UhtRYK14uH5wLNMJrWcPVbjJggQUaS38D3OnH18rHIXErWhvW/LFVaH6V8RwHD +r0HDUQYDYlpFYYxyCDGduhfo6SrEFLjuZgqDn3qVYHn19m638maZPSM1OG+97MBz +rRajg665HubmsTa27uJsE1eSn5pprW/UWGDCK9CqxcAeh+cULUCisjoYr4EZ7QGG +T/n0IJK7p5XAWx43kZbDwsZOiSZTAlfEexhL7V/tj6RliiAkDozSvlBROnfui+j/ +jOLUB8134cJcTxWnaz60KDjmDg3pkg0UewW/kN6UTym2ipvzgByNm++OQdF5Ja+C +9iSAGuTN5gjWjGVALjjy56Ii19TEsu7iNUrnE4gLJRyPn8FyNJJBTugkYDMog6/i +A9og8U8K30fThszK2R4qRMji4GwxroX/uVm+eecjDUpkiboZh9TPi91Fw4JbS+Dv +d/N/Jg8LQOnlDI9azWNCYbrxNC7obmoBen2PEUFSTHb1gJ7MYCdEs194/7Mt7JPG +3vnU54SQ8MtqQxqaM+b/kNVKloUOO75F+qILK3xwRN8DtazU0DQKyg0z+4wKmQhn +gLjtddGsMHIgQyW1cpDtEzvJkYV3UwIDAQABAoICAGET1YF3HaSL73MrLYpK/rWb +c8cwqcoaczV4FT1DJSwbm2FbhQYQOiMvFoGJ9WP1CPou6c8pJ09bIIbPM90MYCWi +IEyYrPR8wDwUulT/lDZ/KwfJAjzTaZOyzwzAYE5Cb52u0jWDJEzU25IGLJV6JN3x +tr9E/IReBVTWuyqu/I2YvMjxNxx/wHHU3gzgrS6erQrDc01dbv3vTAgmGsuFKOPf +KpTH35Bpw3wUEQBO3JHagPLn9pEkh6ar+kokqt/EB3rdS+0x3RSzjgTkCZKO49aK +egriBeafU2B+l1uQIWRTT0xKG0lR/IX3M+ozuzVZt3A0qHB2wa2wCdgiD9zilhbI +zj2b/BhFgcruOB7HzlcsUojAJuLE3h58oF6+z+zjcDOe/RvFZkracpVjklp/OkjQ +JT0mN+yFjUegaz21Xt94KaGBou1g2X3V6AOY4RFP96kesHPRtrwoAgG9yf5sUlS5 +XjlIS4OWqnWRiF4CJ29obKAqgBGKhkJRGEYKuEpcpDK3wEt74qoIcbHJOBvLGckw +ML+WRAhsWTsEWn9E42I3pZqcFhBv+PAGAo0+RcLFB8e/lBzPPOqkbaxdI0sCCcPj +FhHEsj8vj8floI38FC48jHQ38NEkOMlm69UMfkcpd7SNU9H+nIn5uARv5bQ+zEeb +OcJ5dycWC0wkbTnr3dyBAoIBAQDKFU01dfFT4jeCPyjtNY/IQiZTx0puGyEcuboK +CiNPLzsqmYSnjJHKKyTV8uL4jm9lsCjo+g9FlMWXZqPpbAQWZSSj+N6V9Abv8+dZ +OhhjlyowS2raQodUdcpMRnKOCNpsKBgP02JKMdNnaN/ija0NzoHVFXKvoRi48ljL +K/Ctgo7eJufv2POQ0K6o80e11uKKL50b9MTMDbOKsje7JCkdMYNuP/TuE7jSr16v +WQAN+ww+X85QYzIcuUYQPYnyPjscF+boG726XiYxMPsUkfIHKk6tbDycwCk46lGc +y4EZ3xK7VDzAbnuwVNeCUrwglf8yOWawrJL7mpOVxNjdDvJjAoIBAQDEXY6TI5bY +Zwmb87hJ52a4V8KAQ4EDUokcI+vXbL27osF+uqOSOQbJ1PQUa2hIWsKH8WgvJoPH +kqfTmFeVSc+DDvT1aZdMj48NOqk3zgRo9or3od+bR71Cf7bEZvi4i2puw7RWr3xa +pIKZoHt6lFXf4xLd2nzfjmMAbMJAWXxgLkfKD3asumiI3j3ld8o+AzDcFsSKXatI +wJ4Mg9MMmQk/KKkmG75GjAfn40MVg5CgPybfQbQxwlZeKOMwMBRWOJn1+IQpWOb9 +62aAGPLkwivLOiud6cfwjD2q8nNS6lXvLCPceSaeWJvEvNrdoMWNA/MzwNXLS+Yh +hcqvR2XoYgJRAoIBACvgBhxmWBgjVHP17Jfb+jS7kAC+kz1mrIDFHkxRuSrXEVyF +alTKY1jmlx/QlVDr8+m7Hpa+vBQaYfAmO85RQm3uVc84GHOsQNlWNlOcFnGA/4ru +xOtQaHuA+4QmA3ctGudCqT6+YWfEe6bHEVzp77nArVWrS3QwYOK+02KBTscNQqGf +Btp/WxqFBHbwIxCq8BKaldzc/uFi1Cl32jvKdRa+ik+kmTQbmhQ8OS2PAEEI0ba1 +LGEtuFKeM0URZ2Lt+f12fw7D/yR4jog9nzXvHgJKQDzM9DgATLLrxP5q/MO2OCXt ++ya4lihJs2S7O9dDWd34soAHZ/4yqHpq+767IQsCggEAQQTJZKbwF49meyDj8HSS +ao+Ec3vmh/cYNx0dxiLXX/2wHAoohw4i1UmR2AEIcoy6xNCGMraKA9bngwR6W5Ap +Cbg2G9xuoIcYUsUNqtCoXSjlMsGCjKPgYthu5/FAgbqH700VtW49urWmGMAuopPj +K1LAuHzTxCIdXdKlLzFyIVaxppIgNWkzm74auJRFfusHjphrU3VYdapxqqsrgoxZ +p3QLLfcZtbpAE+QIHmOFy8mdUWcsBx3WAy9+qkIBOdtb/zneaOJq+cCsG9Ym9t/k +KFKGhq8V6OxGrwfAb7/v3FW9Og9TXjLwwN/XiHLndp3MNWKwZ7Ql6wul5Qu7DosF +QQKCAQEAwDBs6X6vQyDm0TRqTT3LKzRKlJJCsbK6GFdR5ajpuYWVIZzUqO3vwH5z +EJFTJpszMZYSrAUUQcz2eXH5SE3RUqxt4vJaFkHdrYkii4j1FQ+r5LdaJD0X5YAf +slOSYAewRDEdlK7JqYP3eoF52IHTZP0D0jCZk11RmIvAyfFl/pX+hhsM1CF9OvHf +Cn8caCqR3SIEQbUy9gdFy31QxrI/dkQlRfaCYEJvyzQokr71Cx3AXVxbCw7PIzi5 +dLpTKG4SLlrZTFZ/BLy9LA1YGc1te7l24ZhzMNKS8GgddChrIevDp+TP16zQKbEK +qqfqr7WW//8zsvF1dICf4dFl6UriKQ== +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/storage/oauth-public.key b/storage/oauth-public.key new file mode 100644 index 0000000..c09f057 --- /dev/null +++ b/storage/oauth-public.key @@ -0,0 +1,14 @@ +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmwIpZfHfluAdiKlB38T6 +MNA7S394PuXDEw52Vzk5DabhK1RKwa+ELN2bKSS+MmlqJwTwmDTVBC6A/1/lIbUW +CteLh+cCzTCa1nD1W4yYIEFGkt/A9zpx9fKxyFxK1ob1vyxVWh+lfEcBw69Bw1EG +A2JaRWGMcggxnboX6OkqxBS47mYKg596lWB59fZut/JmmT0jNThvvezAc60Wo4Ou +uR7m5rE2tu7ibBNXkp+aaa1v1FhgwivQqsXAHofnFC1AorI6GK+BGe0Bhk/59CCS +u6eVwFseN5GWw8LGTokmUwJXxHsYS+1f7Y+kZYogJA6M0r5QUTp37ovo/4zi1AfN +d+HCXE8Vp2s+tCg45g4N6ZINFHsFv5DelE8ptoqb84AcjZvvjkHReSWvgvYkgBrk +zeYI1oxlQC448ueiItfUxLLu4jVK5xOICyUcj5/BcjSSQU7oJGAzKIOv4gPaIPFP +Ct9H04bMytkeKkTI4uBsMa6F/7lZvnnnIw1KZIm6GYfUz4vdRcOCW0vg73fzfyYP +C0Dp5QyPWs1jQmG68TQu6G5qAXp9jxFBUkx29YCezGAnRLNfeP+zLeyTxt751OeE +kPDLakMamjPm/5DVSpaFDju+RfqiCyt8cETfA7Ws1NA0CsoNM/uMCpkIZ4C47XXR +rDByIEMltXKQ7RM7yZGFd1MCAwEAAQ== +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/storage/packages/.gitignore b/storage/packages/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/packages/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/textures/002b2742acd9c3373baf6729bd2e0f7e9d6558f5c5cb4f080be7a66e4af138bf b/storage/textures/002b2742acd9c3373baf6729bd2e0f7e9d6558f5c5cb4f080be7a66e4af138bf new file mode 100644 index 0000000..f57e807 Binary files /dev/null and b/storage/textures/002b2742acd9c3373baf6729bd2e0f7e9d6558f5c5cb4f080be7a66e4af138bf differ diff --git a/storage/textures/00a6a6ae5d5df005519c936f2584eda1a1493c36460b7bd3c82974ea6ec6d017 b/storage/textures/00a6a6ae5d5df005519c936f2584eda1a1493c36460b7bd3c82974ea6ec6d017 new file mode 100755 index 0000000..0bad269 Binary files /dev/null and b/storage/textures/00a6a6ae5d5df005519c936f2584eda1a1493c36460b7bd3c82974ea6ec6d017 differ diff --git a/storage/textures/00ebfdd0c10d53e6230a6ca03210ebd63db076e52e13ac381038fe0bcde5eacd b/storage/textures/00ebfdd0c10d53e6230a6ca03210ebd63db076e52e13ac381038fe0bcde5eacd new file mode 100755 index 0000000..e6bd839 Binary files /dev/null and b/storage/textures/00ebfdd0c10d53e6230a6ca03210ebd63db076e52e13ac381038fe0bcde5eacd differ diff --git a/storage/textures/010bfeae54f680f0ba419e11c7001519b7aad9f380805145011cac0ea6991b16 b/storage/textures/010bfeae54f680f0ba419e11c7001519b7aad9f380805145011cac0ea6991b16 new file mode 100755 index 0000000..3d89dee Binary files /dev/null and b/storage/textures/010bfeae54f680f0ba419e11c7001519b7aad9f380805145011cac0ea6991b16 differ diff --git a/storage/textures/014ded4d3cc27980ffc5ddb7b8594890d808847f5cb96f5dc93c290c69f9274a b/storage/textures/014ded4d3cc27980ffc5ddb7b8594890d808847f5cb96f5dc93c290c69f9274a new file mode 100755 index 0000000..79003dd Binary files /dev/null and b/storage/textures/014ded4d3cc27980ffc5ddb7b8594890d808847f5cb96f5dc93c290c69f9274a differ diff --git a/storage/textures/016713d7a7175b2ba242bce13c935d5af8759801ca7832392c01d5e02a22303c b/storage/textures/016713d7a7175b2ba242bce13c935d5af8759801ca7832392c01d5e02a22303c new file mode 100755 index 0000000..a8790d5 Binary files /dev/null and b/storage/textures/016713d7a7175b2ba242bce13c935d5af8759801ca7832392c01d5e02a22303c differ diff --git a/storage/textures/01bf5097d4488db270a5ccb34d48c436b7dacccbbc645ca9130df33cfd212fc1 b/storage/textures/01bf5097d4488db270a5ccb34d48c436b7dacccbbc645ca9130df33cfd212fc1 new file mode 100755 index 0000000..87a5a65 Binary files /dev/null and b/storage/textures/01bf5097d4488db270a5ccb34d48c436b7dacccbbc645ca9130df33cfd212fc1 differ diff --git a/storage/textures/01d360a9b090fbeb240bfbdf1654cd7c2e3cd25e062fe9973532805eea7f4084 b/storage/textures/01d360a9b090fbeb240bfbdf1654cd7c2e3cd25e062fe9973532805eea7f4084 new file mode 100644 index 0000000..be54eb5 Binary files /dev/null and b/storage/textures/01d360a9b090fbeb240bfbdf1654cd7c2e3cd25e062fe9973532805eea7f4084 differ diff --git a/storage/textures/0243eb7a6d252e63f50a409d9866fce329b4f50dab21737bc277e3f4aaa47939 b/storage/textures/0243eb7a6d252e63f50a409d9866fce329b4f50dab21737bc277e3f4aaa47939 new file mode 100644 index 0000000..af0fcfc Binary files /dev/null and b/storage/textures/0243eb7a6d252e63f50a409d9866fce329b4f50dab21737bc277e3f4aaa47939 differ diff --git a/storage/textures/026a190f0a34a659433b6e102d76f7408ea7c7628088985af9c0ed5733d4a323 b/storage/textures/026a190f0a34a659433b6e102d76f7408ea7c7628088985af9c0ed5733d4a323 new file mode 100755 index 0000000..7c6406c Binary files /dev/null and b/storage/textures/026a190f0a34a659433b6e102d76f7408ea7c7628088985af9c0ed5733d4a323 differ diff --git a/storage/textures/027d07e12c36fd74a96e6e61cbda883ee4b30e206c9f105582024aae29a89da7 b/storage/textures/027d07e12c36fd74a96e6e61cbda883ee4b30e206c9f105582024aae29a89da7 new file mode 100644 index 0000000..2f6ee4c Binary files /dev/null and b/storage/textures/027d07e12c36fd74a96e6e61cbda883ee4b30e206c9f105582024aae29a89da7 differ diff --git a/storage/textures/02800b07f53889afc093bc015e324318f0351bf2c185f5e06de979282b929054 b/storage/textures/02800b07f53889afc093bc015e324318f0351bf2c185f5e06de979282b929054 new file mode 100755 index 0000000..cf338a0 Binary files /dev/null and b/storage/textures/02800b07f53889afc093bc015e324318f0351bf2c185f5e06de979282b929054 differ diff --git a/storage/textures/02811870e3ab52abeddc1e318f53d8876f256a15dfd79bd117cb461c3c256dcc b/storage/textures/02811870e3ab52abeddc1e318f53d8876f256a15dfd79bd117cb461c3c256dcc new file mode 100755 index 0000000..3da92d4 Binary files /dev/null and b/storage/textures/02811870e3ab52abeddc1e318f53d8876f256a15dfd79bd117cb461c3c256dcc differ diff --git a/storage/textures/028f5240c06f363eca97beca07c3681c65380997901338a24692c1ed70940500 b/storage/textures/028f5240c06f363eca97beca07c3681c65380997901338a24692c1ed70940500 new file mode 100644 index 0000000..fcc99e6 Binary files /dev/null and b/storage/textures/028f5240c06f363eca97beca07c3681c65380997901338a24692c1ed70940500 differ diff --git a/storage/textures/02e8c4f29e4c4eab71def1267b71af2d6a4bf83a6649852a068115832225c626 b/storage/textures/02e8c4f29e4c4eab71def1267b71af2d6a4bf83a6649852a068115832225c626 new file mode 100644 index 0000000..8960318 Binary files /dev/null and b/storage/textures/02e8c4f29e4c4eab71def1267b71af2d6a4bf83a6649852a068115832225c626 differ diff --git a/storage/textures/02efbd6de9cd663f94e6ffcbb1522a93b04e27eaf20f66fc7929696220e008ce b/storage/textures/02efbd6de9cd663f94e6ffcbb1522a93b04e27eaf20f66fc7929696220e008ce new file mode 100755 index 0000000..a6e65c3 Binary files /dev/null and b/storage/textures/02efbd6de9cd663f94e6ffcbb1522a93b04e27eaf20f66fc7929696220e008ce differ diff --git a/storage/textures/0333eceea8248b3b353a196045c71889a414222753bdc142e7e9f89193ea63f7 b/storage/textures/0333eceea8248b3b353a196045c71889a414222753bdc142e7e9f89193ea63f7 new file mode 100644 index 0000000..16f9c14 Binary files /dev/null and b/storage/textures/0333eceea8248b3b353a196045c71889a414222753bdc142e7e9f89193ea63f7 differ diff --git a/storage/textures/033ac63acf35ce26bf89a9a9c448e70c87e99f5c8ddf02313270e9608f7d3341 b/storage/textures/033ac63acf35ce26bf89a9a9c448e70c87e99f5c8ddf02313270e9608f7d3341 new file mode 100644 index 0000000..177a5f8 Binary files /dev/null and b/storage/textures/033ac63acf35ce26bf89a9a9c448e70c87e99f5c8ddf02313270e9608f7d3341 differ diff --git a/storage/textures/0348b7652cd0b160488ee6ac87fee2e6716d3c9619eaa859fde384f5af533a7d b/storage/textures/0348b7652cd0b160488ee6ac87fee2e6716d3c9619eaa859fde384f5af533a7d new file mode 100755 index 0000000..7d4a99d Binary files /dev/null and b/storage/textures/0348b7652cd0b160488ee6ac87fee2e6716d3c9619eaa859fde384f5af533a7d differ diff --git a/storage/textures/035269374dfec607ace5aa392f954ba8fa812de71c05aeb1077f4814a1b3a5a9 b/storage/textures/035269374dfec607ace5aa392f954ba8fa812de71c05aeb1077f4814a1b3a5a9 new file mode 100755 index 0000000..3f697e0 Binary files /dev/null and b/storage/textures/035269374dfec607ace5aa392f954ba8fa812de71c05aeb1077f4814a1b3a5a9 differ diff --git a/storage/textures/037a713782a20c460d4388dde5ba7efadb9231ee2c4f757f693a9f4e56996974 b/storage/textures/037a713782a20c460d4388dde5ba7efadb9231ee2c4f757f693a9f4e56996974 new file mode 100644 index 0000000..e54ff19 Binary files /dev/null and b/storage/textures/037a713782a20c460d4388dde5ba7efadb9231ee2c4f757f693a9f4e56996974 differ diff --git a/storage/textures/0476985e4d1a7b7a51e7eed33a33cfaea1e2348af70d5c70f6837f9c24c80993 b/storage/textures/0476985e4d1a7b7a51e7eed33a33cfaea1e2348af70d5c70f6837f9c24c80993 new file mode 100755 index 0000000..585280c Binary files /dev/null and b/storage/textures/0476985e4d1a7b7a51e7eed33a33cfaea1e2348af70d5c70f6837f9c24c80993 differ diff --git a/storage/textures/04805432a0d1379c2da401ce981c52a8673bf094df97ac65d7acef7ce827c38e b/storage/textures/04805432a0d1379c2da401ce981c52a8673bf094df97ac65d7acef7ce827c38e new file mode 100755 index 0000000..8558f94 Binary files /dev/null and b/storage/textures/04805432a0d1379c2da401ce981c52a8673bf094df97ac65d7acef7ce827c38e differ diff --git a/storage/textures/048b07911be0d87f3158aef78c2891a98f6494a641d473326c7d2e4ee96502db b/storage/textures/048b07911be0d87f3158aef78c2891a98f6494a641d473326c7d2e4ee96502db new file mode 100755 index 0000000..04c07b9 Binary files /dev/null and b/storage/textures/048b07911be0d87f3158aef78c2891a98f6494a641d473326c7d2e4ee96502db differ diff --git a/storage/textures/05671cab4cdeb4ef59aefebc5e5bba11accbc317aba0b7e428434645c5edef79 b/storage/textures/05671cab4cdeb4ef59aefebc5e5bba11accbc317aba0b7e428434645c5edef79 new file mode 100644 index 0000000..69e6146 Binary files /dev/null and b/storage/textures/05671cab4cdeb4ef59aefebc5e5bba11accbc317aba0b7e428434645c5edef79 differ diff --git a/storage/textures/0575cb6e148869281b24d3f0aaa37391519698a528236ea7b143ee8f9b3c055b b/storage/textures/0575cb6e148869281b24d3f0aaa37391519698a528236ea7b143ee8f9b3c055b new file mode 100755 index 0000000..32c69df Binary files /dev/null and b/storage/textures/0575cb6e148869281b24d3f0aaa37391519698a528236ea7b143ee8f9b3c055b differ diff --git a/storage/textures/0582da9b2714a5b3a45afee00e300e0317c5bab60e3b0ea1ee14bb4bfe6cc37e b/storage/textures/0582da9b2714a5b3a45afee00e300e0317c5bab60e3b0ea1ee14bb4bfe6cc37e new file mode 100755 index 0000000..f94770b Binary files /dev/null and b/storage/textures/0582da9b2714a5b3a45afee00e300e0317c5bab60e3b0ea1ee14bb4bfe6cc37e differ diff --git a/storage/textures/05a0d68dabaee4518b4712ee1434a9533387d2e0707c826d87f2ae8dcb36e4e5 b/storage/textures/05a0d68dabaee4518b4712ee1434a9533387d2e0707c826d87f2ae8dcb36e4e5 new file mode 100755 index 0000000..bd4b8c7 Binary files /dev/null and b/storage/textures/05a0d68dabaee4518b4712ee1434a9533387d2e0707c826d87f2ae8dcb36e4e5 differ diff --git a/storage/textures/05e107cdd2c5ca602b02a8a70d020a7c85f8a5f99265bfee8b635b7848a706fd b/storage/textures/05e107cdd2c5ca602b02a8a70d020a7c85f8a5f99265bfee8b635b7848a706fd new file mode 100755 index 0000000..d4bd497 Binary files /dev/null and b/storage/textures/05e107cdd2c5ca602b02a8a70d020a7c85f8a5f99265bfee8b635b7848a706fd differ diff --git a/storage/textures/05ef447ea589be59fab6237621ae97b419a73c4b309c1d94491a331db112c204 b/storage/textures/05ef447ea589be59fab6237621ae97b419a73c4b309c1d94491a331db112c204 new file mode 100755 index 0000000..3276fb7 Binary files /dev/null and b/storage/textures/05ef447ea589be59fab6237621ae97b419a73c4b309c1d94491a331db112c204 differ diff --git a/storage/textures/0628d222efda662998a7f05aab6adc9ffc9b54bd77a2a25c93c678ba8ebcf14f b/storage/textures/0628d222efda662998a7f05aab6adc9ffc9b54bd77a2a25c93c678ba8ebcf14f new file mode 100644 index 0000000..fe47455 Binary files /dev/null and b/storage/textures/0628d222efda662998a7f05aab6adc9ffc9b54bd77a2a25c93c678ba8ebcf14f differ diff --git a/storage/textures/0642b3370243cdac7d6abb5245288551ac70ee24a474a8b86a97028a50563cda b/storage/textures/0642b3370243cdac7d6abb5245288551ac70ee24a474a8b86a97028a50563cda new file mode 100755 index 0000000..570b463 Binary files /dev/null and b/storage/textures/0642b3370243cdac7d6abb5245288551ac70ee24a474a8b86a97028a50563cda differ diff --git a/storage/textures/0682f553140fdb17a61902526b738d3e54569f2faedf0f760c28b745fdd043f6 b/storage/textures/0682f553140fdb17a61902526b738d3e54569f2faedf0f760c28b745fdd043f6 new file mode 100755 index 0000000..6b49233 Binary files /dev/null and b/storage/textures/0682f553140fdb17a61902526b738d3e54569f2faedf0f760c28b745fdd043f6 differ diff --git a/storage/textures/0693a46e8c8a926d71c6a2f7da929610afea95b4c5cb718524a73ec216ae213a b/storage/textures/0693a46e8c8a926d71c6a2f7da929610afea95b4c5cb718524a73ec216ae213a new file mode 100755 index 0000000..5a372f8 Binary files /dev/null and b/storage/textures/0693a46e8c8a926d71c6a2f7da929610afea95b4c5cb718524a73ec216ae213a differ diff --git a/storage/textures/069d93c6dcfc353fbbeb70be0cd9701e2e4f005fe30f3f4757afe7904a2bcb0b b/storage/textures/069d93c6dcfc353fbbeb70be0cd9701e2e4f005fe30f3f4757afe7904a2bcb0b new file mode 100755 index 0000000..766c7ad Binary files /dev/null and b/storage/textures/069d93c6dcfc353fbbeb70be0cd9701e2e4f005fe30f3f4757afe7904a2bcb0b differ diff --git a/storage/textures/0746f56971dedd6de69c3075fd1e4226538e9eb7b2464a18c57190be200a86fc b/storage/textures/0746f56971dedd6de69c3075fd1e4226538e9eb7b2464a18c57190be200a86fc new file mode 100755 index 0000000..9d388aa Binary files /dev/null and b/storage/textures/0746f56971dedd6de69c3075fd1e4226538e9eb7b2464a18c57190be200a86fc differ diff --git a/storage/textures/074f2b41a784b7a1ced3926897954218b322b1ce2442ca1391b26f7d0387d63f b/storage/textures/074f2b41a784b7a1ced3926897954218b322b1ce2442ca1391b26f7d0387d63f new file mode 100644 index 0000000..1c19750 Binary files /dev/null and b/storage/textures/074f2b41a784b7a1ced3926897954218b322b1ce2442ca1391b26f7d0387d63f differ diff --git a/storage/textures/079f6e741bc5503bcfef525659b6d19413935b418e796f4155d8e989e67279be b/storage/textures/079f6e741bc5503bcfef525659b6d19413935b418e796f4155d8e989e67279be new file mode 100755 index 0000000..3209f0a Binary files /dev/null and b/storage/textures/079f6e741bc5503bcfef525659b6d19413935b418e796f4155d8e989e67279be differ diff --git a/storage/textures/0805d9510e3b4fc1a92e90348158aa699309dea1dfddab3b5ac4485e7a14fcba b/storage/textures/0805d9510e3b4fc1a92e90348158aa699309dea1dfddab3b5ac4485e7a14fcba new file mode 100755 index 0000000..428f16e Binary files /dev/null and b/storage/textures/0805d9510e3b4fc1a92e90348158aa699309dea1dfddab3b5ac4485e7a14fcba differ diff --git a/storage/textures/087137f8c7e7bc05745b532e902a7c44f7e604d02ae1bf07d4d953520b6b2890 b/storage/textures/087137f8c7e7bc05745b532e902a7c44f7e604d02ae1bf07d4d953520b6b2890 new file mode 100755 index 0000000..b1b8928 Binary files /dev/null and b/storage/textures/087137f8c7e7bc05745b532e902a7c44f7e604d02ae1bf07d4d953520b6b2890 differ diff --git a/storage/textures/089b2b379dc8920b4237c4b87b46a6083c792f20ca565c40a851a879416593e2 b/storage/textures/089b2b379dc8920b4237c4b87b46a6083c792f20ca565c40a851a879416593e2 new file mode 100755 index 0000000..443eebb Binary files /dev/null and b/storage/textures/089b2b379dc8920b4237c4b87b46a6083c792f20ca565c40a851a879416593e2 differ diff --git a/storage/textures/09020ac6f9276aa7a0b93596f4fec2a69af41221030558a71520142cceb3cef0 b/storage/textures/09020ac6f9276aa7a0b93596f4fec2a69af41221030558a71520142cceb3cef0 new file mode 100755 index 0000000..04b947a Binary files /dev/null and b/storage/textures/09020ac6f9276aa7a0b93596f4fec2a69af41221030558a71520142cceb3cef0 differ diff --git a/storage/textures/092d6443632a2740ddec6dd0a25d988b3b4c496e5bd880fc038da3086f3fc05e b/storage/textures/092d6443632a2740ddec6dd0a25d988b3b4c496e5bd880fc038da3086f3fc05e new file mode 100644 index 0000000..94d5b9e Binary files /dev/null and b/storage/textures/092d6443632a2740ddec6dd0a25d988b3b4c496e5bd880fc038da3086f3fc05e differ diff --git a/storage/textures/0976e775c1b8120920ab50a0b65c75c6847688a3f3e31dee837f6841b3dfd2f2 b/storage/textures/0976e775c1b8120920ab50a0b65c75c6847688a3f3e31dee837f6841b3dfd2f2 new file mode 100755 index 0000000..2d86647 Binary files /dev/null and b/storage/textures/0976e775c1b8120920ab50a0b65c75c6847688a3f3e31dee837f6841b3dfd2f2 differ diff --git a/storage/textures/09a912c2e78fb39ef44d8b74ad66544305fad1fc2ae5aa2158dc470f734a5c65 b/storage/textures/09a912c2e78fb39ef44d8b74ad66544305fad1fc2ae5aa2158dc470f734a5c65 new file mode 100755 index 0000000..4897d7b Binary files /dev/null and b/storage/textures/09a912c2e78fb39ef44d8b74ad66544305fad1fc2ae5aa2158dc470f734a5c65 differ diff --git a/storage/textures/09d512397104da7152626642604fa7dce69cc9f6dae8f728805e1cbe7f2bd145 b/storage/textures/09d512397104da7152626642604fa7dce69cc9f6dae8f728805e1cbe7f2bd145 new file mode 100755 index 0000000..c798840 Binary files /dev/null and b/storage/textures/09d512397104da7152626642604fa7dce69cc9f6dae8f728805e1cbe7f2bd145 differ diff --git a/storage/textures/09e4429237e3ff016c45ee2ce391c57fb0759418f715e09c5c9ce472ae26c024 b/storage/textures/09e4429237e3ff016c45ee2ce391c57fb0759418f715e09c5c9ce472ae26c024 new file mode 100755 index 0000000..979600b Binary files /dev/null and b/storage/textures/09e4429237e3ff016c45ee2ce391c57fb0759418f715e09c5c9ce472ae26c024 differ diff --git a/storage/textures/0a0198ab071c92107e9c61fe58e930d2977682638ff8b9d2764d8964b1b54b0b b/storage/textures/0a0198ab071c92107e9c61fe58e930d2977682638ff8b9d2764d8964b1b54b0b new file mode 100755 index 0000000..5b17c2a Binary files /dev/null and b/storage/textures/0a0198ab071c92107e9c61fe58e930d2977682638ff8b9d2764d8964b1b54b0b differ diff --git a/storage/textures/0a5d89e1533f9b4e7589b2a413bf766593542b90e9a3469ae960d61afe30163b b/storage/textures/0a5d89e1533f9b4e7589b2a413bf766593542b90e9a3469ae960d61afe30163b new file mode 100755 index 0000000..11390b4 Binary files /dev/null and b/storage/textures/0a5d89e1533f9b4e7589b2a413bf766593542b90e9a3469ae960d61afe30163b differ diff --git a/storage/textures/0ae4949fd133a8397d956e69433778befedb28117c71aed3708dd0abaf2f786e b/storage/textures/0ae4949fd133a8397d956e69433778befedb28117c71aed3708dd0abaf2f786e new file mode 100644 index 0000000..6fd4331 Binary files /dev/null and b/storage/textures/0ae4949fd133a8397d956e69433778befedb28117c71aed3708dd0abaf2f786e differ diff --git a/storage/textures/0b0d631f7a842324a93d3c8f09806428d552d1b56872596c6ff8e898b9a58be2 b/storage/textures/0b0d631f7a842324a93d3c8f09806428d552d1b56872596c6ff8e898b9a58be2 new file mode 100644 index 0000000..2b8839b Binary files /dev/null and b/storage/textures/0b0d631f7a842324a93d3c8f09806428d552d1b56872596c6ff8e898b9a58be2 differ diff --git a/storage/textures/0b37e99f474fc2b43c1e453ebcd273b1a0dab562b53430a0bad1b981af62ed5a b/storage/textures/0b37e99f474fc2b43c1e453ebcd273b1a0dab562b53430a0bad1b981af62ed5a new file mode 100755 index 0000000..3f3926c Binary files /dev/null and b/storage/textures/0b37e99f474fc2b43c1e453ebcd273b1a0dab562b53430a0bad1b981af62ed5a differ diff --git a/storage/textures/0b59260989bc5c34f8db7e330ddc32d68daa525a22902b0711eab3b7b87ee331 b/storage/textures/0b59260989bc5c34f8db7e330ddc32d68daa525a22902b0711eab3b7b87ee331 new file mode 100755 index 0000000..2f2e9f7 Binary files /dev/null and b/storage/textures/0b59260989bc5c34f8db7e330ddc32d68daa525a22902b0711eab3b7b87ee331 differ diff --git a/storage/textures/0be4470ca07d94ace62db886c70740f854cfcc158642338bac9dd90e0497bb1a b/storage/textures/0be4470ca07d94ace62db886c70740f854cfcc158642338bac9dd90e0497bb1a new file mode 100644 index 0000000..d0dd991 Binary files /dev/null and b/storage/textures/0be4470ca07d94ace62db886c70740f854cfcc158642338bac9dd90e0497bb1a differ diff --git a/storage/textures/0c341aff1f1a3692f3aedec8a638678fe4a5fd00e2c0ac1de268275a14f40d1b b/storage/textures/0c341aff1f1a3692f3aedec8a638678fe4a5fd00e2c0ac1de268275a14f40d1b new file mode 100755 index 0000000..d5c588a Binary files /dev/null and b/storage/textures/0c341aff1f1a3692f3aedec8a638678fe4a5fd00e2c0ac1de268275a14f40d1b differ diff --git a/storage/textures/0c5d99561980d396e849117534176bf0691c06d3905f2852733ad56980b9973f b/storage/textures/0c5d99561980d396e849117534176bf0691c06d3905f2852733ad56980b9973f new file mode 100644 index 0000000..abb8d01 Binary files /dev/null and b/storage/textures/0c5d99561980d396e849117534176bf0691c06d3905f2852733ad56980b9973f differ diff --git a/storage/textures/0c6832e9acf1c4e373fc1f68d478301f57974105c0ca986612ac176efa67407e b/storage/textures/0c6832e9acf1c4e373fc1f68d478301f57974105c0ca986612ac176efa67407e new file mode 100755 index 0000000..8e2d3ae Binary files /dev/null and b/storage/textures/0c6832e9acf1c4e373fc1f68d478301f57974105c0ca986612ac176efa67407e differ diff --git a/storage/textures/0c8d3843f7bb24028012c03c36a218f6a9015338ad68ae8bb4577a5651e5baf2 b/storage/textures/0c8d3843f7bb24028012c03c36a218f6a9015338ad68ae8bb4577a5651e5baf2 new file mode 100755 index 0000000..3e9a5e8 Binary files /dev/null and b/storage/textures/0c8d3843f7bb24028012c03c36a218f6a9015338ad68ae8bb4577a5651e5baf2 differ diff --git a/storage/textures/0ccc223b8f23b6e6b6fe249b1a76abc2512e8313d2e3146fa889c2486dbc1df4 b/storage/textures/0ccc223b8f23b6e6b6fe249b1a76abc2512e8313d2e3146fa889c2486dbc1df4 new file mode 100755 index 0000000..bcc9aa7 Binary files /dev/null and b/storage/textures/0ccc223b8f23b6e6b6fe249b1a76abc2512e8313d2e3146fa889c2486dbc1df4 differ diff --git a/storage/textures/0cd52f503e38e4b835aea7c8cd6f9a1034f8be85c6ee35b6626fd0bfd0a3943e b/storage/textures/0cd52f503e38e4b835aea7c8cd6f9a1034f8be85c6ee35b6626fd0bfd0a3943e new file mode 100755 index 0000000..822d30b Binary files /dev/null and b/storage/textures/0cd52f503e38e4b835aea7c8cd6f9a1034f8be85c6ee35b6626fd0bfd0a3943e differ diff --git a/storage/textures/0cebe750e23a754036f7f85a7cbabcf078d631be5fd264113d6fc54d1ec63b4c b/storage/textures/0cebe750e23a754036f7f85a7cbabcf078d631be5fd264113d6fc54d1ec63b4c new file mode 100755 index 0000000..c82b05c Binary files /dev/null and b/storage/textures/0cebe750e23a754036f7f85a7cbabcf078d631be5fd264113d6fc54d1ec63b4c differ diff --git a/storage/textures/0d273b9907070aada0d3df80b89ecc2e76ea2b8411dff79d7f4fd3350ced7735 b/storage/textures/0d273b9907070aada0d3df80b89ecc2e76ea2b8411dff79d7f4fd3350ced7735 new file mode 100755 index 0000000..b348e5d Binary files /dev/null and b/storage/textures/0d273b9907070aada0d3df80b89ecc2e76ea2b8411dff79d7f4fd3350ced7735 differ diff --git a/storage/textures/0d51f77893b5a4ea94ec303ea0c1b8c27815c37b0bf346e4c3071e3dd2d28555 b/storage/textures/0d51f77893b5a4ea94ec303ea0c1b8c27815c37b0bf346e4c3071e3dd2d28555 new file mode 100755 index 0000000..6cb7a31 Binary files /dev/null and b/storage/textures/0d51f77893b5a4ea94ec303ea0c1b8c27815c37b0bf346e4c3071e3dd2d28555 differ diff --git a/storage/textures/0d7434430c395d562a5df9d9ce79f8cdfda5c11ac493fa65147e318a5d79fbff b/storage/textures/0d7434430c395d562a5df9d9ce79f8cdfda5c11ac493fa65147e318a5d79fbff new file mode 100644 index 0000000..76712d3 Binary files /dev/null and b/storage/textures/0d7434430c395d562a5df9d9ce79f8cdfda5c11ac493fa65147e318a5d79fbff differ diff --git a/storage/textures/0da3d767070334286f48704fc3c4730ccdda9c189cf8a2207c36da287526c643 b/storage/textures/0da3d767070334286f48704fc3c4730ccdda9c189cf8a2207c36da287526c643 new file mode 100755 index 0000000..1181038 Binary files /dev/null and b/storage/textures/0da3d767070334286f48704fc3c4730ccdda9c189cf8a2207c36da287526c643 differ diff --git a/storage/textures/0da5cb24e7b85fbb8ca13ad5a54e32ef7db38ae0c8fa6ef833247c4585c40cf5 b/storage/textures/0da5cb24e7b85fbb8ca13ad5a54e32ef7db38ae0c8fa6ef833247c4585c40cf5 new file mode 100755 index 0000000..379276f Binary files /dev/null and b/storage/textures/0da5cb24e7b85fbb8ca13ad5a54e32ef7db38ae0c8fa6ef833247c4585c40cf5 differ diff --git a/storage/textures/0dca4033539adae6b317d54ec6380cdd213697ac39200532e5d8fb330be73bc6 b/storage/textures/0dca4033539adae6b317d54ec6380cdd213697ac39200532e5d8fb330be73bc6 new file mode 100644 index 0000000..1db1bfa Binary files /dev/null and b/storage/textures/0dca4033539adae6b317d54ec6380cdd213697ac39200532e5d8fb330be73bc6 differ diff --git a/storage/textures/0e3913f7c56dbec0b86395b5847be684d54e7a4231905c21c6c54a1fbe9c3b4f b/storage/textures/0e3913f7c56dbec0b86395b5847be684d54e7a4231905c21c6c54a1fbe9c3b4f new file mode 100644 index 0000000..ab29395 Binary files /dev/null and b/storage/textures/0e3913f7c56dbec0b86395b5847be684d54e7a4231905c21c6c54a1fbe9c3b4f differ diff --git a/storage/textures/0e563565450cf4017636601b66e6023d8cf2aa29ebb2ebec7cee43d84900a2cc b/storage/textures/0e563565450cf4017636601b66e6023d8cf2aa29ebb2ebec7cee43d84900a2cc new file mode 100755 index 0000000..53bc7fd Binary files /dev/null and b/storage/textures/0e563565450cf4017636601b66e6023d8cf2aa29ebb2ebec7cee43d84900a2cc differ diff --git a/storage/textures/0ea7b38d823015330076b8f19ffde7164976b3a2e3262f0ff3fc7951a4c6f6ac b/storage/textures/0ea7b38d823015330076b8f19ffde7164976b3a2e3262f0ff3fc7951a4c6f6ac new file mode 100755 index 0000000..2425e86 Binary files /dev/null and b/storage/textures/0ea7b38d823015330076b8f19ffde7164976b3a2e3262f0ff3fc7951a4c6f6ac differ diff --git a/storage/textures/0f0454ea03ca893efc662e357694255fbb8471a0d1608d0f3c286e8c37d40154 b/storage/textures/0f0454ea03ca893efc662e357694255fbb8471a0d1608d0f3c286e8c37d40154 new file mode 100755 index 0000000..354c6bc Binary files /dev/null and b/storage/textures/0f0454ea03ca893efc662e357694255fbb8471a0d1608d0f3c286e8c37d40154 differ diff --git a/storage/textures/0f82858096ef5338c6610d0b1d65c678f0656985599aca474593c7ff64a221d6 b/storage/textures/0f82858096ef5338c6610d0b1d65c678f0656985599aca474593c7ff64a221d6 new file mode 100755 index 0000000..0da62df Binary files /dev/null and b/storage/textures/0f82858096ef5338c6610d0b1d65c678f0656985599aca474593c7ff64a221d6 differ diff --git a/storage/textures/101d536bf891e7b99e9ed461c2c69dfcabdca11b67d91050cdf1355894258888 b/storage/textures/101d536bf891e7b99e9ed461c2c69dfcabdca11b67d91050cdf1355894258888 new file mode 100755 index 0000000..360dd5c Binary files /dev/null and b/storage/textures/101d536bf891e7b99e9ed461c2c69dfcabdca11b67d91050cdf1355894258888 differ diff --git a/storage/textures/1025a2d1b04518859a81ba198c8ee881310fe4f2b0c986bbcb772043f131c871 b/storage/textures/1025a2d1b04518859a81ba198c8ee881310fe4f2b0c986bbcb772043f131c871 new file mode 100755 index 0000000..61d9801 Binary files /dev/null and b/storage/textures/1025a2d1b04518859a81ba198c8ee881310fe4f2b0c986bbcb772043f131c871 differ diff --git a/storage/textures/10477cb3a22ba4fb17f4bb6f55e549bf233d92601ce3348a27a4e6469cd38c55 b/storage/textures/10477cb3a22ba4fb17f4bb6f55e549bf233d92601ce3348a27a4e6469cd38c55 new file mode 100644 index 0000000..049a54c Binary files /dev/null and b/storage/textures/10477cb3a22ba4fb17f4bb6f55e549bf233d92601ce3348a27a4e6469cd38c55 differ diff --git a/storage/textures/10936c8e8ff4847b43cb004e47096276df7a91aa150c265f912f4f16fd421edb b/storage/textures/10936c8e8ff4847b43cb004e47096276df7a91aa150c265f912f4f16fd421edb new file mode 100755 index 0000000..a294ea4 Binary files /dev/null and b/storage/textures/10936c8e8ff4847b43cb004e47096276df7a91aa150c265f912f4f16fd421edb differ diff --git a/storage/textures/109bd69e6a515a31e431f7ef15c1d57c9e5f62e14b9bfd0d6796bb5059e366a7 b/storage/textures/109bd69e6a515a31e431f7ef15c1d57c9e5f62e14b9bfd0d6796bb5059e366a7 new file mode 100755 index 0000000..04c0781 Binary files /dev/null and b/storage/textures/109bd69e6a515a31e431f7ef15c1d57c9e5f62e14b9bfd0d6796bb5059e366a7 differ diff --git a/storage/textures/10a688a49f3e7e6d29614b758cf6ea3a140c82caa608bd351227da60141536dd b/storage/textures/10a688a49f3e7e6d29614b758cf6ea3a140c82caa608bd351227da60141536dd new file mode 100644 index 0000000..e752356 Binary files /dev/null and b/storage/textures/10a688a49f3e7e6d29614b758cf6ea3a140c82caa608bd351227da60141536dd differ diff --git a/storage/textures/10d9d00371970a13bf96a21b382fa17551f73562e01e098fed2744b854b7628e b/storage/textures/10d9d00371970a13bf96a21b382fa17551f73562e01e098fed2744b854b7628e new file mode 100755 index 0000000..401436b Binary files /dev/null and b/storage/textures/10d9d00371970a13bf96a21b382fa17551f73562e01e098fed2744b854b7628e differ diff --git a/storage/textures/10da57679854edb46c5b6bbbe9d95aaed6a65f629adba7f8a33aba6ed1b5f53f b/storage/textures/10da57679854edb46c5b6bbbe9d95aaed6a65f629adba7f8a33aba6ed1b5f53f new file mode 100755 index 0000000..5985304 Binary files /dev/null and b/storage/textures/10da57679854edb46c5b6bbbe9d95aaed6a65f629adba7f8a33aba6ed1b5f53f differ diff --git a/storage/textures/10f3cab257ebdfb33ae7002fdf7136421b688c2459f89104310d039e2b6e5866 b/storage/textures/10f3cab257ebdfb33ae7002fdf7136421b688c2459f89104310d039e2b6e5866 new file mode 100755 index 0000000..ed7c597 Binary files /dev/null and b/storage/textures/10f3cab257ebdfb33ae7002fdf7136421b688c2459f89104310d039e2b6e5866 differ diff --git a/storage/textures/113b7a9ea57ed5104172ca8c0ea1397edcff4f7335b4dc1689ce9771288dbccc b/storage/textures/113b7a9ea57ed5104172ca8c0ea1397edcff4f7335b4dc1689ce9771288dbccc new file mode 100755 index 0000000..d6dcec0 Binary files /dev/null and b/storage/textures/113b7a9ea57ed5104172ca8c0ea1397edcff4f7335b4dc1689ce9771288dbccc differ diff --git a/storage/textures/11acef957da4a553b8f1c7e08c22f1df4db051e440dba292711c829cad784a1e b/storage/textures/11acef957da4a553b8f1c7e08c22f1df4db051e440dba292711c829cad784a1e new file mode 100755 index 0000000..45cbbac Binary files /dev/null and b/storage/textures/11acef957da4a553b8f1c7e08c22f1df4db051e440dba292711c829cad784a1e differ diff --git a/storage/textures/11debc146cb17722d342f9c455bb32273f490ca0a89dda4e99d65481b6e817d4 b/storage/textures/11debc146cb17722d342f9c455bb32273f490ca0a89dda4e99d65481b6e817d4 new file mode 100644 index 0000000..76e64ef Binary files /dev/null and b/storage/textures/11debc146cb17722d342f9c455bb32273f490ca0a89dda4e99d65481b6e817d4 differ diff --git a/storage/textures/122eb16b5d7e2744eeadadb879dfc2b1c8dbefd0f3875b137a7efb9bcd589b66 b/storage/textures/122eb16b5d7e2744eeadadb879dfc2b1c8dbefd0f3875b137a7efb9bcd589b66 new file mode 100755 index 0000000..456c666 Binary files /dev/null and b/storage/textures/122eb16b5d7e2744eeadadb879dfc2b1c8dbefd0f3875b137a7efb9bcd589b66 differ diff --git a/storage/textures/125c11d4cf8ca5a72d05fb29fe9cc4f312ff7b92e6fac4a14f47e806cb442b11 b/storage/textures/125c11d4cf8ca5a72d05fb29fe9cc4f312ff7b92e6fac4a14f47e806cb442b11 new file mode 100755 index 0000000..8f5a479 Binary files /dev/null and b/storage/textures/125c11d4cf8ca5a72d05fb29fe9cc4f312ff7b92e6fac4a14f47e806cb442b11 differ diff --git a/storage/textures/12cd35fd266e57d79c800f43fd982a8666ad4dfbd890d30a16949d6fc355755c b/storage/textures/12cd35fd266e57d79c800f43fd982a8666ad4dfbd890d30a16949d6fc355755c new file mode 100644 index 0000000..beb348d Binary files /dev/null and b/storage/textures/12cd35fd266e57d79c800f43fd982a8666ad4dfbd890d30a16949d6fc355755c differ diff --git a/storage/textures/12fd41eb93a16d492c6631ac375bf8178d9d9f001913f75b4f54d94efbf07cba b/storage/textures/12fd41eb93a16d492c6631ac375bf8178d9d9f001913f75b4f54d94efbf07cba new file mode 100644 index 0000000..c01f2a9 Binary files /dev/null and b/storage/textures/12fd41eb93a16d492c6631ac375bf8178d9d9f001913f75b4f54d94efbf07cba differ diff --git a/storage/textures/1341734d15b90f196f76156b4a870b7ab39891f19b1208cf6223dd4c1a568b4b b/storage/textures/1341734d15b90f196f76156b4a870b7ab39891f19b1208cf6223dd4c1a568b4b new file mode 100644 index 0000000..542ddad Binary files /dev/null and b/storage/textures/1341734d15b90f196f76156b4a870b7ab39891f19b1208cf6223dd4c1a568b4b differ diff --git a/storage/textures/1366cfe0da3d6e1743793f4dd04731079b770aa99e23183d483117ccf62db54b b/storage/textures/1366cfe0da3d6e1743793f4dd04731079b770aa99e23183d483117ccf62db54b new file mode 100755 index 0000000..085150a Binary files /dev/null and b/storage/textures/1366cfe0da3d6e1743793f4dd04731079b770aa99e23183d483117ccf62db54b differ diff --git a/storage/textures/13eb2e22739918aca0c973f0f967d9e554a8446fa323e43fc262edaf80e00824 b/storage/textures/13eb2e22739918aca0c973f0f967d9e554a8446fa323e43fc262edaf80e00824 new file mode 100644 index 0000000..959de5c Binary files /dev/null and b/storage/textures/13eb2e22739918aca0c973f0f967d9e554a8446fa323e43fc262edaf80e00824 differ diff --git a/storage/textures/140ac6443bd5d9ac1818fb8240c1faf6ae32dca16186d55648675eadb5b3530b b/storage/textures/140ac6443bd5d9ac1818fb8240c1faf6ae32dca16186d55648675eadb5b3530b new file mode 100755 index 0000000..56c4f68 Binary files /dev/null and b/storage/textures/140ac6443bd5d9ac1818fb8240c1faf6ae32dca16186d55648675eadb5b3530b differ diff --git a/storage/textures/147a88e5b379a82e9f32778b46b29126b3a121bb45bfaab3934d57d555dc0d00 b/storage/textures/147a88e5b379a82e9f32778b46b29126b3a121bb45bfaab3934d57d555dc0d00 new file mode 100755 index 0000000..d2cc9d0 Binary files /dev/null and b/storage/textures/147a88e5b379a82e9f32778b46b29126b3a121bb45bfaab3934d57d555dc0d00 differ diff --git a/storage/textures/14afe82f520a4fab0bee3b1c7a9b5aa2f785a04f5b0ceabdade4b3c409c71a95 b/storage/textures/14afe82f520a4fab0bee3b1c7a9b5aa2f785a04f5b0ceabdade4b3c409c71a95 new file mode 100644 index 0000000..e5c9d02 Binary files /dev/null and b/storage/textures/14afe82f520a4fab0bee3b1c7a9b5aa2f785a04f5b0ceabdade4b3c409c71a95 differ diff --git a/storage/textures/14e05cd0720865d50f7576e07f06aa0b0270598a7468bd3b8c91d5e4408d9a9d b/storage/textures/14e05cd0720865d50f7576e07f06aa0b0270598a7468bd3b8c91d5e4408d9a9d new file mode 100755 index 0000000..26ddfa1 Binary files /dev/null and b/storage/textures/14e05cd0720865d50f7576e07f06aa0b0270598a7468bd3b8c91d5e4408d9a9d differ diff --git a/storage/textures/14fade95e1e460e43a5d807f6e5b525556cd2f11fe68c25b63e0beaca37bea5d b/storage/textures/14fade95e1e460e43a5d807f6e5b525556cd2f11fe68c25b63e0beaca37bea5d new file mode 100644 index 0000000..eba3e64 Binary files /dev/null and b/storage/textures/14fade95e1e460e43a5d807f6e5b525556cd2f11fe68c25b63e0beaca37bea5d differ diff --git a/storage/textures/153f5a6b1bfab4e89b150c1a540ceceadab9414b0f8b5f4b5a1bcbf11e04f605 b/storage/textures/153f5a6b1bfab4e89b150c1a540ceceadab9414b0f8b5f4b5a1bcbf11e04f605 new file mode 100755 index 0000000..438b076 Binary files /dev/null and b/storage/textures/153f5a6b1bfab4e89b150c1a540ceceadab9414b0f8b5f4b5a1bcbf11e04f605 differ diff --git a/storage/textures/1568aaea860c037898f1541928cf0372c1cb650cde1bc6b8fe52b10eac6f038a b/storage/textures/1568aaea860c037898f1541928cf0372c1cb650cde1bc6b8fe52b10eac6f038a new file mode 100755 index 0000000..2e88943 Binary files /dev/null and b/storage/textures/1568aaea860c037898f1541928cf0372c1cb650cde1bc6b8fe52b10eac6f038a differ diff --git a/storage/textures/158100095ceee2d936891f5d5ae27513ddc7435aca4c2e93f7dcc5e0df802964 b/storage/textures/158100095ceee2d936891f5d5ae27513ddc7435aca4c2e93f7dcc5e0df802964 new file mode 100755 index 0000000..adc0892 Binary files /dev/null and b/storage/textures/158100095ceee2d936891f5d5ae27513ddc7435aca4c2e93f7dcc5e0df802964 differ diff --git a/storage/textures/15a9878c10c847e7e2f77940d9b48f0a908b63cc31803da385fcbdf5e7b70dcc b/storage/textures/15a9878c10c847e7e2f77940d9b48f0a908b63cc31803da385fcbdf5e7b70dcc new file mode 100755 index 0000000..9736721 Binary files /dev/null and b/storage/textures/15a9878c10c847e7e2f77940d9b48f0a908b63cc31803da385fcbdf5e7b70dcc differ diff --git a/storage/textures/1605ac73de182b67d56510238fe1a483b3787d01b5ff0e210e458bce232b8fb7 b/storage/textures/1605ac73de182b67d56510238fe1a483b3787d01b5ff0e210e458bce232b8fb7 new file mode 100644 index 0000000..f56419a Binary files /dev/null and b/storage/textures/1605ac73de182b67d56510238fe1a483b3787d01b5ff0e210e458bce232b8fb7 differ diff --git a/storage/textures/1624cb3acf5f4ba7faca13b904060bf0926061e89b429d516805a5b6e05031b8 b/storage/textures/1624cb3acf5f4ba7faca13b904060bf0926061e89b429d516805a5b6e05031b8 new file mode 100755 index 0000000..37d0e90 Binary files /dev/null and b/storage/textures/1624cb3acf5f4ba7faca13b904060bf0926061e89b429d516805a5b6e05031b8 differ diff --git a/storage/textures/16257fa242d02ebc3b4909137e9cf6b59c527d3d4b29a984b30429812fbf67b0 b/storage/textures/16257fa242d02ebc3b4909137e9cf6b59c527d3d4b29a984b30429812fbf67b0 new file mode 100755 index 0000000..7b80a73 Binary files /dev/null and b/storage/textures/16257fa242d02ebc3b4909137e9cf6b59c527d3d4b29a984b30429812fbf67b0 differ diff --git a/storage/textures/1648768b7c0e4eed6edb63f57d53b8228e2252fffc7e5feaf44853975a70090a b/storage/textures/1648768b7c0e4eed6edb63f57d53b8228e2252fffc7e5feaf44853975a70090a new file mode 100755 index 0000000..9c39bd4 Binary files /dev/null and b/storage/textures/1648768b7c0e4eed6edb63f57d53b8228e2252fffc7e5feaf44853975a70090a differ diff --git a/storage/textures/16866b2c0a006d7265198bc4b3c8f478cf9c9e278784332e1719af2934c1d487 b/storage/textures/16866b2c0a006d7265198bc4b3c8f478cf9c9e278784332e1719af2934c1d487 new file mode 100755 index 0000000..fac7315 Binary files /dev/null and b/storage/textures/16866b2c0a006d7265198bc4b3c8f478cf9c9e278784332e1719af2934c1d487 differ diff --git a/storage/textures/16e0f37cef6311b8f7cbb5dfd41b6192d313e95208cd63777d8aa816745a0670 b/storage/textures/16e0f37cef6311b8f7cbb5dfd41b6192d313e95208cd63777d8aa816745a0670 new file mode 100755 index 0000000..c0d94fa Binary files /dev/null and b/storage/textures/16e0f37cef6311b8f7cbb5dfd41b6192d313e95208cd63777d8aa816745a0670 differ diff --git a/storage/textures/16e8d0120b08116fbed8b1cc5cffa29b9e62039cc368d1952fbd9b048cd14ccb b/storage/textures/16e8d0120b08116fbed8b1cc5cffa29b9e62039cc368d1952fbd9b048cd14ccb new file mode 100644 index 0000000..d3c0c27 Binary files /dev/null and b/storage/textures/16e8d0120b08116fbed8b1cc5cffa29b9e62039cc368d1952fbd9b048cd14ccb differ diff --git a/storage/textures/17789a8cffcb14e3d3dc62f6cdad13eb27cda8e7a2b73539bc657b74009d41db b/storage/textures/17789a8cffcb14e3d3dc62f6cdad13eb27cda8e7a2b73539bc657b74009d41db new file mode 100755 index 0000000..8b28658 Binary files /dev/null and b/storage/textures/17789a8cffcb14e3d3dc62f6cdad13eb27cda8e7a2b73539bc657b74009d41db differ diff --git a/storage/textures/17a6708ce93512db78b5391a3079458d49deb149ca9f133dc343bc143feda0dc b/storage/textures/17a6708ce93512db78b5391a3079458d49deb149ca9f133dc343bc143feda0dc new file mode 100755 index 0000000..205893c Binary files /dev/null and b/storage/textures/17a6708ce93512db78b5391a3079458d49deb149ca9f133dc343bc143feda0dc differ diff --git a/storage/textures/17b56c7301c7d96c79aa950abbdcd6c74ee6d886883e8d6bad206d1003c757fb b/storage/textures/17b56c7301c7d96c79aa950abbdcd6c74ee6d886883e8d6bad206d1003c757fb new file mode 100755 index 0000000..5baf4fe Binary files /dev/null and b/storage/textures/17b56c7301c7d96c79aa950abbdcd6c74ee6d886883e8d6bad206d1003c757fb differ diff --git a/storage/textures/17c88e24a9ca6782f0dfd0ea10f3ffed21de15c2129ce6e6200768ba0adc898a b/storage/textures/17c88e24a9ca6782f0dfd0ea10f3ffed21de15c2129ce6e6200768ba0adc898a new file mode 100755 index 0000000..252cf46 Binary files /dev/null and b/storage/textures/17c88e24a9ca6782f0dfd0ea10f3ffed21de15c2129ce6e6200768ba0adc898a differ diff --git a/storage/textures/18d1d43db8e65b77d6c174c4eaed1fd0baf89b7aa83ccf426f1be76f1ebd5fd9 b/storage/textures/18d1d43db8e65b77d6c174c4eaed1fd0baf89b7aa83ccf426f1be76f1ebd5fd9 new file mode 100755 index 0000000..bd915d8 Binary files /dev/null and b/storage/textures/18d1d43db8e65b77d6c174c4eaed1fd0baf89b7aa83ccf426f1be76f1ebd5fd9 differ diff --git a/storage/textures/18e3b055e35fbfd69949df26ece22b956de5fee005ce9076684d5253c7f889e0 b/storage/textures/18e3b055e35fbfd69949df26ece22b956de5fee005ce9076684d5253c7f889e0 new file mode 100644 index 0000000..6702aa8 Binary files /dev/null and b/storage/textures/18e3b055e35fbfd69949df26ece22b956de5fee005ce9076684d5253c7f889e0 differ diff --git a/storage/textures/19423f61d79e664ab803ea511083eb692d9b3aa64a568481f5075c01e8cb1a36 b/storage/textures/19423f61d79e664ab803ea511083eb692d9b3aa64a568481f5075c01e8cb1a36 new file mode 100644 index 0000000..5f88dbb Binary files /dev/null and b/storage/textures/19423f61d79e664ab803ea511083eb692d9b3aa64a568481f5075c01e8cb1a36 differ diff --git a/storage/textures/1967ae21139a5bb147b63f3fa2dbb8f21d9e7c2a1320b1c50d12fdf910e79911 b/storage/textures/1967ae21139a5bb147b63f3fa2dbb8f21d9e7c2a1320b1c50d12fdf910e79911 new file mode 100755 index 0000000..8271de6 Binary files /dev/null and b/storage/textures/1967ae21139a5bb147b63f3fa2dbb8f21d9e7c2a1320b1c50d12fdf910e79911 differ diff --git a/storage/textures/19f95139e75178063e740347f6414a5965552ca4eae69e35f8acef28f848227a b/storage/textures/19f95139e75178063e740347f6414a5965552ca4eae69e35f8acef28f848227a new file mode 100755 index 0000000..9451b8d Binary files /dev/null and b/storage/textures/19f95139e75178063e740347f6414a5965552ca4eae69e35f8acef28f848227a differ diff --git a/storage/textures/1a4de3fd4e7ed160b5be36e9ff71309832213af05eb38c10777be2769ece40cd b/storage/textures/1a4de3fd4e7ed160b5be36e9ff71309832213af05eb38c10777be2769ece40cd new file mode 100755 index 0000000..adb49aa Binary files /dev/null and b/storage/textures/1a4de3fd4e7ed160b5be36e9ff71309832213af05eb38c10777be2769ece40cd differ diff --git a/storage/textures/1a74e70e7c1d4b8ef82bc5f3f62235209dbf800ea5e4579ad777afcc02e9fd8f b/storage/textures/1a74e70e7c1d4b8ef82bc5f3f62235209dbf800ea5e4579ad777afcc02e9fd8f new file mode 100755 index 0000000..5924dca Binary files /dev/null and b/storage/textures/1a74e70e7c1d4b8ef82bc5f3f62235209dbf800ea5e4579ad777afcc02e9fd8f differ diff --git a/storage/textures/1abb90622b45eef98225ecf67d4f2dd76af0e30a4fa1c34ecb449923bb8139d4 b/storage/textures/1abb90622b45eef98225ecf67d4f2dd76af0e30a4fa1c34ecb449923bb8139d4 new file mode 100755 index 0000000..76847cf Binary files /dev/null and b/storage/textures/1abb90622b45eef98225ecf67d4f2dd76af0e30a4fa1c34ecb449923bb8139d4 differ diff --git a/storage/textures/1ac8b2118165e513c3e96bc6deedc6605f3f4b16dcf661700ad21e9ae7ac2811 b/storage/textures/1ac8b2118165e513c3e96bc6deedc6605f3f4b16dcf661700ad21e9ae7ac2811 new file mode 100644 index 0000000..1394496 Binary files /dev/null and b/storage/textures/1ac8b2118165e513c3e96bc6deedc6605f3f4b16dcf661700ad21e9ae7ac2811 differ diff --git a/storage/textures/1ad4210750c7ed3bcc9db296c41a03560d820a433145c83b2e20bd9cd3dea485 b/storage/textures/1ad4210750c7ed3bcc9db296c41a03560d820a433145c83b2e20bd9cd3dea485 new file mode 100644 index 0000000..5f65d49 Binary files /dev/null and b/storage/textures/1ad4210750c7ed3bcc9db296c41a03560d820a433145c83b2e20bd9cd3dea485 differ diff --git a/storage/textures/1affd6f35244f7d4b1baf32ef6d86603693c3b7e2be41972e1dde197a058d495 b/storage/textures/1affd6f35244f7d4b1baf32ef6d86603693c3b7e2be41972e1dde197a058d495 new file mode 100755 index 0000000..7957c82 Binary files /dev/null and b/storage/textures/1affd6f35244f7d4b1baf32ef6d86603693c3b7e2be41972e1dde197a058d495 differ diff --git a/storage/textures/1b1267f688bb75aa21db50ac175a60d536e02db926f20dc144a0610e1109d23d b/storage/textures/1b1267f688bb75aa21db50ac175a60d536e02db926f20dc144a0610e1109d23d new file mode 100644 index 0000000..9c0c761 Binary files /dev/null and b/storage/textures/1b1267f688bb75aa21db50ac175a60d536e02db926f20dc144a0610e1109d23d differ diff --git a/storage/textures/1b38d2a52fcd7966e4c5807e2112a98ee384eed37f94430a816cb2e65584bcb1 b/storage/textures/1b38d2a52fcd7966e4c5807e2112a98ee384eed37f94430a816cb2e65584bcb1 new file mode 100755 index 0000000..ecd94f5 Binary files /dev/null and b/storage/textures/1b38d2a52fcd7966e4c5807e2112a98ee384eed37f94430a816cb2e65584bcb1 differ diff --git a/storage/textures/1b4e81db55114982e2193662a7eec6ea1f5daf9233ea41dccdcf6949c419a445 b/storage/textures/1b4e81db55114982e2193662a7eec6ea1f5daf9233ea41dccdcf6949c419a445 new file mode 100755 index 0000000..9b9ca29 Binary files /dev/null and b/storage/textures/1b4e81db55114982e2193662a7eec6ea1f5daf9233ea41dccdcf6949c419a445 differ diff --git a/storage/textures/1b65f507406b7942020db0c5ba6704eb29efce66ee7840ad50f7787ee0c48732 b/storage/textures/1b65f507406b7942020db0c5ba6704eb29efce66ee7840ad50f7787ee0c48732 new file mode 100755 index 0000000..3b68c38 Binary files /dev/null and b/storage/textures/1b65f507406b7942020db0c5ba6704eb29efce66ee7840ad50f7787ee0c48732 differ diff --git a/storage/textures/1c364369bd3a67424dff7017ffbe568e7d10445f79f03172be85615824d09f06 b/storage/textures/1c364369bd3a67424dff7017ffbe568e7d10445f79f03172be85615824d09f06 new file mode 100755 index 0000000..c86047d Binary files /dev/null and b/storage/textures/1c364369bd3a67424dff7017ffbe568e7d10445f79f03172be85615824d09f06 differ diff --git a/storage/textures/1c4becd993dd0de27b38e18651b3d91d2d8f29e7df7fc5605dd2b1e6db7b3c4d b/storage/textures/1c4becd993dd0de27b38e18651b3d91d2d8f29e7df7fc5605dd2b1e6db7b3c4d new file mode 100755 index 0000000..d465eac Binary files /dev/null and b/storage/textures/1c4becd993dd0de27b38e18651b3d91d2d8f29e7df7fc5605dd2b1e6db7b3c4d differ diff --git a/storage/textures/1c6bf923f8d77a9141791864d97c8a390e49d622edb3452a8f900f07c0fb9770 b/storage/textures/1c6bf923f8d77a9141791864d97c8a390e49d622edb3452a8f900f07c0fb9770 new file mode 100755 index 0000000..7a0fd84 Binary files /dev/null and b/storage/textures/1c6bf923f8d77a9141791864d97c8a390e49d622edb3452a8f900f07c0fb9770 differ diff --git a/storage/textures/1ca8c50c40313ff5849ecdfbdf4d3ebc4f44309ac5e25b1f9b3008fb7aa9dffc b/storage/textures/1ca8c50c40313ff5849ecdfbdf4d3ebc4f44309ac5e25b1f9b3008fb7aa9dffc new file mode 100755 index 0000000..028e942 Binary files /dev/null and b/storage/textures/1ca8c50c40313ff5849ecdfbdf4d3ebc4f44309ac5e25b1f9b3008fb7aa9dffc differ diff --git a/storage/textures/1d0f490efedd5ddeeb934edfbe366db4cadd4eb93a8659611e19089728798bc9 b/storage/textures/1d0f490efedd5ddeeb934edfbe366db4cadd4eb93a8659611e19089728798bc9 new file mode 100755 index 0000000..ebaec79 Binary files /dev/null and b/storage/textures/1d0f490efedd5ddeeb934edfbe366db4cadd4eb93a8659611e19089728798bc9 differ diff --git a/storage/textures/1d2783409257ffd46b438d9013099a4f14790732f188d30aa470605181234ad1 b/storage/textures/1d2783409257ffd46b438d9013099a4f14790732f188d30aa470605181234ad1 new file mode 100755 index 0000000..2cefaec Binary files /dev/null and b/storage/textures/1d2783409257ffd46b438d9013099a4f14790732f188d30aa470605181234ad1 differ diff --git a/storage/textures/1d67d4cb0f852ee26553f4e3c7960d4a586054a83b940ed4aed7ac23d8565330 b/storage/textures/1d67d4cb0f852ee26553f4e3c7960d4a586054a83b940ed4aed7ac23d8565330 new file mode 100755 index 0000000..ed5c781 Binary files /dev/null and b/storage/textures/1d67d4cb0f852ee26553f4e3c7960d4a586054a83b940ed4aed7ac23d8565330 differ diff --git a/storage/textures/1e06190963928075cd757ab3a243392ec90df1b51456aee193a7bf0e68411cdf b/storage/textures/1e06190963928075cd757ab3a243392ec90df1b51456aee193a7bf0e68411cdf new file mode 100755 index 0000000..c1b6f21 Binary files /dev/null and b/storage/textures/1e06190963928075cd757ab3a243392ec90df1b51456aee193a7bf0e68411cdf differ diff --git a/storage/textures/1e419443a6b388771246fc8eb8e3517238e176fd4006a752e522528a8384df08 b/storage/textures/1e419443a6b388771246fc8eb8e3517238e176fd4006a752e522528a8384df08 new file mode 100755 index 0000000..992465e Binary files /dev/null and b/storage/textures/1e419443a6b388771246fc8eb8e3517238e176fd4006a752e522528a8384df08 differ diff --git a/storage/textures/1e6b915329a64fa5106d6e3efa592404a7d1145bb7865cec0361fe3afb7454bf b/storage/textures/1e6b915329a64fa5106d6e3efa592404a7d1145bb7865cec0361fe3afb7454bf new file mode 100644 index 0000000..d9eaed2 Binary files /dev/null and b/storage/textures/1e6b915329a64fa5106d6e3efa592404a7d1145bb7865cec0361fe3afb7454bf differ diff --git a/storage/textures/1ed416f4dda30b97741e606ff741715bf1e60589ee5d08b8df72780596f8d8b1 b/storage/textures/1ed416f4dda30b97741e606ff741715bf1e60589ee5d08b8df72780596f8d8b1 new file mode 100755 index 0000000..a841aab Binary files /dev/null and b/storage/textures/1ed416f4dda30b97741e606ff741715bf1e60589ee5d08b8df72780596f8d8b1 differ diff --git a/storage/textures/1f08245e6d745e91441cf8bfda4ca97a0d09c5250a5d7ab7ffd3092eb334cf20 b/storage/textures/1f08245e6d745e91441cf8bfda4ca97a0d09c5250a5d7ab7ffd3092eb334cf20 new file mode 100755 index 0000000..a0b7404 Binary files /dev/null and b/storage/textures/1f08245e6d745e91441cf8bfda4ca97a0d09c5250a5d7ab7ffd3092eb334cf20 differ diff --git a/storage/textures/1f738511deded5d6bcb9bf7559a3ce87408651cf78c4bc9e85eccdee365062b1 b/storage/textures/1f738511deded5d6bcb9bf7559a3ce87408651cf78c4bc9e85eccdee365062b1 new file mode 100644 index 0000000..149664a Binary files /dev/null and b/storage/textures/1f738511deded5d6bcb9bf7559a3ce87408651cf78c4bc9e85eccdee365062b1 differ diff --git a/storage/textures/1f762ed9f370d4bbf174413f5c77fbaee1361cfaf0c5e3838b2214ae1f18a65b b/storage/textures/1f762ed9f370d4bbf174413f5c77fbaee1361cfaf0c5e3838b2214ae1f18a65b new file mode 100755 index 0000000..9780bec Binary files /dev/null and b/storage/textures/1f762ed9f370d4bbf174413f5c77fbaee1361cfaf0c5e3838b2214ae1f18a65b differ diff --git a/storage/textures/2037d2508e81bf214fb2e0b1acfd6704f3e795ca9ae14f474c94845fd9d397a6 b/storage/textures/2037d2508e81bf214fb2e0b1acfd6704f3e795ca9ae14f474c94845fd9d397a6 new file mode 100644 index 0000000..4fe03f7 Binary files /dev/null and b/storage/textures/2037d2508e81bf214fb2e0b1acfd6704f3e795ca9ae14f474c94845fd9d397a6 differ diff --git a/storage/textures/204e5a36dc86f5e3f2212446cc1ff7fa1589e9fad6362588a1d06ad7222001bf b/storage/textures/204e5a36dc86f5e3f2212446cc1ff7fa1589e9fad6362588a1d06ad7222001bf new file mode 100644 index 0000000..06eb774 Binary files /dev/null and b/storage/textures/204e5a36dc86f5e3f2212446cc1ff7fa1589e9fad6362588a1d06ad7222001bf differ diff --git a/storage/textures/208501a1d5df689a07a387f81e7380096f921aefb683259cd5fd5a1fc5f9835f b/storage/textures/208501a1d5df689a07a387f81e7380096f921aefb683259cd5fd5a1fc5f9835f new file mode 100644 index 0000000..e67ca04 Binary files /dev/null and b/storage/textures/208501a1d5df689a07a387f81e7380096f921aefb683259cd5fd5a1fc5f9835f differ diff --git a/storage/textures/211217294a68b6a9613ada62aaac387001b01f17c15ad880351fe33aa563b1d4 b/storage/textures/211217294a68b6a9613ada62aaac387001b01f17c15ad880351fe33aa563b1d4 new file mode 100644 index 0000000..9dfd262 Binary files /dev/null and b/storage/textures/211217294a68b6a9613ada62aaac387001b01f17c15ad880351fe33aa563b1d4 differ diff --git a/storage/textures/212ce4b73c3cf45262270d9789d02f411fd0a045c6b388099b0563b1e2ece8a0 b/storage/textures/212ce4b73c3cf45262270d9789d02f411fd0a045c6b388099b0563b1e2ece8a0 new file mode 100755 index 0000000..9066cf5 Binary files /dev/null and b/storage/textures/212ce4b73c3cf45262270d9789d02f411fd0a045c6b388099b0563b1e2ece8a0 differ diff --git a/storage/textures/217f357018af8315b13d118060225c21e90c4db74ec012a9165e30d72cffdc04 b/storage/textures/217f357018af8315b13d118060225c21e90c4db74ec012a9165e30d72cffdc04 new file mode 100644 index 0000000..3cce4ee Binary files /dev/null and b/storage/textures/217f357018af8315b13d118060225c21e90c4db74ec012a9165e30d72cffdc04 differ diff --git a/storage/textures/21ad502434a710d643a8208c34639094d6632aae18900cd65402491b4f1a4cd2 b/storage/textures/21ad502434a710d643a8208c34639094d6632aae18900cd65402491b4f1a4cd2 new file mode 100644 index 0000000..cef4b78 Binary files /dev/null and b/storage/textures/21ad502434a710d643a8208c34639094d6632aae18900cd65402491b4f1a4cd2 differ diff --git a/storage/textures/21cbcf36f2e9ccd4d5ab3f439cce3a79545f66a197572b2c1005ff14b8e9097b b/storage/textures/21cbcf36f2e9ccd4d5ab3f439cce3a79545f66a197572b2c1005ff14b8e9097b new file mode 100644 index 0000000..9b1858c Binary files /dev/null and b/storage/textures/21cbcf36f2e9ccd4d5ab3f439cce3a79545f66a197572b2c1005ff14b8e9097b differ diff --git a/storage/textures/21e174219cc69b0c12faa6de4d28ecdd8bd68bcd59af5bb8510b3b0ee42082dd b/storage/textures/21e174219cc69b0c12faa6de4d28ecdd8bd68bcd59af5bb8510b3b0ee42082dd new file mode 100755 index 0000000..62e5897 Binary files /dev/null and b/storage/textures/21e174219cc69b0c12faa6de4d28ecdd8bd68bcd59af5bb8510b3b0ee42082dd differ diff --git a/storage/textures/2246d7136f62cb9be506ae8d76f290b71cd74507ebf709fa5c3b25eb0040b604 b/storage/textures/2246d7136f62cb9be506ae8d76f290b71cd74507ebf709fa5c3b25eb0040b604 new file mode 100644 index 0000000..620f72d Binary files /dev/null and b/storage/textures/2246d7136f62cb9be506ae8d76f290b71cd74507ebf709fa5c3b25eb0040b604 differ diff --git a/storage/textures/22686b3f8d4c5bc7d8549d8c856cb28592aa5a9d970401901641907c7f3cee44 b/storage/textures/22686b3f8d4c5bc7d8549d8c856cb28592aa5a9d970401901641907c7f3cee44 new file mode 100644 index 0000000..5ce9ac9 Binary files /dev/null and b/storage/textures/22686b3f8d4c5bc7d8549d8c856cb28592aa5a9d970401901641907c7f3cee44 differ diff --git a/storage/textures/22ea572b104fef4a16a6ffc9a4b305851734391671e34063d974ca0bd6d4220b b/storage/textures/22ea572b104fef4a16a6ffc9a4b305851734391671e34063d974ca0bd6d4220b new file mode 100755 index 0000000..215d586 Binary files /dev/null and b/storage/textures/22ea572b104fef4a16a6ffc9a4b305851734391671e34063d974ca0bd6d4220b differ diff --git a/storage/textures/2340c0e03dd24a11b15a8b33c2a7e9e32abb2051b2481d0ba7defd635ca7a933 b/storage/textures/2340c0e03dd24a11b15a8b33c2a7e9e32abb2051b2481d0ba7defd635ca7a933 new file mode 100755 index 0000000..feb6c4c Binary files /dev/null and b/storage/textures/2340c0e03dd24a11b15a8b33c2a7e9e32abb2051b2481d0ba7defd635ca7a933 differ diff --git a/storage/textures/23c5603fac9c89b4eeb3a520ea59059fffaf53c72b49c54bd23242e025bd11a3 b/storage/textures/23c5603fac9c89b4eeb3a520ea59059fffaf53c72b49c54bd23242e025bd11a3 new file mode 100644 index 0000000..0a98427 Binary files /dev/null and b/storage/textures/23c5603fac9c89b4eeb3a520ea59059fffaf53c72b49c54bd23242e025bd11a3 differ diff --git a/storage/textures/23cf727ed5ba9c7bf3e02b6f571d0d3f784a8e7ecaa0931022b550ccd2fa4d71 b/storage/textures/23cf727ed5ba9c7bf3e02b6f571d0d3f784a8e7ecaa0931022b550ccd2fa4d71 new file mode 100755 index 0000000..7948a2a Binary files /dev/null and b/storage/textures/23cf727ed5ba9c7bf3e02b6f571d0d3f784a8e7ecaa0931022b550ccd2fa4d71 differ diff --git a/storage/textures/23d5439b24b60ee2ede6c1dcdb0a47e7db5f57f10247d475f02b31d3a2745114 b/storage/textures/23d5439b24b60ee2ede6c1dcdb0a47e7db5f57f10247d475f02b31d3a2745114 new file mode 100644 index 0000000..944b0c5 Binary files /dev/null and b/storage/textures/23d5439b24b60ee2ede6c1dcdb0a47e7db5f57f10247d475f02b31d3a2745114 differ diff --git a/storage/textures/24257441909d06084113b0305dbef03da8699bf94f9a53d83ddc541a76833694 b/storage/textures/24257441909d06084113b0305dbef03da8699bf94f9a53d83ddc541a76833694 new file mode 100755 index 0000000..94faf12 Binary files /dev/null and b/storage/textures/24257441909d06084113b0305dbef03da8699bf94f9a53d83ddc541a76833694 differ diff --git a/storage/textures/24ca7bcef667ec3ae9221576831365f14dbdbf50c60e6dbdbe0d3b2a53d8b9e4 b/storage/textures/24ca7bcef667ec3ae9221576831365f14dbdbf50c60e6dbdbe0d3b2a53d8b9e4 new file mode 100755 index 0000000..d984b95 Binary files /dev/null and b/storage/textures/24ca7bcef667ec3ae9221576831365f14dbdbf50c60e6dbdbe0d3b2a53d8b9e4 differ diff --git a/storage/textures/24efa0eba173a0e17cab3c18ac64264cce90d1454f4a8132a12e8ebc74c1a7c3 b/storage/textures/24efa0eba173a0e17cab3c18ac64264cce90d1454f4a8132a12e8ebc74c1a7c3 new file mode 100755 index 0000000..53e33ea Binary files /dev/null and b/storage/textures/24efa0eba173a0e17cab3c18ac64264cce90d1454f4a8132a12e8ebc74c1a7c3 differ diff --git a/storage/textures/24fbc1c559fb5d048962cf955c2e8db712df744a76464ca693f61a38e992a5a6 b/storage/textures/24fbc1c559fb5d048962cf955c2e8db712df744a76464ca693f61a38e992a5a6 new file mode 100755 index 0000000..958958e Binary files /dev/null and b/storage/textures/24fbc1c559fb5d048962cf955c2e8db712df744a76464ca693f61a38e992a5a6 differ diff --git a/storage/textures/252511cb3fe52ababd86d9c1409850568cb67e239d78af461f44c93c14abe41f b/storage/textures/252511cb3fe52ababd86d9c1409850568cb67e239d78af461f44c93c14abe41f new file mode 100755 index 0000000..e868c7b Binary files /dev/null and b/storage/textures/252511cb3fe52ababd86d9c1409850568cb67e239d78af461f44c93c14abe41f differ diff --git a/storage/textures/257a9780070613394dbcbb5f5a7c61c8014b2915b45dbe7d8bfbf61b4d9d1a60 b/storage/textures/257a9780070613394dbcbb5f5a7c61c8014b2915b45dbe7d8bfbf61b4d9d1a60 new file mode 100755 index 0000000..01d4259 Binary files /dev/null and b/storage/textures/257a9780070613394dbcbb5f5a7c61c8014b2915b45dbe7d8bfbf61b4d9d1a60 differ diff --git a/storage/textures/2582bb19ad4591b76971871cd62d78be096c43ac9d57c35bceb7cb4bb6cab4e0 b/storage/textures/2582bb19ad4591b76971871cd62d78be096c43ac9d57c35bceb7cb4bb6cab4e0 new file mode 100644 index 0000000..9d5a9e9 Binary files /dev/null and b/storage/textures/2582bb19ad4591b76971871cd62d78be096c43ac9d57c35bceb7cb4bb6cab4e0 differ diff --git a/storage/textures/25c57c2078885a2794633c2c1f220d48b30dc91b974511c9697f726b9996702a b/storage/textures/25c57c2078885a2794633c2c1f220d48b30dc91b974511c9697f726b9996702a new file mode 100755 index 0000000..27a2ab9 Binary files /dev/null and b/storage/textures/25c57c2078885a2794633c2c1f220d48b30dc91b974511c9697f726b9996702a differ diff --git a/storage/textures/25dd426ad3a29ac886c6f62dd41194554eddf0464652f462fec70c1111804652 b/storage/textures/25dd426ad3a29ac886c6f62dd41194554eddf0464652f462fec70c1111804652 new file mode 100755 index 0000000..d268763 Binary files /dev/null and b/storage/textures/25dd426ad3a29ac886c6f62dd41194554eddf0464652f462fec70c1111804652 differ diff --git a/storage/textures/26125f75c0c39ddc138f2d5ceb460f05ab6a291786b7d36e012a810f241e2767 b/storage/textures/26125f75c0c39ddc138f2d5ceb460f05ab6a291786b7d36e012a810f241e2767 new file mode 100644 index 0000000..22c177a Binary files /dev/null and b/storage/textures/26125f75c0c39ddc138f2d5ceb460f05ab6a291786b7d36e012a810f241e2767 differ diff --git a/storage/textures/2633fa346842af2e437bd9c3400c3d51d88a7beb707e63b8bab14c8614e15644 b/storage/textures/2633fa346842af2e437bd9c3400c3d51d88a7beb707e63b8bab14c8614e15644 new file mode 100644 index 0000000..e1ee1c8 Binary files /dev/null and b/storage/textures/2633fa346842af2e437bd9c3400c3d51d88a7beb707e63b8bab14c8614e15644 differ diff --git a/storage/textures/2658d8b8294fad11a5af6751ae9938e44654023f611ee154c914ff7832c14dd4 b/storage/textures/2658d8b8294fad11a5af6751ae9938e44654023f611ee154c914ff7832c14dd4 new file mode 100755 index 0000000..3e77f14 Binary files /dev/null and b/storage/textures/2658d8b8294fad11a5af6751ae9938e44654023f611ee154c914ff7832c14dd4 differ diff --git a/storage/textures/2670a3821323e20a1162222740dda6532108e0270a4542b5e378b96e062ae35c b/storage/textures/2670a3821323e20a1162222740dda6532108e0270a4542b5e378b96e062ae35c new file mode 100644 index 0000000..2707aef Binary files /dev/null and b/storage/textures/2670a3821323e20a1162222740dda6532108e0270a4542b5e378b96e062ae35c differ diff --git a/storage/textures/26b9f6262c5b44490ee8f10501abf7507ac866a33f1dbec6b834857996bec7a9 b/storage/textures/26b9f6262c5b44490ee8f10501abf7507ac866a33f1dbec6b834857996bec7a9 new file mode 100755 index 0000000..d56fd23 Binary files /dev/null and b/storage/textures/26b9f6262c5b44490ee8f10501abf7507ac866a33f1dbec6b834857996bec7a9 differ diff --git a/storage/textures/272f8548f2d31feeb81aabd2a02cb2efc25ad31f90115b60da217d73f2745325 b/storage/textures/272f8548f2d31feeb81aabd2a02cb2efc25ad31f90115b60da217d73f2745325 new file mode 100755 index 0000000..adc60b1 Binary files /dev/null and b/storage/textures/272f8548f2d31feeb81aabd2a02cb2efc25ad31f90115b60da217d73f2745325 differ diff --git a/storage/textures/274324331e81342d48241cc9de44c91ec5f4f128365f4f316c71f2a21f4396e1 b/storage/textures/274324331e81342d48241cc9de44c91ec5f4f128365f4f316c71f2a21f4396e1 new file mode 100755 index 0000000..f6fce14 Binary files /dev/null and b/storage/textures/274324331e81342d48241cc9de44c91ec5f4f128365f4f316c71f2a21f4396e1 differ diff --git a/storage/textures/277524c54e6c2e220458b5270aa9f075bd02282fc4d7a608acad671856f5046d b/storage/textures/277524c54e6c2e220458b5270aa9f075bd02282fc4d7a608acad671856f5046d new file mode 100644 index 0000000..7121f0d Binary files /dev/null and b/storage/textures/277524c54e6c2e220458b5270aa9f075bd02282fc4d7a608acad671856f5046d differ diff --git a/storage/textures/27b6314945684ca18390c8941b11f4ee3a14146168c2a298f5f7b92188de3815 b/storage/textures/27b6314945684ca18390c8941b11f4ee3a14146168c2a298f5f7b92188de3815 new file mode 100755 index 0000000..22f7137 Binary files /dev/null and b/storage/textures/27b6314945684ca18390c8941b11f4ee3a14146168c2a298f5f7b92188de3815 differ diff --git a/storage/textures/27b641a1a9c0f18e72854471a5ed3e21f88a93113735f29a5567db67f84b1cde b/storage/textures/27b641a1a9c0f18e72854471a5ed3e21f88a93113735f29a5567db67f84b1cde new file mode 100644 index 0000000..e5a67fb Binary files /dev/null and b/storage/textures/27b641a1a9c0f18e72854471a5ed3e21f88a93113735f29a5567db67f84b1cde differ diff --git a/storage/textures/28f2a64e45d26399902ae5dbf05436a45e94d6d934340aa6747c69814f068da3 b/storage/textures/28f2a64e45d26399902ae5dbf05436a45e94d6d934340aa6747c69814f068da3 new file mode 100755 index 0000000..0a04b12 Binary files /dev/null and b/storage/textures/28f2a64e45d26399902ae5dbf05436a45e94d6d934340aa6747c69814f068da3 differ diff --git a/storage/textures/29061911ae6f70ef2e1dbf88e096d09021f1a582e282861946877bbe11307440 b/storage/textures/29061911ae6f70ef2e1dbf88e096d09021f1a582e282861946877bbe11307440 new file mode 100755 index 0000000..dbeca31 Binary files /dev/null and b/storage/textures/29061911ae6f70ef2e1dbf88e096d09021f1a582e282861946877bbe11307440 differ diff --git a/storage/textures/291b78910ec2658d7a8a6e69209fa218125b05b62f9f81b504bd60a834d65809 b/storage/textures/291b78910ec2658d7a8a6e69209fa218125b05b62f9f81b504bd60a834d65809 new file mode 100644 index 0000000..1ac29d7 Binary files /dev/null and b/storage/textures/291b78910ec2658d7a8a6e69209fa218125b05b62f9f81b504bd60a834d65809 differ diff --git a/storage/textures/293019cdc86445ef9b706b35d91db9a4e6747ed6f454d2b4faa827d1831a186c b/storage/textures/293019cdc86445ef9b706b35d91db9a4e6747ed6f454d2b4faa827d1831a186c new file mode 100755 index 0000000..bec27fb Binary files /dev/null and b/storage/textures/293019cdc86445ef9b706b35d91db9a4e6747ed6f454d2b4faa827d1831a186c differ diff --git a/storage/textures/29521e80832c80b0bc7c0a414f70092686eaa4da629031b72685ed9fe9caa19c b/storage/textures/29521e80832c80b0bc7c0a414f70092686eaa4da629031b72685ed9fe9caa19c new file mode 100755 index 0000000..297e00c Binary files /dev/null and b/storage/textures/29521e80832c80b0bc7c0a414f70092686eaa4da629031b72685ed9fe9caa19c differ diff --git a/storage/textures/298888f323a1ec1db73f9210741e8c3956e8e4a00d47bc567f106ed00b13b3f6 b/storage/textures/298888f323a1ec1db73f9210741e8c3956e8e4a00d47bc567f106ed00b13b3f6 new file mode 100755 index 0000000..7c585bf Binary files /dev/null and b/storage/textures/298888f323a1ec1db73f9210741e8c3956e8e4a00d47bc567f106ed00b13b3f6 differ diff --git a/storage/textures/2a2147af7ecdbac3fdfa3b737c9c4229033a8a76ab0804efc85ee22e6795730a b/storage/textures/2a2147af7ecdbac3fdfa3b737c9c4229033a8a76ab0804efc85ee22e6795730a new file mode 100755 index 0000000..70a0687 Binary files /dev/null and b/storage/textures/2a2147af7ecdbac3fdfa3b737c9c4229033a8a76ab0804efc85ee22e6795730a differ diff --git a/storage/textures/2a41fc3ecb9c6961c3efae517edd6763963c7deff185d3a1a04aabb171d823c0 b/storage/textures/2a41fc3ecb9c6961c3efae517edd6763963c7deff185d3a1a04aabb171d823c0 new file mode 100755 index 0000000..8c0d727 Binary files /dev/null and b/storage/textures/2a41fc3ecb9c6961c3efae517edd6763963c7deff185d3a1a04aabb171d823c0 differ diff --git a/storage/textures/2a95302885aacfe26b4209f969231d38ec06baeb6a6f453602a539a71f3b2618 b/storage/textures/2a95302885aacfe26b4209f969231d38ec06baeb6a6f453602a539a71f3b2618 new file mode 100755 index 0000000..833d905 Binary files /dev/null and b/storage/textures/2a95302885aacfe26b4209f969231d38ec06baeb6a6f453602a539a71f3b2618 differ diff --git a/storage/textures/2a95dd0be1128add5025e53a96cc276a346a970d4f89fdc54f2ee63250b3cbe4 b/storage/textures/2a95dd0be1128add5025e53a96cc276a346a970d4f89fdc54f2ee63250b3cbe4 new file mode 100755 index 0000000..9a5f10b Binary files /dev/null and b/storage/textures/2a95dd0be1128add5025e53a96cc276a346a970d4f89fdc54f2ee63250b3cbe4 differ diff --git a/storage/textures/2ab62ec6f51c9527d7ddfedbc6f1d622fa29db6b03896d4ed543e6ddccf07202 b/storage/textures/2ab62ec6f51c9527d7ddfedbc6f1d622fa29db6b03896d4ed543e6ddccf07202 new file mode 100755 index 0000000..1b031d8 Binary files /dev/null and b/storage/textures/2ab62ec6f51c9527d7ddfedbc6f1d622fa29db6b03896d4ed543e6ddccf07202 differ diff --git a/storage/textures/2adee0f23352cffe8f888cde05c04b9a49b942f5fbc115eeda7d6171c22dc164 b/storage/textures/2adee0f23352cffe8f888cde05c04b9a49b942f5fbc115eeda7d6171c22dc164 new file mode 100755 index 0000000..d8ec85b Binary files /dev/null and b/storage/textures/2adee0f23352cffe8f888cde05c04b9a49b942f5fbc115eeda7d6171c22dc164 differ diff --git a/storage/textures/2ae23bc810f8f53c91801da25108df2d8f02ee84b5bb564e5021bdbc1b3e855e b/storage/textures/2ae23bc810f8f53c91801da25108df2d8f02ee84b5bb564e5021bdbc1b3e855e new file mode 100755 index 0000000..64c4238 Binary files /dev/null and b/storage/textures/2ae23bc810f8f53c91801da25108df2d8f02ee84b5bb564e5021bdbc1b3e855e differ diff --git a/storage/textures/2b015a6c43690b65d3e7543dd4b5ca5428fd4c77d1a49580923dbf20b409f7fd b/storage/textures/2b015a6c43690b65d3e7543dd4b5ca5428fd4c77d1a49580923dbf20b409f7fd new file mode 100755 index 0000000..5a45a12 Binary files /dev/null and b/storage/textures/2b015a6c43690b65d3e7543dd4b5ca5428fd4c77d1a49580923dbf20b409f7fd differ diff --git a/storage/textures/2b4c91468bfd2f07caa663cb0fe82df2de574d28864026602becfe91125285b0 b/storage/textures/2b4c91468bfd2f07caa663cb0fe82df2de574d28864026602becfe91125285b0 new file mode 100755 index 0000000..44aa3c4 Binary files /dev/null and b/storage/textures/2b4c91468bfd2f07caa663cb0fe82df2de574d28864026602becfe91125285b0 differ diff --git a/storage/textures/2b8bd4ae4be27f122e315b441bf770a49f896125d7c242ba0e440e2c82b2c2bb b/storage/textures/2b8bd4ae4be27f122e315b441bf770a49f896125d7c242ba0e440e2c82b2c2bb new file mode 100755 index 0000000..3e4b4e9 Binary files /dev/null and b/storage/textures/2b8bd4ae4be27f122e315b441bf770a49f896125d7c242ba0e440e2c82b2c2bb differ diff --git a/storage/textures/2ba6bef8bf5772bd633af8f9162d9573407d11d93730e413e117fd1defdab369 b/storage/textures/2ba6bef8bf5772bd633af8f9162d9573407d11d93730e413e117fd1defdab369 new file mode 100644 index 0000000..514f116 Binary files /dev/null and b/storage/textures/2ba6bef8bf5772bd633af8f9162d9573407d11d93730e413e117fd1defdab369 differ diff --git a/storage/textures/2c0fe7921d40120659f38b478c152dc623e2497d41f121ec48668dc526c73bfa b/storage/textures/2c0fe7921d40120659f38b478c152dc623e2497d41f121ec48668dc526c73bfa new file mode 100644 index 0000000..986605c Binary files /dev/null and b/storage/textures/2c0fe7921d40120659f38b478c152dc623e2497d41f121ec48668dc526c73bfa differ diff --git a/storage/textures/2c17884fc2e29f767685f42ca680303d0cb9e1eea0cbc55669a8d4da01e0a0bb b/storage/textures/2c17884fc2e29f767685f42ca680303d0cb9e1eea0cbc55669a8d4da01e0a0bb new file mode 100644 index 0000000..ab58c27 Binary files /dev/null and b/storage/textures/2c17884fc2e29f767685f42ca680303d0cb9e1eea0cbc55669a8d4da01e0a0bb differ diff --git a/storage/textures/2c19b4746cd3190adf944eb2c24d7b4d9ba31d525bd3596898abc0ce60be8bfd b/storage/textures/2c19b4746cd3190adf944eb2c24d7b4d9ba31d525bd3596898abc0ce60be8bfd new file mode 100755 index 0000000..c860bbe Binary files /dev/null and b/storage/textures/2c19b4746cd3190adf944eb2c24d7b4d9ba31d525bd3596898abc0ce60be8bfd differ diff --git a/storage/textures/2c24ed72d6e9c39acf722d025f5e6145a13f6c4702650adac32c9866c3d64c9d b/storage/textures/2c24ed72d6e9c39acf722d025f5e6145a13f6c4702650adac32c9866c3d64c9d new file mode 100755 index 0000000..3a136d4 Binary files /dev/null and b/storage/textures/2c24ed72d6e9c39acf722d025f5e6145a13f6c4702650adac32c9866c3d64c9d differ diff --git a/storage/textures/2c5f0ddee19db24bdf7ebc32a15f6cf1f5548b5806f7aab73a6f381e6399c845 b/storage/textures/2c5f0ddee19db24bdf7ebc32a15f6cf1f5548b5806f7aab73a6f381e6399c845 new file mode 100644 index 0000000..2838a50 Binary files /dev/null and b/storage/textures/2c5f0ddee19db24bdf7ebc32a15f6cf1f5548b5806f7aab73a6f381e6399c845 differ diff --git a/storage/textures/2c82172f98b28923fb374a37cf1ebf42d4f1d1720ef6232a19bee927bcacec4c b/storage/textures/2c82172f98b28923fb374a37cf1ebf42d4f1d1720ef6232a19bee927bcacec4c new file mode 100755 index 0000000..1c0af14 Binary files /dev/null and b/storage/textures/2c82172f98b28923fb374a37cf1ebf42d4f1d1720ef6232a19bee927bcacec4c differ diff --git a/storage/textures/2cb4be4458c9a51d48d88dd96c79cd46258b79ecba380e61121b8db8400c188a b/storage/textures/2cb4be4458c9a51d48d88dd96c79cd46258b79ecba380e61121b8db8400c188a new file mode 100755 index 0000000..4fee751 Binary files /dev/null and b/storage/textures/2cb4be4458c9a51d48d88dd96c79cd46258b79ecba380e61121b8db8400c188a differ diff --git a/storage/textures/2cdfe3ae3a97fbb6542c2aa9015858421246af689e351d7b5fdc070010923c29 b/storage/textures/2cdfe3ae3a97fbb6542c2aa9015858421246af689e351d7b5fdc070010923c29 new file mode 100755 index 0000000..b2711da Binary files /dev/null and b/storage/textures/2cdfe3ae3a97fbb6542c2aa9015858421246af689e351d7b5fdc070010923c29 differ diff --git a/storage/textures/2ce927594257052518f449eb51c0ce7c51f340aa5249e668689ccb0224a24e77 b/storage/textures/2ce927594257052518f449eb51c0ce7c51f340aa5249e668689ccb0224a24e77 new file mode 100644 index 0000000..925baeb Binary files /dev/null and b/storage/textures/2ce927594257052518f449eb51c0ce7c51f340aa5249e668689ccb0224a24e77 differ diff --git a/storage/textures/2cf803fa3d04668b0f4ab87bad5d38e20f026b7f20d2a35092fe004578b5c049 b/storage/textures/2cf803fa3d04668b0f4ab87bad5d38e20f026b7f20d2a35092fe004578b5c049 new file mode 100644 index 0000000..1be6e52 Binary files /dev/null and b/storage/textures/2cf803fa3d04668b0f4ab87bad5d38e20f026b7f20d2a35092fe004578b5c049 differ diff --git a/storage/textures/2d432437d8443fb6443731ebf370414eb6ffba6197df33c34e0768aa9fdcf420 b/storage/textures/2d432437d8443fb6443731ebf370414eb6ffba6197df33c34e0768aa9fdcf420 new file mode 100755 index 0000000..dbab5d9 Binary files /dev/null and b/storage/textures/2d432437d8443fb6443731ebf370414eb6ffba6197df33c34e0768aa9fdcf420 differ diff --git a/storage/textures/2d7e0c36953991f9cc622ebf4dd66192b8977faedeb6263961c4b73111703f81 b/storage/textures/2d7e0c36953991f9cc622ebf4dd66192b8977faedeb6263961c4b73111703f81 new file mode 100755 index 0000000..60bbb24 Binary files /dev/null and b/storage/textures/2d7e0c36953991f9cc622ebf4dd66192b8977faedeb6263961c4b73111703f81 differ diff --git a/storage/textures/2dda3c5c0b8895221a6556e130a9a378b7e681b8e9974578b9a25528387e330b b/storage/textures/2dda3c5c0b8895221a6556e130a9a378b7e681b8e9974578b9a25528387e330b new file mode 100644 index 0000000..eca5f53 Binary files /dev/null and b/storage/textures/2dda3c5c0b8895221a6556e130a9a378b7e681b8e9974578b9a25528387e330b differ diff --git a/storage/textures/2e3bf0d31e5bcee9dce5b71e66c0281452500d1be462f3fcb095ba56de697aa6 b/storage/textures/2e3bf0d31e5bcee9dce5b71e66c0281452500d1be462f3fcb095ba56de697aa6 new file mode 100755 index 0000000..58a928b Binary files /dev/null and b/storage/textures/2e3bf0d31e5bcee9dce5b71e66c0281452500d1be462f3fcb095ba56de697aa6 differ diff --git a/storage/textures/2e6962048a52d1c32b94451a24f0fe011b7c8893fb43aa85eb31d286a18e5baa b/storage/textures/2e6962048a52d1c32b94451a24f0fe011b7c8893fb43aa85eb31d286a18e5baa new file mode 100755 index 0000000..d94ff61 Binary files /dev/null and b/storage/textures/2e6962048a52d1c32b94451a24f0fe011b7c8893fb43aa85eb31d286a18e5baa differ diff --git a/storage/textures/2ef68eb9eaf5864eca6c0d42bf92d6e8bec7650161f98e0cddf83acd7e5af6c9 b/storage/textures/2ef68eb9eaf5864eca6c0d42bf92d6e8bec7650161f98e0cddf83acd7e5af6c9 new file mode 100644 index 0000000..aa08af0 Binary files /dev/null and b/storage/textures/2ef68eb9eaf5864eca6c0d42bf92d6e8bec7650161f98e0cddf83acd7e5af6c9 differ diff --git a/storage/textures/2efaf8e881ecb4ad10e93d07234b7d67838a4d1e2c2412cbc91bdbb38ff9ec91 b/storage/textures/2efaf8e881ecb4ad10e93d07234b7d67838a4d1e2c2412cbc91bdbb38ff9ec91 new file mode 100755 index 0000000..b58af3e Binary files /dev/null and b/storage/textures/2efaf8e881ecb4ad10e93d07234b7d67838a4d1e2c2412cbc91bdbb38ff9ec91 differ diff --git a/storage/textures/2f57b6ac9a636dd8a8e3a897d41cfa0c0bf535bd5daa95119a090d6b989464f9 b/storage/textures/2f57b6ac9a636dd8a8e3a897d41cfa0c0bf535bd5daa95119a090d6b989464f9 new file mode 100755 index 0000000..ebbf8f9 Binary files /dev/null and b/storage/textures/2f57b6ac9a636dd8a8e3a897d41cfa0c0bf535bd5daa95119a090d6b989464f9 differ diff --git a/storage/textures/2f5a5ee9ba7b8ea2ef60873668c30a42f619d04d4ef919b0cafb72623fd8a43a b/storage/textures/2f5a5ee9ba7b8ea2ef60873668c30a42f619d04d4ef919b0cafb72623fd8a43a new file mode 100644 index 0000000..35e1890 Binary files /dev/null and b/storage/textures/2f5a5ee9ba7b8ea2ef60873668c30a42f619d04d4ef919b0cafb72623fd8a43a differ diff --git a/storage/textures/2f61bed8accb957bf054763a143b64280e6c2810ed19135f89641d4bbfee43a0 b/storage/textures/2f61bed8accb957bf054763a143b64280e6c2810ed19135f89641d4bbfee43a0 new file mode 100755 index 0000000..5eff472 Binary files /dev/null and b/storage/textures/2f61bed8accb957bf054763a143b64280e6c2810ed19135f89641d4bbfee43a0 differ diff --git a/storage/textures/2f7ba7019e013a4a3d0d65a43e885c1a6d12ca6297fabb14c0c4e6f0193f4de1 b/storage/textures/2f7ba7019e013a4a3d0d65a43e885c1a6d12ca6297fabb14c0c4e6f0193f4de1 new file mode 100644 index 0000000..a83ba65 Binary files /dev/null and b/storage/textures/2f7ba7019e013a4a3d0d65a43e885c1a6d12ca6297fabb14c0c4e6f0193f4de1 differ diff --git a/storage/textures/2faab4390c11ab0391431039230677ee6793671c22c9c4cf3b4ade2dccac9bfd b/storage/textures/2faab4390c11ab0391431039230677ee6793671c22c9c4cf3b4ade2dccac9bfd new file mode 100755 index 0000000..5eb8ad6 Binary files /dev/null and b/storage/textures/2faab4390c11ab0391431039230677ee6793671c22c9c4cf3b4ade2dccac9bfd differ diff --git a/storage/textures/2fc9aa66248556bba3291747749b3f34c615839c1d504ace2447b032eab01dea b/storage/textures/2fc9aa66248556bba3291747749b3f34c615839c1d504ace2447b032eab01dea new file mode 100644 index 0000000..de425c3 Binary files /dev/null and b/storage/textures/2fc9aa66248556bba3291747749b3f34c615839c1d504ace2447b032eab01dea differ diff --git a/storage/textures/305d4e4d42d72e2b6d2e83e674dfba57c83d9532b136af63a34c1a2d64b37d91 b/storage/textures/305d4e4d42d72e2b6d2e83e674dfba57c83d9532b136af63a34c1a2d64b37d91 new file mode 100755 index 0000000..9d4f04d Binary files /dev/null and b/storage/textures/305d4e4d42d72e2b6d2e83e674dfba57c83d9532b136af63a34c1a2d64b37d91 differ diff --git a/storage/textures/3071fb5ce82714d9c4de87dc96a027474f707833dc043ab790693f90221b5b5d b/storage/textures/3071fb5ce82714d9c4de87dc96a027474f707833dc043ab790693f90221b5b5d new file mode 100755 index 0000000..74ab218 Binary files /dev/null and b/storage/textures/3071fb5ce82714d9c4de87dc96a027474f707833dc043ab790693f90221b5b5d differ diff --git a/storage/textures/3088b49190b15d24fe2c60ed2c42d8fae8a9eef77d03d0e8bad727ef76227d0e b/storage/textures/3088b49190b15d24fe2c60ed2c42d8fae8a9eef77d03d0e8bad727ef76227d0e new file mode 100755 index 0000000..b457d00 Binary files /dev/null and b/storage/textures/3088b49190b15d24fe2c60ed2c42d8fae8a9eef77d03d0e8bad727ef76227d0e differ diff --git a/storage/textures/309190677aba2a0708c48f8b6e244653051722b6f3a00bd440173906e668d3ed b/storage/textures/309190677aba2a0708c48f8b6e244653051722b6f3a00bd440173906e668d3ed new file mode 100755 index 0000000..be4e554 Binary files /dev/null and b/storage/textures/309190677aba2a0708c48f8b6e244653051722b6f3a00bd440173906e668d3ed differ diff --git a/storage/textures/3099a4026155c39289b992b3694f2be3c65a4dd4f21c1cc380e42748e3a29567 b/storage/textures/3099a4026155c39289b992b3694f2be3c65a4dd4f21c1cc380e42748e3a29567 new file mode 100755 index 0000000..b46a967 Binary files /dev/null and b/storage/textures/3099a4026155c39289b992b3694f2be3c65a4dd4f21c1cc380e42748e3a29567 differ diff --git a/storage/textures/30cd4da66ee8152c9bfcb4f44d29bdf51bcc9c04ec572fa425225df6ed59ee47 b/storage/textures/30cd4da66ee8152c9bfcb4f44d29bdf51bcc9c04ec572fa425225df6ed59ee47 new file mode 100755 index 0000000..83c9456 Binary files /dev/null and b/storage/textures/30cd4da66ee8152c9bfcb4f44d29bdf51bcc9c04ec572fa425225df6ed59ee47 differ diff --git a/storage/textures/30d99ee35c423f6df4bfd9414614f89f29a79f4297b37a8bc5804521e54b986b b/storage/textures/30d99ee35c423f6df4bfd9414614f89f29a79f4297b37a8bc5804521e54b986b new file mode 100644 index 0000000..4e6245e Binary files /dev/null and b/storage/textures/30d99ee35c423f6df4bfd9414614f89f29a79f4297b37a8bc5804521e54b986b differ diff --git a/storage/textures/30dfd021f9a1eec5d13f0e31acce2b32c3f44537f4b50ef4f33da530c16d8ce5 b/storage/textures/30dfd021f9a1eec5d13f0e31acce2b32c3f44537f4b50ef4f33da530c16d8ce5 new file mode 100755 index 0000000..f239f2e Binary files /dev/null and b/storage/textures/30dfd021f9a1eec5d13f0e31acce2b32c3f44537f4b50ef4f33da530c16d8ce5 differ diff --git a/storage/textures/3140b06979e68105340e1bd5651898a0e9193c592bb249deeccf6b944c1a0b2e b/storage/textures/3140b06979e68105340e1bd5651898a0e9193c592bb249deeccf6b944c1a0b2e new file mode 100755 index 0000000..7917247 Binary files /dev/null and b/storage/textures/3140b06979e68105340e1bd5651898a0e9193c592bb249deeccf6b944c1a0b2e differ diff --git a/storage/textures/315fe079ee14d440530e07103c34ab9f7e13ee47fddafe264eae8ceb8927abe9 b/storage/textures/315fe079ee14d440530e07103c34ab9f7e13ee47fddafe264eae8ceb8927abe9 new file mode 100755 index 0000000..64d957e Binary files /dev/null and b/storage/textures/315fe079ee14d440530e07103c34ab9f7e13ee47fddafe264eae8ceb8927abe9 differ diff --git a/storage/textures/31bb7060667ff7681bd73bef1b6be030c18eb06dee45177db3f6682387f72cbc b/storage/textures/31bb7060667ff7681bd73bef1b6be030c18eb06dee45177db3f6682387f72cbc new file mode 100644 index 0000000..e3a4440 Binary files /dev/null and b/storage/textures/31bb7060667ff7681bd73bef1b6be030c18eb06dee45177db3f6682387f72cbc differ diff --git a/storage/textures/31c5d08ee66e4f7cf64f55b3dc8ece310a9aebd03af702717f284419edbc249d b/storage/textures/31c5d08ee66e4f7cf64f55b3dc8ece310a9aebd03af702717f284419edbc249d new file mode 100755 index 0000000..29b105b Binary files /dev/null and b/storage/textures/31c5d08ee66e4f7cf64f55b3dc8ece310a9aebd03af702717f284419edbc249d differ diff --git a/storage/textures/31d9b637a85ecce410297370cd90792f069010e206ba797ba35d8b8c6db55b0b b/storage/textures/31d9b637a85ecce410297370cd90792f069010e206ba797ba35d8b8c6db55b0b new file mode 100755 index 0000000..38d7bed Binary files /dev/null and b/storage/textures/31d9b637a85ecce410297370cd90792f069010e206ba797ba35d8b8c6db55b0b differ diff --git a/storage/textures/3239559114805d4e9fb2e96ef705ed89a254b58e42349c9842d3a322cd0cb7a2 b/storage/textures/3239559114805d4e9fb2e96ef705ed89a254b58e42349c9842d3a322cd0cb7a2 new file mode 100644 index 0000000..511a55b Binary files /dev/null and b/storage/textures/3239559114805d4e9fb2e96ef705ed89a254b58e42349c9842d3a322cd0cb7a2 differ diff --git a/storage/textures/328761fa8624cdae139ae47c359c6f1f3f8694b9f8ad48808cac7e50ff83acdb b/storage/textures/328761fa8624cdae139ae47c359c6f1f3f8694b9f8ad48808cac7e50ff83acdb new file mode 100644 index 0000000..f5ae3ce Binary files /dev/null and b/storage/textures/328761fa8624cdae139ae47c359c6f1f3f8694b9f8ad48808cac7e50ff83acdb differ diff --git a/storage/textures/32e12afce24e43892ce092e1fe7c630db15dbe565808a7e26481b71e5ef99f10 b/storage/textures/32e12afce24e43892ce092e1fe7c630db15dbe565808a7e26481b71e5ef99f10 new file mode 100755 index 0000000..90f653e Binary files /dev/null and b/storage/textures/32e12afce24e43892ce092e1fe7c630db15dbe565808a7e26481b71e5ef99f10 differ diff --git a/storage/textures/3329115d96428456edfd5b5d6a12052168dd8dc080ab5bd5210783d4846743f4 b/storage/textures/3329115d96428456edfd5b5d6a12052168dd8dc080ab5bd5210783d4846743f4 new file mode 100755 index 0000000..a6e552d Binary files /dev/null and b/storage/textures/3329115d96428456edfd5b5d6a12052168dd8dc080ab5bd5210783d4846743f4 differ diff --git a/storage/textures/33611ba25c5a1e5067c5b3a1c87f2804686cb2f2ab76d5b6b9b47583dcc69f0d b/storage/textures/33611ba25c5a1e5067c5b3a1c87f2804686cb2f2ab76d5b6b9b47583dcc69f0d new file mode 100755 index 0000000..05da87d Binary files /dev/null and b/storage/textures/33611ba25c5a1e5067c5b3a1c87f2804686cb2f2ab76d5b6b9b47583dcc69f0d differ diff --git a/storage/textures/3369df2d13736376f68f55d90fe109a1af263776c803d9c1b7f156cdfe862342 b/storage/textures/3369df2d13736376f68f55d90fe109a1af263776c803d9c1b7f156cdfe862342 new file mode 100755 index 0000000..9a08c5b Binary files /dev/null and b/storage/textures/3369df2d13736376f68f55d90fe109a1af263776c803d9c1b7f156cdfe862342 differ diff --git a/storage/textures/33a9e467aaa98abff02f74f2262c057329cce66ae56baf86c63e0165b632dc91 b/storage/textures/33a9e467aaa98abff02f74f2262c057329cce66ae56baf86c63e0165b632dc91 new file mode 100755 index 0000000..b95ff8e Binary files /dev/null and b/storage/textures/33a9e467aaa98abff02f74f2262c057329cce66ae56baf86c63e0165b632dc91 differ diff --git a/storage/textures/33c7ca2f443812c09faf1c1b2f6ba79de19324091eeeb722196bfd626857f1d2 b/storage/textures/33c7ca2f443812c09faf1c1b2f6ba79de19324091eeeb722196bfd626857f1d2 new file mode 100755 index 0000000..9c47a12 Binary files /dev/null and b/storage/textures/33c7ca2f443812c09faf1c1b2f6ba79de19324091eeeb722196bfd626857f1d2 differ diff --git a/storage/textures/3435e4b955b2ba53c3322473d7fb09d37270e67156da640f1f554fa6753b6427 b/storage/textures/3435e4b955b2ba53c3322473d7fb09d37270e67156da640f1f554fa6753b6427 new file mode 100755 index 0000000..37e8c4c Binary files /dev/null and b/storage/textures/3435e4b955b2ba53c3322473d7fb09d37270e67156da640f1f554fa6753b6427 differ diff --git a/storage/textures/34379516661a1a3720520e67022ae40cb61cac71747988c54574b9d034bad2e4 b/storage/textures/34379516661a1a3720520e67022ae40cb61cac71747988c54574b9d034bad2e4 new file mode 100755 index 0000000..15438be Binary files /dev/null and b/storage/textures/34379516661a1a3720520e67022ae40cb61cac71747988c54574b9d034bad2e4 differ diff --git a/storage/textures/34432e35ab9fe801cf067022cfc616bd07899c2c9d73642b7aa47f187d1ef2e9 b/storage/textures/34432e35ab9fe801cf067022cfc616bd07899c2c9d73642b7aa47f187d1ef2e9 new file mode 100755 index 0000000..bceadf0 Binary files /dev/null and b/storage/textures/34432e35ab9fe801cf067022cfc616bd07899c2c9d73642b7aa47f187d1ef2e9 differ diff --git a/storage/textures/344a3db98a887a8e5a4907cf56dc7d3da0a11a2fd064ff5c090285d65d938558 b/storage/textures/344a3db98a887a8e5a4907cf56dc7d3da0a11a2fd064ff5c090285d65d938558 new file mode 100755 index 0000000..66f274f Binary files /dev/null and b/storage/textures/344a3db98a887a8e5a4907cf56dc7d3da0a11a2fd064ff5c090285d65d938558 differ diff --git a/storage/textures/348e44a4a3af0a15431c6fb656c62d273757dd500ee60aaaec5df064735a6a1f b/storage/textures/348e44a4a3af0a15431c6fb656c62d273757dd500ee60aaaec5df064735a6a1f new file mode 100755 index 0000000..9e729b5 Binary files /dev/null and b/storage/textures/348e44a4a3af0a15431c6fb656c62d273757dd500ee60aaaec5df064735a6a1f differ diff --git a/storage/textures/3508d94636b0a93228cfaf04ad800d39fea542b721ec1dca88adb29856e840d2 b/storage/textures/3508d94636b0a93228cfaf04ad800d39fea542b721ec1dca88adb29856e840d2 new file mode 100755 index 0000000..0358f75 Binary files /dev/null and b/storage/textures/3508d94636b0a93228cfaf04ad800d39fea542b721ec1dca88adb29856e840d2 differ diff --git a/storage/textures/357d829c660106c808730e633223559f91c76ce2358630087407f4afd52de88d b/storage/textures/357d829c660106c808730e633223559f91c76ce2358630087407f4afd52de88d new file mode 100644 index 0000000..04b594c Binary files /dev/null and b/storage/textures/357d829c660106c808730e633223559f91c76ce2358630087407f4afd52de88d differ diff --git a/storage/textures/35a34669f036b9bd1a09988d83d4b9d443f3622f08c2c5aa0cc24a76eb5195b6 b/storage/textures/35a34669f036b9bd1a09988d83d4b9d443f3622f08c2c5aa0cc24a76eb5195b6 new file mode 100755 index 0000000..87b9374 Binary files /dev/null and b/storage/textures/35a34669f036b9bd1a09988d83d4b9d443f3622f08c2c5aa0cc24a76eb5195b6 differ diff --git a/storage/textures/35c499b4b7ffcb362d6a0bad38a2ef25a30a5d82c58f9860a3873649df211195 b/storage/textures/35c499b4b7ffcb362d6a0bad38a2ef25a30a5d82c58f9860a3873649df211195 new file mode 100755 index 0000000..e9f8995 Binary files /dev/null and b/storage/textures/35c499b4b7ffcb362d6a0bad38a2ef25a30a5d82c58f9860a3873649df211195 differ diff --git a/storage/textures/35cb23f657a546cb6d9c4789681ed1d97f0a839afd4d1c78c4ad83c4b1c8a2df b/storage/textures/35cb23f657a546cb6d9c4789681ed1d97f0a839afd4d1c78c4ad83c4b1c8a2df new file mode 100755 index 0000000..128cb1e Binary files /dev/null and b/storage/textures/35cb23f657a546cb6d9c4789681ed1d97f0a839afd4d1c78c4ad83c4b1c8a2df differ diff --git a/storage/textures/35f4d62bf666fa25f32312b1db4448e01144b87d449f09d2c6b301bc39a9f110 b/storage/textures/35f4d62bf666fa25f32312b1db4448e01144b87d449f09d2c6b301bc39a9f110 new file mode 100755 index 0000000..493d6fc Binary files /dev/null and b/storage/textures/35f4d62bf666fa25f32312b1db4448e01144b87d449f09d2c6b301bc39a9f110 differ diff --git a/storage/textures/362b2ea27db807196b263ad7f1646c21e7d35ecfd73f513e44a7843a3aae3f63 b/storage/textures/362b2ea27db807196b263ad7f1646c21e7d35ecfd73f513e44a7843a3aae3f63 new file mode 100755 index 0000000..7b3b6f6 Binary files /dev/null and b/storage/textures/362b2ea27db807196b263ad7f1646c21e7d35ecfd73f513e44a7843a3aae3f63 differ diff --git a/storage/textures/3643ca6f533d8eca31fce37db6a0e52a656b9db67f0302b569b59bd0f1cecfb5 b/storage/textures/3643ca6f533d8eca31fce37db6a0e52a656b9db67f0302b569b59bd0f1cecfb5 new file mode 100755 index 0000000..f5082cb Binary files /dev/null and b/storage/textures/3643ca6f533d8eca31fce37db6a0e52a656b9db67f0302b569b59bd0f1cecfb5 differ diff --git a/storage/textures/367122a33b146c1b3a05f5ab7260acc6bd3d5dcbb0870f1f7a766b381c8d0555 b/storage/textures/367122a33b146c1b3a05f5ab7260acc6bd3d5dcbb0870f1f7a766b381c8d0555 new file mode 100755 index 0000000..0de73b3 Binary files /dev/null and b/storage/textures/367122a33b146c1b3a05f5ab7260acc6bd3d5dcbb0870f1f7a766b381c8d0555 differ diff --git a/storage/textures/36bde7aa52acc41eff74d3d99352028c3f07de1cfbf980eab89c788d4c144fcd b/storage/textures/36bde7aa52acc41eff74d3d99352028c3f07de1cfbf980eab89c788d4c144fcd new file mode 100644 index 0000000..dcecbf0 Binary files /dev/null and b/storage/textures/36bde7aa52acc41eff74d3d99352028c3f07de1cfbf980eab89c788d4c144fcd differ diff --git a/storage/textures/36c182630190a44c53a8bcb2b144e30fde83580f7157ac0b1e3e07fc4785bc3a b/storage/textures/36c182630190a44c53a8bcb2b144e30fde83580f7157ac0b1e3e07fc4785bc3a new file mode 100755 index 0000000..2fb1678 Binary files /dev/null and b/storage/textures/36c182630190a44c53a8bcb2b144e30fde83580f7157ac0b1e3e07fc4785bc3a differ diff --git a/storage/textures/372b62a47ab6a42add9666518290efcb11a7765c70fbdb342bca3f2ac9774d0f b/storage/textures/372b62a47ab6a42add9666518290efcb11a7765c70fbdb342bca3f2ac9774d0f new file mode 100644 index 0000000..97d2bfd Binary files /dev/null and b/storage/textures/372b62a47ab6a42add9666518290efcb11a7765c70fbdb342bca3f2ac9774d0f differ diff --git a/storage/textures/37355a7dca345810d0b58d0eddee8ef473b5aa94f9ed029401084e7235fd7204 b/storage/textures/37355a7dca345810d0b58d0eddee8ef473b5aa94f9ed029401084e7235fd7204 new file mode 100644 index 0000000..3e1e185 Binary files /dev/null and b/storage/textures/37355a7dca345810d0b58d0eddee8ef473b5aa94f9ed029401084e7235fd7204 differ diff --git a/storage/textures/3768f1200c936c734a223f7465ab24a1c7a83c2db0bc823ee04b48e18d7541d3 b/storage/textures/3768f1200c936c734a223f7465ab24a1c7a83c2db0bc823ee04b48e18d7541d3 new file mode 100644 index 0000000..909f8e0 Binary files /dev/null and b/storage/textures/3768f1200c936c734a223f7465ab24a1c7a83c2db0bc823ee04b48e18d7541d3 differ diff --git a/storage/textures/378d2a2146973fe1f07d76c4f62868ffcb17087ba37241f6fb6f2fc1ea0b8030 b/storage/textures/378d2a2146973fe1f07d76c4f62868ffcb17087ba37241f6fb6f2fc1ea0b8030 new file mode 100644 index 0000000..b2ee7b8 Binary files /dev/null and b/storage/textures/378d2a2146973fe1f07d76c4f62868ffcb17087ba37241f6fb6f2fc1ea0b8030 differ diff --git a/storage/textures/37ca14909fd9038c775c76d6017364cb1e4c3f2017d1f496e11ae81798fc2885 b/storage/textures/37ca14909fd9038c775c76d6017364cb1e4c3f2017d1f496e11ae81798fc2885 new file mode 100755 index 0000000..67d24ea Binary files /dev/null and b/storage/textures/37ca14909fd9038c775c76d6017364cb1e4c3f2017d1f496e11ae81798fc2885 differ diff --git a/storage/textures/37e9c6a71774ad39846f1920d1de40bcb6dd56bf81cec32e00a272f16778d4ea b/storage/textures/37e9c6a71774ad39846f1920d1de40bcb6dd56bf81cec32e00a272f16778d4ea new file mode 100755 index 0000000..e34635f Binary files /dev/null and b/storage/textures/37e9c6a71774ad39846f1920d1de40bcb6dd56bf81cec32e00a272f16778d4ea differ diff --git a/storage/textures/38354d7bc88f05e6e7f2743bf5e7fdd0f1d1bdc26774202522c4abc7997bf2d0 b/storage/textures/38354d7bc88f05e6e7f2743bf5e7fdd0f1d1bdc26774202522c4abc7997bf2d0 new file mode 100755 index 0000000..06633d4 Binary files /dev/null and b/storage/textures/38354d7bc88f05e6e7f2743bf5e7fdd0f1d1bdc26774202522c4abc7997bf2d0 differ diff --git a/storage/textures/3864fd298d2f56dfbd83e5fc3ee1a080a0492b952f64e532b9305ea0826d7748 b/storage/textures/3864fd298d2f56dfbd83e5fc3ee1a080a0492b952f64e532b9305ea0826d7748 new file mode 100755 index 0000000..308c9ba Binary files /dev/null and b/storage/textures/3864fd298d2f56dfbd83e5fc3ee1a080a0492b952f64e532b9305ea0826d7748 differ diff --git a/storage/textures/38a1975d1de3adb88f31201a1d17798b0321c6b06b6f8472ae6c25974e9fc035 b/storage/textures/38a1975d1de3adb88f31201a1d17798b0321c6b06b6f8472ae6c25974e9fc035 new file mode 100755 index 0000000..c3128dd Binary files /dev/null and b/storage/textures/38a1975d1de3adb88f31201a1d17798b0321c6b06b6f8472ae6c25974e9fc035 differ diff --git a/storage/textures/3923a66ab7018a7c00ffe9d91a474f0ed32fd82dd3399b6121e17dcd674e0575 b/storage/textures/3923a66ab7018a7c00ffe9d91a474f0ed32fd82dd3399b6121e17dcd674e0575 new file mode 100644 index 0000000..a663cc8 Binary files /dev/null and b/storage/textures/3923a66ab7018a7c00ffe9d91a474f0ed32fd82dd3399b6121e17dcd674e0575 differ diff --git a/storage/textures/3928a427ab8a42c4126189eaf94d14fa6f88c0fdafe9b3cf76ccd598419509f1 b/storage/textures/3928a427ab8a42c4126189eaf94d14fa6f88c0fdafe9b3cf76ccd598419509f1 new file mode 100644 index 0000000..ba0508a Binary files /dev/null and b/storage/textures/3928a427ab8a42c4126189eaf94d14fa6f88c0fdafe9b3cf76ccd598419509f1 differ diff --git a/storage/textures/393dd6261c30c18b88ad948473b3e4cb98cac1c22bae354a30a5d3704da53b15 b/storage/textures/393dd6261c30c18b88ad948473b3e4cb98cac1c22bae354a30a5d3704da53b15 new file mode 100755 index 0000000..01d6cfb Binary files /dev/null and b/storage/textures/393dd6261c30c18b88ad948473b3e4cb98cac1c22bae354a30a5d3704da53b15 differ diff --git a/storage/textures/39859867f7c65d75246be1ef4dcf48f8c7d1291357e1aafe535d627379cdb180 b/storage/textures/39859867f7c65d75246be1ef4dcf48f8c7d1291357e1aafe535d627379cdb180 new file mode 100755 index 0000000..9dc89e5 Binary files /dev/null and b/storage/textures/39859867f7c65d75246be1ef4dcf48f8c7d1291357e1aafe535d627379cdb180 differ diff --git a/storage/textures/39b5b8220bb5ea61521693ea1c45e0ff438ca7aa79a231b4231b3648b216506f b/storage/textures/39b5b8220bb5ea61521693ea1c45e0ff438ca7aa79a231b4231b3648b216506f new file mode 100644 index 0000000..59f9b3e Binary files /dev/null and b/storage/textures/39b5b8220bb5ea61521693ea1c45e0ff438ca7aa79a231b4231b3648b216506f differ diff --git a/storage/textures/39e66890084fbb872f861355d90fbb5bd382647310686fc95e6db7bd96492376 b/storage/textures/39e66890084fbb872f861355d90fbb5bd382647310686fc95e6db7bd96492376 new file mode 100644 index 0000000..a043321 Binary files /dev/null and b/storage/textures/39e66890084fbb872f861355d90fbb5bd382647310686fc95e6db7bd96492376 differ diff --git a/storage/textures/3a418c4b47a46fdb102dac0953638f79cebebe600b6df07bbea53db92a85a8d5 b/storage/textures/3a418c4b47a46fdb102dac0953638f79cebebe600b6df07bbea53db92a85a8d5 new file mode 100644 index 0000000..8fb6808 Binary files /dev/null and b/storage/textures/3a418c4b47a46fdb102dac0953638f79cebebe600b6df07bbea53db92a85a8d5 differ diff --git a/storage/textures/3a7787c68afb13a4db1451c874970576d1ab84119f902ac2d0011c0ec35db470 b/storage/textures/3a7787c68afb13a4db1451c874970576d1ab84119f902ac2d0011c0ec35db470 new file mode 100755 index 0000000..e36b3cf Binary files /dev/null and b/storage/textures/3a7787c68afb13a4db1451c874970576d1ab84119f902ac2d0011c0ec35db470 differ diff --git a/storage/textures/3aad0a4ab00495c1a5da33c77bae5fb2a75a4a81d90557030aab971c922381e8 b/storage/textures/3aad0a4ab00495c1a5da33c77bae5fb2a75a4a81d90557030aab971c922381e8 new file mode 100644 index 0000000..42aadb9 Binary files /dev/null and b/storage/textures/3aad0a4ab00495c1a5da33c77bae5fb2a75a4a81d90557030aab971c922381e8 differ diff --git a/storage/textures/3ac2b13546436b1cd4080cc2ca1206fae01fb0476992295b06b853843ff9d780 b/storage/textures/3ac2b13546436b1cd4080cc2ca1206fae01fb0476992295b06b853843ff9d780 new file mode 100755 index 0000000..e45a97b Binary files /dev/null and b/storage/textures/3ac2b13546436b1cd4080cc2ca1206fae01fb0476992295b06b853843ff9d780 differ diff --git a/storage/textures/3ae912772e29486d6d51f12dd620fbe6510385455d0932095a81f8cc774d9391 b/storage/textures/3ae912772e29486d6d51f12dd620fbe6510385455d0932095a81f8cc774d9391 new file mode 100755 index 0000000..824f820 Binary files /dev/null and b/storage/textures/3ae912772e29486d6d51f12dd620fbe6510385455d0932095a81f8cc774d9391 differ diff --git a/storage/textures/3b16685a317ae32573a8766dbb9877ee58d4cc5c694640a306aa60130a022c58 b/storage/textures/3b16685a317ae32573a8766dbb9877ee58d4cc5c694640a306aa60130a022c58 new file mode 100755 index 0000000..5ee7133 Binary files /dev/null and b/storage/textures/3b16685a317ae32573a8766dbb9877ee58d4cc5c694640a306aa60130a022c58 differ diff --git a/storage/textures/3b42040a7d4276b86e55293026a3b8efd748f0606f414c3b735553749f507873 b/storage/textures/3b42040a7d4276b86e55293026a3b8efd748f0606f414c3b735553749f507873 new file mode 100644 index 0000000..35a5d04 Binary files /dev/null and b/storage/textures/3b42040a7d4276b86e55293026a3b8efd748f0606f414c3b735553749f507873 differ diff --git a/storage/textures/3b96ad60ec514fda9c7cc4fa220602d493812b1da141ea6e285ac2988f174649 b/storage/textures/3b96ad60ec514fda9c7cc4fa220602d493812b1da141ea6e285ac2988f174649 new file mode 100644 index 0000000..8ba30f5 Binary files /dev/null and b/storage/textures/3b96ad60ec514fda9c7cc4fa220602d493812b1da141ea6e285ac2988f174649 differ diff --git a/storage/textures/3c0a8f73d9646116860ed5e365cac7d5747b475841165b89f0afd43eb746fb4d b/storage/textures/3c0a8f73d9646116860ed5e365cac7d5747b475841165b89f0afd43eb746fb4d new file mode 100644 index 0000000..ae7e206 Binary files /dev/null and b/storage/textures/3c0a8f73d9646116860ed5e365cac7d5747b475841165b89f0afd43eb746fb4d differ diff --git a/storage/textures/3c20aee493f47f284ba1ca1ab69d0df40cd883db604d976afc17df7c6f928a9f b/storage/textures/3c20aee493f47f284ba1ca1ab69d0df40cd883db604d976afc17df7c6f928a9f new file mode 100755 index 0000000..585b9c5 Binary files /dev/null and b/storage/textures/3c20aee493f47f284ba1ca1ab69d0df40cd883db604d976afc17df7c6f928a9f differ diff --git a/storage/textures/3c3b35401dfb116062e0e31258223ae31988331b8764af1e61502cd49ea0c7b5 b/storage/textures/3c3b35401dfb116062e0e31258223ae31988331b8764af1e61502cd49ea0c7b5 new file mode 100755 index 0000000..e551404 Binary files /dev/null and b/storage/textures/3c3b35401dfb116062e0e31258223ae31988331b8764af1e61502cd49ea0c7b5 differ diff --git a/storage/textures/3c8898d95dc6a5a1925c6ffa1713d58a2eb0bb371a5f15fab86183a30d58b5dc b/storage/textures/3c8898d95dc6a5a1925c6ffa1713d58a2eb0bb371a5f15fab86183a30d58b5dc new file mode 100755 index 0000000..beae77b Binary files /dev/null and b/storage/textures/3c8898d95dc6a5a1925c6ffa1713d58a2eb0bb371a5f15fab86183a30d58b5dc differ diff --git a/storage/textures/3cc2dc838c6f4566a24edb5c04ef3c62c0dfc12e00a0ff75ea0a5012a72b219a b/storage/textures/3cc2dc838c6f4566a24edb5c04ef3c62c0dfc12e00a0ff75ea0a5012a72b219a new file mode 100755 index 0000000..e6ea7e9 Binary files /dev/null and b/storage/textures/3cc2dc838c6f4566a24edb5c04ef3c62c0dfc12e00a0ff75ea0a5012a72b219a differ diff --git a/storage/textures/3cf2fe12ae946756e4b7768b776f08287a49ff23702ecbcbf4907596deec7d72 b/storage/textures/3cf2fe12ae946756e4b7768b776f08287a49ff23702ecbcbf4907596deec7d72 new file mode 100755 index 0000000..df800bc Binary files /dev/null and b/storage/textures/3cf2fe12ae946756e4b7768b776f08287a49ff23702ecbcbf4907596deec7d72 differ diff --git a/storage/textures/3d0667daa66aedda7c9fab5f2c56f6b683cf214e81053b4df89d4a0aec1b2838 b/storage/textures/3d0667daa66aedda7c9fab5f2c56f6b683cf214e81053b4df89d4a0aec1b2838 new file mode 100755 index 0000000..78a5a0f Binary files /dev/null and b/storage/textures/3d0667daa66aedda7c9fab5f2c56f6b683cf214e81053b4df89d4a0aec1b2838 differ diff --git a/storage/textures/3d27f24d9d4cc12d45821f4cdc31f0f90b2d7d649158d67350d82cb3ff332006 b/storage/textures/3d27f24d9d4cc12d45821f4cdc31f0f90b2d7d649158d67350d82cb3ff332006 new file mode 100644 index 0000000..535c46d Binary files /dev/null and b/storage/textures/3d27f24d9d4cc12d45821f4cdc31f0f90b2d7d649158d67350d82cb3ff332006 differ diff --git a/storage/textures/3d9823e990270828d78f572aa939a41f1b567c07c7ca5b5a57fabc8b705cef28 b/storage/textures/3d9823e990270828d78f572aa939a41f1b567c07c7ca5b5a57fabc8b705cef28 new file mode 100755 index 0000000..a18b835 Binary files /dev/null and b/storage/textures/3d9823e990270828d78f572aa939a41f1b567c07c7ca5b5a57fabc8b705cef28 differ diff --git a/storage/textures/3da68d08460861b23c5abc64d0731b4c431e487f97fca9ed4938ec1cf432ccdd b/storage/textures/3da68d08460861b23c5abc64d0731b4c431e487f97fca9ed4938ec1cf432ccdd new file mode 100644 index 0000000..0a1dcb6 Binary files /dev/null and b/storage/textures/3da68d08460861b23c5abc64d0731b4c431e487f97fca9ed4938ec1cf432ccdd differ diff --git a/storage/textures/3ddca8d04949256fba4099ad61d8f364dbbbd46bb5715a0971b0048ab3aa505f b/storage/textures/3ddca8d04949256fba4099ad61d8f364dbbbd46bb5715a0971b0048ab3aa505f new file mode 100644 index 0000000..4a7fd4e Binary files /dev/null and b/storage/textures/3ddca8d04949256fba4099ad61d8f364dbbbd46bb5715a0971b0048ab3aa505f differ diff --git a/storage/textures/3dde290f7481d34f97fa00cbcd3b07b374f917e9fb92a1b06c4efd785fef49ab b/storage/textures/3dde290f7481d34f97fa00cbcd3b07b374f917e9fb92a1b06c4efd785fef49ab new file mode 100755 index 0000000..3a3312e Binary files /dev/null and b/storage/textures/3dde290f7481d34f97fa00cbcd3b07b374f917e9fb92a1b06c4efd785fef49ab differ diff --git a/storage/textures/3e79c634e77af74a565fc72b48f7898557af4f1e7d773f019a030182043f8568 b/storage/textures/3e79c634e77af74a565fc72b48f7898557af4f1e7d773f019a030182043f8568 new file mode 100644 index 0000000..f51f2a1 Binary files /dev/null and b/storage/textures/3e79c634e77af74a565fc72b48f7898557af4f1e7d773f019a030182043f8568 differ diff --git a/storage/textures/3e9f0a700bae12166420a965ed9f3ce32c84b846e3869222a8c18710bfd7d940 b/storage/textures/3e9f0a700bae12166420a965ed9f3ce32c84b846e3869222a8c18710bfd7d940 new file mode 100755 index 0000000..91bb7aa Binary files /dev/null and b/storage/textures/3e9f0a700bae12166420a965ed9f3ce32c84b846e3869222a8c18710bfd7d940 differ diff --git a/storage/textures/3f286310412e3d62de1abad7db45cb5df330a79c26563b918e0eaf0d8a19611c b/storage/textures/3f286310412e3d62de1abad7db45cb5df330a79c26563b918e0eaf0d8a19611c new file mode 100755 index 0000000..b46fa02 Binary files /dev/null and b/storage/textures/3f286310412e3d62de1abad7db45cb5df330a79c26563b918e0eaf0d8a19611c differ diff --git a/storage/textures/3f2d736e67c767380ad94eb63ad3e385255693470b44caacc7395807ed67f8d9 b/storage/textures/3f2d736e67c767380ad94eb63ad3e385255693470b44caacc7395807ed67f8d9 new file mode 100755 index 0000000..4648dba Binary files /dev/null and b/storage/textures/3f2d736e67c767380ad94eb63ad3e385255693470b44caacc7395807ed67f8d9 differ diff --git a/storage/textures/3f367e63c3c63d489b478475a9a05b8f54269bf4db8aba3296bde33ff890eb3d b/storage/textures/3f367e63c3c63d489b478475a9a05b8f54269bf4db8aba3296bde33ff890eb3d new file mode 100755 index 0000000..83cb55b Binary files /dev/null and b/storage/textures/3f367e63c3c63d489b478475a9a05b8f54269bf4db8aba3296bde33ff890eb3d differ diff --git a/storage/textures/3f6d9f005e94600314604ceb7bb47448a6f99de7095b929b33b9940d16d13c34 b/storage/textures/3f6d9f005e94600314604ceb7bb47448a6f99de7095b929b33b9940d16d13c34 new file mode 100644 index 0000000..36c9014 Binary files /dev/null and b/storage/textures/3f6d9f005e94600314604ceb7bb47448a6f99de7095b929b33b9940d16d13c34 differ diff --git a/storage/textures/3f7718399d5b7beae022c99b1ada56624010af4be3a07982c37a38f64b9c1e42 b/storage/textures/3f7718399d5b7beae022c99b1ada56624010af4be3a07982c37a38f64b9c1e42 new file mode 100755 index 0000000..c1447f4 Binary files /dev/null and b/storage/textures/3f7718399d5b7beae022c99b1ada56624010af4be3a07982c37a38f64b9c1e42 differ diff --git a/storage/textures/3f9afa2d5e725080f334f0b8ed76494c856ffed4e1763312213da3a56ed1e79f b/storage/textures/3f9afa2d5e725080f334f0b8ed76494c856ffed4e1763312213da3a56ed1e79f new file mode 100755 index 0000000..fdaec8a Binary files /dev/null and b/storage/textures/3f9afa2d5e725080f334f0b8ed76494c856ffed4e1763312213da3a56ed1e79f differ diff --git a/storage/textures/3fa7a186e2a0d7539dd281d418d7191fdf5d763afe3bcbb7417eff3b55cbffea b/storage/textures/3fa7a186e2a0d7539dd281d418d7191fdf5d763afe3bcbb7417eff3b55cbffea new file mode 100755 index 0000000..5191f2d Binary files /dev/null and b/storage/textures/3fa7a186e2a0d7539dd281d418d7191fdf5d763afe3bcbb7417eff3b55cbffea differ diff --git a/storage/textures/3ff26185ebf59ca149e02198d91e1d9f9812eb8db83e47095f5b05e8e0706850 b/storage/textures/3ff26185ebf59ca149e02198d91e1d9f9812eb8db83e47095f5b05e8e0706850 new file mode 100644 index 0000000..f052f63 Binary files /dev/null and b/storage/textures/3ff26185ebf59ca149e02198d91e1d9f9812eb8db83e47095f5b05e8e0706850 differ diff --git a/storage/textures/4036c7b4ac9c49e017c1dbfba8a2ae4324fe00d04a8607d75c91c427b6bd216f b/storage/textures/4036c7b4ac9c49e017c1dbfba8a2ae4324fe00d04a8607d75c91c427b6bd216f new file mode 100644 index 0000000..e44aacd Binary files /dev/null and b/storage/textures/4036c7b4ac9c49e017c1dbfba8a2ae4324fe00d04a8607d75c91c427b6bd216f differ diff --git a/storage/textures/40857ae0c4ebaf7bdcfaaa4d7f44be1459a5396dd694eb7e335b9da58ffc0c37 b/storage/textures/40857ae0c4ebaf7bdcfaaa4d7f44be1459a5396dd694eb7e335b9da58ffc0c37 new file mode 100755 index 0000000..5f92bba Binary files /dev/null and b/storage/textures/40857ae0c4ebaf7bdcfaaa4d7f44be1459a5396dd694eb7e335b9da58ffc0c37 differ diff --git a/storage/textures/40c642e9d3fd3773ff7b3eff61b24039241dcf1c0ef8f3af56480f28791f14b4 b/storage/textures/40c642e9d3fd3773ff7b3eff61b24039241dcf1c0ef8f3af56480f28791f14b4 new file mode 100755 index 0000000..40b2941 Binary files /dev/null and b/storage/textures/40c642e9d3fd3773ff7b3eff61b24039241dcf1c0ef8f3af56480f28791f14b4 differ diff --git a/storage/textures/40e4323175c65a3460605c7604bfc736fb4d1a17301c843943ed60ec357324f7 b/storage/textures/40e4323175c65a3460605c7604bfc736fb4d1a17301c843943ed60ec357324f7 new file mode 100755 index 0000000..89bbf35 Binary files /dev/null and b/storage/textures/40e4323175c65a3460605c7604bfc736fb4d1a17301c843943ed60ec357324f7 differ diff --git a/storage/textures/4143eaa1a2696931924a77a77efb092b8d658fc505a13a9cd7b849daa4ba62a8 b/storage/textures/4143eaa1a2696931924a77a77efb092b8d658fc505a13a9cd7b849daa4ba62a8 new file mode 100755 index 0000000..3c21603 Binary files /dev/null and b/storage/textures/4143eaa1a2696931924a77a77efb092b8d658fc505a13a9cd7b849daa4ba62a8 differ diff --git a/storage/textures/4180b0300b0628a430367f2f5ee1a608b133b9d187515f6e917a602d2c0f8a9e b/storage/textures/4180b0300b0628a430367f2f5ee1a608b133b9d187515f6e917a602d2c0f8a9e new file mode 100644 index 0000000..cdf5951 Binary files /dev/null and b/storage/textures/4180b0300b0628a430367f2f5ee1a608b133b9d187515f6e917a602d2c0f8a9e differ diff --git a/storage/textures/418f719192d9d119e266a0d95f6da78a933cd7a095ad67d3b0f426cbf5ecb613 b/storage/textures/418f719192d9d119e266a0d95f6da78a933cd7a095ad67d3b0f426cbf5ecb613 new file mode 100755 index 0000000..500cc5c Binary files /dev/null and b/storage/textures/418f719192d9d119e266a0d95f6da78a933cd7a095ad67d3b0f426cbf5ecb613 differ diff --git a/storage/textures/41a1c8b4970d93c3e7a512c30cde395f9f1192fc6b61ba3b575ba828a2f742b6 b/storage/textures/41a1c8b4970d93c3e7a512c30cde395f9f1192fc6b61ba3b575ba828a2f742b6 new file mode 100755 index 0000000..4aefb23 Binary files /dev/null and b/storage/textures/41a1c8b4970d93c3e7a512c30cde395f9f1192fc6b61ba3b575ba828a2f742b6 differ diff --git a/storage/textures/41b29f29438986dde2e0086d7a568801cc710c2c1824b186ff91dce98c8c4832 b/storage/textures/41b29f29438986dde2e0086d7a568801cc710c2c1824b186ff91dce98c8c4832 new file mode 100755 index 0000000..eb15f88 Binary files /dev/null and b/storage/textures/41b29f29438986dde2e0086d7a568801cc710c2c1824b186ff91dce98c8c4832 differ diff --git a/storage/textures/41e5c2f4da13eded82c1e5678842fa9927abfc66146be81d92c7604da1572f7a b/storage/textures/41e5c2f4da13eded82c1e5678842fa9927abfc66146be81d92c7604da1572f7a new file mode 100755 index 0000000..e5c02aa Binary files /dev/null and b/storage/textures/41e5c2f4da13eded82c1e5678842fa9927abfc66146be81d92c7604da1572f7a differ diff --git a/storage/textures/4224aae0745bd0493497a69852dd8435bc27c6ac54aba4a416a0520b7c3de4b3 b/storage/textures/4224aae0745bd0493497a69852dd8435bc27c6ac54aba4a416a0520b7c3de4b3 new file mode 100644 index 0000000..ac6520a Binary files /dev/null and b/storage/textures/4224aae0745bd0493497a69852dd8435bc27c6ac54aba4a416a0520b7c3de4b3 differ diff --git a/storage/textures/422ca0fc8435e59d38bd5f83a8dca0d72950760808dbe369dc2e6e80c3a6a50f b/storage/textures/422ca0fc8435e59d38bd5f83a8dca0d72950760808dbe369dc2e6e80c3a6a50f new file mode 100644 index 0000000..7b1d90a Binary files /dev/null and b/storage/textures/422ca0fc8435e59d38bd5f83a8dca0d72950760808dbe369dc2e6e80c3a6a50f differ diff --git a/storage/textures/427e50212248f47dda4900879d705bb93172464cdf260d0c110fdfac204073a6 b/storage/textures/427e50212248f47dda4900879d705bb93172464cdf260d0c110fdfac204073a6 new file mode 100755 index 0000000..b39412b Binary files /dev/null and b/storage/textures/427e50212248f47dda4900879d705bb93172464cdf260d0c110fdfac204073a6 differ diff --git a/storage/textures/434ccdbbc4781989e8c377f359e1a29c2b25b6ed75e2b8089f7dd70de3896f04 b/storage/textures/434ccdbbc4781989e8c377f359e1a29c2b25b6ed75e2b8089f7dd70de3896f04 new file mode 100755 index 0000000..4928b6b Binary files /dev/null and b/storage/textures/434ccdbbc4781989e8c377f359e1a29c2b25b6ed75e2b8089f7dd70de3896f04 differ diff --git a/storage/textures/4375620e3737ed14c679b864169faf0ee730f0f457b340afcc1ec3c4eab68da4 b/storage/textures/4375620e3737ed14c679b864169faf0ee730f0f457b340afcc1ec3c4eab68da4 new file mode 100755 index 0000000..338f7ca Binary files /dev/null and b/storage/textures/4375620e3737ed14c679b864169faf0ee730f0f457b340afcc1ec3c4eab68da4 differ diff --git a/storage/textures/438246aba5ae41c63aa32f152abe39e5726c25ec41161a798e8155890a9604c7 b/storage/textures/438246aba5ae41c63aa32f152abe39e5726c25ec41161a798e8155890a9604c7 new file mode 100755 index 0000000..7c23979 Binary files /dev/null and b/storage/textures/438246aba5ae41c63aa32f152abe39e5726c25ec41161a798e8155890a9604c7 differ diff --git a/storage/textures/43a5feedc8a0bb40fcf537d5755f43aa52fb4bbaf1f0fcf48bcb0cf38a01b8e8 b/storage/textures/43a5feedc8a0bb40fcf537d5755f43aa52fb4bbaf1f0fcf48bcb0cf38a01b8e8 new file mode 100755 index 0000000..087abbf Binary files /dev/null and b/storage/textures/43a5feedc8a0bb40fcf537d5755f43aa52fb4bbaf1f0fcf48bcb0cf38a01b8e8 differ diff --git a/storage/textures/43abfc71744ac43b80b7187f9d8ed3e8487f977e619fd498a8f41e8caf89ec83 b/storage/textures/43abfc71744ac43b80b7187f9d8ed3e8487f977e619fd498a8f41e8caf89ec83 new file mode 100644 index 0000000..d0ca1f1 Binary files /dev/null and b/storage/textures/43abfc71744ac43b80b7187f9d8ed3e8487f977e619fd498a8f41e8caf89ec83 differ diff --git a/storage/textures/43f379b3a51774f0e2c9407ec57be5391661e86f30815ceede4bc6b220433f39 b/storage/textures/43f379b3a51774f0e2c9407ec57be5391661e86f30815ceede4bc6b220433f39 new file mode 100755 index 0000000..e28d9a7 Binary files /dev/null and b/storage/textures/43f379b3a51774f0e2c9407ec57be5391661e86f30815ceede4bc6b220433f39 differ diff --git a/storage/textures/43f537fb81de9cef2105b17e1d3b21cd7b2089b4a9b1c9704216daaaf7fbfa14 b/storage/textures/43f537fb81de9cef2105b17e1d3b21cd7b2089b4a9b1c9704216daaaf7fbfa14 new file mode 100755 index 0000000..e4adfce Binary files /dev/null and b/storage/textures/43f537fb81de9cef2105b17e1d3b21cd7b2089b4a9b1c9704216daaaf7fbfa14 differ diff --git a/storage/textures/4401e856e21c43c43004bd7014a0d1a5387bb9cf7395101469382d62cef012e5 b/storage/textures/4401e856e21c43c43004bd7014a0d1a5387bb9cf7395101469382d62cef012e5 new file mode 100644 index 0000000..bd17b00 Binary files /dev/null and b/storage/textures/4401e856e21c43c43004bd7014a0d1a5387bb9cf7395101469382d62cef012e5 differ diff --git a/storage/textures/44761988acf4a89eed5883901c5e8fba68fc07703fec466a0511ab396495e3ec b/storage/textures/44761988acf4a89eed5883901c5e8fba68fc07703fec466a0511ab396495e3ec new file mode 100644 index 0000000..8d2f43f Binary files /dev/null and b/storage/textures/44761988acf4a89eed5883901c5e8fba68fc07703fec466a0511ab396495e3ec differ diff --git a/storage/textures/44e30a79187396dacc8b9b41c6453ba5111baa0b88839803a3a8a8e0930fb238 b/storage/textures/44e30a79187396dacc8b9b41c6453ba5111baa0b88839803a3a8a8e0930fb238 new file mode 100755 index 0000000..27b3cea Binary files /dev/null and b/storage/textures/44e30a79187396dacc8b9b41c6453ba5111baa0b88839803a3a8a8e0930fb238 differ diff --git a/storage/textures/4539cbd63becf93aea3a173b65275c1f4dc008ca2a679380b0a2cf7a7c85deaa b/storage/textures/4539cbd63becf93aea3a173b65275c1f4dc008ca2a679380b0a2cf7a7c85deaa new file mode 100644 index 0000000..23bf23e Binary files /dev/null and b/storage/textures/4539cbd63becf93aea3a173b65275c1f4dc008ca2a679380b0a2cf7a7c85deaa differ diff --git a/storage/textures/454f43f7504d8f078d00bf0b37c1b41ff67b021d00c0dcbd0a04d48afcb0cd1f b/storage/textures/454f43f7504d8f078d00bf0b37c1b41ff67b021d00c0dcbd0a04d48afcb0cd1f new file mode 100755 index 0000000..5b50555 Binary files /dev/null and b/storage/textures/454f43f7504d8f078d00bf0b37c1b41ff67b021d00c0dcbd0a04d48afcb0cd1f differ diff --git a/storage/textures/4589a0b3d7f3071afcf47ebcaf6bc2994bc1811a13f6f949d622df3b969654a2 b/storage/textures/4589a0b3d7f3071afcf47ebcaf6bc2994bc1811a13f6f949d622df3b969654a2 new file mode 100644 index 0000000..1d63df8 Binary files /dev/null and b/storage/textures/4589a0b3d7f3071afcf47ebcaf6bc2994bc1811a13f6f949d622df3b969654a2 differ diff --git a/storage/textures/45dcedd45bcf4ab9a8b93d7241cf05fb48d638d1b16fc28fc46d162fc22cbd13 b/storage/textures/45dcedd45bcf4ab9a8b93d7241cf05fb48d638d1b16fc28fc46d162fc22cbd13 new file mode 100644 index 0000000..5d0952e Binary files /dev/null and b/storage/textures/45dcedd45bcf4ab9a8b93d7241cf05fb48d638d1b16fc28fc46d162fc22cbd13 differ diff --git a/storage/textures/464c5dbf043450729fd2f6af7346988a746024ed27e349f89dc34c1235b59ee5 b/storage/textures/464c5dbf043450729fd2f6af7346988a746024ed27e349f89dc34c1235b59ee5 new file mode 100644 index 0000000..0b7bdea Binary files /dev/null and b/storage/textures/464c5dbf043450729fd2f6af7346988a746024ed27e349f89dc34c1235b59ee5 differ diff --git a/storage/textures/4657a442479ef25f687d8296d1408a81e2477ccba95c2130fa7c01e757f8e24e b/storage/textures/4657a442479ef25f687d8296d1408a81e2477ccba95c2130fa7c01e757f8e24e new file mode 100644 index 0000000..d74c344 Binary files /dev/null and b/storage/textures/4657a442479ef25f687d8296d1408a81e2477ccba95c2130fa7c01e757f8e24e differ diff --git a/storage/textures/4680ca600fc8bcf466df3a4c4882af6fc291ef523c7a8573eb7fdd2fc2e26b60 b/storage/textures/4680ca600fc8bcf466df3a4c4882af6fc291ef523c7a8573eb7fdd2fc2e26b60 new file mode 100644 index 0000000..d9c4f66 Binary files /dev/null and b/storage/textures/4680ca600fc8bcf466df3a4c4882af6fc291ef523c7a8573eb7fdd2fc2e26b60 differ diff --git a/storage/textures/46af25d83f39e964af60ee6c087090081685d966422ce37ab1765da343100e04 b/storage/textures/46af25d83f39e964af60ee6c087090081685d966422ce37ab1765da343100e04 new file mode 100755 index 0000000..bf4dfdf Binary files /dev/null and b/storage/textures/46af25d83f39e964af60ee6c087090081685d966422ce37ab1765da343100e04 differ diff --git a/storage/textures/46dba4e91f071e59f7bdcefb1948228e4de708e095b8a56411588dddedc6d5ac b/storage/textures/46dba4e91f071e59f7bdcefb1948228e4de708e095b8a56411588dddedc6d5ac new file mode 100644 index 0000000..4738f8b Binary files /dev/null and b/storage/textures/46dba4e91f071e59f7bdcefb1948228e4de708e095b8a56411588dddedc6d5ac differ diff --git a/storage/textures/47340d3065a922bd748211227f5c8aad24797813044f2ca659faec3284767676 b/storage/textures/47340d3065a922bd748211227f5c8aad24797813044f2ca659faec3284767676 new file mode 100644 index 0000000..eed3bcc Binary files /dev/null and b/storage/textures/47340d3065a922bd748211227f5c8aad24797813044f2ca659faec3284767676 differ diff --git a/storage/textures/47412b4d3ea89626616f0f143bfc467ecda95a1222c7bf48dc350573ee2bcf9e b/storage/textures/47412b4d3ea89626616f0f143bfc467ecda95a1222c7bf48dc350573ee2bcf9e new file mode 100755 index 0000000..dcf75f2 Binary files /dev/null and b/storage/textures/47412b4d3ea89626616f0f143bfc467ecda95a1222c7bf48dc350573ee2bcf9e differ diff --git a/storage/textures/47e0811f46346150cbca3f14c64503d1f05e8d5448c921dc22896f6b839d5af8 b/storage/textures/47e0811f46346150cbca3f14c64503d1f05e8d5448c921dc22896f6b839d5af8 new file mode 100755 index 0000000..2b164e3 Binary files /dev/null and b/storage/textures/47e0811f46346150cbca3f14c64503d1f05e8d5448c921dc22896f6b839d5af8 differ diff --git a/storage/textures/47fa82e136f7b5ecf69490b5f4b29b0f278e0ce87c6d92ac36699bb0ec391535 b/storage/textures/47fa82e136f7b5ecf69490b5f4b29b0f278e0ce87c6d92ac36699bb0ec391535 new file mode 100755 index 0000000..0ed179d Binary files /dev/null and b/storage/textures/47fa82e136f7b5ecf69490b5f4b29b0f278e0ce87c6d92ac36699bb0ec391535 differ diff --git a/storage/textures/47ff2a46e652a3298cf5c6ce92c742f8593bd7c1792c3dcf407cfa8ac9c2a0a6 b/storage/textures/47ff2a46e652a3298cf5c6ce92c742f8593bd7c1792c3dcf407cfa8ac9c2a0a6 new file mode 100755 index 0000000..61d7bbb Binary files /dev/null and b/storage/textures/47ff2a46e652a3298cf5c6ce92c742f8593bd7c1792c3dcf407cfa8ac9c2a0a6 differ diff --git a/storage/textures/483cca7636c57690beaef033f4e506f579b65e97fa978367b66bd84ab392244e b/storage/textures/483cca7636c57690beaef033f4e506f579b65e97fa978367b66bd84ab392244e new file mode 100755 index 0000000..26f1a21 Binary files /dev/null and b/storage/textures/483cca7636c57690beaef033f4e506f579b65e97fa978367b66bd84ab392244e differ diff --git a/storage/textures/485ea91a2840ca00369ce69e38f86c752630f088604923853e943727184f5cde b/storage/textures/485ea91a2840ca00369ce69e38f86c752630f088604923853e943727184f5cde new file mode 100644 index 0000000..a85bf9f Binary files /dev/null and b/storage/textures/485ea91a2840ca00369ce69e38f86c752630f088604923853e943727184f5cde differ diff --git a/storage/textures/48b72ce8817de393f5e6572368c64ac6c30d3a13af69c21d90ce0423f929f447 b/storage/textures/48b72ce8817de393f5e6572368c64ac6c30d3a13af69c21d90ce0423f929f447 new file mode 100644 index 0000000..1acb6d0 Binary files /dev/null and b/storage/textures/48b72ce8817de393f5e6572368c64ac6c30d3a13af69c21d90ce0423f929f447 differ diff --git a/storage/textures/48e9c102faa58a5a891694aacda164248bfaa739f183c3b1797510a09539f9ab b/storage/textures/48e9c102faa58a5a891694aacda164248bfaa739f183c3b1797510a09539f9ab new file mode 100644 index 0000000..0545c00 Binary files /dev/null and b/storage/textures/48e9c102faa58a5a891694aacda164248bfaa739f183c3b1797510a09539f9ab differ diff --git a/storage/textures/48edaa01a122211c76ab2bd7e999f50be4d58a0053f6ceb71af2f58751a0f691 b/storage/textures/48edaa01a122211c76ab2bd7e999f50be4d58a0053f6ceb71af2f58751a0f691 new file mode 100755 index 0000000..35791ce Binary files /dev/null and b/storage/textures/48edaa01a122211c76ab2bd7e999f50be4d58a0053f6ceb71af2f58751a0f691 differ diff --git a/storage/textures/490b44fa088922f14678b2315785414854d82ab6e93fec9c62da8b013ace79cd b/storage/textures/490b44fa088922f14678b2315785414854d82ab6e93fec9c62da8b013ace79cd new file mode 100755 index 0000000..9d7d409 Binary files /dev/null and b/storage/textures/490b44fa088922f14678b2315785414854d82ab6e93fec9c62da8b013ace79cd differ diff --git a/storage/textures/4950c0ae52ec5e6a55507ee49fe4748dd8c8143b90ab53c801551032446f3283 b/storage/textures/4950c0ae52ec5e6a55507ee49fe4748dd8c8143b90ab53c801551032446f3283 new file mode 100644 index 0000000..f0b75a9 Binary files /dev/null and b/storage/textures/4950c0ae52ec5e6a55507ee49fe4748dd8c8143b90ab53c801551032446f3283 differ diff --git a/storage/textures/49da7362996bea5d64613949492bf1e2e49e3737688848b82fbf9bb9b97e6f07 b/storage/textures/49da7362996bea5d64613949492bf1e2e49e3737688848b82fbf9bb9b97e6f07 new file mode 100755 index 0000000..893a245 Binary files /dev/null and b/storage/textures/49da7362996bea5d64613949492bf1e2e49e3737688848b82fbf9bb9b97e6f07 differ diff --git a/storage/textures/49fde66fa5139e75326f82c90c3c99207b671abfcef3d39ecb6c1e7e4556edda b/storage/textures/49fde66fa5139e75326f82c90c3c99207b671abfcef3d39ecb6c1e7e4556edda new file mode 100755 index 0000000..48825bd Binary files /dev/null and b/storage/textures/49fde66fa5139e75326f82c90c3c99207b671abfcef3d39ecb6c1e7e4556edda differ diff --git a/storage/textures/4a08a04c88bfd173126e3fd3b092656147c441fc5f7df567b63e5fcc1462ecd7 b/storage/textures/4a08a04c88bfd173126e3fd3b092656147c441fc5f7df567b63e5fcc1462ecd7 new file mode 100755 index 0000000..aa38472 Binary files /dev/null and b/storage/textures/4a08a04c88bfd173126e3fd3b092656147c441fc5f7df567b63e5fcc1462ecd7 differ diff --git a/storage/textures/4ac36fad4c34f26a0e14fbc2e57072fe0b3d113b8ed1eb5d4311ba65eb089c88 b/storage/textures/4ac36fad4c34f26a0e14fbc2e57072fe0b3d113b8ed1eb5d4311ba65eb089c88 new file mode 100755 index 0000000..d714fda Binary files /dev/null and b/storage/textures/4ac36fad4c34f26a0e14fbc2e57072fe0b3d113b8ed1eb5d4311ba65eb089c88 differ diff --git a/storage/textures/4b8f24c05e0763f1c03c3ee327afe3285d1802d368868b6c98f0ef0c5c4346e5 b/storage/textures/4b8f24c05e0763f1c03c3ee327afe3285d1802d368868b6c98f0ef0c5c4346e5 new file mode 100755 index 0000000..5f746d0 Binary files /dev/null and b/storage/textures/4b8f24c05e0763f1c03c3ee327afe3285d1802d368868b6c98f0ef0c5c4346e5 differ diff --git a/storage/textures/4badc0aed1c1a8043c6efb3e1d766d413d5a3c0c0fec25def7fda30a12a4cff4 b/storage/textures/4badc0aed1c1a8043c6efb3e1d766d413d5a3c0c0fec25def7fda30a12a4cff4 new file mode 100644 index 0000000..11f7e0d Binary files /dev/null and b/storage/textures/4badc0aed1c1a8043c6efb3e1d766d413d5a3c0c0fec25def7fda30a12a4cff4 differ diff --git a/storage/textures/4d4505c73e484488e218c85a832eab90925edb6d461f901a04c698d3bbf33575 b/storage/textures/4d4505c73e484488e218c85a832eab90925edb6d461f901a04c698d3bbf33575 new file mode 100755 index 0000000..ef00f24 Binary files /dev/null and b/storage/textures/4d4505c73e484488e218c85a832eab90925edb6d461f901a04c698d3bbf33575 differ diff --git a/storage/textures/4dae02388a49824aee4faca4cbe6c46c007b3ea1af816e12e465ca9b63fb241b b/storage/textures/4dae02388a49824aee4faca4cbe6c46c007b3ea1af816e12e465ca9b63fb241b new file mode 100755 index 0000000..40e38e9 Binary files /dev/null and b/storage/textures/4dae02388a49824aee4faca4cbe6c46c007b3ea1af816e12e465ca9b63fb241b differ diff --git a/storage/textures/4de6c08673e0137367883b00e7a392dcf60ed05c3c1e2d45a0f7bb74596b6d13 b/storage/textures/4de6c08673e0137367883b00e7a392dcf60ed05c3c1e2d45a0f7bb74596b6d13 new file mode 100644 index 0000000..395734b Binary files /dev/null and b/storage/textures/4de6c08673e0137367883b00e7a392dcf60ed05c3c1e2d45a0f7bb74596b6d13 differ diff --git a/storage/textures/4df9c743a0b5092326a9c49f7210d5bc85f66f97492df6882b4e1f15db8be210 b/storage/textures/4df9c743a0b5092326a9c49f7210d5bc85f66f97492df6882b4e1f15db8be210 new file mode 100755 index 0000000..095bbb9 Binary files /dev/null and b/storage/textures/4df9c743a0b5092326a9c49f7210d5bc85f66f97492df6882b4e1f15db8be210 differ diff --git a/storage/textures/4e0020616b834e763901a2c63d26ae84e0af6bdfd580038773f02494744611c4 b/storage/textures/4e0020616b834e763901a2c63d26ae84e0af6bdfd580038773f02494744611c4 new file mode 100755 index 0000000..db7e8b5 Binary files /dev/null and b/storage/textures/4e0020616b834e763901a2c63d26ae84e0af6bdfd580038773f02494744611c4 differ diff --git a/storage/textures/4e0d1f3179edc9e7330a746d65b40b9f1ef2bb39850600aa79c673d5b3427221 b/storage/textures/4e0d1f3179edc9e7330a746d65b40b9f1ef2bb39850600aa79c673d5b3427221 new file mode 100755 index 0000000..c8569f1 Binary files /dev/null and b/storage/textures/4e0d1f3179edc9e7330a746d65b40b9f1ef2bb39850600aa79c673d5b3427221 differ diff --git a/storage/textures/4e4540e2555fef66784ff979e521d3d3abe8274451f3acb68b7b0793ea039429 b/storage/textures/4e4540e2555fef66784ff979e521d3d3abe8274451f3acb68b7b0793ea039429 new file mode 100755 index 0000000..6c16881 Binary files /dev/null and b/storage/textures/4e4540e2555fef66784ff979e521d3d3abe8274451f3acb68b7b0793ea039429 differ diff --git a/storage/textures/4e5944958a0324a381c865006d276977172f771d7d00e0bbcc3effa863ded488 b/storage/textures/4e5944958a0324a381c865006d276977172f771d7d00e0bbcc3effa863ded488 new file mode 100644 index 0000000..6add32a Binary files /dev/null and b/storage/textures/4e5944958a0324a381c865006d276977172f771d7d00e0bbcc3effa863ded488 differ diff --git a/storage/textures/4e76ebac549e8146bede87d2c9df02531ffc29f42a7af6aac3afe947babb7693 b/storage/textures/4e76ebac549e8146bede87d2c9df02531ffc29f42a7af6aac3afe947babb7693 new file mode 100755 index 0000000..b61ffbc Binary files /dev/null and b/storage/textures/4e76ebac549e8146bede87d2c9df02531ffc29f42a7af6aac3afe947babb7693 differ diff --git a/storage/textures/4f3fcbde701830654f56d73297d65c4511a11e5b0cfd90fd2b3e8aba544545e2 b/storage/textures/4f3fcbde701830654f56d73297d65c4511a11e5b0cfd90fd2b3e8aba544545e2 new file mode 100755 index 0000000..802be35 Binary files /dev/null and b/storage/textures/4f3fcbde701830654f56d73297d65c4511a11e5b0cfd90fd2b3e8aba544545e2 differ diff --git a/storage/textures/4f4f555fa2d0268ca26cf575f750d8dcfa3da1711c0c72e8f248283607fdb8e7 b/storage/textures/4f4f555fa2d0268ca26cf575f750d8dcfa3da1711c0c72e8f248283607fdb8e7 new file mode 100755 index 0000000..f5155b2 Binary files /dev/null and b/storage/textures/4f4f555fa2d0268ca26cf575f750d8dcfa3da1711c0c72e8f248283607fdb8e7 differ diff --git a/storage/textures/4f78237b5d3df8200031c178f4fee634056d00e10892cbe76510c43d81a15793 b/storage/textures/4f78237b5d3df8200031c178f4fee634056d00e10892cbe76510c43d81a15793 new file mode 100644 index 0000000..68cea25 Binary files /dev/null and b/storage/textures/4f78237b5d3df8200031c178f4fee634056d00e10892cbe76510c43d81a15793 differ diff --git a/storage/textures/4f9551927debd2f0692cc2ff4c325fe6824051bf19f5c6651e7aa6a34cbec40d b/storage/textures/4f9551927debd2f0692cc2ff4c325fe6824051bf19f5c6651e7aa6a34cbec40d new file mode 100644 index 0000000..f2a9bff Binary files /dev/null and b/storage/textures/4f9551927debd2f0692cc2ff4c325fe6824051bf19f5c6651e7aa6a34cbec40d differ diff --git a/storage/textures/4fe09c482382e246219f326a882487e65dd4d3810b6565949d7f1a2b05d75884 b/storage/textures/4fe09c482382e246219f326a882487e65dd4d3810b6565949d7f1a2b05d75884 new file mode 100755 index 0000000..183c577 Binary files /dev/null and b/storage/textures/4fe09c482382e246219f326a882487e65dd4d3810b6565949d7f1a2b05d75884 differ diff --git a/storage/textures/50a28ace451ece201bb4b4f560d2dc3b7be2cb8efffafeae4a7d61c61e54e1c0 b/storage/textures/50a28ace451ece201bb4b4f560d2dc3b7be2cb8efffafeae4a7d61c61e54e1c0 new file mode 100755 index 0000000..8846bf6 Binary files /dev/null and b/storage/textures/50a28ace451ece201bb4b4f560d2dc3b7be2cb8efffafeae4a7d61c61e54e1c0 differ diff --git a/storage/textures/51139c077efe5317ba5eeee803f97504186c957b029c8e6caa90858a03fea32d b/storage/textures/51139c077efe5317ba5eeee803f97504186c957b029c8e6caa90858a03fea32d new file mode 100644 index 0000000..abba2d8 Binary files /dev/null and b/storage/textures/51139c077efe5317ba5eeee803f97504186c957b029c8e6caa90858a03fea32d differ diff --git a/storage/textures/5146de12a1229f08edd966f34f8f2311e55ec84d70e20226152de5d20225eed6 b/storage/textures/5146de12a1229f08edd966f34f8f2311e55ec84d70e20226152de5d20225eed6 new file mode 100755 index 0000000..2ffab4d Binary files /dev/null and b/storage/textures/5146de12a1229f08edd966f34f8f2311e55ec84d70e20226152de5d20225eed6 differ diff --git a/storage/textures/515501d4ae6037ff949b3a11de9d9dcec0e2e31dae94889c9bb3a3e573b578c5 b/storage/textures/515501d4ae6037ff949b3a11de9d9dcec0e2e31dae94889c9bb3a3e573b578c5 new file mode 100644 index 0000000..ea8f26f Binary files /dev/null and b/storage/textures/515501d4ae6037ff949b3a11de9d9dcec0e2e31dae94889c9bb3a3e573b578c5 differ diff --git a/storage/textures/51f5d0f24f133974710aa7202971cb4fa3ba8051e8aaeee44c43690d09511243 b/storage/textures/51f5d0f24f133974710aa7202971cb4fa3ba8051e8aaeee44c43690d09511243 new file mode 100755 index 0000000..f521771 Binary files /dev/null and b/storage/textures/51f5d0f24f133974710aa7202971cb4fa3ba8051e8aaeee44c43690d09511243 differ diff --git a/storage/textures/5203570e70d5aad7e077cd04c9c29880f2d334cfdcce4e615dc1f2c1fa48703a b/storage/textures/5203570e70d5aad7e077cd04c9c29880f2d334cfdcce4e615dc1f2c1fa48703a new file mode 100644 index 0000000..07016f1 Binary files /dev/null and b/storage/textures/5203570e70d5aad7e077cd04c9c29880f2d334cfdcce4e615dc1f2c1fa48703a differ diff --git a/storage/textures/5225778c1f9d4b8e056200b0bdd211f91c0a7df536e3cc14ca9409ebaf93ff70 b/storage/textures/5225778c1f9d4b8e056200b0bdd211f91c0a7df536e3cc14ca9409ebaf93ff70 new file mode 100755 index 0000000..e989437 Binary files /dev/null and b/storage/textures/5225778c1f9d4b8e056200b0bdd211f91c0a7df536e3cc14ca9409ebaf93ff70 differ diff --git a/storage/textures/5297c2eca5dbc4b08375984069ea45eb82a7684dcd1bab88ac5e942a9e96f394 b/storage/textures/5297c2eca5dbc4b08375984069ea45eb82a7684dcd1bab88ac5e942a9e96f394 new file mode 100755 index 0000000..592f338 Binary files /dev/null and b/storage/textures/5297c2eca5dbc4b08375984069ea45eb82a7684dcd1bab88ac5e942a9e96f394 differ diff --git a/storage/textures/52c0ad8ff983922738e2d623ca6970eb31e0b6080aa8b5eaa647601057c5b698 b/storage/textures/52c0ad8ff983922738e2d623ca6970eb31e0b6080aa8b5eaa647601057c5b698 new file mode 100755 index 0000000..e4a0271 Binary files /dev/null and b/storage/textures/52c0ad8ff983922738e2d623ca6970eb31e0b6080aa8b5eaa647601057c5b698 differ diff --git a/storage/textures/52e1857a666b5ba2ef322e7caa8ab6cd08105c1df7ab668d066abf0c168af094 b/storage/textures/52e1857a666b5ba2ef322e7caa8ab6cd08105c1df7ab668d066abf0c168af094 new file mode 100644 index 0000000..708314e Binary files /dev/null and b/storage/textures/52e1857a666b5ba2ef322e7caa8ab6cd08105c1df7ab668d066abf0c168af094 differ diff --git a/storage/textures/52f1c29f3cec9fb21a93687ce892308a0a91294332e78d9a4029cf758006d26c b/storage/textures/52f1c29f3cec9fb21a93687ce892308a0a91294332e78d9a4029cf758006d26c new file mode 100755 index 0000000..b241540 Binary files /dev/null and b/storage/textures/52f1c29f3cec9fb21a93687ce892308a0a91294332e78d9a4029cf758006d26c differ diff --git a/storage/textures/539a7fb501c6a6898a1928f9099fc5ca432550acfbc294eeb932abd5a678e17d b/storage/textures/539a7fb501c6a6898a1928f9099fc5ca432550acfbc294eeb932abd5a678e17d new file mode 100755 index 0000000..e6255cc Binary files /dev/null and b/storage/textures/539a7fb501c6a6898a1928f9099fc5ca432550acfbc294eeb932abd5a678e17d differ diff --git a/storage/textures/53c92c3c474ca7835d383c3638df7479ee1922bf7a6818b8644bb5e6babde4ff b/storage/textures/53c92c3c474ca7835d383c3638df7479ee1922bf7a6818b8644bb5e6babde4ff new file mode 100755 index 0000000..976aab5 Binary files /dev/null and b/storage/textures/53c92c3c474ca7835d383c3638df7479ee1922bf7a6818b8644bb5e6babde4ff differ diff --git a/storage/textures/54391750b198b16bc3cfbeb16dc254081089a30270db839cc7fee2a12eba7463 b/storage/textures/54391750b198b16bc3cfbeb16dc254081089a30270db839cc7fee2a12eba7463 new file mode 100755 index 0000000..6dece69 Binary files /dev/null and b/storage/textures/54391750b198b16bc3cfbeb16dc254081089a30270db839cc7fee2a12eba7463 differ diff --git a/storage/textures/5448a943da9e7415ee5805fd70a1e7db4af981e56d867e7f4b06113f6f0a2dbb b/storage/textures/5448a943da9e7415ee5805fd70a1e7db4af981e56d867e7f4b06113f6f0a2dbb new file mode 100755 index 0000000..9983377 Binary files /dev/null and b/storage/textures/5448a943da9e7415ee5805fd70a1e7db4af981e56d867e7f4b06113f6f0a2dbb differ diff --git a/storage/textures/54c42b886caca83fc41b6aaaa88c76357a050f1f36725d108d534d5b23d8fee4 b/storage/textures/54c42b886caca83fc41b6aaaa88c76357a050f1f36725d108d534d5b23d8fee4 new file mode 100755 index 0000000..333488e Binary files /dev/null and b/storage/textures/54c42b886caca83fc41b6aaaa88c76357a050f1f36725d108d534d5b23d8fee4 differ diff --git a/storage/textures/54edf177c2a7d024c6de4483123b9a59c684d42baf2b6bd594e01f730832914f b/storage/textures/54edf177c2a7d024c6de4483123b9a59c684d42baf2b6bd594e01f730832914f new file mode 100644 index 0000000..0132293 Binary files /dev/null and b/storage/textures/54edf177c2a7d024c6de4483123b9a59c684d42baf2b6bd594e01f730832914f differ diff --git a/storage/textures/551ea6c1b8aba1b9b7d28016d259d7e26b683a829d36ff2c4cc6176bdc0e6946 b/storage/textures/551ea6c1b8aba1b9b7d28016d259d7e26b683a829d36ff2c4cc6176bdc0e6946 new file mode 100755 index 0000000..a836876 Binary files /dev/null and b/storage/textures/551ea6c1b8aba1b9b7d28016d259d7e26b683a829d36ff2c4cc6176bdc0e6946 differ diff --git a/storage/textures/554bfa1126440af66549fb4ecdb40b9973f0ed13bf6676a5f50d7827684d35c3 b/storage/textures/554bfa1126440af66549fb4ecdb40b9973f0ed13bf6676a5f50d7827684d35c3 new file mode 100755 index 0000000..dbf5766 Binary files /dev/null and b/storage/textures/554bfa1126440af66549fb4ecdb40b9973f0ed13bf6676a5f50d7827684d35c3 differ diff --git a/storage/textures/5556d28535a7c18653d59a4d8e4caf783631b9b48f317f7e19f1aa19f125280b b/storage/textures/5556d28535a7c18653d59a4d8e4caf783631b9b48f317f7e19f1aa19f125280b new file mode 100644 index 0000000..56e0806 Binary files /dev/null and b/storage/textures/5556d28535a7c18653d59a4d8e4caf783631b9b48f317f7e19f1aa19f125280b differ diff --git a/storage/textures/5585a46d79191035e408422a35b5b52fe897e5ad8dbfdb177732c46eefddd7e4 b/storage/textures/5585a46d79191035e408422a35b5b52fe897e5ad8dbfdb177732c46eefddd7e4 new file mode 100755 index 0000000..d30cf5f Binary files /dev/null and b/storage/textures/5585a46d79191035e408422a35b5b52fe897e5ad8dbfdb177732c46eefddd7e4 differ diff --git a/storage/textures/55ebe1318d50cddd3c220c4d7cb7a78a9f9aa041494ed1566a530ac6c6a175b4 b/storage/textures/55ebe1318d50cddd3c220c4d7cb7a78a9f9aa041494ed1566a530ac6c6a175b4 new file mode 100755 index 0000000..f1c23c4 Binary files /dev/null and b/storage/textures/55ebe1318d50cddd3c220c4d7cb7a78a9f9aa041494ed1566a530ac6c6a175b4 differ diff --git a/storage/textures/5631203b5530ab1b312a23a1555a08592906d938035523cb7904ac9f1af0d4e0 b/storage/textures/5631203b5530ab1b312a23a1555a08592906d938035523cb7904ac9f1af0d4e0 new file mode 100755 index 0000000..efa8b7d Binary files /dev/null and b/storage/textures/5631203b5530ab1b312a23a1555a08592906d938035523cb7904ac9f1af0d4e0 differ diff --git a/storage/textures/564052742c522330f4bc8fbc3d1d38bd2b9281961d177513d3700d2751dc7a94 b/storage/textures/564052742c522330f4bc8fbc3d1d38bd2b9281961d177513d3700d2751dc7a94 new file mode 100644 index 0000000..a7f3298 Binary files /dev/null and b/storage/textures/564052742c522330f4bc8fbc3d1d38bd2b9281961d177513d3700d2751dc7a94 differ diff --git a/storage/textures/56516e73d9a3940190f8c8a6a13a7caae6c4aab08788d2d51e581a5568727cda b/storage/textures/56516e73d9a3940190f8c8a6a13a7caae6c4aab08788d2d51e581a5568727cda new file mode 100755 index 0000000..b06e247 Binary files /dev/null and b/storage/textures/56516e73d9a3940190f8c8a6a13a7caae6c4aab08788d2d51e581a5568727cda differ diff --git a/storage/textures/56ed2d2e65eadc53105f565e1e3e835e5cfabed82d2f43132e85cdd00ff32172 b/storage/textures/56ed2d2e65eadc53105f565e1e3e835e5cfabed82d2f43132e85cdd00ff32172 new file mode 100755 index 0000000..2d0a66e Binary files /dev/null and b/storage/textures/56ed2d2e65eadc53105f565e1e3e835e5cfabed82d2f43132e85cdd00ff32172 differ diff --git a/storage/textures/56f5edd1393ddeaf6badcc4e7a3b52abf92ed7c982106f6f50c60bfa39341a38 b/storage/textures/56f5edd1393ddeaf6badcc4e7a3b52abf92ed7c982106f6f50c60bfa39341a38 new file mode 100755 index 0000000..41d42c9 Binary files /dev/null and b/storage/textures/56f5edd1393ddeaf6badcc4e7a3b52abf92ed7c982106f6f50c60bfa39341a38 differ diff --git a/storage/textures/570cdcd206c434335eb243b8aa928177e079d0f6c9cd091bcd8b423ee74a27a2 b/storage/textures/570cdcd206c434335eb243b8aa928177e079d0f6c9cd091bcd8b423ee74a27a2 new file mode 100755 index 0000000..1a74927 Binary files /dev/null and b/storage/textures/570cdcd206c434335eb243b8aa928177e079d0f6c9cd091bcd8b423ee74a27a2 differ diff --git a/storage/textures/573a22e09f7df8bc7551b4f03050359530b51487f6d13202d6c329ce0070a863 b/storage/textures/573a22e09f7df8bc7551b4f03050359530b51487f6d13202d6c329ce0070a863 new file mode 100644 index 0000000..dae1f7e Binary files /dev/null and b/storage/textures/573a22e09f7df8bc7551b4f03050359530b51487f6d13202d6c329ce0070a863 differ diff --git a/storage/textures/574305cd7a8cc557a904fab2afd5471e5c511c3050d8fa8db48f3cee4e9c5377 b/storage/textures/574305cd7a8cc557a904fab2afd5471e5c511c3050d8fa8db48f3cee4e9c5377 new file mode 100755 index 0000000..b3e8b81 Binary files /dev/null and b/storage/textures/574305cd7a8cc557a904fab2afd5471e5c511c3050d8fa8db48f3cee4e9c5377 differ diff --git a/storage/textures/576f02e50b23d8e69f38d8bee53a97e44305953975fda8e7ea82ae08edbf8c1b b/storage/textures/576f02e50b23d8e69f38d8bee53a97e44305953975fda8e7ea82ae08edbf8c1b new file mode 100755 index 0000000..141517e Binary files /dev/null and b/storage/textures/576f02e50b23d8e69f38d8bee53a97e44305953975fda8e7ea82ae08edbf8c1b differ diff --git a/storage/textures/5786fe99be377dfb6858859f926c4dbc995751e91cee373468c5fbf4865e7151 b/storage/textures/5786fe99be377dfb6858859f926c4dbc995751e91cee373468c5fbf4865e7151 new file mode 100755 index 0000000..deac5c5 Binary files /dev/null and b/storage/textures/5786fe99be377dfb6858859f926c4dbc995751e91cee373468c5fbf4865e7151 differ diff --git a/storage/textures/578956530f2d94348b84014e60c7ebc4f6feddb89daafe86a90809ffa6e2ba76 b/storage/textures/578956530f2d94348b84014e60c7ebc4f6feddb89daafe86a90809ffa6e2ba76 new file mode 100755 index 0000000..03f8439 Binary files /dev/null and b/storage/textures/578956530f2d94348b84014e60c7ebc4f6feddb89daafe86a90809ffa6e2ba76 differ diff --git a/storage/textures/57d3fdc5e1f658f9d625e8a76fa3d7f1dc57701c1c4e43bf305f2e78e71bc6ca b/storage/textures/57d3fdc5e1f658f9d625e8a76fa3d7f1dc57701c1c4e43bf305f2e78e71bc6ca new file mode 100755 index 0000000..c88af30 Binary files /dev/null and b/storage/textures/57d3fdc5e1f658f9d625e8a76fa3d7f1dc57701c1c4e43bf305f2e78e71bc6ca differ diff --git a/storage/textures/58069f923521ca4d97f9b6a9a8e34b4632ab98ebddbccf407d2f9d4fa7f8bf2d b/storage/textures/58069f923521ca4d97f9b6a9a8e34b4632ab98ebddbccf407d2f9d4fa7f8bf2d new file mode 100755 index 0000000..9857062 Binary files /dev/null and b/storage/textures/58069f923521ca4d97f9b6a9a8e34b4632ab98ebddbccf407d2f9d4fa7f8bf2d differ diff --git a/storage/textures/58b3195b6e31f3e451c6a1a1e6cf2bf278c5aea5c9b8b5c86f04aa1cfb8e4841 b/storage/textures/58b3195b6e31f3e451c6a1a1e6cf2bf278c5aea5c9b8b5c86f04aa1cfb8e4841 new file mode 100644 index 0000000..237c835 Binary files /dev/null and b/storage/textures/58b3195b6e31f3e451c6a1a1e6cf2bf278c5aea5c9b8b5c86f04aa1cfb8e4841 differ diff --git a/storage/textures/58dc4fad6dfa29bdcbef366d3ed607b3a89f14e2faca11b05edd5bfaac0b7e32 b/storage/textures/58dc4fad6dfa29bdcbef366d3ed607b3a89f14e2faca11b05edd5bfaac0b7e32 new file mode 100644 index 0000000..92b602a Binary files /dev/null and b/storage/textures/58dc4fad6dfa29bdcbef366d3ed607b3a89f14e2faca11b05edd5bfaac0b7e32 differ diff --git a/storage/textures/58e95d09c689f3804e669880294a23933101cbacef588d802e774b60887d9e87 b/storage/textures/58e95d09c689f3804e669880294a23933101cbacef588d802e774b60887d9e87 new file mode 100755 index 0000000..4c0c6b1 Binary files /dev/null and b/storage/textures/58e95d09c689f3804e669880294a23933101cbacef588d802e774b60887d9e87 differ diff --git a/storage/textures/590a677b2f5c72bfec8798b0a9c26bc9b0a8ecf9815df91784dbf6e21cd50d3f b/storage/textures/590a677b2f5c72bfec8798b0a9c26bc9b0a8ecf9815df91784dbf6e21cd50d3f new file mode 100755 index 0000000..a4d454d Binary files /dev/null and b/storage/textures/590a677b2f5c72bfec8798b0a9c26bc9b0a8ecf9815df91784dbf6e21cd50d3f differ diff --git a/storage/textures/596e9ae2626a3cffceddb4dc4f1b4f770802943491507b2758ca2b54a83325a7 b/storage/textures/596e9ae2626a3cffceddb4dc4f1b4f770802943491507b2758ca2b54a83325a7 new file mode 100755 index 0000000..0e6d25f Binary files /dev/null and b/storage/textures/596e9ae2626a3cffceddb4dc4f1b4f770802943491507b2758ca2b54a83325a7 differ diff --git a/storage/textures/59e2d41410eabc7027ac9aae2818100d2e401da5ddd3041b27be30b3e223dcaf b/storage/textures/59e2d41410eabc7027ac9aae2818100d2e401da5ddd3041b27be30b3e223dcaf new file mode 100644 index 0000000..94a9755 Binary files /dev/null and b/storage/textures/59e2d41410eabc7027ac9aae2818100d2e401da5ddd3041b27be30b3e223dcaf differ diff --git a/storage/textures/59e88a26b224b73f112971027ab4258f5d9091a37d7323c8f6ae16875655e633 b/storage/textures/59e88a26b224b73f112971027ab4258f5d9091a37d7323c8f6ae16875655e633 new file mode 100755 index 0000000..d9be472 Binary files /dev/null and b/storage/textures/59e88a26b224b73f112971027ab4258f5d9091a37d7323c8f6ae16875655e633 differ diff --git a/storage/textures/5a0b239e2156af6b0b0d40468a03dc597f2b4df5f63154c23e8fb7e8572f87d1 b/storage/textures/5a0b239e2156af6b0b0d40468a03dc597f2b4df5f63154c23e8fb7e8572f87d1 new file mode 100755 index 0000000..be16b22 Binary files /dev/null and b/storage/textures/5a0b239e2156af6b0b0d40468a03dc597f2b4df5f63154c23e8fb7e8572f87d1 differ diff --git a/storage/textures/5a75945765a8948d073c5856f6c20a1f787cefeaad31911dabe37d78399051bd b/storage/textures/5a75945765a8948d073c5856f6c20a1f787cefeaad31911dabe37d78399051bd new file mode 100755 index 0000000..eaaf6e6 Binary files /dev/null and b/storage/textures/5a75945765a8948d073c5856f6c20a1f787cefeaad31911dabe37d78399051bd differ diff --git a/storage/textures/5a8bbb818fbea3868a650a058e7dd08203d31c715c25b007c2a884e6e9397c69 b/storage/textures/5a8bbb818fbea3868a650a058e7dd08203d31c715c25b007c2a884e6e9397c69 new file mode 100755 index 0000000..66e4ffb Binary files /dev/null and b/storage/textures/5a8bbb818fbea3868a650a058e7dd08203d31c715c25b007c2a884e6e9397c69 differ diff --git a/storage/textures/5ad6b66bac702cdfc584ef8a75de15638443ec3e212367c8e5db70ad8f751613 b/storage/textures/5ad6b66bac702cdfc584ef8a75de15638443ec3e212367c8e5db70ad8f751613 new file mode 100755 index 0000000..9d8c834 Binary files /dev/null and b/storage/textures/5ad6b66bac702cdfc584ef8a75de15638443ec3e212367c8e5db70ad8f751613 differ diff --git a/storage/textures/5c25b44fcaa1646ba82702396ef045c732460023efbdabfeac922127e85cf19e b/storage/textures/5c25b44fcaa1646ba82702396ef045c732460023efbdabfeac922127e85cf19e new file mode 100644 index 0000000..a7a2de7 Binary files /dev/null and b/storage/textures/5c25b44fcaa1646ba82702396ef045c732460023efbdabfeac922127e85cf19e differ diff --git a/storage/textures/5c51c5d88abdecf0cd69ad2f9292e28ce82d25c7c0328f702f6aedf44ad28547 b/storage/textures/5c51c5d88abdecf0cd69ad2f9292e28ce82d25c7c0328f702f6aedf44ad28547 new file mode 100644 index 0000000..2be241b Binary files /dev/null and b/storage/textures/5c51c5d88abdecf0cd69ad2f9292e28ce82d25c7c0328f702f6aedf44ad28547 differ diff --git a/storage/textures/5c8873432ce8d39fc429aac69a9ab5e4b51fd58011a550e97eac653bbcc264d3 b/storage/textures/5c8873432ce8d39fc429aac69a9ab5e4b51fd58011a550e97eac653bbcc264d3 new file mode 100755 index 0000000..941d845 Binary files /dev/null and b/storage/textures/5c8873432ce8d39fc429aac69a9ab5e4b51fd58011a550e97eac653bbcc264d3 differ diff --git a/storage/textures/5c8916dc0f7e26fb631716e61f2476cb10f7e465da5b7fe4f37e3b8f44a6218d b/storage/textures/5c8916dc0f7e26fb631716e61f2476cb10f7e465da5b7fe4f37e3b8f44a6218d new file mode 100644 index 0000000..11e4a87 Binary files /dev/null and b/storage/textures/5c8916dc0f7e26fb631716e61f2476cb10f7e465da5b7fe4f37e3b8f44a6218d differ diff --git a/storage/textures/5c9aca73db42d06ae89d2388b55d19fa0eea0b70adcdbe15a65982d9aec11205 b/storage/textures/5c9aca73db42d06ae89d2388b55d19fa0eea0b70adcdbe15a65982d9aec11205 new file mode 100644 index 0000000..63093d4 Binary files /dev/null and b/storage/textures/5c9aca73db42d06ae89d2388b55d19fa0eea0b70adcdbe15a65982d9aec11205 differ diff --git a/storage/textures/5ca9c02d09c16d756f00cca218e9e25dbfc2f56faccdca1fb3f5efdc9dbe003e b/storage/textures/5ca9c02d09c16d756f00cca218e9e25dbfc2f56faccdca1fb3f5efdc9dbe003e new file mode 100755 index 0000000..4cfd8c3 Binary files /dev/null and b/storage/textures/5ca9c02d09c16d756f00cca218e9e25dbfc2f56faccdca1fb3f5efdc9dbe003e differ diff --git a/storage/textures/5cd9d0a24a50d22c55b9148c35c6c02e9894978ba2c499cc221cc8f946bb68cc b/storage/textures/5cd9d0a24a50d22c55b9148c35c6c02e9894978ba2c499cc221cc8f946bb68cc new file mode 100755 index 0000000..34a0fdc Binary files /dev/null and b/storage/textures/5cd9d0a24a50d22c55b9148c35c6c02e9894978ba2c499cc221cc8f946bb68cc differ diff --git a/storage/textures/5d1e0516669e20190e8e55d6957d92d351f23e79f8ca93ed30945b8c7f2c5979 b/storage/textures/5d1e0516669e20190e8e55d6957d92d351f23e79f8ca93ed30945b8c7f2c5979 new file mode 100755 index 0000000..b605630 Binary files /dev/null and b/storage/textures/5d1e0516669e20190e8e55d6957d92d351f23e79f8ca93ed30945b8c7f2c5979 differ diff --git a/storage/textures/5da181e50b61e56c2242d10763766159d17a908f91bf2f6f69555c6d042a3dcc b/storage/textures/5da181e50b61e56c2242d10763766159d17a908f91bf2f6f69555c6d042a3dcc new file mode 100644 index 0000000..5962d75 Binary files /dev/null and b/storage/textures/5da181e50b61e56c2242d10763766159d17a908f91bf2f6f69555c6d042a3dcc differ diff --git a/storage/textures/5da72b0012273d29d7f79093dad0d3ca94bd1195607de0551f4429456d335fa6 b/storage/textures/5da72b0012273d29d7f79093dad0d3ca94bd1195607de0551f4429456d335fa6 new file mode 100644 index 0000000..0429447 Binary files /dev/null and b/storage/textures/5da72b0012273d29d7f79093dad0d3ca94bd1195607de0551f4429456d335fa6 differ diff --git a/storage/textures/5dff6d8ed64e3463058f1af8b46ff4593662631e6700de484f72c280636a69ca b/storage/textures/5dff6d8ed64e3463058f1af8b46ff4593662631e6700de484f72c280636a69ca new file mode 100755 index 0000000..62aa245 Binary files /dev/null and b/storage/textures/5dff6d8ed64e3463058f1af8b46ff4593662631e6700de484f72c280636a69ca differ diff --git a/storage/textures/5e0142084792e115f3f2cc948ffe060e512640884b88301e1b847a293f293f98 b/storage/textures/5e0142084792e115f3f2cc948ffe060e512640884b88301e1b847a293f293f98 new file mode 100755 index 0000000..6651e20 Binary files /dev/null and b/storage/textures/5e0142084792e115f3f2cc948ffe060e512640884b88301e1b847a293f293f98 differ diff --git a/storage/textures/5e21bf0ca0eb19a130c6f6a8ce1f164d107e75510a818d369b78f54cd136827a b/storage/textures/5e21bf0ca0eb19a130c6f6a8ce1f164d107e75510a818d369b78f54cd136827a new file mode 100755 index 0000000..0e3ed3d Binary files /dev/null and b/storage/textures/5e21bf0ca0eb19a130c6f6a8ce1f164d107e75510a818d369b78f54cd136827a differ diff --git a/storage/textures/5e631f9b740fae48eac80364ff4029889791449faf5ee6d00fac6f20ba5ab3bb b/storage/textures/5e631f9b740fae48eac80364ff4029889791449faf5ee6d00fac6f20ba5ab3bb new file mode 100755 index 0000000..42eddb7 Binary files /dev/null and b/storage/textures/5e631f9b740fae48eac80364ff4029889791449faf5ee6d00fac6f20ba5ab3bb differ diff --git a/storage/textures/5e741930ab47b9c1afcd20fac247af40cefd42c00a1407692ef9b429e9c6b6d5 b/storage/textures/5e741930ab47b9c1afcd20fac247af40cefd42c00a1407692ef9b429e9c6b6d5 new file mode 100755 index 0000000..fff6291 Binary files /dev/null and b/storage/textures/5e741930ab47b9c1afcd20fac247af40cefd42c00a1407692ef9b429e9c6b6d5 differ diff --git a/storage/textures/5e956adb0b57c7182b99e47e6889c90fedc2c6b80f0b6b40759c5705eeb48a94 b/storage/textures/5e956adb0b57c7182b99e47e6889c90fedc2c6b80f0b6b40759c5705eeb48a94 new file mode 100644 index 0000000..0df6ed1 Binary files /dev/null and b/storage/textures/5e956adb0b57c7182b99e47e6889c90fedc2c6b80f0b6b40759c5705eeb48a94 differ diff --git a/storage/textures/5ea9d3b9a7ae89e6e201920b813d325852c8a22c9e703ae4d2125d3210363203 b/storage/textures/5ea9d3b9a7ae89e6e201920b813d325852c8a22c9e703ae4d2125d3210363203 new file mode 100755 index 0000000..d85de7e Binary files /dev/null and b/storage/textures/5ea9d3b9a7ae89e6e201920b813d325852c8a22c9e703ae4d2125d3210363203 differ diff --git a/storage/textures/5eaefb06c6c081b41d02d1d008f5de66ab6d05a1efd77fca6c446314ff07be6f b/storage/textures/5eaefb06c6c081b41d02d1d008f5de66ab6d05a1efd77fca6c446314ff07be6f new file mode 100755 index 0000000..ddc1e40 Binary files /dev/null and b/storage/textures/5eaefb06c6c081b41d02d1d008f5de66ab6d05a1efd77fca6c446314ff07be6f differ diff --git a/storage/textures/5ebbdfe98759837bd172e71e9bd905abb0d37b0400cac41b326532511f619474 b/storage/textures/5ebbdfe98759837bd172e71e9bd905abb0d37b0400cac41b326532511f619474 new file mode 100755 index 0000000..b435636 Binary files /dev/null and b/storage/textures/5ebbdfe98759837bd172e71e9bd905abb0d37b0400cac41b326532511f619474 differ diff --git a/storage/textures/5ef55ce2b0b622a67c6fd418a1ea61e5404effec646533a77075f2c0612fb5f1 b/storage/textures/5ef55ce2b0b622a67c6fd418a1ea61e5404effec646533a77075f2c0612fb5f1 new file mode 100755 index 0000000..a10c1a4 Binary files /dev/null and b/storage/textures/5ef55ce2b0b622a67c6fd418a1ea61e5404effec646533a77075f2c0612fb5f1 differ diff --git a/storage/textures/5ef8f7b82255c3be34d108456e85559cddcc7e79d255dc068d0cefc4fe74bbdb b/storage/textures/5ef8f7b82255c3be34d108456e85559cddcc7e79d255dc068d0cefc4fe74bbdb new file mode 100755 index 0000000..3e526ae Binary files /dev/null and b/storage/textures/5ef8f7b82255c3be34d108456e85559cddcc7e79d255dc068d0cefc4fe74bbdb differ diff --git a/storage/textures/5f100f508ced1f00673a3862abfd8366f2ee4351f6742cd25f91d161fbdc85fa b/storage/textures/5f100f508ced1f00673a3862abfd8366f2ee4351f6742cd25f91d161fbdc85fa new file mode 100755 index 0000000..030dc1a Binary files /dev/null and b/storage/textures/5f100f508ced1f00673a3862abfd8366f2ee4351f6742cd25f91d161fbdc85fa differ diff --git a/storage/textures/5f449896f3ef7f2befa0781629fb4a60ec4c0b7a640a0f772e3281482d93f959 b/storage/textures/5f449896f3ef7f2befa0781629fb4a60ec4c0b7a640a0f772e3281482d93f959 new file mode 100755 index 0000000..94cedb0 Binary files /dev/null and b/storage/textures/5f449896f3ef7f2befa0781629fb4a60ec4c0b7a640a0f772e3281482d93f959 differ diff --git a/storage/textures/5f65014fbd7bd871d5566d1b5de9b236308d29b167043d5b6ad5e97d6e535114 b/storage/textures/5f65014fbd7bd871d5566d1b5de9b236308d29b167043d5b6ad5e97d6e535114 new file mode 100755 index 0000000..187406c Binary files /dev/null and b/storage/textures/5f65014fbd7bd871d5566d1b5de9b236308d29b167043d5b6ad5e97d6e535114 differ diff --git a/storage/textures/5f6c6e47ac21a86044b515a3c0ffb20e44a3df0b079c1448ea75d7028c0403f9 b/storage/textures/5f6c6e47ac21a86044b515a3c0ffb20e44a3df0b079c1448ea75d7028c0403f9 new file mode 100644 index 0000000..a58d7d8 Binary files /dev/null and b/storage/textures/5f6c6e47ac21a86044b515a3c0ffb20e44a3df0b079c1448ea75d7028c0403f9 differ diff --git a/storage/textures/5f9d9c352ccd69af75ec417b812ed2b142db94f373daebf5acdd8a4300c17bf5 b/storage/textures/5f9d9c352ccd69af75ec417b812ed2b142db94f373daebf5acdd8a4300c17bf5 new file mode 100644 index 0000000..84dec15 Binary files /dev/null and b/storage/textures/5f9d9c352ccd69af75ec417b812ed2b142db94f373daebf5acdd8a4300c17bf5 differ diff --git a/storage/textures/5fe167dcecda2b7161895fa3678e9c33ac952cb867cc05391879080bd10fa1e1 b/storage/textures/5fe167dcecda2b7161895fa3678e9c33ac952cb867cc05391879080bd10fa1e1 new file mode 100755 index 0000000..5dba607 Binary files /dev/null and b/storage/textures/5fe167dcecda2b7161895fa3678e9c33ac952cb867cc05391879080bd10fa1e1 differ diff --git a/storage/textures/6045b75b378664fe6ce82cfd0670f40bbb3a0de1d23fd27d8637de811407cc2e b/storage/textures/6045b75b378664fe6ce82cfd0670f40bbb3a0de1d23fd27d8637de811407cc2e new file mode 100755 index 0000000..2d9061a Binary files /dev/null and b/storage/textures/6045b75b378664fe6ce82cfd0670f40bbb3a0de1d23fd27d8637de811407cc2e differ diff --git a/storage/textures/6056e155a7560262445f208d195923e777e73707804e0ccb22657184206e6167 b/storage/textures/6056e155a7560262445f208d195923e777e73707804e0ccb22657184206e6167 new file mode 100755 index 0000000..cd5c767 Binary files /dev/null and b/storage/textures/6056e155a7560262445f208d195923e777e73707804e0ccb22657184206e6167 differ diff --git a/storage/textures/6062569338d4e050339662595fd23b692979e1559b3d89f64e76369750432e1b b/storage/textures/6062569338d4e050339662595fd23b692979e1559b3d89f64e76369750432e1b new file mode 100644 index 0000000..d6e75f4 Binary files /dev/null and b/storage/textures/6062569338d4e050339662595fd23b692979e1559b3d89f64e76369750432e1b differ diff --git a/storage/textures/60a5c4bd31110ccdd114046e7313bab4d2389bad7a8e3db1907b2ea9931f01ac b/storage/textures/60a5c4bd31110ccdd114046e7313bab4d2389bad7a8e3db1907b2ea9931f01ac new file mode 100755 index 0000000..35b7d21 Binary files /dev/null and b/storage/textures/60a5c4bd31110ccdd114046e7313bab4d2389bad7a8e3db1907b2ea9931f01ac differ diff --git a/storage/textures/61482b63ab4735faa5058a60e1af1266969f28dce64d2025743517d1c5912bfc b/storage/textures/61482b63ab4735faa5058a60e1af1266969f28dce64d2025743517d1c5912bfc new file mode 100644 index 0000000..ddc5641 Binary files /dev/null and b/storage/textures/61482b63ab4735faa5058a60e1af1266969f28dce64d2025743517d1c5912bfc differ diff --git a/storage/textures/614b3ccf01763d0d276ba16513af68cdc5bddb419001f4b8bae8f54f5a6ef1d2 b/storage/textures/614b3ccf01763d0d276ba16513af68cdc5bddb419001f4b8bae8f54f5a6ef1d2 new file mode 100755 index 0000000..d8703ec Binary files /dev/null and b/storage/textures/614b3ccf01763d0d276ba16513af68cdc5bddb419001f4b8bae8f54f5a6ef1d2 differ diff --git a/storage/textures/6177bac635711759bb3dba0b49f637bf4f6a93f3857cb773f1172fcd70dcb1e7 b/storage/textures/6177bac635711759bb3dba0b49f637bf4f6a93f3857cb773f1172fcd70dcb1e7 new file mode 100755 index 0000000..277a6b7 Binary files /dev/null and b/storage/textures/6177bac635711759bb3dba0b49f637bf4f6a93f3857cb773f1172fcd70dcb1e7 differ diff --git a/storage/textures/617975661a922ff7705b39d8a8768437d6ac9138ce4602c74c42bc89ca830c46 b/storage/textures/617975661a922ff7705b39d8a8768437d6ac9138ce4602c74c42bc89ca830c46 new file mode 100755 index 0000000..f84fd25 Binary files /dev/null and b/storage/textures/617975661a922ff7705b39d8a8768437d6ac9138ce4602c74c42bc89ca830c46 differ diff --git a/storage/textures/61b4f6d98a9594b038a36071609ead1b63c0a703b4c1a183187ce3aab65db8b9 b/storage/textures/61b4f6d98a9594b038a36071609ead1b63c0a703b4c1a183187ce3aab65db8b9 new file mode 100644 index 0000000..0c6bb1d Binary files /dev/null and b/storage/textures/61b4f6d98a9594b038a36071609ead1b63c0a703b4c1a183187ce3aab65db8b9 differ diff --git a/storage/textures/61da04a0d1590eee44247719d734bdf37816f899afb5ac90d3f6677a6e919ca6 b/storage/textures/61da04a0d1590eee44247719d734bdf37816f899afb5ac90d3f6677a6e919ca6 new file mode 100755 index 0000000..d94d12f Binary files /dev/null and b/storage/textures/61da04a0d1590eee44247719d734bdf37816f899afb5ac90d3f6677a6e919ca6 differ diff --git a/storage/textures/620a65b9b754caa13095d3823a9ba4b27e18662f5d5f0e0e381ec378f895a21d b/storage/textures/620a65b9b754caa13095d3823a9ba4b27e18662f5d5f0e0e381ec378f895a21d new file mode 100755 index 0000000..a31652d Binary files /dev/null and b/storage/textures/620a65b9b754caa13095d3823a9ba4b27e18662f5d5f0e0e381ec378f895a21d differ diff --git a/storage/textures/6253d33c91713915660d6b609e81b381be8ac8afeb19e67cdc10e995e1a734b8 b/storage/textures/6253d33c91713915660d6b609e81b381be8ac8afeb19e67cdc10e995e1a734b8 new file mode 100644 index 0000000..13fe3c8 Binary files /dev/null and b/storage/textures/6253d33c91713915660d6b609e81b381be8ac8afeb19e67cdc10e995e1a734b8 differ diff --git a/storage/textures/62b5995f71328cee33fb93c80cbef4a2313675860db9fecb6306521cb12ffa34 b/storage/textures/62b5995f71328cee33fb93c80cbef4a2313675860db9fecb6306521cb12ffa34 new file mode 100755 index 0000000..9dbec3b Binary files /dev/null and b/storage/textures/62b5995f71328cee33fb93c80cbef4a2313675860db9fecb6306521cb12ffa34 differ diff --git a/storage/textures/62c4f1702a8975cabbe5b6f048949dff437e04478a0aa6cf10adbc1704bd52e3 b/storage/textures/62c4f1702a8975cabbe5b6f048949dff437e04478a0aa6cf10adbc1704bd52e3 new file mode 100755 index 0000000..0871703 Binary files /dev/null and b/storage/textures/62c4f1702a8975cabbe5b6f048949dff437e04478a0aa6cf10adbc1704bd52e3 differ diff --git a/storage/textures/62fc9ca658264d1f8fdc251a0a8508f6a89eafcb81c8086e40ed831fd297abdc b/storage/textures/62fc9ca658264d1f8fdc251a0a8508f6a89eafcb81c8086e40ed831fd297abdc new file mode 100755 index 0000000..fe7f815 Binary files /dev/null and b/storage/textures/62fc9ca658264d1f8fdc251a0a8508f6a89eafcb81c8086e40ed831fd297abdc differ diff --git a/storage/textures/63040c2ef64423047b0b59bf5ca11f78fdd7cf77b553e5d259898edd4ca32b12 b/storage/textures/63040c2ef64423047b0b59bf5ca11f78fdd7cf77b553e5d259898edd4ca32b12 new file mode 100644 index 0000000..eb53703 Binary files /dev/null and b/storage/textures/63040c2ef64423047b0b59bf5ca11f78fdd7cf77b553e5d259898edd4ca32b12 differ diff --git a/storage/textures/6311d132748174a09db199d80b93b314fbff84b55b5fd778978fd82f089824bc b/storage/textures/6311d132748174a09db199d80b93b314fbff84b55b5fd778978fd82f089824bc new file mode 100644 index 0000000..c85d1fe Binary files /dev/null and b/storage/textures/6311d132748174a09db199d80b93b314fbff84b55b5fd778978fd82f089824bc differ diff --git a/storage/textures/639d3bfb8a9fb68708155d5da63ca66ca3b027f65672504f6fab3eefe3e7a7a8 b/storage/textures/639d3bfb8a9fb68708155d5da63ca66ca3b027f65672504f6fab3eefe3e7a7a8 new file mode 100755 index 0000000..120a09f Binary files /dev/null and b/storage/textures/639d3bfb8a9fb68708155d5da63ca66ca3b027f65672504f6fab3eefe3e7a7a8 differ diff --git a/storage/textures/63db727e13ccaabdec06853c4708aa48446020476e3e85b64e5beeb6f0b59e4e b/storage/textures/63db727e13ccaabdec06853c4708aa48446020476e3e85b64e5beeb6f0b59e4e new file mode 100755 index 0000000..d3830c5 Binary files /dev/null and b/storage/textures/63db727e13ccaabdec06853c4708aa48446020476e3e85b64e5beeb6f0b59e4e differ diff --git a/storage/textures/63dba3e48349db1a961801eec9f184e658b076708405e9d88ef1bd211003b70c b/storage/textures/63dba3e48349db1a961801eec9f184e658b076708405e9d88ef1bd211003b70c new file mode 100755 index 0000000..18b69ec Binary files /dev/null and b/storage/textures/63dba3e48349db1a961801eec9f184e658b076708405e9d88ef1bd211003b70c differ diff --git a/storage/textures/63e3abe3163578b11ca982e2ec60e3778b0d7a2e54c87484ffc643e80b352d53 b/storage/textures/63e3abe3163578b11ca982e2ec60e3778b0d7a2e54c87484ffc643e80b352d53 new file mode 100755 index 0000000..d7024a0 Binary files /dev/null and b/storage/textures/63e3abe3163578b11ca982e2ec60e3778b0d7a2e54c87484ffc643e80b352d53 differ diff --git a/storage/textures/64558972bafad713f514e07eea674c1470efa1b3992be5a173fb17463f383fc4 b/storage/textures/64558972bafad713f514e07eea674c1470efa1b3992be5a173fb17463f383fc4 new file mode 100755 index 0000000..40ba32a Binary files /dev/null and b/storage/textures/64558972bafad713f514e07eea674c1470efa1b3992be5a173fb17463f383fc4 differ diff --git a/storage/textures/649d7442cd2df478d79c80650f9c7e61932fd20a690382bbff72b1902deda253 b/storage/textures/649d7442cd2df478d79c80650f9c7e61932fd20a690382bbff72b1902deda253 new file mode 100755 index 0000000..6963f2f Binary files /dev/null and b/storage/textures/649d7442cd2df478d79c80650f9c7e61932fd20a690382bbff72b1902deda253 differ diff --git a/storage/textures/64c9f3b2ebffd2ea0524f8e837fdbe4990eff30b8a5c4f27bbe3c6f8b99e3c5c b/storage/textures/64c9f3b2ebffd2ea0524f8e837fdbe4990eff30b8a5c4f27bbe3c6f8b99e3c5c new file mode 100644 index 0000000..5be8e88 Binary files /dev/null and b/storage/textures/64c9f3b2ebffd2ea0524f8e837fdbe4990eff30b8a5c4f27bbe3c6f8b99e3c5c differ diff --git a/storage/textures/64cae4130d46bdce799deb9f6e9aeec6dfeff0ecefa137629528fc49e68739a0 b/storage/textures/64cae4130d46bdce799deb9f6e9aeec6dfeff0ecefa137629528fc49e68739a0 new file mode 100644 index 0000000..9106326 Binary files /dev/null and b/storage/textures/64cae4130d46bdce799deb9f6e9aeec6dfeff0ecefa137629528fc49e68739a0 differ diff --git a/storage/textures/64d966895d7b0271af201e92a5f0d14a47862f2f0081926ae607874396b31278 b/storage/textures/64d966895d7b0271af201e92a5f0d14a47862f2f0081926ae607874396b31278 new file mode 100755 index 0000000..b5bab93 Binary files /dev/null and b/storage/textures/64d966895d7b0271af201e92a5f0d14a47862f2f0081926ae607874396b31278 differ diff --git a/storage/textures/64dbef8f759788a0d48da24e49b924bbd74ebf99603a3240f8a78d4e0cf8e9de b/storage/textures/64dbef8f759788a0d48da24e49b924bbd74ebf99603a3240f8a78d4e0cf8e9de new file mode 100644 index 0000000..8ee7dec Binary files /dev/null and b/storage/textures/64dbef8f759788a0d48da24e49b924bbd74ebf99603a3240f8a78d4e0cf8e9de differ diff --git a/storage/textures/64dd8178ea3b584c3f72205e6a031fd57376384d5079e6776a7aa6517a341854 b/storage/textures/64dd8178ea3b584c3f72205e6a031fd57376384d5079e6776a7aa6517a341854 new file mode 100644 index 0000000..5d0966b Binary files /dev/null and b/storage/textures/64dd8178ea3b584c3f72205e6a031fd57376384d5079e6776a7aa6517a341854 differ diff --git a/storage/textures/64fa4626f43bec004385be5233097b233f9c72b555a0a156c049b7aad4e6422f b/storage/textures/64fa4626f43bec004385be5233097b233f9c72b555a0a156c049b7aad4e6422f new file mode 100755 index 0000000..e866bb2 Binary files /dev/null and b/storage/textures/64fa4626f43bec004385be5233097b233f9c72b555a0a156c049b7aad4e6422f differ diff --git a/storage/textures/653ddd4e24c7389af6a6c1a4904f9944bf2c158d3a15cdf087778a464a9424d3 b/storage/textures/653ddd4e24c7389af6a6c1a4904f9944bf2c158d3a15cdf087778a464a9424d3 new file mode 100755 index 0000000..3dfba9a Binary files /dev/null and b/storage/textures/653ddd4e24c7389af6a6c1a4904f9944bf2c158d3a15cdf087778a464a9424d3 differ diff --git a/storage/textures/656699151dbb924088a04ca27e7e3beca5114d0cf56f60549a2c4ca74d9857f8 b/storage/textures/656699151dbb924088a04ca27e7e3beca5114d0cf56f60549a2c4ca74d9857f8 new file mode 100644 index 0000000..a0d6adf Binary files /dev/null and b/storage/textures/656699151dbb924088a04ca27e7e3beca5114d0cf56f60549a2c4ca74d9857f8 differ diff --git a/storage/textures/65b236edf0837d2fd206665f8912fb0fb9e5eefc7a4ec2e49074725c9f017beb b/storage/textures/65b236edf0837d2fd206665f8912fb0fb9e5eefc7a4ec2e49074725c9f017beb new file mode 100755 index 0000000..4716b3e Binary files /dev/null and b/storage/textures/65b236edf0837d2fd206665f8912fb0fb9e5eefc7a4ec2e49074725c9f017beb differ diff --git a/storage/textures/665f2183236794e7ee30e39208ae786174f63d122771d1bcb22cca7470b9f2eb b/storage/textures/665f2183236794e7ee30e39208ae786174f63d122771d1bcb22cca7470b9f2eb new file mode 100755 index 0000000..a9e5d2b Binary files /dev/null and b/storage/textures/665f2183236794e7ee30e39208ae786174f63d122771d1bcb22cca7470b9f2eb differ diff --git a/storage/textures/666c36e8bc57a515b1589a4ab33eef7f4facde378cdd9c902a128329239163e1 b/storage/textures/666c36e8bc57a515b1589a4ab33eef7f4facde378cdd9c902a128329239163e1 new file mode 100755 index 0000000..c21eee1 Binary files /dev/null and b/storage/textures/666c36e8bc57a515b1589a4ab33eef7f4facde378cdd9c902a128329239163e1 differ diff --git a/storage/textures/66e93c790a88e4c067c3fc88aa9bf61634c4a9c1c3935ee5a97820cdd1022468 b/storage/textures/66e93c790a88e4c067c3fc88aa9bf61634c4a9c1c3935ee5a97820cdd1022468 new file mode 100755 index 0000000..b48a74e Binary files /dev/null and b/storage/textures/66e93c790a88e4c067c3fc88aa9bf61634c4a9c1c3935ee5a97820cdd1022468 differ diff --git a/storage/textures/673cd3919627c4e6ed4d1352c94b0811b6d86f92830b6c7f81efa91e6c0ffcad b/storage/textures/673cd3919627c4e6ed4d1352c94b0811b6d86f92830b6c7f81efa91e6c0ffcad new file mode 100755 index 0000000..ee17bcd Binary files /dev/null and b/storage/textures/673cd3919627c4e6ed4d1352c94b0811b6d86f92830b6c7f81efa91e6c0ffcad differ diff --git a/storage/textures/67541b1bc6ae93a1272f18539d5d9b1bbc2ed99cc4a390c40dc01b8bed4fe435 b/storage/textures/67541b1bc6ae93a1272f18539d5d9b1bbc2ed99cc4a390c40dc01b8bed4fe435 new file mode 100644 index 0000000..e8964a5 Binary files /dev/null and b/storage/textures/67541b1bc6ae93a1272f18539d5d9b1bbc2ed99cc4a390c40dc01b8bed4fe435 differ diff --git a/storage/textures/6766e3863bdc71340209330963511b9f58b446b0466093e336df80af6cb74e8f b/storage/textures/6766e3863bdc71340209330963511b9f58b446b0466093e336df80af6cb74e8f new file mode 100644 index 0000000..bc738a2 Binary files /dev/null and b/storage/textures/6766e3863bdc71340209330963511b9f58b446b0466093e336df80af6cb74e8f differ diff --git a/storage/textures/677e8322ff9eaca8f2138a81c9a7f4213391a23488b25d616eab3316bec44d4b b/storage/textures/677e8322ff9eaca8f2138a81c9a7f4213391a23488b25d616eab3316bec44d4b new file mode 100755 index 0000000..5bae731 Binary files /dev/null and b/storage/textures/677e8322ff9eaca8f2138a81c9a7f4213391a23488b25d616eab3316bec44d4b differ diff --git a/storage/textures/677f794a6831a42c9e7b2d55e8e20cdf7aa51409c5bc55ff4ebe4d999fa88af7 b/storage/textures/677f794a6831a42c9e7b2d55e8e20cdf7aa51409c5bc55ff4ebe4d999fa88af7 new file mode 100755 index 0000000..af87a0d Binary files /dev/null and b/storage/textures/677f794a6831a42c9e7b2d55e8e20cdf7aa51409c5bc55ff4ebe4d999fa88af7 differ diff --git a/storage/textures/678cb255cad284a6ef8915e3bb8fdca93905a6a1d04dea7b6962728a4d409987 b/storage/textures/678cb255cad284a6ef8915e3bb8fdca93905a6a1d04dea7b6962728a4d409987 new file mode 100755 index 0000000..90a08f9 Binary files /dev/null and b/storage/textures/678cb255cad284a6ef8915e3bb8fdca93905a6a1d04dea7b6962728a4d409987 differ diff --git a/storage/textures/682aa6eae6dde212ae1ec8447e0dc8b2e0f2ff16678cc926cc926f4337cadafa b/storage/textures/682aa6eae6dde212ae1ec8447e0dc8b2e0f2ff16678cc926cc926f4337cadafa new file mode 100644 index 0000000..47c9c27 Binary files /dev/null and b/storage/textures/682aa6eae6dde212ae1ec8447e0dc8b2e0f2ff16678cc926cc926f4337cadafa differ diff --git a/storage/textures/687dda848c3e3e0f1a883a4199d65cfa6054c307d11d38a12ad761f41cc53f40 b/storage/textures/687dda848c3e3e0f1a883a4199d65cfa6054c307d11d38a12ad761f41cc53f40 new file mode 100755 index 0000000..10eb111 Binary files /dev/null and b/storage/textures/687dda848c3e3e0f1a883a4199d65cfa6054c307d11d38a12ad761f41cc53f40 differ diff --git a/storage/textures/687fe6a17b474b682c9b5136cd986c3ee2095108ad171393de13eb9c22f5c9a1 b/storage/textures/687fe6a17b474b682c9b5136cd986c3ee2095108ad171393de13eb9c22f5c9a1 new file mode 100644 index 0000000..c701c96 Binary files /dev/null and b/storage/textures/687fe6a17b474b682c9b5136cd986c3ee2095108ad171393de13eb9c22f5c9a1 differ diff --git a/storage/textures/691eb047682b006a433596ad5bdfdf7b1a266aabedf1dc03ef9e240f3a7365cb b/storage/textures/691eb047682b006a433596ad5bdfdf7b1a266aabedf1dc03ef9e240f3a7365cb new file mode 100755 index 0000000..0230a56 Binary files /dev/null and b/storage/textures/691eb047682b006a433596ad5bdfdf7b1a266aabedf1dc03ef9e240f3a7365cb differ diff --git a/storage/textures/6939747d19cb44611f6dc2b6108c7bf49ecb57256089e84f622bfb49d1ca03e8 b/storage/textures/6939747d19cb44611f6dc2b6108c7bf49ecb57256089e84f622bfb49d1ca03e8 new file mode 100644 index 0000000..9b7e715 Binary files /dev/null and b/storage/textures/6939747d19cb44611f6dc2b6108c7bf49ecb57256089e84f622bfb49d1ca03e8 differ diff --git a/storage/textures/69502010baef0aa6c8cf9350b4fc2c96bc3e7f80ce3696d69f4baa42e9b45990 b/storage/textures/69502010baef0aa6c8cf9350b4fc2c96bc3e7f80ce3696d69f4baa42e9b45990 new file mode 100755 index 0000000..7b77007 Binary files /dev/null and b/storage/textures/69502010baef0aa6c8cf9350b4fc2c96bc3e7f80ce3696d69f4baa42e9b45990 differ diff --git a/storage/textures/695e695db00c8d046bc0904ff424553f7836cde28ade3032375cc81b936c9719 b/storage/textures/695e695db00c8d046bc0904ff424553f7836cde28ade3032375cc81b936c9719 new file mode 100755 index 0000000..d086f27 Binary files /dev/null and b/storage/textures/695e695db00c8d046bc0904ff424553f7836cde28ade3032375cc81b936c9719 differ diff --git a/storage/textures/69aa9514244673280efb192294312d99bb43d793475627757007b59638929af5 b/storage/textures/69aa9514244673280efb192294312d99bb43d793475627757007b59638929af5 new file mode 100755 index 0000000..7d289e5 Binary files /dev/null and b/storage/textures/69aa9514244673280efb192294312d99bb43d793475627757007b59638929af5 differ diff --git a/storage/textures/69b36ac6d3cd13f723d6e1e2db7275e6b395d246f4b83ba1e99562036596c773 b/storage/textures/69b36ac6d3cd13f723d6e1e2db7275e6b395d246f4b83ba1e99562036596c773 new file mode 100644 index 0000000..11461bb Binary files /dev/null and b/storage/textures/69b36ac6d3cd13f723d6e1e2db7275e6b395d246f4b83ba1e99562036596c773 differ diff --git a/storage/textures/69c7e32309efdb12745e0277df0d0352c484eab2e86e2577d973867fe528ad9d b/storage/textures/69c7e32309efdb12745e0277df0d0352c484eab2e86e2577d973867fe528ad9d new file mode 100755 index 0000000..a83dfdb Binary files /dev/null and b/storage/textures/69c7e32309efdb12745e0277df0d0352c484eab2e86e2577d973867fe528ad9d differ diff --git a/storage/textures/6a1f186b21bc0a2cc47590d56208037a91c10873436363056d8014e0f2870799 b/storage/textures/6a1f186b21bc0a2cc47590d56208037a91c10873436363056d8014e0f2870799 new file mode 100755 index 0000000..6ffd097 Binary files /dev/null and b/storage/textures/6a1f186b21bc0a2cc47590d56208037a91c10873436363056d8014e0f2870799 differ diff --git a/storage/textures/6b06fef2449149e49effd58e4d70ef27ad2ddfeb151a32c95c4b9db3a397e27e b/storage/textures/6b06fef2449149e49effd58e4d70ef27ad2ddfeb151a32c95c4b9db3a397e27e new file mode 100644 index 0000000..8a7abed Binary files /dev/null and b/storage/textures/6b06fef2449149e49effd58e4d70ef27ad2ddfeb151a32c95c4b9db3a397e27e differ diff --git a/storage/textures/6b65343db17101eb986e7d832b98b703a1eeed3876bdf52dd23332ccaf83949d b/storage/textures/6b65343db17101eb986e7d832b98b703a1eeed3876bdf52dd23332ccaf83949d new file mode 100755 index 0000000..754b07f Binary files /dev/null and b/storage/textures/6b65343db17101eb986e7d832b98b703a1eeed3876bdf52dd23332ccaf83949d differ diff --git a/storage/textures/6bb49be5b04cdea7fdf5989d9b08d8756281e5251a44bdc9b425b09d64b05332 b/storage/textures/6bb49be5b04cdea7fdf5989d9b08d8756281e5251a44bdc9b425b09d64b05332 new file mode 100755 index 0000000..84cacbc Binary files /dev/null and b/storage/textures/6bb49be5b04cdea7fdf5989d9b08d8756281e5251a44bdc9b425b09d64b05332 differ diff --git a/storage/textures/6c029ae505c08f16872ac8f76b2061a19e7d99c319c80ca4a49f0598869fe114 b/storage/textures/6c029ae505c08f16872ac8f76b2061a19e7d99c319c80ca4a49f0598869fe114 new file mode 100755 index 0000000..a38c698 Binary files /dev/null and b/storage/textures/6c029ae505c08f16872ac8f76b2061a19e7d99c319c80ca4a49f0598869fe114 differ diff --git a/storage/textures/6c368e7678f892348cb1c90d897acf8cebef86440fa363b8b860dce1f35b1cb5 b/storage/textures/6c368e7678f892348cb1c90d897acf8cebef86440fa363b8b860dce1f35b1cb5 new file mode 100644 index 0000000..9a33c61 Binary files /dev/null and b/storage/textures/6c368e7678f892348cb1c90d897acf8cebef86440fa363b8b860dce1f35b1cb5 differ diff --git a/storage/textures/6c46006c11bf497dd22b5a119bf926b2079f945d10ef1409aafaba72a955d231 b/storage/textures/6c46006c11bf497dd22b5a119bf926b2079f945d10ef1409aafaba72a955d231 new file mode 100644 index 0000000..a66cea4 Binary files /dev/null and b/storage/textures/6c46006c11bf497dd22b5a119bf926b2079f945d10ef1409aafaba72a955d231 differ diff --git a/storage/textures/6cb21bc7a7bda8b29597fa80e65eb49173b831c9008a0877962dd6a1cd47db43 b/storage/textures/6cb21bc7a7bda8b29597fa80e65eb49173b831c9008a0877962dd6a1cd47db43 new file mode 100755 index 0000000..d48186d Binary files /dev/null and b/storage/textures/6cb21bc7a7bda8b29597fa80e65eb49173b831c9008a0877962dd6a1cd47db43 differ diff --git a/storage/textures/6cef0b7a85685f54f31bec4c68d15627826db2f781c9f2b0f364c593e3a658f9 b/storage/textures/6cef0b7a85685f54f31bec4c68d15627826db2f781c9f2b0f364c593e3a658f9 new file mode 100755 index 0000000..7357186 Binary files /dev/null and b/storage/textures/6cef0b7a85685f54f31bec4c68d15627826db2f781c9f2b0f364c593e3a658f9 differ diff --git a/storage/textures/6cf0b60975e76b56c01d0ea7e35e4d598d8c34bad1bf7d42640d9c27958702e3 b/storage/textures/6cf0b60975e76b56c01d0ea7e35e4d598d8c34bad1bf7d42640d9c27958702e3 new file mode 100755 index 0000000..8436c3c Binary files /dev/null and b/storage/textures/6cf0b60975e76b56c01d0ea7e35e4d598d8c34bad1bf7d42640d9c27958702e3 differ diff --git a/storage/textures/6d703e428effd35ba13d6525c95202014e0d75ef34e964dbe40758386ab476f7 b/storage/textures/6d703e428effd35ba13d6525c95202014e0d75ef34e964dbe40758386ab476f7 new file mode 100755 index 0000000..d1b602f Binary files /dev/null and b/storage/textures/6d703e428effd35ba13d6525c95202014e0d75ef34e964dbe40758386ab476f7 differ diff --git a/storage/textures/6dd3cc2bc4934b13eb29c44d6d589c0a3b3fe522a0ce0d923b3d1f5792eb3162 b/storage/textures/6dd3cc2bc4934b13eb29c44d6d589c0a3b3fe522a0ce0d923b3d1f5792eb3162 new file mode 100644 index 0000000..217e8ea Binary files /dev/null and b/storage/textures/6dd3cc2bc4934b13eb29c44d6d589c0a3b3fe522a0ce0d923b3d1f5792eb3162 differ diff --git a/storage/textures/6e24ff53ce047dfbd4953fbc881efcb2b1a26fbcff72f1df91d740c6bc992584 b/storage/textures/6e24ff53ce047dfbd4953fbc881efcb2b1a26fbcff72f1df91d740c6bc992584 new file mode 100755 index 0000000..c6a18e6 Binary files /dev/null and b/storage/textures/6e24ff53ce047dfbd4953fbc881efcb2b1a26fbcff72f1df91d740c6bc992584 differ diff --git a/storage/textures/6eb7aa19dfec4af7f2d1836372237efbd6ad0d506fc4b0e723a72c133959960f b/storage/textures/6eb7aa19dfec4af7f2d1836372237efbd6ad0d506fc4b0e723a72c133959960f new file mode 100644 index 0000000..a4d2aeb Binary files /dev/null and b/storage/textures/6eb7aa19dfec4af7f2d1836372237efbd6ad0d506fc4b0e723a72c133959960f differ diff --git a/storage/textures/6edc057bd072a0740fd9d42a1bd1f081882582d0da7a8b9908dc2d822bf7b15c b/storage/textures/6edc057bd072a0740fd9d42a1bd1f081882582d0da7a8b9908dc2d822bf7b15c new file mode 100755 index 0000000..9da0500 Binary files /dev/null and b/storage/textures/6edc057bd072a0740fd9d42a1bd1f081882582d0da7a8b9908dc2d822bf7b15c differ diff --git a/storage/textures/6f028f4f2ea70126f0349938dcd259fdec2c3349adfcf93cc12c67ce6ccc4809 b/storage/textures/6f028f4f2ea70126f0349938dcd259fdec2c3349adfcf93cc12c67ce6ccc4809 new file mode 100755 index 0000000..a8ba33a Binary files /dev/null and b/storage/textures/6f028f4f2ea70126f0349938dcd259fdec2c3349adfcf93cc12c67ce6ccc4809 differ diff --git a/storage/textures/6f310f1b604ca4c7f9bbb7846e257ab61de7fbdff9b5f521e419853c2a81d6fc b/storage/textures/6f310f1b604ca4c7f9bbb7846e257ab61de7fbdff9b5f521e419853c2a81d6fc new file mode 100755 index 0000000..909993b Binary files /dev/null and b/storage/textures/6f310f1b604ca4c7f9bbb7846e257ab61de7fbdff9b5f521e419853c2a81d6fc differ diff --git a/storage/textures/6f4dd78f5ae5540af8d358dac48596a1eab3673fb50ddae7218899649bc0f8d6 b/storage/textures/6f4dd78f5ae5540af8d358dac48596a1eab3673fb50ddae7218899649bc0f8d6 new file mode 100755 index 0000000..0426d27 Binary files /dev/null and b/storage/textures/6f4dd78f5ae5540af8d358dac48596a1eab3673fb50ddae7218899649bc0f8d6 differ diff --git a/storage/textures/6f62b4d9d81cb96972caf6b17e688190edbcdf8fcc1754bf563d94856ab3b5f6 b/storage/textures/6f62b4d9d81cb96972caf6b17e688190edbcdf8fcc1754bf563d94856ab3b5f6 new file mode 100755 index 0000000..0a0a11a Binary files /dev/null and b/storage/textures/6f62b4d9d81cb96972caf6b17e688190edbcdf8fcc1754bf563d94856ab3b5f6 differ diff --git a/storage/textures/6fba5d67ecb468b0e8caf568b27275e2abe113754f02047afe7c82e4d214de31 b/storage/textures/6fba5d67ecb468b0e8caf568b27275e2abe113754f02047afe7c82e4d214de31 new file mode 100755 index 0000000..c5792ce Binary files /dev/null and b/storage/textures/6fba5d67ecb468b0e8caf568b27275e2abe113754f02047afe7c82e4d214de31 differ diff --git a/storage/textures/6fcd99d6c81e8f064a1f4296a7f1f6b1c423e2df3fb55558acfe833afa6479cc b/storage/textures/6fcd99d6c81e8f064a1f4296a7f1f6b1c423e2df3fb55558acfe833afa6479cc new file mode 100755 index 0000000..1bb20b2 Binary files /dev/null and b/storage/textures/6fcd99d6c81e8f064a1f4296a7f1f6b1c423e2df3fb55558acfe833afa6479cc differ diff --git a/storage/textures/703999ea48d81d658efe42bad128f7a3aba90d17698a15b36060cc42bdfe2952 b/storage/textures/703999ea48d81d658efe42bad128f7a3aba90d17698a15b36060cc42bdfe2952 new file mode 100755 index 0000000..b44787c Binary files /dev/null and b/storage/textures/703999ea48d81d658efe42bad128f7a3aba90d17698a15b36060cc42bdfe2952 differ diff --git a/storage/textures/706965133a37dc4c19c8f643b4ae5eb5dab01fae14685f1052c71597a5bae269 b/storage/textures/706965133a37dc4c19c8f643b4ae5eb5dab01fae14685f1052c71597a5bae269 new file mode 100755 index 0000000..03bb0db Binary files /dev/null and b/storage/textures/706965133a37dc4c19c8f643b4ae5eb5dab01fae14685f1052c71597a5bae269 differ diff --git a/storage/textures/70c36755dc5a2ae1c311b5f53df1c35c9eb18e754bead68d0203888591aa8d67 b/storage/textures/70c36755dc5a2ae1c311b5f53df1c35c9eb18e754bead68d0203888591aa8d67 new file mode 100644 index 0000000..b11b183 Binary files /dev/null and b/storage/textures/70c36755dc5a2ae1c311b5f53df1c35c9eb18e754bead68d0203888591aa8d67 differ diff --git a/storage/textures/70d5b943243a197c00bb0f679bb64868670f1da4cc0187ec612f48dfab141e88 b/storage/textures/70d5b943243a197c00bb0f679bb64868670f1da4cc0187ec612f48dfab141e88 new file mode 100755 index 0000000..ea51a6c Binary files /dev/null and b/storage/textures/70d5b943243a197c00bb0f679bb64868670f1da4cc0187ec612f48dfab141e88 differ diff --git a/storage/textures/70d85154dae4c64df43fd8f2e0e341d98476e92c02f82dc8f71aaf001c238a48 b/storage/textures/70d85154dae4c64df43fd8f2e0e341d98476e92c02f82dc8f71aaf001c238a48 new file mode 100644 index 0000000..96f7093 Binary files /dev/null and b/storage/textures/70d85154dae4c64df43fd8f2e0e341d98476e92c02f82dc8f71aaf001c238a48 differ diff --git a/storage/textures/70ee74fefc4b246b2bb49fc5f27df0e96420cb97b141763ee3300e360d0b287b b/storage/textures/70ee74fefc4b246b2bb49fc5f27df0e96420cb97b141763ee3300e360d0b287b new file mode 100644 index 0000000..4ddfcc2 Binary files /dev/null and b/storage/textures/70ee74fefc4b246b2bb49fc5f27df0e96420cb97b141763ee3300e360d0b287b differ diff --git a/storage/textures/71037dda8f446d024d98292f74d71f9a28cbc24b185d69ae58884ca575ce3a3f b/storage/textures/71037dda8f446d024d98292f74d71f9a28cbc24b185d69ae58884ca575ce3a3f new file mode 100644 index 0000000..f1a7575 Binary files /dev/null and b/storage/textures/71037dda8f446d024d98292f74d71f9a28cbc24b185d69ae58884ca575ce3a3f differ diff --git a/storage/textures/711cd678a0e8ff74a78f7df6c7964350ee4281bba9234c5bf8569842dba73c6f b/storage/textures/711cd678a0e8ff74a78f7df6c7964350ee4281bba9234c5bf8569842dba73c6f new file mode 100755 index 0000000..0878a7b Binary files /dev/null and b/storage/textures/711cd678a0e8ff74a78f7df6c7964350ee4281bba9234c5bf8569842dba73c6f differ diff --git a/storage/textures/712b9bb445dd8eae8c4494782605d08e6120c6b5a7c1291b95c286c3f8bbca5e b/storage/textures/712b9bb445dd8eae8c4494782605d08e6120c6b5a7c1291b95c286c3f8bbca5e new file mode 100644 index 0000000..17e1268 Binary files /dev/null and b/storage/textures/712b9bb445dd8eae8c4494782605d08e6120c6b5a7c1291b95c286c3f8bbca5e differ diff --git a/storage/textures/717dbef036f8645e2272bd0dbf26f7917c6d3cb9aeba70b0de1ac81571d3f83d b/storage/textures/717dbef036f8645e2272bd0dbf26f7917c6d3cb9aeba70b0de1ac81571d3f83d new file mode 100644 index 0000000..2d7b394 Binary files /dev/null and b/storage/textures/717dbef036f8645e2272bd0dbf26f7917c6d3cb9aeba70b0de1ac81571d3f83d differ diff --git a/storage/textures/723791e97f27c3fc2dbe0f1bfb6fc71b2e83abdb38cbd644ae71aac248d52905 b/storage/textures/723791e97f27c3fc2dbe0f1bfb6fc71b2e83abdb38cbd644ae71aac248d52905 new file mode 100755 index 0000000..0d81c99 Binary files /dev/null and b/storage/textures/723791e97f27c3fc2dbe0f1bfb6fc71b2e83abdb38cbd644ae71aac248d52905 differ diff --git a/storage/textures/72ac4822a81eada376598454f83ad9ea7c296c685f827b4877595112e1acabb9 b/storage/textures/72ac4822a81eada376598454f83ad9ea7c296c685f827b4877595112e1acabb9 new file mode 100755 index 0000000..cfa1266 Binary files /dev/null and b/storage/textures/72ac4822a81eada376598454f83ad9ea7c296c685f827b4877595112e1acabb9 differ diff --git a/storage/textures/734e438098863b61d1f532b493198e4ffd5c590a80bf3cab66931e3e13868580 b/storage/textures/734e438098863b61d1f532b493198e4ffd5c590a80bf3cab66931e3e13868580 new file mode 100755 index 0000000..b0f5d7c Binary files /dev/null and b/storage/textures/734e438098863b61d1f532b493198e4ffd5c590a80bf3cab66931e3e13868580 differ diff --git a/storage/textures/73d5dbbb9e99a4596084cf9d88a0d2af4f45a70b5bc637413241c652978f36cd b/storage/textures/73d5dbbb9e99a4596084cf9d88a0d2af4f45a70b5bc637413241c652978f36cd new file mode 100755 index 0000000..5f6ebb0 Binary files /dev/null and b/storage/textures/73d5dbbb9e99a4596084cf9d88a0d2af4f45a70b5bc637413241c652978f36cd differ diff --git a/storage/textures/741cc3e5ee2572ae304ccbb0a260497a44df2de0b81249f35bdea35678a8259c b/storage/textures/741cc3e5ee2572ae304ccbb0a260497a44df2de0b81249f35bdea35678a8259c new file mode 100755 index 0000000..9ab1365 Binary files /dev/null and b/storage/textures/741cc3e5ee2572ae304ccbb0a260497a44df2de0b81249f35bdea35678a8259c differ diff --git a/storage/textures/74a8cd9439e7656a765ada4d73444d216364e385884e90fb23617616e1fc5572 b/storage/textures/74a8cd9439e7656a765ada4d73444d216364e385884e90fb23617616e1fc5572 new file mode 100755 index 0000000..c3c1de5 Binary files /dev/null and b/storage/textures/74a8cd9439e7656a765ada4d73444d216364e385884e90fb23617616e1fc5572 differ diff --git a/storage/textures/74f9735100724c3df83a0f3d2bae8ce511984a5230e2231b790e50025f16f04f b/storage/textures/74f9735100724c3df83a0f3d2bae8ce511984a5230e2231b790e50025f16f04f new file mode 100755 index 0000000..07f55b9 Binary files /dev/null and b/storage/textures/74f9735100724c3df83a0f3d2bae8ce511984a5230e2231b790e50025f16f04f differ diff --git a/storage/textures/7546195ef633380b6ebf1c20e4e9ca2ffd24a351b597eb6f74b47bdc2363ebfc b/storage/textures/7546195ef633380b6ebf1c20e4e9ca2ffd24a351b597eb6f74b47bdc2363ebfc new file mode 100755 index 0000000..8e03df3 Binary files /dev/null and b/storage/textures/7546195ef633380b6ebf1c20e4e9ca2ffd24a351b597eb6f74b47bdc2363ebfc differ diff --git a/storage/textures/755c5f947bd18f28cfb8c4915fb53f6eeb12ac3318c114b86af35ba348ff86e0 b/storage/textures/755c5f947bd18f28cfb8c4915fb53f6eeb12ac3318c114b86af35ba348ff86e0 new file mode 100755 index 0000000..9418fce Binary files /dev/null and b/storage/textures/755c5f947bd18f28cfb8c4915fb53f6eeb12ac3318c114b86af35ba348ff86e0 differ diff --git a/storage/textures/758230b7d21510f81cd472a6c209fe65fe262b529f5e6dba824c43b66fa554ef b/storage/textures/758230b7d21510f81cd472a6c209fe65fe262b529f5e6dba824c43b66fa554ef new file mode 100644 index 0000000..93d3650 Binary files /dev/null and b/storage/textures/758230b7d21510f81cd472a6c209fe65fe262b529f5e6dba824c43b66fa554ef differ diff --git a/storage/textures/75c397da8be83313a7512e9411ee5f9526774f6ac5a11bbe1a916dccefca8319 b/storage/textures/75c397da8be83313a7512e9411ee5f9526774f6ac5a11bbe1a916dccefca8319 new file mode 100755 index 0000000..c46978f Binary files /dev/null and b/storage/textures/75c397da8be83313a7512e9411ee5f9526774f6ac5a11bbe1a916dccefca8319 differ diff --git a/storage/textures/75e3bab4c804dea042ff3198ca484857542ef1b6818128accc40093d15724446 b/storage/textures/75e3bab4c804dea042ff3198ca484857542ef1b6818128accc40093d15724446 new file mode 100755 index 0000000..0915431 Binary files /dev/null and b/storage/textures/75e3bab4c804dea042ff3198ca484857542ef1b6818128accc40093d15724446 differ diff --git a/storage/textures/75f9e897759a81af54a260b76aa96d782afcd21ba47accfc6c4db8215a3dde24 b/storage/textures/75f9e897759a81af54a260b76aa96d782afcd21ba47accfc6c4db8215a3dde24 new file mode 100755 index 0000000..e0b1964 Binary files /dev/null and b/storage/textures/75f9e897759a81af54a260b76aa96d782afcd21ba47accfc6c4db8215a3dde24 differ diff --git a/storage/textures/7665b0988955dcd886a39ee621a95e081e4544dee3712f35577c9e6a8b34efc5 b/storage/textures/7665b0988955dcd886a39ee621a95e081e4544dee3712f35577c9e6a8b34efc5 new file mode 100755 index 0000000..db4002e Binary files /dev/null and b/storage/textures/7665b0988955dcd886a39ee621a95e081e4544dee3712f35577c9e6a8b34efc5 differ diff --git a/storage/textures/76b342e1d93f736c877f0783806d453ac02f24fc240e052c64c85916e4303620 b/storage/textures/76b342e1d93f736c877f0783806d453ac02f24fc240e052c64c85916e4303620 new file mode 100755 index 0000000..351b1ea Binary files /dev/null and b/storage/textures/76b342e1d93f736c877f0783806d453ac02f24fc240e052c64c85916e4303620 differ diff --git a/storage/textures/76c54bd09f2297f4fdfb055592461c583212b029d313780ad5badfffd07a0680 b/storage/textures/76c54bd09f2297f4fdfb055592461c583212b029d313780ad5badfffd07a0680 new file mode 100644 index 0000000..af0fec5 Binary files /dev/null and b/storage/textures/76c54bd09f2297f4fdfb055592461c583212b029d313780ad5badfffd07a0680 differ diff --git a/storage/textures/76cfe441ecf80271801c17354ec5dd8ded3038b50f7262eaa0d4a4c93afd729d b/storage/textures/76cfe441ecf80271801c17354ec5dd8ded3038b50f7262eaa0d4a4c93afd729d new file mode 100755 index 0000000..606d6b0 Binary files /dev/null and b/storage/textures/76cfe441ecf80271801c17354ec5dd8ded3038b50f7262eaa0d4a4c93afd729d differ diff --git a/storage/textures/76d4dee6673a0cdcb5539706c7a4c8d11827252b1c1fd5e13c53ef2d483ad1ff b/storage/textures/76d4dee6673a0cdcb5539706c7a4c8d11827252b1c1fd5e13c53ef2d483ad1ff new file mode 100755 index 0000000..ee64311 Binary files /dev/null and b/storage/textures/76d4dee6673a0cdcb5539706c7a4c8d11827252b1c1fd5e13c53ef2d483ad1ff differ diff --git a/storage/textures/770bfdca147ad1cc214a423b15e93b79c88542d96409872bc012469090032042 b/storage/textures/770bfdca147ad1cc214a423b15e93b79c88542d96409872bc012469090032042 new file mode 100755 index 0000000..5377b66 Binary files /dev/null and b/storage/textures/770bfdca147ad1cc214a423b15e93b79c88542d96409872bc012469090032042 differ diff --git a/storage/textures/770c0f9a797dd340c32193c776883e9fda4d2635ab35fabff7bfd1eeec7f67ab b/storage/textures/770c0f9a797dd340c32193c776883e9fda4d2635ab35fabff7bfd1eeec7f67ab new file mode 100644 index 0000000..758627c Binary files /dev/null and b/storage/textures/770c0f9a797dd340c32193c776883e9fda4d2635ab35fabff7bfd1eeec7f67ab differ diff --git a/storage/textures/777e67954d5aa82d03cdd3e203677c60ce1e83a5cb2d4aa85c168ef115edce1d b/storage/textures/777e67954d5aa82d03cdd3e203677c60ce1e83a5cb2d4aa85c168ef115edce1d new file mode 100755 index 0000000..d6a1f72 Binary files /dev/null and b/storage/textures/777e67954d5aa82d03cdd3e203677c60ce1e83a5cb2d4aa85c168ef115edce1d differ diff --git a/storage/textures/778ea176eac8a39b670a6fffa3c2ae0f24d78a4c38332b8585d8db08e8d8ac59 b/storage/textures/778ea176eac8a39b670a6fffa3c2ae0f24d78a4c38332b8585d8db08e8d8ac59 new file mode 100755 index 0000000..7a98ce3 Binary files /dev/null and b/storage/textures/778ea176eac8a39b670a6fffa3c2ae0f24d78a4c38332b8585d8db08e8d8ac59 differ diff --git a/storage/textures/77901ae352d14065973d89a1831b3b37fdfd370c083d66ec51740382d9c0556f b/storage/textures/77901ae352d14065973d89a1831b3b37fdfd370c083d66ec51740382d9c0556f new file mode 100755 index 0000000..361b511 Binary files /dev/null and b/storage/textures/77901ae352d14065973d89a1831b3b37fdfd370c083d66ec51740382d9c0556f differ diff --git a/storage/textures/77e278e1a61ef10fd247cea8c953c45762fd6d253e7b8344b4ec16154d5b828e b/storage/textures/77e278e1a61ef10fd247cea8c953c45762fd6d253e7b8344b4ec16154d5b828e new file mode 100755 index 0000000..1f9453e Binary files /dev/null and b/storage/textures/77e278e1a61ef10fd247cea8c953c45762fd6d253e7b8344b4ec16154d5b828e differ diff --git a/storage/textures/7865e1b45677aeab4d9b2fcafba0637247b0ae8cc4f4fd4f69a6dc8acf3c499e b/storage/textures/7865e1b45677aeab4d9b2fcafba0637247b0ae8cc4f4fd4f69a6dc8acf3c499e new file mode 100755 index 0000000..7f833ec Binary files /dev/null and b/storage/textures/7865e1b45677aeab4d9b2fcafba0637247b0ae8cc4f4fd4f69a6dc8acf3c499e differ diff --git a/storage/textures/78a74feb6307d6bda98c476dd8ae6a49726aa19ec71e450c45e552ede853f4f6 b/storage/textures/78a74feb6307d6bda98c476dd8ae6a49726aa19ec71e450c45e552ede853f4f6 new file mode 100644 index 0000000..b839267 Binary files /dev/null and b/storage/textures/78a74feb6307d6bda98c476dd8ae6a49726aa19ec71e450c45e552ede853f4f6 differ diff --git a/storage/textures/79214fc1c379ebc260ed8c1152f779bd4234db37702a639e48e43379e6de945a b/storage/textures/79214fc1c379ebc260ed8c1152f779bd4234db37702a639e48e43379e6de945a new file mode 100755 index 0000000..86b76f8 Binary files /dev/null and b/storage/textures/79214fc1c379ebc260ed8c1152f779bd4234db37702a639e48e43379e6de945a differ diff --git a/storage/textures/794e0d9cd1d0acbb7782945f7556f8e3aa430f9ff437af045c3b5700c16aee4d b/storage/textures/794e0d9cd1d0acbb7782945f7556f8e3aa430f9ff437af045c3b5700c16aee4d new file mode 100755 index 0000000..6272488 Binary files /dev/null and b/storage/textures/794e0d9cd1d0acbb7782945f7556f8e3aa430f9ff437af045c3b5700c16aee4d differ diff --git a/storage/textures/795227dc03ee56183c5eaa6c7cfe3ebf4bb02598b48ac419f69c32259ba4eed6 b/storage/textures/795227dc03ee56183c5eaa6c7cfe3ebf4bb02598b48ac419f69c32259ba4eed6 new file mode 100644 index 0000000..6830a37 Binary files /dev/null and b/storage/textures/795227dc03ee56183c5eaa6c7cfe3ebf4bb02598b48ac419f69c32259ba4eed6 differ diff --git a/storage/textures/79689816d07ded999138082db9cb740094e61443cb677d1cc1eae44f0ab5bbad b/storage/textures/79689816d07ded999138082db9cb740094e61443cb677d1cc1eae44f0ab5bbad new file mode 100755 index 0000000..655b76d Binary files /dev/null and b/storage/textures/79689816d07ded999138082db9cb740094e61443cb677d1cc1eae44f0ab5bbad differ diff --git a/storage/textures/79d2e7b947366289d722c246dd8b1eadee4b749636400ec2386c92a5497f9735 b/storage/textures/79d2e7b947366289d722c246dd8b1eadee4b749636400ec2386c92a5497f9735 new file mode 100755 index 0000000..2c2b544 Binary files /dev/null and b/storage/textures/79d2e7b947366289d722c246dd8b1eadee4b749636400ec2386c92a5497f9735 differ diff --git a/storage/textures/79e23133c389fef0e0e23126dcf78643149ca5e3a586ff3e117112767dba6352 b/storage/textures/79e23133c389fef0e0e23126dcf78643149ca5e3a586ff3e117112767dba6352 new file mode 100755 index 0000000..0cd1562 Binary files /dev/null and b/storage/textures/79e23133c389fef0e0e23126dcf78643149ca5e3a586ff3e117112767dba6352 differ diff --git a/storage/textures/7a13c1e3fd1595c75bb06a1cdeebb15a8518b783ef7abbbf586b1b11d990f46b b/storage/textures/7a13c1e3fd1595c75bb06a1cdeebb15a8518b783ef7abbbf586b1b11d990f46b new file mode 100755 index 0000000..271d819 Binary files /dev/null and b/storage/textures/7a13c1e3fd1595c75bb06a1cdeebb15a8518b783ef7abbbf586b1b11d990f46b differ diff --git a/storage/textures/7a18d65c05dda353dc52778a8ef7dc98784633094bca7b74c50a70032fa72f3a b/storage/textures/7a18d65c05dda353dc52778a8ef7dc98784633094bca7b74c50a70032fa72f3a new file mode 100755 index 0000000..4611380 Binary files /dev/null and b/storage/textures/7a18d65c05dda353dc52778a8ef7dc98784633094bca7b74c50a70032fa72f3a differ diff --git a/storage/textures/7a1f83972d7e33fd53034c93bf4acfda90b7a68f83e7094e7217a6c753584cee b/storage/textures/7a1f83972d7e33fd53034c93bf4acfda90b7a68f83e7094e7217a6c753584cee new file mode 100644 index 0000000..82aff66 Binary files /dev/null and b/storage/textures/7a1f83972d7e33fd53034c93bf4acfda90b7a68f83e7094e7217a6c753584cee differ diff --git a/storage/textures/7aad612a711a828d8edc6e407f4dacf5de5f0e8f00e00c7185076c9a3ff29964 b/storage/textures/7aad612a711a828d8edc6e407f4dacf5de5f0e8f00e00c7185076c9a3ff29964 new file mode 100755 index 0000000..175f894 Binary files /dev/null and b/storage/textures/7aad612a711a828d8edc6e407f4dacf5de5f0e8f00e00c7185076c9a3ff29964 differ diff --git a/storage/textures/7aba0f787f77f78cced531cb289646f8b3204a08a41e7771ce13fb2f65775478 b/storage/textures/7aba0f787f77f78cced531cb289646f8b3204a08a41e7771ce13fb2f65775478 new file mode 100755 index 0000000..c19b1aa Binary files /dev/null and b/storage/textures/7aba0f787f77f78cced531cb289646f8b3204a08a41e7771ce13fb2f65775478 differ diff --git a/storage/textures/7ace63c45212f467bf40df408c200eacd32ae9b5542a4fc10ad026be120cb699 b/storage/textures/7ace63c45212f467bf40df408c200eacd32ae9b5542a4fc10ad026be120cb699 new file mode 100755 index 0000000..998d798 Binary files /dev/null and b/storage/textures/7ace63c45212f467bf40df408c200eacd32ae9b5542a4fc10ad026be120cb699 differ diff --git a/storage/textures/7b216aadea8492d0515db5c4fceecee730c5124bba545904176454112aa38209 b/storage/textures/7b216aadea8492d0515db5c4fceecee730c5124bba545904176454112aa38209 new file mode 100755 index 0000000..c619204 Binary files /dev/null and b/storage/textures/7b216aadea8492d0515db5c4fceecee730c5124bba545904176454112aa38209 differ diff --git a/storage/textures/7b42b94f81930a91a1cd7b9b956ade3680967eee494097529ae461449dcbe08a b/storage/textures/7b42b94f81930a91a1cd7b9b956ade3680967eee494097529ae461449dcbe08a new file mode 100755 index 0000000..cb9207c Binary files /dev/null and b/storage/textures/7b42b94f81930a91a1cd7b9b956ade3680967eee494097529ae461449dcbe08a differ diff --git a/storage/textures/7b6402182c553dbefbea924d7832fa4feb39ce182aaf96aa9fdcda009461a22e b/storage/textures/7b6402182c553dbefbea924d7832fa4feb39ce182aaf96aa9fdcda009461a22e new file mode 100755 index 0000000..678922e Binary files /dev/null and b/storage/textures/7b6402182c553dbefbea924d7832fa4feb39ce182aaf96aa9fdcda009461a22e differ diff --git a/storage/textures/7c3df22256bbde676cfae43ce5ce36d01c3b41d401bc13015470e23666c86b5e b/storage/textures/7c3df22256bbde676cfae43ce5ce36d01c3b41d401bc13015470e23666c86b5e new file mode 100755 index 0000000..bf7037b Binary files /dev/null and b/storage/textures/7c3df22256bbde676cfae43ce5ce36d01c3b41d401bc13015470e23666c86b5e differ diff --git a/storage/textures/7c3f56f6067c676ef56e373ac18c7219f7b19b539ca40afb2f8fe2332f7b9b8d b/storage/textures/7c3f56f6067c676ef56e373ac18c7219f7b19b539ca40afb2f8fe2332f7b9b8d new file mode 100755 index 0000000..96d7c53 Binary files /dev/null and b/storage/textures/7c3f56f6067c676ef56e373ac18c7219f7b19b539ca40afb2f8fe2332f7b9b8d differ diff --git a/storage/textures/7c9f18b411e771dc68b047337836186a68ba45045369f28ae09c873ddd58d0ca b/storage/textures/7c9f18b411e771dc68b047337836186a68ba45045369f28ae09c873ddd58d0ca new file mode 100644 index 0000000..c711aaf Binary files /dev/null and b/storage/textures/7c9f18b411e771dc68b047337836186a68ba45045369f28ae09c873ddd58d0ca differ diff --git a/storage/textures/7ca11f04668435fe61906bb0213eaae7546df2fd73ef3e37c1b32183a6c79fdd b/storage/textures/7ca11f04668435fe61906bb0213eaae7546df2fd73ef3e37c1b32183a6c79fdd new file mode 100755 index 0000000..78d6819 Binary files /dev/null and b/storage/textures/7ca11f04668435fe61906bb0213eaae7546df2fd73ef3e37c1b32183a6c79fdd differ diff --git a/storage/textures/7ca6502b719769fc9280b0e73a992144c997d041c0f8fe06a2558941ccd19846 b/storage/textures/7ca6502b719769fc9280b0e73a992144c997d041c0f8fe06a2558941ccd19846 new file mode 100644 index 0000000..1e1a869 Binary files /dev/null and b/storage/textures/7ca6502b719769fc9280b0e73a992144c997d041c0f8fe06a2558941ccd19846 differ diff --git a/storage/textures/7cb0331d93732c7d7d1617f3af4bdaac202c69f6466ea3c41faad6f05a85a1c4 b/storage/textures/7cb0331d93732c7d7d1617f3af4bdaac202c69f6466ea3c41faad6f05a85a1c4 new file mode 100644 index 0000000..ec06bcb Binary files /dev/null and b/storage/textures/7cb0331d93732c7d7d1617f3af4bdaac202c69f6466ea3c41faad6f05a85a1c4 differ diff --git a/storage/textures/7cbb8c614f9dfb24756d5b3380d05e9da56b7ca5a34677313dcc962f3b0bf061 b/storage/textures/7cbb8c614f9dfb24756d5b3380d05e9da56b7ca5a34677313dcc962f3b0bf061 new file mode 100755 index 0000000..8ace51b Binary files /dev/null and b/storage/textures/7cbb8c614f9dfb24756d5b3380d05e9da56b7ca5a34677313dcc962f3b0bf061 differ diff --git a/storage/textures/7d19962de7452c1ed206e745cdea56260fa8325bc98b1b3c373a7328bebe7a86 b/storage/textures/7d19962de7452c1ed206e745cdea56260fa8325bc98b1b3c373a7328bebe7a86 new file mode 100755 index 0000000..98b0851 Binary files /dev/null and b/storage/textures/7d19962de7452c1ed206e745cdea56260fa8325bc98b1b3c373a7328bebe7a86 differ diff --git a/storage/textures/7d28d508c75fafc2a8932afdec2be9a43398448dc5a5d121e444fbe709f67e7a b/storage/textures/7d28d508c75fafc2a8932afdec2be9a43398448dc5a5d121e444fbe709f67e7a new file mode 100644 index 0000000..f611cad Binary files /dev/null and b/storage/textures/7d28d508c75fafc2a8932afdec2be9a43398448dc5a5d121e444fbe709f67e7a differ diff --git a/storage/textures/7e2780464fdb4f5e699f960b31c22a9b7f27911bbf33815d9bdbebd9fc208aad b/storage/textures/7e2780464fdb4f5e699f960b31c22a9b7f27911bbf33815d9bdbebd9fc208aad new file mode 100755 index 0000000..e7a99b2 Binary files /dev/null and b/storage/textures/7e2780464fdb4f5e699f960b31c22a9b7f27911bbf33815d9bdbebd9fc208aad differ diff --git a/storage/textures/7e73833c8487a30c61660c445d12d3dd1a57715a8786cd9f8b129d6ffa98cb27 b/storage/textures/7e73833c8487a30c61660c445d12d3dd1a57715a8786cd9f8b129d6ffa98cb27 new file mode 100644 index 0000000..b12e5d1 Binary files /dev/null and b/storage/textures/7e73833c8487a30c61660c445d12d3dd1a57715a8786cd9f8b129d6ffa98cb27 differ diff --git a/storage/textures/7e879523dbb2f5a6adc49ebf2984df48e8c809682bd59e2e7f21491f6b7652f2 b/storage/textures/7e879523dbb2f5a6adc49ebf2984df48e8c809682bd59e2e7f21491f6b7652f2 new file mode 100644 index 0000000..49c49c5 Binary files /dev/null and b/storage/textures/7e879523dbb2f5a6adc49ebf2984df48e8c809682bd59e2e7f21491f6b7652f2 differ diff --git a/storage/textures/7ea3f5d4a858a9031ee367ea0a1e61fe8628630deb1116a6b061aab0251b324e b/storage/textures/7ea3f5d4a858a9031ee367ea0a1e61fe8628630deb1116a6b061aab0251b324e new file mode 100644 index 0000000..9d161d9 Binary files /dev/null and b/storage/textures/7ea3f5d4a858a9031ee367ea0a1e61fe8628630deb1116a6b061aab0251b324e differ diff --git a/storage/textures/7ee62c3a41a125dd9b687c8e6357991b1611655194aed55fc7b3ae9e33c63aa5 b/storage/textures/7ee62c3a41a125dd9b687c8e6357991b1611655194aed55fc7b3ae9e33c63aa5 new file mode 100755 index 0000000..9699322 Binary files /dev/null and b/storage/textures/7ee62c3a41a125dd9b687c8e6357991b1611655194aed55fc7b3ae9e33c63aa5 differ diff --git a/storage/textures/7f0e6a9dc475b897e60a9f57ace9523f6e1308907130705e267d5e97b51c3954 b/storage/textures/7f0e6a9dc475b897e60a9f57ace9523f6e1308907130705e267d5e97b51c3954 new file mode 100755 index 0000000..7d4e8e3 Binary files /dev/null and b/storage/textures/7f0e6a9dc475b897e60a9f57ace9523f6e1308907130705e267d5e97b51c3954 differ diff --git a/storage/textures/7f1ccf061bbaea0b46312cc688387e0bd29cb365109c0482ee0ca0603be19790 b/storage/textures/7f1ccf061bbaea0b46312cc688387e0bd29cb365109c0482ee0ca0603be19790 new file mode 100755 index 0000000..fe66685 Binary files /dev/null and b/storage/textures/7f1ccf061bbaea0b46312cc688387e0bd29cb365109c0482ee0ca0603be19790 differ diff --git a/storage/textures/7f39f89d63a1eb6827f21aeed6b60faaf184abb1ebb7569c80f4b4f3e00ca618 b/storage/textures/7f39f89d63a1eb6827f21aeed6b60faaf184abb1ebb7569c80f4b4f3e00ca618 new file mode 100755 index 0000000..008631e Binary files /dev/null and b/storage/textures/7f39f89d63a1eb6827f21aeed6b60faaf184abb1ebb7569c80f4b4f3e00ca618 differ diff --git a/storage/textures/7f7d219358b49a9aa055d83573b6b71e189eee5ddf9b153273022690331c04ef b/storage/textures/7f7d219358b49a9aa055d83573b6b71e189eee5ddf9b153273022690331c04ef new file mode 100755 index 0000000..0ee0a14 Binary files /dev/null and b/storage/textures/7f7d219358b49a9aa055d83573b6b71e189eee5ddf9b153273022690331c04ef differ diff --git a/storage/textures/7fb52f965115601d0ba4927cdd22c897e5695a67ce951052051fb76a4c08dc92 b/storage/textures/7fb52f965115601d0ba4927cdd22c897e5695a67ce951052051fb76a4c08dc92 new file mode 100644 index 0000000..829d26f Binary files /dev/null and b/storage/textures/7fb52f965115601d0ba4927cdd22c897e5695a67ce951052051fb76a4c08dc92 differ diff --git a/storage/textures/807b32a1ff1f293a5f038064f16870280ea4ae0370c83aaf4d4b7569e3b3edf6 b/storage/textures/807b32a1ff1f293a5f038064f16870280ea4ae0370c83aaf4d4b7569e3b3edf6 new file mode 100755 index 0000000..4a4e38a Binary files /dev/null and b/storage/textures/807b32a1ff1f293a5f038064f16870280ea4ae0370c83aaf4d4b7569e3b3edf6 differ diff --git a/storage/textures/80d4ab43ffd6bd705a40aecdcabd4b8c510877c86ce77c19f1d12471ba2348d7 b/storage/textures/80d4ab43ffd6bd705a40aecdcabd4b8c510877c86ce77c19f1d12471ba2348d7 new file mode 100755 index 0000000..c25c503 Binary files /dev/null and b/storage/textures/80d4ab43ffd6bd705a40aecdcabd4b8c510877c86ce77c19f1d12471ba2348d7 differ diff --git a/storage/textures/812d9b938e7ece471f6a7b0cbbfe5330953d76987d7ce80cdf89ef73f3e04e48 b/storage/textures/812d9b938e7ece471f6a7b0cbbfe5330953d76987d7ce80cdf89ef73f3e04e48 new file mode 100755 index 0000000..76f7a62 Binary files /dev/null and b/storage/textures/812d9b938e7ece471f6a7b0cbbfe5330953d76987d7ce80cdf89ef73f3e04e48 differ diff --git a/storage/textures/81b29f2567c18ad58c4a51d26b9760f76475d085896a384bd150a7c373f8342c b/storage/textures/81b29f2567c18ad58c4a51d26b9760f76475d085896a384bd150a7c373f8342c new file mode 100755 index 0000000..1af182c Binary files /dev/null and b/storage/textures/81b29f2567c18ad58c4a51d26b9760f76475d085896a384bd150a7c373f8342c differ diff --git a/storage/textures/81fdb8e77cd366951bf121315263764a0cdc4f277775b0d7eeb007b4b64fe6aa b/storage/textures/81fdb8e77cd366951bf121315263764a0cdc4f277775b0d7eeb007b4b64fe6aa new file mode 100755 index 0000000..02a55f0 Binary files /dev/null and b/storage/textures/81fdb8e77cd366951bf121315263764a0cdc4f277775b0d7eeb007b4b64fe6aa differ diff --git a/storage/textures/81ff6486e72b3607e219ddda9fb083be04d356c7b90098eaf8d483e303bdc491 b/storage/textures/81ff6486e72b3607e219ddda9fb083be04d356c7b90098eaf8d483e303bdc491 new file mode 100755 index 0000000..a1133e4 Binary files /dev/null and b/storage/textures/81ff6486e72b3607e219ddda9fb083be04d356c7b90098eaf8d483e303bdc491 differ diff --git a/storage/textures/8252dbe44d907d97380a8cfb807edb7314b056d0bad9f1c770e30945a173e5d4 b/storage/textures/8252dbe44d907d97380a8cfb807edb7314b056d0bad9f1c770e30945a173e5d4 new file mode 100755 index 0000000..deb7f25 Binary files /dev/null and b/storage/textures/8252dbe44d907d97380a8cfb807edb7314b056d0bad9f1c770e30945a173e5d4 differ diff --git a/storage/textures/82f2fa72cb0673d3180a2deadcb50d2d7695b31d67303c4c885988a9fa609242 b/storage/textures/82f2fa72cb0673d3180a2deadcb50d2d7695b31d67303c4c885988a9fa609242 new file mode 100755 index 0000000..a0223b6 Binary files /dev/null and b/storage/textures/82f2fa72cb0673d3180a2deadcb50d2d7695b31d67303c4c885988a9fa609242 differ diff --git a/storage/textures/8382253dc22b08f7881f1dbe79dbec197244da7bcab2f2d99b3f76b83aeb13f7 b/storage/textures/8382253dc22b08f7881f1dbe79dbec197244da7bcab2f2d99b3f76b83aeb13f7 new file mode 100644 index 0000000..32732b1 Binary files /dev/null and b/storage/textures/8382253dc22b08f7881f1dbe79dbec197244da7bcab2f2d99b3f76b83aeb13f7 differ diff --git a/storage/textures/83cee5ca6afcdb171285aa00e8049c297b2dbeba0efb8ff970a5677a1b644032 b/storage/textures/83cee5ca6afcdb171285aa00e8049c297b2dbeba0efb8ff970a5677a1b644032 new file mode 100755 index 0000000..ffd8e07 Binary files /dev/null and b/storage/textures/83cee5ca6afcdb171285aa00e8049c297b2dbeba0efb8ff970a5677a1b644032 differ diff --git a/storage/textures/83e9ca1c203e8a39b1fed93e7b8860409b65f3e7eba1f4fd53a3edf5d9955433 b/storage/textures/83e9ca1c203e8a39b1fed93e7b8860409b65f3e7eba1f4fd53a3edf5d9955433 new file mode 100644 index 0000000..5a87af5 Binary files /dev/null and b/storage/textures/83e9ca1c203e8a39b1fed93e7b8860409b65f3e7eba1f4fd53a3edf5d9955433 differ diff --git a/storage/textures/8403806971e179012410c1208f87fb127549defa710dd10040f591fd7dc9e367 b/storage/textures/8403806971e179012410c1208f87fb127549defa710dd10040f591fd7dc9e367 new file mode 100755 index 0000000..b80a323 Binary files /dev/null and b/storage/textures/8403806971e179012410c1208f87fb127549defa710dd10040f591fd7dc9e367 differ diff --git a/storage/textures/84176144ec5b8326616c750cd79bc0c0a0aa21481bfce983f344987331900a13 b/storage/textures/84176144ec5b8326616c750cd79bc0c0a0aa21481bfce983f344987331900a13 new file mode 100644 index 0000000..f07508e Binary files /dev/null and b/storage/textures/84176144ec5b8326616c750cd79bc0c0a0aa21481bfce983f344987331900a13 differ diff --git a/storage/textures/844b59d35591108c408a0a2c3d559806f265bf1c1544d6d89a653e84b6a39412 b/storage/textures/844b59d35591108c408a0a2c3d559806f265bf1c1544d6d89a653e84b6a39412 new file mode 100644 index 0000000..3f2ad31 Binary files /dev/null and b/storage/textures/844b59d35591108c408a0a2c3d559806f265bf1c1544d6d89a653e84b6a39412 differ diff --git a/storage/textures/845a451053de78ea727e2aa1380d56413dc79c4a10a4731b786f63af1649a540 b/storage/textures/845a451053de78ea727e2aa1380d56413dc79c4a10a4731b786f63af1649a540 new file mode 100644 index 0000000..19a9574 Binary files /dev/null and b/storage/textures/845a451053de78ea727e2aa1380d56413dc79c4a10a4731b786f63af1649a540 differ diff --git a/storage/textures/845dd6e583dd32526f941fa80f3a27e59e60974ab1f06909b2e6533160032ce6 b/storage/textures/845dd6e583dd32526f941fa80f3a27e59e60974ab1f06909b2e6533160032ce6 new file mode 100755 index 0000000..9bba1c7 Binary files /dev/null and b/storage/textures/845dd6e583dd32526f941fa80f3a27e59e60974ab1f06909b2e6533160032ce6 differ diff --git a/storage/textures/849dc4d2c6c458f1f95b102f09459fc7e26a13fcd2cef951aef005c85ff5a17c b/storage/textures/849dc4d2c6c458f1f95b102f09459fc7e26a13fcd2cef951aef005c85ff5a17c new file mode 100755 index 0000000..a6cd69e Binary files /dev/null and b/storage/textures/849dc4d2c6c458f1f95b102f09459fc7e26a13fcd2cef951aef005c85ff5a17c differ diff --git a/storage/textures/84b84dbcbe01453a3fa8504c7f5689d982448e85944c30f86216f804bb72ab01 b/storage/textures/84b84dbcbe01453a3fa8504c7f5689d982448e85944c30f86216f804bb72ab01 new file mode 100755 index 0000000..6e65a2b Binary files /dev/null and b/storage/textures/84b84dbcbe01453a3fa8504c7f5689d982448e85944c30f86216f804bb72ab01 differ diff --git a/storage/textures/84c73e92d5f2448d0ce3075a658d86af838e4331611a877b79f1b13240951b4f b/storage/textures/84c73e92d5f2448d0ce3075a658d86af838e4331611a877b79f1b13240951b4f new file mode 100644 index 0000000..c2eaf63 Binary files /dev/null and b/storage/textures/84c73e92d5f2448d0ce3075a658d86af838e4331611a877b79f1b13240951b4f differ diff --git a/storage/textures/84c9b2f5e24e43e9f7b0073ea83dcad16736831a83ebe1efc14c30607f8e547c b/storage/textures/84c9b2f5e24e43e9f7b0073ea83dcad16736831a83ebe1efc14c30607f8e547c new file mode 100644 index 0000000..b1cf621 Binary files /dev/null and b/storage/textures/84c9b2f5e24e43e9f7b0073ea83dcad16736831a83ebe1efc14c30607f8e547c differ diff --git a/storage/textures/84ddbde1a8976324a26b3a76036ba2f92d7de4fb67140ada25677a3aadcf1f69 b/storage/textures/84ddbde1a8976324a26b3a76036ba2f92d7de4fb67140ada25677a3aadcf1f69 new file mode 100644 index 0000000..030a6a0 Binary files /dev/null and b/storage/textures/84ddbde1a8976324a26b3a76036ba2f92d7de4fb67140ada25677a3aadcf1f69 differ diff --git a/storage/textures/84fa67f35cbb09bf1b4fd723a73b8af03034e34846f9dabd53a341952cde6391 b/storage/textures/84fa67f35cbb09bf1b4fd723a73b8af03034e34846f9dabd53a341952cde6391 new file mode 100644 index 0000000..7d98daf Binary files /dev/null and b/storage/textures/84fa67f35cbb09bf1b4fd723a73b8af03034e34846f9dabd53a341952cde6391 differ diff --git a/storage/textures/854d0b7c865fcf6306b0a1c09ae991d3955a8fa68032769f706ce3682750ef2b b/storage/textures/854d0b7c865fcf6306b0a1c09ae991d3955a8fa68032769f706ce3682750ef2b new file mode 100755 index 0000000..6360bd7 Binary files /dev/null and b/storage/textures/854d0b7c865fcf6306b0a1c09ae991d3955a8fa68032769f706ce3682750ef2b differ diff --git a/storage/textures/858f92dbe13a51a8b172f82d4cb30e963e91b094fcf8877577bd3c7dc753657f b/storage/textures/858f92dbe13a51a8b172f82d4cb30e963e91b094fcf8877577bd3c7dc753657f new file mode 100755 index 0000000..7ad06e7 Binary files /dev/null and b/storage/textures/858f92dbe13a51a8b172f82d4cb30e963e91b094fcf8877577bd3c7dc753657f differ diff --git a/storage/textures/85ae7eecc5b037191ea5942ed038ecde23012300333c80323ae4429370e0d387 b/storage/textures/85ae7eecc5b037191ea5942ed038ecde23012300333c80323ae4429370e0d387 new file mode 100755 index 0000000..b8e5651 Binary files /dev/null and b/storage/textures/85ae7eecc5b037191ea5942ed038ecde23012300333c80323ae4429370e0d387 differ diff --git a/storage/textures/85ea6ed45bf612f41db2c865dba18350cf1b9eeb8b1c3c753782c6051f1eabf3 b/storage/textures/85ea6ed45bf612f41db2c865dba18350cf1b9eeb8b1c3c753782c6051f1eabf3 new file mode 100755 index 0000000..65152f4 Binary files /dev/null and b/storage/textures/85ea6ed45bf612f41db2c865dba18350cf1b9eeb8b1c3c753782c6051f1eabf3 differ diff --git a/storage/textures/860a20e103194b30f4dc69caea40799a2a07bd674763ec28b623c1112dd21eba b/storage/textures/860a20e103194b30f4dc69caea40799a2a07bd674763ec28b623c1112dd21eba new file mode 100755 index 0000000..d19f866 Binary files /dev/null and b/storage/textures/860a20e103194b30f4dc69caea40799a2a07bd674763ec28b623c1112dd21eba differ diff --git a/storage/textures/863ca5e9f634f8fe0afaea71bb74f255069fb783d3d10a0eed45da3d7a670205 b/storage/textures/863ca5e9f634f8fe0afaea71bb74f255069fb783d3d10a0eed45da3d7a670205 new file mode 100755 index 0000000..6e0eb6e Binary files /dev/null and b/storage/textures/863ca5e9f634f8fe0afaea71bb74f255069fb783d3d10a0eed45da3d7a670205 differ diff --git a/storage/textures/86549ffdad718b1db3a56d7534d106665560548ac6b1738d417b564ee8bc44f2 b/storage/textures/86549ffdad718b1db3a56d7534d106665560548ac6b1738d417b564ee8bc44f2 new file mode 100755 index 0000000..41a4935 Binary files /dev/null and b/storage/textures/86549ffdad718b1db3a56d7534d106665560548ac6b1738d417b564ee8bc44f2 differ diff --git a/storage/textures/867627f4f41e2b335e7c9057648bdabfe1b33c24549a77d558351a5746dde46d b/storage/textures/867627f4f41e2b335e7c9057648bdabfe1b33c24549a77d558351a5746dde46d new file mode 100755 index 0000000..1d831e2 Binary files /dev/null and b/storage/textures/867627f4f41e2b335e7c9057648bdabfe1b33c24549a77d558351a5746dde46d differ diff --git a/storage/textures/868a41ba6da49b7c6190bb68b4c9511660dc27a1e392eebb67ed0b92f32e7342 b/storage/textures/868a41ba6da49b7c6190bb68b4c9511660dc27a1e392eebb67ed0b92f32e7342 new file mode 100755 index 0000000..1dd0362 Binary files /dev/null and b/storage/textures/868a41ba6da49b7c6190bb68b4c9511660dc27a1e392eebb67ed0b92f32e7342 differ diff --git a/storage/textures/86c8cd20db94c56bd19ff18476c8368f8bea3e2d1c39a9b7fa2c51a2b3cf0550 b/storage/textures/86c8cd20db94c56bd19ff18476c8368f8bea3e2d1c39a9b7fa2c51a2b3cf0550 new file mode 100755 index 0000000..bc1d504 Binary files /dev/null and b/storage/textures/86c8cd20db94c56bd19ff18476c8368f8bea3e2d1c39a9b7fa2c51a2b3cf0550 differ diff --git a/storage/textures/86d9e64cf06469ca733407c0839bf8d4822710f8a1e051beaaae34014fca77b6 b/storage/textures/86d9e64cf06469ca733407c0839bf8d4822710f8a1e051beaaae34014fca77b6 new file mode 100755 index 0000000..98710f0 Binary files /dev/null and b/storage/textures/86d9e64cf06469ca733407c0839bf8d4822710f8a1e051beaaae34014fca77b6 differ diff --git a/storage/textures/8738d22a4241a1f35bd405eef68a0309265e43dab98d8b02e2a9139f089b0950 b/storage/textures/8738d22a4241a1f35bd405eef68a0309265e43dab98d8b02e2a9139f089b0950 new file mode 100755 index 0000000..cf88e21 Binary files /dev/null and b/storage/textures/8738d22a4241a1f35bd405eef68a0309265e43dab98d8b02e2a9139f089b0950 differ diff --git a/storage/textures/8863476b7854f08a8fdd2dd2b5d774c02a4bd5aee9fb24cb54183e90ddf7ea69 b/storage/textures/8863476b7854f08a8fdd2dd2b5d774c02a4bd5aee9fb24cb54183e90ddf7ea69 new file mode 100755 index 0000000..478ff44 Binary files /dev/null and b/storage/textures/8863476b7854f08a8fdd2dd2b5d774c02a4bd5aee9fb24cb54183e90ddf7ea69 differ diff --git a/storage/textures/88bc00f6de6d51092fe08ee31352fd5a6c5848e7ae80cd9ee22d3dcf739bde2b b/storage/textures/88bc00f6de6d51092fe08ee31352fd5a6c5848e7ae80cd9ee22d3dcf739bde2b new file mode 100755 index 0000000..f114521 Binary files /dev/null and b/storage/textures/88bc00f6de6d51092fe08ee31352fd5a6c5848e7ae80cd9ee22d3dcf739bde2b differ diff --git a/storage/textures/88d06af050fd664af4bd82e2ce0212d1c5ad6297c9e60fedd005feb2b4de9451 b/storage/textures/88d06af050fd664af4bd82e2ce0212d1c5ad6297c9e60fedd005feb2b4de9451 new file mode 100755 index 0000000..f2097d8 Binary files /dev/null and b/storage/textures/88d06af050fd664af4bd82e2ce0212d1c5ad6297c9e60fedd005feb2b4de9451 differ diff --git a/storage/textures/89008d9f934fb6e724e583b3c3b463e96adcb9a766b2593c33bd990359038b21 b/storage/textures/89008d9f934fb6e724e583b3c3b463e96adcb9a766b2593c33bd990359038b21 new file mode 100755 index 0000000..07c4e5f Binary files /dev/null and b/storage/textures/89008d9f934fb6e724e583b3c3b463e96adcb9a766b2593c33bd990359038b21 differ diff --git a/storage/textures/89185a203dc32064e19e49872bb0dc57da94c4283e145f61c3581f2609d976e3 b/storage/textures/89185a203dc32064e19e49872bb0dc57da94c4283e145f61c3581f2609d976e3 new file mode 100755 index 0000000..7f48cf8 Binary files /dev/null and b/storage/textures/89185a203dc32064e19e49872bb0dc57da94c4283e145f61c3581f2609d976e3 differ diff --git a/storage/textures/8988649bc5901e4bb36eec5f74e21849551c5208cc0a433075b48760151b6c91 b/storage/textures/8988649bc5901e4bb36eec5f74e21849551c5208cc0a433075b48760151b6c91 new file mode 100755 index 0000000..4c0a73f Binary files /dev/null and b/storage/textures/8988649bc5901e4bb36eec5f74e21849551c5208cc0a433075b48760151b6c91 differ diff --git a/storage/textures/89c1c3f0cb596f4d2e3d2d175c65779c67b5a849714752481624a59e517bb5e7 b/storage/textures/89c1c3f0cb596f4d2e3d2d175c65779c67b5a849714752481624a59e517bb5e7 new file mode 100755 index 0000000..36e4615 Binary files /dev/null and b/storage/textures/89c1c3f0cb596f4d2e3d2d175c65779c67b5a849714752481624a59e517bb5e7 differ diff --git a/storage/textures/89c814797470c1487a1be15e881a5fae8db126a3c0696fd0506722b8da32f9ca b/storage/textures/89c814797470c1487a1be15e881a5fae8db126a3c0696fd0506722b8da32f9ca new file mode 100755 index 0000000..fe5d33c Binary files /dev/null and b/storage/textures/89c814797470c1487a1be15e881a5fae8db126a3c0696fd0506722b8da32f9ca differ diff --git a/storage/textures/89ff25a4d3563d72b1dea36803c5697e70adb6a42e262ee7523c8c19026fe917 b/storage/textures/89ff25a4d3563d72b1dea36803c5697e70adb6a42e262ee7523c8c19026fe917 new file mode 100755 index 0000000..85f7287 Binary files /dev/null and b/storage/textures/89ff25a4d3563d72b1dea36803c5697e70adb6a42e262ee7523c8c19026fe917 differ diff --git a/storage/textures/8a0a97fde730e32cdd156aabf86c413a7a994132af2f2b2a2fe1a3a3395d8796 b/storage/textures/8a0a97fde730e32cdd156aabf86c413a7a994132af2f2b2a2fe1a3a3395d8796 new file mode 100644 index 0000000..73c9869 Binary files /dev/null and b/storage/textures/8a0a97fde730e32cdd156aabf86c413a7a994132af2f2b2a2fe1a3a3395d8796 differ diff --git a/storage/textures/8ab0fb59a76b0edf819b3963f591473301a57c3e602ad96e325aabe9261e4dba b/storage/textures/8ab0fb59a76b0edf819b3963f591473301a57c3e602ad96e325aabe9261e4dba new file mode 100755 index 0000000..e2f4012 Binary files /dev/null and b/storage/textures/8ab0fb59a76b0edf819b3963f591473301a57c3e602ad96e325aabe9261e4dba differ diff --git a/storage/textures/8b40e666cc13c77b6f64a48fd54adb5ffe2b5b6da893623bc23a1bc38497f0cc b/storage/textures/8b40e666cc13c77b6f64a48fd54adb5ffe2b5b6da893623bc23a1bc38497f0cc new file mode 100755 index 0000000..514da8a Binary files /dev/null and b/storage/textures/8b40e666cc13c77b6f64a48fd54adb5ffe2b5b6da893623bc23a1bc38497f0cc differ diff --git a/storage/textures/8b6b15daf531a03477e2e248778ef7387aa37883c2f86a2e92bef4ed1ab66e5e b/storage/textures/8b6b15daf531a03477e2e248778ef7387aa37883c2f86a2e92bef4ed1ab66e5e new file mode 100755 index 0000000..e6100dc Binary files /dev/null and b/storage/textures/8b6b15daf531a03477e2e248778ef7387aa37883c2f86a2e92bef4ed1ab66e5e differ diff --git a/storage/textures/8b954c5f00517dbeeecf85a4b8ced562256afea9c12ba03be3f0992f0417f85a b/storage/textures/8b954c5f00517dbeeecf85a4b8ced562256afea9c12ba03be3f0992f0417f85a new file mode 100755 index 0000000..0609272 Binary files /dev/null and b/storage/textures/8b954c5f00517dbeeecf85a4b8ced562256afea9c12ba03be3f0992f0417f85a differ diff --git a/storage/textures/8c719831623c05d8c519f04838498b54e22ee0390662ebe3c102b1fcc6a34ea5 b/storage/textures/8c719831623c05d8c519f04838498b54e22ee0390662ebe3c102b1fcc6a34ea5 new file mode 100755 index 0000000..adb715e Binary files /dev/null and b/storage/textures/8c719831623c05d8c519f04838498b54e22ee0390662ebe3c102b1fcc6a34ea5 differ diff --git a/storage/textures/8c82abe9e8ab721e98eed71f2b26d2d7d65f298d703d403c6cce32073e910fa0 b/storage/textures/8c82abe9e8ab721e98eed71f2b26d2d7d65f298d703d403c6cce32073e910fa0 new file mode 100755 index 0000000..3265920 Binary files /dev/null and b/storage/textures/8c82abe9e8ab721e98eed71f2b26d2d7d65f298d703d403c6cce32073e910fa0 differ diff --git a/storage/textures/8cb1cddb146d2d3588c6686ed16796e8eeb2f928fd96a7caa19b829b63d1570c b/storage/textures/8cb1cddb146d2d3588c6686ed16796e8eeb2f928fd96a7caa19b829b63d1570c new file mode 100755 index 0000000..a2e2251 Binary files /dev/null and b/storage/textures/8cb1cddb146d2d3588c6686ed16796e8eeb2f928fd96a7caa19b829b63d1570c differ diff --git a/storage/textures/8d2c8d9fcf0e75df8685c766718aea4306a19ec0e207210233f875e818ed0b8f b/storage/textures/8d2c8d9fcf0e75df8685c766718aea4306a19ec0e207210233f875e818ed0b8f new file mode 100755 index 0000000..8b1504c Binary files /dev/null and b/storage/textures/8d2c8d9fcf0e75df8685c766718aea4306a19ec0e207210233f875e818ed0b8f differ diff --git a/storage/textures/8d3faa68974a17b29aa8120d1f5fa1aa605c1e75b75478bab06c52ec6806bd68 b/storage/textures/8d3faa68974a17b29aa8120d1f5fa1aa605c1e75b75478bab06c52ec6806bd68 new file mode 100644 index 0000000..4408210 Binary files /dev/null and b/storage/textures/8d3faa68974a17b29aa8120d1f5fa1aa605c1e75b75478bab06c52ec6806bd68 differ diff --git a/storage/textures/8d48245672d6a0e26595e0376313598fda9bc220a6ed17f6e4cd4d169838e500 b/storage/textures/8d48245672d6a0e26595e0376313598fda9bc220a6ed17f6e4cd4d169838e500 new file mode 100755 index 0000000..652223c Binary files /dev/null and b/storage/textures/8d48245672d6a0e26595e0376313598fda9bc220a6ed17f6e4cd4d169838e500 differ diff --git a/storage/textures/8ddac1821d77f0145d3c66c65d3829ee5ff60ea74b7c3275a37abecc33467fb8 b/storage/textures/8ddac1821d77f0145d3c66c65d3829ee5ff60ea74b7c3275a37abecc33467fb8 new file mode 100755 index 0000000..239d67b Binary files /dev/null and b/storage/textures/8ddac1821d77f0145d3c66c65d3829ee5ff60ea74b7c3275a37abecc33467fb8 differ diff --git a/storage/textures/8e0a33e24a9bd57d8870bb10f09257824c8838b1e46045e94466fc8514c58d0f b/storage/textures/8e0a33e24a9bd57d8870bb10f09257824c8838b1e46045e94466fc8514c58d0f new file mode 100755 index 0000000..4420641 Binary files /dev/null and b/storage/textures/8e0a33e24a9bd57d8870bb10f09257824c8838b1e46045e94466fc8514c58d0f differ diff --git a/storage/textures/8e3e8b464772f7238af3c9d6454db7d3ce5665c69f51f3af6fa971418a2354b1 b/storage/textures/8e3e8b464772f7238af3c9d6454db7d3ce5665c69f51f3af6fa971418a2354b1 new file mode 100755 index 0000000..8d52172 Binary files /dev/null and b/storage/textures/8e3e8b464772f7238af3c9d6454db7d3ce5665c69f51f3af6fa971418a2354b1 differ diff --git a/storage/textures/8e67c7db98a77d320eca894b137dc1a7fa430ad337d1b5f845c56d91835791d3 b/storage/textures/8e67c7db98a77d320eca894b137dc1a7fa430ad337d1b5f845c56d91835791d3 new file mode 100755 index 0000000..18498ad Binary files /dev/null and b/storage/textures/8e67c7db98a77d320eca894b137dc1a7fa430ad337d1b5f845c56d91835791d3 differ diff --git a/storage/textures/8e7981389698eb6a56ef9becadfaed16f06837300d4ad90c13fe77dfed791454 b/storage/textures/8e7981389698eb6a56ef9becadfaed16f06837300d4ad90c13fe77dfed791454 new file mode 100644 index 0000000..3eb7a0f Binary files /dev/null and b/storage/textures/8e7981389698eb6a56ef9becadfaed16f06837300d4ad90c13fe77dfed791454 differ diff --git a/storage/textures/8e95690b933f4dc634b225b731bc645495877c107b00959ac0eed7c675cfba97 b/storage/textures/8e95690b933f4dc634b225b731bc645495877c107b00959ac0eed7c675cfba97 new file mode 100755 index 0000000..075835e Binary files /dev/null and b/storage/textures/8e95690b933f4dc634b225b731bc645495877c107b00959ac0eed7c675cfba97 differ diff --git a/storage/textures/8efaed57aa2c5f531a5819ea8904055ae504fe552182568276a2e36d4e898aa2 b/storage/textures/8efaed57aa2c5f531a5819ea8904055ae504fe552182568276a2e36d4e898aa2 new file mode 100755 index 0000000..ad8b2d7 Binary files /dev/null and b/storage/textures/8efaed57aa2c5f531a5819ea8904055ae504fe552182568276a2e36d4e898aa2 differ diff --git a/storage/textures/8efafb0183325e0bbf4003b3eeea4d860b7ac288e8c3aeb66bd20df788174b40 b/storage/textures/8efafb0183325e0bbf4003b3eeea4d860b7ac288e8c3aeb66bd20df788174b40 new file mode 100755 index 0000000..b7a2746 Binary files /dev/null and b/storage/textures/8efafb0183325e0bbf4003b3eeea4d860b7ac288e8c3aeb66bd20df788174b40 differ diff --git a/storage/textures/8f197f7893fb73d4bfa97ca2e5c7993e35acd2878e333dad62d9c60dba78adbd b/storage/textures/8f197f7893fb73d4bfa97ca2e5c7993e35acd2878e333dad62d9c60dba78adbd new file mode 100755 index 0000000..cf5ff47 Binary files /dev/null and b/storage/textures/8f197f7893fb73d4bfa97ca2e5c7993e35acd2878e333dad62d9c60dba78adbd differ diff --git a/storage/textures/8f21d332afd6ffac21d17e5c2acca916b2289283a9ccce83acff59049d2d87d8 b/storage/textures/8f21d332afd6ffac21d17e5c2acca916b2289283a9ccce83acff59049d2d87d8 new file mode 100644 index 0000000..d22b514 Binary files /dev/null and b/storage/textures/8f21d332afd6ffac21d17e5c2acca916b2289283a9ccce83acff59049d2d87d8 differ diff --git a/storage/textures/8f27ebd6eb2c2f8e28b94f14689df84f281383a1830c5b7c75fc0255feb7e469 b/storage/textures/8f27ebd6eb2c2f8e28b94f14689df84f281383a1830c5b7c75fc0255feb7e469 new file mode 100755 index 0000000..048f36b Binary files /dev/null and b/storage/textures/8f27ebd6eb2c2f8e28b94f14689df84f281383a1830c5b7c75fc0255feb7e469 differ diff --git a/storage/textures/8f34db163066755202194779d8eba30396e9a4ee8c9b2a7e3cff9b67e588c141 b/storage/textures/8f34db163066755202194779d8eba30396e9a4ee8c9b2a7e3cff9b67e588c141 new file mode 100755 index 0000000..df9a88b Binary files /dev/null and b/storage/textures/8f34db163066755202194779d8eba30396e9a4ee8c9b2a7e3cff9b67e588c141 differ diff --git a/storage/textures/8f614fbbff9ba18da1c90729c3c7d2b54931432e039a019bd96aba18d00208db b/storage/textures/8f614fbbff9ba18da1c90729c3c7d2b54931432e039a019bd96aba18d00208db new file mode 100755 index 0000000..47a204e Binary files /dev/null and b/storage/textures/8f614fbbff9ba18da1c90729c3c7d2b54931432e039a019bd96aba18d00208db differ diff --git a/storage/textures/8f6e5be3e68a04d892d8f98bab38cd9470d049718d9cc90fd9291247a2d5ea4b b/storage/textures/8f6e5be3e68a04d892d8f98bab38cd9470d049718d9cc90fd9291247a2d5ea4b new file mode 100755 index 0000000..80f6ef8 Binary files /dev/null and b/storage/textures/8f6e5be3e68a04d892d8f98bab38cd9470d049718d9cc90fd9291247a2d5ea4b differ diff --git a/storage/textures/8fc6f4394eeb53febfaf26a88a51505a68ddbb90c42c093faee760a500beae1d b/storage/textures/8fc6f4394eeb53febfaf26a88a51505a68ddbb90c42c093faee760a500beae1d new file mode 100644 index 0000000..9651ece Binary files /dev/null and b/storage/textures/8fc6f4394eeb53febfaf26a88a51505a68ddbb90c42c093faee760a500beae1d differ diff --git a/storage/textures/8fd680d1887376122f6952bb10d83210c27993042d5baf8edde6f738079f9892 b/storage/textures/8fd680d1887376122f6952bb10d83210c27993042d5baf8edde6f738079f9892 new file mode 100755 index 0000000..c22b8b2 Binary files /dev/null and b/storage/textures/8fd680d1887376122f6952bb10d83210c27993042d5baf8edde6f738079f9892 differ diff --git a/storage/textures/8ff1f6b61edfd4660a16b7d9e63f10d6dec79a0b1f9fc851433abba2a2da3555 b/storage/textures/8ff1f6b61edfd4660a16b7d9e63f10d6dec79a0b1f9fc851433abba2a2da3555 new file mode 100755 index 0000000..64edb85 Binary files /dev/null and b/storage/textures/8ff1f6b61edfd4660a16b7d9e63f10d6dec79a0b1f9fc851433abba2a2da3555 differ diff --git a/storage/textures/900a7562eb49ac91aee2469231ccdca58f876358ea2a96d2056ea913daef0356 b/storage/textures/900a7562eb49ac91aee2469231ccdca58f876358ea2a96d2056ea913daef0356 new file mode 100644 index 0000000..cf20217 Binary files /dev/null and b/storage/textures/900a7562eb49ac91aee2469231ccdca58f876358ea2a96d2056ea913daef0356 differ diff --git a/storage/textures/9016b1b2c01993c85a2c5fb7a944ad932351110e64ce21b1d2d69aa33ab4dc34 b/storage/textures/9016b1b2c01993c85a2c5fb7a944ad932351110e64ce21b1d2d69aa33ab4dc34 new file mode 100644 index 0000000..38a63bb Binary files /dev/null and b/storage/textures/9016b1b2c01993c85a2c5fb7a944ad932351110e64ce21b1d2d69aa33ab4dc34 differ diff --git a/storage/textures/901d43bc5da0b5d7c34fee925ccf48be8e5a92b40d4c1d8cec4ac8fcbd6b575e b/storage/textures/901d43bc5da0b5d7c34fee925ccf48be8e5a92b40d4c1d8cec4ac8fcbd6b575e new file mode 100755 index 0000000..1697825 Binary files /dev/null and b/storage/textures/901d43bc5da0b5d7c34fee925ccf48be8e5a92b40d4c1d8cec4ac8fcbd6b575e differ diff --git a/storage/textures/90a4a2787a2db7a6b75fb66039ddf94b2fb22f53f0830619aec7a3ecce3449b7 b/storage/textures/90a4a2787a2db7a6b75fb66039ddf94b2fb22f53f0830619aec7a3ecce3449b7 new file mode 100755 index 0000000..9d20a46 Binary files /dev/null and b/storage/textures/90a4a2787a2db7a6b75fb66039ddf94b2fb22f53f0830619aec7a3ecce3449b7 differ diff --git a/storage/textures/90b3ed4689c97c1cb6c37144a81660a5e5bc4965e3d8df785e7e6a356d79f2f3 b/storage/textures/90b3ed4689c97c1cb6c37144a81660a5e5bc4965e3d8df785e7e6a356d79f2f3 new file mode 100644 index 0000000..d706161 Binary files /dev/null and b/storage/textures/90b3ed4689c97c1cb6c37144a81660a5e5bc4965e3d8df785e7e6a356d79f2f3 differ diff --git a/storage/textures/90d88b632df3fa27be145e2cfad5144b8d6577fbcfdf37573ea50eacd8b20647 b/storage/textures/90d88b632df3fa27be145e2cfad5144b8d6577fbcfdf37573ea50eacd8b20647 new file mode 100755 index 0000000..338d3dd Binary files /dev/null and b/storage/textures/90d88b632df3fa27be145e2cfad5144b8d6577fbcfdf37573ea50eacd8b20647 differ diff --git a/storage/textures/90f11288f660b935b5ce8d563338c5cbe85957bfb18dc26eb1122ec0cf8e5374 b/storage/textures/90f11288f660b935b5ce8d563338c5cbe85957bfb18dc26eb1122ec0cf8e5374 new file mode 100755 index 0000000..42f530b Binary files /dev/null and b/storage/textures/90f11288f660b935b5ce8d563338c5cbe85957bfb18dc26eb1122ec0cf8e5374 differ diff --git a/storage/textures/912085e6570a106393fb5c9ed1f43ee895e113979a3bc5d846b619a3a6a3c93a b/storage/textures/912085e6570a106393fb5c9ed1f43ee895e113979a3bc5d846b619a3a6a3c93a new file mode 100755 index 0000000..7a5cf66 Binary files /dev/null and b/storage/textures/912085e6570a106393fb5c9ed1f43ee895e113979a3bc5d846b619a3a6a3c93a differ diff --git a/storage/textures/9135c8b2ca05974f9b185ba837edfb222a04d938fd43d8530277c8c235e7de98 b/storage/textures/9135c8b2ca05974f9b185ba837edfb222a04d938fd43d8530277c8c235e7de98 new file mode 100755 index 0000000..0e290db Binary files /dev/null and b/storage/textures/9135c8b2ca05974f9b185ba837edfb222a04d938fd43d8530277c8c235e7de98 differ diff --git a/storage/textures/9182824b6bb00448219c4ef0b9af456f6aac05fcd9e5d34083088ec265a6210b b/storage/textures/9182824b6bb00448219c4ef0b9af456f6aac05fcd9e5d34083088ec265a6210b new file mode 100755 index 0000000..627af3a Binary files /dev/null and b/storage/textures/9182824b6bb00448219c4ef0b9af456f6aac05fcd9e5d34083088ec265a6210b differ diff --git a/storage/textures/918562daba643b66a8c2410939281986d9993efc4bd1855254c9d3bfb7e9cefe b/storage/textures/918562daba643b66a8c2410939281986d9993efc4bd1855254c9d3bfb7e9cefe new file mode 100755 index 0000000..247e2b5 Binary files /dev/null and b/storage/textures/918562daba643b66a8c2410939281986d9993efc4bd1855254c9d3bfb7e9cefe differ diff --git a/storage/textures/919c03ab96a6ad729595a55f5e298f604a226cf66ea8782f139febdee659be53 b/storage/textures/919c03ab96a6ad729595a55f5e298f604a226cf66ea8782f139febdee659be53 new file mode 100755 index 0000000..d7617f9 Binary files /dev/null and b/storage/textures/919c03ab96a6ad729595a55f5e298f604a226cf66ea8782f139febdee659be53 differ diff --git a/storage/textures/91b7a5b71289224f95594b13af2cfd6911fa94c04ee005b18c66b558fd1c9e17 b/storage/textures/91b7a5b71289224f95594b13af2cfd6911fa94c04ee005b18c66b558fd1c9e17 new file mode 100644 index 0000000..c168dd6 Binary files /dev/null and b/storage/textures/91b7a5b71289224f95594b13af2cfd6911fa94c04ee005b18c66b558fd1c9e17 differ diff --git a/storage/textures/91e6edb0551853c4bacce1c4dcb4ed04d581d4bfaeacfa2c9f21ad42251c72db b/storage/textures/91e6edb0551853c4bacce1c4dcb4ed04d581d4bfaeacfa2c9f21ad42251c72db new file mode 100755 index 0000000..9e7ddd0 Binary files /dev/null and b/storage/textures/91e6edb0551853c4bacce1c4dcb4ed04d581d4bfaeacfa2c9f21ad42251c72db differ diff --git a/storage/textures/92075ede0c6b5002d1611dfddb6bccb7a6ac964da9069d3a1c627ed1ab402064 b/storage/textures/92075ede0c6b5002d1611dfddb6bccb7a6ac964da9069d3a1c627ed1ab402064 new file mode 100755 index 0000000..b7e720b Binary files /dev/null and b/storage/textures/92075ede0c6b5002d1611dfddb6bccb7a6ac964da9069d3a1c627ed1ab402064 differ diff --git a/storage/textures/92205f10728abcc34921f99032ab1c10187699bd280a9dcae1472c6e98cfadec b/storage/textures/92205f10728abcc34921f99032ab1c10187699bd280a9dcae1472c6e98cfadec new file mode 100755 index 0000000..72b4fb3 Binary files /dev/null and b/storage/textures/92205f10728abcc34921f99032ab1c10187699bd280a9dcae1472c6e98cfadec differ diff --git a/storage/textures/922f84bf9ee977e3451ded84a060c54ac4d14df4b01a0113b18335b18811f58e b/storage/textures/922f84bf9ee977e3451ded84a060c54ac4d14df4b01a0113b18335b18811f58e new file mode 100755 index 0000000..0893d93 Binary files /dev/null and b/storage/textures/922f84bf9ee977e3451ded84a060c54ac4d14df4b01a0113b18335b18811f58e differ diff --git a/storage/textures/925ee592dfefa85b9b8a0eb93c92ec113973177607f837d46c02945e7dcc44e1 b/storage/textures/925ee592dfefa85b9b8a0eb93c92ec113973177607f837d46c02945e7dcc44e1 new file mode 100644 index 0000000..5aa440e Binary files /dev/null and b/storage/textures/925ee592dfefa85b9b8a0eb93c92ec113973177607f837d46c02945e7dcc44e1 differ diff --git a/storage/textures/926e5da0b7797eada41922b782ce56d7d53c0d40842f86dc97b90d8faadc12e8 b/storage/textures/926e5da0b7797eada41922b782ce56d7d53c0d40842f86dc97b90d8faadc12e8 new file mode 100755 index 0000000..3833202 Binary files /dev/null and b/storage/textures/926e5da0b7797eada41922b782ce56d7d53c0d40842f86dc97b90d8faadc12e8 differ diff --git a/storage/textures/92701a12082507758065bb77596d4a5be4b096d1f4fc298aa68fe7435bd936fa b/storage/textures/92701a12082507758065bb77596d4a5be4b096d1f4fc298aa68fe7435bd936fa new file mode 100755 index 0000000..5c49a51 Binary files /dev/null and b/storage/textures/92701a12082507758065bb77596d4a5be4b096d1f4fc298aa68fe7435bd936fa differ diff --git a/storage/textures/92af5d8f6036694d76aca39e85a96ebc9179dce78cdc8a75037f1ab55ea4a9c2 b/storage/textures/92af5d8f6036694d76aca39e85a96ebc9179dce78cdc8a75037f1ab55ea4a9c2 new file mode 100644 index 0000000..786ed11 Binary files /dev/null and b/storage/textures/92af5d8f6036694d76aca39e85a96ebc9179dce78cdc8a75037f1ab55ea4a9c2 differ diff --git a/storage/textures/9372d173ec95d2e1293a02a5111e859b88c744bee4bc609cdb63bc4e049f01b5 b/storage/textures/9372d173ec95d2e1293a02a5111e859b88c744bee4bc609cdb63bc4e049f01b5 new file mode 100755 index 0000000..dc8e9b3 Binary files /dev/null and b/storage/textures/9372d173ec95d2e1293a02a5111e859b88c744bee4bc609cdb63bc4e049f01b5 differ diff --git a/storage/textures/93803320f07b71b53c24fe0d39e3d00c1d96c85c4710707561956c755e554a12 b/storage/textures/93803320f07b71b53c24fe0d39e3d00c1d96c85c4710707561956c755e554a12 new file mode 100644 index 0000000..73452eb Binary files /dev/null and b/storage/textures/93803320f07b71b53c24fe0d39e3d00c1d96c85c4710707561956c755e554a12 differ diff --git a/storage/textures/9394f9c2b8fd8281c72e81524178cf06c594f4772ca88e1727d5dfc6c2401375 b/storage/textures/9394f9c2b8fd8281c72e81524178cf06c594f4772ca88e1727d5dfc6c2401375 new file mode 100755 index 0000000..b89714c Binary files /dev/null and b/storage/textures/9394f9c2b8fd8281c72e81524178cf06c594f4772ca88e1727d5dfc6c2401375 differ diff --git a/storage/textures/94247f10d1139bdb867f68b324ffdf8c034ab299814261ab11a3d2cc9a4c28e8 b/storage/textures/94247f10d1139bdb867f68b324ffdf8c034ab299814261ab11a3d2cc9a4c28e8 new file mode 100755 index 0000000..0eb9897 Binary files /dev/null and b/storage/textures/94247f10d1139bdb867f68b324ffdf8c034ab299814261ab11a3d2cc9a4c28e8 differ diff --git a/storage/textures/946ac3bac83a12164b228acd25b96549193f3ff470c61fa7ba242e547c7347fa b/storage/textures/946ac3bac83a12164b228acd25b96549193f3ff470c61fa7ba242e547c7347fa new file mode 100755 index 0000000..e852907 Binary files /dev/null and b/storage/textures/946ac3bac83a12164b228acd25b96549193f3ff470c61fa7ba242e547c7347fa differ diff --git a/storage/textures/94c2bf630b4dc1b09e584f5fb67ddd5e5e561385fbc9a6ee72e0c3118e0da0bd b/storage/textures/94c2bf630b4dc1b09e584f5fb67ddd5e5e561385fbc9a6ee72e0c3118e0da0bd new file mode 100644 index 0000000..fa86478 Binary files /dev/null and b/storage/textures/94c2bf630b4dc1b09e584f5fb67ddd5e5e561385fbc9a6ee72e0c3118e0da0bd differ diff --git a/storage/textures/953cac8b779fe41383e675ee2b86071a71658f2180f56fbce8aa315ea70e2ed6 b/storage/textures/953cac8b779fe41383e675ee2b86071a71658f2180f56fbce8aa315ea70e2ed6 new file mode 100755 index 0000000..e4c5728 Binary files /dev/null and b/storage/textures/953cac8b779fe41383e675ee2b86071a71658f2180f56fbce8aa315ea70e2ed6 differ diff --git a/storage/textures/955b3d2d47250e91848cb15fb172f0fb9254901812b84d1dc8cafb5eeafee1cc b/storage/textures/955b3d2d47250e91848cb15fb172f0fb9254901812b84d1dc8cafb5eeafee1cc new file mode 100755 index 0000000..f854c2f Binary files /dev/null and b/storage/textures/955b3d2d47250e91848cb15fb172f0fb9254901812b84d1dc8cafb5eeafee1cc differ diff --git a/storage/textures/959eb909f025512fb9c854ba2e1c7321cc11af1b4617b9cf1e8daaca830e5283 b/storage/textures/959eb909f025512fb9c854ba2e1c7321cc11af1b4617b9cf1e8daaca830e5283 new file mode 100755 index 0000000..90cf782 Binary files /dev/null and b/storage/textures/959eb909f025512fb9c854ba2e1c7321cc11af1b4617b9cf1e8daaca830e5283 differ diff --git a/storage/textures/95ee5251eac0f97ec4e34b503f36c4511c2848e56662052881f039e50e2a3379 b/storage/textures/95ee5251eac0f97ec4e34b503f36c4511c2848e56662052881f039e50e2a3379 new file mode 100755 index 0000000..a4b60dd Binary files /dev/null and b/storage/textures/95ee5251eac0f97ec4e34b503f36c4511c2848e56662052881f039e50e2a3379 differ diff --git a/storage/textures/96646134509e11e2178ea7c5757ffa4f6183991bcd8e613fbcdb282af2122001 b/storage/textures/96646134509e11e2178ea7c5757ffa4f6183991bcd8e613fbcdb282af2122001 new file mode 100755 index 0000000..55d6b13 Binary files /dev/null and b/storage/textures/96646134509e11e2178ea7c5757ffa4f6183991bcd8e613fbcdb282af2122001 differ diff --git a/storage/textures/973e651a2f642e2e5f4679d88a425f26b0e05254c81a914e07af62a4d71ecf5a b/storage/textures/973e651a2f642e2e5f4679d88a425f26b0e05254c81a914e07af62a4d71ecf5a new file mode 100755 index 0000000..2f4588a Binary files /dev/null and b/storage/textures/973e651a2f642e2e5f4679d88a425f26b0e05254c81a914e07af62a4d71ecf5a differ diff --git a/storage/textures/9765fbaf921582da93d9a8a9ac5787b5f994715ff32a4022ee43e64243d2987e b/storage/textures/9765fbaf921582da93d9a8a9ac5787b5f994715ff32a4022ee43e64243d2987e new file mode 100755 index 0000000..221fd5e Binary files /dev/null and b/storage/textures/9765fbaf921582da93d9a8a9ac5787b5f994715ff32a4022ee43e64243d2987e differ diff --git a/storage/textures/9775f2e1641b5c6bed4764b3b3b4ad392e4f15a780155dc201c766fdee4ce35f b/storage/textures/9775f2e1641b5c6bed4764b3b3b4ad392e4f15a780155dc201c766fdee4ce35f new file mode 100644 index 0000000..e826747 Binary files /dev/null and b/storage/textures/9775f2e1641b5c6bed4764b3b3b4ad392e4f15a780155dc201c766fdee4ce35f differ diff --git a/storage/textures/97fe7e28949627fc8a6d975e0fed6dec8b267f483c47773e4e08020053895850 b/storage/textures/97fe7e28949627fc8a6d975e0fed6dec8b267f483c47773e4e08020053895850 new file mode 100755 index 0000000..80ba5d3 Binary files /dev/null and b/storage/textures/97fe7e28949627fc8a6d975e0fed6dec8b267f483c47773e4e08020053895850 differ diff --git a/storage/textures/98342e52643faf3163f6f630afc5f221d757fac02d2d7d83ee2b723a2206be9a b/storage/textures/98342e52643faf3163f6f630afc5f221d757fac02d2d7d83ee2b723a2206be9a new file mode 100644 index 0000000..6f1c2f5 Binary files /dev/null and b/storage/textures/98342e52643faf3163f6f630afc5f221d757fac02d2d7d83ee2b723a2206be9a differ diff --git a/storage/textures/986d9d2f6b7b1990778a8d1b67ffae8e0fe287fffe8d7d02c2ed22065267f4fe b/storage/textures/986d9d2f6b7b1990778a8d1b67ffae8e0fe287fffe8d7d02c2ed22065267f4fe new file mode 100755 index 0000000..d169e32 Binary files /dev/null and b/storage/textures/986d9d2f6b7b1990778a8d1b67ffae8e0fe287fffe8d7d02c2ed22065267f4fe differ diff --git a/storage/textures/9874b8940bbc74651790ae9ca10e0ae59ba2cd5abd6ce803d860733d8f620292 b/storage/textures/9874b8940bbc74651790ae9ca10e0ae59ba2cd5abd6ce803d860733d8f620292 new file mode 100755 index 0000000..458653a Binary files /dev/null and b/storage/textures/9874b8940bbc74651790ae9ca10e0ae59ba2cd5abd6ce803d860733d8f620292 differ diff --git a/storage/textures/98a0a2504bb4187500ae5d9bf86a6321d45c2028715719509174aca369a3a574 b/storage/textures/98a0a2504bb4187500ae5d9bf86a6321d45c2028715719509174aca369a3a574 new file mode 100755 index 0000000..22ddc94 Binary files /dev/null and b/storage/textures/98a0a2504bb4187500ae5d9bf86a6321d45c2028715719509174aca369a3a574 differ diff --git a/storage/textures/98b1b9044b4605c92018f756868e695648ce54145908d0abe3cd01e7a1f8fd59 b/storage/textures/98b1b9044b4605c92018f756868e695648ce54145908d0abe3cd01e7a1f8fd59 new file mode 100755 index 0000000..ac09312 Binary files /dev/null and b/storage/textures/98b1b9044b4605c92018f756868e695648ce54145908d0abe3cd01e7a1f8fd59 differ diff --git a/storage/textures/98b39c87f947bb4764ebe28948bd9f11c5778c6f12e91297b8b25adf2c861e34 b/storage/textures/98b39c87f947bb4764ebe28948bd9f11c5778c6f12e91297b8b25adf2c861e34 new file mode 100644 index 0000000..ac0e5bb Binary files /dev/null and b/storage/textures/98b39c87f947bb4764ebe28948bd9f11c5778c6f12e91297b8b25adf2c861e34 differ diff --git a/storage/textures/98e3557f1e00330186b56d504e0643984a257bea93e8409473123102971608e6 b/storage/textures/98e3557f1e00330186b56d504e0643984a257bea93e8409473123102971608e6 new file mode 100755 index 0000000..f4bef8f Binary files /dev/null and b/storage/textures/98e3557f1e00330186b56d504e0643984a257bea93e8409473123102971608e6 differ diff --git a/storage/textures/9904a64f0d17b543cfba5600e76e7a594c5947867241b814ebf7e167f5784d4a b/storage/textures/9904a64f0d17b543cfba5600e76e7a594c5947867241b814ebf7e167f5784d4a new file mode 100755 index 0000000..1a15494 Binary files /dev/null and b/storage/textures/9904a64f0d17b543cfba5600e76e7a594c5947867241b814ebf7e167f5784d4a differ diff --git a/storage/textures/9975dd28d6c3b0a2a1af26fd4db807a23f18c794439f4de89a688b8c38df9290 b/storage/textures/9975dd28d6c3b0a2a1af26fd4db807a23f18c794439f4de89a688b8c38df9290 new file mode 100755 index 0000000..41cdfe9 Binary files /dev/null and b/storage/textures/9975dd28d6c3b0a2a1af26fd4db807a23f18c794439f4de89a688b8c38df9290 differ diff --git a/storage/textures/9ac3c01af397cb0a7d02c12a391c0dc2910e92ea20b09185d18d8a402215df12 b/storage/textures/9ac3c01af397cb0a7d02c12a391c0dc2910e92ea20b09185d18d8a402215df12 new file mode 100755 index 0000000..a15cb61 Binary files /dev/null and b/storage/textures/9ac3c01af397cb0a7d02c12a391c0dc2910e92ea20b09185d18d8a402215df12 differ diff --git a/storage/textures/9b17dfce6bf48fd8bd25e78c64004921f0b7a702c175b118311a708ac4c5d5bf b/storage/textures/9b17dfce6bf48fd8bd25e78c64004921f0b7a702c175b118311a708ac4c5d5bf new file mode 100644 index 0000000..9cd32cc Binary files /dev/null and b/storage/textures/9b17dfce6bf48fd8bd25e78c64004921f0b7a702c175b118311a708ac4c5d5bf differ diff --git a/storage/textures/9b7344eec075e570565243978abe31e35745b56d63cc2cbcbba6ed21d19dc1c6 b/storage/textures/9b7344eec075e570565243978abe31e35745b56d63cc2cbcbba6ed21d19dc1c6 new file mode 100755 index 0000000..4754b47 Binary files /dev/null and b/storage/textures/9b7344eec075e570565243978abe31e35745b56d63cc2cbcbba6ed21d19dc1c6 differ diff --git a/storage/textures/9bb94eb905793b8e04cba0b263748b668ee97e0cc7ccb251bffcdf7ac6098bbb b/storage/textures/9bb94eb905793b8e04cba0b263748b668ee97e0cc7ccb251bffcdf7ac6098bbb new file mode 100644 index 0000000..87e8b80 Binary files /dev/null and b/storage/textures/9bb94eb905793b8e04cba0b263748b668ee97e0cc7ccb251bffcdf7ac6098bbb differ diff --git a/storage/textures/9bce95cd4f269641eabd1d94af9d364971ddeffd16c9ee68ca10a4f395ec02ad b/storage/textures/9bce95cd4f269641eabd1d94af9d364971ddeffd16c9ee68ca10a4f395ec02ad new file mode 100644 index 0000000..f86409f Binary files /dev/null and b/storage/textures/9bce95cd4f269641eabd1d94af9d364971ddeffd16c9ee68ca10a4f395ec02ad differ diff --git a/storage/textures/9c58699d9d4c7da28101fa8827e40952ca1f498ac78ca8354811d039640672b8 b/storage/textures/9c58699d9d4c7da28101fa8827e40952ca1f498ac78ca8354811d039640672b8 new file mode 100755 index 0000000..4f33538 Binary files /dev/null and b/storage/textures/9c58699d9d4c7da28101fa8827e40952ca1f498ac78ca8354811d039640672b8 differ diff --git a/storage/textures/9cd6ab8949903521d70a6f24f75fbdf4006abe7def9592f398b83b8af0bc78f1 b/storage/textures/9cd6ab8949903521d70a6f24f75fbdf4006abe7def9592f398b83b8af0bc78f1 new file mode 100755 index 0000000..39534e8 Binary files /dev/null and b/storage/textures/9cd6ab8949903521d70a6f24f75fbdf4006abe7def9592f398b83b8af0bc78f1 differ diff --git a/storage/textures/9cde33e8d10c229d83e535c002b06b2a599893c33dd75902c8094935de31064b b/storage/textures/9cde33e8d10c229d83e535c002b06b2a599893c33dd75902c8094935de31064b new file mode 100755 index 0000000..85e7898 Binary files /dev/null and b/storage/textures/9cde33e8d10c229d83e535c002b06b2a599893c33dd75902c8094935de31064b differ diff --git a/storage/textures/9cee33351362eb3c1645079536704bd859d761b64b9578475be0e24e4b6f0e8c b/storage/textures/9cee33351362eb3c1645079536704bd859d761b64b9578475be0e24e4b6f0e8c new file mode 100644 index 0000000..81235fc Binary files /dev/null and b/storage/textures/9cee33351362eb3c1645079536704bd859d761b64b9578475be0e24e4b6f0e8c differ diff --git a/storage/textures/9cf2bd022758e3bce3f84d59991d9ae3d6bf09fb90d575c31624ac1c454739e7 b/storage/textures/9cf2bd022758e3bce3f84d59991d9ae3d6bf09fb90d575c31624ac1c454739e7 new file mode 100644 index 0000000..cf0d26f Binary files /dev/null and b/storage/textures/9cf2bd022758e3bce3f84d59991d9ae3d6bf09fb90d575c31624ac1c454739e7 differ diff --git a/storage/textures/9d50d4028c57a8cfe61d1def0fb509e6191f27d1c1951ad0984a92cdb89dbc03 b/storage/textures/9d50d4028c57a8cfe61d1def0fb509e6191f27d1c1951ad0984a92cdb89dbc03 new file mode 100755 index 0000000..ae33df0 Binary files /dev/null and b/storage/textures/9d50d4028c57a8cfe61d1def0fb509e6191f27d1c1951ad0984a92cdb89dbc03 differ diff --git a/storage/textures/9d61809e66d76f7cfd0e1f7123567be81c35804138b1c225608337a1dc5e7be5 b/storage/textures/9d61809e66d76f7cfd0e1f7123567be81c35804138b1c225608337a1dc5e7be5 new file mode 100644 index 0000000..7b627f3 Binary files /dev/null and b/storage/textures/9d61809e66d76f7cfd0e1f7123567be81c35804138b1c225608337a1dc5e7be5 differ diff --git a/storage/textures/9dc29fbbd6efd5699a365294f957898631fc6bdf310d38f6f78a42e7ecafcc9d b/storage/textures/9dc29fbbd6efd5699a365294f957898631fc6bdf310d38f6f78a42e7ecafcc9d new file mode 100755 index 0000000..a4a2dfe Binary files /dev/null and b/storage/textures/9dc29fbbd6efd5699a365294f957898631fc6bdf310d38f6f78a42e7ecafcc9d differ diff --git a/storage/textures/9e3f3e1a2af0baef88a316f90404f580d2c23a425ba2c9b4379985e2af11e9b9 b/storage/textures/9e3f3e1a2af0baef88a316f90404f580d2c23a425ba2c9b4379985e2af11e9b9 new file mode 100644 index 0000000..443b78e Binary files /dev/null and b/storage/textures/9e3f3e1a2af0baef88a316f90404f580d2c23a425ba2c9b4379985e2af11e9b9 differ diff --git a/storage/textures/9e875d5a9e9a35cbba1e0a1d201db19ffad79235938a0a25d7f0ab61f50aa170 b/storage/textures/9e875d5a9e9a35cbba1e0a1d201db19ffad79235938a0a25d7f0ab61f50aa170 new file mode 100644 index 0000000..60e2497 Binary files /dev/null and b/storage/textures/9e875d5a9e9a35cbba1e0a1d201db19ffad79235938a0a25d7f0ab61f50aa170 differ diff --git a/storage/textures/9e9e5eba5c79e6a7f030f2cdfdc6793cf5ce7a104bf225dad7aace0c8a4235c9 b/storage/textures/9e9e5eba5c79e6a7f030f2cdfdc6793cf5ce7a104bf225dad7aace0c8a4235c9 new file mode 100644 index 0000000..fa69d37 Binary files /dev/null and b/storage/textures/9e9e5eba5c79e6a7f030f2cdfdc6793cf5ce7a104bf225dad7aace0c8a4235c9 differ diff --git a/storage/textures/9ea9462f6cc98bd91244a51010c53990225f1c67bd404048825711f5d0e72c10 b/storage/textures/9ea9462f6cc98bd91244a51010c53990225f1c67bd404048825711f5d0e72c10 new file mode 100755 index 0000000..df6de38 Binary files /dev/null and b/storage/textures/9ea9462f6cc98bd91244a51010c53990225f1c67bd404048825711f5d0e72c10 differ diff --git a/storage/textures/9edf1e6eb43ff1ab0d13d4bfe43805d769f7267f04d1e9a8969a64aeb06d1baa b/storage/textures/9edf1e6eb43ff1ab0d13d4bfe43805d769f7267f04d1e9a8969a64aeb06d1baa new file mode 100644 index 0000000..a313e3e Binary files /dev/null and b/storage/textures/9edf1e6eb43ff1ab0d13d4bfe43805d769f7267f04d1e9a8969a64aeb06d1baa differ diff --git a/storage/textures/9f23b03055d3fcea9211baf0e952853c7b9f52d6031e25df544b33a4953b43ff b/storage/textures/9f23b03055d3fcea9211baf0e952853c7b9f52d6031e25df544b33a4953b43ff new file mode 100755 index 0000000..692a44e Binary files /dev/null and b/storage/textures/9f23b03055d3fcea9211baf0e952853c7b9f52d6031e25df544b33a4953b43ff differ diff --git a/storage/textures/9f3b28f40c8d6283151724a7cb713e0c0216176162d4735dc91a043cdfbce367 b/storage/textures/9f3b28f40c8d6283151724a7cb713e0c0216176162d4735dc91a043cdfbce367 new file mode 100755 index 0000000..a58a919 Binary files /dev/null and b/storage/textures/9f3b28f40c8d6283151724a7cb713e0c0216176162d4735dc91a043cdfbce367 differ diff --git a/storage/textures/a000323043633df195f90956735ca5ed7c6454710bb738d04dbbb78cbab88fc7 b/storage/textures/a000323043633df195f90956735ca5ed7c6454710bb738d04dbbb78cbab88fc7 new file mode 100644 index 0000000..988ac53 Binary files /dev/null and b/storage/textures/a000323043633df195f90956735ca5ed7c6454710bb738d04dbbb78cbab88fc7 differ diff --git a/storage/textures/a01659bdeceae73ded00f26bc364d130be66de0de707047399016456a6100db7 b/storage/textures/a01659bdeceae73ded00f26bc364d130be66de0de707047399016456a6100db7 new file mode 100644 index 0000000..d2d32e8 Binary files /dev/null and b/storage/textures/a01659bdeceae73ded00f26bc364d130be66de0de707047399016456a6100db7 differ diff --git a/storage/textures/a02ff9d0695449c711b31346e069d089935e8f63bc98937ef16d7d771fc7a6fc b/storage/textures/a02ff9d0695449c711b31346e069d089935e8f63bc98937ef16d7d771fc7a6fc new file mode 100755 index 0000000..5983176 Binary files /dev/null and b/storage/textures/a02ff9d0695449c711b31346e069d089935e8f63bc98937ef16d7d771fc7a6fc differ diff --git a/storage/textures/a0a164589973fbfb167757e18f387bb0c0c4e2ce8ddaf75f9bdb9240b6b5c9fa b/storage/textures/a0a164589973fbfb167757e18f387bb0c0c4e2ce8ddaf75f9bdb9240b6b5c9fa new file mode 100644 index 0000000..cfc0520 Binary files /dev/null and b/storage/textures/a0a164589973fbfb167757e18f387bb0c0c4e2ce8ddaf75f9bdb9240b6b5c9fa differ diff --git a/storage/textures/a0a81d1b4637f9c3646025154cc7b740e7de1277da8254c93f3ca0a208e759fd b/storage/textures/a0a81d1b4637f9c3646025154cc7b740e7de1277da8254c93f3ca0a208e759fd new file mode 100644 index 0000000..772df09 Binary files /dev/null and b/storage/textures/a0a81d1b4637f9c3646025154cc7b740e7de1277da8254c93f3ca0a208e759fd differ diff --git a/storage/textures/a0d29f33b6fe9d3f3b8a9df7461e1df1bf629c75a46dd8a79f24a6205395d411 b/storage/textures/a0d29f33b6fe9d3f3b8a9df7461e1df1bf629c75a46dd8a79f24a6205395d411 new file mode 100755 index 0000000..a95903a Binary files /dev/null and b/storage/textures/a0d29f33b6fe9d3f3b8a9df7461e1df1bf629c75a46dd8a79f24a6205395d411 differ diff --git a/storage/textures/a0e776b8d3271d972b1c46497443c6493504be6abea6d0c58882cb6458294e8e b/storage/textures/a0e776b8d3271d972b1c46497443c6493504be6abea6d0c58882cb6458294e8e new file mode 100755 index 0000000..2a22304 Binary files /dev/null and b/storage/textures/a0e776b8d3271d972b1c46497443c6493504be6abea6d0c58882cb6458294e8e differ diff --git a/storage/textures/a13217588210fa9fe2e8dc5d25d281387784228a3a2642784694b6293710003a b/storage/textures/a13217588210fa9fe2e8dc5d25d281387784228a3a2642784694b6293710003a new file mode 100755 index 0000000..cccd540 Binary files /dev/null and b/storage/textures/a13217588210fa9fe2e8dc5d25d281387784228a3a2642784694b6293710003a differ diff --git a/storage/textures/a13744920c719371f23239b739aa0220462aca6c7ec6972b5e3919d2103eabba b/storage/textures/a13744920c719371f23239b739aa0220462aca6c7ec6972b5e3919d2103eabba new file mode 100755 index 0000000..9ff4535 Binary files /dev/null and b/storage/textures/a13744920c719371f23239b739aa0220462aca6c7ec6972b5e3919d2103eabba differ diff --git a/storage/textures/a13b95ed1eca1793b3dd34f058a5670d76b03a7cad18ca91ee72d4b95d37503b b/storage/textures/a13b95ed1eca1793b3dd34f058a5670d76b03a7cad18ca91ee72d4b95d37503b new file mode 100644 index 0000000..8eb88a3 Binary files /dev/null and b/storage/textures/a13b95ed1eca1793b3dd34f058a5670d76b03a7cad18ca91ee72d4b95d37503b differ diff --git a/storage/textures/a2647d000d1f0eac4e01b21caaec358149237e66ee0099347a7bc0845304599c b/storage/textures/a2647d000d1f0eac4e01b21caaec358149237e66ee0099347a7bc0845304599c new file mode 100755 index 0000000..2f54fbd Binary files /dev/null and b/storage/textures/a2647d000d1f0eac4e01b21caaec358149237e66ee0099347a7bc0845304599c differ diff --git a/storage/textures/a282067ba2110a1d5ccc66131c5d0b61f3a7ce6d8d5058728e91cb702960444f b/storage/textures/a282067ba2110a1d5ccc66131c5d0b61f3a7ce6d8d5058728e91cb702960444f new file mode 100644 index 0000000..5696fdc Binary files /dev/null and b/storage/textures/a282067ba2110a1d5ccc66131c5d0b61f3a7ce6d8d5058728e91cb702960444f differ diff --git a/storage/textures/a287e41250c28857220827318f840d0d4163acadc2f17c48bb4677853ddce27c b/storage/textures/a287e41250c28857220827318f840d0d4163acadc2f17c48bb4677853ddce27c new file mode 100755 index 0000000..b72e82c Binary files /dev/null and b/storage/textures/a287e41250c28857220827318f840d0d4163acadc2f17c48bb4677853ddce27c differ diff --git a/storage/textures/a43fe6b9b88c0d2c379ae1ba0347f052113d5b24cc3f6fc116afae2996a85781 b/storage/textures/a43fe6b9b88c0d2c379ae1ba0347f052113d5b24cc3f6fc116afae2996a85781 new file mode 100755 index 0000000..73f2f2e Binary files /dev/null and b/storage/textures/a43fe6b9b88c0d2c379ae1ba0347f052113d5b24cc3f6fc116afae2996a85781 differ diff --git a/storage/textures/a4a0fc52c38e5c39ee826a58541596d7f5aad4b2003d8ee691b36ea2d3a1a573 b/storage/textures/a4a0fc52c38e5c39ee826a58541596d7f5aad4b2003d8ee691b36ea2d3a1a573 new file mode 100755 index 0000000..05a47f6 Binary files /dev/null and b/storage/textures/a4a0fc52c38e5c39ee826a58541596d7f5aad4b2003d8ee691b36ea2d3a1a573 differ diff --git a/storage/textures/a4c125769d42a06c85434b919f43efe24f6d85092cc8b5165cb11a0e53300df9 b/storage/textures/a4c125769d42a06c85434b919f43efe24f6d85092cc8b5165cb11a0e53300df9 new file mode 100644 index 0000000..bbbfc63 Binary files /dev/null and b/storage/textures/a4c125769d42a06c85434b919f43efe24f6d85092cc8b5165cb11a0e53300df9 differ diff --git a/storage/textures/a4ca776362df5f1f46b9175accc807423620e17cd12ad9d3db1eb88d2f08ac91 b/storage/textures/a4ca776362df5f1f46b9175accc807423620e17cd12ad9d3db1eb88d2f08ac91 new file mode 100755 index 0000000..b7c6693 Binary files /dev/null and b/storage/textures/a4ca776362df5f1f46b9175accc807423620e17cd12ad9d3db1eb88d2f08ac91 differ diff --git a/storage/textures/a4dbc8e2288ebb019edd14be95eda0e8158a4f95f4901ab441d96fda4230fb47 b/storage/textures/a4dbc8e2288ebb019edd14be95eda0e8158a4f95f4901ab441d96fda4230fb47 new file mode 100755 index 0000000..c4467a5 Binary files /dev/null and b/storage/textures/a4dbc8e2288ebb019edd14be95eda0e8158a4f95f4901ab441d96fda4230fb47 differ diff --git a/storage/textures/a552d50aa8208287321c6c20a243fc220909a9fe28523fd47eb5f9a8f69f524c b/storage/textures/a552d50aa8208287321c6c20a243fc220909a9fe28523fd47eb5f9a8f69f524c new file mode 100644 index 0000000..a055ec7 Binary files /dev/null and b/storage/textures/a552d50aa8208287321c6c20a243fc220909a9fe28523fd47eb5f9a8f69f524c differ diff --git a/storage/textures/a5ba20386c12eb5af4d7bbc960cf0b37e9a75b4c44c8d590e48897f453d2a80c b/storage/textures/a5ba20386c12eb5af4d7bbc960cf0b37e9a75b4c44c8d590e48897f453d2a80c new file mode 100755 index 0000000..b401766 Binary files /dev/null and b/storage/textures/a5ba20386c12eb5af4d7bbc960cf0b37e9a75b4c44c8d590e48897f453d2a80c differ diff --git a/storage/textures/a6b1ba756e9daf9dc038b0c1d5c49ee808e5c32fe91265dcd6036026463c583b b/storage/textures/a6b1ba756e9daf9dc038b0c1d5c49ee808e5c32fe91265dcd6036026463c583b new file mode 100755 index 0000000..6fe6312 Binary files /dev/null and b/storage/textures/a6b1ba756e9daf9dc038b0c1d5c49ee808e5c32fe91265dcd6036026463c583b differ diff --git a/storage/textures/a6c4c37eacac6a0712efd91a5e31d2d28a117ec207e925124447c5bd3306b2b0 b/storage/textures/a6c4c37eacac6a0712efd91a5e31d2d28a117ec207e925124447c5bd3306b2b0 new file mode 100755 index 0000000..f44e6e5 Binary files /dev/null and b/storage/textures/a6c4c37eacac6a0712efd91a5e31d2d28a117ec207e925124447c5bd3306b2b0 differ diff --git a/storage/textures/a6cef6e6898d9d4a3fad7e5fda2664a6dbb7768c1e1e3907b9d19b36789ae95d b/storage/textures/a6cef6e6898d9d4a3fad7e5fda2664a6dbb7768c1e1e3907b9d19b36789ae95d new file mode 100644 index 0000000..550d4ef Binary files /dev/null and b/storage/textures/a6cef6e6898d9d4a3fad7e5fda2664a6dbb7768c1e1e3907b9d19b36789ae95d differ diff --git a/storage/textures/a7335c8b479b7b87ce1f7f1429b3593ae469c70453a5b4c58cdfba0aacd80012 b/storage/textures/a7335c8b479b7b87ce1f7f1429b3593ae469c70453a5b4c58cdfba0aacd80012 new file mode 100755 index 0000000..c6e2679 Binary files /dev/null and b/storage/textures/a7335c8b479b7b87ce1f7f1429b3593ae469c70453a5b4c58cdfba0aacd80012 differ diff --git a/storage/textures/a74ab0d46ac541447816eb8cef89eb8280e031587ff10079ae5621b313465af8 b/storage/textures/a74ab0d46ac541447816eb8cef89eb8280e031587ff10079ae5621b313465af8 new file mode 100644 index 0000000..80c8375 Binary files /dev/null and b/storage/textures/a74ab0d46ac541447816eb8cef89eb8280e031587ff10079ae5621b313465af8 differ diff --git a/storage/textures/a74bfc9e893d77b3826fb537c3ff15505aac80fb0e7a85fda85351ee536b5506 b/storage/textures/a74bfc9e893d77b3826fb537c3ff15505aac80fb0e7a85fda85351ee536b5506 new file mode 100644 index 0000000..fb90fa3 Binary files /dev/null and b/storage/textures/a74bfc9e893d77b3826fb537c3ff15505aac80fb0e7a85fda85351ee536b5506 differ diff --git a/storage/textures/a782bace839ddcaf3371fdf0e802befb281cd8fab97246261dd614b5e3e4c31e b/storage/textures/a782bace839ddcaf3371fdf0e802befb281cd8fab97246261dd614b5e3e4c31e new file mode 100644 index 0000000..6ff2a8f Binary files /dev/null and b/storage/textures/a782bace839ddcaf3371fdf0e802befb281cd8fab97246261dd614b5e3e4c31e differ diff --git a/storage/textures/a8485c2507f303cfd101ca20342e2c1f91dce7157f2f5edf4d00ad17ffdbf2e4 b/storage/textures/a8485c2507f303cfd101ca20342e2c1f91dce7157f2f5edf4d00ad17ffdbf2e4 new file mode 100755 index 0000000..a19f199 Binary files /dev/null and b/storage/textures/a8485c2507f303cfd101ca20342e2c1f91dce7157f2f5edf4d00ad17ffdbf2e4 differ diff --git a/storage/textures/a8914c8d331c33def2740ae06327e28772ccbc50008dfd532b418e60940e2dc9 b/storage/textures/a8914c8d331c33def2740ae06327e28772ccbc50008dfd532b418e60940e2dc9 new file mode 100755 index 0000000..d0ebf84 Binary files /dev/null and b/storage/textures/a8914c8d331c33def2740ae06327e28772ccbc50008dfd532b418e60940e2dc9 differ diff --git a/storage/textures/a8a035f69bf836606cd9e66a31b3a4197619c6b22999564321a9e2a9b6d12bd8 b/storage/textures/a8a035f69bf836606cd9e66a31b3a4197619c6b22999564321a9e2a9b6d12bd8 new file mode 100755 index 0000000..60828a6 Binary files /dev/null and b/storage/textures/a8a035f69bf836606cd9e66a31b3a4197619c6b22999564321a9e2a9b6d12bd8 differ diff --git a/storage/textures/a8ed14bb4d9674c690d459f12690c10b768d932e7d7f3af85e636296f167850e b/storage/textures/a8ed14bb4d9674c690d459f12690c10b768d932e7d7f3af85e636296f167850e new file mode 100755 index 0000000..4f9c081 Binary files /dev/null and b/storage/textures/a8ed14bb4d9674c690d459f12690c10b768d932e7d7f3af85e636296f167850e differ diff --git a/storage/textures/a8f0a6b4d581a3be077f0f2228c03a799e6d376a43af360f6422dc3ea94e4a3f b/storage/textures/a8f0a6b4d581a3be077f0f2228c03a799e6d376a43af360f6422dc3ea94e4a3f new file mode 100755 index 0000000..264f60e Binary files /dev/null and b/storage/textures/a8f0a6b4d581a3be077f0f2228c03a799e6d376a43af360f6422dc3ea94e4a3f differ diff --git a/storage/textures/a908107cd11aba71b3f273eb62505978e1d8ddda0de8ee4c40f6530aae96e837 b/storage/textures/a908107cd11aba71b3f273eb62505978e1d8ddda0de8ee4c40f6530aae96e837 new file mode 100644 index 0000000..e9e137d Binary files /dev/null and b/storage/textures/a908107cd11aba71b3f273eb62505978e1d8ddda0de8ee4c40f6530aae96e837 differ diff --git a/storage/textures/a9c15be2bb7428340a6427b513ec42f824e769cd4cf37600ee96169f23beee19 b/storage/textures/a9c15be2bb7428340a6427b513ec42f824e769cd4cf37600ee96169f23beee19 new file mode 100755 index 0000000..cdcd14c Binary files /dev/null and b/storage/textures/a9c15be2bb7428340a6427b513ec42f824e769cd4cf37600ee96169f23beee19 differ diff --git a/storage/textures/a9cab9b500b0f3e7cb898d40da342054d147f4ea2bbad03cf602771eaf3d962f b/storage/textures/a9cab9b500b0f3e7cb898d40da342054d147f4ea2bbad03cf602771eaf3d962f new file mode 100644 index 0000000..f2b8b0c Binary files /dev/null and b/storage/textures/a9cab9b500b0f3e7cb898d40da342054d147f4ea2bbad03cf602771eaf3d962f differ diff --git a/storage/textures/a9d57c3a17b70af9062be0e338886f48ceac4f2791f65f8af54ce088d66ffe18 b/storage/textures/a9d57c3a17b70af9062be0e338886f48ceac4f2791f65f8af54ce088d66ffe18 new file mode 100644 index 0000000..e9340a6 Binary files /dev/null and b/storage/textures/a9d57c3a17b70af9062be0e338886f48ceac4f2791f65f8af54ce088d66ffe18 differ diff --git a/storage/textures/a9fa4be673db883427210077d8e3a1853077303c671c9ccb71682784b805f2c4 b/storage/textures/a9fa4be673db883427210077d8e3a1853077303c671c9ccb71682784b805f2c4 new file mode 100644 index 0000000..8a8dc4b Binary files /dev/null and b/storage/textures/a9fa4be673db883427210077d8e3a1853077303c671c9ccb71682784b805f2c4 differ diff --git a/storage/textures/aa4e6b63dd281f72db63d06032babb2c18b9eda9a7cb4a26abe1bb3b133efbb0 b/storage/textures/aa4e6b63dd281f72db63d06032babb2c18b9eda9a7cb4a26abe1bb3b133efbb0 new file mode 100644 index 0000000..e70ba05 Binary files /dev/null and b/storage/textures/aa4e6b63dd281f72db63d06032babb2c18b9eda9a7cb4a26abe1bb3b133efbb0 differ diff --git a/storage/textures/ab9c056d9687109e7b936495a15a175f21e4188d217f352bb6bd1e7d76152fa7 b/storage/textures/ab9c056d9687109e7b936495a15a175f21e4188d217f352bb6bd1e7d76152fa7 new file mode 100755 index 0000000..07e8934 Binary files /dev/null and b/storage/textures/ab9c056d9687109e7b936495a15a175f21e4188d217f352bb6bd1e7d76152fa7 differ diff --git a/storage/textures/abb10da963afaed054d06c9656b329fdf7ca0c8ea008df6e5fc42d9e4c485bf0 b/storage/textures/abb10da963afaed054d06c9656b329fdf7ca0c8ea008df6e5fc42d9e4c485bf0 new file mode 100755 index 0000000..f472371 Binary files /dev/null and b/storage/textures/abb10da963afaed054d06c9656b329fdf7ca0c8ea008df6e5fc42d9e4c485bf0 differ diff --git a/storage/textures/abb765b4df38a094ec80bb843195650b7b298a5d71cdd8637fe0bbf05b2c0649 b/storage/textures/abb765b4df38a094ec80bb843195650b7b298a5d71cdd8637fe0bbf05b2c0649 new file mode 100644 index 0000000..3a3713a Binary files /dev/null and b/storage/textures/abb765b4df38a094ec80bb843195650b7b298a5d71cdd8637fe0bbf05b2c0649 differ diff --git a/storage/textures/ac1e5f9e95374779747e231b49bd76ff8ef7295f3273217e03a61aefe1667d06 b/storage/textures/ac1e5f9e95374779747e231b49bd76ff8ef7295f3273217e03a61aefe1667d06 new file mode 100755 index 0000000..700ab45 Binary files /dev/null and b/storage/textures/ac1e5f9e95374779747e231b49bd76ff8ef7295f3273217e03a61aefe1667d06 differ diff --git a/storage/textures/ac46221ba19a9f47548e3a074d265b6b71084f31fde5dcded2cefeeacad01699 b/storage/textures/ac46221ba19a9f47548e3a074d265b6b71084f31fde5dcded2cefeeacad01699 new file mode 100755 index 0000000..7fbe072 Binary files /dev/null and b/storage/textures/ac46221ba19a9f47548e3a074d265b6b71084f31fde5dcded2cefeeacad01699 differ diff --git a/storage/textures/ac82969c3028145ca1e07a0c8809db95cb32c328a05be133c4e5c41ea726826b b/storage/textures/ac82969c3028145ca1e07a0c8809db95cb32c328a05be133c4e5c41ea726826b new file mode 100644 index 0000000..91ece39 Binary files /dev/null and b/storage/textures/ac82969c3028145ca1e07a0c8809db95cb32c328a05be133c4e5c41ea726826b differ diff --git a/storage/textures/ac9d7ecd8288c99c2a82f88685447c126e79892c336f9513afe1e51b0dcdfba1 b/storage/textures/ac9d7ecd8288c99c2a82f88685447c126e79892c336f9513afe1e51b0dcdfba1 new file mode 100644 index 0000000..ed31d21 Binary files /dev/null and b/storage/textures/ac9d7ecd8288c99c2a82f88685447c126e79892c336f9513afe1e51b0dcdfba1 differ diff --git a/storage/textures/accd24a5e3c281dcc9cda7b5f3b0aa4d05bc132365f72b8ed9fadccd51a4f23b b/storage/textures/accd24a5e3c281dcc9cda7b5f3b0aa4d05bc132365f72b8ed9fadccd51a4f23b new file mode 100644 index 0000000..5c015fe Binary files /dev/null and b/storage/textures/accd24a5e3c281dcc9cda7b5f3b0aa4d05bc132365f72b8ed9fadccd51a4f23b differ diff --git a/storage/textures/acf613a51c0c76f14a4f65709ba7c85478dde62ad06bf50c1aa3077391c5b96b b/storage/textures/acf613a51c0c76f14a4f65709ba7c85478dde62ad06bf50c1aa3077391c5b96b new file mode 100755 index 0000000..24d3949 Binary files /dev/null and b/storage/textures/acf613a51c0c76f14a4f65709ba7c85478dde62ad06bf50c1aa3077391c5b96b differ diff --git a/storage/textures/acf64c94248e3fcf4a58740b8225842d026609d405b64736f0f2a2d002eff7a4 b/storage/textures/acf64c94248e3fcf4a58740b8225842d026609d405b64736f0f2a2d002eff7a4 new file mode 100755 index 0000000..ac1a31f Binary files /dev/null and b/storage/textures/acf64c94248e3fcf4a58740b8225842d026609d405b64736f0f2a2d002eff7a4 differ diff --git a/storage/textures/ad7e69dd2d75a1cc6d996f78fb3be27fc29d56b0dad930f54377618c0fd32ec2 b/storage/textures/ad7e69dd2d75a1cc6d996f78fb3be27fc29d56b0dad930f54377618c0fd32ec2 new file mode 100644 index 0000000..0094fbc Binary files /dev/null and b/storage/textures/ad7e69dd2d75a1cc6d996f78fb3be27fc29d56b0dad930f54377618c0fd32ec2 differ diff --git a/storage/textures/adfcad87900a028e5ad37d698b652514e4f7281ae5119e149506b1a077497a0d b/storage/textures/adfcad87900a028e5ad37d698b652514e4f7281ae5119e149506b1a077497a0d new file mode 100644 index 0000000..28d6c2b Binary files /dev/null and b/storage/textures/adfcad87900a028e5ad37d698b652514e4f7281ae5119e149506b1a077497a0d differ diff --git a/storage/textures/adfd17eb8af2a356761cb242f4b86fec8b5cd95f46e595247d7a98e700283da0 b/storage/textures/adfd17eb8af2a356761cb242f4b86fec8b5cd95f46e595247d7a98e700283da0 new file mode 100755 index 0000000..f0e6b22 Binary files /dev/null and b/storage/textures/adfd17eb8af2a356761cb242f4b86fec8b5cd95f46e595247d7a98e700283da0 differ diff --git a/storage/textures/ae187aaa6c5b8000e0061d5e76de41560ae15254776bf7030cb131b2dc89f3f9 b/storage/textures/ae187aaa6c5b8000e0061d5e76de41560ae15254776bf7030cb131b2dc89f3f9 new file mode 100755 index 0000000..d9afa58 Binary files /dev/null and b/storage/textures/ae187aaa6c5b8000e0061d5e76de41560ae15254776bf7030cb131b2dc89f3f9 differ diff --git a/storage/textures/ae6de07d2b7b41406df3e0445c7698ed04ac1e4229a161c70659044e2bc9a5d5 b/storage/textures/ae6de07d2b7b41406df3e0445c7698ed04ac1e4229a161c70659044e2bc9a5d5 new file mode 100644 index 0000000..199e41a Binary files /dev/null and b/storage/textures/ae6de07d2b7b41406df3e0445c7698ed04ac1e4229a161c70659044e2bc9a5d5 differ diff --git a/storage/textures/af51b94b3d361db6ccf9dbef53e76b9896f9054b2ca24e83b6b6edeeb16c1722 b/storage/textures/af51b94b3d361db6ccf9dbef53e76b9896f9054b2ca24e83b6b6edeeb16c1722 new file mode 100644 index 0000000..97ea74a Binary files /dev/null and b/storage/textures/af51b94b3d361db6ccf9dbef53e76b9896f9054b2ca24e83b6b6edeeb16c1722 differ diff --git a/storage/textures/af5f82cef5f7003b4627bde740a4737e5acc83d9f1dfff3b78960613ef971bf8 b/storage/textures/af5f82cef5f7003b4627bde740a4737e5acc83d9f1dfff3b78960613ef971bf8 new file mode 100755 index 0000000..fb56bff Binary files /dev/null and b/storage/textures/af5f82cef5f7003b4627bde740a4737e5acc83d9f1dfff3b78960613ef971bf8 differ diff --git a/storage/textures/afd9d23b12c1487ec11cd10ecd3e95082944a5f64b7131ffcf47d1be344bd199 b/storage/textures/afd9d23b12c1487ec11cd10ecd3e95082944a5f64b7131ffcf47d1be344bd199 new file mode 100755 index 0000000..a936c14 Binary files /dev/null and b/storage/textures/afd9d23b12c1487ec11cd10ecd3e95082944a5f64b7131ffcf47d1be344bd199 differ diff --git a/storage/textures/b02339745773807bd0409f2433cfad6b3820d8961ba88b44115c1af00370bc77 b/storage/textures/b02339745773807bd0409f2433cfad6b3820d8961ba88b44115c1af00370bc77 new file mode 100644 index 0000000..d87b18b Binary files /dev/null and b/storage/textures/b02339745773807bd0409f2433cfad6b3820d8961ba88b44115c1af00370bc77 differ diff --git a/storage/textures/b09a082e63a3d5417edc553c941c493f3e7a61148d946dc19021f7e7c28bdbf0 b/storage/textures/b09a082e63a3d5417edc553c941c493f3e7a61148d946dc19021f7e7c28bdbf0 new file mode 100755 index 0000000..fef2f49 Binary files /dev/null and b/storage/textures/b09a082e63a3d5417edc553c941c493f3e7a61148d946dc19021f7e7c28bdbf0 differ diff --git a/storage/textures/b0a883042b5d13089687c65c657914f66620a50b374469794d3f15388c87a3b3 b/storage/textures/b0a883042b5d13089687c65c657914f66620a50b374469794d3f15388c87a3b3 new file mode 100755 index 0000000..e1103e3 Binary files /dev/null and b/storage/textures/b0a883042b5d13089687c65c657914f66620a50b374469794d3f15388c87a3b3 differ diff --git a/storage/textures/b10ab688b525c84ea0f215a5bf8c157dc69a01b84954c50d3d6f2e6cfa1614b7 b/storage/textures/b10ab688b525c84ea0f215a5bf8c157dc69a01b84954c50d3d6f2e6cfa1614b7 new file mode 100644 index 0000000..0759f38 Binary files /dev/null and b/storage/textures/b10ab688b525c84ea0f215a5bf8c157dc69a01b84954c50d3d6f2e6cfa1614b7 differ diff --git a/storage/textures/b10bae02c695d225f946abfa96dced272d1a9765bd558022dd65e8e9736f77e3 b/storage/textures/b10bae02c695d225f946abfa96dced272d1a9765bd558022dd65e8e9736f77e3 new file mode 100755 index 0000000..cf7a239 Binary files /dev/null and b/storage/textures/b10bae02c695d225f946abfa96dced272d1a9765bd558022dd65e8e9736f77e3 differ diff --git a/storage/textures/b1126ef7a042ba66502c68772162463b9b819063580016537e9a0e3e0d3eae10 b/storage/textures/b1126ef7a042ba66502c68772162463b9b819063580016537e9a0e3e0d3eae10 new file mode 100644 index 0000000..a839258 Binary files /dev/null and b/storage/textures/b1126ef7a042ba66502c68772162463b9b819063580016537e9a0e3e0d3eae10 differ diff --git a/storage/textures/b15b40e4f86c857ce169f51461a4110549e587c9da712e9298416d84e41a35ee b/storage/textures/b15b40e4f86c857ce169f51461a4110549e587c9da712e9298416d84e41a35ee new file mode 100755 index 0000000..906e342 Binary files /dev/null and b/storage/textures/b15b40e4f86c857ce169f51461a4110549e587c9da712e9298416d84e41a35ee differ diff --git a/storage/textures/b17adc77b1a534bf86253e2aef2597b1612646c33d7b24bb3426c3bfe825ef30 b/storage/textures/b17adc77b1a534bf86253e2aef2597b1612646c33d7b24bb3426c3bfe825ef30 new file mode 100755 index 0000000..6cf9f47 Binary files /dev/null and b/storage/textures/b17adc77b1a534bf86253e2aef2597b1612646c33d7b24bb3426c3bfe825ef30 differ diff --git a/storage/textures/b1822f7a66d1f819341180bd7e32fd446993a5f722d53df3f204a0515a5fc130 b/storage/textures/b1822f7a66d1f819341180bd7e32fd446993a5f722d53df3f204a0515a5fc130 new file mode 100755 index 0000000..d3f8a6a Binary files /dev/null and b/storage/textures/b1822f7a66d1f819341180bd7e32fd446993a5f722d53df3f204a0515a5fc130 differ diff --git a/storage/textures/b197f57e9bf45a815dbc7aaa08302e353b5c3a4f137e88cee476c65c185e3055 b/storage/textures/b197f57e9bf45a815dbc7aaa08302e353b5c3a4f137e88cee476c65c185e3055 new file mode 100755 index 0000000..9bec21f Binary files /dev/null and b/storage/textures/b197f57e9bf45a815dbc7aaa08302e353b5c3a4f137e88cee476c65c185e3055 differ diff --git a/storage/textures/b20f03e636558a52fa897e591ad196442a76db8e4f169051502af8c4d2d235fa b/storage/textures/b20f03e636558a52fa897e591ad196442a76db8e4f169051502af8c4d2d235fa new file mode 100755 index 0000000..20a48e3 Binary files /dev/null and b/storage/textures/b20f03e636558a52fa897e591ad196442a76db8e4f169051502af8c4d2d235fa differ diff --git a/storage/textures/b26435c7515cda70a9a12fd6e1a4b30a9e27611940d3244c96c9fd878bf1ab2c b/storage/textures/b26435c7515cda70a9a12fd6e1a4b30a9e27611940d3244c96c9fd878bf1ab2c new file mode 100644 index 0000000..e841215 Binary files /dev/null and b/storage/textures/b26435c7515cda70a9a12fd6e1a4b30a9e27611940d3244c96c9fd878bf1ab2c differ diff --git a/storage/textures/b275c9fc06fbadeaab99c17eeacf942f8fa60dec10928b0afb116d6c761635ef b/storage/textures/b275c9fc06fbadeaab99c17eeacf942f8fa60dec10928b0afb116d6c761635ef new file mode 100755 index 0000000..5e64072 Binary files /dev/null and b/storage/textures/b275c9fc06fbadeaab99c17eeacf942f8fa60dec10928b0afb116d6c761635ef differ diff --git a/storage/textures/b2916d603f92c61b804e5735bc72a6495c8360a144afd4600847877debbe26d8 b/storage/textures/b2916d603f92c61b804e5735bc72a6495c8360a144afd4600847877debbe26d8 new file mode 100755 index 0000000..21091c7 Binary files /dev/null and b/storage/textures/b2916d603f92c61b804e5735bc72a6495c8360a144afd4600847877debbe26d8 differ diff --git a/storage/textures/b2c3e7d1fe775351fa50544031ffaa51b93ef50108e7530fd3ba349c2d366211 b/storage/textures/b2c3e7d1fe775351fa50544031ffaa51b93ef50108e7530fd3ba349c2d366211 new file mode 100755 index 0000000..eefae53 Binary files /dev/null and b/storage/textures/b2c3e7d1fe775351fa50544031ffaa51b93ef50108e7530fd3ba349c2d366211 differ diff --git a/storage/textures/b3cee44ad0063090900abd0130e5b92f689ff089c2bcb16e17fe9b31e4a9b4d3 b/storage/textures/b3cee44ad0063090900abd0130e5b92f689ff089c2bcb16e17fe9b31e4a9b4d3 new file mode 100644 index 0000000..2f45d04 Binary files /dev/null and b/storage/textures/b3cee44ad0063090900abd0130e5b92f689ff089c2bcb16e17fe9b31e4a9b4d3 differ diff --git a/storage/textures/b3e681553b7963822bfe027fc5218aa695869f1ffbb0e397c65cc4941af5c8d4 b/storage/textures/b3e681553b7963822bfe027fc5218aa695869f1ffbb0e397c65cc4941af5c8d4 new file mode 100644 index 0000000..f939295 Binary files /dev/null and b/storage/textures/b3e681553b7963822bfe027fc5218aa695869f1ffbb0e397c65cc4941af5c8d4 differ diff --git a/storage/textures/b431726ac0d518d51725b0f0298c3f846e499386141a9f42477f7a53da12af19 b/storage/textures/b431726ac0d518d51725b0f0298c3f846e499386141a9f42477f7a53da12af19 new file mode 100755 index 0000000..447bbee Binary files /dev/null and b/storage/textures/b431726ac0d518d51725b0f0298c3f846e499386141a9f42477f7a53da12af19 differ diff --git a/storage/textures/b46beca27684416b7a1d4911505ecebd09a83388c73dd2a5a7043f8ba1b1d374 b/storage/textures/b46beca27684416b7a1d4911505ecebd09a83388c73dd2a5a7043f8ba1b1d374 new file mode 100755 index 0000000..0c0dd82 Binary files /dev/null and b/storage/textures/b46beca27684416b7a1d4911505ecebd09a83388c73dd2a5a7043f8ba1b1d374 differ diff --git a/storage/textures/b4a8c2213960884f9b861a28f868a2e70c8e7d8fa50f15fa690571b0b428254f b/storage/textures/b4a8c2213960884f9b861a28f868a2e70c8e7d8fa50f15fa690571b0b428254f new file mode 100644 index 0000000..a0ed6b5 Binary files /dev/null and b/storage/textures/b4a8c2213960884f9b861a28f868a2e70c8e7d8fa50f15fa690571b0b428254f differ diff --git a/storage/textures/b4e0070a5b97cebf3dcf5d61e8541e91c82d27cb2e056c213ae9d8d3b82843d9 b/storage/textures/b4e0070a5b97cebf3dcf5d61e8541e91c82d27cb2e056c213ae9d8d3b82843d9 new file mode 100755 index 0000000..31c247e Binary files /dev/null and b/storage/textures/b4e0070a5b97cebf3dcf5d61e8541e91c82d27cb2e056c213ae9d8d3b82843d9 differ diff --git a/storage/textures/b528207c4c2de86ceff74a2a2c8ab4019b3eaef7caf9343c70cdd3e16b7ea51b b/storage/textures/b528207c4c2de86ceff74a2a2c8ab4019b3eaef7caf9343c70cdd3e16b7ea51b new file mode 100755 index 0000000..8383386 Binary files /dev/null and b/storage/textures/b528207c4c2de86ceff74a2a2c8ab4019b3eaef7caf9343c70cdd3e16b7ea51b differ diff --git a/storage/textures/b5459f3bd72045c76388e5556dff1a688e5dc4573c42ea256fe270527532e763 b/storage/textures/b5459f3bd72045c76388e5556dff1a688e5dc4573c42ea256fe270527532e763 new file mode 100755 index 0000000..6f48682 Binary files /dev/null and b/storage/textures/b5459f3bd72045c76388e5556dff1a688e5dc4573c42ea256fe270527532e763 differ diff --git a/storage/textures/b555e11d6a2f506909f367572ec83a8c6250480f81152dc53f843005b75a98d8 b/storage/textures/b555e11d6a2f506909f367572ec83a8c6250480f81152dc53f843005b75a98d8 new file mode 100755 index 0000000..082d771 Binary files /dev/null and b/storage/textures/b555e11d6a2f506909f367572ec83a8c6250480f81152dc53f843005b75a98d8 differ diff --git a/storage/textures/b57fcb631c387f3bd08759a818f146f342ce5b68ba0ce7a2ba80257580117efa b/storage/textures/b57fcb631c387f3bd08759a818f146f342ce5b68ba0ce7a2ba80257580117efa new file mode 100644 index 0000000..f527506 Binary files /dev/null and b/storage/textures/b57fcb631c387f3bd08759a818f146f342ce5b68ba0ce7a2ba80257580117efa differ diff --git a/storage/textures/b5d2f237eec0321ad354cdb8dde1cbfd23b793c248075bb6fd26f2083a7cec79 b/storage/textures/b5d2f237eec0321ad354cdb8dde1cbfd23b793c248075bb6fd26f2083a7cec79 new file mode 100755 index 0000000..d6b1c59 Binary files /dev/null and b/storage/textures/b5d2f237eec0321ad354cdb8dde1cbfd23b793c248075bb6fd26f2083a7cec79 differ diff --git a/storage/textures/b5d62a16e5453d8849603a9d888cc84907a47edd5e25cf46b7f733968d73749e b/storage/textures/b5d62a16e5453d8849603a9d888cc84907a47edd5e25cf46b7f733968d73749e new file mode 100755 index 0000000..7ced168 Binary files /dev/null and b/storage/textures/b5d62a16e5453d8849603a9d888cc84907a47edd5e25cf46b7f733968d73749e differ diff --git a/storage/textures/b5df7abd53217e56095654aa81ec035f111a79d3dc9f1e273b35d39391675697 b/storage/textures/b5df7abd53217e56095654aa81ec035f111a79d3dc9f1e273b35d39391675697 new file mode 100644 index 0000000..6bc51cd Binary files /dev/null and b/storage/textures/b5df7abd53217e56095654aa81ec035f111a79d3dc9f1e273b35d39391675697 differ diff --git a/storage/textures/b6317f710864c7334ea32c12030b202df39af777b677892bf8d4caf2365bb226 b/storage/textures/b6317f710864c7334ea32c12030b202df39af777b677892bf8d4caf2365bb226 new file mode 100755 index 0000000..e62e975 Binary files /dev/null and b/storage/textures/b6317f710864c7334ea32c12030b202df39af777b677892bf8d4caf2365bb226 differ diff --git a/storage/textures/b7038f869b51d854ba89ec498f2cbfaa9a5c2c832979b4b5c608dd8101ee24ff b/storage/textures/b7038f869b51d854ba89ec498f2cbfaa9a5c2c832979b4b5c608dd8101ee24ff new file mode 100755 index 0000000..34d7cc9 Binary files /dev/null and b/storage/textures/b7038f869b51d854ba89ec498f2cbfaa9a5c2c832979b4b5c608dd8101ee24ff differ diff --git a/storage/textures/b70511cef82f17a779d7517ef91a8fc24110bb7fde6d8501f40eba74f848f97a b/storage/textures/b70511cef82f17a779d7517ef91a8fc24110bb7fde6d8501f40eba74f848f97a new file mode 100755 index 0000000..aeafa29 Binary files /dev/null and b/storage/textures/b70511cef82f17a779d7517ef91a8fc24110bb7fde6d8501f40eba74f848f97a differ diff --git a/storage/textures/b731c636ff2eb84b55d5c200d5bd80c7c18fcd5c4fc578607eb3d8d5f3ddd469 b/storage/textures/b731c636ff2eb84b55d5c200d5bd80c7c18fcd5c4fc578607eb3d8d5f3ddd469 new file mode 100755 index 0000000..a0e731a Binary files /dev/null and b/storage/textures/b731c636ff2eb84b55d5c200d5bd80c7c18fcd5c4fc578607eb3d8d5f3ddd469 differ diff --git a/storage/textures/b7487b75fe54810a88fec23eda080120c9d25d8bdae6fbc735744b3399d8a6b9 b/storage/textures/b7487b75fe54810a88fec23eda080120c9d25d8bdae6fbc735744b3399d8a6b9 new file mode 100755 index 0000000..6a974c9 Binary files /dev/null and b/storage/textures/b7487b75fe54810a88fec23eda080120c9d25d8bdae6fbc735744b3399d8a6b9 differ diff --git a/storage/textures/b780bcb0909bbe111c9be7b9f22a9fbdb54709734f7b73e1ea0530917b453b2b b/storage/textures/b780bcb0909bbe111c9be7b9f22a9fbdb54709734f7b73e1ea0530917b453b2b new file mode 100755 index 0000000..7e97a01 Binary files /dev/null and b/storage/textures/b780bcb0909bbe111c9be7b9f22a9fbdb54709734f7b73e1ea0530917b453b2b differ diff --git a/storage/textures/b7a259edbb0fb758547edde1786a887cdc03f8ee2d35d033375212252483c055 b/storage/textures/b7a259edbb0fb758547edde1786a887cdc03f8ee2d35d033375212252483c055 new file mode 100755 index 0000000..fe71bdb Binary files /dev/null and b/storage/textures/b7a259edbb0fb758547edde1786a887cdc03f8ee2d35d033375212252483c055 differ diff --git a/storage/textures/b7af394bcc60ed250407570bd0d5282141f0d8e5019cb2079c9c542a6665ae7d b/storage/textures/b7af394bcc60ed250407570bd0d5282141f0d8e5019cb2079c9c542a6665ae7d new file mode 100755 index 0000000..1aba069 Binary files /dev/null and b/storage/textures/b7af394bcc60ed250407570bd0d5282141f0d8e5019cb2079c9c542a6665ae7d differ diff --git a/storage/textures/b7c38b723374afab487e2c2eb9ecf2f35c4a19099e1f9dad5e3002ba3267b4ac b/storage/textures/b7c38b723374afab487e2c2eb9ecf2f35c4a19099e1f9dad5e3002ba3267b4ac new file mode 100755 index 0000000..affdbec Binary files /dev/null and b/storage/textures/b7c38b723374afab487e2c2eb9ecf2f35c4a19099e1f9dad5e3002ba3267b4ac differ diff --git a/storage/textures/b7d88c66a7bce8d2c11b62e18000bd7821b4219fa1ac758b977743f0d9097e03 b/storage/textures/b7d88c66a7bce8d2c11b62e18000bd7821b4219fa1ac758b977743f0d9097e03 new file mode 100644 index 0000000..ef013ed Binary files /dev/null and b/storage/textures/b7d88c66a7bce8d2c11b62e18000bd7821b4219fa1ac758b977743f0d9097e03 differ diff --git a/storage/textures/b7dcfa7d37e5337c4401a26f0d73a0d97bc5d053f174e95a44f172dc24f363a0 b/storage/textures/b7dcfa7d37e5337c4401a26f0d73a0d97bc5d053f174e95a44f172dc24f363a0 new file mode 100755 index 0000000..dae60ea Binary files /dev/null and b/storage/textures/b7dcfa7d37e5337c4401a26f0d73a0d97bc5d053f174e95a44f172dc24f363a0 differ diff --git a/storage/textures/b7e1dbb11e71594724ae3b0b78acebd47c5d31fbadadb61bf603cef5b3a9f5b5 b/storage/textures/b7e1dbb11e71594724ae3b0b78acebd47c5d31fbadadb61bf603cef5b3a9f5b5 new file mode 100644 index 0000000..e13ea72 Binary files /dev/null and b/storage/textures/b7e1dbb11e71594724ae3b0b78acebd47c5d31fbadadb61bf603cef5b3a9f5b5 differ diff --git a/storage/textures/b80f87685ccbe6b90698377a1373cb6c53a5e658891848f3474b94a8e0cb46e8 b/storage/textures/b80f87685ccbe6b90698377a1373cb6c53a5e658891848f3474b94a8e0cb46e8 new file mode 100755 index 0000000..e8f1743 Binary files /dev/null and b/storage/textures/b80f87685ccbe6b90698377a1373cb6c53a5e658891848f3474b94a8e0cb46e8 differ diff --git a/storage/textures/b846e66998ccc44a99503c7340cdba7ccb0bbfbb85a8913b5522997c808d5de3 b/storage/textures/b846e66998ccc44a99503c7340cdba7ccb0bbfbb85a8913b5522997c808d5de3 new file mode 100644 index 0000000..2095cc6 Binary files /dev/null and b/storage/textures/b846e66998ccc44a99503c7340cdba7ccb0bbfbb85a8913b5522997c808d5de3 differ diff --git a/storage/textures/b8525778cd368bd4bdf40d529274f71567b9d4e0ded4857e7a9b1487622ce34a b/storage/textures/b8525778cd368bd4bdf40d529274f71567b9d4e0ded4857e7a9b1487622ce34a new file mode 100755 index 0000000..07a18e3 Binary files /dev/null and b/storage/textures/b8525778cd368bd4bdf40d529274f71567b9d4e0ded4857e7a9b1487622ce34a differ diff --git a/storage/textures/b933738c0bc95d44dd33fcc7ecdfb6bbd33ac4c896f03b84b66178c72adc7dcf b/storage/textures/b933738c0bc95d44dd33fcc7ecdfb6bbd33ac4c896f03b84b66178c72adc7dcf new file mode 100755 index 0000000..50e1a3b Binary files /dev/null and b/storage/textures/b933738c0bc95d44dd33fcc7ecdfb6bbd33ac4c896f03b84b66178c72adc7dcf differ diff --git a/storage/textures/b957c4afd0eae16721e14b2811f923c8c396b2af1c79585ddbffd0b0b0a628a3 b/storage/textures/b957c4afd0eae16721e14b2811f923c8c396b2af1c79585ddbffd0b0b0a628a3 new file mode 100644 index 0000000..f3de1e1 Binary files /dev/null and b/storage/textures/b957c4afd0eae16721e14b2811f923c8c396b2af1c79585ddbffd0b0b0a628a3 differ diff --git a/storage/textures/b95ea87a13e3f82ddea74a2a13135c62241aa2a4958a198fa5b678f80e0265d1 b/storage/textures/b95ea87a13e3f82ddea74a2a13135c62241aa2a4958a198fa5b678f80e0265d1 new file mode 100755 index 0000000..7723f29 Binary files /dev/null and b/storage/textures/b95ea87a13e3f82ddea74a2a13135c62241aa2a4958a198fa5b678f80e0265d1 differ diff --git a/storage/textures/b989b6d45e9fc014dc84e4ff55af6716a57b361be1990dee31da34a69258bb6d b/storage/textures/b989b6d45e9fc014dc84e4ff55af6716a57b361be1990dee31da34a69258bb6d new file mode 100644 index 0000000..2d194fb Binary files /dev/null and b/storage/textures/b989b6d45e9fc014dc84e4ff55af6716a57b361be1990dee31da34a69258bb6d differ diff --git a/storage/textures/b9b995c9593cffdeba9346b210c1c5f32c8358d88f95d6eab06fd7560c924864 b/storage/textures/b9b995c9593cffdeba9346b210c1c5f32c8358d88f95d6eab06fd7560c924864 new file mode 100755 index 0000000..b669d37 Binary files /dev/null and b/storage/textures/b9b995c9593cffdeba9346b210c1c5f32c8358d88f95d6eab06fd7560c924864 differ diff --git a/storage/textures/b9de55276ead64b23342a8465874562e582ebeddbbb979dd82f4018f6d4827d6 b/storage/textures/b9de55276ead64b23342a8465874562e582ebeddbbb979dd82f4018f6d4827d6 new file mode 100755 index 0000000..e2fb5cf Binary files /dev/null and b/storage/textures/b9de55276ead64b23342a8465874562e582ebeddbbb979dd82f4018f6d4827d6 differ diff --git a/storage/textures/ba02b04151df9be2490c86146dbd528212fad7ad0dfc2c6d0c309a2620e68321 b/storage/textures/ba02b04151df9be2490c86146dbd528212fad7ad0dfc2c6d0c309a2620e68321 new file mode 100644 index 0000000..fe5802a Binary files /dev/null and b/storage/textures/ba02b04151df9be2490c86146dbd528212fad7ad0dfc2c6d0c309a2620e68321 differ diff --git a/storage/textures/ba698419c4ea21c46b9a3c220c9d142fce979793ce3c212ff09fd32a13174254 b/storage/textures/ba698419c4ea21c46b9a3c220c9d142fce979793ce3c212ff09fd32a13174254 new file mode 100755 index 0000000..d16b3a5 Binary files /dev/null and b/storage/textures/ba698419c4ea21c46b9a3c220c9d142fce979793ce3c212ff09fd32a13174254 differ diff --git a/storage/textures/ba7b993f3f921f3949c8c2c1356e07c81306e89b94bf50b408d08f78eb1715bc b/storage/textures/ba7b993f3f921f3949c8c2c1356e07c81306e89b94bf50b408d08f78eb1715bc new file mode 100644 index 0000000..f0de135 Binary files /dev/null and b/storage/textures/ba7b993f3f921f3949c8c2c1356e07c81306e89b94bf50b408d08f78eb1715bc differ diff --git a/storage/textures/bac1cde86a5f1cb35abd71b62aa15f2a0e66a928d7b2d46d21e02d7cce0ef409 b/storage/textures/bac1cde86a5f1cb35abd71b62aa15f2a0e66a928d7b2d46d21e02d7cce0ef409 new file mode 100644 index 0000000..7e5aab9 Binary files /dev/null and b/storage/textures/bac1cde86a5f1cb35abd71b62aa15f2a0e66a928d7b2d46d21e02d7cce0ef409 differ diff --git a/storage/textures/bad6cce2f3dfb493567cbc094258515a75dc462456730fcccef518a4f08f51be b/storage/textures/bad6cce2f3dfb493567cbc094258515a75dc462456730fcccef518a4f08f51be new file mode 100755 index 0000000..48e6e72 Binary files /dev/null and b/storage/textures/bad6cce2f3dfb493567cbc094258515a75dc462456730fcccef518a4f08f51be differ diff --git a/storage/textures/bb2373a0b6d2c592395db95ad27fbae84dd9db68d3a34b695071d8cccc06666d b/storage/textures/bb2373a0b6d2c592395db95ad27fbae84dd9db68d3a34b695071d8cccc06666d new file mode 100755 index 0000000..95476bb Binary files /dev/null and b/storage/textures/bb2373a0b6d2c592395db95ad27fbae84dd9db68d3a34b695071d8cccc06666d differ diff --git a/storage/textures/bb35b4eaa3f937e6c6f530a2942608b9ea76dd827138dd8478f6c3089f0a312b b/storage/textures/bb35b4eaa3f937e6c6f530a2942608b9ea76dd827138dd8478f6c3089f0a312b new file mode 100644 index 0000000..09b4a24 Binary files /dev/null and b/storage/textures/bb35b4eaa3f937e6c6f530a2942608b9ea76dd827138dd8478f6c3089f0a312b differ diff --git a/storage/textures/bbbd480282e4b11081753fb84468964415b70ef8ef27b09012e44c4cd43d43db b/storage/textures/bbbd480282e4b11081753fb84468964415b70ef8ef27b09012e44c4cd43d43db new file mode 100644 index 0000000..6ce96e6 Binary files /dev/null and b/storage/textures/bbbd480282e4b11081753fb84468964415b70ef8ef27b09012e44c4cd43d43db differ diff --git a/storage/textures/bbe240ffe7b53a1e65de8945c5387e248b3455219a2d89ee221c3438f33dffb6 b/storage/textures/bbe240ffe7b53a1e65de8945c5387e248b3455219a2d89ee221c3438f33dffb6 new file mode 100644 index 0000000..406c8e8 Binary files /dev/null and b/storage/textures/bbe240ffe7b53a1e65de8945c5387e248b3455219a2d89ee221c3438f33dffb6 differ diff --git a/storage/textures/bccc7feba9798f471696b6951199d9468fbff5afb152a80c958233cc59c1547a b/storage/textures/bccc7feba9798f471696b6951199d9468fbff5afb152a80c958233cc59c1547a new file mode 100644 index 0000000..d0cd781 Binary files /dev/null and b/storage/textures/bccc7feba9798f471696b6951199d9468fbff5afb152a80c958233cc59c1547a differ diff --git a/storage/textures/bcdca43dfcd2ee4159b998e921c5b8728982855d8aca1bb18a4aff4b7edd7985 b/storage/textures/bcdca43dfcd2ee4159b998e921c5b8728982855d8aca1bb18a4aff4b7edd7985 new file mode 100644 index 0000000..8dfd226 Binary files /dev/null and b/storage/textures/bcdca43dfcd2ee4159b998e921c5b8728982855d8aca1bb18a4aff4b7edd7985 differ diff --git a/storage/textures/bce3edbdd2e374788091d9afac03b0a3ebb0087f1b75e7797532f7d8843733c8 b/storage/textures/bce3edbdd2e374788091d9afac03b0a3ebb0087f1b75e7797532f7d8843733c8 new file mode 100755 index 0000000..25c3268 Binary files /dev/null and b/storage/textures/bce3edbdd2e374788091d9afac03b0a3ebb0087f1b75e7797532f7d8843733c8 differ diff --git a/storage/textures/bd2484d2a2885e04bdd0e5834bf772a26f30bd5ce88ed489f0c82bfef8d1c190 b/storage/textures/bd2484d2a2885e04bdd0e5834bf772a26f30bd5ce88ed489f0c82bfef8d1c190 new file mode 100755 index 0000000..a46cd66 Binary files /dev/null and b/storage/textures/bd2484d2a2885e04bdd0e5834bf772a26f30bd5ce88ed489f0c82bfef8d1c190 differ diff --git a/storage/textures/bd7ce485713a317ffbee8db724ce96965626f33a760e1b5527c49906cc29f2c7 b/storage/textures/bd7ce485713a317ffbee8db724ce96965626f33a760e1b5527c49906cc29f2c7 new file mode 100755 index 0000000..1fc05a8 Binary files /dev/null and b/storage/textures/bd7ce485713a317ffbee8db724ce96965626f33a760e1b5527c49906cc29f2c7 differ diff --git a/storage/textures/bdfb4dc40145bcfed75013c08d3e3913585f1f4a01ba32717dfbded303429f32 b/storage/textures/bdfb4dc40145bcfed75013c08d3e3913585f1f4a01ba32717dfbded303429f32 new file mode 100755 index 0000000..357b927 Binary files /dev/null and b/storage/textures/bdfb4dc40145bcfed75013c08d3e3913585f1f4a01ba32717dfbded303429f32 differ diff --git a/storage/textures/be00d82a5c66a4a56c3dbbdbec6fe5d042cc27a6d777fadee3b1c329844d1f5c b/storage/textures/be00d82a5c66a4a56c3dbbdbec6fe5d042cc27a6d777fadee3b1c329844d1f5c new file mode 100755 index 0000000..402ad88 Binary files /dev/null and b/storage/textures/be00d82a5c66a4a56c3dbbdbec6fe5d042cc27a6d777fadee3b1c329844d1f5c differ diff --git a/storage/textures/be0331f7f2715499710e1830c9b8b2a5d0f3f8562258c50a47d51ca97c03cb75 b/storage/textures/be0331f7f2715499710e1830c9b8b2a5d0f3f8562258c50a47d51ca97c03cb75 new file mode 100644 index 0000000..353635a Binary files /dev/null and b/storage/textures/be0331f7f2715499710e1830c9b8b2a5d0f3f8562258c50a47d51ca97c03cb75 differ diff --git a/storage/textures/be82e81b8b4f27090161469d202b88f0b50ddcc507f477bb78693f2e0d1101fd b/storage/textures/be82e81b8b4f27090161469d202b88f0b50ddcc507f477bb78693f2e0d1101fd new file mode 100755 index 0000000..3ecd9c4 Binary files /dev/null and b/storage/textures/be82e81b8b4f27090161469d202b88f0b50ddcc507f477bb78693f2e0d1101fd differ diff --git a/storage/textures/be884bffbc5a53ccc3cb5ace5c57bfe0b64403fe11884cddb913f3cdb72b86a6 b/storage/textures/be884bffbc5a53ccc3cb5ace5c57bfe0b64403fe11884cddb913f3cdb72b86a6 new file mode 100755 index 0000000..24e19e7 Binary files /dev/null and b/storage/textures/be884bffbc5a53ccc3cb5ace5c57bfe0b64403fe11884cddb913f3cdb72b86a6 differ diff --git a/storage/textures/beb91d5cc71120e7b569ab1e4c616f907bab13223ed05342cf384611c98d3886 b/storage/textures/beb91d5cc71120e7b569ab1e4c616f907bab13223ed05342cf384611c98d3886 new file mode 100755 index 0000000..8f83915 Binary files /dev/null and b/storage/textures/beb91d5cc71120e7b569ab1e4c616f907bab13223ed05342cf384611c98d3886 differ diff --git a/storage/textures/bf0e72adb9007d2c2d44875d8cad48a825f440616f0eae639a099376496d9ca8 b/storage/textures/bf0e72adb9007d2c2d44875d8cad48a825f440616f0eae639a099376496d9ca8 new file mode 100755 index 0000000..9dfae06 Binary files /dev/null and b/storage/textures/bf0e72adb9007d2c2d44875d8cad48a825f440616f0eae639a099376496d9ca8 differ diff --git a/storage/textures/bf6a0be52a25884fad8c2a28e9e223d98544eacf91a55b52fc4f22a11d657db1 b/storage/textures/bf6a0be52a25884fad8c2a28e9e223d98544eacf91a55b52fc4f22a11d657db1 new file mode 100644 index 0000000..9409d27 Binary files /dev/null and b/storage/textures/bf6a0be52a25884fad8c2a28e9e223d98544eacf91a55b52fc4f22a11d657db1 differ diff --git a/storage/textures/bf800c6b1bd2242929413d3af468fc05a3cc5bc87009d00c2c8ba893a208a048 b/storage/textures/bf800c6b1bd2242929413d3af468fc05a3cc5bc87009d00c2c8ba893a208a048 new file mode 100755 index 0000000..7b0454d Binary files /dev/null and b/storage/textures/bf800c6b1bd2242929413d3af468fc05a3cc5bc87009d00c2c8ba893a208a048 differ diff --git a/storage/textures/bf905951a31d51ad39b1ad08791ea6feaba2e9413f4d4e828b75ef134ded2595 b/storage/textures/bf905951a31d51ad39b1ad08791ea6feaba2e9413f4d4e828b75ef134ded2595 new file mode 100755 index 0000000..29b1164 Binary files /dev/null and b/storage/textures/bf905951a31d51ad39b1ad08791ea6feaba2e9413f4d4e828b75ef134ded2595 differ diff --git a/storage/textures/bf90a35b699e91e06dca5537d56000eb12f9fc1b2d2e48f47a57821a3876c565 b/storage/textures/bf90a35b699e91e06dca5537d56000eb12f9fc1b2d2e48f47a57821a3876c565 new file mode 100644 index 0000000..3e10dcd Binary files /dev/null and b/storage/textures/bf90a35b699e91e06dca5537d56000eb12f9fc1b2d2e48f47a57821a3876c565 differ diff --git a/storage/textures/bfa227934c2e841a56be3fb34da1394bc63400eb052cc92c090951f6db69b333 b/storage/textures/bfa227934c2e841a56be3fb34da1394bc63400eb052cc92c090951f6db69b333 new file mode 100755 index 0000000..32bcf13 Binary files /dev/null and b/storage/textures/bfa227934c2e841a56be3fb34da1394bc63400eb052cc92c090951f6db69b333 differ diff --git a/storage/textures/bfb1b5a0e1cd6d9a08b6251394de78d01e5ce2392691a94e410b3838a5d19f6e b/storage/textures/bfb1b5a0e1cd6d9a08b6251394de78d01e5ce2392691a94e410b3838a5d19f6e new file mode 100644 index 0000000..27cc147 Binary files /dev/null and b/storage/textures/bfb1b5a0e1cd6d9a08b6251394de78d01e5ce2392691a94e410b3838a5d19f6e differ diff --git a/storage/textures/c0c7594a442ac31f409782f1f1b05058d9075bb96b6f3ad163d5e5c2bfdefe14 b/storage/textures/c0c7594a442ac31f409782f1f1b05058d9075bb96b6f3ad163d5e5c2bfdefe14 new file mode 100644 index 0000000..33b2b65 Binary files /dev/null and b/storage/textures/c0c7594a442ac31f409782f1f1b05058d9075bb96b6f3ad163d5e5c2bfdefe14 differ diff --git a/storage/textures/c149d33bd76cbcae84f4157dc69c324ed0d0248689abeca175856675608f9099 b/storage/textures/c149d33bd76cbcae84f4157dc69c324ed0d0248689abeca175856675608f9099 new file mode 100755 index 0000000..ea9a048 Binary files /dev/null and b/storage/textures/c149d33bd76cbcae84f4157dc69c324ed0d0248689abeca175856675608f9099 differ diff --git a/storage/textures/c1a7ada4a52834dce9d2ba9851e5de925e60323d3ccb78de40f6d7168b6514d8 b/storage/textures/c1a7ada4a52834dce9d2ba9851e5de925e60323d3ccb78de40f6d7168b6514d8 new file mode 100755 index 0000000..0a819e9 Binary files /dev/null and b/storage/textures/c1a7ada4a52834dce9d2ba9851e5de925e60323d3ccb78de40f6d7168b6514d8 differ diff --git a/storage/textures/c1c8dd2f74aa9cd5d8ecbcf7ac6dd7d74a7f45974096f6b4f62b27ae2085247a b/storage/textures/c1c8dd2f74aa9cd5d8ecbcf7ac6dd7d74a7f45974096f6b4f62b27ae2085247a new file mode 100755 index 0000000..280145b Binary files /dev/null and b/storage/textures/c1c8dd2f74aa9cd5d8ecbcf7ac6dd7d74a7f45974096f6b4f62b27ae2085247a differ diff --git a/storage/textures/c1c9b4c230c9539976eea16cf7a1901ae57013346e3cc05ec3d51d5ef99be8d1 b/storage/textures/c1c9b4c230c9539976eea16cf7a1901ae57013346e3cc05ec3d51d5ef99be8d1 new file mode 100755 index 0000000..baade69 Binary files /dev/null and b/storage/textures/c1c9b4c230c9539976eea16cf7a1901ae57013346e3cc05ec3d51d5ef99be8d1 differ diff --git a/storage/textures/c20d561d665626ea628c13b48ba87516273b109b99991b588a64c2b604c3c857 b/storage/textures/c20d561d665626ea628c13b48ba87516273b109b99991b588a64c2b604c3c857 new file mode 100755 index 0000000..bd09813 Binary files /dev/null and b/storage/textures/c20d561d665626ea628c13b48ba87516273b109b99991b588a64c2b604c3c857 differ diff --git a/storage/textures/c20d6661f24ea18cefba4ceaa52a8e28bfac33303d4a27337e1cd7743d6e8f20 b/storage/textures/c20d6661f24ea18cefba4ceaa52a8e28bfac33303d4a27337e1cd7743d6e8f20 new file mode 100644 index 0000000..339fe95 Binary files /dev/null and b/storage/textures/c20d6661f24ea18cefba4ceaa52a8e28bfac33303d4a27337e1cd7743d6e8f20 differ diff --git a/storage/textures/c22aa18ebae6faec86b505f83e76d782637ea160df09a23ac82ae08ff9b56c22 b/storage/textures/c22aa18ebae6faec86b505f83e76d782637ea160df09a23ac82ae08ff9b56c22 new file mode 100644 index 0000000..91ab7ff Binary files /dev/null and b/storage/textures/c22aa18ebae6faec86b505f83e76d782637ea160df09a23ac82ae08ff9b56c22 differ diff --git a/storage/textures/c2ffbcb9325bfa23868afe6b35929becf7906bbaff1ee381b245155149fa606b b/storage/textures/c2ffbcb9325bfa23868afe6b35929becf7906bbaff1ee381b245155149fa606b new file mode 100755 index 0000000..7899dc2 Binary files /dev/null and b/storage/textures/c2ffbcb9325bfa23868afe6b35929becf7906bbaff1ee381b245155149fa606b differ diff --git a/storage/textures/c34f2056c3c5589a20d6d71c85ed6c3c5bb0eeef1f6981ed3c9434d08058e011 b/storage/textures/c34f2056c3c5589a20d6d71c85ed6c3c5bb0eeef1f6981ed3c9434d08058e011 new file mode 100644 index 0000000..dc31500 Binary files /dev/null and b/storage/textures/c34f2056c3c5589a20d6d71c85ed6c3c5bb0eeef1f6981ed3c9434d08058e011 differ diff --git a/storage/textures/c34ffa800e2aedbb8e49f035d76be5124132852f731d6b13e94f3e17cb375bd9 b/storage/textures/c34ffa800e2aedbb8e49f035d76be5124132852f731d6b13e94f3e17cb375bd9 new file mode 100644 index 0000000..82def48 Binary files /dev/null and b/storage/textures/c34ffa800e2aedbb8e49f035d76be5124132852f731d6b13e94f3e17cb375bd9 differ diff --git a/storage/textures/c35c91bcaa5427271ec2bb4f9d4b325a6ec1ccc752e68000568b84d49f171261 b/storage/textures/c35c91bcaa5427271ec2bb4f9d4b325a6ec1ccc752e68000568b84d49f171261 new file mode 100644 index 0000000..cd99d65 Binary files /dev/null and b/storage/textures/c35c91bcaa5427271ec2bb4f9d4b325a6ec1ccc752e68000568b84d49f171261 differ diff --git a/storage/textures/c363dcd6ea5899ae9818abc12a871a722763e8206cc7e9f4dfd95c69284d73d7 b/storage/textures/c363dcd6ea5899ae9818abc12a871a722763e8206cc7e9f4dfd95c69284d73d7 new file mode 100644 index 0000000..d1db075 Binary files /dev/null and b/storage/textures/c363dcd6ea5899ae9818abc12a871a722763e8206cc7e9f4dfd95c69284d73d7 differ diff --git a/storage/textures/c36a666e57df2ce4b69e9bdab5f457d81a67a285bfeee014d3e87c5dfbc95bf6 b/storage/textures/c36a666e57df2ce4b69e9bdab5f457d81a67a285bfeee014d3e87c5dfbc95bf6 new file mode 100755 index 0000000..4a8aa21 Binary files /dev/null and b/storage/textures/c36a666e57df2ce4b69e9bdab5f457d81a67a285bfeee014d3e87c5dfbc95bf6 differ diff --git a/storage/textures/c37a27f5e76931447fd00e5616b4555b14e7e25f48f7044b86eab4c83abf6f13 b/storage/textures/c37a27f5e76931447fd00e5616b4555b14e7e25f48f7044b86eab4c83abf6f13 new file mode 100755 index 0000000..b137376 Binary files /dev/null and b/storage/textures/c37a27f5e76931447fd00e5616b4555b14e7e25f48f7044b86eab4c83abf6f13 differ diff --git a/storage/textures/c4656ea3e60d864ad17bf638377e432cf0dc947ed8fc2d4a7c115278a146e753 b/storage/textures/c4656ea3e60d864ad17bf638377e432cf0dc947ed8fc2d4a7c115278a146e753 new file mode 100755 index 0000000..158633d Binary files /dev/null and b/storage/textures/c4656ea3e60d864ad17bf638377e432cf0dc947ed8fc2d4a7c115278a146e753 differ diff --git a/storage/textures/c475ecdc5cd50b42a4dd3831d1e4404f83b2724359aa48a79e5fcf77b04ce602 b/storage/textures/c475ecdc5cd50b42a4dd3831d1e4404f83b2724359aa48a79e5fcf77b04ce602 new file mode 100755 index 0000000..a95b12f Binary files /dev/null and b/storage/textures/c475ecdc5cd50b42a4dd3831d1e4404f83b2724359aa48a79e5fcf77b04ce602 differ diff --git a/storage/textures/c4fdc2a84961c96db50e78d1174370f313f92bec0841d5202700617de4ca1b5c b/storage/textures/c4fdc2a84961c96db50e78d1174370f313f92bec0841d5202700617de4ca1b5c new file mode 100755 index 0000000..a898a4d Binary files /dev/null and b/storage/textures/c4fdc2a84961c96db50e78d1174370f313f92bec0841d5202700617de4ca1b5c differ diff --git a/storage/textures/c5827bf845fa3c2134109b1910414a53d30d542daf3516ddff4af0bddf12f272 b/storage/textures/c5827bf845fa3c2134109b1910414a53d30d542daf3516ddff4af0bddf12f272 new file mode 100755 index 0000000..bbdc124 Binary files /dev/null and b/storage/textures/c5827bf845fa3c2134109b1910414a53d30d542daf3516ddff4af0bddf12f272 differ diff --git a/storage/textures/c6525d33498340c9b5c9476ba2a6c0578f30ece53ec0eba86d42af5e7c6f06a1 b/storage/textures/c6525d33498340c9b5c9476ba2a6c0578f30ece53ec0eba86d42af5e7c6f06a1 new file mode 100755 index 0000000..0678c00 Binary files /dev/null and b/storage/textures/c6525d33498340c9b5c9476ba2a6c0578f30ece53ec0eba86d42af5e7c6f06a1 differ diff --git a/storage/textures/c65e6f919c7edcac0008510496db6d36d56fddf5926233d7c7f98fe8890dffc5 b/storage/textures/c65e6f919c7edcac0008510496db6d36d56fddf5926233d7c7f98fe8890dffc5 new file mode 100755 index 0000000..27fd968 Binary files /dev/null and b/storage/textures/c65e6f919c7edcac0008510496db6d36d56fddf5926233d7c7f98fe8890dffc5 differ diff --git a/storage/textures/c66e39fd4940f0783dc9165120e3427f75eaf2968d0fdcf2551c4d4d128514da b/storage/textures/c66e39fd4940f0783dc9165120e3427f75eaf2968d0fdcf2551c4d4d128514da new file mode 100755 index 0000000..3927bc9 Binary files /dev/null and b/storage/textures/c66e39fd4940f0783dc9165120e3427f75eaf2968d0fdcf2551c4d4d128514da differ diff --git a/storage/textures/c67b48726cb3d5e1bb2b069fdcf8abb9d5aaf6fd55e1fe9dafbd988e5514df36 b/storage/textures/c67b48726cb3d5e1bb2b069fdcf8abb9d5aaf6fd55e1fe9dafbd988e5514df36 new file mode 100755 index 0000000..370ea8a Binary files /dev/null and b/storage/textures/c67b48726cb3d5e1bb2b069fdcf8abb9d5aaf6fd55e1fe9dafbd988e5514df36 differ diff --git a/storage/textures/c68df94408036a3987a36359807a412e3b700581326d0b732bc0407ea95afba6 b/storage/textures/c68df94408036a3987a36359807a412e3b700581326d0b732bc0407ea95afba6 new file mode 100644 index 0000000..c5e339a Binary files /dev/null and b/storage/textures/c68df94408036a3987a36359807a412e3b700581326d0b732bc0407ea95afba6 differ diff --git a/storage/textures/c6d0740cb1ebbcb54c3a909e5e228047f8d3b24bdffb945bf42842723050377b b/storage/textures/c6d0740cb1ebbcb54c3a909e5e228047f8d3b24bdffb945bf42842723050377b new file mode 100644 index 0000000..57977a3 Binary files /dev/null and b/storage/textures/c6d0740cb1ebbcb54c3a909e5e228047f8d3b24bdffb945bf42842723050377b differ diff --git a/storage/textures/c72e76cc611856308fc6c49f297fa94b9a8fd5371e34ee08aeec5600f90165f8 b/storage/textures/c72e76cc611856308fc6c49f297fa94b9a8fd5371e34ee08aeec5600f90165f8 new file mode 100644 index 0000000..9cd548c Binary files /dev/null and b/storage/textures/c72e76cc611856308fc6c49f297fa94b9a8fd5371e34ee08aeec5600f90165f8 differ diff --git a/storage/textures/c80c6bb1bd327daf6c53f919a04922ac2af2df40eb4c8966b6270c395ad0f1f6 b/storage/textures/c80c6bb1bd327daf6c53f919a04922ac2af2df40eb4c8966b6270c395ad0f1f6 new file mode 100755 index 0000000..30c1b70 Binary files /dev/null and b/storage/textures/c80c6bb1bd327daf6c53f919a04922ac2af2df40eb4c8966b6270c395ad0f1f6 differ diff --git a/storage/textures/c834e6d3288e746ce3c8d22c328d1c6971320f8a824d1b1872a079bcf583e62d b/storage/textures/c834e6d3288e746ce3c8d22c328d1c6971320f8a824d1b1872a079bcf583e62d new file mode 100644 index 0000000..53b05db Binary files /dev/null and b/storage/textures/c834e6d3288e746ce3c8d22c328d1c6971320f8a824d1b1872a079bcf583e62d differ diff --git a/storage/textures/c870360de8e57e133bbc937eaed6a2f2f4504ba5c783931c724a62cba1e03053 b/storage/textures/c870360de8e57e133bbc937eaed6a2f2f4504ba5c783931c724a62cba1e03053 new file mode 100755 index 0000000..75be053 Binary files /dev/null and b/storage/textures/c870360de8e57e133bbc937eaed6a2f2f4504ba5c783931c724a62cba1e03053 differ diff --git a/storage/textures/c92ae361efc5f9345dffa756ebadcc9d1eb7b9ce694355034eb2eacba9a5f6ae b/storage/textures/c92ae361efc5f9345dffa756ebadcc9d1eb7b9ce694355034eb2eacba9a5f6ae new file mode 100755 index 0000000..394c6d5 Binary files /dev/null and b/storage/textures/c92ae361efc5f9345dffa756ebadcc9d1eb7b9ce694355034eb2eacba9a5f6ae differ diff --git a/storage/textures/c98cddd0236b6d7a385842a75eb6bf1ddda4452c0dba3bbb4cf9c59d3a25f32e b/storage/textures/c98cddd0236b6d7a385842a75eb6bf1ddda4452c0dba3bbb4cf9c59d3a25f32e new file mode 100755 index 0000000..457367f Binary files /dev/null and b/storage/textures/c98cddd0236b6d7a385842a75eb6bf1ddda4452c0dba3bbb4cf9c59d3a25f32e differ diff --git a/storage/textures/c996af9040858fe30addc844196c0091c1b872fa784b27198a7d4e0b2475224f b/storage/textures/c996af9040858fe30addc844196c0091c1b872fa784b27198a7d4e0b2475224f new file mode 100755 index 0000000..83731da Binary files /dev/null and b/storage/textures/c996af9040858fe30addc844196c0091c1b872fa784b27198a7d4e0b2475224f differ diff --git a/storage/textures/ca393aec94861e1bff8ed1686e304a629386b3ea7b6f524c4051560853bd720d b/storage/textures/ca393aec94861e1bff8ed1686e304a629386b3ea7b6f524c4051560853bd720d new file mode 100755 index 0000000..b286fdd Binary files /dev/null and b/storage/textures/ca393aec94861e1bff8ed1686e304a629386b3ea7b6f524c4051560853bd720d differ diff --git a/storage/textures/ca93f6fc40488f1877cda94a830b54e9f6f54ab58a5453bad5c947726dd1f473 b/storage/textures/ca93f6fc40488f1877cda94a830b54e9f6f54ab58a5453bad5c947726dd1f473 new file mode 100755 index 0000000..71d2bfa Binary files /dev/null and b/storage/textures/ca93f6fc40488f1877cda94a830b54e9f6f54ab58a5453bad5c947726dd1f473 differ diff --git a/storage/textures/cabbc9a5b023e490b1e82bb123d1938e87be2738ce1fc4172c92b10ba58b9a47 b/storage/textures/cabbc9a5b023e490b1e82bb123d1938e87be2738ce1fc4172c92b10ba58b9a47 new file mode 100644 index 0000000..b8d775e Binary files /dev/null and b/storage/textures/cabbc9a5b023e490b1e82bb123d1938e87be2738ce1fc4172c92b10ba58b9a47 differ diff --git a/storage/textures/cafba9bf6b0b3bbc7e050d27c3f083084e705ee0632381aeceea2c95bea063d2 b/storage/textures/cafba9bf6b0b3bbc7e050d27c3f083084e705ee0632381aeceea2c95bea063d2 new file mode 100644 index 0000000..b9dcd1c Binary files /dev/null and b/storage/textures/cafba9bf6b0b3bbc7e050d27c3f083084e705ee0632381aeceea2c95bea063d2 differ diff --git a/storage/textures/cafe5501720b35640df6eb9fdb23253dc851e4e7d55e0df1bf8e147cbac64388 b/storage/textures/cafe5501720b35640df6eb9fdb23253dc851e4e7d55e0df1bf8e147cbac64388 new file mode 100755 index 0000000..a6c4687 Binary files /dev/null and b/storage/textures/cafe5501720b35640df6eb9fdb23253dc851e4e7d55e0df1bf8e147cbac64388 differ diff --git a/storage/textures/caffc7bc881dd4162b6c3711e669711ae271bf0b26e87d2698fdb9137daad86c b/storage/textures/caffc7bc881dd4162b6c3711e669711ae271bf0b26e87d2698fdb9137daad86c new file mode 100755 index 0000000..8ec87ef Binary files /dev/null and b/storage/textures/caffc7bc881dd4162b6c3711e669711ae271bf0b26e87d2698fdb9137daad86c differ diff --git a/storage/textures/cb6f5a5a3f6d0dc259a2579a169ea6df322004fde596149ee6bad7c3a27d309b b/storage/textures/cb6f5a5a3f6d0dc259a2579a169ea6df322004fde596149ee6bad7c3a27d309b new file mode 100755 index 0000000..409a972 Binary files /dev/null and b/storage/textures/cb6f5a5a3f6d0dc259a2579a169ea6df322004fde596149ee6bad7c3a27d309b differ diff --git a/storage/textures/cb7e6120ee167b8a97e082c4f75aa1210525bff12a50f8de8ae854885991c50d b/storage/textures/cb7e6120ee167b8a97e082c4f75aa1210525bff12a50f8de8ae854885991c50d new file mode 100755 index 0000000..66307f4 Binary files /dev/null and b/storage/textures/cb7e6120ee167b8a97e082c4f75aa1210525bff12a50f8de8ae854885991c50d differ diff --git a/storage/textures/cb86cb067f2b29541ff0eeca0e5ece182c0a288605a0fdb6eb2aae74783363cd b/storage/textures/cb86cb067f2b29541ff0eeca0e5ece182c0a288605a0fdb6eb2aae74783363cd new file mode 100644 index 0000000..08663e4 Binary files /dev/null and b/storage/textures/cb86cb067f2b29541ff0eeca0e5ece182c0a288605a0fdb6eb2aae74783363cd differ diff --git a/storage/textures/cb9ac35be53bf73b20f8231039c77918127179c2e1be87c2119afed6d7def6c5 b/storage/textures/cb9ac35be53bf73b20f8231039c77918127179c2e1be87c2119afed6d7def6c5 new file mode 100755 index 0000000..da6445a Binary files /dev/null and b/storage/textures/cb9ac35be53bf73b20f8231039c77918127179c2e1be87c2119afed6d7def6c5 differ diff --git a/storage/textures/cbc3b32dccb9b45842bae4b00baa878696a8f5384f0ef4f0b1543517ff302b71 b/storage/textures/cbc3b32dccb9b45842bae4b00baa878696a8f5384f0ef4f0b1543517ff302b71 new file mode 100755 index 0000000..ac0430c Binary files /dev/null and b/storage/textures/cbc3b32dccb9b45842bae4b00baa878696a8f5384f0ef4f0b1543517ff302b71 differ diff --git a/storage/textures/cc93affa853ff23bce4f778a602b6777410ff2cd230c60fa3e942baacf54b2a6 b/storage/textures/cc93affa853ff23bce4f778a602b6777410ff2cd230c60fa3e942baacf54b2a6 new file mode 100644 index 0000000..41f73e4 Binary files /dev/null and b/storage/textures/cc93affa853ff23bce4f778a602b6777410ff2cd230c60fa3e942baacf54b2a6 differ diff --git a/storage/textures/ccb9fcb42d4eb31c8de32dcf2664392b9e612415a4626181248b312651dc28bc b/storage/textures/ccb9fcb42d4eb31c8de32dcf2664392b9e612415a4626181248b312651dc28bc new file mode 100644 index 0000000..20e05e8 Binary files /dev/null and b/storage/textures/ccb9fcb42d4eb31c8de32dcf2664392b9e612415a4626181248b312651dc28bc differ diff --git a/storage/textures/ccd16a7bb4c0df0fe220b5f57dcc507db36863d7c87b4135be25fab5347805b8 b/storage/textures/ccd16a7bb4c0df0fe220b5f57dcc507db36863d7c87b4135be25fab5347805b8 new file mode 100755 index 0000000..b9137cf Binary files /dev/null and b/storage/textures/ccd16a7bb4c0df0fe220b5f57dcc507db36863d7c87b4135be25fab5347805b8 differ diff --git a/storage/textures/ccf588b1ded8ac4fd65dc25550ba2d5b7c1695ad7be1f40ee803fad405a74b81 b/storage/textures/ccf588b1ded8ac4fd65dc25550ba2d5b7c1695ad7be1f40ee803fad405a74b81 new file mode 100755 index 0000000..57beffc Binary files /dev/null and b/storage/textures/ccf588b1ded8ac4fd65dc25550ba2d5b7c1695ad7be1f40ee803fad405a74b81 differ diff --git a/storage/textures/cd166fbacafd880567b4aa77b6d75be088bbc8db2e35c9494feb1660399ff63e b/storage/textures/cd166fbacafd880567b4aa77b6d75be088bbc8db2e35c9494feb1660399ff63e new file mode 100644 index 0000000..98a14f8 Binary files /dev/null and b/storage/textures/cd166fbacafd880567b4aa77b6d75be088bbc8db2e35c9494feb1660399ff63e differ diff --git a/storage/textures/cd420e7c6e0c10354e10cd80ae7fcac111e16caa99179f6f83f759e3e3dcf08f b/storage/textures/cd420e7c6e0c10354e10cd80ae7fcac111e16caa99179f6f83f759e3e3dcf08f new file mode 100755 index 0000000..dbf976c Binary files /dev/null and b/storage/textures/cd420e7c6e0c10354e10cd80ae7fcac111e16caa99179f6f83f759e3e3dcf08f differ diff --git a/storage/textures/cdabc46280965c4d2375335b493d60596376bc926c4dd2eb99e62c15243aa470 b/storage/textures/cdabc46280965c4d2375335b493d60596376bc926c4dd2eb99e62c15243aa470 new file mode 100755 index 0000000..6d3a826 Binary files /dev/null and b/storage/textures/cdabc46280965c4d2375335b493d60596376bc926c4dd2eb99e62c15243aa470 differ diff --git a/storage/textures/ce0eb0c7140836e9c8b53c57c1a69040194c820c8e219aba00f32bb03b8aa7bf b/storage/textures/ce0eb0c7140836e9c8b53c57c1a69040194c820c8e219aba00f32bb03b8aa7bf new file mode 100755 index 0000000..510e1c8 Binary files /dev/null and b/storage/textures/ce0eb0c7140836e9c8b53c57c1a69040194c820c8e219aba00f32bb03b8aa7bf differ diff --git a/storage/textures/ce2f0eba68fe9e97ead45fdf22e6b531b84cee77fe97c1e21a8d2bb109b6af9e b/storage/textures/ce2f0eba68fe9e97ead45fdf22e6b531b84cee77fe97c1e21a8d2bb109b6af9e new file mode 100755 index 0000000..124da8f Binary files /dev/null and b/storage/textures/ce2f0eba68fe9e97ead45fdf22e6b531b84cee77fe97c1e21a8d2bb109b6af9e differ diff --git a/storage/textures/cedb837024677db3670677f3c2df2fecb2fe6bd9a107dcc9d6f4ecc2f2702b7e b/storage/textures/cedb837024677db3670677f3c2df2fecb2fe6bd9a107dcc9d6f4ecc2f2702b7e new file mode 100644 index 0000000..59adce2 Binary files /dev/null and b/storage/textures/cedb837024677db3670677f3c2df2fecb2fe6bd9a107dcc9d6f4ecc2f2702b7e differ diff --git a/storage/textures/cee0f6f2b159e17a45e8d1179e8c30bd419fc38f611089a0f2d271b61b56d6c5 b/storage/textures/cee0f6f2b159e17a45e8d1179e8c30bd419fc38f611089a0f2d271b61b56d6c5 new file mode 100755 index 0000000..0b74a43 Binary files /dev/null and b/storage/textures/cee0f6f2b159e17a45e8d1179e8c30bd419fc38f611089a0f2d271b61b56d6c5 differ diff --git a/storage/textures/cf32b7671c6b5a604f60afb213676d120686fc01b45616afcd96f32fcb7169d1 b/storage/textures/cf32b7671c6b5a604f60afb213676d120686fc01b45616afcd96f32fcb7169d1 new file mode 100644 index 0000000..d6a3371 Binary files /dev/null and b/storage/textures/cf32b7671c6b5a604f60afb213676d120686fc01b45616afcd96f32fcb7169d1 differ diff --git a/storage/textures/cf4c906c073c5d8d197ff921ffffabcd37d0015f227ba270a5b3be3c84bd65b6 b/storage/textures/cf4c906c073c5d8d197ff921ffffabcd37d0015f227ba270a5b3be3c84bd65b6 new file mode 100644 index 0000000..5af69d3 Binary files /dev/null and b/storage/textures/cf4c906c073c5d8d197ff921ffffabcd37d0015f227ba270a5b3be3c84bd65b6 differ diff --git a/storage/textures/cf8a1f0626955f7ae9e49fede00c9753113f8cceff8e71d28bbca9ff46e0cdd8 b/storage/textures/cf8a1f0626955f7ae9e49fede00c9753113f8cceff8e71d28bbca9ff46e0cdd8 new file mode 100755 index 0000000..abdd05e Binary files /dev/null and b/storage/textures/cf8a1f0626955f7ae9e49fede00c9753113f8cceff8e71d28bbca9ff46e0cdd8 differ diff --git a/storage/textures/cfa676b0857e02694e6a7f6abfed424e802e3a10d1b3d096e5ef1d9a248faa20 b/storage/textures/cfa676b0857e02694e6a7f6abfed424e802e3a10d1b3d096e5ef1d9a248faa20 new file mode 100755 index 0000000..aa11440 Binary files /dev/null and b/storage/textures/cfa676b0857e02694e6a7f6abfed424e802e3a10d1b3d096e5ef1d9a248faa20 differ diff --git a/storage/textures/cff4cdf21cdd8f704c341ce49147d26a68b1dfbbb2a47eb64dca4a3c118712b6 b/storage/textures/cff4cdf21cdd8f704c341ce49147d26a68b1dfbbb2a47eb64dca4a3c118712b6 new file mode 100755 index 0000000..9307113 Binary files /dev/null and b/storage/textures/cff4cdf21cdd8f704c341ce49147d26a68b1dfbbb2a47eb64dca4a3c118712b6 differ diff --git a/storage/textures/d00b52c7cb84e8e1c9c87dd1cbc50dd38f6184aa406aa915f35f60ea2895926f b/storage/textures/d00b52c7cb84e8e1c9c87dd1cbc50dd38f6184aa406aa915f35f60ea2895926f new file mode 100644 index 0000000..4ddd1ae Binary files /dev/null and b/storage/textures/d00b52c7cb84e8e1c9c87dd1cbc50dd38f6184aa406aa915f35f60ea2895926f differ diff --git a/storage/textures/d0fc71fa57cb7eb7333ab392d3abe0295eb6371992eeb49b09030c2a373a0fd5 b/storage/textures/d0fc71fa57cb7eb7333ab392d3abe0295eb6371992eeb49b09030c2a373a0fd5 new file mode 100644 index 0000000..46109d6 Binary files /dev/null and b/storage/textures/d0fc71fa57cb7eb7333ab392d3abe0295eb6371992eeb49b09030c2a373a0fd5 differ diff --git a/storage/textures/d143cddaac0425fda361eaf91db42d71f4c099c3a10c912570388a33bf918d68 b/storage/textures/d143cddaac0425fda361eaf91db42d71f4c099c3a10c912570388a33bf918d68 new file mode 100755 index 0000000..31bb0e1 Binary files /dev/null and b/storage/textures/d143cddaac0425fda361eaf91db42d71f4c099c3a10c912570388a33bf918d68 differ diff --git a/storage/textures/d1596d33f4b4028c1058894840a8118c2c13a2a48db15f88b8f32a93ac470da2 b/storage/textures/d1596d33f4b4028c1058894840a8118c2c13a2a48db15f88b8f32a93ac470da2 new file mode 100644 index 0000000..b63041b Binary files /dev/null and b/storage/textures/d1596d33f4b4028c1058894840a8118c2c13a2a48db15f88b8f32a93ac470da2 differ diff --git a/storage/textures/d161b9b2b6cb039f15edf8e339905321f07da1141020beb6247347539be69af9 b/storage/textures/d161b9b2b6cb039f15edf8e339905321f07da1141020beb6247347539be69af9 new file mode 100644 index 0000000..571fd6b Binary files /dev/null and b/storage/textures/d161b9b2b6cb039f15edf8e339905321f07da1141020beb6247347539be69af9 differ diff --git a/storage/textures/d1be613ebd383a6917420b17ccad0df3938dbb46c7bc9211f80b7fde08d3ba47 b/storage/textures/d1be613ebd383a6917420b17ccad0df3938dbb46c7bc9211f80b7fde08d3ba47 new file mode 100644 index 0000000..0d665ce Binary files /dev/null and b/storage/textures/d1be613ebd383a6917420b17ccad0df3938dbb46c7bc9211f80b7fde08d3ba47 differ diff --git a/storage/textures/d1d5d83490c5a8245a0193b79bc605735ba98c828ea78d65adeb0a71ab0e5362 b/storage/textures/d1d5d83490c5a8245a0193b79bc605735ba98c828ea78d65adeb0a71ab0e5362 new file mode 100755 index 0000000..f56aafd Binary files /dev/null and b/storage/textures/d1d5d83490c5a8245a0193b79bc605735ba98c828ea78d65adeb0a71ab0e5362 differ diff --git a/storage/textures/d25ff8c2f63e9e924181dc4df81c6c66778a46fdbc093a646b0db2e787921c73 b/storage/textures/d25ff8c2f63e9e924181dc4df81c6c66778a46fdbc093a646b0db2e787921c73 new file mode 100755 index 0000000..57f61db Binary files /dev/null and b/storage/textures/d25ff8c2f63e9e924181dc4df81c6c66778a46fdbc093a646b0db2e787921c73 differ diff --git a/storage/textures/d29cb932c761b1879dbedc1a3d56b8416f42f2b6e2ab21f041fd94aa79fe2f92 b/storage/textures/d29cb932c761b1879dbedc1a3d56b8416f42f2b6e2ab21f041fd94aa79fe2f92 new file mode 100644 index 0000000..4abaa28 Binary files /dev/null and b/storage/textures/d29cb932c761b1879dbedc1a3d56b8416f42f2b6e2ab21f041fd94aa79fe2f92 differ diff --git a/storage/textures/d2abfac2d3b64dfa03f66462266a2971e3a9826cf5abf48f8642c78b512d1e0e b/storage/textures/d2abfac2d3b64dfa03f66462266a2971e3a9826cf5abf48f8642c78b512d1e0e new file mode 100644 index 0000000..095d3b5 Binary files /dev/null and b/storage/textures/d2abfac2d3b64dfa03f66462266a2971e3a9826cf5abf48f8642c78b512d1e0e differ diff --git a/storage/textures/d30ed94c8fee48ed0276e603c288a65299eec191b881c8ff7e2aa89370162c9d b/storage/textures/d30ed94c8fee48ed0276e603c288a65299eec191b881c8ff7e2aa89370162c9d new file mode 100644 index 0000000..9e92953 Binary files /dev/null and b/storage/textures/d30ed94c8fee48ed0276e603c288a65299eec191b881c8ff7e2aa89370162c9d differ diff --git a/storage/textures/d31c76a5c7b315b9e18c9e70559e6806916dd99ee73b2cea635f3915a94d9a79 b/storage/textures/d31c76a5c7b315b9e18c9e70559e6806916dd99ee73b2cea635f3915a94d9a79 new file mode 100755 index 0000000..adc2aba Binary files /dev/null and b/storage/textures/d31c76a5c7b315b9e18c9e70559e6806916dd99ee73b2cea635f3915a94d9a79 differ diff --git a/storage/textures/d3a39e88e9777c71230d65d013af31774da5dd4bde625515d4fe1afa1b4bd550 b/storage/textures/d3a39e88e9777c71230d65d013af31774da5dd4bde625515d4fe1afa1b4bd550 new file mode 100755 index 0000000..e101e24 Binary files /dev/null and b/storage/textures/d3a39e88e9777c71230d65d013af31774da5dd4bde625515d4fe1afa1b4bd550 differ diff --git a/storage/textures/d3c86389b84462791485edf9b9ba97ccd396a34f7efab112ba2d25583fccc3b5 b/storage/textures/d3c86389b84462791485edf9b9ba97ccd396a34f7efab112ba2d25583fccc3b5 new file mode 100755 index 0000000..716e253 Binary files /dev/null and b/storage/textures/d3c86389b84462791485edf9b9ba97ccd396a34f7efab112ba2d25583fccc3b5 differ diff --git a/storage/textures/d4313df5a60b70fcf738ccead16d332a04070a15b78a60f74ba6bd933178094c b/storage/textures/d4313df5a60b70fcf738ccead16d332a04070a15b78a60f74ba6bd933178094c new file mode 100644 index 0000000..8cbff01 Binary files /dev/null and b/storage/textures/d4313df5a60b70fcf738ccead16d332a04070a15b78a60f74ba6bd933178094c differ diff --git a/storage/textures/d43a9c25568477327ed661c387354ff091e20323093b296988a59cea2988f3a3 b/storage/textures/d43a9c25568477327ed661c387354ff091e20323093b296988a59cea2988f3a3 new file mode 100755 index 0000000..636ad30 Binary files /dev/null and b/storage/textures/d43a9c25568477327ed661c387354ff091e20323093b296988a59cea2988f3a3 differ diff --git a/storage/textures/d445d9329971f9a279f8676bb024f373e87d14c37ae272da67f5261002026a53 b/storage/textures/d445d9329971f9a279f8676bb024f373e87d14c37ae272da67f5261002026a53 new file mode 100755 index 0000000..4e745ad Binary files /dev/null and b/storage/textures/d445d9329971f9a279f8676bb024f373e87d14c37ae272da67f5261002026a53 differ diff --git a/storage/textures/d45ea09cb7547ad2e6015a26001692dc0a718328be75455bc8823493406ba3db b/storage/textures/d45ea09cb7547ad2e6015a26001692dc0a718328be75455bc8823493406ba3db new file mode 100755 index 0000000..587608a Binary files /dev/null and b/storage/textures/d45ea09cb7547ad2e6015a26001692dc0a718328be75455bc8823493406ba3db differ diff --git a/storage/textures/d45f9fd6571a47f4c13f6e86d5390abb6a8e195d4967e3fb34c3d7899a6a9775 b/storage/textures/d45f9fd6571a47f4c13f6e86d5390abb6a8e195d4967e3fb34c3d7899a6a9775 new file mode 100755 index 0000000..1df4f27 Binary files /dev/null and b/storage/textures/d45f9fd6571a47f4c13f6e86d5390abb6a8e195d4967e3fb34c3d7899a6a9775 differ diff --git a/storage/textures/d49d03d07c134292fe42c7fa7adcbde4db003b69fd88d0257430815e3828dc02 b/storage/textures/d49d03d07c134292fe42c7fa7adcbde4db003b69fd88d0257430815e3828dc02 new file mode 100755 index 0000000..829e742 Binary files /dev/null and b/storage/textures/d49d03d07c134292fe42c7fa7adcbde4db003b69fd88d0257430815e3828dc02 differ diff --git a/storage/textures/d4d67b670d7a2ab66780baedc4f0f96112e798e4290836930f28fc2b0590ecbb b/storage/textures/d4d67b670d7a2ab66780baedc4f0f96112e798e4290836930f28fc2b0590ecbb new file mode 100755 index 0000000..1b94fb7 Binary files /dev/null and b/storage/textures/d4d67b670d7a2ab66780baedc4f0f96112e798e4290836930f28fc2b0590ecbb differ diff --git a/storage/textures/d55cddb0151a9362d47b1cafc25189346f6c82e0acdc0b7fa74e079e831257f5 b/storage/textures/d55cddb0151a9362d47b1cafc25189346f6c82e0acdc0b7fa74e079e831257f5 new file mode 100755 index 0000000..7aefa19 Binary files /dev/null and b/storage/textures/d55cddb0151a9362d47b1cafc25189346f6c82e0acdc0b7fa74e079e831257f5 differ diff --git a/storage/textures/d606d16160d91988fdd3ef84ddaa8b55b16dca25bf0a9cd204762f303fe398e0 b/storage/textures/d606d16160d91988fdd3ef84ddaa8b55b16dca25bf0a9cd204762f303fe398e0 new file mode 100755 index 0000000..7be2b92 Binary files /dev/null and b/storage/textures/d606d16160d91988fdd3ef84ddaa8b55b16dca25bf0a9cd204762f303fe398e0 differ diff --git a/storage/textures/d63d59f874db1052c6c11f325a844e613b0b8756ec22ec54b3617497500e5f81 b/storage/textures/d63d59f874db1052c6c11f325a844e613b0b8756ec22ec54b3617497500e5f81 new file mode 100755 index 0000000..2a730b3 Binary files /dev/null and b/storage/textures/d63d59f874db1052c6c11f325a844e613b0b8756ec22ec54b3617497500e5f81 differ diff --git a/storage/textures/d64210549713ad4dc611da2cfd0a2aa2862cf2e18cfb9c2887beaea1608205ee b/storage/textures/d64210549713ad4dc611da2cfd0a2aa2862cf2e18cfb9c2887beaea1608205ee new file mode 100755 index 0000000..0d89b45 Binary files /dev/null and b/storage/textures/d64210549713ad4dc611da2cfd0a2aa2862cf2e18cfb9c2887beaea1608205ee differ diff --git a/storage/textures/d6c1d4d869564e487186f5bd79182f40a5fb1c5dee677cdcbc1ac79a730ff49d b/storage/textures/d6c1d4d869564e487186f5bd79182f40a5fb1c5dee677cdcbc1ac79a730ff49d new file mode 100755 index 0000000..13d9cf6 Binary files /dev/null and b/storage/textures/d6c1d4d869564e487186f5bd79182f40a5fb1c5dee677cdcbc1ac79a730ff49d differ diff --git a/storage/textures/d70a952154e2c048b64c7723711cc94dd481ac4da06637727ab54906b1ff22c3 b/storage/textures/d70a952154e2c048b64c7723711cc94dd481ac4da06637727ab54906b1ff22c3 new file mode 100644 index 0000000..91afe4d Binary files /dev/null and b/storage/textures/d70a952154e2c048b64c7723711cc94dd481ac4da06637727ab54906b1ff22c3 differ diff --git a/storage/textures/d76e76a55750b4273eee504d1cfad599699ed8c49116f7d3ea606ff39adc5a34 b/storage/textures/d76e76a55750b4273eee504d1cfad599699ed8c49116f7d3ea606ff39adc5a34 new file mode 100644 index 0000000..e364597 Binary files /dev/null and b/storage/textures/d76e76a55750b4273eee504d1cfad599699ed8c49116f7d3ea606ff39adc5a34 differ diff --git a/storage/textures/d79c37e1e198becc5c2be339466e81b587a238c5c6f45274ca726594b8462063 b/storage/textures/d79c37e1e198becc5c2be339466e81b587a238c5c6f45274ca726594b8462063 new file mode 100644 index 0000000..da4d4b6 Binary files /dev/null and b/storage/textures/d79c37e1e198becc5c2be339466e81b587a238c5c6f45274ca726594b8462063 differ diff --git a/storage/textures/d7b149730e96bf602a5bf7cb227e293a2be764e8836934d62ba0651e61cc1db9 b/storage/textures/d7b149730e96bf602a5bf7cb227e293a2be764e8836934d62ba0651e61cc1db9 new file mode 100755 index 0000000..5f6b1cc Binary files /dev/null and b/storage/textures/d7b149730e96bf602a5bf7cb227e293a2be764e8836934d62ba0651e61cc1db9 differ diff --git a/storage/textures/d7b3baaa610ca2f6f688b2b661d20ab2c69441728bbb35262835b5890f6cf0b3 b/storage/textures/d7b3baaa610ca2f6f688b2b661d20ab2c69441728bbb35262835b5890f6cf0b3 new file mode 100644 index 0000000..0b8f172 Binary files /dev/null and b/storage/textures/d7b3baaa610ca2f6f688b2b661d20ab2c69441728bbb35262835b5890f6cf0b3 differ diff --git a/storage/textures/d7dee00e446a75e2698f7cff9b482b6353bdf6c231f704da4469e3e488954235 b/storage/textures/d7dee00e446a75e2698f7cff9b482b6353bdf6c231f704da4469e3e488954235 new file mode 100644 index 0000000..152a62e Binary files /dev/null and b/storage/textures/d7dee00e446a75e2698f7cff9b482b6353bdf6c231f704da4469e3e488954235 differ diff --git a/storage/textures/d7fc92cd949afa998f9ad8d3e19fa3711c471697d90793f9edf313133b9f6f7a b/storage/textures/d7fc92cd949afa998f9ad8d3e19fa3711c471697d90793f9edf313133b9f6f7a new file mode 100755 index 0000000..fee61f0 Binary files /dev/null and b/storage/textures/d7fc92cd949afa998f9ad8d3e19fa3711c471697d90793f9edf313133b9f6f7a differ diff --git a/storage/textures/d826bb00180fdb39e296c7ab5febf91a208d76b9c7e4c1266e40e7abc789eba4 b/storage/textures/d826bb00180fdb39e296c7ab5febf91a208d76b9c7e4c1266e40e7abc789eba4 new file mode 100644 index 0000000..3b75979 Binary files /dev/null and b/storage/textures/d826bb00180fdb39e296c7ab5febf91a208d76b9c7e4c1266e40e7abc789eba4 differ diff --git a/storage/textures/d83951e12b91bbeb05267b344280e34780821dea9d30f61b311d9c0bd0d9d1fb b/storage/textures/d83951e12b91bbeb05267b344280e34780821dea9d30f61b311d9c0bd0d9d1fb new file mode 100644 index 0000000..c672e90 Binary files /dev/null and b/storage/textures/d83951e12b91bbeb05267b344280e34780821dea9d30f61b311d9c0bd0d9d1fb differ diff --git a/storage/textures/d8655ea51bcc9c2b49bdb859b0cb008fc88d5db479b56c0818540645f02c0812 b/storage/textures/d8655ea51bcc9c2b49bdb859b0cb008fc88d5db479b56c0818540645f02c0812 new file mode 100644 index 0000000..6fdd77b Binary files /dev/null and b/storage/textures/d8655ea51bcc9c2b49bdb859b0cb008fc88d5db479b56c0818540645f02c0812 differ diff --git a/storage/textures/d89759be5d4fd94405404eafaa6bf153b0b58c3edc9894af8ddff1304ad7db2c b/storage/textures/d89759be5d4fd94405404eafaa6bf153b0b58c3edc9894af8ddff1304ad7db2c new file mode 100644 index 0000000..b323657 Binary files /dev/null and b/storage/textures/d89759be5d4fd94405404eafaa6bf153b0b58c3edc9894af8ddff1304ad7db2c differ diff --git a/storage/textures/d8b59bfd887a04bb38a97b6a730b3f65328795998429c2a2db2902b7fc8b6314 b/storage/textures/d8b59bfd887a04bb38a97b6a730b3f65328795998429c2a2db2902b7fc8b6314 new file mode 100755 index 0000000..c2336e0 Binary files /dev/null and b/storage/textures/d8b59bfd887a04bb38a97b6a730b3f65328795998429c2a2db2902b7fc8b6314 differ diff --git a/storage/textures/d8c1d2b72853755971cdc09c5ed801c72ee407d7d6291245147e4f6975f447fb b/storage/textures/d8c1d2b72853755971cdc09c5ed801c72ee407d7d6291245147e4f6975f447fb new file mode 100755 index 0000000..108de6c Binary files /dev/null and b/storage/textures/d8c1d2b72853755971cdc09c5ed801c72ee407d7d6291245147e4f6975f447fb differ diff --git a/storage/textures/d93a699b983f302baa08c79545a903d3294e1fa20743adfda0f70a6fb6c0ef2a b/storage/textures/d93a699b983f302baa08c79545a903d3294e1fa20743adfda0f70a6fb6c0ef2a new file mode 100755 index 0000000..596ad3b Binary files /dev/null and b/storage/textures/d93a699b983f302baa08c79545a903d3294e1fa20743adfda0f70a6fb6c0ef2a differ diff --git a/storage/textures/d9602b7265c4da9a2646e61bed0ca68fa68c8977b2604a5dc7a9d0daf368e55b b/storage/textures/d9602b7265c4da9a2646e61bed0ca68fa68c8977b2604a5dc7a9d0daf368e55b new file mode 100755 index 0000000..5b15364 Binary files /dev/null and b/storage/textures/d9602b7265c4da9a2646e61bed0ca68fa68c8977b2604a5dc7a9d0daf368e55b differ diff --git a/storage/textures/d9b69f657352917efe63690fdf292158fdc06d3ef2f53d2c02efbcddc9f66454 b/storage/textures/d9b69f657352917efe63690fdf292158fdc06d3ef2f53d2c02efbcddc9f66454 new file mode 100644 index 0000000..edaf411 Binary files /dev/null and b/storage/textures/d9b69f657352917efe63690fdf292158fdc06d3ef2f53d2c02efbcddc9f66454 differ diff --git a/storage/textures/d9ca21bf2abf0acc5ed6467710b9a19181119ff290fc4dceb8a2190d87f55f52 b/storage/textures/d9ca21bf2abf0acc5ed6467710b9a19181119ff290fc4dceb8a2190d87f55f52 new file mode 100644 index 0000000..5c65f12 Binary files /dev/null and b/storage/textures/d9ca21bf2abf0acc5ed6467710b9a19181119ff290fc4dceb8a2190d87f55f52 differ diff --git a/storage/textures/da77d239675817f149e0e3b763d171126110a6888e3ee9c5b52aef8cfbb95b14 b/storage/textures/da77d239675817f149e0e3b763d171126110a6888e3ee9c5b52aef8cfbb95b14 new file mode 100755 index 0000000..19f047d Binary files /dev/null and b/storage/textures/da77d239675817f149e0e3b763d171126110a6888e3ee9c5b52aef8cfbb95b14 differ diff --git a/storage/textures/dab37b22052571ca7b76a80f89f9f639d2f1af7938d6b5c80bdea940079d422b b/storage/textures/dab37b22052571ca7b76a80f89f9f639d2f1af7938d6b5c80bdea940079d422b new file mode 100755 index 0000000..e5b40d0 Binary files /dev/null and b/storage/textures/dab37b22052571ca7b76a80f89f9f639d2f1af7938d6b5c80bdea940079d422b differ diff --git a/storage/textures/dab4e798cfe3abb58761b16cb294f26c7101e110dedbed464940cc9af14c79d0 b/storage/textures/dab4e798cfe3abb58761b16cb294f26c7101e110dedbed464940cc9af14c79d0 new file mode 100755 index 0000000..1dd5944 Binary files /dev/null and b/storage/textures/dab4e798cfe3abb58761b16cb294f26c7101e110dedbed464940cc9af14c79d0 differ diff --git a/storage/textures/db02d36866efb2f8ffd90f1740636dda280f38aaf1a9520bd4ecc435c0e0c950 b/storage/textures/db02d36866efb2f8ffd90f1740636dda280f38aaf1a9520bd4ecc435c0e0c950 new file mode 100755 index 0000000..46c521f Binary files /dev/null and b/storage/textures/db02d36866efb2f8ffd90f1740636dda280f38aaf1a9520bd4ecc435c0e0c950 differ diff --git a/storage/textures/db1a71dbf2c725e92793c40fdea6b8476fb6926c9991ab8e1878861b68b55f4e b/storage/textures/db1a71dbf2c725e92793c40fdea6b8476fb6926c9991ab8e1878861b68b55f4e new file mode 100755 index 0000000..8cc8cb8 Binary files /dev/null and b/storage/textures/db1a71dbf2c725e92793c40fdea6b8476fb6926c9991ab8e1878861b68b55f4e differ diff --git a/storage/textures/db2bdd9110a3b2e4035402312160a145e602b40779aae5c1c3c9b6cac5d3666a b/storage/textures/db2bdd9110a3b2e4035402312160a145e602b40779aae5c1c3c9b6cac5d3666a new file mode 100755 index 0000000..984a37d Binary files /dev/null and b/storage/textures/db2bdd9110a3b2e4035402312160a145e602b40779aae5c1c3c9b6cac5d3666a differ diff --git a/storage/textures/db36376d2a12e06df28b9783450fb279e60ed7f641e463a1b8a8fd9254d78ad9 b/storage/textures/db36376d2a12e06df28b9783450fb279e60ed7f641e463a1b8a8fd9254d78ad9 new file mode 100644 index 0000000..512267b Binary files /dev/null and b/storage/textures/db36376d2a12e06df28b9783450fb279e60ed7f641e463a1b8a8fd9254d78ad9 differ diff --git a/storage/textures/db45f51cf4a1aa20fb39d011c044f0b7ef8f1c27b1c24a478be855baa1bc4087 b/storage/textures/db45f51cf4a1aa20fb39d011c044f0b7ef8f1c27b1c24a478be855baa1bc4087 new file mode 100755 index 0000000..b947756 Binary files /dev/null and b/storage/textures/db45f51cf4a1aa20fb39d011c044f0b7ef8f1c27b1c24a478be855baa1bc4087 differ diff --git a/storage/textures/db6d9894314822f894305048b6076d933d7dc0785a247c99d43b4e86a3ccfcab b/storage/textures/db6d9894314822f894305048b6076d933d7dc0785a247c99d43b4e86a3ccfcab new file mode 100755 index 0000000..e528ae7 Binary files /dev/null and b/storage/textures/db6d9894314822f894305048b6076d933d7dc0785a247c99d43b4e86a3ccfcab differ diff --git a/storage/textures/db76f3c162e48f5d0d765bc93b29a8eb112d87985280b82e68a7454524687d25 b/storage/textures/db76f3c162e48f5d0d765bc93b29a8eb112d87985280b82e68a7454524687d25 new file mode 100755 index 0000000..339850e Binary files /dev/null and b/storage/textures/db76f3c162e48f5d0d765bc93b29a8eb112d87985280b82e68a7454524687d25 differ diff --git a/storage/textures/dba95e647e09af3cee41a3fbbf7bc458e45767cd33dc92ca336f54cd1d88560a b/storage/textures/dba95e647e09af3cee41a3fbbf7bc458e45767cd33dc92ca336f54cd1d88560a new file mode 100755 index 0000000..9c1c627 Binary files /dev/null and b/storage/textures/dba95e647e09af3cee41a3fbbf7bc458e45767cd33dc92ca336f54cd1d88560a differ diff --git a/storage/textures/dc0e48ebd7ee3414c3ccd9f9a39c700d23b8a3395dbd94a735778dedaf0f13f9 b/storage/textures/dc0e48ebd7ee3414c3ccd9f9a39c700d23b8a3395dbd94a735778dedaf0f13f9 new file mode 100755 index 0000000..ea5cf45 Binary files /dev/null and b/storage/textures/dc0e48ebd7ee3414c3ccd9f9a39c700d23b8a3395dbd94a735778dedaf0f13f9 differ diff --git a/storage/textures/dc4f059524c1ba33396106c5f38fc79b608983f44473bd5b661566baef888d61 b/storage/textures/dc4f059524c1ba33396106c5f38fc79b608983f44473bd5b661566baef888d61 new file mode 100755 index 0000000..7a6957f Binary files /dev/null and b/storage/textures/dc4f059524c1ba33396106c5f38fc79b608983f44473bd5b661566baef888d61 differ diff --git a/storage/textures/dc96cca835dfd70b196fb78a1c72daa1e912871e17c128c126c95b2f9623a5dd b/storage/textures/dc96cca835dfd70b196fb78a1c72daa1e912871e17c128c126c95b2f9623a5dd new file mode 100755 index 0000000..655c17d Binary files /dev/null and b/storage/textures/dc96cca835dfd70b196fb78a1c72daa1e912871e17c128c126c95b2f9623a5dd differ diff --git a/storage/textures/dc9dc11ac019bccfd1a206f2f26f2a979d08710cfe4c26327ca4301657602e7a b/storage/textures/dc9dc11ac019bccfd1a206f2f26f2a979d08710cfe4c26327ca4301657602e7a new file mode 100755 index 0000000..9331fba Binary files /dev/null and b/storage/textures/dc9dc11ac019bccfd1a206f2f26f2a979d08710cfe4c26327ca4301657602e7a differ diff --git a/storage/textures/dd2b58aa845e252941b7f5b925d7a6566a4ab4e809d23cbb81535a4ccb4a1dd3 b/storage/textures/dd2b58aa845e252941b7f5b925d7a6566a4ab4e809d23cbb81535a4ccb4a1dd3 new file mode 100755 index 0000000..ad5fe8e Binary files /dev/null and b/storage/textures/dd2b58aa845e252941b7f5b925d7a6566a4ab4e809d23cbb81535a4ccb4a1dd3 differ diff --git a/storage/textures/dd37a89ddea770b33ee1562592e17f46719974d5f17581c48184611915dc2598 b/storage/textures/dd37a89ddea770b33ee1562592e17f46719974d5f17581c48184611915dc2598 new file mode 100644 index 0000000..d6820f0 Binary files /dev/null and b/storage/textures/dd37a89ddea770b33ee1562592e17f46719974d5f17581c48184611915dc2598 differ diff --git a/storage/textures/dda3a1c53ab8f74d1911fa8293b2c3d212c24d00a4b27b27d8c9a39e191383f4 b/storage/textures/dda3a1c53ab8f74d1911fa8293b2c3d212c24d00a4b27b27d8c9a39e191383f4 new file mode 100755 index 0000000..fbe61ce Binary files /dev/null and b/storage/textures/dda3a1c53ab8f74d1911fa8293b2c3d212c24d00a4b27b27d8c9a39e191383f4 differ diff --git a/storage/textures/de76d46658b1529a8aaec5333bc0ddaabeef41b054f13f79753440844c47cae1 b/storage/textures/de76d46658b1529a8aaec5333bc0ddaabeef41b054f13f79753440844c47cae1 new file mode 100755 index 0000000..b4f38cf Binary files /dev/null and b/storage/textures/de76d46658b1529a8aaec5333bc0ddaabeef41b054f13f79753440844c47cae1 differ diff --git a/storage/textures/deaf65bdc53687d0b8dfb0bcb95cbbeb058e8e2820629b1917effd3558cd6f5a b/storage/textures/deaf65bdc53687d0b8dfb0bcb95cbbeb058e8e2820629b1917effd3558cd6f5a new file mode 100755 index 0000000..7e451a8 Binary files /dev/null and b/storage/textures/deaf65bdc53687d0b8dfb0bcb95cbbeb058e8e2820629b1917effd3558cd6f5a differ diff --git a/storage/textures/dee9f26f9c208aaf7dfe3131a0c82e8caaf190e36e8accf9c7bb23914702118b b/storage/textures/dee9f26f9c208aaf7dfe3131a0c82e8caaf190e36e8accf9c7bb23914702118b new file mode 100755 index 0000000..a6eb09f Binary files /dev/null and b/storage/textures/dee9f26f9c208aaf7dfe3131a0c82e8caaf190e36e8accf9c7bb23914702118b differ diff --git a/storage/textures/def145c78ae7414c099c46735ba8f5136832fda25800a9500c295b34da0b207d b/storage/textures/def145c78ae7414c099c46735ba8f5136832fda25800a9500c295b34da0b207d new file mode 100755 index 0000000..e35f6d8 Binary files /dev/null and b/storage/textures/def145c78ae7414c099c46735ba8f5136832fda25800a9500c295b34da0b207d differ diff --git a/storage/textures/df78fd0329c746cb0324e74e27db5f1b76a2a2670bd4b6f4f0a504400924039f b/storage/textures/df78fd0329c746cb0324e74e27db5f1b76a2a2670bd4b6f4f0a504400924039f new file mode 100755 index 0000000..99620a3 Binary files /dev/null and b/storage/textures/df78fd0329c746cb0324e74e27db5f1b76a2a2670bd4b6f4f0a504400924039f differ diff --git a/storage/textures/df830fba50a350ab9dc3075892024baab5d5de4eef7e9b490b81f804685dd937 b/storage/textures/df830fba50a350ab9dc3075892024baab5d5de4eef7e9b490b81f804685dd937 new file mode 100755 index 0000000..90a82c8 Binary files /dev/null and b/storage/textures/df830fba50a350ab9dc3075892024baab5d5de4eef7e9b490b81f804685dd937 differ diff --git a/storage/textures/df9a22a61fb1893e42194458d98f794534a486b8bd0e5787f1b64e076e5c3fb7 b/storage/textures/df9a22a61fb1893e42194458d98f794534a486b8bd0e5787f1b64e076e5c3fb7 new file mode 100755 index 0000000..7d289fa Binary files /dev/null and b/storage/textures/df9a22a61fb1893e42194458d98f794534a486b8bd0e5787f1b64e076e5c3fb7 differ diff --git a/storage/textures/e048454e369829937cf3af2ae123047accdef5ff774f09267bed66a60d7048f9 b/storage/textures/e048454e369829937cf3af2ae123047accdef5ff774f09267bed66a60d7048f9 new file mode 100755 index 0000000..2c88a3b Binary files /dev/null and b/storage/textures/e048454e369829937cf3af2ae123047accdef5ff774f09267bed66a60d7048f9 differ diff --git a/storage/textures/e07b37256e0cb51d3d5356ec8049b4e06c5ee6f027b5fab55852bbb6181c79dc b/storage/textures/e07b37256e0cb51d3d5356ec8049b4e06c5ee6f027b5fab55852bbb6181c79dc new file mode 100644 index 0000000..f3126ad Binary files /dev/null and b/storage/textures/e07b37256e0cb51d3d5356ec8049b4e06c5ee6f027b5fab55852bbb6181c79dc differ diff --git a/storage/textures/e0c6b44976d79f3d7c67d14b23d190944bcc94fd8be1703f530b1dbcc2f2176c b/storage/textures/e0c6b44976d79f3d7c67d14b23d190944bcc94fd8be1703f530b1dbcc2f2176c new file mode 100755 index 0000000..8124775 Binary files /dev/null and b/storage/textures/e0c6b44976d79f3d7c67d14b23d190944bcc94fd8be1703f530b1dbcc2f2176c differ diff --git a/storage/textures/e0e7c7a4143d0894d9b73d8e4d9b0b40a074978b9e22aedeef38d789b2905c63 b/storage/textures/e0e7c7a4143d0894d9b73d8e4d9b0b40a074978b9e22aedeef38d789b2905c63 new file mode 100644 index 0000000..ab06af9 Binary files /dev/null and b/storage/textures/e0e7c7a4143d0894d9b73d8e4d9b0b40a074978b9e22aedeef38d789b2905c63 differ diff --git a/storage/textures/e0fc8bde598907540732001cdee4f3395261614d4672ad604565e487b07f25b0 b/storage/textures/e0fc8bde598907540732001cdee4f3395261614d4672ad604565e487b07f25b0 new file mode 100755 index 0000000..c43009c Binary files /dev/null and b/storage/textures/e0fc8bde598907540732001cdee4f3395261614d4672ad604565e487b07f25b0 differ diff --git a/storage/textures/e11f87f9a544567356275d7eb4857c29561325add9a4d481bd5feb61cc6f01cf b/storage/textures/e11f87f9a544567356275d7eb4857c29561325add9a4d481bd5feb61cc6f01cf new file mode 100755 index 0000000..2e5111b Binary files /dev/null and b/storage/textures/e11f87f9a544567356275d7eb4857c29561325add9a4d481bd5feb61cc6f01cf differ diff --git a/storage/textures/e12586a68cb8950b503fe7a64f1e16d26abeab9235a77f477a78f89cc6caa80f b/storage/textures/e12586a68cb8950b503fe7a64f1e16d26abeab9235a77f477a78f89cc6caa80f new file mode 100755 index 0000000..7e1c69f Binary files /dev/null and b/storage/textures/e12586a68cb8950b503fe7a64f1e16d26abeab9235a77f477a78f89cc6caa80f differ diff --git a/storage/textures/e163710695374faf28efcddda929246c7f710170abfc6c6261be24ae5ed673cb b/storage/textures/e163710695374faf28efcddda929246c7f710170abfc6c6261be24ae5ed673cb new file mode 100644 index 0000000..0661904 Binary files /dev/null and b/storage/textures/e163710695374faf28efcddda929246c7f710170abfc6c6261be24ae5ed673cb differ diff --git a/storage/textures/e198def08bf1f696998e97ec9b9a27a3358e08c21094e2ff4759170c9a0570e2 b/storage/textures/e198def08bf1f696998e97ec9b9a27a3358e08c21094e2ff4759170c9a0570e2 new file mode 100644 index 0000000..d037925 Binary files /dev/null and b/storage/textures/e198def08bf1f696998e97ec9b9a27a3358e08c21094e2ff4759170c9a0570e2 differ diff --git a/storage/textures/e2553e33873c5cb1ed568f6fe4ea1b2bc5d0523b9c12ef3c5714dd78c8b51ea5 b/storage/textures/e2553e33873c5cb1ed568f6fe4ea1b2bc5d0523b9c12ef3c5714dd78c8b51ea5 new file mode 100755 index 0000000..1095daa Binary files /dev/null and b/storage/textures/e2553e33873c5cb1ed568f6fe4ea1b2bc5d0523b9c12ef3c5714dd78c8b51ea5 differ diff --git a/storage/textures/e28b62621b258e7c955435d7c837d57a61c93e4dee80642aab6f990d63eac892 b/storage/textures/e28b62621b258e7c955435d7c837d57a61c93e4dee80642aab6f990d63eac892 new file mode 100755 index 0000000..8403755 Binary files /dev/null and b/storage/textures/e28b62621b258e7c955435d7c837d57a61c93e4dee80642aab6f990d63eac892 differ diff --git a/storage/textures/e2d19c0e4c8a6b06afd4b67b0f4b2b90c5cfb7f49fdae052c41d5db30db76eb1 b/storage/textures/e2d19c0e4c8a6b06afd4b67b0f4b2b90c5cfb7f49fdae052c41d5db30db76eb1 new file mode 100644 index 0000000..546ee52 Binary files /dev/null and b/storage/textures/e2d19c0e4c8a6b06afd4b67b0f4b2b90c5cfb7f49fdae052c41d5db30db76eb1 differ diff --git a/storage/textures/e2ea145565a17f4c12a83f95ee04cae201bcd76c06aa5180c702fa4413c18f0c b/storage/textures/e2ea145565a17f4c12a83f95ee04cae201bcd76c06aa5180c702fa4413c18f0c new file mode 100755 index 0000000..88fe4fd Binary files /dev/null and b/storage/textures/e2ea145565a17f4c12a83f95ee04cae201bcd76c06aa5180c702fa4413c18f0c differ diff --git a/storage/textures/e2f2aac9c7206965d0038ecf319ee821b0b50a52cc1a309e13904ec530ce39c2 b/storage/textures/e2f2aac9c7206965d0038ecf319ee821b0b50a52cc1a309e13904ec530ce39c2 new file mode 100755 index 0000000..d8ad4ad Binary files /dev/null and b/storage/textures/e2f2aac9c7206965d0038ecf319ee821b0b50a52cc1a309e13904ec530ce39c2 differ diff --git a/storage/textures/e301b89917e583bb178a85a02bbbe3f45354a0bce76859f3af686d07db72b6c9 b/storage/textures/e301b89917e583bb178a85a02bbbe3f45354a0bce76859f3af686d07db72b6c9 new file mode 100644 index 0000000..220075c Binary files /dev/null and b/storage/textures/e301b89917e583bb178a85a02bbbe3f45354a0bce76859f3af686d07db72b6c9 differ diff --git a/storage/textures/e30e4ab749b10116a0af9198223ad1c0489c072471282250d15fc9b0be5577f7 b/storage/textures/e30e4ab749b10116a0af9198223ad1c0489c072471282250d15fc9b0be5577f7 new file mode 100755 index 0000000..a3e42da Binary files /dev/null and b/storage/textures/e30e4ab749b10116a0af9198223ad1c0489c072471282250d15fc9b0be5577f7 differ diff --git a/storage/textures/e31014e3a2c74a3ac5d2f8e9681681af0b0c5ac3a3d4d00b3dc96c64c5fde772 b/storage/textures/e31014e3a2c74a3ac5d2f8e9681681af0b0c5ac3a3d4d00b3dc96c64c5fde772 new file mode 100755 index 0000000..ef171cc Binary files /dev/null and b/storage/textures/e31014e3a2c74a3ac5d2f8e9681681af0b0c5ac3a3d4d00b3dc96c64c5fde772 differ diff --git a/storage/textures/e33f240cbeeb6d165d3a1182848a3d07859fe650734e7a568ef09a36fffe0efc b/storage/textures/e33f240cbeeb6d165d3a1182848a3d07859fe650734e7a568ef09a36fffe0efc new file mode 100755 index 0000000..370d84c Binary files /dev/null and b/storage/textures/e33f240cbeeb6d165d3a1182848a3d07859fe650734e7a568ef09a36fffe0efc differ diff --git a/storage/textures/e36b3787977c7e5c939668735f3f50831a2ffe2efd96bd096bf1712dca897af8 b/storage/textures/e36b3787977c7e5c939668735f3f50831a2ffe2efd96bd096bf1712dca897af8 new file mode 100755 index 0000000..41805d2 Binary files /dev/null and b/storage/textures/e36b3787977c7e5c939668735f3f50831a2ffe2efd96bd096bf1712dca897af8 differ diff --git a/storage/textures/e3cce4e63343b43fb17035d11c6e714b0ac9393c3afd52d5d9a29c6a7101241c b/storage/textures/e3cce4e63343b43fb17035d11c6e714b0ac9393c3afd52d5d9a29c6a7101241c new file mode 100644 index 0000000..d059f00 Binary files /dev/null and b/storage/textures/e3cce4e63343b43fb17035d11c6e714b0ac9393c3afd52d5d9a29c6a7101241c differ diff --git a/storage/textures/e44bb0d505468cd894900b00beffee8acf079d11e30d221784baa9f6776d5100 b/storage/textures/e44bb0d505468cd894900b00beffee8acf079d11e30d221784baa9f6776d5100 new file mode 100755 index 0000000..6c46bde Binary files /dev/null and b/storage/textures/e44bb0d505468cd894900b00beffee8acf079d11e30d221784baa9f6776d5100 differ diff --git a/storage/textures/e45f81c7c824e5eff95ed6a447fe73bcfa1612a6b74cdbe30126d9590221797a b/storage/textures/e45f81c7c824e5eff95ed6a447fe73bcfa1612a6b74cdbe30126d9590221797a new file mode 100755 index 0000000..9d77564 Binary files /dev/null and b/storage/textures/e45f81c7c824e5eff95ed6a447fe73bcfa1612a6b74cdbe30126d9590221797a differ diff --git a/storage/textures/e4a43a0b1da8ede04365a5095da7d86db1358f938cfeed6cf613bd0893bf2838 b/storage/textures/e4a43a0b1da8ede04365a5095da7d86db1358f938cfeed6cf613bd0893bf2838 new file mode 100755 index 0000000..75a2302 Binary files /dev/null and b/storage/textures/e4a43a0b1da8ede04365a5095da7d86db1358f938cfeed6cf613bd0893bf2838 differ diff --git a/storage/textures/e4a486240df62fe1578a96fbef62a138c38d3c30546d150063bbe619a1e6f8c5 b/storage/textures/e4a486240df62fe1578a96fbef62a138c38d3c30546d150063bbe619a1e6f8c5 new file mode 100644 index 0000000..5e0ca0b Binary files /dev/null and b/storage/textures/e4a486240df62fe1578a96fbef62a138c38d3c30546d150063bbe619a1e6f8c5 differ diff --git a/storage/textures/e4b3cb6bfb304f9357d187f53b8b94896dd5fd4c31d361bc845568dfae22953f b/storage/textures/e4b3cb6bfb304f9357d187f53b8b94896dd5fd4c31d361bc845568dfae22953f new file mode 100755 index 0000000..15dfde0 Binary files /dev/null and b/storage/textures/e4b3cb6bfb304f9357d187f53b8b94896dd5fd4c31d361bc845568dfae22953f differ diff --git a/storage/textures/e51cefb895af893e59b94784245b9f8ab4e9bffee3731a929dc1fa21c65d7146 b/storage/textures/e51cefb895af893e59b94784245b9f8ab4e9bffee3731a929dc1fa21c65d7146 new file mode 100755 index 0000000..c817706 Binary files /dev/null and b/storage/textures/e51cefb895af893e59b94784245b9f8ab4e9bffee3731a929dc1fa21c65d7146 differ diff --git a/storage/textures/e55fc9446200d241b2666eae711a245c1254b2e9084ac2b0bd0401939ac56a55 b/storage/textures/e55fc9446200d241b2666eae711a245c1254b2e9084ac2b0bd0401939ac56a55 new file mode 100644 index 0000000..deae0ff Binary files /dev/null and b/storage/textures/e55fc9446200d241b2666eae711a245c1254b2e9084ac2b0bd0401939ac56a55 differ diff --git a/storage/textures/e5a74988b27a6ca5eafc4624cbd028d642dfa374aa69e101e14f68b016c97358 b/storage/textures/e5a74988b27a6ca5eafc4624cbd028d642dfa374aa69e101e14f68b016c97358 new file mode 100755 index 0000000..20890f4 Binary files /dev/null and b/storage/textures/e5a74988b27a6ca5eafc4624cbd028d642dfa374aa69e101e14f68b016c97358 differ diff --git a/storage/textures/e5aa295e03563b8a61d1d7aa78e8f31795171b9cdebb55a84e904c3bb0d535f1 b/storage/textures/e5aa295e03563b8a61d1d7aa78e8f31795171b9cdebb55a84e904c3bb0d535f1 new file mode 100755 index 0000000..6a990b1 Binary files /dev/null and b/storage/textures/e5aa295e03563b8a61d1d7aa78e8f31795171b9cdebb55a84e904c3bb0d535f1 differ diff --git a/storage/textures/e5b3417aed829faf2fecfd65afa1b1cbab2afb8bb628cf6ee654f53759b6b8f4 b/storage/textures/e5b3417aed829faf2fecfd65afa1b1cbab2afb8bb628cf6ee654f53759b6b8f4 new file mode 100755 index 0000000..f72175c Binary files /dev/null and b/storage/textures/e5b3417aed829faf2fecfd65afa1b1cbab2afb8bb628cf6ee654f53759b6b8f4 differ diff --git a/storage/textures/e5b613a1385d83f1669e9e934121d86b89990b7aa83a7dd2f2ace1bfd4679ade b/storage/textures/e5b613a1385d83f1669e9e934121d86b89990b7aa83a7dd2f2ace1bfd4679ade new file mode 100755 index 0000000..77df69e Binary files /dev/null and b/storage/textures/e5b613a1385d83f1669e9e934121d86b89990b7aa83a7dd2f2ace1bfd4679ade differ diff --git a/storage/textures/e66bfa84e3b56376178705b4b0d3b57d5f282b8366da95d89cf396df336b60fa b/storage/textures/e66bfa84e3b56376178705b4b0d3b57d5f282b8366da95d89cf396df336b60fa new file mode 100755 index 0000000..986bbae Binary files /dev/null and b/storage/textures/e66bfa84e3b56376178705b4b0d3b57d5f282b8366da95d89cf396df336b60fa differ diff --git a/storage/textures/e6c263c84e91a38b5d60ecdc5f96d30135cfe1e4fc791ea1c1c16884e78234a1 b/storage/textures/e6c263c84e91a38b5d60ecdc5f96d30135cfe1e4fc791ea1c1c16884e78234a1 new file mode 100755 index 0000000..23e089a Binary files /dev/null and b/storage/textures/e6c263c84e91a38b5d60ecdc5f96d30135cfe1e4fc791ea1c1c16884e78234a1 differ diff --git a/storage/textures/e6dca09e4c03abe4ef5b0d24be5c000f899f3311f994583012ee90473782b31c b/storage/textures/e6dca09e4c03abe4ef5b0d24be5c000f899f3311f994583012ee90473782b31c new file mode 100755 index 0000000..e0558b8 Binary files /dev/null and b/storage/textures/e6dca09e4c03abe4ef5b0d24be5c000f899f3311f994583012ee90473782b31c differ diff --git a/storage/textures/e7108bfb1113429ae87676949ffc3bd6475141325711faea4e71cc7f5561c247 b/storage/textures/e7108bfb1113429ae87676949ffc3bd6475141325711faea4e71cc7f5561c247 new file mode 100755 index 0000000..497053a Binary files /dev/null and b/storage/textures/e7108bfb1113429ae87676949ffc3bd6475141325711faea4e71cc7f5561c247 differ diff --git a/storage/textures/e711dc34930967cd6008b786836a6550333a0836199da5be2f4f1056fb698d70 b/storage/textures/e711dc34930967cd6008b786836a6550333a0836199da5be2f4f1056fb698d70 new file mode 100755 index 0000000..701381b Binary files /dev/null and b/storage/textures/e711dc34930967cd6008b786836a6550333a0836199da5be2f4f1056fb698d70 differ diff --git a/storage/textures/e7a383b03d62eb5b7bf56833d9b140f76c36057ce742717b0f5fbf1d6212ca9c b/storage/textures/e7a383b03d62eb5b7bf56833d9b140f76c36057ce742717b0f5fbf1d6212ca9c new file mode 100644 index 0000000..785c7d2 Binary files /dev/null and b/storage/textures/e7a383b03d62eb5b7bf56833d9b140f76c36057ce742717b0f5fbf1d6212ca9c differ diff --git a/storage/textures/e7c684b54c7e649f6c03313cca08c75a101ce28243dd4fd6003dcf79864420fd b/storage/textures/e7c684b54c7e649f6c03313cca08c75a101ce28243dd4fd6003dcf79864420fd new file mode 100644 index 0000000..2e2fbd4 Binary files /dev/null and b/storage/textures/e7c684b54c7e649f6c03313cca08c75a101ce28243dd4fd6003dcf79864420fd differ diff --git a/storage/textures/e7cc5a402a4f81f726e921c249305f491c6f359ba17323d5eb87104f9f3d49ec b/storage/textures/e7cc5a402a4f81f726e921c249305f491c6f359ba17323d5eb87104f9f3d49ec new file mode 100644 index 0000000..53572ee Binary files /dev/null and b/storage/textures/e7cc5a402a4f81f726e921c249305f491c6f359ba17323d5eb87104f9f3d49ec differ diff --git a/storage/textures/e7f1e8dbb4b2e394b422f9af0e4402bbca4f2c9143e7b0a6e7bfff65c72ce2e2 b/storage/textures/e7f1e8dbb4b2e394b422f9af0e4402bbca4f2c9143e7b0a6e7bfff65c72ce2e2 new file mode 100755 index 0000000..d7ba5bb Binary files /dev/null and b/storage/textures/e7f1e8dbb4b2e394b422f9af0e4402bbca4f2c9143e7b0a6e7bfff65c72ce2e2 differ diff --git a/storage/textures/e83a5d1fde510a177ffa011982d915b5b9568c51e3ba4c494aad3b871c64031c b/storage/textures/e83a5d1fde510a177ffa011982d915b5b9568c51e3ba4c494aad3b871c64031c new file mode 100755 index 0000000..b91430a Binary files /dev/null and b/storage/textures/e83a5d1fde510a177ffa011982d915b5b9568c51e3ba4c494aad3b871c64031c differ diff --git a/storage/textures/e8576ff85f56347c77393ff82330c0d39fc4d653705f651b45266c477853aa23 b/storage/textures/e8576ff85f56347c77393ff82330c0d39fc4d653705f651b45266c477853aa23 new file mode 100644 index 0000000..8c9af2d Binary files /dev/null and b/storage/textures/e8576ff85f56347c77393ff82330c0d39fc4d653705f651b45266c477853aa23 differ diff --git a/storage/textures/e88aa3dc1c42f70a2e4314c1c74c978ec0f001299a9839b305f9ab0f4c4bf183 b/storage/textures/e88aa3dc1c42f70a2e4314c1c74c978ec0f001299a9839b305f9ab0f4c4bf183 new file mode 100755 index 0000000..ba99ea8 Binary files /dev/null and b/storage/textures/e88aa3dc1c42f70a2e4314c1c74c978ec0f001299a9839b305f9ab0f4c4bf183 differ diff --git a/storage/textures/e8b6b51be61ff9a76bfd8aec89adf950f3bd9e6bc464b0158b0ee46d2dbf4c1a b/storage/textures/e8b6b51be61ff9a76bfd8aec89adf950f3bd9e6bc464b0158b0ee46d2dbf4c1a new file mode 100755 index 0000000..b5d0ecc Binary files /dev/null and b/storage/textures/e8b6b51be61ff9a76bfd8aec89adf950f3bd9e6bc464b0158b0ee46d2dbf4c1a differ diff --git a/storage/textures/e90753fc8324fa1e1b94f3b7d2c4a66f76b8837f29d83a838db775b30f792152 b/storage/textures/e90753fc8324fa1e1b94f3b7d2c4a66f76b8837f29d83a838db775b30f792152 new file mode 100755 index 0000000..5b65105 Binary files /dev/null and b/storage/textures/e90753fc8324fa1e1b94f3b7d2c4a66f76b8837f29d83a838db775b30f792152 differ diff --git a/storage/textures/e93aa3729fb4253d7ebff2bbf0e11ad82eee549e575944482e92dba0ad7e4fb7 b/storage/textures/e93aa3729fb4253d7ebff2bbf0e11ad82eee549e575944482e92dba0ad7e4fb7 new file mode 100755 index 0000000..e33fdc4 Binary files /dev/null and b/storage/textures/e93aa3729fb4253d7ebff2bbf0e11ad82eee549e575944482e92dba0ad7e4fb7 differ diff --git a/storage/textures/e984fa7c6ed7f0fd9186f34d3019b729cd39f46869eb90c050d5a54210e5c237 b/storage/textures/e984fa7c6ed7f0fd9186f34d3019b729cd39f46869eb90c050d5a54210e5c237 new file mode 100755 index 0000000..d976c49 Binary files /dev/null and b/storage/textures/e984fa7c6ed7f0fd9186f34d3019b729cd39f46869eb90c050d5a54210e5c237 differ diff --git a/storage/textures/e98f30857e2f3b79654e86ddc40d236d1a9fb9bdc0ef8cf727869df22f644fdf b/storage/textures/e98f30857e2f3b79654e86ddc40d236d1a9fb9bdc0ef8cf727869df22f644fdf new file mode 100755 index 0000000..9b7d7ec Binary files /dev/null and b/storage/textures/e98f30857e2f3b79654e86ddc40d236d1a9fb9bdc0ef8cf727869df22f644fdf differ diff --git a/storage/textures/e9c9ddaf681d557cf7383e01f41236a09262fad83e426f0365944596a9e5a638 b/storage/textures/e9c9ddaf681d557cf7383e01f41236a09262fad83e426f0365944596a9e5a638 new file mode 100755 index 0000000..2cd0291 Binary files /dev/null and b/storage/textures/e9c9ddaf681d557cf7383e01f41236a09262fad83e426f0365944596a9e5a638 differ diff --git a/storage/textures/e9e0d9410d399134ef105c2fae6628b932c461f1ea544df01ff0becdf4a9a50a b/storage/textures/e9e0d9410d399134ef105c2fae6628b932c461f1ea544df01ff0becdf4a9a50a new file mode 100755 index 0000000..68e1f0b Binary files /dev/null and b/storage/textures/e9e0d9410d399134ef105c2fae6628b932c461f1ea544df01ff0becdf4a9a50a differ diff --git a/storage/textures/e9e56c80b2e8caabeb597d3c21b45f55c753d6565d95f7811165d5d3a7dbb7cf b/storage/textures/e9e56c80b2e8caabeb597d3c21b45f55c753d6565d95f7811165d5d3a7dbb7cf new file mode 100755 index 0000000..6f619a1 Binary files /dev/null and b/storage/textures/e9e56c80b2e8caabeb597d3c21b45f55c753d6565d95f7811165d5d3a7dbb7cf differ diff --git a/storage/textures/e9f0fe8ecd472c163ef2e5056d7d0f07b67074d6b7bed511904912ec2192adcd b/storage/textures/e9f0fe8ecd472c163ef2e5056d7d0f07b67074d6b7bed511904912ec2192adcd new file mode 100755 index 0000000..5c87d7a Binary files /dev/null and b/storage/textures/e9f0fe8ecd472c163ef2e5056d7d0f07b67074d6b7bed511904912ec2192adcd differ diff --git a/storage/textures/ea4f2250504e658a480cb48eb5c5dc69d28b612b70839cc01d45039c882f981c b/storage/textures/ea4f2250504e658a480cb48eb5c5dc69d28b612b70839cc01d45039c882f981c new file mode 100755 index 0000000..ed2612d Binary files /dev/null and b/storage/textures/ea4f2250504e658a480cb48eb5c5dc69d28b612b70839cc01d45039c882f981c differ diff --git a/storage/textures/ea56f0456fedebc52a616687d3ab6ba3c458ce36916a3c5d622b1790588f7219 b/storage/textures/ea56f0456fedebc52a616687d3ab6ba3c458ce36916a3c5d622b1790588f7219 new file mode 100755 index 0000000..8f03c92 Binary files /dev/null and b/storage/textures/ea56f0456fedebc52a616687d3ab6ba3c458ce36916a3c5d622b1790588f7219 differ diff --git a/storage/textures/eadeb22ee619af1023073c13575cdf82b17c841595df4d02a2eb746a048ca701 b/storage/textures/eadeb22ee619af1023073c13575cdf82b17c841595df4d02a2eb746a048ca701 new file mode 100755 index 0000000..fe6600e Binary files /dev/null and b/storage/textures/eadeb22ee619af1023073c13575cdf82b17c841595df4d02a2eb746a048ca701 differ diff --git a/storage/textures/eb1016138fe83bbe788da7a0e46f49512a7e48ae6adeb65a42c879f6fc0953bb b/storage/textures/eb1016138fe83bbe788da7a0e46f49512a7e48ae6adeb65a42c879f6fc0953bb new file mode 100755 index 0000000..85d6a37 Binary files /dev/null and b/storage/textures/eb1016138fe83bbe788da7a0e46f49512a7e48ae6adeb65a42c879f6fc0953bb differ diff --git a/storage/textures/eb106c5437bd49b205371d9246dbf56f329086a97d708e6ef8b54f86d2ef354d b/storage/textures/eb106c5437bd49b205371d9246dbf56f329086a97d708e6ef8b54f86d2ef354d new file mode 100644 index 0000000..98286a9 Binary files /dev/null and b/storage/textures/eb106c5437bd49b205371d9246dbf56f329086a97d708e6ef8b54f86d2ef354d differ diff --git a/storage/textures/eb29c14b1b774597e4b0fe0940279d878347f77042c32bc9bf5fb85ad96035a3 b/storage/textures/eb29c14b1b774597e4b0fe0940279d878347f77042c32bc9bf5fb85ad96035a3 new file mode 100644 index 0000000..8904254 Binary files /dev/null and b/storage/textures/eb29c14b1b774597e4b0fe0940279d878347f77042c32bc9bf5fb85ad96035a3 differ diff --git a/storage/textures/eb80969bba9c9e0bca74deee8486938d26f0f24433278114f1ffa4292b4858f0 b/storage/textures/eb80969bba9c9e0bca74deee8486938d26f0f24433278114f1ffa4292b4858f0 new file mode 100755 index 0000000..f6d424f Binary files /dev/null and b/storage/textures/eb80969bba9c9e0bca74deee8486938d26f0f24433278114f1ffa4292b4858f0 differ diff --git a/storage/textures/ec0332dbbfad80bdb2fcba0c4552abcfcaa3454208ec039ef5b02b77ea1d0a50 b/storage/textures/ec0332dbbfad80bdb2fcba0c4552abcfcaa3454208ec039ef5b02b77ea1d0a50 new file mode 100755 index 0000000..b101820 Binary files /dev/null and b/storage/textures/ec0332dbbfad80bdb2fcba0c4552abcfcaa3454208ec039ef5b02b77ea1d0a50 differ diff --git a/storage/textures/ec213e0d7ca5c506a8f27c74ab45b3fd2ff42ce6a5a499c830704553bec6b2a2 b/storage/textures/ec213e0d7ca5c506a8f27c74ab45b3fd2ff42ce6a5a499c830704553bec6b2a2 new file mode 100755 index 0000000..140363d Binary files /dev/null and b/storage/textures/ec213e0d7ca5c506a8f27c74ab45b3fd2ff42ce6a5a499c830704553bec6b2a2 differ diff --git a/storage/textures/ec338450d4294bd071c5a14159af8e61a85df6b3ecd5168b20c8911588f82a77 b/storage/textures/ec338450d4294bd071c5a14159af8e61a85df6b3ecd5168b20c8911588f82a77 new file mode 100644 index 0000000..dcf1237 Binary files /dev/null and b/storage/textures/ec338450d4294bd071c5a14159af8e61a85df6b3ecd5168b20c8911588f82a77 differ diff --git a/storage/textures/eccdbad1dca140ef0410a08d69f8eba4e32b5ab5ce0e9fad5bda01fcbef7f33d b/storage/textures/eccdbad1dca140ef0410a08d69f8eba4e32b5ab5ce0e9fad5bda01fcbef7f33d new file mode 100644 index 0000000..f7669b5 Binary files /dev/null and b/storage/textures/eccdbad1dca140ef0410a08d69f8eba4e32b5ab5ce0e9fad5bda01fcbef7f33d differ diff --git a/storage/textures/ed489cf9a182ab7fd280cbdf027aa409501cceb1d83a69b280fae72e473f3f3a b/storage/textures/ed489cf9a182ab7fd280cbdf027aa409501cceb1d83a69b280fae72e473f3f3a new file mode 100755 index 0000000..6ca46f3 Binary files /dev/null and b/storage/textures/ed489cf9a182ab7fd280cbdf027aa409501cceb1d83a69b280fae72e473f3f3a differ diff --git a/storage/textures/ed5515760a1f093a5c60deb9c0b762c6111d1f817f6271ff5518b689ff15a71c b/storage/textures/ed5515760a1f093a5c60deb9c0b762c6111d1f817f6271ff5518b689ff15a71c new file mode 100755 index 0000000..3ecd184 Binary files /dev/null and b/storage/textures/ed5515760a1f093a5c60deb9c0b762c6111d1f817f6271ff5518b689ff15a71c differ diff --git a/storage/textures/eda91431190dd0ebf1bf523c2663335ac51a95a6793c978a40d8ebace0dcbb1f b/storage/textures/eda91431190dd0ebf1bf523c2663335ac51a95a6793c978a40d8ebace0dcbb1f new file mode 100755 index 0000000..80a5031 Binary files /dev/null and b/storage/textures/eda91431190dd0ebf1bf523c2663335ac51a95a6793c978a40d8ebace0dcbb1f differ diff --git a/storage/textures/edde02afa295b48b32d8bc69abf10501462de1d2749397fa24cf22af86c258c8 b/storage/textures/edde02afa295b48b32d8bc69abf10501462de1d2749397fa24cf22af86c258c8 new file mode 100644 index 0000000..eeb5065 Binary files /dev/null and b/storage/textures/edde02afa295b48b32d8bc69abf10501462de1d2749397fa24cf22af86c258c8 differ diff --git a/storage/textures/ee4cace8559bd2636b59a88aef359c084fd8c7a4f9e1b6daeb4fff5cc1ac6c73 b/storage/textures/ee4cace8559bd2636b59a88aef359c084fd8c7a4f9e1b6daeb4fff5cc1ac6c73 new file mode 100755 index 0000000..1e21df2 Binary files /dev/null and b/storage/textures/ee4cace8559bd2636b59a88aef359c084fd8c7a4f9e1b6daeb4fff5cc1ac6c73 differ diff --git a/storage/textures/eeb7608cb63b3fe5727c0ecc6abf4e42d3c81a1baf2cad134895fc1b1ed7e7fa b/storage/textures/eeb7608cb63b3fe5727c0ecc6abf4e42d3c81a1baf2cad134895fc1b1ed7e7fa new file mode 100755 index 0000000..a194dc1 Binary files /dev/null and b/storage/textures/eeb7608cb63b3fe5727c0ecc6abf4e42d3c81a1baf2cad134895fc1b1ed7e7fa differ diff --git a/storage/textures/eec94c74154e11f73952585813cdfec6d4a0968cdab175ea4f604ad5ddb624d5 b/storage/textures/eec94c74154e11f73952585813cdfec6d4a0968cdab175ea4f604ad5ddb624d5 new file mode 100644 index 0000000..3af8219 Binary files /dev/null and b/storage/textures/eec94c74154e11f73952585813cdfec6d4a0968cdab175ea4f604ad5ddb624d5 differ diff --git a/storage/textures/eede79b40d4f68c8177e8ed262a185d0171092d4728456b298cfc01648bfb477 b/storage/textures/eede79b40d4f68c8177e8ed262a185d0171092d4728456b298cfc01648bfb477 new file mode 100755 index 0000000..1dff794 Binary files /dev/null and b/storage/textures/eede79b40d4f68c8177e8ed262a185d0171092d4728456b298cfc01648bfb477 differ diff --git a/storage/textures/ef231c09c0bda8e1c2466bb5953274d63d523b90576a9a13d821c05790750ce3 b/storage/textures/ef231c09c0bda8e1c2466bb5953274d63d523b90576a9a13d821c05790750ce3 new file mode 100755 index 0000000..8cefe26 Binary files /dev/null and b/storage/textures/ef231c09c0bda8e1c2466bb5953274d63d523b90576a9a13d821c05790750ce3 differ diff --git a/storage/textures/ef300f310da4371c53d42ab2e6dbc1edff5ba70ff748677df02cabc122cb3449 b/storage/textures/ef300f310da4371c53d42ab2e6dbc1edff5ba70ff748677df02cabc122cb3449 new file mode 100644 index 0000000..37f92a9 Binary files /dev/null and b/storage/textures/ef300f310da4371c53d42ab2e6dbc1edff5ba70ff748677df02cabc122cb3449 differ diff --git a/storage/textures/ef6c153134beb522833ef0fa157264ed4b1bfb34b253dc15ce614310cc7fd849 b/storage/textures/ef6c153134beb522833ef0fa157264ed4b1bfb34b253dc15ce614310cc7fd849 new file mode 100755 index 0000000..dc6219c Binary files /dev/null and b/storage/textures/ef6c153134beb522833ef0fa157264ed4b1bfb34b253dc15ce614310cc7fd849 differ diff --git a/storage/textures/ef6d3357c94ec7de76515544ec3b0bb1f1e345752ebcdafff64736ea796d430a b/storage/textures/ef6d3357c94ec7de76515544ec3b0bb1f1e345752ebcdafff64736ea796d430a new file mode 100755 index 0000000..ab576d0 Binary files /dev/null and b/storage/textures/ef6d3357c94ec7de76515544ec3b0bb1f1e345752ebcdafff64736ea796d430a differ diff --git a/storage/textures/efad49dbc4bd7d0cafa276a637996cccbf735220c025916ea8a9937bbdac475e b/storage/textures/efad49dbc4bd7d0cafa276a637996cccbf735220c025916ea8a9937bbdac475e new file mode 100644 index 0000000..6d53189 Binary files /dev/null and b/storage/textures/efad49dbc4bd7d0cafa276a637996cccbf735220c025916ea8a9937bbdac475e differ diff --git a/storage/textures/efc1fb7363393f8e38d6495d6c5fc650b25ada68bd23ccf702128a58f9bd0940 b/storage/textures/efc1fb7363393f8e38d6495d6c5fc650b25ada68bd23ccf702128a58f9bd0940 new file mode 100644 index 0000000..d40005a Binary files /dev/null and b/storage/textures/efc1fb7363393f8e38d6495d6c5fc650b25ada68bd23ccf702128a58f9bd0940 differ diff --git a/storage/textures/effbe88cd8be3e06d189299b574e62152ef95bc989989d32bec142c960717806 b/storage/textures/effbe88cd8be3e06d189299b574e62152ef95bc989989d32bec142c960717806 new file mode 100644 index 0000000..128b92c Binary files /dev/null and b/storage/textures/effbe88cd8be3e06d189299b574e62152ef95bc989989d32bec142c960717806 differ diff --git a/storage/textures/f035f5189944ec166b5fee5e54863a3bf8f326ed0c5e4699f5bdab4d198b8a5f b/storage/textures/f035f5189944ec166b5fee5e54863a3bf8f326ed0c5e4699f5bdab4d198b8a5f new file mode 100755 index 0000000..065f6f1 Binary files /dev/null and b/storage/textures/f035f5189944ec166b5fee5e54863a3bf8f326ed0c5e4699f5bdab4d198b8a5f differ diff --git a/storage/textures/f0369962774382ab2bc9e35d831c584fd06595fac6d160855b9a30de6c00d93a b/storage/textures/f0369962774382ab2bc9e35d831c584fd06595fac6d160855b9a30de6c00d93a new file mode 100755 index 0000000..438f0b1 Binary files /dev/null and b/storage/textures/f0369962774382ab2bc9e35d831c584fd06595fac6d160855b9a30de6c00d93a differ diff --git a/storage/textures/f0f971d803ce58ff7361177f7fc905f884e801ec63a3aa95a783f84686b3872e b/storage/textures/f0f971d803ce58ff7361177f7fc905f884e801ec63a3aa95a783f84686b3872e new file mode 100644 index 0000000..faabcc8 Binary files /dev/null and b/storage/textures/f0f971d803ce58ff7361177f7fc905f884e801ec63a3aa95a783f84686b3872e differ diff --git a/storage/textures/f0fe3439c8a5110585c5075c5695ee8b128eb0b6e2eb5bbda021ced88ffd896b b/storage/textures/f0fe3439c8a5110585c5075c5695ee8b128eb0b6e2eb5bbda021ced88ffd896b new file mode 100644 index 0000000..4b8bf80 Binary files /dev/null and b/storage/textures/f0fe3439c8a5110585c5075c5695ee8b128eb0b6e2eb5bbda021ced88ffd896b differ diff --git a/storage/textures/f10fc1bb12374376482a634990e2e85cfc1319cac821cd6b68933c5f5c523760 b/storage/textures/f10fc1bb12374376482a634990e2e85cfc1319cac821cd6b68933c5f5c523760 new file mode 100755 index 0000000..21d2d32 Binary files /dev/null and b/storage/textures/f10fc1bb12374376482a634990e2e85cfc1319cac821cd6b68933c5f5c523760 differ diff --git a/storage/textures/f15953678bebec352dd7c509b3c02f5065d4da64a945efd070dffeac6d3e800e b/storage/textures/f15953678bebec352dd7c509b3c02f5065d4da64a945efd070dffeac6d3e800e new file mode 100755 index 0000000..b3a6f9d Binary files /dev/null and b/storage/textures/f15953678bebec352dd7c509b3c02f5065d4da64a945efd070dffeac6d3e800e differ diff --git a/storage/textures/f1b0e03948751e22d2890461d612cc4fe8f71fbf8de0ad7cd33c93de102976a9 b/storage/textures/f1b0e03948751e22d2890461d612cc4fe8f71fbf8de0ad7cd33c93de102976a9 new file mode 100644 index 0000000..7c63827 Binary files /dev/null and b/storage/textures/f1b0e03948751e22d2890461d612cc4fe8f71fbf8de0ad7cd33c93de102976a9 differ diff --git a/storage/textures/f1f9d628b43b3cf9d4459d4e0340a6f1079c7ea53c31003eea62ed39ac2a214a b/storage/textures/f1f9d628b43b3cf9d4459d4e0340a6f1079c7ea53c31003eea62ed39ac2a214a new file mode 100644 index 0000000..fa25f8f Binary files /dev/null and b/storage/textures/f1f9d628b43b3cf9d4459d4e0340a6f1079c7ea53c31003eea62ed39ac2a214a differ diff --git a/storage/textures/f2122d6706d3b2d7bf615de51c733a109a42e6d3d431b00d00af57afa721935b b/storage/textures/f2122d6706d3b2d7bf615de51c733a109a42e6d3d431b00d00af57afa721935b new file mode 100644 index 0000000..253e0f0 Binary files /dev/null and b/storage/textures/f2122d6706d3b2d7bf615de51c733a109a42e6d3d431b00d00af57afa721935b differ diff --git a/storage/textures/f242077a09e43bffa0d7b2883ee104d1268cce2c34c1e07329f6c11c0bb78f53 b/storage/textures/f242077a09e43bffa0d7b2883ee104d1268cce2c34c1e07329f6c11c0bb78f53 new file mode 100755 index 0000000..7a9bf8b Binary files /dev/null and b/storage/textures/f242077a09e43bffa0d7b2883ee104d1268cce2c34c1e07329f6c11c0bb78f53 differ diff --git a/storage/textures/f2950b366813cad1359838f568bb3e22186e3b996468fdb7a2234e17998188af b/storage/textures/f2950b366813cad1359838f568bb3e22186e3b996468fdb7a2234e17998188af new file mode 100755 index 0000000..2d8f520 Binary files /dev/null and b/storage/textures/f2950b366813cad1359838f568bb3e22186e3b996468fdb7a2234e17998188af differ diff --git a/storage/textures/f2f1ced29988f856e9f3b50e5b5aba814aa1c097704b65781cf103d5d5cb4637 b/storage/textures/f2f1ced29988f856e9f3b50e5b5aba814aa1c097704b65781cf103d5d5cb4637 new file mode 100755 index 0000000..6a9b706 Binary files /dev/null and b/storage/textures/f2f1ced29988f856e9f3b50e5b5aba814aa1c097704b65781cf103d5d5cb4637 differ diff --git a/storage/textures/f318aacb3823109d5d575ea6a2cf2d05115046ec82a7a055418c2dc8a7bb9bfb b/storage/textures/f318aacb3823109d5d575ea6a2cf2d05115046ec82a7a055418c2dc8a7bb9bfb new file mode 100755 index 0000000..86a0621 Binary files /dev/null and b/storage/textures/f318aacb3823109d5d575ea6a2cf2d05115046ec82a7a055418c2dc8a7bb9bfb differ diff --git a/storage/textures/f33184d66e210dad337d00301ad25526e14ee6db1e86850e4c815c5e49b6c39e b/storage/textures/f33184d66e210dad337d00301ad25526e14ee6db1e86850e4c815c5e49b6c39e new file mode 100755 index 0000000..35a74eb Binary files /dev/null and b/storage/textures/f33184d66e210dad337d00301ad25526e14ee6db1e86850e4c815c5e49b6c39e differ diff --git a/storage/textures/f33881030b2604e9db6b02885622887b01b4392861fa9bef1e94e1dfa6732bac b/storage/textures/f33881030b2604e9db6b02885622887b01b4392861fa9bef1e94e1dfa6732bac new file mode 100755 index 0000000..cdc6f59 Binary files /dev/null and b/storage/textures/f33881030b2604e9db6b02885622887b01b4392861fa9bef1e94e1dfa6732bac differ diff --git a/storage/textures/f349deb25573cc43d83c7b85107223b15334aa94a4a0560a769ea78bd824090a b/storage/textures/f349deb25573cc43d83c7b85107223b15334aa94a4a0560a769ea78bd824090a new file mode 100755 index 0000000..b769683 Binary files /dev/null and b/storage/textures/f349deb25573cc43d83c7b85107223b15334aa94a4a0560a769ea78bd824090a differ diff --git a/storage/textures/f358ca7cd73907856f83426c5b3343ee227d784f63890874145cfb11ab8392eb b/storage/textures/f358ca7cd73907856f83426c5b3343ee227d784f63890874145cfb11ab8392eb new file mode 100755 index 0000000..6634e9e Binary files /dev/null and b/storage/textures/f358ca7cd73907856f83426c5b3343ee227d784f63890874145cfb11ab8392eb differ diff --git a/storage/textures/f399fb583d63dd08b2dc752e693215b1f8ef92a79a964289e1857839f88308dc b/storage/textures/f399fb583d63dd08b2dc752e693215b1f8ef92a79a964289e1857839f88308dc new file mode 100644 index 0000000..50a32ad Binary files /dev/null and b/storage/textures/f399fb583d63dd08b2dc752e693215b1f8ef92a79a964289e1857839f88308dc differ diff --git a/storage/textures/f3be8559f3b6824c4b8d0cd5480a0def13173d159e0b6e493a26cbd2e4f6df48 b/storage/textures/f3be8559f3b6824c4b8d0cd5480a0def13173d159e0b6e493a26cbd2e4f6df48 new file mode 100755 index 0000000..a30b980 Binary files /dev/null and b/storage/textures/f3be8559f3b6824c4b8d0cd5480a0def13173d159e0b6e493a26cbd2e4f6df48 differ diff --git a/storage/textures/f3e8819610033e7e9f594f45961b6c31e44fb6711a5f2f54ebb02c836e015a84 b/storage/textures/f3e8819610033e7e9f594f45961b6c31e44fb6711a5f2f54ebb02c836e015a84 new file mode 100755 index 0000000..a5f63d0 Binary files /dev/null and b/storage/textures/f3e8819610033e7e9f594f45961b6c31e44fb6711a5f2f54ebb02c836e015a84 differ diff --git a/storage/textures/f466d97c33f8ee182c060df47b4b1945a5ae7e56105419e90d07e3a38e1a4f39 b/storage/textures/f466d97c33f8ee182c060df47b4b1945a5ae7e56105419e90d07e3a38e1a4f39 new file mode 100644 index 0000000..d964bd4 Binary files /dev/null and b/storage/textures/f466d97c33f8ee182c060df47b4b1945a5ae7e56105419e90d07e3a38e1a4f39 differ diff --git a/storage/textures/f47573ae0c7b0f61c0cc97e849b0f9c3fada8e1f9e4d0a7d6526b7560e8955ac b/storage/textures/f47573ae0c7b0f61c0cc97e849b0f9c3fada8e1f9e4d0a7d6526b7560e8955ac new file mode 100755 index 0000000..58d9bf1 Binary files /dev/null and b/storage/textures/f47573ae0c7b0f61c0cc97e849b0f9c3fada8e1f9e4d0a7d6526b7560e8955ac differ diff --git a/storage/textures/f4a13e292ca509432d9995b426683331d1d6c4bc3ae256464f7cdd9d938ac25f b/storage/textures/f4a13e292ca509432d9995b426683331d1d6c4bc3ae256464f7cdd9d938ac25f new file mode 100755 index 0000000..d060d48 Binary files /dev/null and b/storage/textures/f4a13e292ca509432d9995b426683331d1d6c4bc3ae256464f7cdd9d938ac25f differ diff --git a/storage/textures/f50e1213d591dad74c213e74bebc6e49b45b4f7d66bd6dd7c77f31380af1b0a3 b/storage/textures/f50e1213d591dad74c213e74bebc6e49b45b4f7d66bd6dd7c77f31380af1b0a3 new file mode 100755 index 0000000..8c791c3 Binary files /dev/null and b/storage/textures/f50e1213d591dad74c213e74bebc6e49b45b4f7d66bd6dd7c77f31380af1b0a3 differ diff --git a/storage/textures/f512c063ac6eb5df5fe88629c9965a20269363d0b742a84c2284a6b3b827ee57 b/storage/textures/f512c063ac6eb5df5fe88629c9965a20269363d0b742a84c2284a6b3b827ee57 new file mode 100755 index 0000000..cc5fad1 Binary files /dev/null and b/storage/textures/f512c063ac6eb5df5fe88629c9965a20269363d0b742a84c2284a6b3b827ee57 differ diff --git a/storage/textures/f558c76c2ab95869d3f4daee15f23208ede916e577e68f56f87a9944f26e3582 b/storage/textures/f558c76c2ab95869d3f4daee15f23208ede916e577e68f56f87a9944f26e3582 new file mode 100755 index 0000000..5f9834c Binary files /dev/null and b/storage/textures/f558c76c2ab95869d3f4daee15f23208ede916e577e68f56f87a9944f26e3582 differ diff --git a/storage/textures/f55f642e88fd53814abd7c84033cef4c9c2a6a7ead39333136203d3d680607ec b/storage/textures/f55f642e88fd53814abd7c84033cef4c9c2a6a7ead39333136203d3d680607ec new file mode 100644 index 0000000..c9df363 Binary files /dev/null and b/storage/textures/f55f642e88fd53814abd7c84033cef4c9c2a6a7ead39333136203d3d680607ec differ diff --git a/storage/textures/f5c61085818908483fd38e07bd4e0046284895dc2c229cbd09c3f29ed6f65e1a b/storage/textures/f5c61085818908483fd38e07bd4e0046284895dc2c229cbd09c3f29ed6f65e1a new file mode 100644 index 0000000..06013fc Binary files /dev/null and b/storage/textures/f5c61085818908483fd38e07bd4e0046284895dc2c229cbd09c3f29ed6f65e1a differ diff --git a/storage/textures/f5f45bcd32275934e9ce10f1c5b63ecce5fb4d90b0b73db742e4ee0e233552ef b/storage/textures/f5f45bcd32275934e9ce10f1c5b63ecce5fb4d90b0b73db742e4ee0e233552ef new file mode 100644 index 0000000..138ca98 Binary files /dev/null and b/storage/textures/f5f45bcd32275934e9ce10f1c5b63ecce5fb4d90b0b73db742e4ee0e233552ef differ diff --git a/storage/textures/f64d95e7a862113c3c0dd2769bb696552deba8cd676451b8591a34d2e58e071f b/storage/textures/f64d95e7a862113c3c0dd2769bb696552deba8cd676451b8591a34d2e58e071f new file mode 100755 index 0000000..c69a194 Binary files /dev/null and b/storage/textures/f64d95e7a862113c3c0dd2769bb696552deba8cd676451b8591a34d2e58e071f differ diff --git a/storage/textures/f670e519c1ec6db8150409f161c73375392db5e5661ea65ec031d84afaf6e1f0 b/storage/textures/f670e519c1ec6db8150409f161c73375392db5e5661ea65ec031d84afaf6e1f0 new file mode 100755 index 0000000..db13043 Binary files /dev/null and b/storage/textures/f670e519c1ec6db8150409f161c73375392db5e5661ea65ec031d84afaf6e1f0 differ diff --git a/storage/textures/f6b3d2fb5b266a8966c896231a673bf3e145d0684b901e1b390f83b88019d337 b/storage/textures/f6b3d2fb5b266a8966c896231a673bf3e145d0684b901e1b390f83b88019d337 new file mode 100755 index 0000000..8a5d9b3 Binary files /dev/null and b/storage/textures/f6b3d2fb5b266a8966c896231a673bf3e145d0684b901e1b390f83b88019d337 differ diff --git a/storage/textures/f6bd7202ee76e648fee9b20814ce3f8fa757cc7483957d1396ede2a9753d4c74 b/storage/textures/f6bd7202ee76e648fee9b20814ce3f8fa757cc7483957d1396ede2a9753d4c74 new file mode 100755 index 0000000..fae1654 Binary files /dev/null and b/storage/textures/f6bd7202ee76e648fee9b20814ce3f8fa757cc7483957d1396ede2a9753d4c74 differ diff --git a/storage/textures/f77988f195ab773e7d987a04acb060e77b6434216c9a5107117d6a06ef0c935d b/storage/textures/f77988f195ab773e7d987a04acb060e77b6434216c9a5107117d6a06ef0c935d new file mode 100755 index 0000000..bd68d67 Binary files /dev/null and b/storage/textures/f77988f195ab773e7d987a04acb060e77b6434216c9a5107117d6a06ef0c935d differ diff --git a/storage/textures/f8083f12dd6d0ad6f5688faf371329723b69bcd331bd47bfffdc7ab1b2ad8545 b/storage/textures/f8083f12dd6d0ad6f5688faf371329723b69bcd331bd47bfffdc7ab1b2ad8545 new file mode 100755 index 0000000..4343cc8 Binary files /dev/null and b/storage/textures/f8083f12dd6d0ad6f5688faf371329723b69bcd331bd47bfffdc7ab1b2ad8545 differ diff --git a/storage/textures/f81400cfe18314a4d3816185545d529a1b84b013ef5657836f64bc861cff4243 b/storage/textures/f81400cfe18314a4d3816185545d529a1b84b013ef5657836f64bc861cff4243 new file mode 100755 index 0000000..6df5209 Binary files /dev/null and b/storage/textures/f81400cfe18314a4d3816185545d529a1b84b013ef5657836f64bc861cff4243 differ diff --git a/storage/textures/f89d8c241f7d67e2f3c554b00c9f79e95a0d30383fc5ed8c0bac50887b396bc4 b/storage/textures/f89d8c241f7d67e2f3c554b00c9f79e95a0d30383fc5ed8c0bac50887b396bc4 new file mode 100644 index 0000000..cbda7e3 Binary files /dev/null and b/storage/textures/f89d8c241f7d67e2f3c554b00c9f79e95a0d30383fc5ed8c0bac50887b396bc4 differ diff --git a/storage/textures/f8a1a206b700d62607681da08dccec7bbf4a348472b34d03fb12c21118072032 b/storage/textures/f8a1a206b700d62607681da08dccec7bbf4a348472b34d03fb12c21118072032 new file mode 100755 index 0000000..3d77363 Binary files /dev/null and b/storage/textures/f8a1a206b700d62607681da08dccec7bbf4a348472b34d03fb12c21118072032 differ diff --git a/storage/textures/f8fe6de458ac37c5ba00e8f8504cef17dbfa60fa3ac6539aa50740bc5019e337 b/storage/textures/f8fe6de458ac37c5ba00e8f8504cef17dbfa60fa3ac6539aa50740bc5019e337 new file mode 100755 index 0000000..bfa36d0 Binary files /dev/null and b/storage/textures/f8fe6de458ac37c5ba00e8f8504cef17dbfa60fa3ac6539aa50740bc5019e337 differ diff --git a/storage/textures/f9135c8b8d0f3408256bab03953ff01d58fb23120aedda373ca459c29674d4c4 b/storage/textures/f9135c8b8d0f3408256bab03953ff01d58fb23120aedda373ca459c29674d4c4 new file mode 100644 index 0000000..9d80731 Binary files /dev/null and b/storage/textures/f9135c8b8d0f3408256bab03953ff01d58fb23120aedda373ca459c29674d4c4 differ diff --git a/storage/textures/f960547eee916ae6b6fc9d9a6d555f67c66eb0587e3a8dcfce65c8c0e5242644 b/storage/textures/f960547eee916ae6b6fc9d9a6d555f67c66eb0587e3a8dcfce65c8c0e5242644 new file mode 100644 index 0000000..7403683 Binary files /dev/null and b/storage/textures/f960547eee916ae6b6fc9d9a6d555f67c66eb0587e3a8dcfce65c8c0e5242644 differ diff --git a/storage/textures/f96c4f99815782c6208429aff63bd6cccb5a7fe58c60c97c04cae314622ad682 b/storage/textures/f96c4f99815782c6208429aff63bd6cccb5a7fe58c60c97c04cae314622ad682 new file mode 100755 index 0000000..76e0967 Binary files /dev/null and b/storage/textures/f96c4f99815782c6208429aff63bd6cccb5a7fe58c60c97c04cae314622ad682 differ diff --git a/storage/textures/f97f9e5b04c1ba915eaa3a1aada586841311a95c8f2dae8ab168bc9e34f4466d b/storage/textures/f97f9e5b04c1ba915eaa3a1aada586841311a95c8f2dae8ab168bc9e34f4466d new file mode 100644 index 0000000..c8206ca Binary files /dev/null and b/storage/textures/f97f9e5b04c1ba915eaa3a1aada586841311a95c8f2dae8ab168bc9e34f4466d differ diff --git a/storage/textures/f9919bce7a4b629236be9a2a61aa63cee0cd6ceb54468bcc5ccd9b840a6f9a0e b/storage/textures/f9919bce7a4b629236be9a2a61aa63cee0cd6ceb54468bcc5ccd9b840a6f9a0e new file mode 100644 index 0000000..dde1274 Binary files /dev/null and b/storage/textures/f9919bce7a4b629236be9a2a61aa63cee0cd6ceb54468bcc5ccd9b840a6f9a0e differ diff --git a/storage/textures/f9936e65aa7202fd986a80d2477089c6b663319707b6f94161593e025f63e00b b/storage/textures/f9936e65aa7202fd986a80d2477089c6b663319707b6f94161593e025f63e00b new file mode 100755 index 0000000..12c94a8 Binary files /dev/null and b/storage/textures/f9936e65aa7202fd986a80d2477089c6b663319707b6f94161593e025f63e00b differ diff --git a/storage/textures/f9cd1218f1a4bf3b884d157c4512320927360d940f80922496e30dd40b72def2 b/storage/textures/f9cd1218f1a4bf3b884d157c4512320927360d940f80922496e30dd40b72def2 new file mode 100644 index 0000000..574995e Binary files /dev/null and b/storage/textures/f9cd1218f1a4bf3b884d157c4512320927360d940f80922496e30dd40b72def2 differ diff --git a/storage/textures/f9e13b3f19af51ee7d4fe2db7b02f2cc6076f007a77daae7c1936ce4ff8fd0e4 b/storage/textures/f9e13b3f19af51ee7d4fe2db7b02f2cc6076f007a77daae7c1936ce4ff8fd0e4 new file mode 100755 index 0000000..1483378 Binary files /dev/null and b/storage/textures/f9e13b3f19af51ee7d4fe2db7b02f2cc6076f007a77daae7c1936ce4ff8fd0e4 differ diff --git a/storage/textures/fa6ff9cbd1c7dabd840a79df2f3a3a9c43d678b9e9a7d5ff40de6d0fd4a78140 b/storage/textures/fa6ff9cbd1c7dabd840a79df2f3a3a9c43d678b9e9a7d5ff40de6d0fd4a78140 new file mode 100755 index 0000000..7bb260a Binary files /dev/null and b/storage/textures/fa6ff9cbd1c7dabd840a79df2f3a3a9c43d678b9e9a7d5ff40de6d0fd4a78140 differ diff --git a/storage/textures/fa8e16cd6caa7be1fa1ca3345c45af8ad4a0d19dc427182e685a908b6b587c1d b/storage/textures/fa8e16cd6caa7be1fa1ca3345c45af8ad4a0d19dc427182e685a908b6b587c1d new file mode 100644 index 0000000..4775f88 Binary files /dev/null and b/storage/textures/fa8e16cd6caa7be1fa1ca3345c45af8ad4a0d19dc427182e685a908b6b587c1d differ diff --git a/storage/textures/fa9c8ae0cbb3f6c02b7ad30fd22e11b0aff41d7a60c5eeaa78fd6b968b397968 b/storage/textures/fa9c8ae0cbb3f6c02b7ad30fd22e11b0aff41d7a60c5eeaa78fd6b968b397968 new file mode 100755 index 0000000..11749e4 Binary files /dev/null and b/storage/textures/fa9c8ae0cbb3f6c02b7ad30fd22e11b0aff41d7a60c5eeaa78fd6b968b397968 differ diff --git a/storage/textures/faa51909048ebe7a4ace270979adb1734094fd879b3d35e1562695698cae0bf6 b/storage/textures/faa51909048ebe7a4ace270979adb1734094fd879b3d35e1562695698cae0bf6 new file mode 100644 index 0000000..8cb8437 Binary files /dev/null and b/storage/textures/faa51909048ebe7a4ace270979adb1734094fd879b3d35e1562695698cae0bf6 differ diff --git a/storage/textures/faf1b60b288047c4dd3b65bb9b6b936a36f26c6820e51f7f90c10a82d369ad45 b/storage/textures/faf1b60b288047c4dd3b65bb9b6b936a36f26c6820e51f7f90c10a82d369ad45 new file mode 100644 index 0000000..eb57e10 Binary files /dev/null and b/storage/textures/faf1b60b288047c4dd3b65bb9b6b936a36f26c6820e51f7f90c10a82d369ad45 differ diff --git a/storage/textures/fb58f8f14eea7f2ba45cd881222c656667cf0625ecd4df2960a03cbfef47be67 b/storage/textures/fb58f8f14eea7f2ba45cd881222c656667cf0625ecd4df2960a03cbfef47be67 new file mode 100755 index 0000000..98824d1 Binary files /dev/null and b/storage/textures/fb58f8f14eea7f2ba45cd881222c656667cf0625ecd4df2960a03cbfef47be67 differ diff --git a/storage/textures/fb652c62478d17864fcb4ef28d5a06a1c7cfa22062ee858dba7361689434a0ed b/storage/textures/fb652c62478d17864fcb4ef28d5a06a1c7cfa22062ee858dba7361689434a0ed new file mode 100644 index 0000000..1abd726 Binary files /dev/null and b/storage/textures/fb652c62478d17864fcb4ef28d5a06a1c7cfa22062ee858dba7361689434a0ed differ diff --git a/storage/textures/fb90f697b3898bbe7444fd828691fbf04dfa5118bec5698433b386fb34cbc792 b/storage/textures/fb90f697b3898bbe7444fd828691fbf04dfa5118bec5698433b386fb34cbc792 new file mode 100644 index 0000000..1652fa1 Binary files /dev/null and b/storage/textures/fb90f697b3898bbe7444fd828691fbf04dfa5118bec5698433b386fb34cbc792 differ diff --git a/storage/textures/fc40a7b7457f25cac13b8fca52deb37464ccee70d19bbf3169d6a8a1a114d9a2 b/storage/textures/fc40a7b7457f25cac13b8fca52deb37464ccee70d19bbf3169d6a8a1a114d9a2 new file mode 100755 index 0000000..4a2844b Binary files /dev/null and b/storage/textures/fc40a7b7457f25cac13b8fca52deb37464ccee70d19bbf3169d6a8a1a114d9a2 differ diff --git a/storage/textures/fcfda7efdcbc5bd62e37eb5b9c6ddaa8382864bbc4799d24095ade26dc274e91 b/storage/textures/fcfda7efdcbc5bd62e37eb5b9c6ddaa8382864bbc4799d24095ade26dc274e91 new file mode 100755 index 0000000..eda97eb Binary files /dev/null and b/storage/textures/fcfda7efdcbc5bd62e37eb5b9c6ddaa8382864bbc4799d24095ade26dc274e91 differ diff --git a/storage/textures/fcfeec2e3782c102223240eb25b841ff6189c3353b00de34bb047c17d9f06fca b/storage/textures/fcfeec2e3782c102223240eb25b841ff6189c3353b00de34bb047c17d9f06fca new file mode 100755 index 0000000..6a43ad3 Binary files /dev/null and b/storage/textures/fcfeec2e3782c102223240eb25b841ff6189c3353b00de34bb047c17d9f06fca differ diff --git a/storage/textures/fd38a7673e5727e9dc45f967cdd62894f819baa107d184c82a90266a322ea936 b/storage/textures/fd38a7673e5727e9dc45f967cdd62894f819baa107d184c82a90266a322ea936 new file mode 100755 index 0000000..2eb0d29 Binary files /dev/null and b/storage/textures/fd38a7673e5727e9dc45f967cdd62894f819baa107d184c82a90266a322ea936 differ diff --git a/storage/textures/fd3faf49cae3bb9b608e1a8c96e2401ed36fc0062f38b13a59463833b0321a41 b/storage/textures/fd3faf49cae3bb9b608e1a8c96e2401ed36fc0062f38b13a59463833b0321a41 new file mode 100755 index 0000000..30166ca Binary files /dev/null and b/storage/textures/fd3faf49cae3bb9b608e1a8c96e2401ed36fc0062f38b13a59463833b0321a41 differ diff --git a/storage/textures/fd955aa2f63caf0e64fb6bcb1bb1ba4b24ecb7bf2a58c5c19649aebf125043ec b/storage/textures/fd955aa2f63caf0e64fb6bcb1bb1ba4b24ecb7bf2a58c5c19649aebf125043ec new file mode 100755 index 0000000..f381414 Binary files /dev/null and b/storage/textures/fd955aa2f63caf0e64fb6bcb1bb1ba4b24ecb7bf2a58c5c19649aebf125043ec differ diff --git a/storage/textures/fdac624ce395740eca6c34954602a8d8added4e93a476b68a09d4a4c19e4aca6 b/storage/textures/fdac624ce395740eca6c34954602a8d8added4e93a476b68a09d4a4c19e4aca6 new file mode 100644 index 0000000..849dc83 Binary files /dev/null and b/storage/textures/fdac624ce395740eca6c34954602a8d8added4e93a476b68a09d4a4c19e4aca6 differ diff --git a/storage/textures/fdc2105176c72d14864bc4c65ddadc05edce4aecfdbb9f3842df214a435af7f8 b/storage/textures/fdc2105176c72d14864bc4c65ddadc05edce4aecfdbb9f3842df214a435af7f8 new file mode 100644 index 0000000..3998b66 Binary files /dev/null and b/storage/textures/fdc2105176c72d14864bc4c65ddadc05edce4aecfdbb9f3842df214a435af7f8 differ diff --git a/storage/textures/fdd407e17cb7436fd33b4a86c55d72ec13e6f853f26d833360b6e201a9249e6f b/storage/textures/fdd407e17cb7436fd33b4a86c55d72ec13e6f853f26d833360b6e201a9249e6f new file mode 100755 index 0000000..e894fb3 Binary files /dev/null and b/storage/textures/fdd407e17cb7436fd33b4a86c55d72ec13e6f853f26d833360b6e201a9249e6f differ diff --git a/storage/textures/fe60a01777d201d85c410693aee95fbe616e4387feaf2ca336ee7c9f63c30bc5 b/storage/textures/fe60a01777d201d85c410693aee95fbe616e4387feaf2ca336ee7c9f63c30bc5 new file mode 100755 index 0000000..cff7130 Binary files /dev/null and b/storage/textures/fe60a01777d201d85c410693aee95fbe616e4387feaf2ca336ee7c9f63c30bc5 differ diff --git a/storage/textures/fe9da85e2b5e4561616e5aed6d2f2f0a06fd87afac86d49bf84388d94b9b0b3c b/storage/textures/fe9da85e2b5e4561616e5aed6d2f2f0a06fd87afac86d49bf84388d94b9b0b3c new file mode 100755 index 0000000..e454b3c Binary files /dev/null and b/storage/textures/fe9da85e2b5e4561616e5aed6d2f2f0a06fd87afac86d49bf84388d94b9b0b3c differ diff --git a/storage/textures/fefe871a54484fcdc995ca4e66a10746823f3ea8ffc0df2f08e0f7f458f24de1 b/storage/textures/fefe871a54484fcdc995ca4e66a10746823f3ea8ffc0df2f08e0f7f458f24de1 new file mode 100755 index 0000000..f7fa08a Binary files /dev/null and b/storage/textures/fefe871a54484fcdc995ca4e66a10746823f3ea8ffc0df2f08e0f7f458f24de1 differ diff --git a/storage/textures/ff33bc8518c178c3bd8ddc457b69d74361b298e6b11ae3260c260cd21e29ee1b b/storage/textures/ff33bc8518c178c3bd8ddc457b69d74361b298e6b11ae3260c260cd21e29ee1b new file mode 100644 index 0000000..22ee6f7 Binary files /dev/null and b/storage/textures/ff33bc8518c178c3bd8ddc457b69d74361b298e6b11ae3260c260cd21e29ee1b differ diff --git a/storage/textures/ff6f21a227f10d097a740a4adbb8e79433d4a2886eb92a8d09feb8de8b3e528e b/storage/textures/ff6f21a227f10d097a740a4adbb8e79433d4a2886eb92a8d09feb8de8b3e528e new file mode 100755 index 0000000..e13f0c0 Binary files /dev/null and b/storage/textures/ff6f21a227f10d097a740a4adbb8e79433d4a2886eb92a8d09feb8de8b3e528e differ diff --git a/storage/textures/ffdb6f14f40a54580d8b9cd431ba271f7288bbea18b8350f472c235a96ac58da b/storage/textures/ffdb6f14f40a54580d8b9cd431ba271f7288bbea18b8350f472c235a96ac58da new file mode 100644 index 0000000..d8c3c56 Binary files /dev/null and b/storage/textures/ffdb6f14f40a54580d8b9cd431ba271f7288bbea18b8350f472c235a96ac58da differ diff --git a/storage/textures/ffe44f22b269d54ee8b18d9eb18ad81ba7485010a4749596f0a1497822373168 b/storage/textures/ffe44f22b269d54ee8b18d9eb18ad81ba7485010a4749596f0a1497822373168 new file mode 100755 index 0000000..0fa7d1b Binary files /dev/null and b/storage/textures/ffe44f22b269d54ee8b18d9eb18ad81ba7485010a4749596f0a1497822373168 differ diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100755 index 0000000..e9df40c --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,12 @@ +in('src') + ->in('tests') +; + +return PhpCsFixer\Config::create() + ->setRules([ + '@Symfony' => true, + 'align_multiline_comment' => true, + 'array_syntax' => ['syntax' => 'short'], + 'increment_style' => ['style' => 'post'], + 'list_syntax' => ['syntax' => 'short'], + 'yoda_style' => false, + + ]) + ->setFinder($finder) +; diff --git a/vendor/blessing/filter/CHANGELOG.md b/vendor/blessing/filter/CHANGELOG.md new file mode 100755 index 0000000..f9393e4 --- /dev/null +++ b/vendor/blessing/filter/CHANGELOG.md @@ -0,0 +1,11 @@ +## v1.1.1 + +- Fix compatibility with Laravel v7.7.0. + +## v1.1.0 + +- Support Laravel v7. + +## v1.0.0 + +- Initial release. diff --git a/vendor/blessing/filter/LICENSE b/vendor/blessing/filter/LICENSE new file mode 100755 index 0000000..579be77 --- /dev/null +++ b/vendor/blessing/filter/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-present The Blessing Skin Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/blessing/filter/README.md b/vendor/blessing/filter/README.md new file mode 100755 index 0000000..77cecd1 --- /dev/null +++ b/vendor/blessing/filter/README.md @@ -0,0 +1,126 @@ +# filters + +Filters API for designing and creating plugin system, within Laravel. + +> We used this in Blessing Skin Server. + +The "Filters API" is similar with Filters API of WordPress, but comes with different API. +And this package is designed for Laravel, so it may not work if you use it without Laravel. + +## 💿 Install + +Run Composer: + +``` +composer require blessing/filter +``` + +## 🔨 Usage + +With Laravel's Auto-Discovery, you don't need to configure your Laravel application manually. + +Currently this package doesn't provide Facade. +You must get instance by using type-hint in your controllers or using global `resolve()` helper function. + +For example: + +```php +use Blessing\Filter; + +class MyController extends Controller +{ + public function home(Filter $filter) + { + // + } +} +``` + +### Add a filter + +To add a filter for a specified hook, just call the `add` method: + +```php +$filter->add('hook_name', function ($value) { + return $value; +}); +``` + +Note that the filter handler must return a value; otherwise, the value after applied will be `null`. + +You also can pass a class which has a public method called `filter` as handler. + +```php +class MyFilter +{ + public function filter($value) + { + return $value; + } +} + +$filter->add('hook_name', MyFilter::class); +// or +$filter->add('hook_name', 'MyFilter'); +``` + +The class will be resolved from Laravel's service container, +so you can use type-hint at the constructor of your class to resolve dependencies. + +Additionally, you can specify the priority for your filter handler. +Higher integer value indicates that it should come with higher priority. + +Default priority is `20`. + +```php +$filter->add('hook_name', function ($value) { + return $value; +}, 30); // Higher than default priority. +``` + +### Apply a hook + +You can call `apply` method to apply a hook: + +```php +$value = $filter->apply('hook_name', 'hi'); +``` + +Then, the second argument you passed will be manipulated by filters. + +Also, you can pass additional arguments as an array: + +```php +$value = $filter->apply('hook_name', 'hi', [$arg1, $arg2]); +``` + +Those additional arguments **won't** be manipulated by filters. + +### Remove all filters + +To remove all filters for a specified hook, just: + +```php +$filter->remove('hook_name'); +``` + +### Totally... + +This is a full example: + +```php +$filter->add('hook_name', function ($value, $arg1, $arg2) { + if ($arg1 === '...') { + return $value; + } + + return $value.'!'; +}); + +$value = $filter->apply('hook_name', 'hi', ['abc', 'def']); +// You should get the text "hi!" here. +``` + +## 📄 License + +MIT License (c) The Blessing Skin Team diff --git a/vendor/blessing/filter/composer.json b/vendor/blessing/filter/composer.json new file mode 100755 index 0000000..8ec6c62 --- /dev/null +++ b/vendor/blessing/filter/composer.json @@ -0,0 +1,46 @@ +{ + "name": "blessing/filter", + "description": "Filters API for designing plugin system.", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Pig Fang", + "email": "g-plane@hotmail.com" + } + ], + "keywords": [ + "filters", + "laravel", + "wordpress" + ], + "require": { + "illuminate/contracts": "^6 || ^7 || ^8", + "illuminate/support": "^6 || ^7 || ^8" + }, + "require-dev": { + "illuminate/container": "^6 || ^7 || ^8", + "phpunit/phpunit": "~9.0" + }, + "autoload": { + "psr-4": { + "Blessing\\": "src/Blessing" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "config": { + "sort-packages": true + }, + "extra": { + "laravel": { + "providers": [ + "Blessing\\FilterServiceProvider" + ] + } + }, + "minimum-stability": "stable" +} diff --git a/vendor/blessing/filter/phpunit.xml b/vendor/blessing/filter/phpunit.xml new file mode 100755 index 0000000..73ccce6 --- /dev/null +++ b/vendor/blessing/filter/phpunit.xml @@ -0,0 +1,13 @@ + + + + + src/Blessing + + + + + ./tests + + + diff --git a/vendor/blessing/filter/src/Blessing/Filter.php b/vendor/blessing/filter/src/Blessing/Filter.php new file mode 100755 index 0000000..457cddf --- /dev/null +++ b/vendor/blessing/filter/src/Blessing/Filter.php @@ -0,0 +1,89 @@ +container = $container; + } + + /** + * Add one filter to a specified hook. + * + * @param string $hook the hook to be listened + * @param mixed $filter filter handler + * @param int $priority Priority for this filter. Higher value is with higher priority. + */ + public function add(string $hook, $filter, $priority = 20): void + { + if (!isset($this->listeners[$hook])) { + $this->listeners[$hook] = new Collection(); + } + + $this->listeners[$hook]->push([ + 'filter' => $filter, + 'priority' => $priority, + ]); + } + + /** + * Apply a hook with initial value and additional arguments. + * + * @param string $hook hook name + * @param mixed $init initial value + * @param array $args additional arguments + */ + public function apply(string $hook, $init, $args = []) + { + $listeners = $this->getListeners($hook); + if ($listeners->isNotEmpty()) { + return $this->listeners[$hook] + ->sortBy('priority') + ->reduce(function ($carry, $item) use ($args) { + $arguments = array_merge([], [$carry], $args); + + $filter = $item['filter']; + if (is_callable($filter)) { + return call_user_func_array($item['filter'], $arguments); + } + + $instance = $this->container->make($item['filter']); + + return call_user_func_array([$instance, 'filter'], $arguments); + }, $init); + } else { + return $init; + } + } + + /** + * Remove all filter listeners for a specified hook. + * + * @param string $hook hook name + */ + public function remove(string $hook): void + { + unset($this->listeners[$hook]); + } + + /** + * Get all listeners for a specified hook. + * + * @param string $hook hook name + */ + public function getListeners(string $hook): Collection + { + return Arr::get($this->listeners, $hook, new Collection()); + } +} diff --git a/vendor/blessing/filter/src/Blessing/FilterServiceProvider.php b/vendor/blessing/filter/src/Blessing/FilterServiceProvider.php new file mode 100755 index 0000000..eff781d --- /dev/null +++ b/vendor/blessing/filter/src/Blessing/FilterServiceProvider.php @@ -0,0 +1,17 @@ +app->singleton(Filter::class); + } + + public function boot() + { + } +} diff --git a/vendor/blessing/filter/tests/Dependency.php b/vendor/blessing/filter/tests/Dependency.php new file mode 100755 index 0000000..0117fe9 --- /dev/null +++ b/vendor/blessing/filter/tests/Dependency.php @@ -0,0 +1,7 @@ +dependency = $dependency; + } + + public function filter($value) + { + return $this->dependency instanceof Dependency; + } +} diff --git a/vendor/blessing/filter/tests/FilterTest.php b/vendor/blessing/filter/tests/FilterTest.php new file mode 100755 index 0000000..cf65c5c --- /dev/null +++ b/vendor/blessing/filter/tests/FilterTest.php @@ -0,0 +1,66 @@ +add('hook', function () { + }); + $filter->add('hook', function () { + }, 10); + $this->assertCount(2, $filter->getListeners('hook')); + } + + public function testApply() + { + $filter = new Filter(new Container()); + $this->assertEquals('value', $filter->apply('hook', 'value', ['add'])); + + $filter->add('hook', function ($value, $addition) { + $this->assertEquals('add', $addition); + + return $value.'_medium'; + }); + $filter->add('hook', function ($value) { + return $value.'_low'; + }, 10); + $filter->add('hook', function ($value) { + return $value.'_high'; + }, 30); + $this->assertEquals('value_low_medium_high', $filter->apply('hook', 'value', ['add'])); + } + + public function testRemove() + { + $filter = new Filter(new Container()); + $filter->remove('hook'); + $this->assertCount(0, $filter->getListeners('hook')); + + $filter->add('hook', function () { + }); + $this->assertCount(1, $filter->getListeners('hook')); + $filter->remove('hook'); + $this->assertCount(0, $filter->getListeners('hook')); + } + + public function testGetListeners() + { + $filter = new Filter(new Container()); + $this->assertCount(0, $filter->getListeners('hook')); + } + + public function testResolveFromContainer() + { + $filter = new Filter(new Container()); + $filter->add('hook', FilterClass::class); + + $this->assertTrue($filter->apply('hook', 'value')); + } +} diff --git a/vendor/blessing/filter/tests/ServiceProviderTest.php b/vendor/blessing/filter/tests/ServiceProviderTest.php new file mode 100755 index 0000000..565080a --- /dev/null +++ b/vendor/blessing/filter/tests/ServiceProviderTest.php @@ -0,0 +1,28 @@ +instance( + \Illuminate\Contracts\Container\Container::class, + $container + ); + $provider = new FilterServiceProvider($container); + + $provider->register(); + $provider->boot(); + + $instance = $container->make(Filter::class); + $this->assertInstanceof(Filter::class, $instance); + $this->assertSame($instance, $container->make(Filter::class)); + } +} diff --git a/vendor/blessing/rejection/.editorconfig b/vendor/blessing/rejection/.editorconfig new file mode 100755 index 0000000..f2e0939 --- /dev/null +++ b/vendor/blessing/rejection/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[composer.*] +indent_size = 4 + +[*.{php,md}] +indent_size = 4 diff --git a/vendor/blessing/rejection/.github/workflows/CI.yml b/vendor/blessing/rejection/.github/workflows/CI.yml new file mode 100755 index 0000000..1aa6f8b --- /dev/null +++ b/vendor/blessing/rejection/.github/workflows/CI.yml @@ -0,0 +1,44 @@ +name: CI + +on: [push, pull_request] + +jobs: + php: + name: PHP ${{ matrix.php }} Tests + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, 'skip ci')" + strategy: + fail-fast: false + matrix: + php: ['7.3', '7.4'] + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup PHP only + uses: shivammathur/setup-php@v2 + if: matrix.php != '7.3' + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + - name: Setup PHP with Xdebug + uses: shivammathur/setup-php@v2 + if: matrix.php == '7.3' + with: + php-version: ${{ matrix.php }} + coverage: xdebug + extensions: mbstring + - name: Install Composer dependencies + run: composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader + - name: Run tests only + if: matrix.php != '7.3' + run: ./vendor/bin/phpunit + - name: Run tests with coverage report + if: matrix.php == '7.3' + run: ./vendor/bin/phpunit --coverage-clover=coverage.xml + - name: Upload coverage report + uses: codecov/codecov-action@v1 + if: matrix.php == '7.3' && success() + with: + token: ${{ secrets.CODECOV_TOKEN }} + name: github-actions diff --git a/vendor/blessing/rejection/.gitignore b/vendor/blessing/rejection/.gitignore new file mode 100755 index 0000000..1d9fc01 --- /dev/null +++ b/vendor/blessing/rejection/.gitignore @@ -0,0 +1,5 @@ +composer.lock +vendor/ +coverage/ +.phpunit.result.cache +.php_cs.cache diff --git a/vendor/blessing/rejection/.php_cs.dist b/vendor/blessing/rejection/.php_cs.dist new file mode 100755 index 0000000..f576514 --- /dev/null +++ b/vendor/blessing/rejection/.php_cs.dist @@ -0,0 +1,19 @@ +in('src') + ->in('tests') +; + +return PhpCsFixer\Config::create() + ->setRules([ + '@Symfony' => true, + 'align_multiline_comment' => true, + 'array_syntax' => ['syntax' => 'short'], + 'increment_style' => ['style' => 'post'], + 'list_syntax' => ['syntax' => 'short'], + 'yoda_style' => false, + + ]) + ->setFinder($finder) +; diff --git a/vendor/blessing/rejection/LICENSE b/vendor/blessing/rejection/LICENSE new file mode 100755 index 0000000..579be77 --- /dev/null +++ b/vendor/blessing/rejection/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-present The Blessing Skin Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/blessing/rejection/README.md b/vendor/blessing/rejection/README.md new file mode 100755 index 0000000..56aefae --- /dev/null +++ b/vendor/blessing/rejection/README.md @@ -0,0 +1,52 @@ +# rejection + +Rejection is an object that indicates you are rejecting. + +> We used this in Blessing Skin Server for plugins. + +## 💿 Install + +Run Composer: + +``` +composer require blessing/rejection +``` + +## 🔨 Usage + +### Create a rejection + +```php +use Blessing\Rejection; + +$rejection = new Rejection('reason'); +``` + +You can pass optional second argument to constructor: + +```php +$rejection = new Rejection('reason', ['name' => '']); +``` + +### Retrieve reason + +```php +$rejection->getReason(); +``` + +### Retrieve data: + +```php +$rejection->getData(); +``` + +If your data is an array, you pass a key: + +```php +$rejection = new Rejection('reason', ['name' => '']); +$rejection->getData('name'); +``` + +## 📄 License + +MIT License (c) The Blessing Skin Team diff --git a/vendor/blessing/rejection/composer.json b/vendor/blessing/rejection/composer.json new file mode 100755 index 0000000..2281384 --- /dev/null +++ b/vendor/blessing/rejection/composer.json @@ -0,0 +1,32 @@ +{ + "name": "blessing/rejection", + "description": "Rejection is an object that indicates you are rejecting.", + "license": "MIT", + "authors": [ + { + "name": "Pig Fang", + "email": "g-plane@hotmail.com" + } + ], + "type": "library", + "require": { + "illuminate/support": "^6 || ^7 || ^8" + }, + "require-dev": { + "phpunit/phpunit": "~9.0" + }, + "autoload": { + "psr-4": { + "Blessing\\": "src/Blessing" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests" + } + }, + "config": { + "sort-packages": true + }, + "minimum-stability": "stable" +} diff --git a/vendor/blessing/rejection/phpunit.xml b/vendor/blessing/rejection/phpunit.xml new file mode 100755 index 0000000..4e8afa8 --- /dev/null +++ b/vendor/blessing/rejection/phpunit.xml @@ -0,0 +1,13 @@ + + + + + src/Blessing + + + + + ./tests + + + diff --git a/vendor/blessing/rejection/src/Blessing/Rejection.php b/vendor/blessing/rejection/src/Blessing/Rejection.php new file mode 100755 index 0000000..ea2e0d8 --- /dev/null +++ b/vendor/blessing/rejection/src/Blessing/Rejection.php @@ -0,0 +1,34 @@ +reason = $reason; + $this->data = $data; + } + + public function getReason(): string + { + return $this->reason; + } + + public function getData($key = null, $default = null) + { + if (is_null($key)) { + return $this->data; + } + + return Arr::get($this->data, $key, $default); + } +} diff --git a/vendor/blessing/rejection/tests/RejectionTest.php b/vendor/blessing/rejection/tests/RejectionTest.php new file mode 100755 index 0000000..239f834 --- /dev/null +++ b/vendor/blessing/rejection/tests/RejectionTest.php @@ -0,0 +1,28 @@ +assertEquals($reason, $rejection->getReason()); + } + + public function testGetData() + { + $rejection = new Rejection('', 'data'); + $this->assertEquals('data', $rejection->getData()); + + $rejection = new Rejection('', ['a' => 'b']); + $this->assertEquals('b', $rejection->getData('a')); + $this->assertNull($rejection->getData('nope')); + $this->assertEquals('default', $rejection->getData('nope', 'default')); + $this->assertEquals(['a' => 'b'], $rejection->getData()); + } +} diff --git a/vendor/blessing/texture-renderer/.editorconfig b/vendor/blessing/texture-renderer/.editorconfig new file mode 100755 index 0000000..3c44241 --- /dev/null +++ b/vendor/blessing/texture-renderer/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/vendor/blessing/texture-renderer/.gitignore b/vendor/blessing/texture-renderer/.gitignore new file mode 100755 index 0000000..7579f74 --- /dev/null +++ b/vendor/blessing/texture-renderer/.gitignore @@ -0,0 +1,2 @@ +vendor +composer.lock diff --git a/vendor/blessing/texture-renderer/LICENSE b/vendor/blessing/texture-renderer/LICENSE new file mode 100755 index 0000000..1dd1ed5 --- /dev/null +++ b/vendor/blessing/texture-renderer/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-present The Blessing Skin Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/blessing/texture-renderer/README.md b/vendor/blessing/texture-renderer/README.md new file mode 100755 index 0000000..c330dbe --- /dev/null +++ b/vendor/blessing/texture-renderer/README.md @@ -0,0 +1,79 @@ +# texture-renderer + +Minecraft texture renderer written in pure PHP. + +## Install + +``` +composer require blessing/texture-renderer +``` + +## Usage + +At all the code examples below, we assume you've prepared your texture source as the variable `$source`. +The source can be a file path, a URL, or a string represents texture binary. + +### High Level API + +All the high level APIs will return a GD resource. + +```php +use Blessing\Minecraft; + +$m = new Minecraft(); +$resource = $m->renderSkin($source, /* optional */ $ratio, /* optional */ $isAlex); +$resource = $m->renderCape($source, $height); +$resource = $m->render2dAvatar($source, /* optional */ $ratio); +$resource = $m->render3dAvatar($source, /* optional */ $ratio); +``` + +### Low Level API + +This library contains two renderers: skin renderer and cape renderer. + +#### Skin Renderer + +The constructor of the skin renderer can accept many parameters (all are optional). +For example, you can specify `$ratio`, `$headOnly`, `$horizontalRotation`, `$verticalRotation`. +For details, please check out the source code. + +```php +use Blessing\Renderer\SkinRenderer; + +$renderer = new SkinRenderer(); +$resource = $renderer->render($source, $isAlex); // returns GD resource +``` + +As you can see above, the second parameter of the `render` method will tell the renderer +whether your texture is of Alex model or not. Default value is `false`. + +#### Cape Renderer + +Two arguments below are necessary. + +The `$height` stands for the height of rendered image. + +```php +use Blessing\Renderer\CapeRenderer; + +$renderer = new CapeRenderer(); +$resource = $renderer->render($source, $height); // returns GD resource +``` + +### Utility Functions + +#### `isAlex` + +This utility can be used to detect if a texture is an alex texture. + +```php +use Blessing\Renderer\TextureUtil; + +$isAlex = TextureUtil::isAlex($texture); // returns bool type +``` + +## License + +MIT License + +2020-present (c) The Blessing Skin Team diff --git a/vendor/blessing/texture-renderer/composer.json b/vendor/blessing/texture-renderer/composer.json new file mode 100755 index 0000000..bae61e7 --- /dev/null +++ b/vendor/blessing/texture-renderer/composer.json @@ -0,0 +1,22 @@ +{ + "name": "blessing/texture-renderer", + "description": "Minecraft texture renderer.", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Pig Fang", + "email": "g-plane@hotmail.com" + } + ], + "require": { + "ext-gd": "*", + "intervention/image": "^2.5" + }, + "autoload": { + "psr-4": { + "Blessing\\": "src/Blessing" + } + }, + "minimum-stability": "stable" +} diff --git a/vendor/blessing/texture-renderer/src/Blessing/Minecraft.php b/vendor/blessing/texture-renderer/src/Blessing/Minecraft.php new file mode 100755 index 0000000..10d5ea4 --- /dev/null +++ b/vendor/blessing/texture-renderer/src/Blessing/Minecraft.php @@ -0,0 +1,82 @@ +render($skin, $isAlex); + + $renderer = new SkinRenderer($ratio, false, 135); + $back = $renderer->render($skin, $isAlex); + + $width = imagesx($front); + $height = imagesy($front); + + $canvas = ImageUtil::createEmptyCanvas(($hp + $width + $ip) * 2, $vp * 2 + $height); + + imagecopy($canvas, $back, $hp, $vp, 0, 0, $width, $height); + imagecopy($canvas, $front, $hp + $width + $ip * 2, $vp, 0, 0, $width, $height); + + imagedestroy($front); + imagedestroy($back); + + return $canvas; + } + + /** + * @return resource|false + */ + public function renderCape($cape, int $height) + { + $vp = 20; // vertical padding + $hp = 40; // horizontal padding + + $renderer = new CapeRenderer(); + $cape = $renderer->render($cape, $height); + $width = imagesx($cape); + $height = imagesy($cape); + + $canvas = ImageUtil::createEmptyCanvas($hp * 2 + $width, $vp * 2 + $height); + imagecopy($canvas, $cape, $hp, $vp, 0, 0, $width, $height); + + imagedestroy($cape); + + return $canvas; + } + + /** + * @return resource|false + */ + public function render2dAvatar($skin, $ratio = 15.0) + { + $renderer = new SkinRenderer($ratio, true, 0, 0); + $avatar = $renderer->render($skin); + + return $avatar; + } + + /** + * @return resource|false + */ + public function render3dAvatar($skin, $ratio = 15.0) + { + $renderer = new SkinRenderer($ratio, true, 45); + $avatar = $renderer->render($skin); + + return $avatar; + } +} diff --git a/vendor/blessing/texture-renderer/src/Blessing/Renderer/CapeRenderer.php b/vendor/blessing/texture-renderer/src/Blessing/Renderer/CapeRenderer.php new file mode 100755 index 0000000..b9edbff --- /dev/null +++ b/vendor/blessing/texture-renderer/src/Blessing/Renderer/CapeRenderer.php @@ -0,0 +1,23 @@ + 'gd']); + + return $manager->make($source)->getCore(); + } + + public static function createEmptyCanvas($width, $height) + { + $dst = imagecreatetruecolor($width, $height); + imagesavealpha($dst, true); + $trans_color = imagecolorallocatealpha($dst, 255, 255, 255, 127); + imagefill($dst, 0, 0, $trans_color); + + return $dst; + } + + public static function convertToTrueColor($img) + { + if (imageistruecolor($img)) { + return $img; + } + + $dst = ImageUtil::createEmptyCanvas(imagesx($img), imagesy($img)); + + imagecopy($dst, $img, 0, 0, 0, 0, imagesx($img), imagesy($img)); + imagedestroy($img); + + return $dst; + } +} diff --git a/vendor/blessing/texture-renderer/src/Blessing/Renderer/LICENSE b/vendor/blessing/texture-renderer/src/Blessing/Renderer/LICENSE new file mode 100755 index 0000000..b204822 --- /dev/null +++ b/vendor/blessing/texture-renderer/src/Blessing/Renderer/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2012, Pierre Gros +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + The names of its contributors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/blessing/texture-renderer/src/Blessing/Renderer/Point.php b/vendor/blessing/texture-renderer/src/Blessing/Renderer/Point.php new file mode 100755 index 0000000..d542f43 --- /dev/null +++ b/vendor/blessing/texture-renderer/src/Blessing/Renderer/Point.php @@ -0,0 +1,80 @@ +originCoord = array( + 'x' => (isset($originCoord['x']) ? $originCoord['x'] : 0), + 'y' => (isset($originCoord['y']) ? $originCoord['y'] : 0), + 'z' => (isset($originCoord['z']) ? $originCoord['z'] : 0) + ); + } else { + $this->originCoord = array( + 'x' => 0, + 'y' => 0, + 'z' => 0 + ); + } + } + + public function project($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, &$minX, &$maxX, &$minY, &$maxY) + { + // 1, 0, 1, 0 + $x = $this->originCoord['x']; + $y = $this->originCoord['y']; + $z = $this->originCoord['z']; + $this->destCoord['x'] = $x * $cos_omega + $z * $sin_omega; + $this->destCoord['y'] = $x * $sin_alpha * $sin_omega + $y * $cos_alpha - $z * $sin_alpha * $cos_omega; + $this->destCoord['z'] = -$x * $cos_alpha * $sin_omega + $y * $sin_alpha + $z * $cos_alpha * $cos_omega; + $this->isProjected = true; + $minX = min($minX, $this->destCoord['x']); + $maxX = max($maxX, $this->destCoord['x']); + $minY = min($minY, $this->destCoord['y']); + $maxY = max($maxY, $this->destCoord['y']); + } + + public function preProject($dx, $dy, $dz, $cos_alpha, $sin_alpha, $cos_omega, $sin_omega) + { + if (!$this->isPreProjected) { + $x = $this->originCoord['x'] - $dx; + $y = $this->originCoord['y'] - $dy; + $z = $this->originCoord['z'] - $dz; + $this->originCoord['x'] = $x * $cos_omega + $z * $sin_omega + $dx; + $this->originCoord['y'] = $x * $sin_alpha * $sin_omega + $y * $cos_alpha - $z * $sin_alpha * $cos_omega + $dy; + $this->originCoord['z'] = -$x * $cos_alpha * $sin_omega + $y * $sin_alpha + $z * $cos_alpha * $cos_omega + $dz; + $this->isPreProjected = true; + } + } + + public function getOriginCoord() + { + return $this->originCoord; + } + + public function getDestCoord() + { + return $this->destCoord; + } + + public function getDepth($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, &$minX, &$maxX, &$minY, &$maxY) + { + if (!$this->isProjected) { + $this->project($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, $minX, $maxX, $minY, $maxY); + } + return $this->destCoord['z']; + } + + public function isProjected() + { + return $this->isProjected; + } +} diff --git a/vendor/blessing/texture-renderer/src/Blessing/Renderer/Polygon.php b/vendor/blessing/texture-renderer/src/Blessing/Renderer/Polygon.php new file mode 100755 index 0000000..91a7c5a --- /dev/null +++ b/vendor/blessing/texture-renderer/src/Blessing/Renderer/Polygon.php @@ -0,0 +1,83 @@ +dots = $dots; + $this->color = $color; + $coord_0 = $dots[0]->getOriginCoord(); + $coord_1 = $dots[1]->getOriginCoord(); + $coord_2 = $dots[2]->getOriginCoord(); + if ($coord_0['x'] == $coord_1['x'] && $coord_1['x'] == $coord_2['x']) { + $this->_face = 'x'; + $this->_faceDepth = $coord_0['x']; + } elseif ($coord_0['y'] == $coord_1['y'] && $coord_1['y'] == $coord_2['y']) { + $this->_face = 'y'; + $this->_faceDepth = $coord_0['y']; + } elseif ($coord_0['z'] == $coord_1['z'] && $coord_1['z'] == $coord_2['z']) { + $this->_face = 'z'; + $this->_faceDepth = $coord_0['z']; + } + } + + public function addPngPolygon(&$image, $minX, $minY, $ratio) + { + $points_2d = array(); + $nb_points = 0; + $r = ($this->color >> 16) & 0xFF; + $g = ($this->color >> 8) & 0xFF; + $b = $this->color & 0xFF; + $vR = (127 - (($this->color & 0x7F000000) >> 24)) / 127; + if ($vR == 0) + return; + $same_plan_x = true; + $same_plan_y = true; + foreach ($this->dots as $dot) { + $coord = $dot->getDestCoord(); + if (!isset($coord_x)) + $coord_x = $coord['x']; + if (!isset($coord_y)) + $coord_y = $coord['y']; + if ($coord_x != $coord['x']) + $same_plan_x = false; + if ($coord_y != $coord['y']) + $same_plan_y = false; + $points_2d[] = ($coord['x'] - $minX) * $ratio; + $points_2d[] = ($coord['y'] - $minY) * $ratio; + $nb_points++; + } + if (!($same_plan_x || $same_plan_y)) { + $colour = imagecolorallocate($image, $r, $g, $b); + imagefilledpolygon($image, $points_2d, $nb_points, $colour); + } + } + + public function isProjected() + { + return $this->isProjected; + } + + public function project($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, &$minX, &$maxX, &$minY, &$maxY) + { + foreach ($this->dots as &$dot) { + if (!$dot->isProjected()) { + $dot->project($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, $minX, $maxX, $minY, $maxY); + } + } + $this->isProjected = true; + } + + public function preProject($dx, $dy, $dz, $cos_alpha, $sin_alpha, $cos_omega, $sin_omega) + { + foreach ($this->dots as &$dot) { + $dot->preProject($dx, $dy, $dz, $cos_alpha, $sin_alpha, $cos_omega, $sin_omega); + } + } +} diff --git a/vendor/blessing/texture-renderer/src/Blessing/Renderer/README.md b/vendor/blessing/texture-renderer/src/Blessing/Renderer/README.md new file mode 100755 index 0000000..d061f68 --- /dev/null +++ b/vendor/blessing/texture-renderer/src/Blessing/Renderer/README.md @@ -0,0 +1,12 @@ +# About The Skin Renderer + +Project first developed by [supermamie](https://github.com/supermamie), +and [here](https://github.com/supermamie/php-Minecraft-3D-skin) is original project. +The open source license of that original project is [BSD-3-Clause](https://github.com/supermamie/php-Minecraft-3D-skin/blob/7b50bc7a439adb1fb9c5a4f65b8db0e5484de95d/3d.php#L2-L26) and please see the license file at this directory. + +Later translated to English by [cajogos](https://github.com/cajogos), and project is [here](https://github.com/cajogos/php-Minecraft-3D-Skin-Renderer). + +Later modified by [Gyzie](https://github.com/Gyzie), and project is [here](https://github.com/Gyzie/php-Minecraft-3D-Skin-Renderer). + +Now the project is modified by [GPlane](https://github.com/g-plane). It fixed for Alex model texture, not perfect currently. +The API is simplified and it supports different kinds of source image. diff --git a/vendor/blessing/texture-renderer/src/Blessing/Renderer/SkinRenderer.php b/vendor/blessing/texture-renderer/src/Blessing/Renderer/SkinRenderer.php new file mode 100755 index 0000000..4b9397e --- /dev/null +++ b/vendor/blessing/texture-renderer/src/Blessing/Renderer/SkinRenderer.php @@ -0,0 +1,1498 @@ +ratio = $ratio; + $this->head_only = $headOnly; + $this->hR = $horizontalRotation; + $this->vR = $verticalRotation; + $this->hrh = $horizontalRotationOfHead; + $this->vrll = $verticalRotationOfLeftLeg; + $this->vrrl = $verticalRotationOfRightLeg; + $this->vrla = $verticalRotationOfLeftArm; + $this->vrra = $verticalRotationOfRightArm; + $this->layers = $layers; + } + + public function render($source, $isAlex = false) + { + $this->playerSkin = ImageUtil::initGdResource($source); + + $sourceWidth = imagesx($this->playerSkin); + $sourceHeight = imagesy($this->playerSkin); + + // prevent memory overflow + if ($sourceWidth > 256) { + $newHeight = $sourceHeight / ($sourceWidth / 256); + $dest = ImageUtil::createEmptyCanvas(256, $newHeight); + imagecopyresampled($dest, $this->playerSkin, 0, 0, 0, 0, 256, $newHeight, $sourceWidth, $sourceHeight); + $this->playerSkin = $dest; + } + + $this->isAlex = $isAlex; + $this->hd_ratio = imagesx($this->playerSkin) / 64; // Set HD ratio to 2 if the skin is 128x64. Check via width, not height because of new skin type. + + // check if new skin type. If both sides are equaly long: new skin type + if (imagesx($this->playerSkin) === imagesy($this->playerSkin)) { + $this->isNewSkinType = true; + } + + $this->playerSkin = ImageUtil::convertToTrueColor($this->playerSkin); // Convert the image to true color if not a true color image + $this->makeBackgroundTransparent(); // make background transparent (fix for weird rendering skins) + + // Quick fix for 1.8: + // Copy the extra layers ontop of the base layers + if ($this->layers) { + $this->fixNewSkinTypeLayers(); + } + + $this->calculateAngles(); + $this->facesDetermination(); + $this->generatePolygons(); + $this->memberRotation(); + $this->createProjectionPlan(); + $image = $this->displayImage(); + + imagedestroy($this->playerSkin); + + return $image; + } + + private function makeBackgroundTransparent() + { + // check if the corner box is one solid color + $tempValue = null; + $needRemove = true; + + for ($iH = 0; $iH < 8; $iH++) { + for ($iV = 0; $iV < 8; $iV++) { + $pixelColor = imagecolorat($this->playerSkin, $iH, $iV); + + $indexColor = imagecolorsforindex($this->playerSkin, $pixelColor); + if ($indexColor['alpha'] > 120) { + // the image contains transparancy, noting to do + $needRemove = false; + } + + if ($tempValue === null) { + $tempValue = $pixelColor; + } else if ($tempValue != $pixelColor) { + // Cannot determine a background color, file is probably fine + $needRemove = false; + } + } + } + + $imgX = imagesx($this->playerSkin); + $imgY = imagesy($this->playerSkin); + + $dst = ImageUtil::createEmptyCanvas($imgX, $imgY); + + imagesavealpha($this->playerSkin, false); + + if ($needRemove) { + // the entire block is one solid color. Use this color to clear the background. + $r = ($tempValue >> 16) & 0xFF; + $g = ($tempValue >> 8) & 0xFF; + $b = $tempValue & 0xFF; + + + //imagealphablending($dst, true); + $transparant = imagecolorallocate($this->playerSkin, $r, $g, $b); + imagecolortransparent($this->playerSkin, $transparant); + + // create fill + $color = imagecolorallocate($dst, $r, $g, $b); + } else { + // create fill + $color = imagecolorallocate($dst, 0, 0, 0); + } + + // fill the areas that should not be transparant + $positionMultiply = $imgX / 64; + + // head + imagefilledrectangle($dst, 8 * $positionMultiply, 0 * $positionMultiply, 23 * $positionMultiply, 7 * $positionMultiply, $color); + imagefilledrectangle($dst, 0 * $positionMultiply, 8 * $positionMultiply, 31 * $positionMultiply, 15 * $positionMultiply, $color); + + // right leg, body, right arm + imagefilledrectangle($dst, 4 * $positionMultiply, 16 * $positionMultiply, 11 * $positionMultiply, 19 * $positionMultiply, $color); + imagefilledrectangle($dst, 20 * $positionMultiply, 16 * $positionMultiply, 35 * $positionMultiply, 19 * $positionMultiply, $color); + imagefilledrectangle($dst, 44 * $positionMultiply, 16 * $positionMultiply, 51 * $positionMultiply, 19 * $positionMultiply, $color); + imagefilledrectangle($dst, 0 * $positionMultiply, 20 * $positionMultiply, 54 * $positionMultiply, 31 * $positionMultiply, $color); + + // left leg, left arm + imagefilledrectangle($dst, 20 * $positionMultiply, 48 * $positionMultiply, 27 * $positionMultiply, 51 * $positionMultiply, $color); + imagefilledrectangle($dst, 36 * $positionMultiply, 48 * $positionMultiply, 43 * $positionMultiply, 51 * $positionMultiply, $color); + imagefilledrectangle($dst, 16 * $positionMultiply, 52 * $positionMultiply, 47 * $positionMultiply, 63 * $positionMultiply, $color); + + imagecopy($dst, $this->playerSkin, 0, 0, 0, 0, $imgX, $imgY); + + $this->playerSkin = $dst; + return; + } + + /* Function copys the extra layers of a 1.8 skin + * onto the base layers so that it will still show. QUICK FIX, NEEDS BETTER FIX + * + * Espects an image. + * Returns a croped image. + */ + private function fixNewSkinTypeLayers() + { + if (!$this->isNewSkinType) { + return; + } + + imagecopy($this->playerSkin, $this->playerSkin, 0, 16, 0, 32, 56, 16); // RL2, BODY2, RA2 + imagecopy($this->playerSkin, $this->playerSkin, 16, 48, 0, 48, 16, 16); // LL2 + imagecopy($this->playerSkin, $this->playerSkin, 32, 48, 48, 48, 16, 16); // LA2 + } + + private function calculateAngles() + { + // Rotation variables in radians (3D Rendering) + $this->alpha = deg2rad($this->vR); // Vertical rotation on the X axis. + $this->omega = deg2rad($this->hR); // Horizontal rotation on the Y axis. + + // Cosine and Sine values + $this->cos_alpha = cos($this->alpha); + $this->sin_alpha = sin($this->alpha); + $this->cos_omega = cos($this->omega); + $this->sin_omega = sin($this->omega); + + $this->members_angles['torso'] = array( + 'cos_alpha' => cos(0), + 'sin_alpha' => sin(0), + 'cos_omega' => cos(0), + 'sin_omega' => sin(0) + ); + + $alpha_head = 0; + $omega_head = deg2rad($this->hrh); + $this->members_angles['head'] = $this->members_angles['helmet'] = array( // Head and helmet get the same calculations + 'cos_alpha' => cos($alpha_head), + 'sin_alpha' => sin($alpha_head), + 'cos_omega' => cos($omega_head), + 'sin_omega' => sin($omega_head) + ); + + $alpha_right_arm = deg2rad($this->vrra); + $omega_right_arm = 0; + $this->members_angles['rightArm'] = array( + 'cos_alpha' => cos($alpha_right_arm), + 'sin_alpha' => sin($alpha_right_arm), + 'cos_omega' => cos($omega_right_arm), + 'sin_omega' => sin($omega_right_arm) + ); + + $alpha_left_arm = deg2rad($this->vrla); + $omega_left_arm = 0; + $this->members_angles['leftArm'] = array( + 'cos_alpha' => cos($alpha_left_arm), + 'sin_alpha' => sin($alpha_left_arm), + 'cos_omega' => cos($omega_left_arm), + 'sin_omega' => sin($omega_left_arm) + ); + + $alpha_right_leg = deg2rad($this->vrrl); + $omega_right_leg = 0; + $this->members_angles['rightLeg'] = array( + 'cos_alpha' => cos($alpha_right_leg), + 'sin_alpha' => sin($alpha_right_leg), + 'cos_omega' => cos($omega_right_leg), + 'sin_omega' => sin($omega_right_leg) + ); + + $alpha_left_leg = deg2rad($this->vrll); + $omega_left_leg = 0; + $this->members_angles['leftLeg'] = array( + 'cos_alpha' => cos($alpha_left_leg), + 'sin_alpha' => sin($alpha_left_leg), + 'cos_omega' => cos($omega_left_leg), + 'sin_omega' => sin($omega_left_leg) + ); + $this->minX = 0; + $this->maxX = 0; + $this->minY = 0; + $this->maxY = 0; + } + + private function facesDetermination() + { + $cos_alpha = $this->cos_alpha; + $sin_alpha = $this->sin_alpha; + $cos_omega = $this->cos_omega; + $sin_omega = $this->sin_omega; + + $this->visible_faces_format = array( + 'front' => array(), + 'back' => array() + ); + + $this->visible_faces = array( + 'head' => $this->visible_faces_format, + 'torso' => $this->visible_faces_format, + 'rightArm' => $this->visible_faces_format, + 'leftArm' => $this->visible_faces_format, + 'rightLeg' => $this->visible_faces_format, + 'leftLeg' => $this->visible_faces_format + ); + + $this->all_faces = array( + 'back', + 'right', + 'top', + 'front', + 'left', + 'bottom' + ); + + // Loop each preProject and Project then calculate the visible faces for each - also display + foreach ($this->visible_faces as $k => &$v) { + unset($cube_max_depth_faces, $this->cube_points); + + $this->setCubePoints(); + + foreach ($this->cube_points as $cube_point) { + $cube_point[0]->preProject( + 0, + 0, + 0, + $this->members_angles[$k]['cos_alpha'], + $this->members_angles[$k]['sin_alpha'], + $this->members_angles[$k]['cos_omega'], + $this->members_angles[$k]['sin_omega'] + ); + $cube_point[0]->project($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, $this->minX, $this->maxX, $this->minY, $this->maxY); + + if (!isset($cube_max_depth_faces)) { + $cube_max_depth_faces = $cube_point; + } elseif ( + $cube_max_depth_faces[0]->getDepth($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, $this->minX, $this->maxX, $this->minY, $this->maxY) > + $cube_point[0]->getDepth($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, $this->minX, $this->maxX, $this->minY, $this->maxY) + ) { + $cube_max_depth_faces = $cube_point; + } + } + + $v['back'] = $cube_max_depth_faces[1]; + $v['front'] = array_diff($this->all_faces, $v['back']); + } + + $this->setCubePoints(); + + unset($cube_max_depth_faces); + foreach ($this->cube_points as $cube_point) { + $cube_point[0]->project($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, $this->minX, $this->maxX, $this->minY, $this->maxY); + + if (!isset($cube_max_depth_faces)) { + $cube_max_depth_faces = $cube_point; + } elseif ( + $cube_max_depth_faces[0]->getDepth($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, $this->minX, $this->maxX, $this->minY, $this->maxY) > + $cube_point[0]->getDepth($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, $this->minX, $this->maxX, $this->minY, $this->maxY) + ) { + $cube_max_depth_faces = $cube_point; + } + + $this->back_faces = $cube_max_depth_faces[1]; + $this->front_faces = array_diff($this->all_faces, $this->back_faces); + } + } + + private function setCubePoints() + { + $this->cube_points = []; + $this->cube_points[] = array( + new Point(array( + 'x' => 0, + 'y' => 0, + 'z' => 0 + )), array( + 'back', + 'right', + 'top' + ) + ); // 0 + + $this->cube_points[] = array( + new Point(array( + 'x' => 0, + 'y' => 0, + 'z' => 1 + )), array( + 'front', + 'right', + 'top' + ) + ); // 1 + + $this->cube_points[] = array( + new Point(array( + 'x' => 0, + 'y' => 1, + 'z' => 0 + )), array( + 'back', + 'right', + 'bottom' + ) + ); // 2 + + $this->cube_points[] = array( + new Point(array( + 'x' => 0, + 'y' => 1, + 'z' => 1 + )), array( + 'front', + 'right', + 'bottom' + ) + ); // 3 + + $this->cube_points[] = array( + new Point(array( + 'x' => 1, + 'y' => 0, + 'z' => 0 + )), array( + 'back', + 'left', + 'top' + ) + ); // 4 + + $this->cube_points[] = array( + new Point(array( + 'x' => 1, + 'y' => 0, + 'z' => 1 + )), array( + 'front', + 'left', + 'top' + ) + ); // 5 + + $this->cube_points[] = array( + new Point(array( + 'x' => 1, + 'y' => 1, + 'z' => 0 + )), array( + 'back', + 'left', + 'bottom' + ) + ); // 6 + + $this->cube_points[] = array( + new Point(array( + 'x' => 1, + 'y' => 1, + 'z' => 1 + )), array( + 'front', + 'left', + 'bottom' + ) + ); // 7 + } + + private function generatePolygons() + { + $this->polygons = array(); + $cube_faces_array = array( + 'front' => array(), + 'back' => array(), + 'top' => array(), + 'bottom' => array(), + 'right' => array(), + 'left' => array() + ); + + $this->polygons = array( + 'helmet' => $cube_faces_array, + 'head' => $cube_faces_array, + 'torso' => $cube_faces_array, + 'rightArm' => $cube_faces_array, + 'leftArm' => $cube_faces_array, + 'rightLeg' => $cube_faces_array, + 'leftLeg' => $cube_faces_array + ); + + $is_alex = $this->isAlex; + $hd_ratio = $this->hd_ratio; + $img_png = $this->playerSkin; + + // HEAD + $volume_points = array(); + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($j = 0; $j < 9 * $hd_ratio; $j++) { + if (!isset($volume_points[$i][$j][-2 * $hd_ratio])) { + $volume_points[$i][$j][-2 * $hd_ratio] = new Point(array( + 'x' => $i, + 'y' => $j, + 'z' => -2 * $hd_ratio + )); + } + if (!isset($volume_points[$i][$j][6 * $hd_ratio])) { + $volume_points[$i][$j][6 * $hd_ratio] = new Point(array( + 'x' => $i, + 'y' => $j, + 'z' => 6 * $hd_ratio + )); + } + } + } + for ($j = 0; $j < 9 * $hd_ratio; $j++) { + for ($k = -2 * $hd_ratio; $k < 7 * $hd_ratio; $k++) { + if (!isset($volume_points[0][$j][$k])) { + $volume_points[0][$j][$k] = new Point(array( + 'x' => 0, + 'y' => $j, + 'z' => $k + )); + } + if (!isset($volume_points[8 * $hd_ratio][$j][$k])) { + $volume_points[8 * $hd_ratio][$j][$k] = new Point(array( + 'x' => 8 * $hd_ratio, + 'y' => $j, + 'z' => $k + )); + } + } + } + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($k = -2 * $hd_ratio; $k < 7 * $hd_ratio; $k++) { + if (!isset($volume_points[$i][0][$k])) { + $volume_points[$i][0][$k] = new Point(array( + 'x' => $i, + 'y' => 0, + 'z' => $k + )); + } + if (!isset($volume_points[$i][8 * $hd_ratio][$k])) { + $volume_points[$i][8 * $hd_ratio][$k] = new Point(array( + 'x' => $i, + 'y' => 8 * $hd_ratio, + 'z' => $k + )); + } + } + } + for ($i = 0; $i < 8 * $hd_ratio; $i++) { + for ($j = 0; $j < 8 * $hd_ratio; $j++) { + $this->polygons['head']['back'][] = new Polygon(array( + $volume_points[$i][$j][-2 * $hd_ratio], + $volume_points[$i + 1][$j][-2 * $hd_ratio], + $volume_points[$i + 1][$j + 1][-2 * $hd_ratio], + $volume_points[$i][$j + 1][-2 * $hd_ratio] + ), imagecolorat($img_png, (32 * $hd_ratio - 1) - $i, 8 * $hd_ratio + $j)); + $this->polygons['head']['front'][] = new Polygon(array( + $volume_points[$i][$j][6 * $hd_ratio], + $volume_points[$i + 1][$j][6 * $hd_ratio], + $volume_points[$i + 1][$j + 1][6 * $hd_ratio], + $volume_points[$i][$j + 1][6 * $hd_ratio] + ), imagecolorat($img_png, 8 * $hd_ratio + $i, 8 * $hd_ratio + $j)); + } + } + for ($j = 0; $j < 8 * $hd_ratio; $j++) { + for ($k = -2 * $hd_ratio; $k < 6 * $hd_ratio; $k++) { + $this->polygons['head']['right'][] = new Polygon(array( + $volume_points[0][$j][$k], + $volume_points[0][$j][$k + 1], + $volume_points[0][$j + 1][$k + 1], + $volume_points[0][$j + 1][$k] + ), imagecolorat($img_png, $k + 2 * $hd_ratio, 8 * $hd_ratio + $j)); + $this->polygons['head']['left'][] = new Polygon(array( + $volume_points[8 * $hd_ratio][$j][$k], + $volume_points[8 * $hd_ratio][$j][$k + 1], + $volume_points[8 * $hd_ratio][$j + 1][$k + 1], + $volume_points[8 * $hd_ratio][$j + 1][$k] + ), imagecolorat($img_png, (24 * $hd_ratio - 1) - $k - 2 * $hd_ratio, 8 * $hd_ratio + $j)); + } + } + for ($i = 0; $i < 8 * $hd_ratio; $i++) { + for ($k = -2 * $hd_ratio; $k < 6 * $hd_ratio; $k++) { + $this->polygons['head']['top'][] = new Polygon(array( + $volume_points[$i][0][$k], + $volume_points[$i + 1][0][$k], + $volume_points[$i + 1][0][$k + 1], + $volume_points[$i][0][$k + 1] + ), imagecolorat($img_png, 8 * $hd_ratio + $i, $k + 2 * $hd_ratio)); + $this->polygons['head']['bottom'][] = new Polygon(array( + $volume_points[$i][8 * $hd_ratio][$k], + $volume_points[$i + 1][8 * $hd_ratio][$k], + $volume_points[$i + 1][8 * $hd_ratio][$k + 1], + $volume_points[$i][8 * $hd_ratio][$k + 1] + ), imagecolorat($img_png, 16 * $hd_ratio + $i, 2 * $hd_ratio + $k)); + } + } + // HELMET/HAIR + $volume_points = array(); + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($j = 0; $j < 9 * $hd_ratio; $j++) { + if (!isset($volume_points[$i][$j][-2 * $hd_ratio])) { + $volume_points[$i][$j][-2 * $hd_ratio] = new Point(array( + 'x' => $i * 9 / 8 - 0.5 * $hd_ratio, + 'y' => $j * 9 / 8 - 0.5 * $hd_ratio, + 'z' => -2.5 * $hd_ratio + )); + } + if (!isset($volume_points[$i][$j][6 * $hd_ratio])) { + $volume_points[$i][$j][6 * $hd_ratio] = new Point(array( + 'x' => $i * 9 / 8 - 0.5 * $hd_ratio, + 'y' => $j * 9 / 8 - 0.5 * $hd_ratio, + 'z' => 6.5 * $hd_ratio + )); + } + } + } + for ($j = 0; $j < 9 * $hd_ratio; $j++) { + for ($k = -2 * $hd_ratio; $k < 7 * $hd_ratio; $k++) { + if (!isset($volume_points[0][$j][$k])) { + $volume_points[0][$j][$k] = new Point(array( + 'x' => -0.5 * $hd_ratio, + 'y' => $j * 9 / 8 - 0.5 * $hd_ratio, + 'z' => $k * 9 / 8 - 0.5 * $hd_ratio + )); + } + if (!isset($volume_points[8 * $hd_ratio][$j][$k])) { + $volume_points[8 * $hd_ratio][$j][$k] = new Point(array( + 'x' => 8.5 * $hd_ratio, + 'y' => $j * 9 / 8 - 0.5 * $hd_ratio, + 'z' => $k * 9 / 8 - 0.5 * $hd_ratio + )); + } + } + } + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($k = -2 * $hd_ratio; $k < 7 * $hd_ratio; $k++) { + if (!isset($volume_points[$i][0][$k])) { + $volume_points[$i][0][$k] = new Point(array( + 'x' => $i * 9 / 8 - 0.5 * $hd_ratio, + 'y' => -0.5 * $hd_ratio, + 'z' => $k * 9 / 8 - 0.5 * $hd_ratio + )); + } + if (!isset($volume_points[$i][8 * $hd_ratio][$k])) { + $volume_points[$i][8 * $hd_ratio][$k] = new Point(array( + 'x' => $i * 9 / 8 - 0.5 * $hd_ratio, + 'y' => 8.5 * $hd_ratio, + 'z' => $k * 9 / 8 - 0.5 * $hd_ratio + )); + } + } + } + for ($i = 0; $i < 8 * $hd_ratio; $i++) { + for ($j = 0; $j < 8 * $hd_ratio; $j++) { + $this->polygons['helmet']['back'][] = new Polygon(array( + $volume_points[$i][$j][-2 * $hd_ratio], + $volume_points[$i + 1][$j][-2 * $hd_ratio], + $volume_points[$i + 1][$j + 1][-2 * $hd_ratio], + $volume_points[$i][$j + 1][-2 * $hd_ratio] + ), imagecolorat($img_png, 32 * $hd_ratio + (32 * $hd_ratio - 1) - $i, 8 * $hd_ratio + $j)); + $this->polygons['helmet']['front'][] = new Polygon(array( + $volume_points[$i][$j][6 * $hd_ratio], + $volume_points[$i + 1][$j][6 * $hd_ratio], + $volume_points[$i + 1][$j + 1][6 * $hd_ratio], + $volume_points[$i][$j + 1][6 * $hd_ratio] + ), imagecolorat($img_png, 32 * $hd_ratio + 8 * $hd_ratio + $i, 8 * $hd_ratio + $j)); + } + } + for ($j = 0; $j < 8 * $hd_ratio; $j++) { + for ($k = -2 * $hd_ratio; $k < 6 * $hd_ratio; $k++) { + $this->polygons['helmet']['right'][] = new Polygon(array( + $volume_points[0][$j][$k], + $volume_points[0][$j][$k + 1], + $volume_points[0][$j + 1][$k + 1], + $volume_points[0][$j + 1][$k] + ), imagecolorat($img_png, 32 * $hd_ratio + $k + 2 * $hd_ratio, 8 * $hd_ratio + $j)); + $this->polygons['helmet']['left'][] = new Polygon(array( + $volume_points[8 * $hd_ratio][$j][$k], + $volume_points[8 * $hd_ratio][$j][$k + 1], + $volume_points[8 * $hd_ratio][$j + 1][$k + 1], + $volume_points[8 * $hd_ratio][$j + 1][$k] + ), imagecolorat($img_png, 32 * $hd_ratio + (24 * $hd_ratio - 1) - $k - 2 * $hd_ratio, 8 * $hd_ratio + $j)); + } + } + for ($i = 0; $i < 8 * $hd_ratio; $i++) { + for ($k = -2 * $hd_ratio; $k < 6 * $hd_ratio; $k++) { + $this->polygons['helmet']['top'][] = new Polygon(array( + $volume_points[$i][0][$k], + $volume_points[$i + 1][0][$k], + $volume_points[$i + 1][0][$k + 1], + $volume_points[$i][0][$k + 1] + ), imagecolorat($img_png, 32 * $hd_ratio + 8 * $hd_ratio + $i, $k + 2 * $hd_ratio)); + $this->polygons['helmet']['bottom'][] = new Polygon(array( + $volume_points[$i][8 * $hd_ratio][$k], + $volume_points[$i + 1][8 * $hd_ratio][$k], + $volume_points[$i + 1][8 * $hd_ratio][$k + 1], + $volume_points[$i][8 * $hd_ratio][$k + 1] + ), imagecolorat($img_png, 32 * $hd_ratio + 16 * $hd_ratio + $i, 2 * $hd_ratio + $k)); + } + } + if (!$this->head_only) { + // TORSO + $volume_points = array(); + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($j = 0; $j < 13 * $hd_ratio; $j++) { + if (!isset($volume_points[$i][$j][0])) { + $volume_points[$i][$j][0] = new Point(array( + 'x' => $i, + 'y' => $j + 8 * $hd_ratio, + 'z' => 0 + )); + } + if (!isset($volume_points[$i][$j][4 * $hd_ratio])) { + $volume_points[$i][$j][4 * $hd_ratio] = new Point(array( + 'x' => $i, + 'y' => $j + 8 * $hd_ratio, + 'z' => 4 * $hd_ratio + )); + } + } + } + for ($j = 0; $j < 13 * $hd_ratio; $j++) { + for ($k = 0; $k < 5 * $hd_ratio; $k++) { + if (!isset($volume_points[0][$j][$k])) { + $volume_points[0][$j][$k] = new Point(array( + 'x' => 0, + 'y' => $j + 8 * $hd_ratio, + 'z' => $k + )); + } + if (!isset($volume_points[8 * $hd_ratio][$j][$k])) { + $volume_points[8 * $hd_ratio][$j][$k] = new Point(array( + 'x' => 8 * $hd_ratio, + 'y' => $j + 8 * $hd_ratio, + 'z' => $k + )); + } + } + } + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($k = 0; $k < 5 * $hd_ratio; $k++) { + if (!isset($volume_points[$i][0][$k])) { + $volume_points[$i][0][$k] = new Point(array( + 'x' => $i, + 'y' => 0 + 8 * $hd_ratio, + 'z' => $k + )); + } + if (!isset($volume_points[$i][12 * $hd_ratio][$k])) { + $volume_points[$i][12 * $hd_ratio][$k] = new Point(array( + 'x' => $i, + 'y' => 12 * $hd_ratio + 8 * $hd_ratio, + 'z' => $k + )); + } + } + } + for ($i = 0; $i < 8 * $hd_ratio; $i++) { + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + $this->polygons['torso']['back'][] = new Polygon(array( + $volume_points[$i][$j][0], + $volume_points[$i + 1][$j][0], + $volume_points[$i + 1][$j + 1][0], + $volume_points[$i][$j + 1][0] + ), imagecolorat($img_png, (40 * $hd_ratio - 1) - $i, 20 * $hd_ratio + $j)); + $this->polygons['torso']['front'][] = new Polygon(array( + $volume_points[$i][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j + 1][4 * $hd_ratio], + $volume_points[$i][$j + 1][4 * $hd_ratio] + ), imagecolorat($img_png, 20 * $hd_ratio + $i, 20 * $hd_ratio + $j)); + } + } + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + $this->polygons['torso']['right'][] = new Polygon(array( + $volume_points[0][$j][$k], + $volume_points[0][$j][$k + 1], + $volume_points[0][$j + 1][$k + 1], + $volume_points[0][$j + 1][$k] + ), imagecolorat($img_png, 16 * $hd_ratio + $k, 20 * $hd_ratio + $j)); + $this->polygons['torso']['left'][] = new Polygon(array( + $volume_points[8 * $hd_ratio][$j][$k], + $volume_points[8 * $hd_ratio][$j][$k + 1], + $volume_points[8 * $hd_ratio][$j + 1][$k + 1], + $volume_points[8 * $hd_ratio][$j + 1][$k] + ), imagecolorat($img_png, (32 * $hd_ratio - 1) - $k, 20 * $hd_ratio + $j)); + } + } + for ($i = 0; $i < 8 * $hd_ratio; $i++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + $this->polygons['torso']['top'][] = new Polygon(array( + $volume_points[$i][0][$k], + $volume_points[$i + 1][0][$k], + $volume_points[$i + 1][0][$k + 1], + $volume_points[$i][0][$k + 1] + ), imagecolorat($img_png, 20 * $hd_ratio + $i, 16 * $hd_ratio + $k)); + $this->polygons['torso']['bottom'][] = new Polygon(array( + $volume_points[$i][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k + 1], + $volume_points[$i][12 * $hd_ratio][$k + 1] + ), imagecolorat($img_png, 28 * $hd_ratio + $i, (20 * $hd_ratio - 1) - $k)); + } + } + // RIGHT ARM + $volume_points = array(); + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($j = 0; $j < 13 * $hd_ratio; $j++) { + if (!isset($volume_points[$i][$j][0])) { + $volume_points[$i][$j][0] = new Point(array( + 'x' => $i - 4 * $hd_ratio, + 'y' => $j + 8 * $hd_ratio, + 'z' => 0 + )); + } + if (!isset($volume_points[$i][$j][4 * $hd_ratio])) { + $volume_points[$i][$j][4 * $hd_ratio] = new Point(array( + 'x' => $i - 4 * $hd_ratio, + 'y' => $j + 8 * $hd_ratio, + 'z' => 4 * $hd_ratio + )); + } + } + } + for ($j = 0; $j < 13 * $hd_ratio; $j++) { + for ($k = 0; $k < 5 * $hd_ratio; $k++) { + if (!isset($volume_points[0][$j][$k])) { + $volume_points[0][$j][$k] = new Point(array( + 'x' => 0 - 4 * $hd_ratio, + 'y' => $j + 8 * $hd_ratio, + 'z' => $k + )); + } + if (!isset($volume_points[8 * $hd_ratio][$j][$k])) { + $volume_points[4 * $hd_ratio][$j][$k] = new Point(array( + 'x' => 4 * $hd_ratio - 4 * $hd_ratio, + 'y' => $j + 8 * $hd_ratio, + 'z' => $k + )); + } + } + } + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($k = 0; $k < 5 * $hd_ratio; $k++) { + if (!isset($volume_points[$i][0][$k])) { + $volume_points[$i][0][$k] = new Point(array( + 'x' => $i - 4 * $hd_ratio, + 'y' => 0 + 8 * $hd_ratio, + 'z' => $k + )); + } + if (!isset($volume_points[$i][12 * $hd_ratio][$k])) { + $volume_points[$i][12 * $hd_ratio][$k] = new Point(array( + 'x' => $i - 4 * $hd_ratio, + 'y' => 12 * $hd_ratio + 8 * $hd_ratio, + 'z' => $k + )); + } + } + } + if ($is_alex) { + for ($i = 0; $i < 3 * $hd_ratio; $i++) { + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + $this->polygons['rightArm']['back'][] = new Polygon(array( + $volume_points[$i][$j][0], + $volume_points[$i + 1][$j][0], + $volume_points[$i + 1][$j + 1][0], + $volume_points[$i][$j + 1][0] + ), imagecolorat($img_png, (51 * $hd_ratio - 1) - $i, 20 * $hd_ratio + $j)); + $this->polygons['rightArm']['front'][] = new Polygon(array( + $volume_points[$i][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j + 1][4 * $hd_ratio], + $volume_points[$i][$j + 1][4 * $hd_ratio] + ), imagecolorat($img_png, 44 * $hd_ratio + $i, 20 * $hd_ratio + $j)); + } + } + } else { + for ($i = 0; $i < 4 * $hd_ratio; $i++) { + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + $this->polygons['rightArm']['back'][] = new Polygon(array( + $volume_points[$i][$j][0], + $volume_points[$i + 1][$j][0], + $volume_points[$i + 1][$j + 1][0], + $volume_points[$i][$j + 1][0] + ), imagecolorat($img_png, (56 * $hd_ratio - 1) - $i, 20 * $hd_ratio + $j)); + $this->polygons['rightArm']['front'][] = new Polygon(array( + $volume_points[$i][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j + 1][4 * $hd_ratio], + $volume_points[$i][$j + 1][4 * $hd_ratio] + ), imagecolorat($img_png, 44 * $hd_ratio + $i, 20 * $hd_ratio + $j)); + } + } + } + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + $right_offset_x = ($is_alex ? 47 : 40) * $hd_ratio; + $this->polygons['rightArm']['right'][] = new Polygon(array( + $volume_points[0][$j][$k], + $volume_points[0][$j][$k + 1], + $volume_points[0][$j + 1][$k + 1], + $volume_points[0][$j + 1][$k] + ), imagecolorat($img_png, $right_offset_x + $k, 20 * $hd_ratio + $j)); + $left_offset_x = ($is_alex ? 40 : 52) * $hd_ratio; + $this->polygons['rightArm']['left'][] = new Polygon(array( + $volume_points[4 * $hd_ratio][$j][$k], + $volume_points[4 * $hd_ratio][$j][$k + 1], + $volume_points[4 * $hd_ratio][$j + 1][$k + 1], + $volume_points[4 * $hd_ratio][$j + 1][$k] + ), imagecolorat($img_png, ($left_offset_x - 1) - $k, 20 * $hd_ratio + $j)); + } + } + if ($is_alex) { + for ($i = 0; $i < 3 * $hd_ratio; $i++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + $this->polygons['rightArm']['top'][] = new Polygon(array( + $volume_points[$i][0][$k], + $volume_points[$i + 1][0][$k], + $volume_points[$i + 1][0][$k + 1], + $volume_points[$i][0][$k + 1] + ), imagecolorat($img_png, 44 * $hd_ratio + $i, 16 * $hd_ratio + $k)); + $this->polygons['rightArm']['bottom'][] = new Polygon(array( + $volume_points[$i][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k + 1], + $volume_points[$i][12 * $hd_ratio][$k + 1] + ), imagecolorat($img_png, 47 * $hd_ratio + $i, 16 * $hd_ratio + $k)); + } + } + } else { + for ($i = 0; $i < 4 * $hd_ratio; $i++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + $this->polygons['rightArm']['top'][] = new Polygon(array( + $volume_points[$i][0][$k], + $volume_points[$i + 1][0][$k], + $volume_points[$i + 1][0][$k + 1], + $volume_points[$i][0][$k + 1] + ), imagecolorat($img_png, 44 * $hd_ratio + $i, 16 * $hd_ratio + $k)); + $this->polygons['rightArm']['bottom'][] = new Polygon(array( + $volume_points[$i][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k + 1], + $volume_points[$i][12 * $hd_ratio][$k + 1] + ), imagecolorat($img_png, 48 * $hd_ratio + $i, 16 * $hd_ratio + $k)); + } + } + } + // LEFT ARM + $volume_points = array(); + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($j = 0; $j < 13 * $hd_ratio; $j++) { + if (!isset($volume_points[$i][$j][0])) { + $volume_points[$i][$j][0] = new Point(array( + 'x' => $i + 8 * $hd_ratio, + 'y' => $j + 8 * $hd_ratio, + 'z' => 0 + )); + } + if (!isset($volume_points[$i][$j][4 * $hd_ratio])) { + $volume_points[$i][$j][4 * $hd_ratio] = new Point(array( + 'x' => $i + 8 * $hd_ratio, + 'y' => $j + 8 * $hd_ratio, + 'z' => 4 * $hd_ratio + )); + } + } + } + for ($j = 0; $j < 13 * $hd_ratio; $j++) { + for ($k = 0; $k < 5 * $hd_ratio; $k++) { + if (!isset($volume_points[0][$j][$k])) { + $volume_points[0][$j][$k] = new Point(array( + 'x' => 8 * $hd_ratio, + 'y' => $j + 8 * $hd_ratio, + 'z' => $k + )); + } + if (!isset($volume_points[8 * $hd_ratio][$j][$k])) { + $volume_points[4 * $hd_ratio][$j][$k] = new Point(array( + 'x' => 4 * $hd_ratio + 8 * $hd_ratio, + 'y' => $j + 8 * $hd_ratio, + 'z' => $k + )); + } + } + } + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($k = 0; $k < 5 * $hd_ratio; $k++) { + if (!isset($volume_points[$i][0][$k])) { + $volume_points[$i][0][$k] = new Point(array( + 'x' => $i + 8 * $hd_ratio, + 'y' => 0 + 8 * $hd_ratio, + 'z' => $k + )); + } + if (!isset($volume_points[$i][12 * $hd_ratio][$k])) { + $volume_points[$i][12 * $hd_ratio][$k] = new Point(array( + 'x' => $i + 8 * $hd_ratio, + 'y' => 12 * $hd_ratio + 8 * $hd_ratio, + 'z' => $k + )); + } + } + } + if ($is_alex) { + for ($i = 0; $i < 3 * $hd_ratio; $i++) { + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + $this->polygons['leftArm']['back'][] = new Polygon(array( + $volume_points[$i][$j][0], + $volume_points[$i + 1][$j][0], + $volume_points[$i + 1][$j + 1][0], + $volume_points[$i][$j + 1][0] + ), imagecolorat($img_png, 43 * $hd_ratio + $i, 52 * $hd_ratio + $j)); + $this->polygons['leftArm']['front'][] = new Polygon(array( + $volume_points[$i][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j + 1][4 * $hd_ratio], + $volume_points[$i][$j + 1][4 * $hd_ratio] + ), imagecolorat($img_png, 36 * $hd_ratio + $i, 52 * $hd_ratio + $j)); + } + } + } else { + for ($i = 0; $i < 4 * $hd_ratio; $i++) { + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + if ($this->isNewSkinType) { + $color1 = imagecolorat($img_png, 47 * $hd_ratio - $i, 52 * $hd_ratio + $j); // from right to left + $color2 = imagecolorat($img_png, 36 * $hd_ratio + $i, 52 * $hd_ratio + $j); // from left to right + } else { + $color1 = imagecolorat($img_png, (56 * $hd_ratio - 1) - ((4 * $hd_ratio - 1) - $i), 20 * $hd_ratio + $j); + $color2 = imagecolorat($img_png, 44 * $hd_ratio + ((4 * $hd_ratio - 1) - $i), 20 * $hd_ratio + $j); + } + + $this->polygons['leftArm']['back'][] = new Polygon(array( + $volume_points[$i][$j][0], + $volume_points[$i + 1][$j][0], + $volume_points[$i + 1][$j + 1][0], + $volume_points[$i][$j + 1][0] + ), $color1); + $this->polygons['leftArm']['front'][] = new Polygon(array( + $volume_points[$i][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j + 1][4 * $hd_ratio], + $volume_points[$i][$j + 1][4 * $hd_ratio] + ), $color2); + } + } + } + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + if ($this->isNewSkinType) { + $color1 = imagecolorat($img_png, 32 * $hd_ratio + $k, 52 * $hd_ratio + $j); // from left to right + $color2 = imagecolorat($img_png, 43 * $hd_ratio - $k, 52 * $hd_ratio + $j); // from right to left + } else { + $color1 = imagecolorat($img_png, 40 * $hd_ratio + ((4 * $hd_ratio - 1) - $k), 20 * $hd_ratio + $j); + $color2 = imagecolorat($img_png, (52 * $hd_ratio - 1) - ((4 * $hd_ratio - 1) - $k), 20 * $hd_ratio + $j); + } + + $this->polygons['leftArm']['right'][] = new Polygon(array( + $volume_points[0][$j][$k], + $volume_points[0][$j][$k + 1], + $volume_points[0][$j + 1][$k + 1], + $volume_points[0][$j + 1][$k] + ), $color1); + $this->polygons['leftArm']['left'][] = new Polygon(array( + $volume_points[4 * $hd_ratio][$j][$k], + $volume_points[4 * $hd_ratio][$j][$k + 1], + $volume_points[4 * $hd_ratio][$j + 1][$k + 1], + $volume_points[4 * $hd_ratio][$j + 1][$k] + ), $color2); + } + } + if ($is_alex) { + for ($i = 0; $i < 3 * $hd_ratio; $i++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + $this->polygons['leftArm']['top'][] = new Polygon(array( + $volume_points[$i][0][$k], + $volume_points[$i + 1][0][$k], + $volume_points[$i + 1][0][$k + 1], + $volume_points[$i][0][$k + 1] + ), imagecolorat($img_png, 36 * $hd_ratio + $i, 48 * $hd_ratio + $k)); + $this->polygons['leftArm']['bottom'][] = new Polygon(array( + $volume_points[$i][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k + 1], + $volume_points[$i][12 * $hd_ratio][$k + 1] + ), imagecolorat($img_png, 39 * $hd_ratio + $i, 48 * $hd_ratio + $k)); + } + } + } else { + for ($i = 0; $i < 4 * $hd_ratio; $i++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + if ($this->isNewSkinType) { + $color1 = imagecolorat($img_png, 36 * $hd_ratio + $i, 48 * $hd_ratio + $k); // from left to right + $color2 = imagecolorat($img_png, 40 * $hd_ratio + $i, 48 * $hd_ratio + $k); // from left to right + } else { + $color1 = imagecolorat($img_png, 44 * $hd_ratio + ((4 * $hd_ratio - 1) - $i), 16 * $hd_ratio + $k); + $color2 = imagecolorat($img_png, 48 * $hd_ratio + ((4 * $hd_ratio - 1) - $i), (20 * $hd_ratio - 1) - $k); + } + + $this->polygons['leftArm']['top'][] = new Polygon(array( + $volume_points[$i][0][$k], + $volume_points[$i + 1][0][$k], + $volume_points[$i + 1][0][$k + 1], + $volume_points[$i][0][$k + 1] + ), $color1); + $this->polygons['leftArm']['bottom'][] = new Polygon(array( + $volume_points[$i][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k + 1], + $volume_points[$i][12 * $hd_ratio][$k + 1] + ), $color2); + } + } + } + // RIGHT LEG + $volume_points = array(); + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($j = 0; $j < 13 * $hd_ratio; $j++) { + if (!isset($volume_points[$i][$j][0])) { + $volume_points[$i][$j][0] = new Point(array( + 'x' => $i, + 'y' => $j + 20 * $hd_ratio, + 'z' => 0 + )); + } + if (!isset($volume_points[$i][$j][4 * $hd_ratio])) { + $volume_points[$i][$j][4 * $hd_ratio] = new Point(array( + 'x' => $i, + 'y' => $j + 20 * $hd_ratio, + 'z' => 4 * $hd_ratio + )); + } + } + } + for ($j = 0; $j < 13 * $hd_ratio; $j++) { + for ($k = 0; $k < 5 * $hd_ratio; $k++) { + if (!isset($volume_points[0][$j][$k])) { + $volume_points[0][$j][$k] = new Point(array( + 'x' => 0, + 'y' => $j + 20 * $hd_ratio, + 'z' => $k + )); + } + if (!isset($volume_points[8 * $hd_ratio][$j][$k])) { + $volume_points[4 * $hd_ratio][$j][$k] = new Point(array( + 'x' => 4 * $hd_ratio, + 'y' => $j + 20 * $hd_ratio, + 'z' => $k + )); + } + } + } + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($k = 0; $k < 5 * $hd_ratio; $k++) { + if (!isset($volume_points[$i][0][$k])) { + $volume_points[$i][0][$k] = new Point(array( + 'x' => $i, + 'y' => 0 + 20 * $hd_ratio, + 'z' => $k + )); + } + if (!isset($volume_points[$i][12 * $hd_ratio][$k])) { + $volume_points[$i][12 * $hd_ratio][$k] = new Point(array( + 'x' => $i, + 'y' => 12 * $hd_ratio + 20 * $hd_ratio, + 'z' => $k + )); + } + } + } + for ($i = 0; $i < 4 * $hd_ratio; $i++) { + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + $this->polygons['rightLeg']['back'][] = new Polygon(array( + $volume_points[$i][$j][0], + $volume_points[$i + 1][$j][0], + $volume_points[$i + 1][$j + 1][0], + $volume_points[$i][$j + 1][0] + ), imagecolorat($img_png, (16 * $hd_ratio - 1) - $i, 20 * $hd_ratio + $j)); + $this->polygons['rightLeg']['front'][] = new Polygon(array( + $volume_points[$i][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j + 1][4 * $hd_ratio], + $volume_points[$i][$j + 1][4 * $hd_ratio] + ), imagecolorat($img_png, 4 * $hd_ratio + $i, 20 * $hd_ratio + $j)); + } + } + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + $this->polygons['rightLeg']['right'][] = new Polygon(array( + $volume_points[0][$j][$k], + $volume_points[0][$j][$k + 1], + $volume_points[0][$j + 1][$k + 1], + $volume_points[0][$j + 1][$k] + ), imagecolorat($img_png, 0 + $k, 20 * $hd_ratio + $j)); + $this->polygons['rightLeg']['left'][] = new Polygon(array( + $volume_points[4 * $hd_ratio][$j][$k], + $volume_points[4 * $hd_ratio][$j][$k + 1], + $volume_points[4 * $hd_ratio][$j + 1][$k + 1], + $volume_points[4 * $hd_ratio][$j + 1][$k] + ), imagecolorat($img_png, (12 * $hd_ratio - 1) - $k, 20 * $hd_ratio + $j)); + } + } + for ($i = 0; $i < 4 * $hd_ratio; $i++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + $this->polygons['rightLeg']['top'][] = new Polygon(array( + $volume_points[$i][0][$k], + $volume_points[$i + 1][0][$k], + $volume_points[$i + 1][0][$k + 1], + $volume_points[$i][0][$k + 1] + ), imagecolorat($img_png, 4 * $hd_ratio + $i, 16 * $hd_ratio + $k)); + $this->polygons['rightLeg']['bottom'][] = new Polygon(array( + $volume_points[$i][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k + 1], + $volume_points[$i][12 * $hd_ratio][$k + 1] + ), imagecolorat($img_png, 8 * $hd_ratio + $i, 16 * $hd_ratio + $k)); + } + } + // LEFT LEG + $volume_points = array(); + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($j = 0; $j < 13 * $hd_ratio; $j++) { + if (!isset($volume_points[$i][$j][0])) { + $volume_points[$i][$j][0] = new Point(array( + 'x' => $i + 4 * $hd_ratio, + 'y' => $j + 20 * $hd_ratio, + 'z' => 0 + )); + } + if (!isset($volume_points[$i][$j][4 * $hd_ratio])) { + $volume_points[$i][$j][4 * $hd_ratio] = new Point(array( + 'x' => $i + 4 * $hd_ratio, + 'y' => $j + 20 * $hd_ratio, + 'z' => 4 * $hd_ratio + )); + } + } + } + for ($j = 0; $j < 13 * $hd_ratio; $j++) { + for ($k = 0; $k < 5 * $hd_ratio; $k++) { + if (!isset($volume_points[0][$j][$k])) { + $volume_points[0][$j][$k] = new Point(array( + 'x' => 0 + 4 * $hd_ratio, + 'y' => $j + 20 * $hd_ratio, + 'z' => $k + )); + } + if (!isset($volume_points[8 * $hd_ratio][$j][$k])) { + $volume_points[4 * $hd_ratio][$j][$k] = new Point(array( + 'x' => 4 * $hd_ratio + 4 * $hd_ratio, + 'y' => $j + 20 * $hd_ratio, + 'z' => $k + )); + } + } + } + for ($i = 0; $i < 9 * $hd_ratio; $i++) { + for ($k = 0; $k < 5 * $hd_ratio; $k++) { + if (!isset($volume_points[$i][0][$k])) { + $volume_points[$i][0][$k] = new Point(array( + 'x' => $i + 4 * $hd_ratio, + 'y' => 0 + 20 * $hd_ratio, + 'z' => $k + )); + } + if (!isset($volume_points[$i][12 * $hd_ratio][$k])) { + $volume_points[$i][12 * $hd_ratio][$k] = new Point(array( + 'x' => $i + 4 * $hd_ratio, + 'y' => 12 * $hd_ratio + 20 * $hd_ratio, + 'z' => $k + )); + } + } + } + for ($i = 0; $i < 4 * $hd_ratio; $i++) { + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + if ($this->isNewSkinType) { + $color1 = imagecolorat($img_png, 31 * $hd_ratio - $i, 52 * $hd_ratio + $j); // from right to left + $color2 = imagecolorat($img_png, 20 * $hd_ratio + $i, 52 * $hd_ratio + $j); // from left to right + } else { + $color1 = imagecolorat($img_png, (16 * $hd_ratio - 1) - ((4 * $hd_ratio - 1) - $i), 20 * $hd_ratio + $j); + $color2 = imagecolorat($img_png, 4 * $hd_ratio + ((4 * $hd_ratio - 1) - $i), 20 * $hd_ratio + $j); + } + + $this->polygons['leftLeg']['back'][] = new Polygon(array( + $volume_points[$i][$j][0], + $volume_points[$i + 1][$j][0], + $volume_points[$i + 1][$j + 1][0], + $volume_points[$i][$j + 1][0] + ), $color1); + $this->polygons['leftLeg']['front'][] = new Polygon(array( + $volume_points[$i][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j][4 * $hd_ratio], + $volume_points[$i + 1][$j + 1][4 * $hd_ratio], + $volume_points[$i][$j + 1][4 * $hd_ratio] + ), $color2); + } + } + for ($j = 0; $j < 12 * $hd_ratio; $j++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + if ($this->isNewSkinType) { + $color1 = imagecolorat($img_png, 16 * $hd_ratio + $k, 52 * $hd_ratio + $j); // from left to right + $color2 = imagecolorat($img_png, 27 * $hd_ratio - $k, 52 * $hd_ratio + $j); // from right to left + } else { + $color1 = imagecolorat($img_png, 0 + ((4 * $hd_ratio - 1) - $k), 20 * $hd_ratio + $j); + $color2 = imagecolorat($img_png, (12 * $hd_ratio - 1) - ((4 * $hd_ratio - 1) - $k), 20 * $hd_ratio + $j); + } + + $this->polygons['leftLeg']['right'][] = new Polygon(array( + $volume_points[0][$j][$k], + $volume_points[0][$j][$k + 1], + $volume_points[0][$j + 1][$k + 1], + $volume_points[0][$j + 1][$k] + ), $color1); + $this->polygons['leftLeg']['left'][] = new Polygon(array( + $volume_points[4 * $hd_ratio][$j][$k], + $volume_points[4 * $hd_ratio][$j][$k + 1], + $volume_points[4 * $hd_ratio][$j + 1][$k + 1], + $volume_points[4 * $hd_ratio][$j + 1][$k] + ), $color2); + } + } + for ($i = 0; $i < 4 * $hd_ratio; $i++) { + for ($k = 0; $k < 4 * $hd_ratio; $k++) { + if ($this->isNewSkinType) { + $color1 = imagecolorat($img_png, 20 * $hd_ratio + $i, 48 * $hd_ratio + $k); // from left to right + $color2 = imagecolorat($img_png, 24 * $hd_ratio + $i, 48 * $hd_ratio + $k); // from left to right + } else { + $color1 = imagecolorat($img_png, 4 * $hd_ratio + ((4 * $hd_ratio - 1) - $i), 16 * $hd_ratio + $k); + $color2 = imagecolorat($img_png, 8 * $hd_ratio + ((4 * $hd_ratio - 1) - $i), (20 * $hd_ratio - 1) - $k); + } + + $this->polygons['leftLeg']['top'][] = new Polygon(array( + $volume_points[$i][0][$k], + $volume_points[$i + 1][0][$k], + $volume_points[$i + 1][0][$k + 1], + $volume_points[$i][0][$k + 1] + ), $color1); + $this->polygons['leftLeg']['bottom'][] = new Polygon(array( + $volume_points[$i][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k], + $volume_points[$i + 1][12 * $hd_ratio][$k + 1], + $volume_points[$i][12 * $hd_ratio][$k + 1] + ), $color2); + } + } + } + } + + private function memberRotation() + { + foreach ($this->polygons['head'] as $face) { + foreach ($face as $poly) { + $poly->preProject(4, 8, 2, $this->members_angles['head']['cos_alpha'], $this->members_angles['head']['sin_alpha'], $this->members_angles['head']['cos_omega'], $this->members_angles['head']['sin_omega']); + } + } + + foreach ($this->polygons['helmet'] as $face) { + foreach ($face as $poly) { + $poly->preProject(4, 8, 2, $this->members_angles['head']['cos_alpha'], $this->members_angles['head']['sin_alpha'], $this->members_angles['head']['cos_omega'], $this->members_angles['head']['sin_omega']); + } + } + + if (!$this->head_only) { + foreach ($this->polygons['rightArm'] as $face) { + foreach ($face as $poly) { + $poly->preProject(-2, 8, 2, $this->members_angles['rightArm']['cos_alpha'], $this->members_angles['rightArm']['sin_alpha'], $this->members_angles['rightArm']['cos_omega'], $this->members_angles['rightArm']['sin_omega']); + } + } + foreach ($this->polygons['leftArm'] as $face) { + foreach ($face as $poly) { + $poly->preProject(10, 8, 2, $this->members_angles['leftArm']['cos_alpha'], $this->members_angles['leftArm']['sin_alpha'], $this->members_angles['leftArm']['cos_omega'], $this->members_angles['leftArm']['sin_omega']); + } + } + foreach ($this->polygons['rightLeg'] as $face) { + foreach ($face as $poly) { + $poly->preProject(2, 20, ($this->members_angles['rightLeg']['sin_alpha'] < 0 ? 0 : 4), $this->members_angles['rightLeg']['cos_alpha'], $this->members_angles['rightLeg']['sin_alpha'], $this->members_angles['rightLeg']['cos_omega'], $this->members_angles['rightLeg']['sin_omega']); + } + } + foreach ($this->polygons['leftLeg'] as $face) { + foreach ($face as $poly) { + $poly->preProject(6, 20, ($this->members_angles['leftLeg']['sin_alpha'] < 0 ? 0 : 4), $this->members_angles['leftLeg']['cos_alpha'], $this->members_angles['leftLeg']['sin_alpha'], $this->members_angles['leftLeg']['cos_omega'], $this->members_angles['leftLeg']['sin_omega']); + } + } + } + } + + private function createProjectionPlan() + { + $cos_alpha = $this->cos_alpha; + $sin_alpha = $this->sin_alpha; + $cos_omega = $this->cos_omega; + $sin_omega = $this->sin_omega; + + foreach ($this->polygons as $piece) { + foreach ($piece as $face) { + foreach ($face as $poly) { + if (!$poly->isProjected()) { + $poly->project($cos_alpha, $sin_alpha, $cos_omega, $sin_omega, $this->minX, $this->maxX, $this->minY, $this->maxY); + } + } + } + } + } + + private function displayImage() + { + $width = $this->maxX - $this->minX; + $height = $this->maxY - $this->minY; + $ratio = $this->ratio * 2; + + $srcWidth = $ratio * $width + 1; + $srcHeight = $ratio * $height + 1; + + $image = ImageUtil::createEmptyCanvas($srcWidth, $srcHeight); + + $display_order = $this->getDisplayOrder(); + + foreach ($display_order as $pieces) { + foreach ($pieces as $piece => $faces) { + foreach ($faces as $face) { + foreach ($this->polygons[$piece][$face] as $poly) { + $poly->addPngPolygon($image, $this->minX, $this->minY, $ratio); + } + } + } + } + + // Anti-aliasing + $realWidth = $srcWidth / 2; + $realHeight = $srcHeight / 2; + $destImage = ImageUtil::createEmptyCanvas($realWidth, $realHeight); + imagecopyresampled($destImage, $image, 0, 0, 0, 0, $realWidth, $realHeight, $srcWidth, $srcHeight); + $image = $destImage; + + return $image; + } + + private function getDisplayOrder() + { + $display_order = array(); + if (in_array('top', $this->front_faces)) { + if (in_array('right', $this->front_faces)) { + $display_order[] = array('leftLeg' => $this->back_faces); + $display_order[] = array('leftLeg' => $this->visible_faces['leftLeg']['front']); + $display_order[] = array('rightLeg' => $this->back_faces); + $display_order[] = array('rightLeg' => $this->visible_faces['rightLeg']['front']); + $display_order[] = array('leftArm' => $this->back_faces); + $display_order[] = array('leftArm' => $this->visible_faces['leftArm']['front']); + $display_order[] = array('torso' => $this->back_faces); + $display_order[] = array('torso' => $this->visible_faces['torso']['front']); + $display_order[] = array('rightArm' => $this->back_faces); + $display_order[] = array('rightArm' => $this->visible_faces['rightArm']['front']); + } else { + $display_order[] = array('rightLeg' => $this->back_faces); + $display_order[] = array('rightLeg' => $this->visible_faces['rightLeg']['front']); + $display_order[] = array('leftLeg' => $this->back_faces); + $display_order[] = array('leftLeg' => $this->visible_faces['leftLeg']['front']); + $display_order[] = array('rightArm' => $this->back_faces); + $display_order[] = array('rightArm' => $this->visible_faces['rightArm']['front']); + $display_order[] = array('torso' => $this->back_faces); + $display_order[] = array('torso' => $this->visible_faces['torso']['front']); + $display_order[] = array('leftArm' => $this->back_faces); + $display_order[] = array('leftArm' => $this->visible_faces['leftArm']['front']); + } + + $display_order[] = array('helmet' => $this->back_faces); + $display_order[] = array('head' => $this->back_faces); + $display_order[] = array('head' => $this->visible_faces['head']['front']); + $display_order[] = array('helmet' => $this->visible_faces['head']['front']); + } else { + $display_order[] = array('helmet' => $this->back_faces); + $display_order[] = array('head' => $this->back_faces); + $display_order[] = array('head' => $this->visible_faces['head']['front']); + $display_order[] = array('helmet' => $this->visible_faces['head']['front']); + + if (in_array('right', $this->front_faces)) { + $display_order[] = array('leftArm' => $this->back_faces); + $display_order[] = array('leftArm' => $this->visible_faces['leftArm']['front']); + $display_order[] = array('torso' => $this->back_faces); + $display_order[] = array('torso' => $this->visible_faces['torso']['front']); + $display_order[] = array('rightArm' => $this->back_faces); + $display_order[] = array('rightArm' => $this->visible_faces['rightArm']['front']); + $display_order[] = array('leftLeg' => $this->back_faces); + $display_order[] = array('leftLeg' => $this->visible_faces['leftLeg']['front']); + $display_order[] = array('rightLeg' => $this->back_faces); + $display_order[] = array('rightLeg' => $this->visible_faces['rightLeg']['front']); + } else { + $display_order[] = array('rightArm' => $this->back_faces); + $display_order[] = array('rightArm' => $this->visible_faces['rightArm']['front']); + $display_order[] = array('torso' => $this->back_faces); + $display_order[] = array('torso' => $this->visible_faces['torso']['front']); + $display_order[] = array('leftArm' => $this->back_faces); + $display_order[] = array('leftArm' => $this->visible_faces['leftArm']['front']); + $display_order[] = array('rightLeg' => $this->back_faces); + $display_order[] = array('rightLeg' => $this->visible_faces['rightLeg']['front']); + $display_order[] = array('leftLeg' => $this->back_faces); + $display_order[] = array('leftLeg' => $this->visible_faces['leftLeg']['front']); + } + } + + return $display_order; + } +} diff --git a/vendor/blessing/texture-renderer/src/Blessing/Renderer/TextureUtil.php b/vendor/blessing/texture-renderer/src/Blessing/Renderer/TextureUtil.php new file mode 100755 index 0000000..a88c23d --- /dev/null +++ b/vendor/blessing/texture-renderer/src/Blessing/Renderer/TextureUtil.php @@ -0,0 +1,35 @@ + 'gd']); + $image = $manager->make($imageData); + $width = $image->width(); + + if ($width === $image->height()) { + $ratio = $width / 64; + for ($x = 46 * $ratio; $x < 48 * $ratio; $x += 1) { + for ($y = 52 * $ratio; $y < 64 * $ratio; $y += 1) { + if (!static::checkPixel($image->pickColor($x, $y))) { + return false; + } + } + } + + return true; + } else { + return false; + } + } + + protected static function checkPixel(array $color): bool + { + return $color[0] === 0 && $color[1] === 0 && $color[2] === 0; + } +} diff --git a/vendor/brick/math/CHANGELOG.md b/vendor/brick/math/CHANGELOG.md new file mode 100755 index 0000000..03c3d82 --- /dev/null +++ b/vendor/brick/math/CHANGELOG.md @@ -0,0 +1,415 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.9.3](https://github.com/brick/math/releases/tag/0.9.3) - 2021-08-15 + +🚀 **Compatibility with PHP 8.1** + +- Support for custom object serialization; this removes a warning on PHP 8.1 due to the `Serializable` interface being deprecated (thanks @TRowbotham) + +## [0.9.2](https://github.com/brick/math/releases/tag/0.9.2) - 2021-01-20 + +🐛 **Bug fix** + +- Incorrect results could be returned when using the BCMath calculator, with a default scale set with `bcscale()`, on PHP >= 7.2 (#55). + +## [0.9.1](https://github.com/brick/math/releases/tag/0.9.1) - 2020-08-19 + +✨ New features + +- `BigInteger::not()` returns the bitwise `NOT` value + +🐛 **Bug fixes** + +- `BigInteger::toBytes()` could return an incorrect binary representation for some numbers +- The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available + +## [0.9.0](https://github.com/brick/math/releases/tag/0.9.0) - 2020-08-18 + +👌 **Improvements** + +- `BigNumber::of()` now accepts `.123` and `123.` formats, both of which return a `BigDecimal` + +💥 **Breaking changes** + +- Deprecated method `BigInteger::powerMod()` has been removed - use `modPow()` instead +- Deprecated method `BigInteger::parse()` has been removed - use `fromBase()` instead + +## [0.8.17](https://github.com/brick/math/releases/tag/0.8.17) - 2020-08-19 + +🐛 **Bug fix** + +- `BigInteger::toBytes()` could return an incorrect binary representation for some numbers +- The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available + +## [0.8.16](https://github.com/brick/math/releases/tag/0.8.16) - 2020-08-18 + +🚑 **Critical fix** + +- This version reintroduces the deprecated `BigInteger::parse()` method, that has been removed by mistake in version `0.8.9` and should have lasted for the whole `0.8` release cycle. + +✨ **New features** + +- `BigInteger::modInverse()` calculates a modular multiplicative inverse +- `BigInteger::fromBytes()` creates a `BigInteger` from a byte string +- `BigInteger::toBytes()` converts a `BigInteger` to a byte string +- `BigInteger::randomBits()` creates a pseudo-random `BigInteger` of a given bit length +- `BigInteger::randomRange()` creates a pseudo-random `BigInteger` between two bounds + +💩 **Deprecations** + +- `BigInteger::powerMod()` is now deprecated in favour of `modPow()` + +## [0.8.15](https://github.com/brick/math/releases/tag/0.8.15) - 2020-04-15 + +🐛 **Fixes** + +- added missing `ext-json` requirement, due to `BigNumber` implementing `JsonSerializable` + +⚡️ **Optimizations** + +- additional optimization in `BigInteger::remainder()` + +## [0.8.14](https://github.com/brick/math/releases/tag/0.8.14) - 2020-02-18 + +✨ **New features** + +- `BigInteger::getLowestSetBit()` returns the index of the rightmost one bit + +## [0.8.13](https://github.com/brick/math/releases/tag/0.8.13) - 2020-02-16 + +✨ **New features** + +- `BigInteger::isEven()` tests whether the number is even +- `BigInteger::isOdd()` tests whether the number is odd +- `BigInteger::testBit()` tests if a bit is set +- `BigInteger::getBitLength()` returns the number of bits in the minimal representation of the number + +## [0.8.12](https://github.com/brick/math/releases/tag/0.8.12) - 2020-02-03 + +🛠️ **Maintenance release** + +Classes are now annotated for better static analysis with [psalm](https://psalm.dev/). + +This is a maintenance release: no bug fixes, no new features, no breaking changes. + +## [0.8.11](https://github.com/brick/math/releases/tag/0.8.11) - 2020-01-23 + +✨ **New feature** + +`BigInteger::powerMod()` performs a power-with-modulo operation. Useful for crypto. + +## [0.8.10](https://github.com/brick/math/releases/tag/0.8.10) - 2020-01-21 + +✨ **New feature** + +`BigInteger::mod()` returns the **modulo** of two numbers. The *modulo* differs from the *remainder* when the signs of the operands are different. + +## [0.8.9](https://github.com/brick/math/releases/tag/0.8.9) - 2020-01-08 + +⚡️ **Performance improvements** + +A few additional optimizations in `BigInteger` and `BigDecimal` when one of the operands can be returned as is. Thanks to @tomtomsen in #24. + +## [0.8.8](https://github.com/brick/math/releases/tag/0.8.8) - 2019-04-25 + +🐛 **Bug fixes** + +- `BigInteger::toBase()` could return an empty string for zero values (BCMath & Native calculators only, GMP calculator unaffected) + +✨ **New features** + +- `BigInteger::toArbitraryBase()` converts a number to an arbitrary base, using a custom alphabet +- `BigInteger::fromArbitraryBase()` converts a string in an arbitrary base, using a custom alphabet, back to a number + +These methods can be used as the foundation to convert strings between different bases/alphabets, using BigInteger as an intermediate representation. + +💩 **Deprecations** + +- `BigInteger::parse()` is now deprecated in favour of `fromBase()` + +`BigInteger::fromBase()` works the same way as `parse()`, with 2 minor differences: + +- the `$base` parameter is required, it does not default to `10` +- it throws a `NumberFormatException` instead of an `InvalidArgumentException` when the number is malformed + +## [0.8.7](https://github.com/brick/math/releases/tag/0.8.7) - 2019-04-20 + +**Improvements** + +- Safer conversion from `float` when using custom locales +- **Much faster** `NativeCalculator` implementation 🚀 + +You can expect **at least a 3x performance improvement** for common arithmetic operations when using the library on systems without GMP or BCMath; it gets exponentially faster on multiplications with a high number of digits. This is due to calculations now being performed on whole blocks of digits (the block size depending on the platform, 32-bit or 64-bit) instead of digit-by-digit as before. + +## [0.8.6](https://github.com/brick/math/releases/tag/0.8.6) - 2019-04-11 + +**New method** + +`BigNumber::sum()` returns the sum of one or more numbers. + +## [0.8.5](https://github.com/brick/math/releases/tag/0.8.5) - 2019-02-12 + +**Bug fix**: `of()` factory methods could fail when passing a `float` in environments using a `LC_NUMERIC` locale with a decimal separator other than `'.'` (#20). + +Thanks @manowark 👍 + +## [0.8.4](https://github.com/brick/math/releases/tag/0.8.4) - 2018-12-07 + +**New method** + +`BigDecimal::sqrt()` calculates the square root of a decimal number, to a given scale. + +## [0.8.3](https://github.com/brick/math/releases/tag/0.8.3) - 2018-12-06 + +**New method** + +`BigInteger::sqrt()` calculates the square root of a number (thanks @peter279k). + +**New exception** + +`NegativeNumberException` is thrown when calling `sqrt()` on a negative number. + +## [0.8.2](https://github.com/brick/math/releases/tag/0.8.2) - 2018-11-08 + +**Performance update** + +- Further improvement of `toInt()` performance +- `NativeCalculator` can now perform some multiplications more efficiently + +## [0.8.1](https://github.com/brick/math/releases/tag/0.8.1) - 2018-11-07 + +Performance optimization of `toInt()` methods. + +## [0.8.0](https://github.com/brick/math/releases/tag/0.8.0) - 2018-10-13 + +**Breaking changes** + +The following deprecated methods have been removed. Use the new method name instead: + +| Method removed | Replacement method | +| --- | --- | +| `BigDecimal::getIntegral()` | `BigDecimal::getIntegralPart()` | +| `BigDecimal::getFraction()` | `BigDecimal::getFractionalPart()` | + +--- + +**New features** + +`BigInteger` has been augmented with 5 new methods for bitwise operations: + +| New method | Description | +| --- | --- | +| `and()` | performs a bitwise `AND` operation on two numbers | +| `or()` | performs a bitwise `OR` operation on two numbers | +| `xor()` | performs a bitwise `XOR` operation on two numbers | +| `shiftedLeft()` | returns the number shifted left by a number of bits | +| `shiftedRight()` | returns the number shifted right by a number of bits | + +Thanks to @DASPRiD 👍 + +## [0.7.3](https://github.com/brick/math/releases/tag/0.7.3) - 2018-08-20 + +**New method:** `BigDecimal::hasNonZeroFractionalPart()` + +**Renamed/deprecated methods:** + +- `BigDecimal::getIntegral()` has been renamed to `getIntegralPart()` and is now deprecated +- `BigDecimal::getFraction()` has been renamed to `getFractionalPart()` and is now deprecated + +## [0.7.2](https://github.com/brick/math/releases/tag/0.7.2) - 2018-07-21 + +**Performance update** + +`BigInteger::parse()` and `toBase()` now use GMP's built-in base conversion features when available. + +## [0.7.1](https://github.com/brick/math/releases/tag/0.7.1) - 2018-03-01 + +This is a maintenance release, no code has been changed. + +- When installed with `--no-dev`, the autoloader does not autoload tests anymore +- Tests and other files unnecessary for production are excluded from the dist package + +This will help make installations more compact. + +## [0.7.0](https://github.com/brick/math/releases/tag/0.7.0) - 2017-10-02 + +Methods renamed: + +- `BigNumber:sign()` has been renamed to `getSign()` +- `BigDecimal::unscaledValue()` has been renamed to `getUnscaledValue()` +- `BigDecimal::scale()` has been renamed to `getScale()` +- `BigDecimal::integral()` has been renamed to `getIntegral()` +- `BigDecimal::fraction()` has been renamed to `getFraction()` +- `BigRational::numerator()` has been renamed to `getNumerator()` +- `BigRational::denominator()` has been renamed to `getDenominator()` + +Classes renamed: + +- `ArithmeticException` has been renamed to `MathException` + +## [0.6.2](https://github.com/brick/math/releases/tag/0.6.2) - 2017-10-02 + +The base class for all exceptions is now `MathException`. +`ArithmeticException` has been deprecated, and will be removed in 0.7.0. + +## [0.6.1](https://github.com/brick/math/releases/tag/0.6.1) - 2017-10-02 + +A number of methods have been renamed: + +- `BigNumber:sign()` is deprecated; use `getSign()` instead +- `BigDecimal::unscaledValue()` is deprecated; use `getUnscaledValue()` instead +- `BigDecimal::scale()` is deprecated; use `getScale()` instead +- `BigDecimal::integral()` is deprecated; use `getIntegral()` instead +- `BigDecimal::fraction()` is deprecated; use `getFraction()` instead +- `BigRational::numerator()` is deprecated; use `getNumerator()` instead +- `BigRational::denominator()` is deprecated; use `getDenominator()` instead + +The old methods will be removed in version 0.7.0. + +## [0.6.0](https://github.com/brick/math/releases/tag/0.6.0) - 2017-08-25 + +- Minimum PHP version is now [7.1](https://gophp71.org/); for PHP 5.6 and PHP 7.0 support, use version `0.5` +- Deprecated method `BigDecimal::withScale()` has been removed; use `toScale()` instead +- Method `BigNumber::toInteger()` has been renamed to `toInt()` + +## [0.5.4](https://github.com/brick/math/releases/tag/0.5.4) - 2016-10-17 + +`BigNumber` classes now implement [JsonSerializable](http://php.net/manual/en/class.jsonserializable.php). +The JSON output is always a string. + +## [0.5.3](https://github.com/brick/math/releases/tag/0.5.3) - 2016-03-31 + +This is a bugfix release. Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6. + +## [0.5.2](https://github.com/brick/math/releases/tag/0.5.2) - 2015-08-06 + +The `$scale` parameter of `BigDecimal::dividedBy()` is now optional again. + +## [0.5.1](https://github.com/brick/math/releases/tag/0.5.1) - 2015-07-05 + +**New method: `BigNumber::toScale()`** + +This allows to convert any `BigNumber` to a `BigDecimal` with a given scale, using rounding if necessary. + +## [0.5.0](https://github.com/brick/math/releases/tag/0.5.0) - 2015-07-04 + +**New features** +- Common `BigNumber` interface for all classes, with the following methods: + - `sign()` and derived methods (`isZero()`, `isPositive()`, ...) + - `compareTo()` and derived methods (`isEqualTo()`, `isGreaterThan()`, ...) that work across different `BigNumber` types + - `toBigInteger()`, `toBigDecimal()`, `toBigRational`() conversion methods + - `toInteger()` and `toFloat()` conversion methods to native types +- Unified `of()` behaviour: every class now accepts any type of number, provided that it can be safely converted to the current type +- New method: `BigDecimal::exactlyDividedBy()`; this method automatically computes the scale of the result, provided that the division yields a finite number of digits +- New methods: `BigRational::quotient()` and `remainder()` +- Fine-grained exceptions: `DivisionByZeroException`, `RoundingNecessaryException`, `NumberFormatException` +- Factory methods `zero()`, `one()` and `ten()` available in all classes +- Rounding mode reintroduced in `BigInteger::dividedBy()` + +This release also comes with many performance improvements. + +--- + +**Breaking changes** +- `BigInteger`: + - `getSign()` is renamed to `sign()` + - `toString()` is renamed to `toBase()` + - `BigInteger::dividedBy()` now throws an exception by default if the remainder is not zero; use `quotient()` to get the previous behaviour +- `BigDecimal`: + - `getSign()` is renamed to `sign()` + - `getUnscaledValue()` is renamed to `unscaledValue()` + - `getScale()` is renamed to `scale()` + - `getIntegral()` is renamed to `integral()` + - `getFraction()` is renamed to `fraction()` + - `divideAndRemainder()` is renamed to `quotientAndRemainder()` + - `dividedBy()` now takes a **mandatory** `$scale` parameter **before** the rounding mode + - `toBigInteger()` does not accept a `$roundingMode` parameter any more + - `toBigRational()` does not simplify the fraction any more; explicitly add `->simplified()` to get the previous behaviour +- `BigRational`: + - `getSign()` is renamed to `sign()` + - `getNumerator()` is renamed to `numerator()` + - `getDenominator()` is renamed to `denominator()` + - `of()` is renamed to `nd()`, while `parse()` is renamed to `of()` +- Miscellaneous: + - `ArithmeticException` is moved to an `Exception\` sub-namespace + - `of()` factory methods now throw `NumberFormatException` instead of `InvalidArgumentException` + +## [0.4.3](https://github.com/brick/math/releases/tag/0.4.3) - 2016-03-31 + +Backport of two bug fixes from the 0.5 branch: +- `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected +- Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6. + +## [0.4.2](https://github.com/brick/math/releases/tag/0.4.2) - 2015-06-16 + +New method: `BigDecimal::stripTrailingZeros()` + +## [0.4.1](https://github.com/brick/math/releases/tag/0.4.1) - 2015-06-12 + +Introducing a `BigRational` class, to perform calculations on fractions of any size. + +## [0.4.0](https://github.com/brick/math/releases/tag/0.4.0) - 2015-06-12 + +Rounding modes have been removed from `BigInteger`, and are now a concept specific to `BigDecimal`. + +`BigInteger::dividedBy()` now always returns the quotient of the division. + +## [0.3.5](https://github.com/brick/math/releases/tag/0.3.5) - 2016-03-31 + +Backport of two bug fixes from the 0.5 branch: + +- `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected +- Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6. + +## [0.3.4](https://github.com/brick/math/releases/tag/0.3.4) - 2015-06-11 + +New methods: +- `BigInteger::remainder()` returns the remainder of a division only +- `BigInteger::gcd()` returns the greatest common divisor of two numbers + +## [0.3.3](https://github.com/brick/math/releases/tag/0.3.3) - 2015-06-07 + +Fix `toString()` not handling negative numbers. + +## [0.3.2](https://github.com/brick/math/releases/tag/0.3.2) - 2015-06-07 + +`BigInteger` and `BigDecimal` now have a `getSign()` method that returns: +- `-1` if the number is negative +- `0` if the number is zero +- `1` if the number is positive + +## [0.3.1](https://github.com/brick/math/releases/tag/0.3.1) - 2015-06-05 + +Minor performance improvements + +## [0.3.0](https://github.com/brick/math/releases/tag/0.3.0) - 2015-06-04 + +The `$roundingMode` and `$scale` parameters have been swapped in `BigDecimal::dividedBy()`. + +## [0.2.2](https://github.com/brick/math/releases/tag/0.2.2) - 2015-06-04 + +Stronger immutability guarantee for `BigInteger` and `BigDecimal`. + +So far, it would have been possible to break immutability of these classes by calling the `unserialize()` internal function. This release fixes that. + +## [0.2.1](https://github.com/brick/math/releases/tag/0.2.1) - 2015-06-02 + +Added `BigDecimal::divideAndRemainder()` + +## [0.2.0](https://github.com/brick/math/releases/tag/0.2.0) - 2015-05-22 + +- `min()` and `max()` do not accept an `array` any more, but a variable number of parameters +- **minimum PHP version is now 5.6** +- continuous integration with PHP 7 + +## [0.1.1](https://github.com/brick/math/releases/tag/0.1.1) - 2014-09-01 + +- Added `BigInteger::power()` +- Added HHVM support + +## [0.1.0](https://github.com/brick/math/releases/tag/0.1.0) - 2014-08-31 + +First beta release. + diff --git a/vendor/brick/math/LICENSE b/vendor/brick/math/LICENSE new file mode 100755 index 0000000..f9b724f --- /dev/null +++ b/vendor/brick/math/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-present Benjamin Morel + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/brick/math/SECURITY.md b/vendor/brick/math/SECURITY.md new file mode 100755 index 0000000..cc8289b --- /dev/null +++ b/vendor/brick/math/SECURITY.md @@ -0,0 +1,17 @@ +# Security Policy + +## Supported Versions + +Only the last two release streams are supported. + +| Version | Supported | +| ------- | ------------------ | +| 0.9.x | :white_check_mark: | +| 0.8.x | :white_check_mark: | +| < 0.8 | :x: | + +## Reporting a Vulnerability + +To report a security vulnerability, please use the +[Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. diff --git a/vendor/brick/math/composer.json b/vendor/brick/math/composer.json new file mode 100755 index 0000000..ec19663 --- /dev/null +++ b/vendor/brick/math/composer.json @@ -0,0 +1,35 @@ +{ + "name": "brick/math", + "description": "Arbitrary-precision arithmetic library", + "type": "library", + "keywords": [ + "Brick", + "Math", + "Arbitrary-precision", + "Arithmetic", + "BigInteger", + "BigDecimal", + "BigRational", + "Bignum" + ], + "license": "MIT", + "require": { + "php": "^7.1 || ^8.0", + "ext-json": "*" + }, + "require-dev": { + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "php-coveralls/php-coveralls": "^2.2", + "vimeo/psalm": "4.9.2" + }, + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Brick\\Math\\Tests\\": "tests/" + } + } +} diff --git a/vendor/brick/math/src/BigDecimal.php b/vendor/brick/math/src/BigDecimal.php new file mode 100755 index 0000000..7824650 --- /dev/null +++ b/vendor/brick/math/src/BigDecimal.php @@ -0,0 +1,895 @@ +value = $value; + $this->scale = $scale; + } + + /** + * Creates a BigDecimal of the given value. + * + * @param BigNumber|int|float|string $value + * + * @return BigDecimal + * + * @throws MathException If the value cannot be converted to a BigDecimal. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + return parent::of($value)->toBigDecimal(); + } + + /** + * Creates a BigDecimal from an unscaled value and a scale. + * + * Example: `(12345, 3)` will result in the BigDecimal `12.345`. + * + * @param BigNumber|int|float|string $value The unscaled value. Must be convertible to a BigInteger. + * @param int $scale The scale of the number, positive or zero. + * + * @return BigDecimal + * + * @throws \InvalidArgumentException If the scale is negative. + * + * @psalm-pure + */ + public static function ofUnscaledValue($value, int $scale = 0) : BigDecimal + { + if ($scale < 0) { + throw new \InvalidArgumentException('The scale cannot be negative.'); + } + + return new BigDecimal((string) BigInteger::of($value), $scale); + } + + /** + * Returns a BigDecimal representing zero, with a scale of zero. + * + * @return BigDecimal + * + * @psalm-pure + */ + public static function zero() : BigDecimal + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigDecimal|null $zero + */ + static $zero; + + if ($zero === null) { + $zero = new BigDecimal('0'); + } + + return $zero; + } + + /** + * Returns a BigDecimal representing one, with a scale of zero. + * + * @return BigDecimal + * + * @psalm-pure + */ + public static function one() : BigDecimal + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigDecimal|null $one + */ + static $one; + + if ($one === null) { + $one = new BigDecimal('1'); + } + + return $one; + } + + /** + * Returns a BigDecimal representing ten, with a scale of zero. + * + * @return BigDecimal + * + * @psalm-pure + */ + public static function ten() : BigDecimal + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigDecimal|null $ten + */ + static $ten; + + if ($ten === null) { + $ten = new BigDecimal('10'); + } + + return $ten; + } + + /** + * Returns the sum of this number and the given one. + * + * The result has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. + */ + public function plus($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '0' && $that->scale <= $this->scale) { + return $this; + } + + if ($this->value === '0' && $this->scale <= $that->scale) { + return $that; + } + + [$a, $b] = $this->scaleValues($this, $that); + + $value = Calculator::get()->add($a, $b); + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the difference of this number and the given one. + * + * The result has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. + */ + public function minus($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '0' && $that->scale <= $this->scale) { + return $this; + } + + [$a, $b] = $this->scaleValues($this, $that); + + $value = Calculator::get()->sub($a, $b); + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the product of this number and the given one. + * + * The result has a scale of `$this->scale + $that->scale`. + * + * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal. + */ + public function multipliedBy($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '1' && $that->scale === 0) { + return $this; + } + + if ($this->value === '1' && $this->scale === 0) { + return $that; + } + + $value = Calculator::get()->mul($this->value, $that->value); + $scale = $this->scale + $that->scale; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the result of the division of this number by the given one, at the given scale. + * + * @param BigNumber|int|float|string $that The divisor. + * @param int|null $scale The desired scale, or null to use the scale of this number. + * @param int $roundingMode An optional rounding mode. + * + * @return BigDecimal + * + * @throws \InvalidArgumentException If the scale or rounding mode is invalid. + * @throws MathException If the number is invalid, is zero, or rounding was necessary. + */ + public function dividedBy($that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + if ($scale === null) { + $scale = $this->scale; + } elseif ($scale < 0) { + throw new \InvalidArgumentException('Scale cannot be negative.'); + } + + if ($that->value === '1' && $that->scale === 0 && $scale === $this->scale) { + return $this; + } + + $p = $this->valueWithMinScale($that->scale + $scale); + $q = $that->valueWithMinScale($this->scale - $scale); + + $result = Calculator::get()->divRound($p, $q, $roundingMode); + + return new BigDecimal($result, $scale); + } + + /** + * Returns the exact result of the division of this number by the given one. + * + * The scale of the result is automatically calculated to fit all the fraction digits. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the divisor is not a valid number, is not convertible to a BigDecimal, is zero, + * or the result yields an infinite number of digits. + */ + public function exactlyDividedBy($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + [, $b] = $this->scaleValues($this, $that); + + $d = \rtrim($b, '0'); + $scale = \strlen($b) - \strlen($d); + + $calculator = Calculator::get(); + + foreach ([5, 2] as $prime) { + for (;;) { + $lastDigit = (int) $d[-1]; + + if ($lastDigit % $prime !== 0) { + break; + } + + $d = $calculator->divQ($d, (string) $prime); + $scale++; + } + } + + return $this->dividedBy($that, $scale)->stripTrailingZeros(); + } + + /** + * Returns this number exponentiated to the given value. + * + * The result has a scale of `$this->scale * $exponent`. + * + * @param int $exponent The exponent. + * + * @return BigDecimal The result. + * + * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + */ + public function power(int $exponent) : BigDecimal + { + if ($exponent === 0) { + return BigDecimal::one(); + } + + if ($exponent === 1) { + return $this; + } + + if ($exponent < 0 || $exponent > Calculator::MAX_POWER) { + throw new \InvalidArgumentException(\sprintf( + 'The exponent %d is not in the range 0 to %d.', + $exponent, + Calculator::MAX_POWER + )); + } + + return new BigDecimal(Calculator::get()->pow($this->value, $exponent), $this->scale * $exponent); + } + + /** + * Returns the quotient of the division of this number by this given one. + * + * The quotient has a scale of `0`. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal The quotient. + * + * @throws MathException If the divisor is not a valid decimal number, or is zero. + */ + public function quotient($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + $p = $this->valueWithMinScale($that->scale); + $q = $that->valueWithMinScale($this->scale); + + $quotient = Calculator::get()->divQ($p, $q); + + return new BigDecimal($quotient, 0); + } + + /** + * Returns the remainder of the division of this number by this given one. + * + * The remainder has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal The remainder. + * + * @throws MathException If the divisor is not a valid decimal number, or is zero. + */ + public function remainder($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + $p = $this->valueWithMinScale($that->scale); + $q = $that->valueWithMinScale($this->scale); + + $remainder = Calculator::get()->divR($p, $q); + + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + return new BigDecimal($remainder, $scale); + } + + /** + * Returns the quotient and remainder of the division of this number by the given one. + * + * The quotient has a scale of `0`, and the remainder has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal[] An array containing the quotient and the remainder. + * + * @throws MathException If the divisor is not a valid decimal number, or is zero. + */ + public function quotientAndRemainder($that) : array + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + $p = $this->valueWithMinScale($that->scale); + $q = $that->valueWithMinScale($this->scale); + + [$quotient, $remainder] = Calculator::get()->divQR($p, $q); + + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + $quotient = new BigDecimal($quotient, 0); + $remainder = new BigDecimal($remainder, $scale); + + return [$quotient, $remainder]; + } + + /** + * Returns the square root of this number, rounded down to the given number of decimals. + * + * @param int $scale + * + * @return BigDecimal + * + * @throws \InvalidArgumentException If the scale is negative. + * @throws NegativeNumberException If this number is negative. + */ + public function sqrt(int $scale) : BigDecimal + { + if ($scale < 0) { + throw new \InvalidArgumentException('Scale cannot be negative.'); + } + + if ($this->value === '0') { + return new BigDecimal('0', $scale); + } + + if ($this->value[0] === '-') { + throw new NegativeNumberException('Cannot calculate the square root of a negative number.'); + } + + $value = $this->value; + $addDigits = 2 * $scale - $this->scale; + + if ($addDigits > 0) { + // add zeros + $value .= \str_repeat('0', $addDigits); + } elseif ($addDigits < 0) { + // trim digits + if (-$addDigits >= \strlen($this->value)) { + // requesting a scale too low, will always yield a zero result + return new BigDecimal('0', $scale); + } + + $value = \substr($value, 0, $addDigits); + } + + $value = Calculator::get()->sqrt($value); + + return new BigDecimal($value, $scale); + } + + /** + * Returns a copy of this BigDecimal with the decimal point moved $n places to the left. + * + * @param int $n + * + * @return BigDecimal + */ + public function withPointMovedLeft(int $n) : BigDecimal + { + if ($n === 0) { + return $this; + } + + if ($n < 0) { + return $this->withPointMovedRight(-$n); + } + + return new BigDecimal($this->value, $this->scale + $n); + } + + /** + * Returns a copy of this BigDecimal with the decimal point moved $n places to the right. + * + * @param int $n + * + * @return BigDecimal + */ + public function withPointMovedRight(int $n) : BigDecimal + { + if ($n === 0) { + return $this; + } + + if ($n < 0) { + return $this->withPointMovedLeft(-$n); + } + + $value = $this->value; + $scale = $this->scale - $n; + + if ($scale < 0) { + if ($value !== '0') { + $value .= \str_repeat('0', -$scale); + } + $scale = 0; + } + + return new BigDecimal($value, $scale); + } + + /** + * Returns a copy of this BigDecimal with any trailing zeros removed from the fractional part. + * + * @return BigDecimal + */ + public function stripTrailingZeros() : BigDecimal + { + if ($this->scale === 0) { + return $this; + } + + $trimmedValue = \rtrim($this->value, '0'); + + if ($trimmedValue === '') { + return BigDecimal::zero(); + } + + $trimmableZeros = \strlen($this->value) - \strlen($trimmedValue); + + if ($trimmableZeros === 0) { + return $this; + } + + if ($trimmableZeros > $this->scale) { + $trimmableZeros = $this->scale; + } + + $value = \substr($this->value, 0, -$trimmableZeros); + $scale = $this->scale - $trimmableZeros; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the absolute value of this number. + * + * @return BigDecimal + */ + public function abs() : BigDecimal + { + return $this->isNegative() ? $this->negated() : $this; + } + + /** + * Returns the negated value of this number. + * + * @return BigDecimal + */ + public function negated() : BigDecimal + { + return new BigDecimal(Calculator::get()->neg($this->value), $this->scale); + } + + /** + * {@inheritdoc} + */ + public function compareTo($that) : int + { + $that = BigNumber::of($that); + + if ($that instanceof BigInteger) { + $that = $that->toBigDecimal(); + } + + if ($that instanceof BigDecimal) { + [$a, $b] = $this->scaleValues($this, $that); + + return Calculator::get()->cmp($a, $b); + } + + return - $that->compareTo($this); + } + + /** + * {@inheritdoc} + */ + public function getSign() : int + { + return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1); + } + + /** + * @return BigInteger + */ + public function getUnscaledValue() : BigInteger + { + return BigInteger::create($this->value); + } + + /** + * @return int + */ + public function getScale() : int + { + return $this->scale; + } + + /** + * Returns a string representing the integral part of this decimal number. + * + * Example: `-123.456` => `-123`. + * + * @return string + */ + public function getIntegralPart() : string + { + if ($this->scale === 0) { + return $this->value; + } + + $value = $this->getUnscaledValueWithLeadingZeros(); + + return \substr($value, 0, -$this->scale); + } + + /** + * Returns a string representing the fractional part of this decimal number. + * + * If the scale is zero, an empty string is returned. + * + * Examples: `-123.456` => '456', `123` => ''. + * + * @return string + */ + public function getFractionalPart() : string + { + if ($this->scale === 0) { + return ''; + } + + $value = $this->getUnscaledValueWithLeadingZeros(); + + return \substr($value, -$this->scale); + } + + /** + * Returns whether this decimal number has a non-zero fractional part. + * + * @return bool + */ + public function hasNonZeroFractionalPart() : bool + { + return $this->getFractionalPart() !== \str_repeat('0', $this->scale); + } + + /** + * {@inheritdoc} + */ + public function toBigInteger() : BigInteger + { + $zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0); + + return BigInteger::create($zeroScaleDecimal->value); + } + + /** + * {@inheritdoc} + */ + public function toBigDecimal() : BigDecimal + { + return $this; + } + + /** + * {@inheritdoc} + */ + public function toBigRational() : BigRational + { + $numerator = BigInteger::create($this->value); + $denominator = BigInteger::create('1' . \str_repeat('0', $this->scale)); + + return BigRational::create($numerator, $denominator, false); + } + + /** + * {@inheritdoc} + */ + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + if ($scale === $this->scale) { + return $this; + } + + return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode); + } + + /** + * {@inheritdoc} + */ + public function toInt() : int + { + return $this->toBigInteger()->toInt(); + } + + /** + * {@inheritdoc} + */ + public function toFloat() : float + { + return (float) (string) $this; + } + + /** + * {@inheritdoc} + */ + public function __toString() : string + { + if ($this->scale === 0) { + return $this->value; + } + + $value = $this->getUnscaledValueWithLeadingZeros(); + + return \substr($value, 0, -$this->scale) . '.' . \substr($value, -$this->scale); + } + + /** + * This method is required for serializing the object and SHOULD NOT be accessed directly. + * + * @internal + * + * @return array{value: string, scale: int} + */ + public function __serialize(): array + { + return ['value' => $this->value, 'scale' => $this->scale]; + } + + /** + * This method is only here to allow unserializing the object and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param array{value: string, scale: int} $data + * + * @return void + * + * @throws \LogicException + */ + public function __unserialize(array $data): void + { + if (isset($this->value)) { + throw new \LogicException('__unserialize() is an internal function, it must not be called directly.'); + } + + $this->value = $data['value']; + $this->scale = $data['scale']; + } + + /** + * This method is required by interface Serializable and SHOULD NOT be accessed directly. + * + * @internal + * + * @return string + */ + public function serialize() : string + { + return $this->value . ':' . $this->scale; + } + + /** + * This method is only here to implement interface Serializable and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param string $value + * + * @return void + * + * @throws \LogicException + */ + public function unserialize($value) : void + { + if (isset($this->value)) { + throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); + } + + [$value, $scale] = \explode(':', $value); + + $this->value = $value; + $this->scale = (int) $scale; + } + + /** + * Puts the internal values of the given decimal numbers on the same scale. + * + * @param BigDecimal $x The first decimal number. + * @param BigDecimal $y The second decimal number. + * + * @return array{string, string} The scaled integer values of $x and $y. + */ + private function scaleValues(BigDecimal $x, BigDecimal $y) : array + { + $a = $x->value; + $b = $y->value; + + if ($b !== '0' && $x->scale > $y->scale) { + $b .= \str_repeat('0', $x->scale - $y->scale); + } elseif ($a !== '0' && $x->scale < $y->scale) { + $a .= \str_repeat('0', $y->scale - $x->scale); + } + + return [$a, $b]; + } + + /** + * @param int $scale + * + * @return string + */ + private function valueWithMinScale(int $scale) : string + { + $value = $this->value; + + if ($this->value !== '0' && $scale > $this->scale) { + $value .= \str_repeat('0', $scale - $this->scale); + } + + return $value; + } + + /** + * Adds leading zeros if necessary to the unscaled value to represent the full decimal number. + * + * @return string + */ + private function getUnscaledValueWithLeadingZeros() : string + { + $value = $this->value; + $targetLength = $this->scale + 1; + $negative = ($value[0] === '-'); + $length = \strlen($value); + + if ($negative) { + $length--; + } + + if ($length >= $targetLength) { + return $this->value; + } + + if ($negative) { + $value = \substr($value, 1); + } + + $value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT); + + if ($negative) { + $value = '-' . $value; + } + + return $value; + } +} diff --git a/vendor/brick/math/src/BigInteger.php b/vendor/brick/math/src/BigInteger.php new file mode 100755 index 0000000..f213fbe --- /dev/null +++ b/vendor/brick/math/src/BigInteger.php @@ -0,0 +1,1184 @@ +value = $value; + } + + /** + * Creates a BigInteger of the given value. + * + * @param BigNumber|int|float|string $value + * + * @return BigInteger + * + * @throws MathException If the value cannot be converted to a BigInteger. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + return parent::of($value)->toBigInteger(); + } + + /** + * Creates a number from a string in a given base. + * + * The string can optionally be prefixed with the `+` or `-` sign. + * + * Bases greater than 36 are not supported by this method, as there is no clear consensus on which of the lowercase + * or uppercase characters should come first. Instead, this method accepts any base up to 36, and does not + * differentiate lowercase and uppercase characters, which are considered equal. + * + * For bases greater than 36, and/or custom alphabets, use the fromArbitraryBase() method. + * + * @param string $number The number to convert, in the given base. + * @param int $base The base of the number, between 2 and 36. + * + * @return BigInteger + * + * @throws NumberFormatException If the number is empty, or contains invalid chars for the given base. + * @throws \InvalidArgumentException If the base is out of range. + * + * @psalm-pure + */ + public static function fromBase(string $number, int $base) : BigInteger + { + if ($number === '') { + throw new NumberFormatException('The number cannot be empty.'); + } + + if ($base < 2 || $base > 36) { + throw new \InvalidArgumentException(\sprintf('Base %d is not in range 2 to 36.', $base)); + } + + if ($number[0] === '-') { + $sign = '-'; + $number = \substr($number, 1); + } elseif ($number[0] === '+') { + $sign = ''; + $number = \substr($number, 1); + } else { + $sign = ''; + } + + if ($number === '') { + throw new NumberFormatException('The number cannot be empty.'); + } + + $number = \ltrim($number, '0'); + + if ($number === '') { + // The result will be the same in any base, avoid further calculation. + return BigInteger::zero(); + } + + if ($number === '1') { + // The result will be the same in any base, avoid further calculation. + return new BigInteger($sign . '1'); + } + + $pattern = '/[^' . \substr(Calculator::ALPHABET, 0, $base) . ']/'; + + if (\preg_match($pattern, \strtolower($number), $matches) === 1) { + throw new NumberFormatException(\sprintf('"%s" is not a valid character in base %d.', $matches[0], $base)); + } + + if ($base === 10) { + // The number is usable as is, avoid further calculation. + return new BigInteger($sign . $number); + } + + $result = Calculator::get()->fromBase($number, $base); + + return new BigInteger($sign . $result); + } + + /** + * Parses a string containing an integer in an arbitrary base, using a custom alphabet. + * + * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers. + * + * @param string $number The number to parse. + * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8. + * + * @return BigInteger + * + * @throws NumberFormatException If the given number is empty or contains invalid chars for the given alphabet. + * @throws \InvalidArgumentException If the alphabet does not contain at least 2 chars. + * + * @psalm-pure + */ + public static function fromArbitraryBase(string $number, string $alphabet) : BigInteger + { + if ($number === '') { + throw new NumberFormatException('The number cannot be empty.'); + } + + $base = \strlen($alphabet); + + if ($base < 2) { + throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.'); + } + + $pattern = '/[^' . \preg_quote($alphabet, '/') . ']/'; + + if (\preg_match($pattern, $number, $matches) === 1) { + throw NumberFormatException::charNotInAlphabet($matches[0]); + } + + $number = Calculator::get()->fromArbitraryBase($number, $alphabet, $base); + + return new BigInteger($number); + } + + /** + * Translates a string of bytes containing the binary representation of a BigInteger into a BigInteger. + * + * The input string is assumed to be in big-endian byte-order: the most significant byte is in the zeroth element. + * + * If `$signed` is true, the input is assumed to be in two's-complement representation, and the leading bit is + * interpreted as a sign bit. If `$signed` is false, the input is interpreted as an unsigned number, and the + * resulting BigInteger will always be positive or zero. + * + * This method can be used to retrieve a number exported by `toBytes()`, as long as the `$signed` flags match. + * + * @param string $value The byte string. + * @param bool $signed Whether to interpret as a signed number in two's-complement representation with a leading + * sign bit. + * + * @return BigInteger + * + * @throws NumberFormatException If the string is empty. + */ + public static function fromBytes(string $value, bool $signed = true) : BigInteger + { + if ($value === '') { + throw new NumberFormatException('The byte string must not be empty.'); + } + + $twosComplement = false; + + if ($signed) { + $x = \ord($value[0]); + + if (($twosComplement = ($x >= 0x80))) { + $value = ~$value; + } + } + + $number = self::fromBase(\bin2hex($value), 16); + + if ($twosComplement) { + return $number->plus(1)->negated(); + } + + return $number; + } + + /** + * Generates a pseudo-random number in the range 0 to 2^numBits - 1. + * + * Using the default random bytes generator, this method is suitable for cryptographic use. + * + * @psalm-param callable(int): string $randomBytesGenerator + * + * @param int $numBits The number of bits. + * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer, and returns a + * string of random bytes of the given length. Defaults to the + * `random_bytes()` function. + * + * @return BigInteger + * + * @throws \InvalidArgumentException If $numBits is negative. + */ + public static function randomBits(int $numBits, ?callable $randomBytesGenerator = null) : BigInteger + { + if ($numBits < 0) { + throw new \InvalidArgumentException('The number of bits cannot be negative.'); + } + + if ($numBits === 0) { + return BigInteger::zero(); + } + + if ($randomBytesGenerator === null) { + $randomBytesGenerator = 'random_bytes'; + } + + $byteLength = \intdiv($numBits - 1, 8) + 1; + + $extraBits = ($byteLength * 8 - $numBits); + $bitmask = \chr(0xFF >> $extraBits); + + $randomBytes = $randomBytesGenerator($byteLength); + $randomBytes[0] = $randomBytes[0] & $bitmask; + + return self::fromBytes($randomBytes, false); + } + + /** + * Generates a pseudo-random number between `$min` and `$max`. + * + * Using the default random bytes generator, this method is suitable for cryptographic use. + * + * @psalm-param (callable(int): string)|null $randomBytesGenerator + * + * @param BigNumber|int|float|string $min The lower bound. Must be convertible to a BigInteger. + * @param BigNumber|int|float|string $max The upper bound. Must be convertible to a BigInteger. + * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer, + * and returns a string of random bytes of the given length. + * Defaults to the `random_bytes()` function. + * + * @return BigInteger + * + * @throws MathException If one of the parameters cannot be converted to a BigInteger, + * or `$min` is greater than `$max`. + */ + public static function randomRange($min, $max, ?callable $randomBytesGenerator = null) : BigInteger + { + $min = BigInteger::of($min); + $max = BigInteger::of($max); + + if ($min->isGreaterThan($max)) { + throw new MathException('$min cannot be greater than $max.'); + } + + if ($min->isEqualTo($max)) { + return $min; + } + + $diff = $max->minus($min); + $bitLength = $diff->getBitLength(); + + // try until the number is in range (50% to 100% chance of success) + do { + $randomNumber = self::randomBits($bitLength, $randomBytesGenerator); + } while ($randomNumber->isGreaterThan($diff)); + + return $randomNumber->plus($min); + } + + /** + * Returns a BigInteger representing zero. + * + * @return BigInteger + * + * @psalm-pure + */ + public static function zero() : BigInteger + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigInteger|null $zero + */ + static $zero; + + if ($zero === null) { + $zero = new BigInteger('0'); + } + + return $zero; + } + + /** + * Returns a BigInteger representing one. + * + * @return BigInteger + * + * @psalm-pure + */ + public static function one() : BigInteger + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigInteger|null $one + */ + static $one; + + if ($one === null) { + $one = new BigInteger('1'); + } + + return $one; + } + + /** + * Returns a BigInteger representing ten. + * + * @return BigInteger + * + * @psalm-pure + */ + public static function ten() : BigInteger + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigInteger|null $ten + */ + static $ten; + + if ($ten === null) { + $ten = new BigInteger('10'); + } + + return $ten; + } + + /** + * Returns the sum of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigInteger. + * + * @return BigInteger The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigInteger. + */ + public function plus($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + return $this; + } + + if ($this->value === '0') { + return $that; + } + + $value = Calculator::get()->add($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the difference of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigInteger. + * + * @return BigInteger The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigInteger. + */ + public function minus($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + return $this; + } + + $value = Calculator::get()->sub($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the product of this number and the given one. + * + * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigInteger. + * + * @return BigInteger The result. + * + * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigInteger. + */ + public function multipliedBy($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return $this; + } + + if ($this->value === '1') { + return $that; + } + + $value = Calculator::get()->mul($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the result of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * @param int $roundingMode An optional rounding mode. + * + * @return BigInteger The result. + * + * @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero, + * or RoundingMode::UNNECESSARY is used and the remainder is not zero. + */ + public function dividedBy($that, int $roundingMode = RoundingMode::UNNECESSARY) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return $this; + } + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + $result = Calculator::get()->divRound($this->value, $that->value, $roundingMode); + + return new BigInteger($result); + } + + /** + * Returns this number exponentiated to the given value. + * + * @param int $exponent The exponent. + * + * @return BigInteger The result. + * + * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + */ + public function power(int $exponent) : BigInteger + { + if ($exponent === 0) { + return BigInteger::one(); + } + + if ($exponent === 1) { + return $this; + } + + if ($exponent < 0 || $exponent > Calculator::MAX_POWER) { + throw new \InvalidArgumentException(\sprintf( + 'The exponent %d is not in the range 0 to %d.', + $exponent, + Calculator::MAX_POWER + )); + } + + return new BigInteger(Calculator::get()->pow($this->value, $exponent)); + } + + /** + * Returns the quotient of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function quotient($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return $this; + } + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + $quotient = Calculator::get()->divQ($this->value, $that->value); + + return new BigInteger($quotient); + } + + /** + * Returns the remainder of the division of this number by the given one. + * + * The remainder, when non-zero, has the same sign as the dividend. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function remainder($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return BigInteger::zero(); + } + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + $remainder = Calculator::get()->divR($this->value, $that->value); + + return new BigInteger($remainder); + } + + /** + * Returns the quotient and remainder of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger[] An array containing the quotient and the remainder. + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function quotientAndRemainder($that) : array + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + [$quotient, $remainder] = Calculator::get()->divQR($this->value, $that->value); + + return [ + new BigInteger($quotient), + new BigInteger($remainder) + ]; + } + + /** + * Returns the modulo of this number and the given one. + * + * The modulo operation yields the same result as the remainder operation when both operands are of the same sign, + * and may differ when signs are different. + * + * The result of the modulo operation, when non-zero, has the same sign as the divisor. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function mod($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + throw DivisionByZeroException::modulusMustNotBeZero(); + } + + $value = Calculator::get()->mod($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the modular multiplicative inverse of this BigInteger modulo $m. + * + * @param BigInteger $m + * + * @return BigInteger + * + * @throws DivisionByZeroException If $m is zero. + * @throws NegativeNumberException If $m is negative. + * @throws MathException If this BigInteger has no multiplicative inverse mod m (that is, this BigInteger + * is not relatively prime to m). + */ + public function modInverse(BigInteger $m) : BigInteger + { + if ($m->value === '0') { + throw DivisionByZeroException::modulusMustNotBeZero(); + } + + if ($m->isNegative()) { + throw new NegativeNumberException('Modulus must not be negative.'); + } + + if ($m->value === '1') { + return BigInteger::zero(); + } + + $value = Calculator::get()->modInverse($this->value, $m->value); + + if ($value === null) { + throw new MathException('Unable to compute the modInverse for the given modulus.'); + } + + return new BigInteger($value); + } + + /** + * Returns this number raised into power with modulo. + * + * This operation only works on positive numbers. + * + * @param BigNumber|int|float|string $exp The exponent. Must be positive or zero. + * @param BigNumber|int|float|string $mod The modulus. Must be strictly positive. + * + * @return BigInteger + * + * @throws NegativeNumberException If any of the operands is negative. + * @throws DivisionByZeroException If the modulus is zero. + */ + public function modPow($exp, $mod) : BigInteger + { + $exp = BigInteger::of($exp); + $mod = BigInteger::of($mod); + + if ($this->isNegative() || $exp->isNegative() || $mod->isNegative()) { + throw new NegativeNumberException('The operands cannot be negative.'); + } + + if ($mod->isZero()) { + throw DivisionByZeroException::modulusMustNotBeZero(); + } + + $result = Calculator::get()->modPow($this->value, $exp->value, $mod->value); + + return new BigInteger($result); + } + + /** + * Returns the greatest common divisor of this number and the given one. + * + * The GCD is always positive, unless both operands are zero, in which case it is zero. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function gcd($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0' && $this->value[0] !== '-') { + return $this; + } + + if ($this->value === '0' && $that->value[0] !== '-') { + return $that; + } + + $value = Calculator::get()->gcd($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the integer square root number of this number, rounded down. + * + * The result is the largest x such that x² ≤ n. + * + * @return BigInteger + * + * @throws NegativeNumberException If this number is negative. + */ + public function sqrt() : BigInteger + { + if ($this->value[0] === '-') { + throw new NegativeNumberException('Cannot calculate the square root of a negative number.'); + } + + $value = Calculator::get()->sqrt($this->value); + + return new BigInteger($value); + } + + /** + * Returns the absolute value of this number. + * + * @return BigInteger + */ + public function abs() : BigInteger + { + return $this->isNegative() ? $this->negated() : $this; + } + + /** + * Returns the inverse of this number. + * + * @return BigInteger + */ + public function negated() : BigInteger + { + return new BigInteger(Calculator::get()->neg($this->value)); + } + + /** + * Returns the integer bitwise-and combined with another integer. + * + * This method returns a negative BigInteger if and only if both operands are negative. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function and($that) : BigInteger + { + $that = BigInteger::of($that); + + return new BigInteger(Calculator::get()->and($this->value, $that->value)); + } + + /** + * Returns the integer bitwise-or combined with another integer. + * + * This method returns a negative BigInteger if and only if either of the operands is negative. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function or($that) : BigInteger + { + $that = BigInteger::of($that); + + return new BigInteger(Calculator::get()->or($this->value, $that->value)); + } + + /** + * Returns the integer bitwise-xor combined with another integer. + * + * This method returns a negative BigInteger if and only if exactly one of the operands is negative. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function xor($that) : BigInteger + { + $that = BigInteger::of($that); + + return new BigInteger(Calculator::get()->xor($this->value, $that->value)); + } + + /** + * Returns the bitwise-not of this BigInteger. + * + * @return BigInteger + */ + public function not() : BigInteger + { + return $this->negated()->minus(1); + } + + /** + * Returns the integer left shifted by a given number of bits. + * + * @param int $distance The distance to shift. + * + * @return BigInteger + */ + public function shiftedLeft(int $distance) : BigInteger + { + if ($distance === 0) { + return $this; + } + + if ($distance < 0) { + return $this->shiftedRight(- $distance); + } + + return $this->multipliedBy(BigInteger::of(2)->power($distance)); + } + + /** + * Returns the integer right shifted by a given number of bits. + * + * @param int $distance The distance to shift. + * + * @return BigInteger + */ + public function shiftedRight(int $distance) : BigInteger + { + if ($distance === 0) { + return $this; + } + + if ($distance < 0) { + return $this->shiftedLeft(- $distance); + } + + $operand = BigInteger::of(2)->power($distance); + + if ($this->isPositiveOrZero()) { + return $this->quotient($operand); + } + + return $this->dividedBy($operand, RoundingMode::UP); + } + + /** + * Returns the number of bits in the minimal two's-complement representation of this BigInteger, excluding a sign bit. + * + * For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation. + * Computes (ceil(log2(this < 0 ? -this : this+1))). + * + * @return int + */ + public function getBitLength() : int + { + if ($this->value === '0') { + return 0; + } + + if ($this->isNegative()) { + return $this->abs()->minus(1)->getBitLength(); + } + + return \strlen($this->toBase(2)); + } + + /** + * Returns the index of the rightmost (lowest-order) one bit in this BigInteger. + * + * Returns -1 if this BigInteger contains no one bits. + * + * @return int + */ + public function getLowestSetBit() : int + { + $n = $this; + $bitLength = $this->getBitLength(); + + for ($i = 0; $i <= $bitLength; $i++) { + if ($n->isOdd()) { + return $i; + } + + $n = $n->shiftedRight(1); + } + + return -1; + } + + /** + * Returns whether this number is even. + * + * @return bool + */ + public function isEven() : bool + { + return \in_array($this->value[-1], ['0', '2', '4', '6', '8'], true); + } + + /** + * Returns whether this number is odd. + * + * @return bool + */ + public function isOdd() : bool + { + return \in_array($this->value[-1], ['1', '3', '5', '7', '9'], true); + } + + /** + * Returns true if and only if the designated bit is set. + * + * Computes ((this & (1<shiftedRight($n)->isOdd(); + } + + /** + * {@inheritdoc} + */ + public function compareTo($that) : int + { + $that = BigNumber::of($that); + + if ($that instanceof BigInteger) { + return Calculator::get()->cmp($this->value, $that->value); + } + + return - $that->compareTo($this); + } + + /** + * {@inheritdoc} + */ + public function getSign() : int + { + return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1); + } + + /** + * {@inheritdoc} + */ + public function toBigInteger() : BigInteger + { + return $this; + } + + /** + * {@inheritdoc} + */ + public function toBigDecimal() : BigDecimal + { + return BigDecimal::create($this->value); + } + + /** + * {@inheritdoc} + */ + public function toBigRational() : BigRational + { + return BigRational::create($this, BigInteger::one(), false); + } + + /** + * {@inheritdoc} + */ + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + return $this->toBigDecimal()->toScale($scale, $roundingMode); + } + + /** + * {@inheritdoc} + */ + public function toInt() : int + { + $intValue = (int) $this->value; + + if ($this->value !== (string) $intValue) { + throw IntegerOverflowException::toIntOverflow($this); + } + + return $intValue; + } + + /** + * {@inheritdoc} + */ + public function toFloat() : float + { + return (float) $this->value; + } + + /** + * Returns a string representation of this number in the given base. + * + * The output will always be lowercase for bases greater than 10. + * + * @param int $base + * + * @return string + * + * @throws \InvalidArgumentException If the base is out of range. + */ + public function toBase(int $base) : string + { + if ($base === 10) { + return $this->value; + } + + if ($base < 2 || $base > 36) { + throw new \InvalidArgumentException(\sprintf('Base %d is out of range [2, 36]', $base)); + } + + return Calculator::get()->toBase($this->value, $base); + } + + /** + * Returns a string representation of this number in an arbitrary base with a custom alphabet. + * + * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers; + * a NegativeNumberException will be thrown when attempting to call this method on a negative number. + * + * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8. + * + * @return string + * + * @throws NegativeNumberException If this number is negative. + * @throws \InvalidArgumentException If the given alphabet does not contain at least 2 chars. + */ + public function toArbitraryBase(string $alphabet) : string + { + $base = \strlen($alphabet); + + if ($base < 2) { + throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.'); + } + + if ($this->value[0] === '-') { + throw new NegativeNumberException(__FUNCTION__ . '() does not support negative numbers.'); + } + + return Calculator::get()->toArbitraryBase($this->value, $alphabet, $base); + } + + /** + * Returns a string of bytes containing the binary representation of this BigInteger. + * + * The string is in big-endian byte-order: the most significant byte is in the zeroth element. + * + * If `$signed` is true, the output will be in two's-complement representation, and a sign bit will be prepended to + * the output. If `$signed` is false, no sign bit will be prepended, and this method will throw an exception if the + * number is negative. + * + * The string will contain the minimum number of bytes required to represent this BigInteger, including a sign bit + * if `$signed` is true. + * + * This representation is compatible with the `fromBytes()` factory method, as long as the `$signed` flags match. + * + * @param bool $signed Whether to output a signed number in two's-complement representation with a leading sign bit. + * + * @return string + * + * @throws NegativeNumberException If $signed is false, and the number is negative. + */ + public function toBytes(bool $signed = true) : string + { + if (! $signed && $this->isNegative()) { + throw new NegativeNumberException('Cannot convert a negative number to a byte string when $signed is false.'); + } + + $hex = $this->abs()->toBase(16); + + if (\strlen($hex) % 2 !== 0) { + $hex = '0' . $hex; + } + + $baseHexLength = \strlen($hex); + + if ($signed) { + if ($this->isNegative()) { + $bin = \hex2bin($hex); + assert($bin !== false); + + $hex = \bin2hex(~$bin); + $hex = self::fromBase($hex, 16)->plus(1)->toBase(16); + + $hexLength = \strlen($hex); + + if ($hexLength < $baseHexLength) { + $hex = \str_repeat('0', $baseHexLength - $hexLength) . $hex; + } + + if ($hex[0] < '8') { + $hex = 'FF' . $hex; + } + } else { + if ($hex[0] >= '8') { + $hex = '00' . $hex; + } + } + } + + return \hex2bin($hex); + } + + /** + * {@inheritdoc} + */ + public function __toString() : string + { + return $this->value; + } + + /** + * This method is required for serializing the object and SHOULD NOT be accessed directly. + * + * @internal + * + * @return array{value: string} + */ + public function __serialize(): array + { + return ['value' => $this->value]; + } + + /** + * This method is only here to allow unserializing the object and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param array{value: string} $data + * + * @return void + * + * @throws \LogicException + */ + public function __unserialize(array $data): void + { + if (isset($this->value)) { + throw new \LogicException('__unserialize() is an internal function, it must not be called directly.'); + } + + $this->value = $data['value']; + } + + /** + * This method is required by interface Serializable and SHOULD NOT be accessed directly. + * + * @internal + * + * @return string + */ + public function serialize() : string + { + return $this->value; + } + + /** + * This method is only here to implement interface Serializable and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param string $value + * + * @return void + * + * @throws \LogicException + */ + public function unserialize($value) : void + { + if (isset($this->value)) { + throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); + } + + $this->value = $value; + } +} diff --git a/vendor/brick/math/src/BigNumber.php b/vendor/brick/math/src/BigNumber.php new file mode 100755 index 0000000..38c8c55 --- /dev/null +++ b/vendor/brick/math/src/BigNumber.php @@ -0,0 +1,572 @@ +[\-\+])?' . + '(?:' . + '(?:' . + '(?[0-9]+)?' . + '(?\.)?' . + '(?[0-9]+)?' . + '(?:[eE](?[\-\+]?[0-9]+))?' . + ')|(?:' . + '(?[0-9]+)' . + '\/?' . + '(?[0-9]+)' . + ')' . + ')' . + '$/'; + + /** + * Creates a BigNumber of the given value. + * + * The concrete return type is dependent on the given value, with the following rules: + * + * - BigNumber instances are returned as is + * - integer numbers are returned as BigInteger + * - floating point numbers are converted to a string then parsed as such + * - strings containing a `/` character are returned as BigRational + * - strings containing a `.` character or using an exponential notation are returned as BigDecimal + * - strings containing only digits with an optional leading `+` or `-` sign are returned as BigInteger + * + * @param BigNumber|int|float|string $value + * + * @return BigNumber + * + * @throws NumberFormatException If the format of the number is not valid. + * @throws DivisionByZeroException If the value represents a rational number with a denominator of zero. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + if ($value instanceof BigNumber) { + return $value; + } + + if (\is_int($value)) { + return new BigInteger((string) $value); + } + + /** @psalm-suppress RedundantCastGivenDocblockType We cannot trust the untyped $value here! */ + $value = \is_float($value) ? self::floatToString($value) : (string) $value; + + $throw = static function() use ($value) : void { + throw new NumberFormatException(\sprintf( + 'The given value "%s" does not represent a valid number.', + $value + )); + }; + + if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) { + $throw(); + } + + $getMatch = static function(string $value) use ($matches) : ?string { + return isset($matches[$value]) && $matches[$value] !== '' ? $matches[$value] : null; + }; + + $sign = $getMatch('sign'); + $numerator = $getMatch('numerator'); + $denominator = $getMatch('denominator'); + + if ($numerator !== null) { + assert($denominator !== null); + + if ($sign !== null) { + $numerator = $sign . $numerator; + } + + $numerator = self::cleanUp($numerator); + $denominator = self::cleanUp($denominator); + + if ($denominator === '0') { + throw DivisionByZeroException::denominatorMustNotBeZero(); + } + + return new BigRational( + new BigInteger($numerator), + new BigInteger($denominator), + false + ); + } + + $point = $getMatch('point'); + $integral = $getMatch('integral'); + $fractional = $getMatch('fractional'); + $exponent = $getMatch('exponent'); + + if ($integral === null && $fractional === null) { + $throw(); + } + + if ($integral === null) { + $integral = '0'; + } + + if ($point !== null || $exponent !== null) { + $fractional = ($fractional ?? ''); + $exponent = ($exponent !== null) ? (int) $exponent : 0; + + if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) { + throw new NumberFormatException('Exponent too large.'); + } + + $unscaledValue = self::cleanUp(($sign ?? ''). $integral . $fractional); + + $scale = \strlen($fractional) - $exponent; + + if ($scale < 0) { + if ($unscaledValue !== '0') { + $unscaledValue .= \str_repeat('0', - $scale); + } + $scale = 0; + } + + return new BigDecimal($unscaledValue, $scale); + } + + $integral = self::cleanUp(($sign ?? '') . $integral); + + return new BigInteger($integral); + } + + /** + * Safely converts float to string, avoiding locale-dependent issues. + * + * @see https://github.com/brick/math/pull/20 + * + * @param float $float + * + * @return string + * + * @psalm-pure + * @psalm-suppress ImpureFunctionCall + */ + private static function floatToString(float $float) : string + { + $currentLocale = \setlocale(LC_NUMERIC, '0'); + \setlocale(LC_NUMERIC, 'C'); + + $result = (string) $float; + + \setlocale(LC_NUMERIC, $currentLocale); + + return $result; + } + + /** + * Proxy method to access protected constructors from sibling classes. + * + * @internal + * + * @param mixed ...$args The arguments to the constructor. + * + * @return static + * + * @psalm-pure + * @psalm-suppress TooManyArguments + * @psalm-suppress UnsafeInstantiation + */ + protected static function create(... $args) : BigNumber + { + return new static(... $args); + } + + /** + * Returns the minimum of the given values. + * + * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible + * to an instance of the class this method is called on. + * + * @return static The minimum value. + * + * @throws \InvalidArgumentException If no values are given. + * @throws MathException If an argument is not valid. + * + * @psalm-suppress LessSpecificReturnStatement + * @psalm-suppress MoreSpecificReturnType + * @psalm-pure + */ + public static function min(...$values) : BigNumber + { + $min = null; + + foreach ($values as $value) { + $value = static::of($value); + + if ($min === null || $value->isLessThan($min)) { + $min = $value; + } + } + + if ($min === null) { + throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); + } + + return $min; + } + + /** + * Returns the maximum of the given values. + * + * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible + * to an instance of the class this method is called on. + * + * @return static The maximum value. + * + * @throws \InvalidArgumentException If no values are given. + * @throws MathException If an argument is not valid. + * + * @psalm-suppress LessSpecificReturnStatement + * @psalm-suppress MoreSpecificReturnType + * @psalm-pure + */ + public static function max(...$values) : BigNumber + { + $max = null; + + foreach ($values as $value) { + $value = static::of($value); + + if ($max === null || $value->isGreaterThan($max)) { + $max = $value; + } + } + + if ($max === null) { + throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); + } + + return $max; + } + + /** + * Returns the sum of the given values. + * + * @param BigNumber|int|float|string ...$values The numbers to add. All the numbers need to be convertible + * to an instance of the class this method is called on. + * + * @return static The sum. + * + * @throws \InvalidArgumentException If no values are given. + * @throws MathException If an argument is not valid. + * + * @psalm-suppress LessSpecificReturnStatement + * @psalm-suppress MoreSpecificReturnType + * @psalm-pure + */ + public static function sum(...$values) : BigNumber + { + /** @var BigNumber|null $sum */ + $sum = null; + + foreach ($values as $value) { + $value = static::of($value); + + $sum = $sum === null ? $value : self::add($sum, $value); + } + + if ($sum === null) { + throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); + } + + return $sum; + } + + /** + * Adds two BigNumber instances in the correct order to avoid a RoundingNecessaryException. + * + * @todo This could be better resolved by creating an abstract protected method in BigNumber, and leaving to + * concrete classes the responsibility to perform the addition themselves or delegate it to the given number, + * depending on their ability to perform the operation. This will also require a version bump because we're + * potentially breaking custom BigNumber implementations (if any...) + * + * @param BigNumber $a + * @param BigNumber $b + * + * @return BigNumber + * + * @psalm-pure + */ + private static function add(BigNumber $a, BigNumber $b) : BigNumber + { + if ($a instanceof BigRational) { + return $a->plus($b); + } + + if ($b instanceof BigRational) { + return $b->plus($a); + } + + if ($a instanceof BigDecimal) { + return $a->plus($b); + } + + if ($b instanceof BigDecimal) { + return $b->plus($a); + } + + /** @var BigInteger $a */ + + return $a->plus($b); + } + + /** + * Removes optional leading zeros and + sign from the given number. + * + * @param string $number The number, validated as a non-empty string of digits with optional leading sign. + * + * @return string + * + * @psalm-pure + */ + private static function cleanUp(string $number) : string + { + $firstChar = $number[0]; + + if ($firstChar === '+' || $firstChar === '-') { + $number = \substr($number, 1); + } + + $number = \ltrim($number, '0'); + + if ($number === '') { + return '0'; + } + + if ($firstChar === '-') { + return '-' . $number; + } + + return $number; + } + + /** + * Checks if this number is equal to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isEqualTo($that) : bool + { + return $this->compareTo($that) === 0; + } + + /** + * Checks if this number is strictly lower than the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isLessThan($that) : bool + { + return $this->compareTo($that) < 0; + } + + /** + * Checks if this number is lower than or equal to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isLessThanOrEqualTo($that) : bool + { + return $this->compareTo($that) <= 0; + } + + /** + * Checks if this number is strictly greater than the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isGreaterThan($that) : bool + { + return $this->compareTo($that) > 0; + } + + /** + * Checks if this number is greater than or equal to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isGreaterThanOrEqualTo($that) : bool + { + return $this->compareTo($that) >= 0; + } + + /** + * Checks if this number equals zero. + * + * @return bool + */ + public function isZero() : bool + { + return $this->getSign() === 0; + } + + /** + * Checks if this number is strictly negative. + * + * @return bool + */ + public function isNegative() : bool + { + return $this->getSign() < 0; + } + + /** + * Checks if this number is negative or zero. + * + * @return bool + */ + public function isNegativeOrZero() : bool + { + return $this->getSign() <= 0; + } + + /** + * Checks if this number is strictly positive. + * + * @return bool + */ + public function isPositive() : bool + { + return $this->getSign() > 0; + } + + /** + * Checks if this number is positive or zero. + * + * @return bool + */ + public function isPositiveOrZero() : bool + { + return $this->getSign() >= 0; + } + + /** + * Returns the sign of this number. + * + * @return int -1 if the number is negative, 0 if zero, 1 if positive. + */ + abstract public function getSign() : int; + + /** + * Compares this number to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`. + * + * @throws MathException If the number is not valid. + */ + abstract public function compareTo($that) : int; + + /** + * Converts this number to a BigInteger. + * + * @return BigInteger The converted number. + * + * @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding. + */ + abstract public function toBigInteger() : BigInteger; + + /** + * Converts this number to a BigDecimal. + * + * @return BigDecimal The converted number. + * + * @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding. + */ + abstract public function toBigDecimal() : BigDecimal; + + /** + * Converts this number to a BigRational. + * + * @return BigRational The converted number. + */ + abstract public function toBigRational() : BigRational; + + /** + * Converts this number to a BigDecimal with the given scale, using rounding if necessary. + * + * @param int $scale The scale of the resulting `BigDecimal`. + * @param int $roundingMode A `RoundingMode` constant. + * + * @return BigDecimal + * + * @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding. + * This only applies when RoundingMode::UNNECESSARY is used. + */ + abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal; + + /** + * Returns the exact value of this number as a native integer. + * + * If this number cannot be converted to a native integer without losing precision, an exception is thrown. + * Note that the acceptable range for an integer depends on the platform and differs for 32-bit and 64-bit. + * + * @return int The converted value. + * + * @throws MathException If this number cannot be exactly converted to a native integer. + */ + abstract public function toInt() : int; + + /** + * Returns an approximation of this number as a floating-point value. + * + * Note that this method can discard information as the precision of a floating-point value + * is inherently limited. + * + * If the number is greater than the largest representable floating point number, positive infinity is returned. + * If the number is less than the smallest representable floating point number, negative infinity is returned. + * + * @return float The converted value. + */ + abstract public function toFloat() : float; + + /** + * Returns a string representation of this number. + * + * The output of this method can be parsed by the `of()` factory method; + * this will yield an object equal to this one, without any information loss. + * + * @return string + */ + abstract public function __toString() : string; + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : string + { + return $this->__toString(); + } +} diff --git a/vendor/brick/math/src/BigRational.php b/vendor/brick/math/src/BigRational.php new file mode 100755 index 0000000..bee094f --- /dev/null +++ b/vendor/brick/math/src/BigRational.php @@ -0,0 +1,523 @@ +isZero()) { + throw DivisionByZeroException::denominatorMustNotBeZero(); + } + + if ($denominator->isNegative()) { + $numerator = $numerator->negated(); + $denominator = $denominator->negated(); + } + } + + $this->numerator = $numerator; + $this->denominator = $denominator; + } + + /** + * Creates a BigRational of the given value. + * + * @param BigNumber|int|float|string $value + * + * @return BigRational + * + * @throws MathException If the value cannot be converted to a BigRational. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + return parent::of($value)->toBigRational(); + } + + /** + * Creates a BigRational out of a numerator and a denominator. + * + * If the denominator is negative, the signs of both the numerator and the denominator + * will be inverted to ensure that the denominator is always positive. + * + * @param BigNumber|int|float|string $numerator The numerator. Must be convertible to a BigInteger. + * @param BigNumber|int|float|string $denominator The denominator. Must be convertible to a BigInteger. + * + * @return BigRational + * + * @throws NumberFormatException If an argument does not represent a valid number. + * @throws RoundingNecessaryException If an argument represents a non-integer number. + * @throws DivisionByZeroException If the denominator is zero. + * + * @psalm-pure + */ + public static function nd($numerator, $denominator) : BigRational + { + $numerator = BigInteger::of($numerator); + $denominator = BigInteger::of($denominator); + + return new BigRational($numerator, $denominator, true); + } + + /** + * Returns a BigRational representing zero. + * + * @return BigRational + * + * @psalm-pure + */ + public static function zero() : BigRational + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigRational|null $zero + */ + static $zero; + + if ($zero === null) { + $zero = new BigRational(BigInteger::zero(), BigInteger::one(), false); + } + + return $zero; + } + + /** + * Returns a BigRational representing one. + * + * @return BigRational + * + * @psalm-pure + */ + public static function one() : BigRational + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigRational|null $one + */ + static $one; + + if ($one === null) { + $one = new BigRational(BigInteger::one(), BigInteger::one(), false); + } + + return $one; + } + + /** + * Returns a BigRational representing ten. + * + * @return BigRational + * + * @psalm-pure + */ + public static function ten() : BigRational + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigRational|null $ten + */ + static $ten; + + if ($ten === null) { + $ten = new BigRational(BigInteger::ten(), BigInteger::one(), false); + } + + return $ten; + } + + /** + * @return BigInteger + */ + public function getNumerator() : BigInteger + { + return $this->numerator; + } + + /** + * @return BigInteger + */ + public function getDenominator() : BigInteger + { + return $this->denominator; + } + + /** + * Returns the quotient of the division of the numerator by the denominator. + * + * @return BigInteger + */ + public function quotient() : BigInteger + { + return $this->numerator->quotient($this->denominator); + } + + /** + * Returns the remainder of the division of the numerator by the denominator. + * + * @return BigInteger + */ + public function remainder() : BigInteger + { + return $this->numerator->remainder($this->denominator); + } + + /** + * Returns the quotient and remainder of the division of the numerator by the denominator. + * + * @return BigInteger[] + */ + public function quotientAndRemainder() : array + { + return $this->numerator->quotientAndRemainder($this->denominator); + } + + /** + * Returns the sum of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to add. + * + * @return BigRational The result. + * + * @throws MathException If the number is not valid. + */ + public function plus($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->denominator); + $numerator = $numerator->plus($that->numerator->multipliedBy($this->denominator)); + $denominator = $this->denominator->multipliedBy($that->denominator); + + return new BigRational($numerator, $denominator, false); + } + + /** + * Returns the difference of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to subtract. + * + * @return BigRational The result. + * + * @throws MathException If the number is not valid. + */ + public function minus($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->denominator); + $numerator = $numerator->minus($that->numerator->multipliedBy($this->denominator)); + $denominator = $this->denominator->multipliedBy($that->denominator); + + return new BigRational($numerator, $denominator, false); + } + + /** + * Returns the product of this number and the given one. + * + * @param BigNumber|int|float|string $that The multiplier. + * + * @return BigRational The result. + * + * @throws MathException If the multiplier is not a valid number. + */ + public function multipliedBy($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->numerator); + $denominator = $this->denominator->multipliedBy($that->denominator); + + return new BigRational($numerator, $denominator, false); + } + + /** + * Returns the result of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. + * + * @return BigRational The result. + * + * @throws MathException If the divisor is not a valid number, or is zero. + */ + public function dividedBy($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->denominator); + $denominator = $this->denominator->multipliedBy($that->numerator); + + return new BigRational($numerator, $denominator, true); + } + + /** + * Returns this number exponentiated to the given value. + * + * @param int $exponent The exponent. + * + * @return BigRational The result. + * + * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + */ + public function power(int $exponent) : BigRational + { + if ($exponent === 0) { + $one = BigInteger::one(); + + return new BigRational($one, $one, false); + } + + if ($exponent === 1) { + return $this; + } + + return new BigRational( + $this->numerator->power($exponent), + $this->denominator->power($exponent), + false + ); + } + + /** + * Returns the reciprocal of this BigRational. + * + * The reciprocal has the numerator and denominator swapped. + * + * @return BigRational + * + * @throws DivisionByZeroException If the numerator is zero. + */ + public function reciprocal() : BigRational + { + return new BigRational($this->denominator, $this->numerator, true); + } + + /** + * Returns the absolute value of this BigRational. + * + * @return BigRational + */ + public function abs() : BigRational + { + return new BigRational($this->numerator->abs(), $this->denominator, false); + } + + /** + * Returns the negated value of this BigRational. + * + * @return BigRational + */ + public function negated() : BigRational + { + return new BigRational($this->numerator->negated(), $this->denominator, false); + } + + /** + * Returns the simplified value of this BigRational. + * + * @return BigRational + */ + public function simplified() : BigRational + { + $gcd = $this->numerator->gcd($this->denominator); + + $numerator = $this->numerator->quotient($gcd); + $denominator = $this->denominator->quotient($gcd); + + return new BigRational($numerator, $denominator, false); + } + + /** + * {@inheritdoc} + */ + public function compareTo($that) : int + { + return $this->minus($that)->getSign(); + } + + /** + * {@inheritdoc} + */ + public function getSign() : int + { + return $this->numerator->getSign(); + } + + /** + * {@inheritdoc} + */ + public function toBigInteger() : BigInteger + { + $simplified = $this->simplified(); + + if (! $simplified->denominator->isEqualTo(1)) { + throw new RoundingNecessaryException('This rational number cannot be represented as an integer value without rounding.'); + } + + return $simplified->numerator; + } + + /** + * {@inheritdoc} + */ + public function toBigDecimal() : BigDecimal + { + return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator); + } + + /** + * {@inheritdoc} + */ + public function toBigRational() : BigRational + { + return $this; + } + + /** + * {@inheritdoc} + */ + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode); + } + + /** + * {@inheritdoc} + */ + public function toInt() : int + { + return $this->toBigInteger()->toInt(); + } + + /** + * {@inheritdoc} + */ + public function toFloat() : float + { + return $this->numerator->toFloat() / $this->denominator->toFloat(); + } + + /** + * {@inheritdoc} + */ + public function __toString() : string + { + $numerator = (string) $this->numerator; + $denominator = (string) $this->denominator; + + if ($denominator === '1') { + return $numerator; + } + + return $this->numerator . '/' . $this->denominator; + } + + /** + * This method is required for serializing the object and SHOULD NOT be accessed directly. + * + * @internal + * + * @return array{numerator: BigInteger, denominator: BigInteger} + */ + public function __serialize(): array + { + return ['numerator' => $this->numerator, 'denominator' => $this->denominator]; + } + + /** + * This method is only here to allow unserializing the object and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param array{numerator: BigInteger, denominator: BigInteger} $data + * + * @return void + * + * @throws \LogicException + */ + public function __unserialize(array $data): void + { + if (isset($this->numerator)) { + throw new \LogicException('__unserialize() is an internal function, it must not be called directly.'); + } + + $this->numerator = $data['numerator']; + $this->denominator = $data['denominator']; + } + + /** + * This method is required by interface Serializable and SHOULD NOT be accessed directly. + * + * @internal + * + * @return string + */ + public function serialize() : string + { + return $this->numerator . '/' . $this->denominator; + } + + /** + * This method is only here to implement interface Serializable and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param string $value + * + * @return void + * + * @throws \LogicException + */ + public function unserialize($value) : void + { + if (isset($this->numerator)) { + throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); + } + + [$numerator, $denominator] = \explode('/', $value); + + $this->numerator = BigInteger::of($numerator); + $this->denominator = BigInteger::of($denominator); + } +} diff --git a/vendor/brick/math/src/Exception/DivisionByZeroException.php b/vendor/brick/math/src/Exception/DivisionByZeroException.php new file mode 100755 index 0000000..a4e4431 --- /dev/null +++ b/vendor/brick/math/src/Exception/DivisionByZeroException.php @@ -0,0 +1,41 @@ + 126) { + $char = \strtoupper(\dechex($ord)); + + if ($ord < 10) { + $char = '0' . $char; + } + } else { + $char = '"' . $char . '"'; + } + + return new self(sprintf('Char %s is not a valid character in the given alphabet.', $char)); + } +} diff --git a/vendor/brick/math/src/Exception/RoundingNecessaryException.php b/vendor/brick/math/src/Exception/RoundingNecessaryException.php new file mode 100755 index 0000000..1c61005 --- /dev/null +++ b/vendor/brick/math/src/Exception/RoundingNecessaryException.php @@ -0,0 +1,21 @@ +init($a, $b); + + if ($aNeg && ! $bNeg) { + return -1; + } + + if ($bNeg && ! $aNeg) { + return 1; + } + + $aLen = \strlen($aDig); + $bLen = \strlen($bDig); + + if ($aLen < $bLen) { + $result = -1; + } elseif ($aLen > $bLen) { + $result = 1; + } else { + $result = $aDig <=> $bDig; + } + + return $aNeg ? -$result : $result; + } + + /** + * Adds two numbers. + * + * @param string $a The augend. + * @param string $b The addend. + * + * @return string The sum. + */ + abstract public function add(string $a, string $b) : string; + + /** + * Subtracts two numbers. + * + * @param string $a The minuend. + * @param string $b The subtrahend. + * + * @return string The difference. + */ + abstract public function sub(string $a, string $b) : string; + + /** + * Multiplies two numbers. + * + * @param string $a The multiplicand. + * @param string $b The multiplier. + * + * @return string The product. + */ + abstract public function mul(string $a, string $b) : string; + + /** + * Returns the quotient of the division of two numbers. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * + * @return string The quotient. + */ + abstract public function divQ(string $a, string $b) : string; + + /** + * Returns the remainder of the division of two numbers. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * + * @return string The remainder. + */ + abstract public function divR(string $a, string $b) : string; + + /** + * Returns the quotient and remainder of the division of two numbers. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * + * @return string[] An array containing the quotient and remainder. + */ + abstract public function divQR(string $a, string $b) : array; + + /** + * Exponentiates a number. + * + * @param string $a The base number. + * @param int $e The exponent, validated as an integer between 0 and MAX_POWER. + * + * @return string The power. + */ + abstract public function pow(string $a, int $e) : string; + + /** + * @param string $a + * @param string $b The modulus; must not be zero. + * + * @return string + */ + public function mod(string $a, string $b) : string + { + return $this->divR($this->add($this->divR($a, $b), $b), $b); + } + + /** + * Returns the modular multiplicative inverse of $x modulo $m. + * + * If $x has no multiplicative inverse mod m, this method must return null. + * + * This method can be overridden by the concrete implementation if the underlying library has built-in support. + * + * @param string $x + * @param string $m The modulus; must not be negative or zero. + * + * @return string|null + */ + public function modInverse(string $x, string $m) : ?string + { + if ($m === '1') { + return '0'; + } + + $modVal = $x; + + if ($x[0] === '-' || ($this->cmp($this->abs($x), $m) >= 0)) { + $modVal = $this->mod($x, $m); + } + + $x = '0'; + $y = '0'; + $g = $this->gcdExtended($modVal, $m, $x, $y); + + if ($g !== '1') { + return null; + } + + return $this->mod($this->add($this->mod($x, $m), $m), $m); + } + + /** + * Raises a number into power with modulo. + * + * @param string $base The base number; must be positive or zero. + * @param string $exp The exponent; must be positive or zero. + * @param string $mod The modulus; must be strictly positive. + * + * @return string The power. + */ + abstract public function modPow(string $base, string $exp, string $mod) : string; + + /** + * Returns the greatest common divisor of the two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for GCD calculations. + * + * @param string $a The first number. + * @param string $b The second number. + * + * @return string The GCD, always positive, or zero if both arguments are zero. + */ + public function gcd(string $a, string $b) : string + { + if ($a === '0') { + return $this->abs($b); + } + + if ($b === '0') { + return $this->abs($a); + } + + return $this->gcd($b, $this->divR($a, $b)); + } + + private function gcdExtended(string $a, string $b, string &$x, string &$y) : string + { + if ($a === '0') { + $x = '0'; + $y = '1'; + + return $b; + } + + $x1 = '0'; + $y1 = '0'; + + $gcd = $this->gcdExtended($this->mod($b, $a), $a, $x1, $y1); + + $x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1)); + $y = $x1; + + return $gcd; + } + + /** + * Returns the square root of the given number, rounded down. + * + * The result is the largest x such that x² ≤ n. + * The input MUST NOT be negative. + * + * @param string $n The number. + * + * @return string The square root. + */ + abstract public function sqrt(string $n) : string; + + /** + * Converts a number from an arbitrary base. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for base conversion. + * + * @param string $number The number, positive or zero, non-empty, case-insensitively validated for the given base. + * @param int $base The base of the number, validated from 2 to 36. + * + * @return string The converted number, following the Calculator conventions. + */ + public function fromBase(string $number, int $base) : string + { + return $this->fromArbitraryBase(\strtolower($number), self::ALPHABET, $base); + } + + /** + * Converts a number to an arbitrary base. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for base conversion. + * + * @param string $number The number to convert, following the Calculator conventions. + * @param int $base The base to convert to, validated from 2 to 36. + * + * @return string The converted number, lowercase. + */ + public function toBase(string $number, int $base) : string + { + $negative = ($number[0] === '-'); + + if ($negative) { + $number = \substr($number, 1); + } + + $number = $this->toArbitraryBase($number, self::ALPHABET, $base); + + if ($negative) { + return '-' . $number; + } + + return $number; + } + + /** + * Converts a non-negative number in an arbitrary base using a custom alphabet, to base 10. + * + * @param string $number The number to convert, validated as a non-empty string, + * containing only chars in the given alphabet/base. + * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum. + * @param int $base The base of the number, validated from 2 to alphabet length. + * + * @return string The number in base 10, following the Calculator conventions. + */ + final public function fromArbitraryBase(string $number, string $alphabet, int $base) : string + { + // remove leading "zeros" + $number = \ltrim($number, $alphabet[0]); + + if ($number === '') { + return '0'; + } + + // optimize for "one" + if ($number === $alphabet[1]) { + return '1'; + } + + $result = '0'; + $power = '1'; + + $base = (string) $base; + + for ($i = \strlen($number) - 1; $i >= 0; $i--) { + $index = \strpos($alphabet, $number[$i]); + + if ($index !== 0) { + $result = $this->add($result, ($index === 1) + ? $power + : $this->mul($power, (string) $index) + ); + } + + if ($i !== 0) { + $power = $this->mul($power, $base); + } + } + + return $result; + } + + /** + * Converts a non-negative number to an arbitrary base using a custom alphabet. + * + * @param string $number The number to convert, positive or zero, following the Calculator conventions. + * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum. + * @param int $base The base to convert to, validated from 2 to alphabet length. + * + * @return string The converted number in the given alphabet. + */ + final public function toArbitraryBase(string $number, string $alphabet, int $base) : string + { + if ($number === '0') { + return $alphabet[0]; + } + + $base = (string) $base; + $result = ''; + + while ($number !== '0') { + [$number, $remainder] = $this->divQR($number, $base); + $remainder = (int) $remainder; + + $result .= $alphabet[$remainder]; + } + + return \strrev($result); + } + + /** + * Performs a rounded division. + * + * Rounding is performed when the remainder of the division is not zero. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * @param int $roundingMode The rounding mode. + * + * @return string + * + * @throws \InvalidArgumentException If the rounding mode is invalid. + * @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary. + */ + final public function divRound(string $a, string $b, int $roundingMode) : string + { + [$quotient, $remainder] = $this->divQR($a, $b); + + $hasDiscardedFraction = ($remainder !== '0'); + $isPositiveOrZero = ($a[0] === '-') === ($b[0] === '-'); + + $discardedFractionSign = function() use ($remainder, $b) : int { + $r = $this->abs($this->mul($remainder, '2')); + $b = $this->abs($b); + + return $this->cmp($r, $b); + }; + + $increment = false; + + switch ($roundingMode) { + case RoundingMode::UNNECESSARY: + if ($hasDiscardedFraction) { + throw RoundingNecessaryException::roundingNecessary(); + } + break; + + case RoundingMode::UP: + $increment = $hasDiscardedFraction; + break; + + case RoundingMode::DOWN: + break; + + case RoundingMode::CEILING: + $increment = $hasDiscardedFraction && $isPositiveOrZero; + break; + + case RoundingMode::FLOOR: + $increment = $hasDiscardedFraction && ! $isPositiveOrZero; + break; + + case RoundingMode::HALF_UP: + $increment = $discardedFractionSign() >= 0; + break; + + case RoundingMode::HALF_DOWN: + $increment = $discardedFractionSign() > 0; + break; + + case RoundingMode::HALF_CEILING: + $increment = $isPositiveOrZero ? $discardedFractionSign() >= 0 : $discardedFractionSign() > 0; + break; + + case RoundingMode::HALF_FLOOR: + $increment = $isPositiveOrZero ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0; + break; + + case RoundingMode::HALF_EVEN: + $lastDigit = (int) $quotient[-1]; + $lastDigitIsEven = ($lastDigit % 2 === 0); + $increment = $lastDigitIsEven ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0; + break; + + default: + throw new \InvalidArgumentException('Invalid rounding mode.'); + } + + if ($increment) { + return $this->add($quotient, $isPositiveOrZero ? '1' : '-1'); + } + + return $quotient; + } + + /** + * Calculates bitwise AND of two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for bitwise operations. + * + * @param string $a + * @param string $b + * + * @return string + */ + public function and(string $a, string $b) : string + { + return $this->bitwise('and', $a, $b); + } + + /** + * Calculates bitwise OR of two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for bitwise operations. + * + * @param string $a + * @param string $b + * + * @return string + */ + public function or(string $a, string $b) : string + { + return $this->bitwise('or', $a, $b); + } + + /** + * Calculates bitwise XOR of two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for bitwise operations. + * + * @param string $a + * @param string $b + * + * @return string + */ + public function xor(string $a, string $b) : string + { + return $this->bitwise('xor', $a, $b); + } + + /** + * Performs a bitwise operation on a decimal number. + * + * @param string $operator The operator to use, must be "and", "or" or "xor". + * @param string $a The left operand. + * @param string $b The right operand. + * + * @return string + */ + private function bitwise(string $operator, string $a, string $b) : string + { + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + $aBin = $this->toBinary($aDig); + $bBin = $this->toBinary($bDig); + + $aLen = \strlen($aBin); + $bLen = \strlen($bBin); + + if ($aLen > $bLen) { + $bBin = \str_repeat("\x00", $aLen - $bLen) . $bBin; + } elseif ($bLen > $aLen) { + $aBin = \str_repeat("\x00", $bLen - $aLen) . $aBin; + } + + if ($aNeg) { + $aBin = $this->twosComplement($aBin); + } + if ($bNeg) { + $bBin = $this->twosComplement($bBin); + } + + switch ($operator) { + case 'and': + $value = $aBin & $bBin; + $negative = ($aNeg and $bNeg); + break; + + case 'or': + $value = $aBin | $bBin; + $negative = ($aNeg or $bNeg); + break; + + case 'xor': + $value = $aBin ^ $bBin; + $negative = ($aNeg xor $bNeg); + break; + + // @codeCoverageIgnoreStart + default: + throw new \InvalidArgumentException('Invalid bitwise operator.'); + // @codeCoverageIgnoreEnd + } + + if ($negative) { + $value = $this->twosComplement($value); + } + + $result = $this->toDecimal($value); + + return $negative ? $this->neg($result) : $result; + } + + /** + * @param string $number A positive, binary number. + * + * @return string + */ + private function twosComplement(string $number) : string + { + $xor = \str_repeat("\xff", \strlen($number)); + + $number ^= $xor; + + for ($i = \strlen($number) - 1; $i >= 0; $i--) { + $byte = \ord($number[$i]); + + if (++$byte !== 256) { + $number[$i] = \chr($byte); + break; + } + + $number[$i] = "\x00"; + + if ($i === 0) { + $number = "\x01" . $number; + } + } + + return $number; + } + + /** + * Converts a decimal number to a binary string. + * + * @param string $number The number to convert, positive or zero, only digits. + * + * @return string + */ + private function toBinary(string $number) : string + { + $result = ''; + + while ($number !== '0') { + [$number, $remainder] = $this->divQR($number, '256'); + $result .= \chr((int) $remainder); + } + + return \strrev($result); + } + + /** + * Returns the positive decimal representation of a binary number. + * + * @param string $bytes The bytes representing the number. + * + * @return string + */ + private function toDecimal(string $bytes) : string + { + $result = '0'; + $power = '1'; + + for ($i = \strlen($bytes) - 1; $i >= 0; $i--) { + $index = \ord($bytes[$i]); + + if ($index !== 0) { + $result = $this->add($result, ($index === 1) + ? $power + : $this->mul($power, (string) $index) + ); + } + + if ($i !== 0) { + $power = $this->mul($power, '256'); + } + } + + return $result; + } +} diff --git a/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php b/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php new file mode 100755 index 0000000..6632b37 --- /dev/null +++ b/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php @@ -0,0 +1,116 @@ += 0) { + return \bcmod($a, $b, 0); + } + + return \bcmod($a, $b); + } + + /** + * {@inheritdoc} + */ + public function divQR(string $a, string $b) : array + { + $q = \bcdiv($a, $b, 0); + + if (version_compare(PHP_VERSION, '7.2') >= 0) { + $r = \bcmod($a, $b, 0); + } else { + $r = \bcmod($a, $b); + } + + assert($q !== null); + assert($r !== null); + + return [$q, $r]; + } + + /** + * {@inheritdoc} + */ + public function pow(string $a, int $e) : string + { + return \bcpow($a, (string) $e, 0); + } + + /** + * {@inheritdoc} + * + * @psalm-suppress InvalidNullableReturnType + * @psalm-suppress NullableReturnStatement + */ + public function modPow(string $base, string $exp, string $mod) : string + { + return \bcpowmod($base, $exp, $mod, 0); + } + + /** + * {@inheritDoc} + * + * @psalm-suppress NullableReturnStatement + * @psalm-suppress InvalidNullableReturnType + */ + public function sqrt(string $n) : string + { + return \bcsqrt($n, 0); + } +} diff --git a/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php b/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php new file mode 100755 index 0000000..52d1880 --- /dev/null +++ b/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php @@ -0,0 +1,156 @@ +maxDigits = 9; + break; + + case 8: + $this->maxDigits = 18; + break; + + default: + throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.'); + } + } + + /** + * {@inheritdoc} + */ + public function add(string $a, string $b) : string + { + /** + * @psalm-var numeric-string $a + * @psalm-var numeric-string $b + */ + $result = $a + $b; + + if (is_int($result)) { + return (string) $result; + } + + if ($a === '0') { + return $b; + } + + if ($b === '0') { + return $a; + } + + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + $result = $aNeg === $bNeg ? $this->doAdd($aDig, $bDig) : $this->doSub($aDig, $bDig); + + if ($aNeg) { + $result = $this->neg($result); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function sub(string $a, string $b) : string + { + return $this->add($a, $this->neg($b)); + } + + /** + * {@inheritdoc} + */ + public function mul(string $a, string $b) : string + { + /** + * @psalm-var numeric-string $a + * @psalm-var numeric-string $b + */ + $result = $a * $b; + + if (is_int($result)) { + return (string) $result; + } + + if ($a === '0' || $b === '0') { + return '0'; + } + + if ($a === '1') { + return $b; + } + + if ($b === '1') { + return $a; + } + + if ($a === '-1') { + return $this->neg($b); + } + + if ($b === '-1') { + return $this->neg($a); + } + + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + $result = $this->doMul($aDig, $bDig); + + if ($aNeg !== $bNeg) { + $result = $this->neg($result); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function divQ(string $a, string $b) : string + { + return $this->divQR($a, $b)[0]; + } + + /** + * {@inheritdoc} + */ + public function divR(string $a, string $b): string + { + return $this->divQR($a, $b)[1]; + } + + /** + * {@inheritdoc} + */ + public function divQR(string $a, string $b) : array + { + if ($a === '0') { + return ['0', '0']; + } + + if ($a === $b) { + return ['1', '0']; + } + + if ($b === '1') { + return [$a, '0']; + } + + if ($b === '-1') { + return [$this->neg($a), '0']; + } + + /** @psalm-var numeric-string $a */ + $na = $a * 1; // cast to number + + if (is_int($na)) { + /** @psalm-var numeric-string $b */ + $nb = $b * 1; + + if (is_int($nb)) { + // the only division that may overflow is PHP_INT_MIN / -1, + // which cannot happen here as we've already handled a divisor of -1 above. + $r = $na % $nb; + $q = ($na - $r) / $nb; + + assert(is_int($q)); + + return [ + (string) $q, + (string) $r + ]; + } + } + + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + [$q, $r] = $this->doDiv($aDig, $bDig); + + if ($aNeg !== $bNeg) { + $q = $this->neg($q); + } + + if ($aNeg) { + $r = $this->neg($r); + } + + return [$q, $r]; + } + + /** + * {@inheritdoc} + */ + public function pow(string $a, int $e) : string + { + if ($e === 0) { + return '1'; + } + + if ($e === 1) { + return $a; + } + + $odd = $e % 2; + $e -= $odd; + + $aa = $this->mul($a, $a); + + /** @psalm-suppress PossiblyInvalidArgument We're sure that $e / 2 is an int now */ + $result = $this->pow($aa, $e / 2); + + if ($odd === 1) { + $result = $this->mul($result, $a); + } + + return $result; + } + + /** + * Algorithm from: https://www.geeksforgeeks.org/modular-exponentiation-power-in-modular-arithmetic/ + * + * {@inheritdoc} + */ + public function modPow(string $base, string $exp, string $mod) : string + { + // special case: the algorithm below fails with 0 power 0 mod 1 (returns 1 instead of 0) + if ($base === '0' && $exp === '0' && $mod === '1') { + return '0'; + } + + // special case: the algorithm below fails with power 0 mod 1 (returns 1 instead of 0) + if ($exp === '0' && $mod === '1') { + return '0'; + } + + $x = $base; + + $res = '1'; + + // numbers are positive, so we can use remainder instead of modulo + $x = $this->divR($x, $mod); + + while ($exp !== '0') { + if (in_array($exp[-1], ['1', '3', '5', '7', '9'])) { // odd + $res = $this->divR($this->mul($res, $x), $mod); + } + + $exp = $this->divQ($exp, '2'); + $x = $this->divR($this->mul($x, $x), $mod); + } + + return $res; + } + + /** + * Adapted from https://cp-algorithms.com/num_methods/roots_newton.html + * + * {@inheritDoc} + */ + public function sqrt(string $n) : string + { + if ($n === '0') { + return '0'; + } + + // initial approximation + $x = \str_repeat('9', \intdiv(\strlen($n), 2) ?: 1); + + $decreased = false; + + for (;;) { + $nx = $this->divQ($this->add($x, $this->divQ($n, $x)), '2'); + + if ($x === $nx || $this->cmp($nx, $x) > 0 && $decreased) { + break; + } + + $decreased = $this->cmp($nx, $x) < 0; + $x = $nx; + } + + return $x; + } + + /** + * Performs the addition of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string + */ + private function doAdd(string $a, string $b) : string + { + [$a, $b, $length] = $this->pad($a, $b); + + $carry = 0; + $result = ''; + + for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) { + $blockLength = $this->maxDigits; + + if ($i < 0) { + $blockLength += $i; + /** @psalm-suppress LoopInvalidation */ + $i = 0; + } + + /** @psalm-var numeric-string $blockA */ + $blockA = \substr($a, $i, $blockLength); + + /** @psalm-var numeric-string $blockB */ + $blockB = \substr($b, $i, $blockLength); + + $sum = (string) ($blockA + $blockB + $carry); + $sumLength = \strlen($sum); + + if ($sumLength > $blockLength) { + $sum = \substr($sum, 1); + $carry = 1; + } else { + if ($sumLength < $blockLength) { + $sum = \str_repeat('0', $blockLength - $sumLength) . $sum; + } + $carry = 0; + } + + $result = $sum . $result; + + if ($i === 0) { + break; + } + } + + if ($carry === 1) { + $result = '1' . $result; + } + + return $result; + } + + /** + * Performs the subtraction of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string + */ + private function doSub(string $a, string $b) : string + { + if ($a === $b) { + return '0'; + } + + // Ensure that we always subtract to a positive result: biggest minus smallest. + $cmp = $this->doCmp($a, $b); + + $invert = ($cmp === -1); + + if ($invert) { + $c = $a; + $a = $b; + $b = $c; + } + + [$a, $b, $length] = $this->pad($a, $b); + + $carry = 0; + $result = ''; + + $complement = 10 ** $this->maxDigits; + + for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) { + $blockLength = $this->maxDigits; + + if ($i < 0) { + $blockLength += $i; + /** @psalm-suppress LoopInvalidation */ + $i = 0; + } + + /** @psalm-var numeric-string $blockA */ + $blockA = \substr($a, $i, $blockLength); + + /** @psalm-var numeric-string $blockB */ + $blockB = \substr($b, $i, $blockLength); + + $sum = $blockA - $blockB - $carry; + + if ($sum < 0) { + $sum += $complement; + $carry = 1; + } else { + $carry = 0; + } + + $sum = (string) $sum; + $sumLength = \strlen($sum); + + if ($sumLength < $blockLength) { + $sum = \str_repeat('0', $blockLength - $sumLength) . $sum; + } + + $result = $sum . $result; + + if ($i === 0) { + break; + } + } + + // Carry cannot be 1 when the loop ends, as a > b + assert($carry === 0); + + $result = \ltrim($result, '0'); + + if ($invert) { + $result = $this->neg($result); + } + + return $result; + } + + /** + * Performs the multiplication of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string + */ + private function doMul(string $a, string $b) : string + { + $x = \strlen($a); + $y = \strlen($b); + + $maxDigits = \intdiv($this->maxDigits, 2); + $complement = 10 ** $maxDigits; + + $result = '0'; + + for ($i = $x - $maxDigits;; $i -= $maxDigits) { + $blockALength = $maxDigits; + + if ($i < 0) { + $blockALength += $i; + /** @psalm-suppress LoopInvalidation */ + $i = 0; + } + + $blockA = (int) \substr($a, $i, $blockALength); + + $line = ''; + $carry = 0; + + for ($j = $y - $maxDigits;; $j -= $maxDigits) { + $blockBLength = $maxDigits; + + if ($j < 0) { + $blockBLength += $j; + /** @psalm-suppress LoopInvalidation */ + $j = 0; + } + + $blockB = (int) \substr($b, $j, $blockBLength); + + $mul = $blockA * $blockB + $carry; + $value = $mul % $complement; + $carry = ($mul - $value) / $complement; + + $value = (string) $value; + $value = \str_pad($value, $maxDigits, '0', STR_PAD_LEFT); + + $line = $value . $line; + + if ($j === 0) { + break; + } + } + + if ($carry !== 0) { + $line = $carry . $line; + } + + $line = \ltrim($line, '0'); + + if ($line !== '') { + $line .= \str_repeat('0', $x - $blockALength - $i); + $result = $this->add($result, $line); + } + + if ($i === 0) { + break; + } + } + + return $result; + } + + /** + * Performs the division of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string[] The quotient and remainder. + */ + private function doDiv(string $a, string $b) : array + { + $cmp = $this->doCmp($a, $b); + + if ($cmp === -1) { + return ['0', $a]; + } + + $x = \strlen($a); + $y = \strlen($b); + + // we now know that a >= b && x >= y + + $q = '0'; // quotient + $r = $a; // remainder + $z = $y; // focus length, always $y or $y+1 + + for (;;) { + $focus = \substr($a, 0, $z); + + $cmp = $this->doCmp($focus, $b); + + if ($cmp === -1) { + if ($z === $x) { // remainder < dividend + break; + } + + $z++; + } + + $zeros = \str_repeat('0', $x - $z); + + $q = $this->add($q, '1' . $zeros); + $a = $this->sub($a, $b . $zeros); + + $r = $a; + + if ($r === '0') { // remainder == 0 + break; + } + + $x = \strlen($a); + + if ($x < $y) { // remainder < dividend + break; + } + + $z = $y; + } + + return [$q, $r]; + } + + /** + * Compares two non-signed large numbers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return int [-1, 0, 1] + */ + private function doCmp(string $a, string $b) : int + { + $x = \strlen($a); + $y = \strlen($b); + + $cmp = $x <=> $y; + + if ($cmp !== 0) { + return $cmp; + } + + return \strcmp($a, $b) <=> 0; // enforce [-1, 0, 1] + } + + /** + * Pads the left of one of the given numbers with zeros if necessary to make both numbers the same length. + * + * The numbers must only consist of digits, without leading minus sign. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return array{string, string, int} + */ + private function pad(string $a, string $b) : array + { + $x = \strlen($a); + $y = \strlen($b); + + if ($x > $y) { + $b = \str_repeat('0', $x - $y) . $b; + + return [$a, $b, $x]; + } + + if ($x < $y) { + $a = \str_repeat('0', $y - $x) . $a; + + return [$a, $b, $y]; + } + + return [$a, $b, $x]; + } +} diff --git a/vendor/brick/math/src/RoundingMode.php b/vendor/brick/math/src/RoundingMode.php new file mode 100755 index 0000000..06936d8 --- /dev/null +++ b/vendor/brick/math/src/RoundingMode.php @@ -0,0 +1,107 @@ += 0.5; otherwise, behaves as for DOWN. + * Note that this is the rounding mode commonly taught at school. + */ + public const HALF_UP = 5; + + /** + * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down. + * + * Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves as for DOWN. + */ + public const HALF_DOWN = 6; + + /** + * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards positive infinity. + * + * If the result is positive, behaves as for HALF_UP; if negative, behaves as for HALF_DOWN. + */ + public const HALF_CEILING = 7; + + /** + * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards negative infinity. + * + * If the result is positive, behaves as for HALF_DOWN; if negative, behaves as for HALF_UP. + */ + public const HALF_FLOOR = 8; + + /** + * Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor. + * + * Behaves as for HALF_UP if the digit to the left of the discarded fraction is odd; + * behaves as for HALF_DOWN if it's even. + * + * Note that this is the rounding mode that statistically minimizes + * cumulative error when applied repeatedly over a sequence of calculations. + * It is sometimes known as "Banker's rounding", and is chiefly used in the USA. + */ + public const HALF_EVEN = 9; +} diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php new file mode 100755 index 0000000..afef3fa --- /dev/null +++ b/vendor/composer/ClassLoader.php @@ -0,0 +1,572 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var ?string */ + private $vendorDir; + + // PSR-4 + /** + * @var array[] + * @psalm-var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array[] + * @psalm-var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var array[] + * @psalm-var array + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * @var array[] + * @psalm-var array> + */ + private $prefixesPsr0 = array(); + /** + * @var array[] + * @psalm-var array + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var string[] + * @psalm-var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var bool[] + * @psalm-var array + */ + private $missingClasses = array(); + + /** @var ?string */ + private $apcuPrefix; + + /** + * @var self[] + */ + private static $registeredLoaders = array(); + + /** + * @param ?string $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + /** + * @return string[] + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array[] + * @psalm-return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return array[] + * @psalm-return array + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return array[] + * @psalm-return array + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return string[] Array of classname => path + * @psalm-return array + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + * @private + */ +function includeFile($file) +{ + include $file; +} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100755 index 0000000..c6b54af --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,352 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints($constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = require __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + $installed[] = self::$installed; + + return $installed; + } +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100755 index 0000000..f27399a --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100755 index 0000000..7279989 --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,73 @@ + $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', + 'Nette\\ArgumentOutOfRangeException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\DeprecatedException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\DirectoryNotFoundException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\FileNotFoundException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\HtmlStringable' => $vendorDir . '/nette/utils/src/HtmlStringable.php', + 'Nette\\IOException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\InvalidArgumentException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\InvalidStateException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\Iterators\\CachingIterator' => $vendorDir . '/nette/utils/src/Iterators/CachingIterator.php', + 'Nette\\Iterators\\Mapper' => $vendorDir . '/nette/utils/src/Iterators/Mapper.php', + 'Nette\\Localization\\ITranslator' => $vendorDir . '/nette/utils/src/compatibility.php', + 'Nette\\Localization\\Translator' => $vendorDir . '/nette/utils/src/Translator.php', + 'Nette\\MemberAccessException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\NotImplementedException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\NotSupportedException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\OutOfRangeException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\Schema\\Context' => $vendorDir . '/nette/schema/src/Schema/Context.php', + 'Nette\\Schema\\DynamicParameter' => $vendorDir . '/nette/schema/src/Schema/DynamicParameter.php', + 'Nette\\Schema\\Elements\\AnyOf' => $vendorDir . '/nette/schema/src/Schema/Elements/AnyOf.php', + 'Nette\\Schema\\Elements\\Base' => $vendorDir . '/nette/schema/src/Schema/Elements/Base.php', + 'Nette\\Schema\\Elements\\Structure' => $vendorDir . '/nette/schema/src/Schema/Elements/Structure.php', + 'Nette\\Schema\\Elements\\Type' => $vendorDir . '/nette/schema/src/Schema/Elements/Type.php', + 'Nette\\Schema\\Expect' => $vendorDir . '/nette/schema/src/Schema/Expect.php', + 'Nette\\Schema\\Helpers' => $vendorDir . '/nette/schema/src/Schema/Helpers.php', + 'Nette\\Schema\\Message' => $vendorDir . '/nette/schema/src/Schema/Message.php', + 'Nette\\Schema\\Processor' => $vendorDir . '/nette/schema/src/Schema/Processor.php', + 'Nette\\Schema\\Schema' => $vendorDir . '/nette/schema/src/Schema/Schema.php', + 'Nette\\Schema\\ValidationException' => $vendorDir . '/nette/schema/src/Schema/ValidationException.php', + 'Nette\\SmartObject' => $vendorDir . '/nette/utils/src/SmartObject.php', + 'Nette\\StaticClass' => $vendorDir . '/nette/utils/src/StaticClass.php', + 'Nette\\UnexpectedValueException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\Utils\\ArrayHash' => $vendorDir . '/nette/utils/src/Utils/ArrayHash.php', + 'Nette\\Utils\\ArrayList' => $vendorDir . '/nette/utils/src/Utils/ArrayList.php', + 'Nette\\Utils\\Arrays' => $vendorDir . '/nette/utils/src/Utils/Arrays.php', + 'Nette\\Utils\\AssertionException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Callback' => $vendorDir . '/nette/utils/src/Utils/Callback.php', + 'Nette\\Utils\\DateTime' => $vendorDir . '/nette/utils/src/Utils/DateTime.php', + 'Nette\\Utils\\FileSystem' => $vendorDir . '/nette/utils/src/Utils/FileSystem.php', + 'Nette\\Utils\\Floats' => $vendorDir . '/nette/utils/src/Utils/Floats.php', + 'Nette\\Utils\\Helpers' => $vendorDir . '/nette/utils/src/Utils/Helpers.php', + 'Nette\\Utils\\Html' => $vendorDir . '/nette/utils/src/Utils/Html.php', + 'Nette\\Utils\\IHtmlString' => $vendorDir . '/nette/utils/src/compatibility.php', + 'Nette\\Utils\\Image' => $vendorDir . '/nette/utils/src/Utils/Image.php', + 'Nette\\Utils\\ImageException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Json' => $vendorDir . '/nette/utils/src/Utils/Json.php', + 'Nette\\Utils\\JsonException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\ObjectHelpers' => $vendorDir . '/nette/utils/src/Utils/ObjectHelpers.php', + 'Nette\\Utils\\ObjectMixin' => $vendorDir . '/nette/utils/src/Utils/ObjectMixin.php', + 'Nette\\Utils\\Paginator' => $vendorDir . '/nette/utils/src/Utils/Paginator.php', + 'Nette\\Utils\\Random' => $vendorDir . '/nette/utils/src/Utils/Random.php', + 'Nette\\Utils\\Reflection' => $vendorDir . '/nette/utils/src/Utils/Reflection.php', + 'Nette\\Utils\\RegexpException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Strings' => $vendorDir . '/nette/utils/src/Utils/Strings.php', + 'Nette\\Utils\\Type' => $vendorDir . '/nette/utils/src/Utils/Type.php', + 'Nette\\Utils\\UnknownImageFileException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Validators' => $vendorDir . '/nette/utils/src/Utils/Validators.php', + 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'ReturnTypeWillChange' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php', + 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', +); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php new file mode 100755 index 0000000..5ecc578 --- /dev/null +++ b/vendor/composer/autoload_files.php @@ -0,0 +1,39 @@ + $vendorDir . '/hoa/consistency/Prelude.php', + 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', + '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', + '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', + 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', + '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', + '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php', + '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php', + '23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php', + 'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php', + 'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php', + '9cdd7b9056abc3081735233ba9dd9c7f' => $vendorDir . '/facade/flare-client-php/src/helpers.php', + 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', + '538ca81a9a966a6716601ecf48f4eaef' => $vendorDir . '/opis/closure/functions.php', + 'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php', + 'e39a8b23c42d4e1452234d762b03835a' => $vendorDir . '/ramsey/uuid/src/functions.php', + 'f9b6863383dcc91013f6afb5fc590b03' => $vendorDir . '/sanmai/hoa-protocol/Source/Wrapper.php', + '2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php', + 'ed962a97bd972bc82007176b647d4e36' => $vendorDir . '/facade/ignition/src/helpers.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', + '265b4faa2b3a9766332744949e83bf97' => $vendorDir . '/laravel/framework/src/Illuminate/Collections/helpers.php', + 'c7a3c339e7e14b60e06a2d7fcce9476b' => $vendorDir . '/laravel/framework/src/Illuminate/Events/functions.php', + 'f0906e6318348a765ffb6eb24e0d0938' => $vendorDir . '/laravel/framework/src/Illuminate/Foundation/helpers.php', + '58571171fd5812e6e447dce228f52f4d' => $vendorDir . '/laravel/framework/src/Illuminate/Support/helpers.php', + '8c29ea8d67d27b0e3d03dbb3e7e3ed7a' => $baseDir . '/app/helpers.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100755 index 0000000..2a91a87 --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,10 @@ + array($vendorDir . '/twig/twig/lib'), +); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php new file mode 100755 index 0000000..31cfc6f --- /dev/null +++ b/vendor/composer/autoload_psr4.php @@ -0,0 +1,121 @@ + array($vendorDir . '/voku/portable-ascii/src/voku'), + 'phpseclib3\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'), + 'Whoops\\' => array($vendorDir . '/filp/whoops/src/Whoops'), + 'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'), + 'Vectorface\\Whip\\' => array($vendorDir . '/vectorface/whip/src'), + 'Vectorface\\WhipTests\\' => array($vendorDir . '/vectorface/whip/tests'), + 'VectorFace\\Whip\\' => array($vendorDir . '/vectorface/whip/src'), + 'Twig\\' => array($vendorDir . '/twig/twig/src'), + 'TwigBridge\\Tests\\' => array($vendorDir . '/rcrowe/twigbridge/tests'), + 'TwigBridge\\' => array($vendorDir . '/rcrowe/twigbridge/src'), + 'TijsVerkoyen\\CssToInlineStyles\\' => array($vendorDir . '/tijsverkoyen/css-to-inline-styles/src'), + 'Symfony\\Polyfill\\Php81\\' => array($vendorDir . '/symfony/polyfill-php81'), + 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), + 'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'), + 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'), + 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), + 'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'), + 'Symfony\\Polyfill\\Intl\\Grapheme\\' => array($vendorDir . '/symfony/polyfill-intl-grapheme'), + 'Symfony\\Polyfill\\Iconv\\' => array($vendorDir . '/symfony/polyfill-iconv'), + 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), + 'Symfony\\Contracts\\Translation\\' => array($vendorDir . '/symfony/translation-contracts'), + 'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'), + 'Symfony\\Contracts\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher-contracts'), + 'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'), + 'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'), + 'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'), + 'Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'), + 'Symfony\\Component\\Routing\\' => array($vendorDir . '/symfony/routing'), + 'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'), + 'Symfony\\Component\\Mime\\' => array($vendorDir . '/symfony/mime'), + 'Symfony\\Component\\HttpKernel\\' => array($vendorDir . '/symfony/http-kernel'), + 'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'), + 'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'), + 'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'), + 'Symfony\\Component\\ErrorHandler\\' => array($vendorDir . '/symfony/error-handler'), + 'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'), + 'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'), + 'Symfony\\Bridge\\PsrHttpMessage\\' => array($vendorDir . '/symfony/psr-http-message-bridge'), + 'Spatie\\TranslationLoader\\' => array($vendorDir . '/spatie/laravel-translation-loader/src'), + 'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'), + 'Ramsey\\Collection\\' => array($vendorDir . '/ramsey/collection/src'), + 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/src'), + 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'), + 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), + 'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'), + 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), + 'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src/PhpOption'), + 'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'), + 'Opis\\Closure\\' => array($vendorDir . '/opis/closure/src'), + 'Nyholm\\Psr7\\' => array($vendorDir . '/nyholm/psr7/src'), + 'NunoMaduro\\Collision\\' => array($vendorDir . '/nunomaduro/collision/src'), + 'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'), + 'Lorisleiva\\LaravelSearchString\\' => array($vendorDir . '/lorisleiva/laravel-search-string/src'), + 'League\\OAuth2\\Server\\' => array($vendorDir . '/league/oauth2-server/src'), + 'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'), + 'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'), + 'League\\Event\\' => array($vendorDir . '/league/event/src'), + 'League\\Config\\' => array($vendorDir . '/league/config/src'), + 'League\\CommonMark\\' => array($vendorDir . '/league/commonmark/src'), + 'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'), + 'Lcobucci\\Clock\\' => array($vendorDir . '/lcobucci/clock/src'), + 'Laravel\\SerializableClosure\\' => array($vendorDir . '/laravel/serializable-closure/src'), + 'Laravel\\Passport\\Database\\Factories\\' => array($vendorDir . '/laravel/passport/database/factories'), + 'Laravel\\Passport\\' => array($vendorDir . '/laravel/passport/src'), + 'Intervention\\Image\\' => array($vendorDir . '/intervention/image/src/Intervention/Image'), + 'Illuminate\\Support\\' => array($vendorDir . '/laravel/framework/src/Illuminate/Macroable', $vendorDir . '/laravel/framework/src/Illuminate/Collections'), + 'Illuminate\\' => array($vendorDir . '/laravel/framework/src/Illuminate'), + 'Http\\Message\\' => array($vendorDir . '/php-http/message-factory/src'), + 'Hoa\\Zformat\\' => array($vendorDir . '/hoa/zformat'), + 'Hoa\\Visitor\\' => array($vendorDir . '/hoa/visitor'), + 'Hoa\\Ustring\\' => array($vendorDir . '/hoa/ustring'), + 'Hoa\\Stream\\' => array($vendorDir . '/hoa/stream'), + 'Hoa\\Regex\\' => array($vendorDir . '/hoa/regex'), + 'Hoa\\Protocol\\Bin\\' => array($vendorDir . '/sanmai/hoa-protocol/Bin'), + 'Hoa\\Protocol\\' => array($vendorDir . '/sanmai/hoa-protocol/Source'), + 'Hoa\\Math\\' => array($vendorDir . '/hoa/math'), + 'Hoa\\Iterator\\' => array($vendorDir . '/hoa/iterator'), + 'Hoa\\File\\' => array($vendorDir . '/hoa/file'), + 'Hoa\\Exception\\' => array($vendorDir . '/hoa/exception'), + 'Hoa\\Event\\' => array($vendorDir . '/hoa/event'), + 'Hoa\\Consistency\\' => array($vendorDir . '/hoa/consistency'), + 'Hoa\\Compiler\\' => array($vendorDir . '/hoa/compiler'), + 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), + 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), + 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), + 'Gregwar\\' => array($vendorDir . '/gregwar/captcha/src/Gregwar'), + 'GrahamCampbell\\ResultType\\' => array($vendorDir . '/graham-campbell/result-type/src'), + 'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'), + 'Facade\\Ignition\\' => array($vendorDir . '/facade/ignition/src'), + 'Facade\\IgnitionContracts\\' => array($vendorDir . '/facade/ignition-contracts/src'), + 'Facade\\FlareClient\\' => array($vendorDir . '/facade/flare-client-php/src'), + 'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/src'), + 'Dotenv\\' => array($vendorDir . '/vlucas/phpdotenv/src'), + 'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector'), + 'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations'), + 'Doctrine\\DBAL\\' => array($vendorDir . '/doctrine/dbal/lib/Doctrine/DBAL'), + 'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib/Doctrine/Common/Lexer'), + 'Doctrine\\Common\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Common/Inflector'), + 'Doctrine\\Common\\Cache\\' => array($vendorDir . '/doctrine/cache/lib/Doctrine/Common/Cache'), + 'Doctrine\\Common\\' => array($vendorDir . '/doctrine/event-manager/lib/Doctrine/Common'), + 'Dflydev\\DotAccessData\\' => array($vendorDir . '/dflydev/dot-access-data/src'), + 'Defuse\\Crypto\\' => array($vendorDir . '/defuse/php-encryption/src'), + 'Database\\Factories\\' => array($baseDir . '/database/factories'), + 'Cron\\' => array($vendorDir . '/dragonmantank/cron-expression/src/Cron'), + 'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'), + 'Composer\\CaBundle\\' => array($vendorDir . '/composer/ca-bundle/src'), + 'Carbon\\' => array($vendorDir . '/nesbot/carbon/src/Carbon'), + 'Brick\\Math\\' => array($vendorDir . '/brick/math/src'), + 'Blessing\\' => array($vendorDir . '/blessing/filter/src/Blessing', $vendorDir . '/blessing/rejection/src/Blessing', $vendorDir . '/blessing/texture-renderer/src/Blessing'), + 'App\\' => array($baseDir . '/app'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100755 index 0000000..b0c95e2 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,57 @@ +register(true); + + $includeFiles = \Composer\Autoload\ComposerStaticInit0a9d7af445e16b3da8206b47ab1f0594::$files; + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequire0a9d7af445e16b3da8206b47ab1f0594($fileIdentifier, $file); + } + + return $loader; + } +} + +/** + * @param string $fileIdentifier + * @param string $file + * @return void + */ +function composerRequire0a9d7af445e16b3da8206b47ab1f0594($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100755 index 0000000..5e63ecf --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,762 @@ + __DIR__ . '/..' . '/hoa/consistency/Prelude.php', + 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', + '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', + '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', + 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', + '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php', + '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php', + '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php', + '23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php', + 'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php', + 'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php', + '9cdd7b9056abc3081735233ba9dd9c7f' => __DIR__ . '/..' . '/facade/flare-client-php/src/helpers.php', + 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', + '538ca81a9a966a6716601ecf48f4eaef' => __DIR__ . '/..' . '/opis/closure/functions.php', + 'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php', + 'e39a8b23c42d4e1452234d762b03835a' => __DIR__ . '/..' . '/ramsey/uuid/src/functions.php', + 'f9b6863383dcc91013f6afb5fc590b03' => __DIR__ . '/..' . '/sanmai/hoa-protocol/Source/Wrapper.php', + '2c102faa651ef8ea5874edb585946bce' => __DIR__ . '/..' . '/swiftmailer/swiftmailer/lib/swift_required.php', + 'ed962a97bd972bc82007176b647d4e36' => __DIR__ . '/..' . '/facade/ignition/src/helpers.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', + '265b4faa2b3a9766332744949e83bf97' => __DIR__ . '/..' . '/laravel/framework/src/Illuminate/Collections/helpers.php', + 'c7a3c339e7e14b60e06a2d7fcce9476b' => __DIR__ . '/..' . '/laravel/framework/src/Illuminate/Events/functions.php', + 'f0906e6318348a765ffb6eb24e0d0938' => __DIR__ . '/..' . '/laravel/framework/src/Illuminate/Foundation/helpers.php', + '58571171fd5812e6e447dce228f52f4d' => __DIR__ . '/..' . '/laravel/framework/src/Illuminate/Support/helpers.php', + '8c29ea8d67d27b0e3d03dbb3e7e3ed7a' => __DIR__ . '/../..' . '/app/helpers.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'v' => + array ( + 'voku\\' => 5, + ), + 'p' => + array ( + 'phpseclib3\\' => 11, + ), + 'W' => + array ( + 'Whoops\\' => 7, + 'Webmozart\\Assert\\' => 17, + ), + 'V' => + array ( + 'Vectorface\\Whip\\' => 16, + 'Vectorface\\WhipTests\\' => 21, + 'VectorFace\\Whip\\' => 16, + ), + 'T' => + array ( + 'Twig\\' => 5, + 'TwigBridge\\Tests\\' => 17, + 'TwigBridge\\' => 11, + 'TijsVerkoyen\\CssToInlineStyles\\' => 31, + ), + 'S' => + array ( + 'Symfony\\Polyfill\\Php81\\' => 23, + 'Symfony\\Polyfill\\Php80\\' => 23, + 'Symfony\\Polyfill\\Php73\\' => 23, + 'Symfony\\Polyfill\\Php72\\' => 23, + 'Symfony\\Polyfill\\Mbstring\\' => 26, + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33, + 'Symfony\\Polyfill\\Intl\\Idn\\' => 26, + 'Symfony\\Polyfill\\Intl\\Grapheme\\' => 31, + 'Symfony\\Polyfill\\Iconv\\' => 23, + 'Symfony\\Polyfill\\Ctype\\' => 23, + 'Symfony\\Contracts\\Translation\\' => 30, + 'Symfony\\Contracts\\Service\\' => 26, + 'Symfony\\Contracts\\EventDispatcher\\' => 34, + 'Symfony\\Component\\Yaml\\' => 23, + 'Symfony\\Component\\VarDumper\\' => 28, + 'Symfony\\Component\\Translation\\' => 30, + 'Symfony\\Component\\String\\' => 25, + 'Symfony\\Component\\Routing\\' => 26, + 'Symfony\\Component\\Process\\' => 26, + 'Symfony\\Component\\Mime\\' => 23, + 'Symfony\\Component\\HttpKernel\\' => 29, + 'Symfony\\Component\\HttpFoundation\\' => 33, + 'Symfony\\Component\\Finder\\' => 25, + 'Symfony\\Component\\EventDispatcher\\' => 34, + 'Symfony\\Component\\ErrorHandler\\' => 31, + 'Symfony\\Component\\CssSelector\\' => 30, + 'Symfony\\Component\\Console\\' => 26, + 'Symfony\\Bridge\\PsrHttpMessage\\' => 30, + 'Spatie\\TranslationLoader\\' => 25, + ), + 'R' => + array ( + 'Ramsey\\Uuid\\' => 12, + 'Ramsey\\Collection\\' => 18, + ), + 'P' => + array ( + 'Psr\\SimpleCache\\' => 16, + 'Psr\\Log\\' => 8, + 'Psr\\Http\\Message\\' => 17, + 'Psr\\Http\\Client\\' => 16, + 'Psr\\EventDispatcher\\' => 20, + 'Psr\\Container\\' => 14, + 'PhpOption\\' => 10, + 'ParagonIE\\ConstantTime\\' => 23, + ), + 'O' => + array ( + 'Opis\\Closure\\' => 13, + ), + 'N' => + array ( + 'Nyholm\\Psr7\\' => 12, + 'NunoMaduro\\Collision\\' => 21, + ), + 'M' => + array ( + 'Monolog\\' => 8, + ), + 'L' => + array ( + 'Lorisleiva\\LaravelSearchString\\' => 31, + 'League\\OAuth2\\Server\\' => 21, + 'League\\MimeTypeDetection\\' => 25, + 'League\\Flysystem\\' => 17, + 'League\\Event\\' => 13, + 'League\\Config\\' => 14, + 'League\\CommonMark\\' => 18, + 'Lcobucci\\JWT\\' => 13, + 'Lcobucci\\Clock\\' => 15, + 'Laravel\\SerializableClosure\\' => 28, + 'Laravel\\Passport\\Database\\Factories\\' => 36, + 'Laravel\\Passport\\' => 17, + ), + 'I' => + array ( + 'Intervention\\Image\\' => 19, + 'Illuminate\\Support\\' => 19, + 'Illuminate\\' => 11, + ), + 'H' => + array ( + 'Http\\Message\\' => 13, + 'Hoa\\Zformat\\' => 12, + 'Hoa\\Visitor\\' => 12, + 'Hoa\\Ustring\\' => 12, + 'Hoa\\Stream\\' => 11, + 'Hoa\\Regex\\' => 10, + 'Hoa\\Protocol\\Bin\\' => 17, + 'Hoa\\Protocol\\' => 13, + 'Hoa\\Math\\' => 9, + 'Hoa\\Iterator\\' => 13, + 'Hoa\\File\\' => 9, + 'Hoa\\Exception\\' => 14, + 'Hoa\\Event\\' => 10, + 'Hoa\\Consistency\\' => 16, + 'Hoa\\Compiler\\' => 13, + ), + 'G' => + array ( + 'GuzzleHttp\\Psr7\\' => 16, + 'GuzzleHttp\\Promise\\' => 19, + 'GuzzleHttp\\' => 11, + 'Gregwar\\' => 8, + 'GrahamCampbell\\ResultType\\' => 26, + ), + 'F' => + array ( + 'Firebase\\JWT\\' => 13, + 'Facade\\Ignition\\' => 16, + 'Facade\\IgnitionContracts\\' => 25, + 'Facade\\FlareClient\\' => 19, + ), + 'E' => + array ( + 'Egulias\\EmailValidator\\' => 23, + ), + 'D' => + array ( + 'Dotenv\\' => 7, + 'Doctrine\\Inflector\\' => 19, + 'Doctrine\\Deprecations\\' => 22, + 'Doctrine\\DBAL\\' => 14, + 'Doctrine\\Common\\Lexer\\' => 22, + 'Doctrine\\Common\\Inflector\\' => 26, + 'Doctrine\\Common\\Cache\\' => 22, + 'Doctrine\\Common\\' => 16, + 'Dflydev\\DotAccessData\\' => 22, + 'Defuse\\Crypto\\' => 14, + 'Database\\Factories\\' => 19, + ), + 'C' => + array ( + 'Cron\\' => 5, + 'Composer\\Semver\\' => 16, + 'Composer\\CaBundle\\' => 18, + 'Carbon\\' => 7, + ), + 'B' => + array ( + 'Brick\\Math\\' => 11, + 'Blessing\\' => 9, + ), + 'A' => + array ( + 'App\\' => 4, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'voku\\' => + array ( + 0 => __DIR__ . '/..' . '/voku/portable-ascii/src/voku', + ), + 'phpseclib3\\' => + array ( + 0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib', + ), + 'Whoops\\' => + array ( + 0 => __DIR__ . '/..' . '/filp/whoops/src/Whoops', + ), + 'Webmozart\\Assert\\' => + array ( + 0 => __DIR__ . '/..' . '/webmozart/assert/src', + ), + 'Vectorface\\Whip\\' => + array ( + 0 => __DIR__ . '/..' . '/vectorface/whip/src', + ), + 'Vectorface\\WhipTests\\' => + array ( + 0 => __DIR__ . '/..' . '/vectorface/whip/tests', + ), + 'VectorFace\\Whip\\' => + array ( + 0 => __DIR__ . '/..' . '/vectorface/whip/src', + ), + 'Twig\\' => + array ( + 0 => __DIR__ . '/..' . '/twig/twig/src', + ), + 'TwigBridge\\Tests\\' => + array ( + 0 => __DIR__ . '/..' . '/rcrowe/twigbridge/tests', + ), + 'TwigBridge\\' => + array ( + 0 => __DIR__ . '/..' . '/rcrowe/twigbridge/src', + ), + 'TijsVerkoyen\\CssToInlineStyles\\' => + array ( + 0 => __DIR__ . '/..' . '/tijsverkoyen/css-to-inline-styles/src', + ), + 'Symfony\\Polyfill\\Php81\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php81', + ), + 'Symfony\\Polyfill\\Php80\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', + ), + 'Symfony\\Polyfill\\Php73\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php73', + ), + 'Symfony\\Polyfill\\Php72\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php72', + ), + 'Symfony\\Polyfill\\Mbstring\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', + ), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer', + ), + 'Symfony\\Polyfill\\Intl\\Idn\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn', + ), + 'Symfony\\Polyfill\\Intl\\Grapheme\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme', + ), + 'Symfony\\Polyfill\\Iconv\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-iconv', + ), + 'Symfony\\Polyfill\\Ctype\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', + ), + 'Symfony\\Contracts\\Translation\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/translation-contracts', + ), + 'Symfony\\Contracts\\Service\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/service-contracts', + ), + 'Symfony\\Contracts\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts', + ), + 'Symfony\\Component\\Yaml\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/yaml', + ), + 'Symfony\\Component\\VarDumper\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/var-dumper', + ), + 'Symfony\\Component\\Translation\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/translation', + ), + 'Symfony\\Component\\String\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/string', + ), + 'Symfony\\Component\\Routing\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/routing', + ), + 'Symfony\\Component\\Process\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/process', + ), + 'Symfony\\Component\\Mime\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/mime', + ), + 'Symfony\\Component\\HttpKernel\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/http-kernel', + ), + 'Symfony\\Component\\HttpFoundation\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/http-foundation', + ), + 'Symfony\\Component\\Finder\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/finder', + ), + 'Symfony\\Component\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/event-dispatcher', + ), + 'Symfony\\Component\\ErrorHandler\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/error-handler', + ), + 'Symfony\\Component\\CssSelector\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/css-selector', + ), + 'Symfony\\Component\\Console\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/console', + ), + 'Symfony\\Bridge\\PsrHttpMessage\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/psr-http-message-bridge', + ), + 'Spatie\\TranslationLoader\\' => + array ( + 0 => __DIR__ . '/..' . '/spatie/laravel-translation-loader/src', + ), + 'Ramsey\\Uuid\\' => + array ( + 0 => __DIR__ . '/..' . '/ramsey/uuid/src', + ), + 'Ramsey\\Collection\\' => + array ( + 0 => __DIR__ . '/..' . '/ramsey/collection/src', + ), + 'Psr\\SimpleCache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/simple-cache/src', + ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/src', + ), + 'Psr\\Http\\Message\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-message/src', + 1 => __DIR__ . '/..' . '/psr/http-factory/src', + ), + 'Psr\\Http\\Client\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-client/src', + ), + 'Psr\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/event-dispatcher/src', + ), + 'Psr\\Container\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/container/src', + ), + 'PhpOption\\' => + array ( + 0 => __DIR__ . '/..' . '/phpoption/phpoption/src/PhpOption', + ), + 'ParagonIE\\ConstantTime\\' => + array ( + 0 => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src', + ), + 'Opis\\Closure\\' => + array ( + 0 => __DIR__ . '/..' . '/opis/closure/src', + ), + 'Nyholm\\Psr7\\' => + array ( + 0 => __DIR__ . '/..' . '/nyholm/psr7/src', + ), + 'NunoMaduro\\Collision\\' => + array ( + 0 => __DIR__ . '/..' . '/nunomaduro/collision/src', + ), + 'Monolog\\' => + array ( + 0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog', + ), + 'Lorisleiva\\LaravelSearchString\\' => + array ( + 0 => __DIR__ . '/..' . '/lorisleiva/laravel-search-string/src', + ), + 'League\\OAuth2\\Server\\' => + array ( + 0 => __DIR__ . '/..' . '/league/oauth2-server/src', + ), + 'League\\MimeTypeDetection\\' => + array ( + 0 => __DIR__ . '/..' . '/league/mime-type-detection/src', + ), + 'League\\Flysystem\\' => + array ( + 0 => __DIR__ . '/..' . '/league/flysystem/src', + ), + 'League\\Event\\' => + array ( + 0 => __DIR__ . '/..' . '/league/event/src', + ), + 'League\\Config\\' => + array ( + 0 => __DIR__ . '/..' . '/league/config/src', + ), + 'League\\CommonMark\\' => + array ( + 0 => __DIR__ . '/..' . '/league/commonmark/src', + ), + 'Lcobucci\\JWT\\' => + array ( + 0 => __DIR__ . '/..' . '/lcobucci/jwt/src', + ), + 'Lcobucci\\Clock\\' => + array ( + 0 => __DIR__ . '/..' . '/lcobucci/clock/src', + ), + 'Laravel\\SerializableClosure\\' => + array ( + 0 => __DIR__ . '/..' . '/laravel/serializable-closure/src', + ), + 'Laravel\\Passport\\Database\\Factories\\' => + array ( + 0 => __DIR__ . '/..' . '/laravel/passport/database/factories', + ), + 'Laravel\\Passport\\' => + array ( + 0 => __DIR__ . '/..' . '/laravel/passport/src', + ), + 'Intervention\\Image\\' => + array ( + 0 => __DIR__ . '/..' . '/intervention/image/src/Intervention/Image', + ), + 'Illuminate\\Support\\' => + array ( + 0 => __DIR__ . '/..' . '/laravel/framework/src/Illuminate/Macroable', + 1 => __DIR__ . '/..' . '/laravel/framework/src/Illuminate/Collections', + ), + 'Illuminate\\' => + array ( + 0 => __DIR__ . '/..' . '/laravel/framework/src/Illuminate', + ), + 'Http\\Message\\' => + array ( + 0 => __DIR__ . '/..' . '/php-http/message-factory/src', + ), + 'Hoa\\Zformat\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/zformat', + ), + 'Hoa\\Visitor\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/visitor', + ), + 'Hoa\\Ustring\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/ustring', + ), + 'Hoa\\Stream\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/stream', + ), + 'Hoa\\Regex\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/regex', + ), + 'Hoa\\Protocol\\Bin\\' => + array ( + 0 => __DIR__ . '/..' . '/sanmai/hoa-protocol/Bin', + ), + 'Hoa\\Protocol\\' => + array ( + 0 => __DIR__ . '/..' . '/sanmai/hoa-protocol/Source', + ), + 'Hoa\\Math\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/math', + ), + 'Hoa\\Iterator\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/iterator', + ), + 'Hoa\\File\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/file', + ), + 'Hoa\\Exception\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/exception', + ), + 'Hoa\\Event\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/event', + ), + 'Hoa\\Consistency\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/consistency', + ), + 'Hoa\\Compiler\\' => + array ( + 0 => __DIR__ . '/..' . '/hoa/compiler', + ), + 'GuzzleHttp\\Psr7\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', + ), + 'GuzzleHttp\\Promise\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/promises/src', + ), + 'GuzzleHttp\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src', + ), + 'Gregwar\\' => + array ( + 0 => __DIR__ . '/..' . '/gregwar/captcha/src/Gregwar', + ), + 'GrahamCampbell\\ResultType\\' => + array ( + 0 => __DIR__ . '/..' . '/graham-campbell/result-type/src', + ), + 'Firebase\\JWT\\' => + array ( + 0 => __DIR__ . '/..' . '/firebase/php-jwt/src', + ), + 'Facade\\Ignition\\' => + array ( + 0 => __DIR__ . '/..' . '/facade/ignition/src', + ), + 'Facade\\IgnitionContracts\\' => + array ( + 0 => __DIR__ . '/..' . '/facade/ignition-contracts/src', + ), + 'Facade\\FlareClient\\' => + array ( + 0 => __DIR__ . '/..' . '/facade/flare-client-php/src', + ), + 'Egulias\\EmailValidator\\' => + array ( + 0 => __DIR__ . '/..' . '/egulias/email-validator/src', + ), + 'Dotenv\\' => + array ( + 0 => __DIR__ . '/..' . '/vlucas/phpdotenv/src', + ), + 'Doctrine\\Inflector\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Inflector', + ), + 'Doctrine\\Deprecations\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations', + ), + 'Doctrine\\DBAL\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/dbal/lib/Doctrine/DBAL', + ), + 'Doctrine\\Common\\Lexer\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/lexer/lib/Doctrine/Common/Lexer', + ), + 'Doctrine\\Common\\Inflector\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Common/Inflector', + ), + 'Doctrine\\Common\\Cache\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/cache/lib/Doctrine/Common/Cache', + ), + 'Doctrine\\Common\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/event-manager/lib/Doctrine/Common', + ), + 'Dflydev\\DotAccessData\\' => + array ( + 0 => __DIR__ . '/..' . '/dflydev/dot-access-data/src', + ), + 'Defuse\\Crypto\\' => + array ( + 0 => __DIR__ . '/..' . '/defuse/php-encryption/src', + ), + 'Database\\Factories\\' => + array ( + 0 => __DIR__ . '/../..' . '/database/factories', + ), + 'Cron\\' => + array ( + 0 => __DIR__ . '/..' . '/dragonmantank/cron-expression/src/Cron', + ), + 'Composer\\Semver\\' => + array ( + 0 => __DIR__ . '/..' . '/composer/semver/src', + ), + 'Composer\\CaBundle\\' => + array ( + 0 => __DIR__ . '/..' . '/composer/ca-bundle/src', + ), + 'Carbon\\' => + array ( + 0 => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon', + ), + 'Brick\\Math\\' => + array ( + 0 => __DIR__ . '/..' . '/brick/math/src', + ), + 'Blessing\\' => + array ( + 0 => __DIR__ . '/..' . '/blessing/filter/src/Blessing', + 1 => __DIR__ . '/..' . '/blessing/rejection/src/Blessing', + 2 => __DIR__ . '/..' . '/blessing/texture-renderer/src/Blessing', + ), + 'App\\' => + array ( + 0 => __DIR__ . '/../..' . '/app', + ), + ); + + public static $prefixesPsr0 = array ( + 'T' => + array ( + 'Twig_' => + array ( + 0 => __DIR__ . '/..' . '/twig/twig/lib', + ), + ), + ); + + public static $classMap = array ( + 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', + 'Nette\\ArgumentOutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\DeprecatedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\DirectoryNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\FileNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\HtmlStringable' => __DIR__ . '/..' . '/nette/utils/src/HtmlStringable.php', + 'Nette\\IOException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\InvalidArgumentException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\InvalidStateException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\Iterators\\CachingIterator' => __DIR__ . '/..' . '/nette/utils/src/Iterators/CachingIterator.php', + 'Nette\\Iterators\\Mapper' => __DIR__ . '/..' . '/nette/utils/src/Iterators/Mapper.php', + 'Nette\\Localization\\ITranslator' => __DIR__ . '/..' . '/nette/utils/src/compatibility.php', + 'Nette\\Localization\\Translator' => __DIR__ . '/..' . '/nette/utils/src/Translator.php', + 'Nette\\MemberAccessException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\NotImplementedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\NotSupportedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\OutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\Schema\\Context' => __DIR__ . '/..' . '/nette/schema/src/Schema/Context.php', + 'Nette\\Schema\\DynamicParameter' => __DIR__ . '/..' . '/nette/schema/src/Schema/DynamicParameter.php', + 'Nette\\Schema\\Elements\\AnyOf' => __DIR__ . '/..' . '/nette/schema/src/Schema/Elements/AnyOf.php', + 'Nette\\Schema\\Elements\\Base' => __DIR__ . '/..' . '/nette/schema/src/Schema/Elements/Base.php', + 'Nette\\Schema\\Elements\\Structure' => __DIR__ . '/..' . '/nette/schema/src/Schema/Elements/Structure.php', + 'Nette\\Schema\\Elements\\Type' => __DIR__ . '/..' . '/nette/schema/src/Schema/Elements/Type.php', + 'Nette\\Schema\\Expect' => __DIR__ . '/..' . '/nette/schema/src/Schema/Expect.php', + 'Nette\\Schema\\Helpers' => __DIR__ . '/..' . '/nette/schema/src/Schema/Helpers.php', + 'Nette\\Schema\\Message' => __DIR__ . '/..' . '/nette/schema/src/Schema/Message.php', + 'Nette\\Schema\\Processor' => __DIR__ . '/..' . '/nette/schema/src/Schema/Processor.php', + 'Nette\\Schema\\Schema' => __DIR__ . '/..' . '/nette/schema/src/Schema/Schema.php', + 'Nette\\Schema\\ValidationException' => __DIR__ . '/..' . '/nette/schema/src/Schema/ValidationException.php', + 'Nette\\SmartObject' => __DIR__ . '/..' . '/nette/utils/src/SmartObject.php', + 'Nette\\StaticClass' => __DIR__ . '/..' . '/nette/utils/src/StaticClass.php', + 'Nette\\UnexpectedValueException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\Utils\\ArrayHash' => __DIR__ . '/..' . '/nette/utils/src/Utils/ArrayHash.php', + 'Nette\\Utils\\ArrayList' => __DIR__ . '/..' . '/nette/utils/src/Utils/ArrayList.php', + 'Nette\\Utils\\Arrays' => __DIR__ . '/..' . '/nette/utils/src/Utils/Arrays.php', + 'Nette\\Utils\\AssertionException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Callback' => __DIR__ . '/..' . '/nette/utils/src/Utils/Callback.php', + 'Nette\\Utils\\DateTime' => __DIR__ . '/..' . '/nette/utils/src/Utils/DateTime.php', + 'Nette\\Utils\\FileSystem' => __DIR__ . '/..' . '/nette/utils/src/Utils/FileSystem.php', + 'Nette\\Utils\\Floats' => __DIR__ . '/..' . '/nette/utils/src/Utils/Floats.php', + 'Nette\\Utils\\Helpers' => __DIR__ . '/..' . '/nette/utils/src/Utils/Helpers.php', + 'Nette\\Utils\\Html' => __DIR__ . '/..' . '/nette/utils/src/Utils/Html.php', + 'Nette\\Utils\\IHtmlString' => __DIR__ . '/..' . '/nette/utils/src/compatibility.php', + 'Nette\\Utils\\Image' => __DIR__ . '/..' . '/nette/utils/src/Utils/Image.php', + 'Nette\\Utils\\ImageException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Json' => __DIR__ . '/..' . '/nette/utils/src/Utils/Json.php', + 'Nette\\Utils\\JsonException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\ObjectHelpers' => __DIR__ . '/..' . '/nette/utils/src/Utils/ObjectHelpers.php', + 'Nette\\Utils\\ObjectMixin' => __DIR__ . '/..' . '/nette/utils/src/Utils/ObjectMixin.php', + 'Nette\\Utils\\Paginator' => __DIR__ . '/..' . '/nette/utils/src/Utils/Paginator.php', + 'Nette\\Utils\\Random' => __DIR__ . '/..' . '/nette/utils/src/Utils/Random.php', + 'Nette\\Utils\\Reflection' => __DIR__ . '/..' . '/nette/utils/src/Utils/Reflection.php', + 'Nette\\Utils\\RegexpException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Strings' => __DIR__ . '/..' . '/nette/utils/src/Utils/Strings.php', + 'Nette\\Utils\\Type' => __DIR__ . '/..' . '/nette/utils/src/Utils/Type.php', + 'Nette\\Utils\\UnknownImageFileException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Validators' => __DIR__ . '/..' . '/nette/utils/src/Utils/Validators.php', + 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'ReturnTypeWillChange' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php', + 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit0a9d7af445e16b3da8206b47ab1f0594::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit0a9d7af445e16b3da8206b47ab1f0594::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInit0a9d7af445e16b3da8206b47ab1f0594::$prefixesPsr0; + $loader->classMap = ComposerStaticInit0a9d7af445e16b3da8206b47ab1f0594::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/ca-bundle/LICENSE b/vendor/composer/ca-bundle/LICENSE new file mode 100755 index 0000000..c5b5220 --- /dev/null +++ b/vendor/composer/ca-bundle/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2016 Composer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/composer/ca-bundle/README.md b/vendor/composer/ca-bundle/README.md new file mode 100755 index 0000000..d8205ec --- /dev/null +++ b/vendor/composer/ca-bundle/README.md @@ -0,0 +1,85 @@ +composer/ca-bundle +================== + +Small utility library that lets you find a path to the system CA bundle, +and includes a fallback to the Mozilla CA bundle. + +Originally written as part of [composer/composer](https://github.com/composer/composer), +now extracted and made available as a stand-alone library. + + +Installation +------------ + +Install the latest version with: + +```bash +$ composer require composer/ca-bundle +``` + + +Requirements +------------ + +* PHP 5.3.2 is required but using the latest version of PHP is highly recommended. + + +Basic usage +----------- + +### `Composer\CaBundle\CaBundle` + +- `CaBundle::getSystemCaRootBundlePath()`: Returns the system CA bundle path, or a path to the bundled one as fallback +- `CaBundle::getBundledCaBundlePath()`: Returns the path to the bundled CA file +- `CaBundle::validateCaFile($filename)`: Validates a CA file using openssl_x509_parse only if it is safe to use +- `CaBundle::isOpensslParseSafe()`: Test if it is safe to use the PHP function openssl_x509_parse() +- `CaBundle::reset()`: Resets the static caches + + +#### To use with curl + +```php +$curl = curl_init("https://example.org/"); + +$caPathOrFile = \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(); +if (is_dir($caPathOrFile)) { + curl_setopt($curl, CURLOPT_CAPATH, $caPathOrFile); +} else { + curl_setopt($curl, CURLOPT_CAINFO, $caPathOrFile); +} + +$result = curl_exec($curl); +``` + +#### To use with php streams + +```php +$opts = array( + 'http' => array( + 'method' => "GET" + ) +); + +$caPathOrFile = \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(); +if (is_dir($caPathOrFile)) { + $opts['ssl']['capath'] = $caPathOrFile; +} else { + $opts['ssl']['cafile'] = $caPathOrFile; +} + +$context = stream_context_create($opts); +$result = file_get_contents('https://example.com', false, $context); +``` + +#### To use with Guzzle + +```php +$client = new \GuzzleHttp\Client([ + \GuzzleHttp\RequestOptions::VERIFY => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath() +]); +``` + +License +------- + +composer/ca-bundle is licensed under the MIT License, see the LICENSE file for details. diff --git a/vendor/composer/ca-bundle/composer.json b/vendor/composer/ca-bundle/composer.json new file mode 100755 index 0000000..ed6a1b3 --- /dev/null +++ b/vendor/composer/ca-bundle/composer.json @@ -0,0 +1,54 @@ +{ + "name": "composer/ca-bundle", + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "type": "library", + "license": "MIT", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.2 || ^5", + "phpstan/phpstan": "^0.12.55", + "psr/log": "^1.0", + "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0" + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Composer\\CaBundle\\": "tests" + } + }, + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "scripts": { + "test": "SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1 vendor/bin/simple-phpunit", + "phpstan": "vendor/bin/phpstan analyse" + } +} diff --git a/vendor/composer/ca-bundle/res/cacert.pem b/vendor/composer/ca-bundle/res/cacert.pem new file mode 100755 index 0000000..0bf312f --- /dev/null +++ b/vendor/composer/ca-bundle/res/cacert.pem @@ -0,0 +1,3232 @@ +## +## Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Tue Oct 26 03:12:05 2021 GMT +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## +## Conversion done with mk-ca-bundle.pl version 1.28. +## SHA256: bb36818a81feaa4cca61101e6d6276cd09e972efcb08112dfed846918ca41d7f +## + + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +GlobalSign Root CA - R2 +======================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 +ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp +s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN +S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL +TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C +ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i +YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN +BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp +9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu +01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 +9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ +KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy +T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT +J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e +nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx +ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 +XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk +lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB +lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy +lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt +66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn +wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh +D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy +BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie +J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud +DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU +a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv +Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 +UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm +VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK ++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW +IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 +WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X +f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II +4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 +VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx +OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg +DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij +KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K +DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv +BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp +p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 +nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX +MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM +Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz +uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT +BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj +YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB +BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD +VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 +ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE +AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV +qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s +hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z +POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 +Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp +8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC +bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu +g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p +vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr +qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +Security Communication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw +8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM +DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX +5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd +DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 +JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g +0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a +mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ +s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ +6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi +FL39vmwLAw== +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw +EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN +MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp +c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq +t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C +jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg +vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF +ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR +AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend +jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO +peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR +7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi +GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 +OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm +5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr +44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf +Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m +Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp +mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk +vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf +KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br +NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj +viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X +DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 +aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 +N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm ++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH +6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu +MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h +qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 +FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs +ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc +celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X +CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB +tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P +4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F +kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L +3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx +/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa +DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP +e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu +WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ +DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub +DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +Network Solutions Certificate Authority +======================================= +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG +EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr +IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx +MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx +jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT +aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT +crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc +/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB +AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv +bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA +A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q +4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ +GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD +ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +Cybertrust Global Root +====================== +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li +ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 +MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD +ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW +0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL +AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin +89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT +8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 +MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G +A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO +lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi +5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 +hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T +X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +======================================== +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Hongkong Post Root CA 1 +======================= +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT +DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx +NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n +IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 +ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr +auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh +qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY +V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV +HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i +h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio +l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei +IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps +T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT +c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud +EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH +DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA +bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx +ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx +51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk +R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP +T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f +Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl +osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR +crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR +saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD +KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi +6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG +EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz +MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu +QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ +03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK +ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU ++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC +PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT +OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK +F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK +0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ +0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB +leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID +AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ +SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG +NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l +Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga +kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q +hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs +g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 +aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 +nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC +ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo +Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z +WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +EC-ACC +====== +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE +BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w +ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD +VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE +CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT +BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 +MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt +SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl +Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh +cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK +w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT +ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 +HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a +E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw +0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD +VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 +Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l +dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ +lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa +Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe +l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 +E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D +5EI= +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2011 +======================================================= +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT +O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y +aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT +AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo +IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI +1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa +71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u +8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH +3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ +MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 +MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu +b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt +XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD +/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N +7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM +BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE +AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky +MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz +IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ +wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa +by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 +zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f +YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 +oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l +EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 +hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 +EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 +jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY +iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI +WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 +JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx +K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ +Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC +4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo +2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz +lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem +OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 +vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe +Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE +LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD +ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA +BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv +KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z +p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC +AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ +4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y +eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw +MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G +PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw +OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm +2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV +dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph +X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +================================= +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS +egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh +zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T +7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 +sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 +11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv +cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El +MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp +b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh +c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ +PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX +ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA +NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv +w9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +CA Disig Root R2 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC +w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia +xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 +A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S +GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV +g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa +5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE +koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A +Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i +Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u +Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV +sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je +dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 +1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx +mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 +utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 +sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg +UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV +7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +========= +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB +SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 +MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH +UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM +jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 +RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD +aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ +0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG +WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 +8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR +5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J +9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK +Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw +Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu +Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM +Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA +QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh +AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA +YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj +AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA +IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk +aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 +dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 +MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI +hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E +R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN +YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 +nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ +TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 +sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg +Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd +3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p +EfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT +CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD +QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK +EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C +nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV +r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR +Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV +tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W +KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 +sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p +yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn +kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI +zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g +cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M +8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg +/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg +lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP +A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m +i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 +EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 +zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= +-----END CERTIFICATE----- + +TeliaSonera Root CA v1 +====================== +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE +CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 +MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW +VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ +6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA +3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k +B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn +Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH +oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 +F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ +oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 +gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc +TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB +AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW +DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm +zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW +pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV +G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc +c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT +JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 +qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 +Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems +WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +E-Tugra Certification Authority +=============================== +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w +DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls +ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw +NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx +QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl +cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD +DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd +hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K +CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g +ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ +BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0 +E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz +rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq +jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5 +dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB +/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG +MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK +kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO +XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807 +VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo +a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc +dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV +KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT +Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0 +8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G +C7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 2 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx +MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ +SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F +vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 +2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV +WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy +YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 +r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf +vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR +3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== +-----END CERTIFICATE----- + +Atos TrustedRoot 2011 +===================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU +cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 +MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG +A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV +hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr +54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ +DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 +HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR +z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R +l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ +bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h +k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh +TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 +61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G +3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +QuoVadis Root CA 1 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE +PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm +PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 +Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN +ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l +g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV +7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX +9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f +iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg +t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI +hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 +GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct +Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP ++V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh +3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa +wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 +O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 +FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV +hMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +QuoVadis Root CA 2 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh +ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY +NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t +oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o +MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l +V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo +L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ +sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD +6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh +lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI +hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K +pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 +x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz +dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X +U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw +mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD +zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN +JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr +O3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +QuoVadis Root CA 3 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 +IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL +Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe +6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 +I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U +VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 +5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi +Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM +dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt +rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI +hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS +t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ +TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du +DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib +Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD +hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX +0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW +dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 +PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +DigiCert Assured ID Root G2 +=========================== +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw +MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH +35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq +bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw +VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP +YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn +lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO +w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv +0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz +d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW +hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M +jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +DigiCert Assured ID Root G3 +=========================== +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD +VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb +RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs +KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF +UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy +YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy +1vUhZscv6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +DigiCert Global Root G2 +======================= +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx +MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ +kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO +3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV +BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM +UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu +5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr +F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U +WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH +QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ +iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +DigiCert Global Root G3 +======================= +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD +VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw +MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k +aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C +AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O +YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp +Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y +3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 +VOKa5Vt8sycX +-----END CERTIFICATE----- + +DigiCert Trusted Root G4 +======================== +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw +HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp +pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o +k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa +vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY +QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 +MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm +mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 +f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH +dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 +oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY +ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr +yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy +7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah +ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN +5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb +/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa +5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK +G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP +82Z+ +-----END CERTIFICATE----- + +COMODO RSA Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn +dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ +FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ +5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG +x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX +2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL +OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 +sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C +GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 +WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt +rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ +nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg +tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW +sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp +pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA +zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq +ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 +7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I +LaZRfyHBNVOFBkpdn627G190 +-----END CERTIFICATE----- + +USERTrust RSA Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz +0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j +Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn +RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O ++T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq +/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE +Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM +lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8 +yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+ +eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW +FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ +7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ +Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM +8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi +FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi +yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c +J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw +sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx +Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +USERTrust ECC Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2 +0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez +nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV +HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB +HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu +9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R4 +=========================== +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl +OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P +AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV +MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF +JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R5 +=========================== +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6 +SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS +h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx +uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 +yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +Staat der Nederlanden EV Root CA +================================ +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M +MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl +cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk +SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW +O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r +0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8 +Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV +XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr +08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV +0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd +74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx +fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa +ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu +c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq +5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN +b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN +f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi +5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4 +WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK +DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy +eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg== +-----END CERTIFICATE----- + +IdenTrust Commercial Root CA 1 +============================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS +b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES +MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB +IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld +hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ +mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi +1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C +XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl +3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy +NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV +WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg +xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix +uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI +hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg +ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt +ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV +YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX +feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro +kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe +2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz +Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R +cGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +IdenTrust Public Sector Root CA 1 +================================= +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv +ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV +UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS +b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy +P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 +Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI +rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf +qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS +mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn +ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh +LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v +iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL +4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B +Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw +DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A +mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt +GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt +m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx +NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 +Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI +ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC +ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ +3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy +bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug +b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw +HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT +DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx +OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP +/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz +HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU +s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y +TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx +AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 +0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z +iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi +nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ +vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO +e4pIb4tF9g== +-----END CERTIFICATE----- + +Entrust Root Certification Authority - EC1 +========================================== +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx +FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn +YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw +FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs +LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg +dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy +AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef +9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h +vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 +kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +CFCA EV ROOT +============ +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE +CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB +IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw +MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD +DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV +BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD +7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN +uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW +ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 +xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f +py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K +gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol +hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ +tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf +BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q +ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua +4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG +E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX +BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn +aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy +PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX +kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C +ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GB CA +=============================== +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG +EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw +MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds +b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX +scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP +rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk +9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o +Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg +GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI +hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD +dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0 +VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui +HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +SZAFIR ROOT CA2 +=============== +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV +BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ +BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD +VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q +qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK +DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE +2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ +ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi +ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC +AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5 +O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67 +oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul +4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6 ++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +Certum Trusted Network CA 2 +=========================== +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE +BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1 +bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y +ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ +TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB +IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9 +7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o +CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b +Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p +uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130 +GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ +9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB +Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye +hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM +BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI +hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW +Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA +L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo +clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM +pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb +w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo +J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm +ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX +is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7 +zAYspsbiDrW5viSP +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2015 +======================================================= +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT +BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0 +aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx +MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg +QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV +BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw +MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv +bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh +iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+ +6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd +FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr +i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F +GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2 +fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu +iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI +hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+ +D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM +d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y +d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn +82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb +davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F +Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt +J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa +JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q +p/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions ECC RootCA 2015 +=========================================================== +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0 +aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw +MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj +IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD +VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290 +Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP +dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK +Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA +GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn +dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +ISRG Root X1 +============ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE +BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD +EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG +EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT +DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r +Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1 +3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K +b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN +Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ +4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf +1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu +hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH +usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r +OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY +9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV +0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt +hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw +TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx +e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA +JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD +YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n +JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ +m+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM +================ +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT +AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw +MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD +TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf +qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr +btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL +j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou +08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw +WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT +tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ +47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC +ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa +i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o +dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s +D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ +j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT +Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW ++YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7 +Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d +8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm +5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG +rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +Amazon Root CA 1 +================ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1 +MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH +FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ +gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t +dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce +VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3 +DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM +CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy +8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa +2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2 +xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +Amazon Root CA 2 +================ +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1 +MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4 +kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp +N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9 +AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd +fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx +kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS +btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0 +Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN +c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+ +3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw +DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA +A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE +YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW +xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ +gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW +aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV +Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3 +KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi +JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw= +-----END CERTIFICATE----- + +Amazon Root CA 3 +================ +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB +f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr +Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43 +rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc +eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +Amazon Root CA 4 +================ +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN +/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri +83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA +MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1 +AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT +D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr +IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g +TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp +ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD +VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt +c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth +bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11 +IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8 +6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc +wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0 +3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9 +WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU +ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc +lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R +e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j +q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +GDCA TrustAUTH R5 ROOT +====================== +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw +BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD +DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow +YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs +AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p +OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr +pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ +9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ +xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM +R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ +D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4 +oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx +9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9 +H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35 +6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd ++PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ +HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD +F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ +8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv +/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT +aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +TrustCor RootCert CA-1 +====================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYDVQQGEwJQQTEP +MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig +U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkx +MjMxMTcyMzE2WjCBpDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFu +YW1hIENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUGA1UECwwe +VHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZUcnVzdENvciBSb290Q2Vy +dCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv463leLCJhJrMxnHQFgKq1mq +jQCj/IDHUHuO1CAmujIS2CNUSSUQIpidRtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4 +pQa81QBeCQryJ3pS/C3Vseq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0 +JEsq1pme9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CVEY4h +gLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorWhnAbJN7+KIor0Gqw +/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/DeOxCbeKyKsZn3MzUOcwHwYDVR0j +BBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwDQYJKoZIhvcNAQELBQADggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5 +mDo4Nvu7Zp5I/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf +ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZyonnMlo2HD6C +qFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djtsL1Ac59v2Z3kf9YKVmgenFK+P +3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdNzl/HHk484IkzlQsPpTLWPFp5LBk= +-----END CERTIFICATE----- + +TrustCor RootCert CA-2 +====================== +-----BEGIN CERTIFICATE----- +MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNVBAYTAlBBMQ8w +DQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBT +eXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0 +eTEfMB0GA1UEAwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEy +MzExNzI2MzlaMIGkMQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5h +bWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0 +IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnIG7CKqJiJJWQdsg4foDSq8Gb +ZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9Nk +RvRUqdw6VC0xK5mC8tkq1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1 +oYxOdqHp2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nKDOOb +XUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hapeaz6LMvYHL1cEksr1 +/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF3wP+TfSvPd9cW436cOGlfifHhi5q +jxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQP +eSghYA2FFn3XVDjxklb9tTNMg9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+Ctg +rKAmrhQhJ8Z3mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh +8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAdBgNVHQ4EFgQU +2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6UnrybPZx9mCAZ5YwwYrIwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/h +Osh80QA9z+LqBrWyOrsGS2h60COXdKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnp +kpfbsEZC89NiqpX+MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv +2wnL/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RXCI/hOWB3 +S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYaZH9bDTMJBzN7Bj8RpFxw +PIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dv +DDqPys/cA8GiCcjl/YBeyGBCARsaU1q7N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYU +RpFHmygk71dSTlxCnKr3Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANE +xdqtvArBAs8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp5KeX +RKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu1uwJ +-----END CERTIFICATE----- + +TrustCor ECA-1 +============== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYDVQQGEwJQQTEP +MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig +U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkxFzAVBgNVBAMMDlRydXN0Q29yIEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3Mjgw +N1owgZwxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5 +MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29y +IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3IgRUNBLTEwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb3w9U73NjKYKtR8aja+3+XzP4Q1HpGjOR +MRegdMTUpwHmspI+ap3tDvl0mEDTPwOABoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23 +xFUfJ3zSCNV2HykVh0A53ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmc +p0yJF4OuowReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/wZ0+ +fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZFZtS6mFjBAgMBAAGj +YzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAfBgNVHSMEGDAWgBREnkj1zG1I1KBL +f/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF +AAOCAQEABT41XBVwm8nHc2FvcivUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u +/ukZMjgDfxT2AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F +hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50soIipX1TH0Xs +J5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BIWJZpTdwHjFGTot+fDz2LYLSC +jaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1WitJ/X5g== +-----END CERTIFICATE----- + +SSL.com Root Certification Authority RSA +======================================== +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM +BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x +MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw +MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM +LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C +Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8 +P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge +oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp +k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z +fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ +gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2 +UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8 +1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s +bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr +dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf +ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl +u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq +erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj +MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ +vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI +Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y +wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI +WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +SSL.com Root Certification Authority ECC +======================================== +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv +BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy +MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO +BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+ +8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR +hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT +jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW +e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z +5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority RSA R2 +============================================== +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w +DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u +MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI +DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD +VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh +hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w +cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO +Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+ +B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh +CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim +9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto +RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm +JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48 ++qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp +qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1 +++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx +Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G +guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz +OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7 +CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq +lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR +rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1 +hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX +9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority ECC +=========================================== +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy +BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw +MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM +LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy +3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O +BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe +5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ +N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm +m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +GlobalSign Root CA - R6 +======================= +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX +R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i +YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs +U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss +grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE +3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF +vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM +PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+ +azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O +WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy +CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP +0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN +b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE +AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV +HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0 +lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY +BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym +Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr +3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1 +0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T +uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK +oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t +JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GC CA +=============================== +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD +SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo +MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa +Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL +ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr +VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab +NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E +AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk +AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +GTS Root R1 +=========== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG +EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv +b3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG +A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx +9vaMf/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7r +aKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnW +r4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqM +LnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly +4cpk9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr +06zqkUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om +3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNu +JLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEM +BQADggIBADiWCu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 +d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6ZXPYfcX3v73sv +fuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZRgyFmxhE+885H7pwoHyXa/6xm +ld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9b +gsiG1eGZbYwE8na6SfZu6W0eX6DvJ4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq +4BjFbkerQUIpm/ZgDdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWEr +tXvM+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyyF62ARPBo +pY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9SQ98POyDGCBDTtWTurQ0 +sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdwsE3PYJ/HQcu51OyLemGhmW/HGY0dVHLql +CFF1pkgl +-----END CERTIFICATE----- + +GTS Root R2 +=========== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG +EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv +b3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG +A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTuk +k3LvCvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo +7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWI +m8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5Gm +dFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbu +ak7MkogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscsz +cTJGr61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW +Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73Vululycsl +aVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy +5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEM +BQADggIBALZp8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT +vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiTz9D2PGcDFWEJ ++YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiApJiS4wGWAqoC7o87xdFtCjMw +c3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvbpxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3Da +WsYDQvTtN6LwG1BUSw7YhN4ZKJmBR64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5r +n/WkhLx3+WuXrD5RRaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56Gtmwfu +Nmsk0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC5AwiWVIQ +7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiFizoHCBy69Y9Vmhh1fuXs +gWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLnyOd/xCxgXS/Dr55FBcOEArf9LAhST4Ld +o/DUhgkC +-----END CERTIFICATE----- + +GTS Root R3 +=========== +-----BEGIN CERTIFICATE----- +MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUU +Rout736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24Cej +QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP +0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFukfCPAlaUs3L6JbyO5o91lAFJekazInXJ0 +glMLfalAvWhgxeG4VDvBNhcl2MG9AjEAnjWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOa +KaqW04MjyaR7YbPMAuhd +-----END CERTIFICATE----- + +GTS Root R4 +=========== +-----BEGIN CERTIFICATE----- +MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa +6zzuhXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqj +QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV +2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0CMRw3J5QdCHojXohw0+WbhXRIjVhLfoI +N+4Zba3bssx9BzT1YBkstTTZbyACMANxsbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11x +zPKwTdb+mciUqXWi4w== +-----END CERTIFICATE----- + +UCA Global G2 Root +================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x +NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU +cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT +oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV +8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS +h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o +LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/ +R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe +KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa +4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc +OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97 +8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo +5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A +Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9 +yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX +c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo +jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk +bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x +ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn +RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A== +-----END CERTIFICATE----- + +UCA Extended Validation Root +============================ +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u +IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G +A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs +iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF +Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu +eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR +59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH +0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR +el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv +B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth +WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS +NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS +3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL +BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM +aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4 +dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb ++7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW +F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi +GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc +GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi +djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr +dhh2n1ax +-----END CERTIFICATE----- + +Certigna Root CA +================ +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE +BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ +MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda +MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz +MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX +stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz +KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8 +JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16 +XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq +4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej +wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ +lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI +jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/ +/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy +dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h +LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl +cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt +OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP +TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq +7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3 +4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd +8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS +6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY +tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS +aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde +E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +emSign Root CA - G1 +=================== +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET +MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl +ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx +ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk +aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN +LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1 +cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW +DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ +6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH +hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2 +vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q +NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q ++Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih +U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +emSign ECC Root CA - G3 +======================= +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG +A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg +MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4 +MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11 +ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc +58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr +MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D +CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7 +jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +emSign Root CA - C1 +=================== +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx +EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp +Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD +ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up +ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/ +Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX +OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V +I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms +lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+ +XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD +ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp +/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1 +NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9 +wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ +BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +emSign ECC Root CA - C3 +======================= +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG +A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF +Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD +ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd +6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9 +SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA +B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA +MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU +ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +Hongkong Post Root CA 3 +======================= +-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG +A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK +Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2 +MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv +bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX +SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz +iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf +jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim +5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe +sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj +0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/ +JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u +y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h ++bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG +xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID +AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN +AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw +W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld +y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov ++BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc +eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw +9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7 +nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY +hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB +60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq +dBb9HxEGmpv0 +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G4 +========================================= +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAwgb4xCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu +bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1 +dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eSAtIEc0MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYT +AlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3D +umSXbcr3DbVZwbPLqGgZ2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV +3imz/f3ET+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j5pds +8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAMC1rlLAHGVK/XqsEQ +e9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73TDtTUXm6Hnmo9RR3RXRv06QqsYJn7 +ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNXwbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5X +xNMhIWNlUpEbsZmOeX7m640A2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV +7rtNOzK+mndmnqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwlN4y6mACXi0mW +Hv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNjc0kCAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9n +MA0GCSqGSIb3DQEBCwUAA4ICAQAS5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4Q +jbRaZIxowLByQzTSGwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht +7LGrhFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/B7NTeLUK +YvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uIAeV8KEsD+UmDfLJ/fOPt +jqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbwH5Lk6rWS02FREAutp9lfx1/cH6NcjKF+ +m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKW +RGhXxNUzzxkvFMSUHHuk2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjA +JOgc47OlIQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk5F6G ++TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuYn/PIjhs4ViFqUZPT +kcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- + +Microsoft ECC Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND +IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4 +MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6 +thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB +eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM ++Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf +Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR +eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +Microsoft RSA Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg +UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw +NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u +MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml +7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e +S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7 +1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+ +dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F +yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS +MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr +lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ +0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ +ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og +6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80 +dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk ++ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex +/2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy +AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW +ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE +7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT +c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D +5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +e-Szigno Root CA 2017 +===================== +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw +DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt +MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa +Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE +CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp +Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx +s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G +A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv +vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA +tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO +svxyqltZ+efcMQ== +-----END CERTIFICATE----- + +certSIGN Root CA G2 +=================== +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw +EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy +MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH +TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05 +N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk +abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg +wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp +dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh +ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732 +jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf +95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc +z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL +iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud +DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB +ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB +/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5 +8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5 +BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW +atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU +Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M +NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N +0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +Trustwave Global Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29 +zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf +LdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq +stTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o +WN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+ +OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40 +Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE +uE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm ++9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj +ifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB +BjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H +PinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H +ZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla +4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R +vbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd +zyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O +856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH +Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu +3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP +29FpHOTKyeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- + +Trustwave Global ECC P256 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1 +NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj +43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm +P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt +0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz +RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- + +Trustwave Global ECC P384 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4 +NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH +Ba5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr +/TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV +HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn +ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl +CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw== +-----END CERTIFICATE----- + +NAVER Global Root Certification Authority +========================================= +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG +A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD +DClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4 +NDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT +UyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb +UGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW ++j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7 +XNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2 +aacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4 +Yb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z +VHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B +A0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai +cdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy +YhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV +HQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK +21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB +jCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx +hYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg +E34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH +D8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ +A76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY +qqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG +I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg +kpzNNIaRkPpkUZ3+/uul9XXeifdy +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM SERVIDORES SEGUROS +=================================== +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF +UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy +NjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4 +MTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt +UkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB +QyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2 +LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG +SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD +zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c= +-----END CERTIFICATE----- + +GlobalSign Root R46 +=================== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv +b3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX +BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es +CVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/ +r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje +2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt +bWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj +K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4 +12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on +ccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls +eVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9 +vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM +BQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy +gxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92 +CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm +OUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq +JZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye +qiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz +nxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7 +DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3 +QEUxeCp6 +-----END CERTIFICATE----- + +GlobalSign Root E46 +=================== +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT +AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg +RTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV +BAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB +jtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj +QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL +gLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk +vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+ +CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +GLOBALTRUST 2020 +================ +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx +IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT +VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh +BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy +MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi +D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO +VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM +CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm +fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA +A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR +JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG +DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU +clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ +mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud +IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw +4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9 +iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS +8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2 +HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS +vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918 +oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF +YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl +gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +ANF Secure Server Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4 +NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv +bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg +Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw +MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw +EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz +BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv +T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv +B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse +zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM +VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j +7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z +JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe +8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO +Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ +UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx +j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt +dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM +5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb +5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54 +EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H +hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy +g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3 +r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE----- + +Certum EC-384 CA +================ +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ +TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2 +MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh +dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq +vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn +iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo +ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0 +QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +Certum Trusted Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG +EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew +HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY +QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p +fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52 +HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2 +fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt +g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4 +NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk +fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ +P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY +njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK +HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL +LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s +ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K +h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8 +CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA +4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo +WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj +6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT +OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck +bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- + +TunTrust Root CA +================ +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG +A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj +dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw +NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD +ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz +2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b +bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7 +NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd +gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW +VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f +Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ +juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas +DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS +VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI +04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl +0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd +Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY +YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp +adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x +xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP +jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM +MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z +ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r +AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- + +HARICA TLS RSA Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG +EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz +OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl +bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB +IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN +JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu +a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y +Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K +5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv +dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR +0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH +GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm +haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ +CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU +EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq +QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD +QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR +j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5 +vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0 +qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6 +Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/ +PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn +kf3/W9b3raYvAwtt41dU63ZTGI0RmLo= +-----END CERTIFICATE----- + +HARICA TLS ECC Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH +UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD +QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX +DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj +IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv +b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l +AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b +ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW +0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi +rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw +CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE----- diff --git a/vendor/composer/ca-bundle/src/CaBundle.php b/vendor/composer/ca-bundle/src/CaBundle.php new file mode 100755 index 0000000..d99c00f --- /dev/null +++ b/vendor/composer/ca-bundle/src/CaBundle.php @@ -0,0 +1,431 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\CaBundle; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Process\PhpProcess; + +/** + * @author Chris Smith + * @author Jordi Boggiano + */ +class CaBundle +{ + /** @var string|null */ + private static $caPath; + /** @var array */ + private static $caFileValidity = array(); + /** @var bool|null */ + private static $useOpensslParse; + + /** + * Returns the system CA bundle path, or a path to the bundled one + * + * This method was adapted from Sslurp. + * https://github.com/EvanDotPro/Sslurp + * + * (c) Evan Coury + * + * For the full copyright and license information, please see below: + * + * Copyright (c) 2013, Evan Coury + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @param LoggerInterface $logger optional logger for information about which CA files were loaded + * @return string path to a CA bundle file or directory + */ + public static function getSystemCaRootBundlePath(LoggerInterface $logger = null) + { + if (self::$caPath !== null) { + return self::$caPath; + } + $caBundlePaths = array(); + + // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that. + // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. + $caBundlePaths[] = self::getEnvVariable('SSL_CERT_FILE'); + + // If SSL_CERT_DIR env variable points to a valid certificate/bundle, use that. + // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. + $caBundlePaths[] = self::getEnvVariable('SSL_CERT_DIR'); + + $caBundlePaths[] = ini_get('openssl.cafile'); + $caBundlePaths[] = ini_get('openssl.capath'); + + $otherLocations = array( + '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package) + '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package) + '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package) + '/usr/local/share/certs/ca-root-nss.crt', // FreeBSD (ca_root_nss_package) + '/usr/ssl/certs/ca-bundle.crt', // Cygwin + '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package + '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option) + '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat? + '/etc/ssl/cert.pem', // OpenBSD + '/usr/local/etc/ssl/cert.pem', // FreeBSD 10.x + '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package + '/usr/local/etc/openssl@1.1/cert.pem', // OS X homebrew, openssl@1.1 package + ); + + foreach($otherLocations as $location) { + $otherLocations[] = dirname($location); + } + + $caBundlePaths = array_merge($caBundlePaths, $otherLocations); + + foreach ($caBundlePaths as $caBundle) { + if ($caBundle && self::caFileUsable($caBundle, $logger)) { + return self::$caPath = $caBundle; + } + + if ($caBundle && self::caDirUsable($caBundle, $logger)) { + return self::$caPath = $caBundle; + } + } + + return self::$caPath = static::getBundledCaBundlePath(); // Bundled CA file, last resort + } + + /** + * Returns the path to the bundled CA file + * + * In case you don't want to trust the user or the system, you can use this directly + * + * @return string path to a CA bundle file + */ + public static function getBundledCaBundlePath() + { + $caBundleFile = __DIR__.'/../res/cacert.pem'; + + // cURL does not understand 'phar://' paths + // see https://github.com/composer/ca-bundle/issues/10 + if (0 === strpos($caBundleFile, 'phar://')) { + $tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-'); + if (false === $tempCaBundleFile) { + throw new \RuntimeException('Could not create a temporary file to store the bundled CA file'); + } + + file_put_contents( + $tempCaBundleFile, + file_get_contents($caBundleFile) + ); + + register_shutdown_function(function() use ($tempCaBundleFile) { + @unlink($tempCaBundleFile); + }); + + $caBundleFile = $tempCaBundleFile; + } + + return $caBundleFile; + } + + /** + * Validates a CA file using opensl_x509_parse only if it is safe to use + * + * @param string $filename + * @param LoggerInterface $logger optional logger for information about which CA files were loaded + * + * @return bool + */ + public static function validateCaFile($filename, LoggerInterface $logger = null) + { + static $warned = false; + + if (isset(self::$caFileValidity[$filename])) { + return self::$caFileValidity[$filename]; + } + + $contents = file_get_contents($filename); + + // assume the CA is valid if php is vulnerable to + // https://www.sektioneins.de/advisories/advisory-012013-php-openssl_x509_parse-memory-corruption-vulnerability.html + if (!static::isOpensslParseSafe()) { + if (!$warned && $logger) { + $logger->warning(sprintf( + 'Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.', + PHP_VERSION + )); + $warned = true; + } + + $isValid = !empty($contents); + } elseif (is_string($contents) && strlen($contents) > 0) { + $contents = preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents); + if (null === $contents) { + // regex extraction failed + $isValid = false; + } else { + $isValid = (bool) openssl_x509_parse($contents); + } + } else { + $isValid = false; + } + + if ($logger) { + $logger->debug('Checked CA file '.realpath($filename).': '.($isValid ? 'valid' : 'invalid')); + } + + return self::$caFileValidity[$filename] = $isValid; + } + + /** + * Test if it is safe to use the PHP function openssl_x509_parse(). + * + * This checks if OpenSSL extensions is vulnerable to remote code execution + * via the exploit documented as CVE-2013-6420. + * + * @return bool + */ + public static function isOpensslParseSafe() + { + if (null !== self::$useOpensslParse) { + return self::$useOpensslParse; + } + + if (PHP_VERSION_ID >= 50600) { + return self::$useOpensslParse = true; + } + + // Vulnerable: + // PHP 5.3.0 - PHP 5.3.27 + // PHP 5.4.0 - PHP 5.4.22 + // PHP 5.5.0 - PHP 5.5.6 + if ( + (PHP_VERSION_ID < 50400 && PHP_VERSION_ID >= 50328) + || (PHP_VERSION_ID < 50500 && PHP_VERSION_ID >= 50423) + || PHP_VERSION_ID >= 50507 + ) { + // This version of PHP has the fix for CVE-2013-6420 applied. + return self::$useOpensslParse = true; + } + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + // Windows is probably insecure in this case. + return self::$useOpensslParse = false; + } + + $compareDistroVersionPrefix = function ($prefix, $fixedVersion) { + $regex = '{^'.preg_quote($prefix).'([0-9]+)$}'; + + if (preg_match($regex, PHP_VERSION, $m)) { + return ((int) $m[1]) >= $fixedVersion; + } + + return false; + }; + + // Hard coded list of PHP distributions with the fix backported. + if ( + $compareDistroVersionPrefix('5.3.3-7+squeeze', 18) // Debian 6 (Squeeze) + || $compareDistroVersionPrefix('5.4.4-14+deb7u', 7) // Debian 7 (Wheezy) + || $compareDistroVersionPrefix('5.3.10-1ubuntu3.', 9) // Ubuntu 12.04 (Precise) + ) { + return self::$useOpensslParse = true; + } + + // Symfony Process component is missing so we assume it is unsafe at this point + if (!class_exists('Symfony\Component\Process\PhpProcess')) { + return self::$useOpensslParse = false; + } + + // This is where things get crazy, because distros backport security + // fixes the chances are on NIX systems the fix has been applied but + // it's not possible to verify that from the PHP version. + // + // To verify exec a new PHP process and run the issue testcase with + // known safe input that replicates the bug. + + // Based on testcase in https://github.com/php/php-src/commit/c1224573c773b6845e83505f717fbf820fc18415 + // changes in https://github.com/php/php-src/commit/76a7fd893b7d6101300cc656058704a73254d593 + $cert = 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVwRENDQTR5Z0F3SUJBZ0lKQUp6dThyNnU2ZUJjTUEwR0NTcUdTSWIzRFFFQkJRVUFNSUhETVFzd0NRWUQKVlFRR0V3SkVSVEVjTUJvR0ExVUVDQXdUVG05eVpISm9aV2x1TFZkbGMzUm1ZV3hsYmpFUU1BNEdBMVVFQnd3SApTOE9Ed3Jac2JqRVVNQklHQTFVRUNnd0xVMlZyZEdsdmJrVnBibk14SHpBZEJnTlZCQXNNRmsxaGJHbGphVzkxCmN5QkRaWEowSUZObFkzUnBiMjR4SVRBZkJnTlZCQU1NR0cxaGJHbGphVzkxY3k1elpXdDBhVzl1WldsdWN5NWsKWlRFcU1DZ0dDU3FHU0liM0RRRUpBUlliYzNSbFptRnVMbVZ6YzJWeVFITmxhM1JwYjI1bGFXNXpMbVJsTUhVWQpaREU1TnpBd01UQXhNREF3TURBd1dnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBCkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEKQUFBQUFBQVhEVEUwTVRFeU9ERXhNemt6TlZvd2djTXhDekFKQmdOVkJBWVRBa1JGTVJ3d0dnWURWUVFJREJOTwpiM0prY21obGFXNHRWMlZ6ZEdaaGJHVnVNUkF3RGdZRFZRUUhEQWRMdzRQQ3RteHVNUlF3RWdZRFZRUUtEQXRUClpXdDBhVzl1UldsdWN6RWZNQjBHQTFVRUN3d1dUV0ZzYVdOcGIzVnpJRU5sY25RZ1UyVmpkR2x2YmpFaE1COEcKQTFVRUF3d1liV0ZzYVdOcGIzVnpMbk5sYTNScGIyNWxhVzV6TG1SbE1Tb3dLQVlKS29aSWh2Y05BUWtCRmh0egpkR1ZtWVc0dVpYTnpaWEpBYzJWcmRHbHZibVZwYm5NdVpHVXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRRERBZjNobDdKWTBYY0ZuaXlFSnBTU0RxbjBPcUJyNlFQNjV1c0pQUnQvOFBhRG9xQnUKd0VZVC9OYSs2ZnNnUGpDMHVLOURaZ1dnMnRIV1dvYW5TYmxBTW96NVBINlorUzRTSFJaN2UyZERJalBqZGhqaAowbUxnMlVNTzV5cDBWNzk3R2dzOWxOdDZKUmZIODFNTjJvYlhXczROdHp0TE11RDZlZ3FwcjhkRGJyMzRhT3M4CnBrZHVpNVVhd1Raa3N5NXBMUEhxNWNNaEZHbTA2djY1Q0xvMFYyUGQ5K0tBb2tQclBjTjVLTEtlYno3bUxwazYKU01lRVhPS1A0aWRFcXh5UTdPN2ZCdUhNZWRzUWh1K3ByWTNzaTNCVXlLZlF0UDVDWm5YMmJwMHdLSHhYMTJEWAoxbmZGSXQ5RGJHdkhUY3lPdU4rblpMUEJtM3ZXeG50eUlJdlZBZ01CQUFHalFqQkFNQWtHQTFVZEV3UUNNQUF3CkVRWUpZSVpJQVliNFFnRUJCQVFEQWdlQU1Bc0dBMVVkRHdRRUF3SUZvREFUQmdOVkhTVUVEREFLQmdnckJnRUYKQlFjREFqQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFHMGZaWVlDVGJkajFYWWMrMVNub2FQUit2SThDOENhRAo4KzBVWWhkbnlVNGdnYTBCQWNEclk5ZTk0ZUVBdTZacXljRjZGakxxWFhkQWJvcHBXb2NyNlQ2R0QxeDMzQ2tsClZBcnpHL0t4UW9oR0QySmVxa2hJTWxEb214SE83a2EzOStPYThpMnZXTFZ5alU4QVp2V01BcnVIYTRFRU55RzcKbFcyQWFnYUZLRkNyOVRuWFRmcmR4R1ZFYnY3S1ZRNmJkaGc1cDVTanBXSDErTXEwM3VSM1pYUEJZZHlWODMxOQpvMGxWajFLRkkyRENML2xpV2lzSlJvb2YrMWNSMzVDdGQwd1lCY3BCNlRac2xNY09QbDc2ZHdLd0pnZUpvMlFnClpzZm1jMnZDMS9xT2xOdU5xLzBUenprVkd2OEVUVDNDZ2FVK1VYZTRYT1Z2a2NjZWJKbjJkZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K'; + $script = <<<'EOT' + +error_reporting(-1); +$info = openssl_x509_parse(base64_decode('%s')); +var_dump(PHP_VERSION, $info['issuer']['emailAddress'], $info['validFrom_time_t']); + +EOT; + $script = '<'."?php\n".sprintf($script, $cert); + + try { + $process = new PhpProcess($script); + $process->mustRun(); + } catch (\Exception $e) { + // In the case of any exceptions just accept it is not possible to + // determine the safety of openssl_x509_parse and bail out. + return self::$useOpensslParse = false; + } + + $output = preg_split('{\r?\n}', trim($process->getOutput())); + $errorOutput = trim($process->getErrorOutput()); + + if ( + is_array($output) + && count($output) === 3 + && $output[0] === sprintf('string(%d) "%s"', strlen(PHP_VERSION), PHP_VERSION) + && $output[1] === 'string(27) "stefan.esser@sektioneins.de"' + && $output[2] === 'int(-1)' + && preg_match('{openssl_x509_parse\(\): illegal (?:ASN1 data type for|length in) timestamp in - on line \d+}', $errorOutput) + ) { + // This PHP has the fix backported probably by a distro security team. + return self::$useOpensslParse = true; + } + + return self::$useOpensslParse = false; + } + + /** + * Resets the static caches + * @return void + */ + public static function reset() + { + self::$caFileValidity = array(); + self::$caPath = null; + self::$useOpensslParse = null; + } + + /** + * @param string $name + * @return string|false + */ + private static function getEnvVariable($name) + { + if (isset($_SERVER[$name])) { + return (string) $_SERVER[$name]; + } + + if (PHP_SAPI === 'cli' && ($value = getenv($name)) !== false && $value !== null) { + return (string) $value; + } + + return false; + } + + /** + * @param string|false $certFile + * @param LoggerInterface|null $logger + * @return bool + */ + private static function caFileUsable($certFile, LoggerInterface $logger = null) + { + return $certFile + && static::isFile($certFile, $logger) + && static::isReadable($certFile, $logger) + && static::validateCaFile($certFile, $logger); + } + + /** + * @param string|false $certDir + * @param LoggerInterface|null $logger + * @return bool + */ + private static function caDirUsable($certDir, LoggerInterface $logger = null) + { + return $certDir + && static::isDir($certDir, $logger) + && static::isReadable($certDir, $logger) + && static::glob($certDir . '/*', $logger); + } + + /** + * @param string $certFile + * @param LoggerInterface|null $logger + * @return bool + */ + private static function isFile($certFile, LoggerInterface $logger = null) + { + $isFile = @is_file($certFile); + if (!$isFile && $logger) { + $logger->debug(sprintf('Checked CA file %s does not exist or it is not a file.', $certFile)); + } + + return $isFile; + } + + /** + * @param string $certDir + * @param LoggerInterface|null $logger + * @return bool + */ + private static function isDir($certDir, LoggerInterface $logger = null) + { + $isDir = @is_dir($certDir); + if (!$isDir && $logger) { + $logger->debug(sprintf('Checked directory %s does not exist or it is not a directory.', $certDir)); + } + + return $isDir; + } + + /** + * @param string $certFileOrDir + * @param LoggerInterface|null $logger + * @return bool + */ + private static function isReadable($certFileOrDir, LoggerInterface $logger = null) + { + $isReadable = @is_readable($certFileOrDir); + if (!$isReadable && $logger) { + $logger->debug(sprintf('Checked file or directory %s is not readable.', $certFileOrDir)); + } + + return $isReadable; + } + + /** + * @param string $pattern + * @param LoggerInterface|null $logger + * @return bool + */ + private static function glob($pattern, LoggerInterface $logger = null) + { + $certs = glob($pattern); + if ($certs === false) { + if ($logger) { + $logger->debug(sprintf("An error occurred while trying to find certificates for pattern: %s", $pattern)); + } + return false; + } + + if (count($certs) === 0) { + if ($logger) { + $logger->debug(sprintf("No CA files found for pattern: %s", $pattern)); + } + return false; + } + + return true; + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100755 index 0000000..6317670 --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,8696 @@ +{ + "packages": [ + { + "name": "blessing/filter", + "version": "v1.2.0", + "version_normalized": "1.2.0.0", + "source": { + "type": "git", + "url": "https://github.com/bs-community/filter.git", + "reference": "b2e48bcb852bdc92cee39f2188e32550f95be8d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bs-community/filter/zipball/b2e48bcb852bdc92cee39f2188e32550f95be8d2", + "reference": "b2e48bcb852bdc92cee39f2188e32550f95be8d2", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^6 || ^7 || ^8", + "illuminate/support": "^6 || ^7 || ^8" + }, + "require-dev": { + "illuminate/container": "^6 || ^7 || ^8", + "phpunit/phpunit": "~9.0" + }, + "time": "2020-10-14T02:29:54+00:00", + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Blessing\\FilterServiceProvider" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Blessing\\": "src/Blessing" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Pig Fang", + "email": "g-plane@hotmail.com" + } + ], + "description": "Filters API for designing plugin system.", + "keywords": [ + "filters", + "laravel", + "wordpress" + ], + "support": { + "issues": "https://github.com/bs-community/filter/issues", + "source": "https://github.com/bs-community/filter/tree/v1.2.0" + }, + "install-path": "../blessing/filter" + }, + { + "name": "blessing/rejection", + "version": "v1.2.0", + "version_normalized": "1.2.0.0", + "source": { + "type": "git", + "url": "https://github.com/bs-community/rejection.git", + "reference": "2de752ba7793060ae7bc6607d885a8be2be2e08c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bs-community/rejection/zipball/2de752ba7793060ae7bc6607d885a8be2be2e08c", + "reference": "2de752ba7793060ae7bc6607d885a8be2be2e08c", + "shasum": "" + }, + "require": { + "illuminate/support": "^6 || ^7 || ^8" + }, + "require-dev": { + "phpunit/phpunit": "~9.0" + }, + "time": "2020-10-14T02:32:06+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Blessing\\": "src/Blessing" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Pig Fang", + "email": "g-plane@hotmail.com" + } + ], + "description": "Rejection is an object that indicates you are rejecting.", + "support": { + "issues": "https://github.com/bs-community/rejection/issues", + "source": "https://github.com/bs-community/rejection/tree/v1.2.0" + }, + "install-path": "../blessing/rejection" + }, + { + "name": "blessing/texture-renderer", + "version": "0.2.1", + "version_normalized": "0.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/bs-community/texture-renderer.git", + "reference": "78480e5df9c7ae7d56c5966994b06e49265fbab4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bs-community/texture-renderer/zipball/78480e5df9c7ae7d56c5966994b06e49265fbab4", + "reference": "78480e5df9c7ae7d56c5966994b06e49265fbab4", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "intervention/image": "^2.5" + }, + "time": "2021-08-15T06:57:22+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Blessing\\": "src/Blessing" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Pig Fang", + "email": "g-plane@hotmail.com" + } + ], + "description": "Minecraft texture renderer.", + "support": { + "issues": "https://github.com/bs-community/texture-renderer/issues", + "source": "https://github.com/bs-community/texture-renderer/tree/0.2.1" + }, + "install-path": "../blessing/texture-renderer" + }, + { + "name": "brick/math", + "version": "0.9.3", + "version_normalized": "0.9.3.0", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "vimeo/psalm": "4.9.2" + }, + "time": "2021-08-15T20:50:18+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Arbitrary-precision arithmetic library", + "keywords": [ + "Arbitrary-precision", + "BigInteger", + "BigRational", + "arithmetic", + "bigdecimal", + "bignum", + "brick", + "math" + ], + "support": { + "issues": "https://github.com/brick/math/issues", + "source": "https://github.com/brick/math/tree/0.9.3" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/brick/math", + "type": "tidelift" + } + ], + "install-path": "../brick/math" + }, + { + "name": "composer/ca-bundle", + "version": "1.3.1", + "version_normalized": "1.3.1.0", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "4c679186f2aca4ab6a0f1b0b9cf9252decb44d0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/4c679186f2aca4ab6a0f1b0b9cf9252decb44d0b", + "reference": "4c679186f2aca4ab6a0f1b0b9cf9252decb44d0b", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.55", + "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", + "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0" + }, + "time": "2021-10-28T20:44:15+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.3.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "install-path": "./ca-bundle" + }, + { + "name": "composer/semver", + "version": "3.2.6", + "version_normalized": "3.2.6.0", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "83e511e247de329283478496f7a1e114c9517506" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/83e511e247de329283478496f7a1e114c9517506", + "reference": "83e511e247de329283478496f7a1e114c9517506", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.54", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "time": "2021-10-25T11:34:17+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.2.6" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "install-path": "./semver" + }, + { + "name": "defuse/php-encryption", + "version": "v2.3.1", + "version_normalized": "2.3.1.0", + "source": { + "type": "git", + "url": "https://github.com/defuse/php-encryption.git", + "reference": "77880488b9954b7884c25555c2a0ea9e7053f9d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/defuse/php-encryption/zipball/77880488b9954b7884c25555c2a0ea9e7053f9d2", + "reference": "77880488b9954b7884c25555c2a0ea9e7053f9d2", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "paragonie/random_compat": ">= 2", + "php": ">=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5|^6|^7|^8|^9" + }, + "time": "2021-04-09T23:57:26+00:00", + "bin": [ + "bin/generate-defuse-key" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Defuse\\Crypto\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Hornby", + "email": "taylor@defuse.ca", + "homepage": "https://defuse.ca/" + }, + { + "name": "Scott Arciszewski", + "email": "info@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "Secure PHP Encryption Library", + "keywords": [ + "aes", + "authenticated encryption", + "cipher", + "crypto", + "cryptography", + "encrypt", + "encryption", + "openssl", + "security", + "symmetric key cryptography" + ], + "support": { + "issues": "https://github.com/defuse/php-encryption/issues", + "source": "https://github.com/defuse/php-encryption/tree/v2.3.1" + }, + "install-path": "../defuse/php-encryption" + }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.1", + "version_normalized": "3.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "0992cc19268b259a39e86f296da5f0677841f42c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/0992cc19268b259a39e86f296da5f0677841f42c", + "reference": "0992cc19268b259a39e86f296da5f0677841f42c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^3.14" + }, + "time": "2021-08-13T13:06:58+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.1" + }, + "install-path": "../dflydev/dot-access-data" + }, + { + "name": "doctrine/cache", + "version": "2.1.1", + "version_normalized": "2.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/331b4d5dbaeab3827976273e9356b3b453c300ce", + "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce", + "shasum": "" + }, + "require": { + "php": "~7.1 || ^8.0" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "alcaeus/mongo-php-adapter": "^1.1", + "cache/integration-tests": "dev-master", + "doctrine/coding-standard": "^8.0", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "predis/predis": "~1.0", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "symfony/cache": "^4.4 || ^5.2 || ^6.0@dev", + "symfony/var-exporter": "^4.4 || ^5.2 || ^6.0@dev" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" + }, + "time": "2021-07-17T14:49:29+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "homepage": "https://www.doctrine-project.org/projects/cache.html", + "keywords": [ + "abstraction", + "apcu", + "cache", + "caching", + "couchdb", + "memcached", + "php", + "redis", + "xcache" + ], + "support": { + "issues": "https://github.com/doctrine/cache/issues", + "source": "https://github.com/doctrine/cache/tree/2.1.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", + "type": "tidelift" + } + ], + "install-path": "../doctrine/cache" + }, + { + "name": "doctrine/dbal", + "version": "2.13.6", + "version_normalized": "2.13.6.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "67ef6d0327ccbab1202b39e0222977a47ed3ef2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/67ef6d0327ccbab1202b39e0222977a47ed3ef2f", + "reference": "67ef6d0327ccbab1202b39e0222977a47ed3ef2f", + "shasum": "" + }, + "require": { + "doctrine/cache": "^1.0|^2.0", + "doctrine/deprecations": "^0.5.3", + "doctrine/event-manager": "^1.0", + "ext-pdo": "*", + "php": "^7.1 || ^8" + }, + "require-dev": { + "doctrine/coding-standard": "9.0.0", + "jetbrains/phpstorm-stubs": "2021.1", + "phpstan/phpstan": "1.2.0", + "phpunit/phpunit": "^7.5.20|^8.5|9.5.10", + "psalm/plugin-phpunit": "0.16.1", + "squizlabs/php_codesniffer": "3.6.1", + "symfony/cache": "^4.4", + "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", + "vimeo/psalm": "4.13.0" + }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "time": "2021-11-26T20:11:05+00:00", + "bin": [ + "bin/doctrine-dbal" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Doctrine\\DBAL\\": "lib/Doctrine/DBAL" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "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", + "db2", + "dbal", + "mariadb", + "mssql", + "mysql", + "oci8", + "oracle", + "pdo", + "pgsql", + "postgresql", + "queryobject", + "sasql", + "sql", + "sqlanywhere", + "sqlite", + "sqlserver", + "sqlsrv" + ], + "support": { + "issues": "https://github.com/doctrine/dbal/issues", + "source": "https://github.com/doctrine/dbal/tree/2.13.6" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal", + "type": "tidelift" + } + ], + "install-path": "../doctrine/dbal" + }, + { + "name": "doctrine/deprecations", + "version": "v0.5.3", + "version_normalized": "0.5.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "9504165960a1f83cc1480e2be1dd0a0478561314" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/9504165960a1f83cc1480e2be1dd0a0478561314", + "reference": "9504165960a1f83cc1480e2be1dd0a0478561314", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0|^7.0|^8.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "time": "2021-03-21T12:59:47+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v0.5.3" + }, + "install-path": "../doctrine/deprecations" + }, + { + "name": "doctrine/event-manager", + "version": "1.1.1", + "version_normalized": "1.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/event-manager.git", + "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/41370af6a30faa9dc0368c4a6814d596e81aba7f", + "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/common": "<2.9@dev" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpunit/phpunit": "^7.0" + }, + "time": "2020-05-29T18:28:51+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", + "homepage": "https://www.doctrine-project.org/projects/event-manager.html", + "keywords": [ + "event", + "event dispatcher", + "event manager", + "event system", + "events" + ], + "support": { + "issues": "https://github.com/doctrine/event-manager/issues", + "source": "https://github.com/doctrine/event-manager/tree/1.1.x" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager", + "type": "tidelift" + } + ], + "install-path": "../doctrine/event-manager" + }, + { + "name": "doctrine/inflector", + "version": "1.4.4", + "version_normalized": "1.4.4.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9", + "reference": "4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^8.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + }, + "time": "2021-04-16T17:34:40+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector", + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/1.4.4" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "install-path": "../doctrine/inflector" + }, + { + "name": "doctrine/lexer", + "version": "1.2.1", + "version_normalized": "1.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11.8", + "phpunit/phpunit": "^8.2" + }, + "time": "2020-05-25T17:44:05+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "install-path": "../doctrine/lexer" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v3.1.0", + "version_normalized": "3.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c", + "reference": "7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0", + "webmozart/assert": "^1.7.0" + }, + "replace": { + "mtdowling/cron-expression": "^1.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-webmozart-assert": "^0.12.7", + "phpunit/phpunit": "^7.0|^8.0|^9.0" + }, + "time": "2020-11-24T19:55:57+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.1.0" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "install-path": "../dragonmantank/cron-expression" + }, + { + "name": "egulias/email-validator", + "version": "2.1.25", + "version_normalized": "2.1.25.0", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "0dbf5d78455d4d6a41d186da50adc1122ec066f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/0dbf5d78455d4d6a41d186da50adc1122ec066f4", + "reference": "0dbf5d78455d4d6a41d186da50adc1122ec066f4", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1.0.1", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.10" + }, + "require-dev": { + "dominicsayers/isemail": "^3.0.7", + "phpunit/phpunit": "^4.8.36|^7.5.15", + "satooshi/php-coveralls": "^1.0.1" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "time": "2020-12-29T14:50:06+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/2.1.25" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "install-path": "../egulias/email-validator" + }, + { + "name": "facade/flare-client-php", + "version": "1.9.1", + "version_normalized": "1.9.1.0", + "source": { + "type": "git", + "url": "https://github.com/facade/flare-client-php.git", + "reference": "b2adf1512755637d0cef4f7d1b54301325ac78ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/b2adf1512755637d0cef4f7d1b54301325ac78ed", + "reference": "b2adf1512755637d0cef4f7d1b54301325ac78ed", + "shasum": "" + }, + "require": { + "facade/ignition-contracts": "~1.0", + "illuminate/pipeline": "^5.5|^6.0|^7.0|^8.0", + "php": "^7.1|^8.0", + "symfony/http-foundation": "^3.3|^4.1|^5.0", + "symfony/mime": "^3.4|^4.0|^5.1", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "phpunit/phpunit": "^7.5.16", + "spatie/phpunit-snapshot-assertions": "^2.0" + }, + "time": "2021-09-13T12:16:46+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Facade\\FlareClient\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Send PHP errors to Flare", + "homepage": "https://github.com/facade/flare-client-php", + "keywords": [ + "exception", + "facade", + "flare", + "reporting" + ], + "support": { + "issues": "https://github.com/facade/flare-client-php/issues", + "source": "https://github.com/facade/flare-client-php/tree/1.9.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "install-path": "../facade/flare-client-php" + }, + { + "name": "facade/ignition", + "version": "2.17.2", + "version_normalized": "2.17.2.0", + "source": { + "type": "git", + "url": "https://github.com/facade/ignition.git", + "reference": "af3cd70d58ca3ef5189ff0e59efbe5a5c043e2d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/ignition/zipball/af3cd70d58ca3ef5189ff0e59efbe5a5c043e2d2", + "reference": "af3cd70d58ca3ef5189ff0e59efbe5a5c043e2d2", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "facade/flare-client-php": "^1.9.1", + "facade/ignition-contracts": "^1.0.2", + "illuminate/support": "^7.0|^8.0", + "monolog/monolog": "^2.0", + "php": "^7.2.5|^8.0", + "symfony/console": "^5.0", + "symfony/var-dumper": "^5.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "livewire/livewire": "^2.4", + "mockery/mockery": "^1.3", + "orchestra/testbench": "^5.0|^6.0", + "psalm/plugin-laravel": "^1.2" + }, + "suggest": { + "laravel/telescope": "^3.1" + }, + "time": "2021-11-29T14:04:22+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + }, + "laravel": { + "providers": [ + "Facade\\Ignition\\IgnitionServiceProvider" + ], + "aliases": { + "Flare": "Facade\\Ignition\\Facades\\Flare" + } + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Facade\\Ignition\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A beautiful error page for Laravel applications.", + "homepage": "https://github.com/facade/ignition", + "keywords": [ + "error", + "flare", + "laravel", + "page" + ], + "support": { + "docs": "https://flareapp.io/docs/ignition-for-laravel/introduction", + "forum": "https://twitter.com/flareappio", + "issues": "https://github.com/facade/ignition/issues", + "source": "https://github.com/facade/ignition" + }, + "install-path": "../facade/ignition" + }, + { + "name": "facade/ignition-contracts", + "version": "1.0.2", + "version_normalized": "1.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/facade/ignition-contracts.git", + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267", + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v2.15.8", + "phpunit/phpunit": "^9.3.11", + "vimeo/psalm": "^3.17.1" + }, + "time": "2020-10-16T08:27:54+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Facade\\IgnitionContracts\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://flareapp.io", + "role": "Developer" + } + ], + "description": "Solution contracts for Ignition", + "homepage": "https://github.com/facade/ignition-contracts", + "keywords": [ + "contracts", + "flare", + "ignition" + ], + "support": { + "issues": "https://github.com/facade/ignition-contracts/issues", + "source": "https://github.com/facade/ignition-contracts/tree/1.0.2" + }, + "install-path": "../facade/ignition-contracts" + }, + { + "name": "filp/whoops", + "version": "2.14.4", + "version_normalized": "2.14.4.0", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "f056f1fe935d9ed86e698905a957334029899895" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/f056f1fe935d9ed86e698905a957334029899895", + "reference": "f056f1fe935d9ed86e698905a957334029899895", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^0.9 || ^1.0", + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "time": "2021-10-03T12:00:00+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.14.4" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "install-path": "../filp/whoops" + }, + { + "name": "firebase/php-jwt", + "version": "v5.5.1", + "version_normalized": "5.5.1.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "83b609028194aa042ea33b5af2d41a7427de80e6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/83b609028194aa042ea33b5af2d41a7427de80e6", + "reference": "83b609028194aa042ea33b5af2d41a7427de80e6", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": ">=4.8 <=9" + }, + "suggest": { + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "time": "2021-11-08T20:18:51+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v5.5.1" + }, + "install-path": "../firebase/php-jwt" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.0.4", + "version_normalized": "1.0.4.0", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "0690bde05318336c7221785f2a932467f98b64ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/0690bde05318336c7221785f2a932467f98b64ca", + "reference": "0690bde05318336c7221785f2a932467f98b64ca", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "phpoption/phpoption": "^1.8" + }, + "require-dev": { + "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" + }, + "time": "2021-11-21T21:41:47+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "install-path": "../graham-campbell/result-type" + }, + { + "name": "gregwar/captcha", + "version": "v1.1.9", + "version_normalized": "1.1.9.0", + "source": { + "type": "git", + "url": "https://github.com/Gregwar/Captcha.git", + "reference": "4bb668e6b40e3205a020ca5ee4ca8cff8b8780c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Gregwar/Captcha/zipball/4bb668e6b40e3205a020ca5ee4ca8cff8b8780c5", + "reference": "4bb668e6b40e3205a020ca5ee4ca8cff8b8780c5", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "ext-mbstring": "*", + "php": ">=5.3.0", + "symfony/finder": "*" + }, + "require-dev": { + "phpunit/phpunit": "^6.4" + }, + "time": "2020-03-24T14:39:05+00:00", + "type": "captcha", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Gregwar\\": "src/Gregwar" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Passault", + "email": "g.passault@gmail.com", + "homepage": "http://www.gregwar.com/" + }, + { + "name": "Jeremy Livingston", + "email": "jeremy.j.livingston@gmail.com" + } + ], + "description": "Captcha generator", + "homepage": "https://github.com/Gregwar/Captcha", + "keywords": [ + "bot", + "captcha", + "spam" + ], + "support": { + "issues": "https://github.com/Gregwar/Captcha/issues", + "source": "https://github.com/Gregwar/Captcha/tree/master" + }, + "install-path": "../gregwar/captcha" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.4.1", + "version_normalized": "7.4.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ee0a041b1760e6a53d2a39c8c34115adc2af2c79", + "reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5", + "guzzlehttp/psr7": "^1.8.3 || ^2.1", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "ext-curl": "*", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.5 || ^9.3.5", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "time": "2021-12-06T18:43:05+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.4-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.4.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/guzzle" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.1", + "version_normalized": "1.5.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "time": "2021-10-22T20:56:57+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/promises" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.1.0", + "version_normalized": "2.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/089edd38f5b8abba6cb01567c2a8aaa47cec4c72", + "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "time": "2021-10-06T17:43:30+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.1.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/psr7" + }, + { + "name": "hoa/compiler", + "version": "3.17.08.08", + "version_normalized": "3.17.08.08", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Compiler.git", + "reference": "aa09caf0bf28adae6654ca6ee415ee2f522672de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Compiler/zipball/aa09caf0bf28adae6654ca6ee415ee2f522672de", + "reference": "aa09caf0bf28adae6654ca6ee415ee2f522672de", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0", + "hoa/file": "~1.0", + "hoa/iterator": "~2.0", + "hoa/math": "~1.0", + "hoa/protocol": "~1.0", + "hoa/regex": "~1.0", + "hoa/visitor": "~2.0" + }, + "require-dev": { + "hoa/json": "~2.0", + "hoa/test": "~2.0" + }, + "time": "2017-08-08T07:44:07+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Compiler\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Compiler library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "algebraic", + "ast", + "compiler", + "context-free", + "coverage", + "exhaustive", + "grammar", + "isotropic", + "language", + "lexer", + "library", + "ll1", + "llk", + "parser", + "pp", + "random", + "regular", + "rule", + "sampler", + "syntax", + "token", + "trace", + "uniform" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Compiler", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Compiler/issues", + "source": "https://central.hoa-project.net/Resource/Library/Compiler" + }, + "abandoned": true, + "install-path": "../hoa/compiler" + }, + { + "name": "hoa/consistency", + "version": "1.17.05.02", + "version_normalized": "1.17.05.02", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Consistency.git", + "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Consistency/zipball/fd7d0adc82410507f332516faf655b6ed22e4c2f", + "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f", + "shasum": "" + }, + "require": { + "hoa/exception": "~1.0", + "php": ">=5.5.0" + }, + "require-dev": { + "hoa/stream": "~1.0", + "hoa/test": "~2.0" + }, + "time": "2017-05-02T12:18:12+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Consistency\\": "." + }, + "files": [ + "Prelude.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Consistency library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "autoloader", + "callable", + "consistency", + "entity", + "flex", + "keyword", + "library" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Consistency", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Consistency/issues", + "source": "https://central.hoa-project.net/Resource/Library/Consistency" + }, + "abandoned": true, + "install-path": "../hoa/consistency" + }, + { + "name": "hoa/event", + "version": "1.17.01.13", + "version_normalized": "1.17.01.13", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Event.git", + "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Event/zipball/6c0060dced212ffa3af0e34bb46624f990b29c54", + "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "time": "2017-01-13T15:30:50+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Event\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Event library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "event", + "library", + "listener", + "observer" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Event", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Event/issues", + "source": "https://central.hoa-project.net/Resource/Library/Event" + }, + "abandoned": true, + "install-path": "../hoa/event" + }, + { + "name": "hoa/exception", + "version": "1.17.01.16", + "version_normalized": "1.17.01.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Exception.git", + "reference": "091727d46420a3d7468ef0595651488bfc3a458f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Exception/zipball/091727d46420a3d7468ef0595651488bfc3a458f", + "reference": "091727d46420a3d7468ef0595651488bfc3a458f", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "time": "2017-01-16T07:53:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Exception\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Exception library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "exception", + "library" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Exception", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Exception/issues", + "source": "https://central.hoa-project.net/Resource/Library/Exception" + }, + "abandoned": true, + "install-path": "../hoa/exception" + }, + { + "name": "hoa/file", + "version": "1.17.07.11", + "version_normalized": "1.17.07.11", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/File.git", + "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/File/zipball/35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", + "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0", + "hoa/exception": "~1.0", + "hoa/iterator": "~2.0", + "hoa/stream": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "time": "2017-07-11T07:42:15+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\File\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\File library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "Socket", + "directory", + "file", + "finder", + "library", + "link", + "temporary" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/File", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/File/issues", + "source": "https://central.hoa-project.net/Resource/Library/File" + }, + "abandoned": true, + "install-path": "../hoa/file" + }, + { + "name": "hoa/iterator", + "version": "2.17.01.10", + "version_normalized": "2.17.01.10", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Iterator.git", + "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Iterator/zipball/d1120ba09cb4ccd049c86d10058ab94af245f0cc", + "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "time": "2017-01-10T10:34:47+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Iterator\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Iterator library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "iterator", + "library" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Iterator", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Iterator/issues", + "source": "https://central.hoa-project.net/Resource/Library/Iterator" + }, + "abandoned": true, + "install-path": "../hoa/iterator" + }, + { + "name": "hoa/math", + "version": "1.17.05.16", + "version_normalized": "1.17.05.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Math.git", + "reference": "7150785d30f5d565704912116a462e9f5bc83a0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Math/zipball/7150785d30f5d565704912116a462e9f5bc83a0c", + "reference": "7150785d30f5d565704912116a462e9f5bc83a0c", + "shasum": "" + }, + "require": { + "hoa/compiler": "~3.0", + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0", + "hoa/iterator": "~2.0", + "hoa/protocol": "~1.0", + "hoa/zformat": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "time": "2017-05-16T08:02:17+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Math\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Math library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "arrangement", + "combination", + "combinatorics", + "counting", + "library", + "math", + "permutation", + "sampler", + "set" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Math", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Math/issues", + "source": "https://central.hoa-project.net/Resource/Library/Math" + }, + "abandoned": true, + "install-path": "../hoa/math" + }, + { + "name": "hoa/regex", + "version": "1.17.01.13", + "version_normalized": "1.17.01.13", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Regex.git", + "reference": "7e263a61b6fb45c1d03d8e5ef77668518abd5bec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Regex/zipball/7e263a61b6fb45c1d03d8e5ef77668518abd5bec", + "reference": "7e263a61b6fb45c1d03d8e5ef77668518abd5bec", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0", + "hoa/math": "~1.0", + "hoa/protocol": "~1.0", + "hoa/ustring": "~4.0", + "hoa/visitor": "~2.0" + }, + "time": "2017-01-13T16:10:24+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Regex\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Regex library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "compiler", + "library", + "regex" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Regex", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Regex/issues", + "source": "https://central.hoa-project.net/Resource/Library/Regex" + }, + "abandoned": true, + "install-path": "../hoa/regex" + }, + { + "name": "hoa/stream", + "version": "1.17.02.21", + "version_normalized": "1.17.02.21", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Stream.git", + "reference": "3293cfffca2de10525df51436adf88a559151d82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Stream/zipball/3293cfffca2de10525df51436adf88a559151d82", + "reference": "3293cfffca2de10525df51436adf88a559151d82", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0", + "hoa/exception": "~1.0", + "hoa/protocol": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "time": "2017-02-21T16:01:06+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Stream\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Stream library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "Context", + "bucket", + "composite", + "filter", + "in", + "library", + "out", + "protocol", + "stream", + "wrapper" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Stream", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Stream/issues", + "source": "https://central.hoa-project.net/Resource/Library/Stream" + }, + "abandoned": true, + "install-path": "../hoa/stream" + }, + { + "name": "hoa/ustring", + "version": "4.17.01.16", + "version_normalized": "4.17.01.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Ustring.git", + "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Ustring/zipball/e6326e2739178799b1fe3fdd92029f9517fa17a0", + "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "suggest": { + "ext-iconv": "ext/iconv must be present (or a third implementation) to use Hoa\\Ustring::transcode().", + "ext-intl": "To get a better Hoa\\Ustring::toAscii() and Hoa\\Ustring::compareTo()." + }, + "time": "2017-01-16T07:08:25+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Ustring\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Ustring library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "library", + "search", + "string", + "unicode" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Ustring", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Ustring/issues", + "source": "https://central.hoa-project.net/Resource/Library/Ustring" + }, + "abandoned": true, + "install-path": "../hoa/ustring" + }, + { + "name": "hoa/visitor", + "version": "2.17.01.16", + "version_normalized": "2.17.01.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Visitor.git", + "reference": "c18fe1cbac98ae449e0d56e87469103ba08f224a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Visitor/zipball/c18fe1cbac98ae449e0d56e87469103ba08f224a", + "reference": "c18fe1cbac98ae449e0d56e87469103ba08f224a", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "time": "2017-01-16T07:02:03+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Visitor\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Visitor library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "library", + "structure", + "visit", + "visitor" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Visitor", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Visitor/issues", + "source": "https://central.hoa-project.net/Resource/Library/Visitor" + }, + "abandoned": true, + "install-path": "../hoa/visitor" + }, + { + "name": "hoa/zformat", + "version": "1.17.01.10", + "version_normalized": "1.17.01.10", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Zformat.git", + "reference": "522c381a2a075d4b9dbb42eb4592dd09520e4ac2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Zformat/zipball/522c381a2a075d4b9dbb42eb4592dd09520e4ac2", + "reference": "522c381a2a075d4b9dbb42eb4592dd09520e4ac2", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "time": "2017-01-10T10:39:54+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Zformat\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Zformat library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "library", + "parameter", + "zformat" + ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Zformat", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Zformat/issues", + "source": "https://central.hoa-project.net/Resource/Library/Zformat" + }, + "abandoned": true, + "install-path": "../hoa/zformat" + }, + { + "name": "intervention/image", + "version": "2.7.0", + "version_normalized": "2.7.0.0", + "source": { + "type": "git", + "url": "https://github.com/Intervention/image.git", + "reference": "9a8cc99d30415ec0b3f7649e1647d03a55698545" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Intervention/image/zipball/9a8cc99d30415ec0b3f7649e1647d03a55698545", + "reference": "9a8cc99d30415ec0b3f7649e1647d03a55698545", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "guzzlehttp/psr7": "~1.1 || ^2.0", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.2", + "phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15" + }, + "suggest": { + "ext-gd": "to use GD library based image processing.", + "ext-imagick": "to use Imagick based image processing.", + "intervention/imagecache": "Caching extension for the Intervention Image library" + }, + "time": "2021-10-03T14:17:12+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + }, + "laravel": { + "providers": [ + "Intervention\\Image\\ImageServiceProvider" + ], + "aliases": { + "Image": "Intervention\\Image\\Facades\\Image" + } + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Intervention\\Image\\": "src/Intervention/Image" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oliver Vogel", + "email": "oliver@olivervogel.com", + "homepage": "http://olivervogel.com/" + } + ], + "description": "Image handling and manipulation library with support for Laravel integration", + "homepage": "http://image.intervention.io/", + "keywords": [ + "gd", + "image", + "imagick", + "laravel", + "thumbnail", + "watermark" + ], + "support": { + "issues": "https://github.com/Intervention/image/issues", + "source": "https://github.com/Intervention/image/tree/2.7.0" + }, + "funding": [ + { + "url": "https://www.paypal.me/interventionphp", + "type": "custom" + }, + { + "url": "https://github.com/Intervention", + "type": "github" + } + ], + "install-path": "../intervention/image" + }, + { + "name": "laravel/framework", + "version": "v8.75.0", + "version_normalized": "8.75.0.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "0bb91d3176357da232da69762a64b0e0a0988637" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/0bb91d3176357da232da69762a64b0e0a0988637", + "reference": "0bb91d3176357da232da69762a64b0e0a0988637", + "shasum": "" + }, + "require": { + "doctrine/inflector": "^1.4|^2.0", + "dragonmantank/cron-expression": "^3.0.2", + "egulias/email-validator": "^2.1.10", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "laravel/serializable-closure": "^1.0", + "league/commonmark": "^1.3|^2.0.2", + "league/flysystem": "^1.1", + "monolog/monolog": "^2.0", + "nesbot/carbon": "^2.53.1", + "opis/closure": "^3.6", + "php": "^7.3|^8.0", + "psr/container": "^1.0", + "psr/log": "^1.0 || ^2.0", + "psr/simple-cache": "^1.0", + "ramsey/uuid": "^4.2.2", + "swiftmailer/swiftmailer": "^6.3", + "symfony/console": "^5.4", + "symfony/error-handler": "^5.4", + "symfony/finder": "^5.4", + "symfony/http-foundation": "^5.4", + "symfony/http-kernel": "^5.4", + "symfony/mime": "^5.4", + "symfony/process": "^5.4", + "symfony/routing": "^5.4", + "symfony/var-dumper": "^5.4", + "tijsverkoyen/css-to-inline-styles": "^2.2.2", + "vlucas/phpdotenv": "^5.2", + "voku/portable-ascii": "^1.4.8" + }, + "conflict": { + "tightenco/collect": "<5.5.33" + }, + "provide": { + "psr/container-implementation": "1.0", + "psr/simple-cache-implementation": "1.0" + }, + "replace": { + "illuminate/auth": "self.version", + "illuminate/broadcasting": "self.version", + "illuminate/bus": "self.version", + "illuminate/cache": "self.version", + "illuminate/collections": "self.version", + "illuminate/config": "self.version", + "illuminate/console": "self.version", + "illuminate/container": "self.version", + "illuminate/contracts": "self.version", + "illuminate/cookie": "self.version", + "illuminate/database": "self.version", + "illuminate/encryption": "self.version", + "illuminate/events": "self.version", + "illuminate/filesystem": "self.version", + "illuminate/hashing": "self.version", + "illuminate/http": "self.version", + "illuminate/log": "self.version", + "illuminate/macroable": "self.version", + "illuminate/mail": "self.version", + "illuminate/notifications": "self.version", + "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", + "illuminate/queue": "self.version", + "illuminate/redis": "self.version", + "illuminate/routing": "self.version", + "illuminate/session": "self.version", + "illuminate/support": "self.version", + "illuminate/testing": "self.version", + "illuminate/translation": "self.version", + "illuminate/validation": "self.version", + "illuminate/view": "self.version" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.198.1", + "doctrine/dbal": "^2.13.3|^3.1.4", + "filp/whoops": "^2.14.3", + "guzzlehttp/guzzle": "^6.5.5|^7.0.1", + "league/flysystem-cached-adapter": "^1.0", + "mockery/mockery": "^1.4.4", + "orchestra/testbench-core": "^6.27", + "pda/pheanstalk": "^4.0", + "phpunit/phpunit": "^8.5.19|^9.5.8", + "predis/predis": "^1.1.9", + "symfony/cache": "^5.4" + }, + "suggest": { + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.198.1).", + "brianium/paratest": "Required to run tests in parallel (^6.0).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.13.3|^3.1.4).", + "ext-bcmath": "Required to use the multiple_of validation rule.", + "ext-ftp": "Required to use the Flysystem FTP driver.", + "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", + "ext-memcached": "Required to use the memcache cache driver.", + "ext-pcntl": "Required to use all features of the queue worker.", + "ext-posix": "Required to use all features of the queue worker.", + "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).", + "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", + "filp/whoops": "Required for friendly error pages in development (^2.14.3).", + "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^6.5.5|^7.0.1).", + "laravel/tinker": "Required to use the tinker console command (^2.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).", + "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", + "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", + "mockery/mockery": "Required to use mocking (^1.4.4).", + "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).", + "phpunit/phpunit": "Required to use assertions and run tests (^8.5.19|^9.5.8).", + "predis/predis": "Required to use the predis connector (^1.1.9).", + "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0|^6.0|^7.0).", + "symfony/cache": "Required to PSR-6 cache bridge (^5.4).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^5.4).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0).", + "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." + }, + "time": "2021-12-07T14:55:46+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/Illuminate/Collections/helpers.php", + "src/Illuminate/Events/functions.php", + "src/Illuminate/Foundation/helpers.php", + "src/Illuminate/Support/helpers.php" + ], + "psr-4": { + "Illuminate\\": "src/Illuminate/", + "Illuminate\\Support\\": [ + "src/Illuminate/Macroable/", + "src/Illuminate/Collections/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Laravel Framework.", + "homepage": "https://laravel.com", + "keywords": [ + "framework", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "install-path": "../laravel/framework" + }, + { + "name": "laravel/passport", + "version": "v10.2.2", + "version_normalized": "10.2.2.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/passport.git", + "reference": "7981abed1a0979afd4a5a8bec81624b8127a287f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/passport/zipball/7981abed1a0979afd4a5a8bec81624b8127a287f", + "reference": "7981abed1a0979afd4a5a8bec81624b8127a287f", + "shasum": "" + }, + "require": { + "ext-json": "*", + "firebase/php-jwt": "^5.0", + "illuminate/auth": "^8.2", + "illuminate/console": "^8.2", + "illuminate/container": "^8.2", + "illuminate/contracts": "^8.2", + "illuminate/cookie": "^8.2", + "illuminate/database": "^8.2", + "illuminate/encryption": "^8.2", + "illuminate/http": "^8.2", + "illuminate/support": "^8.2", + "lcobucci/jwt": "^3.4|^4.0", + "league/oauth2-server": "^8.2", + "nyholm/psr7": "^1.3", + "php": "^7.3|^8.0", + "phpseclib/phpseclib": "^2.0|^3.0", + "symfony/psr-http-message-bridge": "^2.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "orchestra/testbench": "^6.0", + "phpunit/phpunit": "^9.3" + }, + "time": "2021-12-07T16:57:03+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Passport\\PassportServiceProvider" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laravel\\Passport\\": "src/", + "Laravel\\Passport\\Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel Passport provides OAuth2 server support to Laravel.", + "keywords": [ + "laravel", + "oauth", + "passport" + ], + "support": { + "issues": "https://github.com/laravel/passport/issues", + "source": "https://github.com/laravel/passport" + }, + "install-path": "../laravel/passport" + }, + { + "name": "laravel/serializable-closure", + "version": "v1.0.5", + "version_normalized": "1.0.5.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "25de3be1bca1b17d52ff0dc02b646c667ac7266c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/25de3be1bca1b17d52ff0dc02b646c667ac7266c", + "reference": "25de3be1bca1b17d52ff0dc02b646c667ac7266c", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "pestphp/pest": "^1.18", + "phpstan/phpstan": "^0.12.98", + "symfony/var-dumper": "^5.3" + }, + "time": "2021-11-30T15:53:04+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "install-path": "../laravel/serializable-closure" + }, + { + "name": "lcobucci/clock", + "version": "2.1.0", + "version_normalized": "2.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/clock.git", + "reference": "903513d28e85376a33385ebc601afd2ee69e5653" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/903513d28e85376a33385ebc601afd2ee69e5653", + "reference": "903513d28e85376a33385ebc601afd2ee69e5653", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "infection/infection": "^0.25", + "lcobucci/coding-standard": "^8.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-deprecation-rules": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^9.5" + }, + "time": "2021-10-31T21:32:07+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Lcobucci\\Clock\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com" + } + ], + "description": "Yet another clock abstraction", + "support": { + "issues": "https://github.com/lcobucci/clock/issues", + "source": "https://github.com/lcobucci/clock/tree/2.1.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "install-path": "../lcobucci/clock" + }, + { + "name": "lcobucci/jwt", + "version": "4.0.4", + "version_normalized": "4.0.4.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "55564265fddf810504110bd68ca311932324b0e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/55564265fddf810504110bd68ca311932324b0e9", + "reference": "55564265fddf810504110bd68ca311932324b0e9", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-openssl": "*", + "lcobucci/clock": "^2.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "infection/infection": "^0.20", + "lcobucci/coding-standard": "^6.0", + "mikey179/vfsstream": "^1.6", + "phpbench/phpbench": "^0.17", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-deprecation-rules": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/php-invoker": "^3.1", + "phpunit/phpunit": "^9.4" + }, + "time": "2021-09-28T19:18:28+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "install-path": "../lcobucci/jwt" + }, + { + "name": "league/commonmark", + "version": "2.1.0", + "version_normalized": "2.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "819276bc54e83c160617d3ac0a436c239e479928" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/819276bc54e83c160617d3ac0a436c239e479928", + "reference": "819276bc54e83c160617d3ac0a436c239e479928", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/polyfill-php80": "^1.15" + }, + "require-dev": { + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.30.0", + "commonmark/commonmark.js": "0.30.0", + "composer/package-versions-deprecated": "^1.8", + "erusev/parsedown": "^1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "^1.4", + "phpstan/phpstan": "^0.12.88 || ^1.0.0", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "symfony/finder": "^5.3", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" + }, + "time": "2021-12-05T18:25:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.2-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "support": { + "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", + "issues": "https://github.com/thephpleague/commonmark/issues", + "rss": "https://github.com/thephpleague/commonmark/releases.atom", + "source": "https://github.com/thephpleague/commonmark" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/commonmark", + "type": "tidelift" + } + ], + "install-path": "../league/commonmark" + }, + { + "name": "league/config", + "version": "v1.1.1", + "version_normalized": "1.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/config.git", + "reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/config/zipball/a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e", + "reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.90", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "time": "2021-08-14T12:15:32+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "install-path": "../league/config" + }, + { + "name": "league/event", + "version": "2.2.0", + "version_normalized": "2.2.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/event.git", + "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/event/zipball/d2cc124cf9a3fab2bb4ff963307f60361ce4d119", + "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "~1.0.1", + "phpspec/phpspec": "^2.2" + }, + "time": "2018-11-26T11:52:41+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\Event\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Event package", + "keywords": [ + "emitter", + "event", + "listener" + ], + "support": { + "issues": "https://github.com/thephpleague/event/issues", + "source": "https://github.com/thephpleague/event/tree/master" + }, + "install-path": "../league/event" + }, + { + "name": "league/flysystem", + "version": "1.1.9", + "version_normalized": "1.1.9.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "094defdb4a7001845300334e7c1ee2335925ef99" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/094defdb4a7001845300334e7c1ee2335925ef99", + "reference": "094defdb4a7001845300334e7c1ee2335925ef99", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/mime-type-detection": "^1.3", + "php": "^7.2.5 || ^8.0" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" + }, + "suggest": { + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "time": "2021-12-09T09:40:50+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.1.9" + }, + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "install-path": "../league/flysystem" + }, + { + "name": "league/mime-type-detection", + "version": "1.9.0", + "version_normalized": "1.9.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "aa70e813a6ad3d1558fc927863d47309b4c23e69" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/aa70e813a6ad3d1558fc927863d47309b4c23e69", + "reference": "aa70e813a6ad3d1558fc927863d47309b4c23e69", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3" + }, + "time": "2021-11-21T11:48:40+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.9.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "install-path": "../league/mime-type-detection" + }, + { + "name": "league/oauth2-server", + "version": "8.3.3", + "version_normalized": "8.3.3.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/oauth2-server.git", + "reference": "f5698a3893eda9a17bcd48636990281e7ca77b2a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/f5698a3893eda9a17bcd48636990281e7ca77b2a", + "reference": "f5698a3893eda9a17bcd48636990281e7ca77b2a", + "shasum": "" + }, + "require": { + "defuse/php-encryption": "^2.2.1", + "ext-json": "*", + "ext-openssl": "*", + "lcobucci/jwt": "^3.4.6 || ^4.0.4", + "league/event": "^2.2", + "php": "^7.2 || ^8.0", + "psr/http-message": "^1.0.1" + }, + "replace": { + "league/oauth2server": "*", + "lncd/oauth2": "*" + }, + "require-dev": { + "laminas/laminas-diactoros": "^2.4.1", + "phpstan/phpstan": "^0.12.57", + "phpstan/phpstan-phpunit": "^0.12.16", + "phpunit/phpunit": "^8.5.13", + "roave/security-advisories": "dev-master" + }, + "time": "2021-10-11T20:41:49+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\OAuth2\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alex Bilbie", + "email": "hello@alexbilbie.com", + "homepage": "http://www.alexbilbie.com", + "role": "Developer" + }, + { + "name": "Andy Millington", + "email": "andrew@noexceptions.io", + "homepage": "https://www.noexceptions.io", + "role": "Developer" + } + ], + "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.", + "homepage": "https://oauth2.thephpleague.com/", + "keywords": [ + "Authentication", + "api", + "auth", + "authorisation", + "authorization", + "oauth", + "oauth 2", + "oauth 2.0", + "oauth2", + "protect", + "resource", + "secure", + "server" + ], + "support": { + "issues": "https://github.com/thephpleague/oauth2-server/issues", + "source": "https://github.com/thephpleague/oauth2-server/tree/8.3.3" + }, + "funding": [ + { + "url": "https://github.com/sephster", + "type": "github" + } + ], + "install-path": "../league/oauth2-server" + }, + { + "name": "lorisleiva/laravel-search-string", + "version": "v1.1.3", + "version_normalized": "1.1.3.0", + "source": { + "type": "git", + "url": "https://github.com/lorisleiva/laravel-search-string.git", + "reference": "366f5584f2ae13d6751644f05079f2c0d6634c0e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lorisleiva/laravel-search-string/zipball/366f5584f2ae13d6751644f05079f2c0d6634c0e", + "reference": "366f5584f2ae13d6751644f05079f2c0d6634c0e", + "shasum": "" + }, + "require": { + "hoa/compiler": "^3.17", + "illuminate/support": "^5.5|^6.0|^7.0|^8.0", + "sanmai/hoa-protocol": "^1.17" + }, + "require-dev": { + "orchestra/testbench": "^4.0|^5.0|^6.0" + }, + "time": "2021-04-30T19:12:09+00:00", + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Lorisleiva\\LaravelSearchString\\ServiceProvider" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Lorisleiva\\LaravelSearchString\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Loris Leiva", + "email": "loris.leiva@gmail.com" + } + ], + "description": "Generates database queries based on one unique string using a simple and customizable syntax.", + "support": { + "issues": "https://github.com/lorisleiva/laravel-search-string/issues", + "source": "https://github.com/lorisleiva/laravel-search-string/tree/v1.1.3" + }, + "funding": [ + { + "url": "https://github.com/lorisleiva", + "type": "github" + } + ], + "install-path": "../lorisleiva/laravel-search-string" + }, + { + "name": "monolog/monolog", + "version": "2.3.5", + "version_normalized": "2.3.5.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "fd4380d6fc37626e2f799f29d91195040137eba9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd4380d6fc37626e2f799f29d91195040137eba9", + "reference": "fd4380d6fc37626e2f799f29d91195040137eba9", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7", + "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "php-console/php-console": "^3.1.3", + "phpspec/prophecy": "^1.6.1", + "phpstan/phpstan": "^0.12.91", + "phpunit/phpunit": "^8.5", + "predis/predis": "^1.1", + "rollbar/rollbar": "^1.3", + "ruflin/elastica": ">=0.90@dev", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "time": "2021-10-01T21:08:31+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/2.3.5" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "install-path": "../monolog/monolog" + }, + { + "name": "nesbot/carbon", + "version": "2.55.2", + "version_normalized": "2.55.2.0", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "8c2a18ce3e67c34efc1b29f64fe61304368259a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8c2a18ce3e67c34efc1b29f64fe61304368259a2", + "reference": "8c2a18ce3e67c34efc1b29f64fe61304368259a2", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.1.8 || ^8.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" + }, + "require-dev": { + "doctrine/dbal": "^2.0 || ^3.0", + "doctrine/orm": "^2.7", + "friendsofphp/php-cs-fixer": "^3.0", + "kylekatarnls/multi-tester": "^2.0", + "phpmd/phpmd": "^2.9", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.54", + "phpunit/phpunit": "^7.5.20 || ^8.5.14", + "squizlabs/php_codesniffer": "^3.4" + }, + "time": "2021-12-03T14:59:52+00:00", + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-3.x": "3.x-dev", + "dev-master": "2.x-dev" + }, + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbon.nesbot.com/docs", + "issues": "https://github.com/briannesbitt/Carbon/issues", + "source": "https://github.com/briannesbitt/Carbon" + }, + "funding": [ + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "install-path": "../nesbot/carbon" + }, + { + "name": "nette/schema", + "version": "v1.2.2", + "version_normalized": "1.2.2.0", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/9a39cef03a5b34c7de64f551538cbba05c2be5df", + "reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df", + "shasum": "" + }, + "require": { + "nette/utils": "^2.5.7 || ^3.1.5 || ^4.0", + "php": ">=7.1 <8.2" + }, + "require-dev": { + "nette/tester": "^2.3 || ^2.4", + "phpstan/phpstan-nette": "^0.12", + "tracy/tracy": "^2.7" + }, + "time": "2021-10-15T11:40:02+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "installation-source": "dist", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.2.2" + }, + "install-path": "../nette/schema" + }, + { + "name": "nette/utils", + "version": "v3.2.6", + "version_normalized": "3.2.6.0", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "2f261e55bd6a12057442045bf2c249806abc1d02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/2f261e55bd6a12057442045bf2c249806abc1d02", + "reference": "2f261e55bd6a12057442045bf2c249806abc1d02", + "shasum": "" + }, + "require": { + "php": ">=7.2 <8.2" + }, + "conflict": { + "nette/di": "<3.0.6" + }, + "require-dev": { + "nette/tester": "~2.0", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.3" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", + "ext-xml": "to use Strings::length() etc. when mbstring is not available" + }, + "time": "2021-11-24T15:47:23+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "installation-source": "dist", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v3.2.6" + }, + "install-path": "../nette/utils" + }, + { + "name": "nunomaduro/collision", + "version": "v5.10.0", + "version_normalized": "5.10.0.0", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "3004cfa49c022183395eabc6d0e5207dfe498d00" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/3004cfa49c022183395eabc6d0e5207dfe498d00", + "reference": "3004cfa49c022183395eabc6d0e5207dfe498d00", + "shasum": "" + }, + "require": { + "facade/ignition-contracts": "^1.0", + "filp/whoops": "^2.14.3", + "php": "^7.3 || ^8.0", + "symfony/console": "^5.0" + }, + "require-dev": { + "brianium/paratest": "^6.1", + "fideloper/proxy": "^4.4.1", + "fruitcake/laravel-cors": "^2.0.3", + "laravel/framework": "8.x-dev", + "nunomaduro/larastan": "^0.6.2", + "nunomaduro/mock-final-classes": "^1.0", + "orchestra/testbench": "^6.0", + "phpstan/phpstan": "^0.12.64", + "phpunit/phpunit": "^9.5.0" + }, + "time": "2021-09-20T15:06:32+00:00", + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "support": { + "issues": "https://github.com/nunomaduro/collision/issues", + "source": "https://github.com/nunomaduro/collision" + }, + "funding": [ + { + "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "install-path": "../nunomaduro/collision" + }, + { + "name": "nyholm/psr7", + "version": "1.4.1", + "version_normalized": "1.4.1.0", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7.git", + "reference": "2212385b47153ea71b1c1b1374f8cb5e4f7892ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/2212385b47153ea71b1c1b1374f8cb5e4f7892ec", + "reference": "2212385b47153ea71b1c1b1374f8cb5e4f7892ec", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "php-http/message-factory": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "^0.9", + "php-http/psr7-integration-tests": "^1.0", + "phpunit/phpunit": "^7.5 || 8.5 || 9.4", + "symfony/error-handler": "^4.4" + }, + "time": "2021-07-02T08:32:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "A fast PHP7 implementation of PSR-7", + "homepage": "https://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/Nyholm/psr7/issues", + "source": "https://github.com/Nyholm/psr7/tree/1.4.1" + }, + "funding": [ + { + "url": "https://github.com/Zegnat", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "install-path": "../nyholm/psr7" + }, + { + "name": "opis/closure", + "version": "3.6.2", + "version_normalized": "3.6.2.0", + "source": { + "type": "git", + "url": "https://github.com/opis/closure.git", + "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/closure/zipball/06e2ebd25f2869e54a306dda991f7db58066f7f6", + "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0" + }, + "require-dev": { + "jeremeamia/superclosure": "^2.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + }, + "time": "2021-04-09T13:42:10+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.6.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Opis\\Closure\\": "src/" + }, + "files": [ + "functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", + "homepage": "https://opis.io/closure", + "keywords": [ + "anonymous functions", + "closure", + "function", + "serializable", + "serialization", + "serialize" + ], + "support": { + "issues": "https://github.com/opis/closure/issues", + "source": "https://github.com/opis/closure/tree/3.6.2" + }, + "install-path": "../opis/closure" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.4.0", + "version_normalized": "2.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "shasum": "" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" + }, + "time": "2020-12-06T15:14:20+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "install-path": "../paragonie/constant_time_encoding" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "version_normalized": "9.99.100.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "time": "2020-10-15T08:29:30+00:00", + "type": "library", + "installation-source": "dist", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "install-path": "../paragonie/random_compat" + }, + { + "name": "php-http/message-factory", + "version": "v1.0.2", + "version_normalized": "1.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/message-factory.git", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "psr/http-message": "^1.0" + }, + "time": "2015-12-19T14:08:53+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Factory interfaces for PSR-7 HTTP Message", + "homepage": "http://php-http.org", + "keywords": [ + "factory", + "http", + "message", + "stream", + "uri" + ], + "support": { + "issues": "https://github.com/php-http/message-factory/issues", + "source": "https://github.com/php-http/message-factory/tree/master" + }, + "install-path": "../php-http/message-factory" + }, + { + "name": "phpoption/phpoption", + "version": "1.8.1", + "version_normalized": "1.8.1.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", + "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" + }, + "time": "2021-12-04T23:24:31+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.8.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "install-path": "../phpoption/phpoption" + }, + { + "name": "phpseclib/phpseclib", + "version": "3.0.12", + "version_normalized": "3.0.12.0", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "89bfb45bd8b1abc3b37e910d57f5dbd3174f40fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/89bfb45bd8b1abc3b37e910d57f5dbd3174f40fb", + "reference": "89bfb45bd8b1abc3b37e910d57f5dbd3174f40fb", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1|^2", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "^5.7|^6.0|^9.4", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "time": "2021-11-28T23:46:03+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.12" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "install-path": "../phpseclib/phpseclib" + }, + { + "name": "psr/container", + "version": "1.1.2", + "version_normalized": "1.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "time": "2021-11-05T16:50:12+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "install-path": "../psr/container" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "time": "2019-01-08T18:20:26+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "install-path": "../psr/event-dispatcher" + }, + { + "name": "psr/http-client", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "time": "2020-06-29T06:28:15+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, + "install-path": "../psr/http-client" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "time": "2019-04-30T12:38:16+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "install-path": "../psr/http-factory" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2016-08-06T14:39:51+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "install-path": "../psr/http-message" + }, + { + "name": "psr/log", + "version": "2.0.0", + "version_normalized": "2.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/ef29f6d262798707a9edd554e2b82517ef3a9376", + "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "time": "2021-07-14T16:41:46+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/2.0.0" + }, + "install-path": "../psr/log" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2017-10-23T01:57:42+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "install-path": "../psr/simple-cache" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "version_normalized": "3.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "time": "2019-03-08T08:55:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "install-path": "../ralouphie/getallheaders" + }, + { + "name": "ramsey/collection", + "version": "1.2.2", + "version_normalized": "1.2.2.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/cccc74ee5e328031b15640b51056ee8d3bb66c0a", + "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8", + "symfony/polyfill-php81": "^1.23" + }, + "require-dev": { + "captainhook/captainhook": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "ergebnis/composer-normalize": "^2.6", + "fakerphp/faker": "^1.5", + "hamcrest/hamcrest-php": "^2", + "jangregor/phpstan-prophecy": "^0.8", + "mockery/mockery": "^1.3", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/extension-installer": "^1", + "phpstan/phpstan": "^0.12.32", + "phpstan/phpstan-mockery": "^0.12.5", + "phpstan/phpstan-phpunit": "^0.12.11", + "phpunit/phpunit": "^8.5 || ^9", + "psy/psysh": "^0.10.4", + "slevomat/coding-standard": "^6.3", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.4" + }, + "time": "2021-10-10T03:01:02+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/1.2.2" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", + "type": "tidelift" + } + ], + "install-path": "../ramsey/collection" + }, + { + "name": "ramsey/uuid", + "version": "4.2.3", + "version_normalized": "4.2.3.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", + "shasum": "" + }, + "require": { + "brick/math": "^0.8 || ^0.9", + "ext-json": "*", + "php": "^7.2 || ^8.0", + "ramsey/collection": "^1.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php80": "^1.14" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.8", + "ergebnis/composer-normalize": "^2.15", + "mockery/mockery": "^1.3", + "moontoast/math": "^1.1", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", + "php-mock/php-mock-mockery": "^1.3", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpbench/phpbench": "^1.0", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-mockery": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^8.5 || ^9", + "slevomat/coding-standard": "^7.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.9" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-ctype": "Enables faster processing of character classification using ctype functions.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "time": "2021-09-25T23:10:38+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.x-dev" + }, + "captainhook": { + "force-install": true + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Ramsey\\Uuid\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.2.3" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" + } + ], + "install-path": "../ramsey/uuid" + }, + { + "name": "rcrowe/twigbridge", + "version": "v0.12.3", + "version_normalized": "0.12.3.0", + "source": { + "type": "git", + "url": "https://github.com/rcrowe/TwigBridge.git", + "reference": "5d6dc0c907c5db476cf0caf3210eb10e44a78369" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rcrowe/TwigBridge/zipball/5d6dc0c907c5db476cf0caf3210eb10e44a78369", + "reference": "5d6dc0c907c5db476cf0caf3210eb10e44a78369", + "shasum": "" + }, + "require": { + "illuminate/support": "^5.5|^6|^7|^8", + "illuminate/view": "^5.5|^6|^7|^8", + "php": ">=7.1", + "twig/twig": "^2.11" + }, + "require-dev": { + "ext-json": "*", + "laravel/framework": "5.5.*", + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "~6.0", + "satooshi/php-coveralls": "~0.6", + "squizlabs/php_codesniffer": "~1.5" + }, + "suggest": { + "laravelcollective/html": "For bringing back html/form in Laravel 5.x", + "twig/extensions": "~1.0" + }, + "time": "2020-10-14T18:14:32+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.12-dev" + }, + "laravel": { + "providers": [ + "TwigBridge\\ServiceProvider" + ], + "aliases": { + "Twig": "TwigBridge\\Facade\\Twig" + } + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "TwigBridge\\": "src", + "TwigBridge\\Tests\\": "tests" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rob Crowe", + "email": "hello@vivalacrowe.com" + }, + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Adds the power of Twig to Laravel", + "keywords": [ + "laravel", + "twig" + ], + "support": { + "issues": "https://github.com/rcrowe/TwigBridge/issues", + "source": "https://github.com/rcrowe/TwigBridge/tree/v0.12.3" + }, + "install-path": "../rcrowe/twigbridge" + }, + { + "name": "sanmai/hoa-protocol", + "version": "1.21", + "version_normalized": "1.21.0.0", + "source": { + "type": "git", + "url": "https://github.com/sanmai/Protocol.git", + "reference": "3cf1a72c12fed6aa0169433a10f0275face91362" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sanmai/Protocol/zipball/3cf1a72c12fed6aa0169433a10f0275face91362", + "reference": "3cf1a72c12fed6aa0169433a10f0275face91362", + "shasum": "" + }, + "require": { + "hoa/consistency": "*", + "hoa/exception": "*", + "php": ">=7.0" + }, + "replace": { + "hoa/protocol": "*" + }, + "require-dev": { + "atoum/atoum": "^3", + "atoum/stubs": "*", + "hoa/test": "*" + }, + "time": "2021-01-01T15:57:23+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Hoa\\Protocol\\": "Source", + "Hoa\\Protocol\\Bin\\": "Bin" + }, + "files": [ + "Source/Wrapper.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin" + }, + { + "name": "Hoa community" + } + ], + "description": "The Hoa\\Protocol library.", + "keywords": [ + "library", + "protocol", + "resource", + "stream", + "wrapper" + ], + "support": { + "issues": "https://github.com/sanmai/Protocol/issues", + "source": "https://github.com/sanmai/Protocol/tree/1.21" + }, + "install-path": "../sanmai/hoa-protocol" + }, + { + "name": "spatie/laravel-translation-loader", + "version": "2.7.0", + "version_normalized": "2.7.0.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-translation-loader.git", + "reference": "16c9ac39a4dbf4c978ab48921e27362cbbb429b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-translation-loader/zipball/16c9ac39a4dbf4c978ab48921e27362cbbb429b0", + "reference": "16c9ac39a4dbf4c978ab48921e27362cbbb429b0", + "shasum": "" + }, + "require": { + "illuminate/translation": "^6.0|^7.0|^8.0", + "php": "^7.2|^8.0" + }, + "require-dev": { + "orchestra/testbench": "^4.0|^5.0|^6.0", + "phpunit/phpunit": "^8.0|^9.0" + }, + "time": "2020-12-04T12:54:57+00:00", + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\TranslationLoader\\TranslationServiceProvider" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Spatie\\TranslationLoader\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Store your language lines in the database, yaml or other sources", + "homepage": "https://github.com/spatie/laravel-translation-loader", + "keywords": [ + "database", + "db", + "i8n", + "language", + "laravel", + "laravel-translation-loader", + "spatie", + "translate" + ], + "support": { + "issues": "https://github.com/spatie/laravel-translation-loader/issues", + "source": "https://github.com/spatie/laravel-translation-loader/tree/2.7.0" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + } + ], + "install-path": "../spatie/laravel-translation-loader" + }, + { + "name": "swiftmailer/swiftmailer", + "version": "v6.3.0", + "version_normalized": "6.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/8a5d5072dca8f48460fce2f4131fcc495eec654c", + "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.0|^3.1", + "php": ">=7.0.0", + "symfony/polyfill-iconv": "^1.0", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "symfony/phpunit-bridge": "^4.4|^5.4" + }, + "suggest": { + "ext-intl": "Needed to support internationalized email addresses" + }, + "time": "2021-10-18T15:26:12+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "https://swiftmailer.symfony.com", + "keywords": [ + "email", + "mail", + "mailer" + ], + "support": { + "issues": "https://github.com/swiftmailer/swiftmailer/issues", + "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/swiftmailer/swiftmailer", + "type": "tidelift" + } + ], + "abandoned": "symfony/mailer", + "install-path": "../swiftmailer/swiftmailer" + }, + { + "name": "symfony/console", + "version": "v5.4.1", + "version_normalized": "5.4.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "9130e1a0fc93cb0faadca4ee917171bd2ca9e5f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/9130e1a0fc93cb0faadca4ee917171bd2ca9e5f4", + "reference": "9130e1a0fc93cb0faadca4ee917171bd2ca9e5f4", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.1|^6.0" + }, + "conflict": { + "psr/log": ">=3", + "symfony/dependency-injection": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/lock": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "time": "2021-12-09T11:22:43+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v5.4.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/console" + }, + { + "name": "symfony/css-selector", + "version": "v5.4.0", + "version_normalized": "5.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "44b933f98bb4b5220d10bed9ce5662f8c2d13dcc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/44b933f98bb4b5220d10bed9ce5662f8c2d13dcc", + "reference": "44b933f98bb4b5220d10bed9ce5662f8c2d13dcc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "time": "2021-09-09T08:06:01+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v5.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/css-selector" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/c726b64c1ccfe2896cb7df2e1331c357ad1c8ced", + "reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced", + "shasum": "" + }, + "require": { + "php": ">=8.0.2" + }, + "time": "2021-11-01T23:48:49+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/deprecation-contracts" + }, + { + "name": "symfony/error-handler", + "version": "v5.4.1", + "version_normalized": "5.4.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "1e3cb3565af49cd5f93e5787500134500a29f0d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/1e3cb3565af49cd5f93e5787500134500a29f0d9", + "reference": "1e3cb3565af49cd5f93e5787500134500a29f0d9", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^4.4|^5.0|^6.0" + }, + "require-dev": { + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" + }, + "time": "2021-12-01T15:04:08+00:00", + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v5.4.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/error-handler" + }, + { + "name": "symfony/event-dispatcher", + "version": "v6.0.1", + "version_normalized": "6.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "4f06d19a5f78087061f9de6df3269c139c3d289d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4f06d19a5f78087061f9de6df3269c139c3d289d", + "reference": "4f06d19a5f78087061f9de6df3269c139c3d289d", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "symfony/event-dispatcher-contracts": "^2|^3" + }, + "conflict": { + "symfony/dependency-injection": "<5.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/error-handler": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^5.4|^6.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "time": "2021-12-08T15:13:44+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v6.0.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/event-dispatcher" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "aa5422287b75594b90ee9cd807caf8f0df491385" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/aa5422287b75594b90ee9cd807caf8f0df491385", + "reference": "aa5422287b75594b90ee9cd807caf8f0df491385", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "time": "2021-07-15T12:33:35+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.0.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/event-dispatcher-contracts" + }, + { + "name": "symfony/finder", + "version": "v5.4.0", + "version_normalized": "5.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "d2f29dac98e96a98be467627bd49c2efb1bc2590" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/d2f29dac98e96a98be467627bd49c2efb1bc2590", + "reference": "d2f29dac98e96a98be467627bd49c2efb1bc2590", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" + }, + "time": "2021-11-28T15:25:38+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v5.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/finder" + }, + { + "name": "symfony/http-foundation", + "version": "v5.4.1", + "version_normalized": "5.4.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "5dad3780023a707f4c24beac7d57aead85c1ce3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5dad3780023a707f4c24beac7d57aead85c1ce3c", + "reference": "5dad3780023a707f4c24beac7d57aead85c1ce3c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/mime": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/mime": "To use the file extension guesser" + }, + "time": "2021-12-09T12:46:57+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v5.4.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/http-foundation" + }, + { + "name": "symfony/http-kernel", + "version": "v5.4.1", + "version_normalized": "5.4.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "2bdace75c9d6a6eec7e318801b7dc87a72375052" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/2bdace75c9d6a6eec7e318801b7dc87a72375052", + "reference": "2bdace75c9d6a6eec7e318801b7dc87a72375052", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/log": "^1|^2", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^5.0|^6.0", + "symfony/http-foundation": "^5.3.7|^6.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/browser-kit": "<5.4", + "symfony/cache": "<5.0", + "symfony/config": "<5.0", + "symfony/console": "<4.4", + "symfony/dependency-injection": "<5.3", + "symfony/doctrine-bridge": "<5.0", + "symfony/form": "<5.0", + "symfony/http-client": "<5.0", + "symfony/mailer": "<5.0", + "symfony/messenger": "<5.0", + "symfony/translation": "<5.0", + "symfony/twig-bridge": "<5.0", + "symfony/validator": "<5.0", + "twig/twig": "<2.13" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^5.4|^6.0", + "symfony/config": "^5.0|^6.0", + "symfony/console": "^4.4|^5.0|^6.0", + "symfony/css-selector": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^5.3|^6.0", + "symfony/dom-crawler": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/http-client-contracts": "^1.1|^2|^3", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/routing": "^4.4|^5.0|^6.0", + "symfony/stopwatch": "^4.4|^5.0|^6.0", + "symfony/translation": "^4.4|^5.0|^6.0", + "symfony/translation-contracts": "^1.1|^2|^3", + "twig/twig": "^2.13|^3.0.4" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" + }, + "time": "2021-12-09T13:36:09+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v5.4.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/http-kernel" + }, + { + "name": "symfony/mime", + "version": "v5.4.0", + "version_normalized": "5.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "d4365000217b67c01acff407573906ff91bcfb34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/d4365000217b67c01acff407573906ff91bcfb34", + "reference": "d4365000217b67c01acff407573906ff91bcfb34", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.1|^6.0", + "symfony/property-info": "^4.4|^5.1|^6.0", + "symfony/serializer": "^5.2|^6.0" + }, + "time": "2021-11-23T10:19:22+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v5.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/mime" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.23.0", + "version_normalized": "1.23.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "time": "2021-02-19T12:13:01+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-ctype" + }, + { + "name": "symfony/polyfill-iconv", + "version": "v1.23.0", + "version_normalized": "1.23.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-iconv.git", + "reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/63b5bb7db83e5673936d6e3b8b3e022ff6474933", + "reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-iconv": "For best performance" + }, + "time": "2021-05-27T09:27:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Iconv\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Iconv extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "iconv", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-iconv" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.23.1", + "version_normalized": "1.23.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "16880ba9c5ebe3642d1995ab866db29270b36535" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/16880ba9c5ebe3642d1995ab866db29270b36535", + "reference": "16880ba9c5ebe3642d1995ab866db29270b36535", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2021-05-27T12:26:48+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-grapheme" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.23.0", + "version_normalized": "1.23.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65", + "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2021-05-27T09:27:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-idn" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.23.0", + "version_normalized": "1.23.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2021-02-19T12:13:01+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-normalizer" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.23.1", + "version_normalized": "1.23.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "time": "2021-05-27T12:26:48+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-mbstring" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.23.0", + "version_normalized": "1.23.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2021-05-27T09:17:38+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php72" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.23.0", + "version_normalized": "1.23.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2021-02-19T12:13:01+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php73" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.23.1", + "version_normalized": "1.23.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be", + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2021-07-28T13:41:28+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php80" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.23.0", + "version_normalized": "1.23.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "e66119f3de95efc359483f810c4c3e6436279436" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436", + "reference": "e66119f3de95efc359483f810c4c3e6436279436", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2021-05-21T13:25:03+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php81" + }, + { + "name": "symfony/process", + "version": "v5.4.0", + "version_normalized": "5.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "5be20b3830f726e019162b26223110c8f47cf274" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/5be20b3830f726e019162b26223110c8f47cf274", + "reference": "5be20b3830f726e019162b26223110c8f47cf274", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "time": "2021-11-28T15:25:38+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v5.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/process" + }, + { + "name": "symfony/psr-http-message-bridge", + "version": "v2.1.2", + "version_normalized": "2.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/psr-http-message-bridge.git", + "reference": "22b37c8a3f6b5d94e9cdbd88e1270d96e2f97b34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/22b37c8a3f6b5d94e9cdbd88e1270d96e2f97b34", + "reference": "22b37c8a3f6b5d94e9cdbd88e1270d96e2f97b34", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0", + "symfony/http-foundation": "^4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "nyholm/psr7": "^1.1", + "psr/log": "^1.1 || ^2 || ^3", + "symfony/browser-kit": "^4.4 || ^5.0 || ^6.0", + "symfony/config": "^4.4 || ^5.0 || ^6.0", + "symfony/event-dispatcher": "^4.4 || ^5.0 || ^6.0", + "symfony/framework-bundle": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "^4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.4@dev || ^6.0" + }, + "suggest": { + "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" + }, + "time": "2021-11-05T13:13:39+00:00", + "type": "symfony-bridge", + "extra": { + "branch-alias": { + "dev-main": "2.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\PsrHttpMessage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "PSR HTTP message bridge", + "homepage": "http://symfony.com", + "keywords": [ + "http", + "http-message", + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/symfony/psr-http-message-bridge/issues", + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.1.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/psr-http-message-bridge" + }, + { + "name": "symfony/routing", + "version": "v5.4.0", + "version_normalized": "5.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "9eeae93c32ca86746e5d38f3679e9569981038b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/9eeae93c32ca86746e5d38f3679e9569981038b1", + "reference": "9eeae93c32ca86746e5d38f3679e9569981038b1", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "doctrine/annotations": "<1.12", + "symfony/config": "<5.3", + "symfony/dependency-injection": "<4.4", + "symfony/yaml": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "^1.12", + "psr/log": "^1|^2|^3", + "symfony/config": "^5.3|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/yaml": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "time": "2021-11-23T10:19:22+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v5.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/routing" + }, + { + "name": "symfony/service-contracts", + "version": "v2.4.1", + "version_normalized": "2.4.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "d664541b99d6fb0247ec5ff32e87238582236204" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d664541b99d6fb0247ec5ff32e87238582236204", + "reference": "d664541b99d6fb0247ec5ff32e87238582236204", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "time": "2021-11-04T16:37:19+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.4.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/service-contracts" + }, + { + "name": "symfony/string", + "version": "v6.0.1", + "version_normalized": "6.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "0cfed595758ec6e0a25591bdc8ca733c1896af32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/0cfed595758ec6e0a25591bdc8ca733c1896af32", + "reference": "0cfed595758ec6e0a25591bdc8ca733c1896af32", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.0" + }, + "require-dev": { + "symfony/error-handler": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/translation-contracts": "^2.0|^3.0", + "symfony/var-exporter": "^5.4|^6.0" + }, + "time": "2021-12-08T15:13:44+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "files": [ + "Resources/functions.php" + ], + "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": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v6.0.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/string" + }, + { + "name": "symfony/translation", + "version": "v6.0.1", + "version_normalized": "6.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "b7956e00c6e03546f2ba489fc50f7c47933e76b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/b7956e00c6e03546f2ba489fc50f7c47933e76b8", + "reference": "b7956e00c6e03546f2ba489fc50f7c47933e76b8", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.3|^3.0" + }, + "conflict": { + "symfony/config": "<5.4", + "symfony/console": "<5.4", + "symfony/dependency-injection": "<5.4", + "symfony/http-kernel": "<5.4", + "symfony/twig-bundle": "<5.4", + "symfony/yaml": "<5.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/http-client-contracts": "^1.1|^2.0|^3.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/intl": "^5.4|^6.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/service-contracts": "^1.1.2|^2|^3", + "symfony/yaml": "^5.4|^6.0" + }, + "suggest": { + "psr/log-implementation": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "time": "2021-12-08T15:13:44+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v6.0.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/translation" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "1b6ea5a7442af5a12dba3dbd6d71034b5b234e77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/1b6ea5a7442af5a12dba3dbd6d71034b5b234e77", + "reference": "1b6ea5a7442af5a12dba3dbd6d71034b5b234e77", + "shasum": "" + }, + "require": { + "php": ">=8.0.2" + }, + "suggest": { + "symfony/translation-implementation": "" + }, + "time": "2021-09-07T12:43:40+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.0.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/translation-contracts" + }, + { + "name": "symfony/var-dumper", + "version": "v5.4.1", + "version_normalized": "5.4.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "2366ac8d8abe0c077844613c1a4f0c0a9f522dcc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2366ac8d8abe0c077844613c1a4f0c0a9f522dcc", + "reference": "2366ac8d8abe0c077844613c1a4f0c0a9f522dcc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpunit/phpunit": "<5.4.3", + "symfony/console": "<4.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/uid": "^5.1|^6.0", + "twig/twig": "^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "time": "2021-12-01T15:04:08+00:00", + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "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": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v5.4.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/var-dumper" + }, + { + "name": "symfony/yaml", + "version": "v5.4.0", + "version_normalized": "5.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "034ccc0994f1ae3f7499fa5b1f2e75d5e7a94efc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/034ccc0994f1ae3f7499fa5b1f2e75d5e7a94efc", + "reference": "034ccc0994f1ae3f7499fa5b1f2e75d5e7a94efc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<5.3" + }, + "require-dev": { + "symfony/console": "^5.3|^6.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "time": "2021-11-28T15:25:38+00:00", + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v5.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/yaml" + }, + { + "name": "tijsverkoyen/css-to-inline-styles", + "version": "2.2.4", + "version_normalized": "2.2.4.0", + "source": { + "type": "git", + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "da444caae6aca7a19c0c140f68c6182e337d5b1c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/da444caae6aca7a19c0c140f68c6182e337d5b1c", + "reference": "da444caae6aca7a19c0c140f68c6182e337d5b1c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "php": "^5.5 || ^7.0 || ^8.0", + "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5 || ^8.5.21 || ^9.5.10" + }, + "time": "2021-12-08T09:12:39+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "TijsVerkoyen\\CssToInlineStyles\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Tijs Verkoyen", + "email": "css_to_inline_styles@verkoyen.eu", + "role": "Developer" + } + ], + "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", + "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", + "support": { + "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.4" + }, + "install-path": "../tijsverkoyen/css-to-inline-styles" + }, + { + "name": "twig/twig", + "version": "v2.14.8", + "version_normalized": "2.14.8.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "06b450a2326aa879faa2061ff72fe1588b3ab043" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/06b450a2326aa879faa2061ff72fe1588b3ab043", + "reference": "06b450a2326aa879faa2061ff72fe1588b3ab043", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "psr/container": "^1.0", + "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" + }, + "time": "2021-11-25T13:38:06+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.14-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Twig_": "lib/" + }, + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v2.14.8" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "install-path": "../twig/twig" + }, + { + "name": "vectorface/whip", + "version": "v0.3.2", + "version_normalized": "0.3.2.0", + "source": { + "type": "git", + "url": "https://github.com/Vectorface/whip.git", + "reference": "c3cdf71f532c83c3ab512cfa57130dad36fdbc83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Vectorface/whip/zipball/c3cdf71f532c83c3ab512cfa57130dad36fdbc83", + "reference": "c3cdf71f532c83c3ab512cfa57130dad36fdbc83", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "psr/http-message": "~1.0", + "squizlabs/php_codesniffer": "~2.0", + "vectorface/dunit": "~2.0" + }, + "time": "2017-10-30T14:05:31+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Vectorface\\Whip\\": "./src", + "VectorFace\\Whip\\": "./src", + "Vectorface\\WhipTests\\": "./tests" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Bruce", + "email": "dbruce@vectorface.com", + "role": "Developer" + }, + { + "name": "Cory Darby", + "email": "ckdarby@vectorface.com", + "role": "Developer" + } + ], + "description": "A PHP class for retrieving accurate IP address information for the client.", + "homepage": "https://github.com/Vectorface/whip", + "keywords": [ + "IP", + "cdn", + "cloudflare" + ], + "support": { + "issues": "https://github.com/Vectorface/whip/issues", + "source": "https://github.com/Vectorface/whip" + }, + "install-path": "../vectorface/whip" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.4.0", + "version_normalized": "5.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "d4394d044ed69a8f244f3445bcedf8a0d7fe2403" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/d4394d044ed69a8f244f3445bcedf8a0d7fe2403", + "reference": "d4394d044ed69a8f244f3445bcedf8a0d7fe2403", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.0.2", + "php": "^7.1.3 || ^8.0", + "phpoption/phpoption": "^1.8", + "symfony/polyfill-ctype": "^1.23", + "symfony/polyfill-mbstring": "^1.23.1", + "symfony/polyfill-php80": "^1.23.1" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "ext-filter": "*", + "phpunit/phpunit": "^7.5.20 || ^8.5.21 || ^9.5.10" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "time": "2021-11-10T01:08:39+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.4-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.4.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "install-path": "../vlucas/phpdotenv" + }, + { + "name": "voku/portable-ascii", + "version": "1.5.6", + "version_normalized": "1.5.6.0", + "source": { + "type": "git", + "url": "https://github.com/voku/portable-ascii.git", + "reference": "80953678b19901e5165c56752d087fc11526017c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/80953678b19901e5165c56752d087fc11526017c", + "reference": "80953678b19901e5165c56752d087fc11526017c", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + }, + "suggest": { + "ext-intl": "Use Intl for transliterator_transliterate() support" + }, + "time": "2020-11-12T00:07:28+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "voku\\": "src/voku/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lars Moelleken", + "homepage": "http://www.moelleken.org/" + } + ], + "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", + "homepage": "https://github.com/voku/portable-ascii", + "keywords": [ + "ascii", + "clean", + "php" + ], + "support": { + "issues": "https://github.com/voku/portable-ascii/issues", + "source": "https://github.com/voku/portable-ascii/tree/1.5.6" + }, + "funding": [ + { + "url": "https://www.paypal.me/moelleken", + "type": "custom" + }, + { + "url": "https://github.com/voku", + "type": "github" + }, + { + "url": "https://opencollective.com/portable-ascii", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/voku", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", + "type": "tidelift" + } + ], + "install-path": "../voku/portable-ascii" + }, + { + "name": "webmozart/assert", + "version": "1.10.0", + "version_normalized": "1.10.0.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "time": "2021-03-09T10:59:23+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" + }, + "install-path": "../webmozart/assert" + } + ], + "dev": false, + "dev-package-names": [] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100755 index 0000000..f60ea3b --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,1302 @@ + array( + 'name' => 'bs-community/blessing-skin-server', + 'pretty_version' => '6.0.2', + 'version' => '6.0.2.0', + 'reference' => 'b737a65f5f5fce1f897f8603db74fd970437b351', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => false, + ), + 'versions' => array( + 'blessing/filter' => array( + 'pretty_version' => 'v1.2.0', + 'version' => '1.2.0.0', + 'reference' => 'b2e48bcb852bdc92cee39f2188e32550f95be8d2', + 'type' => 'library', + 'install_path' => __DIR__ . '/../blessing/filter', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'blessing/rejection' => array( + 'pretty_version' => 'v1.2.0', + 'version' => '1.2.0.0', + 'reference' => '2de752ba7793060ae7bc6607d885a8be2be2e08c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../blessing/rejection', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'blessing/texture-renderer' => array( + 'pretty_version' => '0.2.1', + 'version' => '0.2.1.0', + 'reference' => '78480e5df9c7ae7d56c5966994b06e49265fbab4', + 'type' => 'library', + 'install_path' => __DIR__ . '/../blessing/texture-renderer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'brick/math' => array( + 'pretty_version' => '0.9.3', + 'version' => '0.9.3.0', + 'reference' => 'ca57d18f028f84f777b2168cd1911b0dee2343ae', + 'type' => 'library', + 'install_path' => __DIR__ . '/../brick/math', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'bs-community/blessing-skin-server' => array( + 'pretty_version' => '6.0.2', + 'version' => '6.0.2.0', + 'reference' => 'b737a65f5f5fce1f897f8603db74fd970437b351', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'composer/ca-bundle' => array( + 'pretty_version' => '1.3.1', + 'version' => '1.3.1.0', + 'reference' => '4c679186f2aca4ab6a0f1b0b9cf9252decb44d0b', + 'type' => 'library', + 'install_path' => __DIR__ . '/./ca-bundle', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'composer/semver' => array( + 'pretty_version' => '3.2.6', + 'version' => '3.2.6.0', + 'reference' => '83e511e247de329283478496f7a1e114c9517506', + 'type' => 'library', + 'install_path' => __DIR__ . '/./semver', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'defuse/php-encryption' => array( + 'pretty_version' => 'v2.3.1', + 'version' => '2.3.1.0', + 'reference' => '77880488b9954b7884c25555c2a0ea9e7053f9d2', + 'type' => 'library', + 'install_path' => __DIR__ . '/../defuse/php-encryption', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'dflydev/dot-access-data' => array( + 'pretty_version' => 'v3.0.1', + 'version' => '3.0.1.0', + 'reference' => '0992cc19268b259a39e86f296da5f0677841f42c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../dflydev/dot-access-data', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'doctrine/cache' => array( + 'pretty_version' => '2.1.1', + 'version' => '2.1.1.0', + 'reference' => '331b4d5dbaeab3827976273e9356b3b453c300ce', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/cache', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'doctrine/dbal' => array( + 'pretty_version' => '2.13.6', + 'version' => '2.13.6.0', + 'reference' => '67ef6d0327ccbab1202b39e0222977a47ed3ef2f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/dbal', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'doctrine/deprecations' => array( + 'pretty_version' => 'v0.5.3', + 'version' => '0.5.3.0', + 'reference' => '9504165960a1f83cc1480e2be1dd0a0478561314', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/deprecations', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'doctrine/event-manager' => array( + 'pretty_version' => '1.1.1', + 'version' => '1.1.1.0', + 'reference' => '41370af6a30faa9dc0368c4a6814d596e81aba7f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/event-manager', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'doctrine/inflector' => array( + 'pretty_version' => '1.4.4', + 'version' => '1.4.4.0', + 'reference' => '4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/inflector', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'doctrine/lexer' => array( + 'pretty_version' => '1.2.1', + 'version' => '1.2.1.0', + 'reference' => 'e864bbf5904cb8f5bb334f99209b48018522f042', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/lexer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'dragonmantank/cron-expression' => array( + 'pretty_version' => 'v3.1.0', + 'version' => '3.1.0.0', + 'reference' => '7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../dragonmantank/cron-expression', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'egulias/email-validator' => array( + 'pretty_version' => '2.1.25', + 'version' => '2.1.25.0', + 'reference' => '0dbf5d78455d4d6a41d186da50adc1122ec066f4', + 'type' => 'library', + 'install_path' => __DIR__ . '/../egulias/email-validator', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'facade/flare-client-php' => array( + 'pretty_version' => '1.9.1', + 'version' => '1.9.1.0', + 'reference' => 'b2adf1512755637d0cef4f7d1b54301325ac78ed', + 'type' => 'library', + 'install_path' => __DIR__ . '/../facade/flare-client-php', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'facade/ignition' => array( + 'pretty_version' => '2.17.2', + 'version' => '2.17.2.0', + 'reference' => 'af3cd70d58ca3ef5189ff0e59efbe5a5c043e2d2', + 'type' => 'library', + 'install_path' => __DIR__ . '/../facade/ignition', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'facade/ignition-contracts' => array( + 'pretty_version' => '1.0.2', + 'version' => '1.0.2.0', + 'reference' => '3c921a1cdba35b68a7f0ccffc6dffc1995b18267', + 'type' => 'library', + 'install_path' => __DIR__ . '/../facade/ignition-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'filp/whoops' => array( + 'pretty_version' => '2.14.4', + 'version' => '2.14.4.0', + 'reference' => 'f056f1fe935d9ed86e698905a957334029899895', + 'type' => 'library', + 'install_path' => __DIR__ . '/../filp/whoops', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'firebase/php-jwt' => array( + 'pretty_version' => 'v5.5.1', + 'version' => '5.5.1.0', + 'reference' => '83b609028194aa042ea33b5af2d41a7427de80e6', + 'type' => 'library', + 'install_path' => __DIR__ . '/../firebase/php-jwt', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'graham-campbell/result-type' => array( + 'pretty_version' => 'v1.0.4', + 'version' => '1.0.4.0', + 'reference' => '0690bde05318336c7221785f2a932467f98b64ca', + 'type' => 'library', + 'install_path' => __DIR__ . '/../graham-campbell/result-type', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'gregwar/captcha' => array( + 'pretty_version' => 'v1.1.9', + 'version' => '1.1.9.0', + 'reference' => '4bb668e6b40e3205a020ca5ee4ca8cff8b8780c5', + 'type' => 'captcha', + 'install_path' => __DIR__ . '/../gregwar/captcha', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzlehttp/guzzle' => array( + 'pretty_version' => '7.4.1', + 'version' => '7.4.1.0', + 'reference' => 'ee0a041b1760e6a53d2a39c8c34115adc2af2c79', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/guzzle', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzlehttp/promises' => array( + 'pretty_version' => '1.5.1', + 'version' => '1.5.1.0', + 'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/promises', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzlehttp/psr7' => array( + 'pretty_version' => '2.1.0', + 'version' => '2.1.0.0', + 'reference' => '089edd38f5b8abba6cb01567c2a8aaa47cec4c72', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/psr7', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/compiler' => array( + 'pretty_version' => '3.17.08.08', + 'version' => '3.17.08.08', + 'reference' => 'aa09caf0bf28adae6654ca6ee415ee2f522672de', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/compiler', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/consistency' => array( + 'pretty_version' => '1.17.05.02', + 'version' => '1.17.05.02', + 'reference' => 'fd7d0adc82410507f332516faf655b6ed22e4c2f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/consistency', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/event' => array( + 'pretty_version' => '1.17.01.13', + 'version' => '1.17.01.13', + 'reference' => '6c0060dced212ffa3af0e34bb46624f990b29c54', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/event', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/exception' => array( + 'pretty_version' => '1.17.01.16', + 'version' => '1.17.01.16', + 'reference' => '091727d46420a3d7468ef0595651488bfc3a458f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/exception', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/file' => array( + 'pretty_version' => '1.17.07.11', + 'version' => '1.17.07.11', + 'reference' => '35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/file', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/iterator' => array( + 'pretty_version' => '2.17.01.10', + 'version' => '2.17.01.10', + 'reference' => 'd1120ba09cb4ccd049c86d10058ab94af245f0cc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/iterator', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/math' => array( + 'pretty_version' => '1.17.05.16', + 'version' => '1.17.05.16', + 'reference' => '7150785d30f5d565704912116a462e9f5bc83a0c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/math', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/protocol' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '*', + ), + ), + 'hoa/regex' => array( + 'pretty_version' => '1.17.01.13', + 'version' => '1.17.01.13', + 'reference' => '7e263a61b6fb45c1d03d8e5ef77668518abd5bec', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/regex', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/stream' => array( + 'pretty_version' => '1.17.02.21', + 'version' => '1.17.02.21', + 'reference' => '3293cfffca2de10525df51436adf88a559151d82', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/stream', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/ustring' => array( + 'pretty_version' => '4.17.01.16', + 'version' => '4.17.01.16', + 'reference' => 'e6326e2739178799b1fe3fdd92029f9517fa17a0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/ustring', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/visitor' => array( + 'pretty_version' => '2.17.01.16', + 'version' => '2.17.01.16', + 'reference' => 'c18fe1cbac98ae449e0d56e87469103ba08f224a', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/visitor', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'hoa/zformat' => array( + 'pretty_version' => '1.17.01.10', + 'version' => '1.17.01.10', + 'reference' => '522c381a2a075d4b9dbb42eb4592dd09520e4ac2', + 'type' => 'library', + 'install_path' => __DIR__ . '/../hoa/zformat', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'illuminate/auth' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/broadcasting' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/bus' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/cache' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/collections' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/config' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/console' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/container' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/contracts' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/cookie' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/database' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/encryption' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/events' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/filesystem' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/hashing' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/http' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/log' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/macroable' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/mail' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/notifications' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/pagination' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/pipeline' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/queue' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/redis' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/routing' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/session' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/support' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/testing' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/translation' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/validation' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'illuminate/view' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v8.75.0', + ), + ), + 'intervention/image' => array( + 'pretty_version' => '2.7.0', + 'version' => '2.7.0.0', + 'reference' => '9a8cc99d30415ec0b3f7649e1647d03a55698545', + 'type' => 'library', + 'install_path' => __DIR__ . '/../intervention/image', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'laravel/framework' => array( + 'pretty_version' => 'v8.75.0', + 'version' => '8.75.0.0', + 'reference' => '0bb91d3176357da232da69762a64b0e0a0988637', + 'type' => 'library', + 'install_path' => __DIR__ . '/../laravel/framework', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'laravel/passport' => array( + 'pretty_version' => 'v10.2.2', + 'version' => '10.2.2.0', + 'reference' => '7981abed1a0979afd4a5a8bec81624b8127a287f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../laravel/passport', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'laravel/serializable-closure' => array( + 'pretty_version' => 'v1.0.5', + 'version' => '1.0.5.0', + 'reference' => '25de3be1bca1b17d52ff0dc02b646c667ac7266c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../laravel/serializable-closure', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'lcobucci/clock' => array( + 'pretty_version' => '2.1.0', + 'version' => '2.1.0.0', + 'reference' => '903513d28e85376a33385ebc601afd2ee69e5653', + 'type' => 'library', + 'install_path' => __DIR__ . '/../lcobucci/clock', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'lcobucci/jwt' => array( + 'pretty_version' => '4.0.4', + 'version' => '4.0.4.0', + 'reference' => '55564265fddf810504110bd68ca311932324b0e9', + 'type' => 'library', + 'install_path' => __DIR__ . '/../lcobucci/jwt', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'league/commonmark' => array( + 'pretty_version' => '2.1.0', + 'version' => '2.1.0.0', + 'reference' => '819276bc54e83c160617d3ac0a436c239e479928', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/commonmark', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'league/config' => array( + 'pretty_version' => 'v1.1.1', + 'version' => '1.1.1.0', + 'reference' => 'a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/config', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'league/event' => array( + 'pretty_version' => '2.2.0', + 'version' => '2.2.0.0', + 'reference' => 'd2cc124cf9a3fab2bb4ff963307f60361ce4d119', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/event', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'league/flysystem' => array( + 'pretty_version' => '1.1.9', + 'version' => '1.1.9.0', + 'reference' => '094defdb4a7001845300334e7c1ee2335925ef99', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/flysystem', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'league/mime-type-detection' => array( + 'pretty_version' => '1.9.0', + 'version' => '1.9.0.0', + 'reference' => 'aa70e813a6ad3d1558fc927863d47309b4c23e69', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/mime-type-detection', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'league/oauth2-server' => array( + 'pretty_version' => '8.3.3', + 'version' => '8.3.3.0', + 'reference' => 'f5698a3893eda9a17bcd48636990281e7ca77b2a', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/oauth2-server', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'league/oauth2server' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '*', + ), + ), + 'lncd/oauth2' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '*', + ), + ), + 'lorisleiva/laravel-search-string' => array( + 'pretty_version' => 'v1.1.3', + 'version' => '1.1.3.0', + 'reference' => '366f5584f2ae13d6751644f05079f2c0d6634c0e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../lorisleiva/laravel-search-string', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'monolog/monolog' => array( + 'pretty_version' => '2.3.5', + 'version' => '2.3.5.0', + 'reference' => 'fd4380d6fc37626e2f799f29d91195040137eba9', + 'type' => 'library', + 'install_path' => __DIR__ . '/../monolog/monolog', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'mtdowling/cron-expression' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '^1.0', + ), + ), + 'nesbot/carbon' => array( + 'pretty_version' => '2.55.2', + 'version' => '2.55.2.0', + 'reference' => '8c2a18ce3e67c34efc1b29f64fe61304368259a2', + 'type' => 'library', + 'install_path' => __DIR__ . '/../nesbot/carbon', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'nette/schema' => array( + 'pretty_version' => 'v1.2.2', + 'version' => '1.2.2.0', + 'reference' => '9a39cef03a5b34c7de64f551538cbba05c2be5df', + 'type' => 'library', + 'install_path' => __DIR__ . '/../nette/schema', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'nette/utils' => array( + 'pretty_version' => 'v3.2.6', + 'version' => '3.2.6.0', + 'reference' => '2f261e55bd6a12057442045bf2c249806abc1d02', + 'type' => 'library', + 'install_path' => __DIR__ . '/../nette/utils', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'nunomaduro/collision' => array( + 'pretty_version' => 'v5.10.0', + 'version' => '5.10.0.0', + 'reference' => '3004cfa49c022183395eabc6d0e5207dfe498d00', + 'type' => 'library', + 'install_path' => __DIR__ . '/../nunomaduro/collision', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'nyholm/psr7' => array( + 'pretty_version' => '1.4.1', + 'version' => '1.4.1.0', + 'reference' => '2212385b47153ea71b1c1b1374f8cb5e4f7892ec', + 'type' => 'library', + 'install_path' => __DIR__ . '/../nyholm/psr7', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'opis/closure' => array( + 'pretty_version' => '3.6.2', + 'version' => '3.6.2.0', + 'reference' => '06e2ebd25f2869e54a306dda991f7db58066f7f6', + 'type' => 'library', + 'install_path' => __DIR__ . '/../opis/closure', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'paragonie/constant_time_encoding' => array( + 'pretty_version' => 'v2.4.0', + 'version' => '2.4.0.0', + 'reference' => 'f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../paragonie/constant_time_encoding', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'paragonie/random_compat' => array( + 'pretty_version' => 'v9.99.100', + 'version' => '9.99.100.0', + 'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a', + 'type' => 'library', + 'install_path' => __DIR__ . '/../paragonie/random_compat', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'php-http/message-factory' => array( + 'pretty_version' => 'v1.0.2', + 'version' => '1.0.2.0', + 'reference' => 'a478cb11f66a6ac48d8954216cfed9aa06a501a1', + 'type' => 'library', + 'install_path' => __DIR__ . '/../php-http/message-factory', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'phpoption/phpoption' => array( + 'pretty_version' => '1.8.1', + 'version' => '1.8.1.0', + 'reference' => 'eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpoption/phpoption', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'phpseclib/phpseclib' => array( + 'pretty_version' => '3.0.12', + 'version' => '3.0.12.0', + 'reference' => '89bfb45bd8b1abc3b37e910d57f5dbd3174f40fb', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpseclib/phpseclib', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/container' => array( + 'pretty_version' => '1.1.2', + 'version' => '1.1.2.0', + 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/container', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/container-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/event-dispatcher' => array( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'reference' => 'dbefd12671e8a14ec7f180cab83036ed26714bb0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/event-dispatcher', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/event-dispatcher-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/http-client' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-client', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-client-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/http-factory' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-factory', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-factory-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/http-message' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-message', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-message-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/log' => array( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'reference' => 'ef29f6d262798707a9edd554e2b82517ef3a9376', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/log-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0|2.0', + 1 => '1.0.0 || 2.0.0 || 3.0.0', + ), + ), + 'psr/simple-cache' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/simple-cache', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/simple-cache-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'ralouphie/getallheaders' => array( + 'pretty_version' => '3.0.3', + 'version' => '3.0.3.0', + 'reference' => '120b605dfeb996808c31b6477290a714d356e822', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ralouphie/getallheaders', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ramsey/collection' => array( + 'pretty_version' => '1.2.2', + 'version' => '1.2.2.0', + 'reference' => 'cccc74ee5e328031b15640b51056ee8d3bb66c0a', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ramsey/collection', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ramsey/uuid' => array( + 'pretty_version' => '4.2.3', + 'version' => '4.2.3.0', + 'reference' => 'fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ramsey/uuid', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'rcrowe/twigbridge' => array( + 'pretty_version' => 'v0.12.3', + 'version' => '0.12.3.0', + 'reference' => '5d6dc0c907c5db476cf0caf3210eb10e44a78369', + 'type' => 'library', + 'install_path' => __DIR__ . '/../rcrowe/twigbridge', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'rhumsaa/uuid' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '4.2.3', + ), + ), + 'sanmai/hoa-protocol' => array( + 'pretty_version' => '1.21', + 'version' => '1.21.0.0', + 'reference' => '3cf1a72c12fed6aa0169433a10f0275face91362', + 'type' => 'library', + 'install_path' => __DIR__ . '/../sanmai/hoa-protocol', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'spatie/laravel-translation-loader' => array( + 'pretty_version' => '2.7.0', + 'version' => '2.7.0.0', + 'reference' => '16c9ac39a4dbf4c978ab48921e27362cbbb429b0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../spatie/laravel-translation-loader', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'swiftmailer/swiftmailer' => array( + 'pretty_version' => 'v6.3.0', + 'version' => '6.3.0.0', + 'reference' => '8a5d5072dca8f48460fce2f4131fcc495eec654c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../swiftmailer/swiftmailer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/console' => array( + 'pretty_version' => 'v5.4.1', + 'version' => '5.4.1.0', + 'reference' => '9130e1a0fc93cb0faadca4ee917171bd2ca9e5f4', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/console', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/css-selector' => array( + 'pretty_version' => 'v5.4.0', + 'version' => '5.4.0.0', + 'reference' => '44b933f98bb4b5220d10bed9ce5662f8c2d13dcc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/css-selector', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/deprecation-contracts' => array( + 'pretty_version' => 'v3.0.0', + 'version' => '3.0.0.0', + 'reference' => 'c726b64c1ccfe2896cb7df2e1331c357ad1c8ced', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/error-handler' => array( + 'pretty_version' => 'v5.4.1', + 'version' => '5.4.1.0', + 'reference' => '1e3cb3565af49cd5f93e5787500134500a29f0d9', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/error-handler', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/event-dispatcher' => array( + 'pretty_version' => 'v6.0.1', + 'version' => '6.0.1.0', + 'reference' => '4f06d19a5f78087061f9de6df3269c139c3d289d', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/event-dispatcher', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/event-dispatcher-contracts' => array( + 'pretty_version' => 'v3.0.0', + 'version' => '3.0.0.0', + 'reference' => 'aa5422287b75594b90ee9cd807caf8f0df491385', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/event-dispatcher-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '2.0|3.0', + ), + ), + 'symfony/finder' => array( + 'pretty_version' => 'v5.4.0', + 'version' => '5.4.0.0', + 'reference' => 'd2f29dac98e96a98be467627bd49c2efb1bc2590', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/finder', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/http-foundation' => array( + 'pretty_version' => 'v5.4.1', + 'version' => '5.4.1.0', + 'reference' => '5dad3780023a707f4c24beac7d57aead85c1ce3c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/http-foundation', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/http-kernel' => array( + 'pretty_version' => 'v5.4.1', + 'version' => '5.4.1.0', + 'reference' => '2bdace75c9d6a6eec7e318801b7dc87a72375052', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/http-kernel', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/mime' => array( + 'pretty_version' => 'v5.4.0', + 'version' => '5.4.0.0', + 'reference' => 'd4365000217b67c01acff407573906ff91bcfb34', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/mime', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-ctype' => array( + 'pretty_version' => 'v1.23.0', + 'version' => '1.23.0.0', + 'reference' => '46cd95797e9df938fdd2b03693b5fca5e64b01ce', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-iconv' => array( + 'pretty_version' => 'v1.23.0', + 'version' => '1.23.0.0', + 'reference' => '63b5bb7db83e5673936d6e3b8b3e022ff6474933', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-iconv', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-grapheme' => array( + 'pretty_version' => 'v1.23.1', + 'version' => '1.23.1.0', + 'reference' => '16880ba9c5ebe3642d1995ab866db29270b36535', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-idn' => array( + 'pretty_version' => 'v1.23.0', + 'version' => '1.23.0.0', + 'reference' => '65bd267525e82759e7d8c4e8ceea44f398838e65', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-normalizer' => array( + 'pretty_version' => 'v1.23.0', + 'version' => '1.23.0.0', + 'reference' => '8590a5f561694770bdcd3f9b5c69dde6945028e8', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-mbstring' => array( + 'pretty_version' => 'v1.23.1', + 'version' => '1.23.1.0', + 'reference' => '9174a3d80210dca8daa7f31fec659150bbeabfc6', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-php72' => array( + 'pretty_version' => 'v1.23.0', + 'version' => '1.23.0.0', + 'reference' => '9a142215a36a3888e30d0a9eeea9766764e96976', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php72', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-php73' => array( + 'pretty_version' => 'v1.23.0', + 'version' => '1.23.0.0', + 'reference' => 'fba8933c384d6476ab14fb7b8526e5287ca7e010', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php73', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-php80' => array( + 'pretty_version' => 'v1.23.1', + 'version' => '1.23.1.0', + 'reference' => '1100343ed1a92e3a38f9ae122fc0eb21602547be', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php80', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-php81' => array( + 'pretty_version' => 'v1.23.0', + 'version' => '1.23.0.0', + 'reference' => 'e66119f3de95efc359483f810c4c3e6436279436', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php81', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/process' => array( + 'pretty_version' => 'v5.4.0', + 'version' => '5.4.0.0', + 'reference' => '5be20b3830f726e019162b26223110c8f47cf274', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/process', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/psr-http-message-bridge' => array( + 'pretty_version' => 'v2.1.2', + 'version' => '2.1.2.0', + 'reference' => '22b37c8a3f6b5d94e9cdbd88e1270d96e2f97b34', + 'type' => 'symfony-bridge', + 'install_path' => __DIR__ . '/../symfony/psr-http-message-bridge', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/routing' => array( + 'pretty_version' => 'v5.4.0', + 'version' => '5.4.0.0', + 'reference' => '9eeae93c32ca86746e5d38f3679e9569981038b1', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/routing', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/service-contracts' => array( + 'pretty_version' => 'v2.4.1', + 'version' => '2.4.1.0', + 'reference' => 'd664541b99d6fb0247ec5ff32e87238582236204', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/service-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/string' => array( + 'pretty_version' => 'v6.0.1', + 'version' => '6.0.1.0', + 'reference' => '0cfed595758ec6e0a25591bdc8ca733c1896af32', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/string', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/translation' => array( + 'pretty_version' => 'v6.0.1', + 'version' => '6.0.1.0', + 'reference' => 'b7956e00c6e03546f2ba489fc50f7c47933e76b8', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/translation', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/translation-contracts' => array( + 'pretty_version' => 'v3.0.0', + 'version' => '3.0.0.0', + 'reference' => '1b6ea5a7442af5a12dba3dbd6d71034b5b234e77', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/translation-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/translation-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '2.3|3.0', + ), + ), + 'symfony/var-dumper' => array( + 'pretty_version' => 'v5.4.1', + 'version' => '5.4.1.0', + 'reference' => '2366ac8d8abe0c077844613c1a4f0c0a9f522dcc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/var-dumper', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/yaml' => array( + 'pretty_version' => 'v5.4.0', + 'version' => '5.4.0.0', + 'reference' => '034ccc0994f1ae3f7499fa5b1f2e75d5e7a94efc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/yaml', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'tijsverkoyen/css-to-inline-styles' => array( + 'pretty_version' => '2.2.4', + 'version' => '2.2.4.0', + 'reference' => 'da444caae6aca7a19c0c140f68c6182e337d5b1c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../tijsverkoyen/css-to-inline-styles', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'twig/twig' => array( + 'pretty_version' => 'v2.14.8', + 'version' => '2.14.8.0', + 'reference' => '06b450a2326aa879faa2061ff72fe1588b3ab043', + 'type' => 'library', + 'install_path' => __DIR__ . '/../twig/twig', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'vectorface/whip' => array( + 'pretty_version' => 'v0.3.2', + 'version' => '0.3.2.0', + 'reference' => 'c3cdf71f532c83c3ab512cfa57130dad36fdbc83', + 'type' => 'library', + 'install_path' => __DIR__ . '/../vectorface/whip', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'vlucas/phpdotenv' => array( + 'pretty_version' => 'v5.4.0', + 'version' => '5.4.0.0', + 'reference' => 'd4394d044ed69a8f244f3445bcedf8a0d7fe2403', + 'type' => 'library', + 'install_path' => __DIR__ . '/../vlucas/phpdotenv', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'voku/portable-ascii' => array( + 'pretty_version' => '1.5.6', + 'version' => '1.5.6.0', + 'reference' => '80953678b19901e5165c56752d087fc11526017c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../voku/portable-ascii', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'webmozart/assert' => array( + 'pretty_version' => '1.10.0', + 'version' => '1.10.0.0', + 'reference' => '6964c76c7804814a842473e0c8fd15bab0f18e25', + 'type' => 'library', + 'install_path' => __DIR__ . '/../webmozart/assert', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100755 index 0000000..b168ddd --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 80002)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.2". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/vendor/composer/semver/CHANGELOG.md b/vendor/composer/semver/CHANGELOG.md new file mode 100755 index 0000000..4542fa3 --- /dev/null +++ b/vendor/composer/semver/CHANGELOG.md @@ -0,0 +1,176 @@ +# Change Log + +All notable changes to this project will be documented in this file. +This project adheres to [Semantic Versioning](http://semver.org/). + +### [3.2.6] 2021-10-25 + + * Fixed: type improvements to parseStability + +### [3.2.5] 2021-05-24 + + * Fixed: issue comparing disjunctive MultiConstraints to conjunctive ones (#127) + * Fixed: added complete type information using phpstan annotations + +### [3.2.4] 2020-11-13 + + * Fixed: code clean-up + +### [3.2.3] 2020-11-12 + + * Fixed: constraints in the form of `X || Y, >=Y.1` and other such complex constructs were in some cases being optimized into a more restrictive constraint + +### [3.2.2] 2020-10-14 + + * Fixed: internal code cleanups + +### [3.2.1] 2020-09-27 + + * Fixed: accidental validation of broken constraints combining ^/~ and wildcards, and -dev suffix allowing weird cases + * Fixed: normalization of beta0 and such which was dropping the 0 + +### [3.2.0] 2020-09-09 + + * Added: support for `x || @dev`, not very useful but seen in the wild and failed to validate with 1.5.2/1.6.0 + * Added: support for `foobar-dev` being equal to `dev-foobar`, dev-foobar is the official way to write it but we need to support the other for BC and convenience + +### [3.1.0] 2020-09-08 + + * Added: support for constraints like `^2.x-dev` and `~2.x-dev`, not very useful but seen in the wild and failed to validate with 3.0.1 + * Fixed: invalid aliases will no longer throw, unless explicitly validated by Composer in the root package + +### [3.0.1] 2020-09-08 + + * Fixed: handling of some invalid -dev versions which were seen as valid + +### [3.0.0] 2020-05-26 + + * Break: Renamed `EmptyConstraint`, replace it with `MatchAllConstraint` + * Break: Unlikely to affect anyone but strictly speaking a breaking change, `*.*` and such variants will not match all `dev-*` versions anymore, only `*` does + * Break: ConstraintInterface is now considered internal/private and not meant to be implemented by third parties anymore + * Added `Intervals` class to check if a constraint is a subsets of another one, and allow compacting complex MultiConstraints into simpler ones + * Added `CompilingMatcher` class to speed up constraint matching against simple Constraint instances + * Added `MatchAllConstraint` and `MatchNoneConstraint` which match everything and nothing + * Added more advanced optimization of contiguous constraints inside MultiConstraint + * Added tentative support for PHP 8 + * Fixed ConstraintInterface::matches to be commutative in all cases + +### [2.0.0] 2020-04-21 + + * Break: `dev-master`, `dev-trunk` and `dev-default` now normalize to `dev-master`, `dev-trunk` and `dev-default` instead of `9999999-dev` in 1.x + * Break: Removed the deprecated `AbstractConstraint` + * Added `getUpperBound` and `getLowerBound` to ConstraintInterface. They return `Composer\Semver\Constraint\Bound` instances + * Added `MultiConstraint::create` to create the most-optimal form of ConstraintInterface from an array of constraint strings + +### [1.7.2] 2020-12-03 + + * Fixed: Allow installing on php 8 + +### [1.7.1] 2020-09-27 + + * Fixed: accidental validation of broken constraints combining ^/~ and wildcards, and -dev suffix allowing weird cases + * Fixed: normalization of beta0 and such which was dropping the 0 + +### [1.7.0] 2020-09-09 + + * Added: support for `x || @dev`, not very useful but seen in the wild and failed to validate with 1.5.2/1.6.0 + * Added: support for `foobar-dev` being equal to `dev-foobar`, dev-foobar is the official way to write it but we need to support the other for BC and convenience + +### [1.6.0] 2020-09-08 + + * Added: support for constraints like `^2.x-dev` and `~2.x-dev`, not very useful but seen in the wild and failed to validate with 1.5.2 + * Fixed: invalid aliases will no longer throw, unless explicitly validated by Composer in the root package + +### [1.5.2] 2020-09-08 + + * Fixed: handling of some invalid -dev versions which were seen as valid + * Fixed: some doctypes + +### [1.5.1] 2020-01-13 + + * Fixed: Parsing of aliased version was not validating the alias to be a valid version + +### [1.5.0] 2019-03-19 + + * Added: some support for date versions (e.g. 201903) in `~` operator + * Fixed: support for stabilities in `~` operator was inconsistent + +### [1.4.2] 2016-08-30 + + * Fixed: collapsing of complex constraints lead to buggy constraints + +### [1.4.1] 2016-06-02 + + * Changed: branch-like requirements no longer strip build metadata - [composer/semver#38](https://github.com/composer/semver/pull/38). + +### [1.4.0] 2016-03-30 + + * Added: getters on MultiConstraint - [composer/semver#35](https://github.com/composer/semver/pull/35). + +### [1.3.0] 2016-02-25 + + * Fixed: stability parsing - [composer/composer#1234](https://github.com/composer/composer/issues/4889). + * Changed: collapse contiguous constraints when possible. + +### [1.2.0] 2015-11-10 + + * Changed: allow multiple numerical identifiers in 'pre-release' version part. + * Changed: add more 'v' prefix support. + +### [1.1.0] 2015-11-03 + + * Changed: dropped redundant `test` namespace. + * Changed: minor adjustment in datetime parsing normalization. + * Changed: `ConstraintInterface` relaxed, setPrettyString is not required anymore. + * Changed: `AbstractConstraint` marked deprecated, will be removed in 2.0. + * Changed: `Constraint` is now extensible. + +### [1.0.0] 2015-09-21 + + * Break: `VersionConstraint` renamed to `Constraint`. + * Break: `SpecificConstraint` renamed to `AbstractConstraint`. + * Break: `LinkConstraintInterface` renamed to `ConstraintInterface`. + * Break: `VersionParser::parseNameVersionPairs` was removed. + * Changed: `VersionParser::parseConstraints` allows (but ignores) build metadata now. + * Changed: `VersionParser::parseConstraints` allows (but ignores) prefixing numeric versions with a 'v' now. + * Changed: Fixed namespace(s) of test files. + * Changed: `Comparator::compare` no longer throws `InvalidArgumentException`. + * Changed: `Constraint` now throws `InvalidArgumentException`. + +### [0.1.0] 2015-07-23 + + * Added: `Composer\Semver\Comparator`, various methods to compare versions. + * Added: various documents such as README.md, LICENSE, etc. + * Added: configuration files for Git, Travis, php-cs-fixer, phpunit. + * Break: the following namespaces were renamed: + - Namespace: `Composer\Package\Version` -> `Composer\Semver` + - Namespace: `Composer\Package\LinkConstraint` -> `Composer\Semver\Constraint` + - Namespace: `Composer\Test\Package\Version` -> `Composer\Test\Semver` + - Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint` + * Changed: code style using php-cs-fixer. + +[3.2.5]: https://github.com/composer/semver/compare/3.2.4...3.2.5 +[3.2.4]: https://github.com/composer/semver/compare/3.2.3...3.2.4 +[3.2.3]: https://github.com/composer/semver/compare/3.2.2...3.2.3 +[3.2.2]: https://github.com/composer/semver/compare/3.2.1...3.2.2 +[3.2.1]: https://github.com/composer/semver/compare/3.2.0...3.2.1 +[3.2.0]: https://github.com/composer/semver/compare/3.1.0...3.2.0 +[3.1.0]: https://github.com/composer/semver/compare/3.0.1...3.1.0 +[3.0.1]: https://github.com/composer/semver/compare/3.0.0...3.0.1 +[3.0.0]: https://github.com/composer/semver/compare/2.0.0...3.0.0 +[2.0.0]: https://github.com/composer/semver/compare/1.5.1...2.0.0 +[1.7.2]: https://github.com/composer/semver/compare/1.7.1...1.7.2 +[1.7.1]: https://github.com/composer/semver/compare/1.7.0...1.7.1 +[1.7.0]: https://github.com/composer/semver/compare/1.6.0...1.7.0 +[1.6.0]: https://github.com/composer/semver/compare/1.5.2...1.6.0 +[1.5.2]: https://github.com/composer/semver/compare/1.5.1...1.5.2 +[1.5.1]: https://github.com/composer/semver/compare/1.5.0...1.5.1 +[1.5.0]: https://github.com/composer/semver/compare/1.4.2...1.5.0 +[1.4.2]: https://github.com/composer/semver/compare/1.4.1...1.4.2 +[1.4.1]: https://github.com/composer/semver/compare/1.4.0...1.4.1 +[1.4.0]: https://github.com/composer/semver/compare/1.3.0...1.4.0 +[1.3.0]: https://github.com/composer/semver/compare/1.2.0...1.3.0 +[1.2.0]: https://github.com/composer/semver/compare/1.1.0...1.2.0 +[1.1.0]: https://github.com/composer/semver/compare/1.0.0...1.1.0 +[1.0.0]: https://github.com/composer/semver/compare/0.1.0...1.0.0 +[0.1.0]: https://github.com/composer/semver/compare/5e0b9a4da...0.1.0 diff --git a/vendor/composer/semver/LICENSE b/vendor/composer/semver/LICENSE new file mode 100755 index 0000000..4669758 --- /dev/null +++ b/vendor/composer/semver/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2015 Composer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/composer/semver/README.md b/vendor/composer/semver/README.md new file mode 100755 index 0000000..99bc461 --- /dev/null +++ b/vendor/composer/semver/README.md @@ -0,0 +1,98 @@ +composer/semver +=============== + +Semver library that offers utilities, version constraint parsing and validation. + +Originally written as part of [composer/composer](https://github.com/composer/composer), +now extracted and made available as a stand-alone library. + +[![Continuous Integration](https://github.com/composer/semver/workflows/Continuous%20Integration/badge.svg?branch=main)](https://github.com/composer/semver/actions) + + +Installation +------------ + +Install the latest version with: + +```bash +$ composer require composer/semver +``` + + +Requirements +------------ + +* PHP 5.3.2 is required but using the latest version of PHP is highly recommended. + + +Version Comparison +------------------ + +For details on how versions are compared, refer to the [Versions](https://getcomposer.org/doc/articles/versions.md) +article in the documentation section of the [getcomposer.org](https://getcomposer.org) website. + + +Basic usage +----------- + +### Comparator + +The [`Composer\Semver\Comparator`](https://github.com/composer/semver/blob/main/src/Comparator.php) class provides the following methods for comparing versions: + +* greaterThan($v1, $v2) +* greaterThanOrEqualTo($v1, $v2) +* lessThan($v1, $v2) +* lessThanOrEqualTo($v1, $v2) +* equalTo($v1, $v2) +* notEqualTo($v1, $v2) + +Each function takes two version strings as arguments and returns a boolean. For example: + +```php +use Composer\Semver\Comparator; + +Comparator::greaterThan('1.25.0', '1.24.0'); // 1.25.0 > 1.24.0 +``` + +### Semver + +The [`Composer\Semver\Semver`](https://github.com/composer/semver/blob/main/src/Semver.php) class provides the following methods: + +* satisfies($version, $constraints) +* satisfiedBy(array $versions, $constraint) +* sort($versions) +* rsort($versions) + +### Intervals + +The [`Composer\Semver\Intervals`](https://github.com/composer/semver/blob/main/src/Intervals.php) static class provides +a few utilities to work with complex constraints or read version intervals from a constraint: + +```php +use Composer\Semver\Intervals; + +// Checks whether $candidate is a subset of $constraint +Intervals::isSubsetOf(ConstraintInterface $candidate, ConstraintInterface $constraint); + +// Checks whether $a and $b have any intersection, equivalent to $a->matches($b) +Intervals::haveIntersections(ConstraintInterface $a, ConstraintInterface $b); + +// Optimizes a complex multi constraint by merging all intervals down to the smallest +// possible multi constraint. The drawbacks are this is not very fast, and the resulting +// multi constraint will have no human readable prettyConstraint configured on it +Intervals::compactConstraint(ConstraintInterface $constraint); + +// Creates an array of numeric intervals and branch constraints representing a given constraint +Intervals::get(ConstraintInterface $constraint); + +// Clears the memoization cache when you are done processing constraints +Intervals::clear() +``` + +See the class docblocks for more details. + + +License +------- + +composer/semver is licensed under the MIT License, see the LICENSE file for details. diff --git a/vendor/composer/semver/composer.json b/vendor/composer/semver/composer.json new file mode 100755 index 0000000..030df2e --- /dev/null +++ b/vendor/composer/semver/composer.json @@ -0,0 +1,59 @@ +{ + "name": "composer/semver", + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "type": "library", + "license": "MIT", + "keywords": [ + "semver", + "semantic", + "versioning", + "validation" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.2 || ^5", + "phpstan/phpstan": "^0.12.54" + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Composer\\Semver\\": "tests" + } + }, + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "scripts": { + "test": "SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1 vendor/bin/simple-phpunit", + "phpstan": "phpstan analyse" + } +} diff --git a/vendor/composer/semver/src/Comparator.php b/vendor/composer/semver/src/Comparator.php new file mode 100755 index 0000000..38f483a --- /dev/null +++ b/vendor/composer/semver/src/Comparator.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver; + +use Composer\Semver\Constraint\Constraint; + +class Comparator +{ + /** + * Evaluates the expression: $version1 > $version2. + * + * @param string $version1 + * @param string $version2 + * + * @return bool + */ + public static function greaterThan($version1, $version2) + { + return self::compare($version1, '>', $version2); + } + + /** + * Evaluates the expression: $version1 >= $version2. + * + * @param string $version1 + * @param string $version2 + * + * @return bool + */ + public static function greaterThanOrEqualTo($version1, $version2) + { + return self::compare($version1, '>=', $version2); + } + + /** + * Evaluates the expression: $version1 < $version2. + * + * @param string $version1 + * @param string $version2 + * + * @return bool + */ + public static function lessThan($version1, $version2) + { + return self::compare($version1, '<', $version2); + } + + /** + * Evaluates the expression: $version1 <= $version2. + * + * @param string $version1 + * @param string $version2 + * + * @return bool + */ + public static function lessThanOrEqualTo($version1, $version2) + { + return self::compare($version1, '<=', $version2); + } + + /** + * Evaluates the expression: $version1 == $version2. + * + * @param string $version1 + * @param string $version2 + * + * @return bool + */ + public static function equalTo($version1, $version2) + { + return self::compare($version1, '==', $version2); + } + + /** + * Evaluates the expression: $version1 != $version2. + * + * @param string $version1 + * @param string $version2 + * + * @return bool + */ + public static function notEqualTo($version1, $version2) + { + return self::compare($version1, '!=', $version2); + } + + /** + * Evaluates the expression: $version1 $operator $version2. + * + * @param string $version1 + * @param string $operator + * @param string $version2 + * + * @return bool + * + * @phpstan-param Constraint::STR_OP_* $operator + */ + public static function compare($version1, $operator, $version2) + { + $constraint = new Constraint($operator, $version2); + + return $constraint->matchSpecific(new Constraint('==', $version1), true); + } +} diff --git a/vendor/composer/semver/src/CompilingMatcher.php b/vendor/composer/semver/src/CompilingMatcher.php new file mode 100755 index 0000000..f118667 --- /dev/null +++ b/vendor/composer/semver/src/CompilingMatcher.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver; + +use Composer\Semver\Constraint\Constraint; +use Composer\Semver\Constraint\ConstraintInterface; + +/** + * Helper class to evaluate constraint by compiling and reusing the code to evaluate + */ +class CompilingMatcher +{ + /** + * @var array + * @phpstan-var array + */ + private static $compiledCheckerCache = array(); + /** @var bool */ + private static $enabled; + + /** + * @phpstan-var array + */ + private static $transOpInt = array( + Constraint::OP_EQ => Constraint::STR_OP_EQ, + Constraint::OP_LT => Constraint::STR_OP_LT, + Constraint::OP_LE => Constraint::STR_OP_LE, + Constraint::OP_GT => Constraint::STR_OP_GT, + Constraint::OP_GE => Constraint::STR_OP_GE, + Constraint::OP_NE => Constraint::STR_OP_NE, + ); + + /** + * Evaluates the expression: $constraint match $operator $version + * + * @param ConstraintInterface $constraint + * @param int $operator + * @phpstan-param Constraint::OP_* $operator + * @param string $version + * + * @return mixed + */ + public static function match(ConstraintInterface $constraint, $operator, $version) + { + if (self::$enabled === null) { + self::$enabled = !\in_array('eval', explode(',', (string) ini_get('disable_functions')), true); + } + if (!self::$enabled) { + return $constraint->matches(new Constraint(self::$transOpInt[$operator], $version)); + } + + $cacheKey = $operator.$constraint; + if (!isset(self::$compiledCheckerCache[$cacheKey])) { + $code = $constraint->compile($operator); + self::$compiledCheckerCache[$cacheKey] = $function = eval('return function($v, $b){return '.$code.';};'); + } else { + $function = self::$compiledCheckerCache[$cacheKey]; + } + + return $function($version, strpos($version, 'dev-') === 0); + } +} diff --git a/vendor/composer/semver/src/Constraint/Bound.php b/vendor/composer/semver/src/Constraint/Bound.php new file mode 100755 index 0000000..7effb11 --- /dev/null +++ b/vendor/composer/semver/src/Constraint/Bound.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver\Constraint; + +class Bound +{ + /** + * @var string + */ + private $version; + + /** + * @var bool + */ + private $isInclusive; + + /** + * @param string $version + * @param bool $isInclusive + */ + public function __construct($version, $isInclusive) + { + $this->version = $version; + $this->isInclusive = $isInclusive; + } + + /** + * @return string + */ + public function getVersion() + { + return $this->version; + } + + /** + * @return bool + */ + public function isInclusive() + { + return $this->isInclusive; + } + + /** + * @return bool + */ + public function isZero() + { + return $this->getVersion() === '0.0.0.0-dev' && $this->isInclusive(); + } + + /** + * @return bool + */ + public function isPositiveInfinity() + { + return $this->getVersion() === PHP_INT_MAX.'.0.0.0' && !$this->isInclusive(); + } + + /** + * Compares a bound to another with a given operator. + * + * @param Bound $other + * @param string $operator + * + * @return bool + */ + public function compareTo(Bound $other, $operator) + { + if (!\in_array($operator, array('<', '>'), true)) { + throw new \InvalidArgumentException('Does not support any other operator other than > or <.'); + } + + // If they are the same it doesn't matter + if ($this == $other) { + return false; + } + + $compareResult = version_compare($this->getVersion(), $other->getVersion()); + + // Not the same version means we don't need to check if the bounds are inclusive or not + if (0 !== $compareResult) { + return (('>' === $operator) ? 1 : -1) === $compareResult; + } + + // Question we're answering here is "am I higher than $other?" + return '>' === $operator ? $other->isInclusive() : !$other->isInclusive(); + } + + public function __toString() + { + return sprintf( + '%s [%s]', + $this->getVersion(), + $this->isInclusive() ? 'inclusive' : 'exclusive' + ); + } + + /** + * @return self + */ + public static function zero() + { + return new Bound('0.0.0.0-dev', true); + } + + /** + * @return self + */ + public static function positiveInfinity() + { + return new Bound(PHP_INT_MAX.'.0.0.0', false); + } +} diff --git a/vendor/composer/semver/src/Constraint/Constraint.php b/vendor/composer/semver/src/Constraint/Constraint.php new file mode 100755 index 0000000..dc39482 --- /dev/null +++ b/vendor/composer/semver/src/Constraint/Constraint.php @@ -0,0 +1,435 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver\Constraint; + +/** + * Defines a constraint. + */ +class Constraint implements ConstraintInterface +{ + /* operator integer values */ + const OP_EQ = 0; + const OP_LT = 1; + const OP_LE = 2; + const OP_GT = 3; + const OP_GE = 4; + const OP_NE = 5; + + /* operator string values */ + const STR_OP_EQ = '=='; + const STR_OP_EQ_ALT = '='; + const STR_OP_LT = '<'; + const STR_OP_LE = '<='; + const STR_OP_GT = '>'; + const STR_OP_GE = '>='; + const STR_OP_NE = '!='; + const STR_OP_NE_ALT = '<>'; + + /** + * Operator to integer translation table. + * + * @var array + * @phpstan-var array + */ + private static $transOpStr = array( + '=' => self::OP_EQ, + '==' => self::OP_EQ, + '<' => self::OP_LT, + '<=' => self::OP_LE, + '>' => self::OP_GT, + '>=' => self::OP_GE, + '<>' => self::OP_NE, + '!=' => self::OP_NE, + ); + + /** + * Integer to operator translation table. + * + * @var array + * @phpstan-var array + */ + private static $transOpInt = array( + self::OP_EQ => '==', + self::OP_LT => '<', + self::OP_LE => '<=', + self::OP_GT => '>', + self::OP_GE => '>=', + self::OP_NE => '!=', + ); + + /** + * @var int + * @phpstan-var self::OP_* + */ + protected $operator; + + /** @var string */ + protected $version; + + /** @var string|null */ + protected $prettyString; + + /** @var Bound */ + protected $lowerBound; + + /** @var Bound */ + protected $upperBound; + + /** + * Sets operator and version to compare with. + * + * @param string $operator + * @param string $version + * + * @throws \InvalidArgumentException if invalid operator is given. + * + * @phpstan-param self::STR_OP_* $operator + */ + public function __construct($operator, $version) + { + if (!isset(self::$transOpStr[$operator])) { + throw new \InvalidArgumentException(sprintf( + 'Invalid operator "%s" given, expected one of: %s', + $operator, + implode(', ', self::getSupportedOperators()) + )); + } + + $this->operator = self::$transOpStr[$operator]; + $this->version = $version; + } + + /** + * @return string + */ + public function getVersion() + { + return $this->version; + } + + /** + * @return string + * + * @phpstan-return self::STR_OP_* + */ + public function getOperator() + { + return self::$transOpInt[$this->operator]; + } + + /** + * @param ConstraintInterface $provider + * + * @return bool + */ + public function matches(ConstraintInterface $provider) + { + if ($provider instanceof self) { + return $this->matchSpecific($provider); + } + + // turn matching around to find a match + return $provider->matches($this); + } + + /** + * {@inheritDoc} + */ + public function setPrettyString($prettyString) + { + $this->prettyString = $prettyString; + } + + /** + * {@inheritDoc} + */ + public function getPrettyString() + { + if ($this->prettyString) { + return $this->prettyString; + } + + return $this->__toString(); + } + + /** + * Get all supported comparison operators. + * + * @return array + * + * @phpstan-return list + */ + public static function getSupportedOperators() + { + return array_keys(self::$transOpStr); + } + + /** + * @param string $operator + * @return int + * + * @phpstan-param self::STR_OP_* $operator + * @phpstan-return self::OP_* + */ + public static function getOperatorConstant($operator) + { + return self::$transOpStr[$operator]; + } + + /** + * @param string $a + * @param string $b + * @param string $operator + * @param bool $compareBranches + * + * @throws \InvalidArgumentException if invalid operator is given. + * + * @return bool + * + * @phpstan-param self::STR_OP_* $operator + */ + public function versionCompare($a, $b, $operator, $compareBranches = false) + { + if (!isset(self::$transOpStr[$operator])) { + throw new \InvalidArgumentException(sprintf( + 'Invalid operator "%s" given, expected one of: %s', + $operator, + implode(', ', self::getSupportedOperators()) + )); + } + + $aIsBranch = strpos($a, 'dev-') === 0; + $bIsBranch = strpos($b, 'dev-') === 0; + + if ($operator === '!=' && ($aIsBranch || $bIsBranch)) { + return $a !== $b; + } + + if ($aIsBranch && $bIsBranch) { + return $operator === '==' && $a === $b; + } + + // when branches are not comparable, we make sure dev branches never match anything + if (!$compareBranches && ($aIsBranch || $bIsBranch)) { + return false; + } + + return \version_compare($a, $b, $operator); + } + + /** + * {@inheritDoc} + */ + public function compile($otherOperator) + { + if (strpos($this->version, 'dev-') === 0) { + if (self::OP_EQ === $this->operator) { + if (self::OP_EQ === $otherOperator) { + return sprintf('$b && $v === %s', \var_export($this->version, true)); + } + if (self::OP_NE === $otherOperator) { + return sprintf('!$b || $v !== %s', \var_export($this->version, true)); + } + return 'false'; + } + + if (self::OP_NE === $this->operator) { + if (self::OP_EQ === $otherOperator) { + return sprintf('!$b || $v !== %s', \var_export($this->version, true)); + } + if (self::OP_NE === $otherOperator) { + return 'true'; + } + return '!$b'; + } + + return 'false'; + } + + if (self::OP_EQ === $this->operator) { + if (self::OP_EQ === $otherOperator) { + return sprintf('\version_compare($v, %s, \'==\')', \var_export($this->version, true)); + } + if (self::OP_NE === $otherOperator) { + return sprintf('$b || \version_compare($v, %s, \'!=\')', \var_export($this->version, true)); + } + + return sprintf('!$b && \version_compare(%s, $v, \'%s\')', \var_export($this->version, true), self::$transOpInt[$otherOperator]); + } + + if (self::OP_NE === $this->operator) { + if (self::OP_EQ === $otherOperator) { + return sprintf('$b || (!$b && \version_compare($v, %s, \'!=\'))', \var_export($this->version, true)); + } + + if (self::OP_NE === $otherOperator) { + return 'true'; + } + return '!$b'; + } + + if (self::OP_LT === $this->operator || self::OP_LE === $this->operator) { + if (self::OP_LT === $otherOperator || self::OP_LE === $otherOperator) { + return '!$b'; + } + } else { // $this->operator must be self::OP_GT || self::OP_GE here + if (self::OP_GT === $otherOperator || self::OP_GE === $otherOperator) { + return '!$b'; + } + } + + if (self::OP_NE === $otherOperator) { + return 'true'; + } + + $codeComparison = sprintf('\version_compare($v, %s, \'%s\')', \var_export($this->version, true), self::$transOpInt[$this->operator]); + if ($this->operator === self::OP_LE) { + if ($otherOperator === self::OP_GT) { + return sprintf('!$b && \version_compare($v, %s, \'!=\') && ', \var_export($this->version, true)) . $codeComparison; + } + } elseif ($this->operator === self::OP_GE) { + if ($otherOperator === self::OP_LT) { + return sprintf('!$b && \version_compare($v, %s, \'!=\') && ', \var_export($this->version, true)) . $codeComparison; + } + } + + return sprintf('!$b && %s', $codeComparison); + } + + /** + * @param Constraint $provider + * @param bool $compareBranches + * + * @return bool + */ + public function matchSpecific(Constraint $provider, $compareBranches = false) + { + $noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]); + $providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]); + + $isEqualOp = self::OP_EQ === $this->operator; + $isNonEqualOp = self::OP_NE === $this->operator; + $isProviderEqualOp = self::OP_EQ === $provider->operator; + $isProviderNonEqualOp = self::OP_NE === $provider->operator; + + // '!=' operator is match when other operator is not '==' operator or version is not match + // these kinds of comparisons always have a solution + if ($isNonEqualOp || $isProviderNonEqualOp) { + if ($isNonEqualOp && !$isProviderNonEqualOp && !$isProviderEqualOp && strpos($provider->version, 'dev-') === 0) { + return false; + } + + if ($isProviderNonEqualOp && !$isNonEqualOp && !$isEqualOp && strpos($this->version, 'dev-') === 0) { + return false; + } + + if (!$isEqualOp && !$isProviderEqualOp) { + return true; + } + return $this->versionCompare($provider->version, $this->version, '!=', $compareBranches); + } + + // an example for the condition is <= 2.0 & < 1.0 + // these kinds of comparisons always have a solution + if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) { + return !(strpos($this->version, 'dev-') === 0 || strpos($provider->version, 'dev-') === 0); + } + + $version1 = $isEqualOp ? $this->version : $provider->version; + $version2 = $isEqualOp ? $provider->version : $this->version; + $operator = $isEqualOp ? $provider->operator : $this->operator; + + if ($this->versionCompare($version1, $version2, self::$transOpInt[$operator], $compareBranches)) { + // special case, e.g. require >= 1.0 and provide < 1.0 + // 1.0 >= 1.0 but 1.0 is outside of the provided interval + + return !(self::$transOpInt[$provider->operator] === $providerNoEqualOp + && self::$transOpInt[$this->operator] !== $noEqualOp + && \version_compare($provider->version, $this->version, '==')); + } + + return false; + } + + /** + * @return string + */ + public function __toString() + { + return self::$transOpInt[$this->operator] . ' ' . $this->version; + } + + /** + * {@inheritDoc} + */ + public function getLowerBound() + { + $this->extractBounds(); + + return $this->lowerBound; + } + + /** + * {@inheritDoc} + */ + public function getUpperBound() + { + $this->extractBounds(); + + return $this->upperBound; + } + + /** + * @return void + */ + private function extractBounds() + { + if (null !== $this->lowerBound) { + return; + } + + // Branches + if (strpos($this->version, 'dev-') === 0) { + $this->lowerBound = Bound::zero(); + $this->upperBound = Bound::positiveInfinity(); + + return; + } + + switch ($this->operator) { + case self::OP_EQ: + $this->lowerBound = new Bound($this->version, true); + $this->upperBound = new Bound($this->version, true); + break; + case self::OP_LT: + $this->lowerBound = Bound::zero(); + $this->upperBound = new Bound($this->version, false); + break; + case self::OP_LE: + $this->lowerBound = Bound::zero(); + $this->upperBound = new Bound($this->version, true); + break; + case self::OP_GT: + $this->lowerBound = new Bound($this->version, false); + $this->upperBound = Bound::positiveInfinity(); + break; + case self::OP_GE: + $this->lowerBound = new Bound($this->version, true); + $this->upperBound = Bound::positiveInfinity(); + break; + case self::OP_NE: + $this->lowerBound = Bound::zero(); + $this->upperBound = Bound::positiveInfinity(); + break; + } + } +} diff --git a/vendor/composer/semver/src/Constraint/ConstraintInterface.php b/vendor/composer/semver/src/Constraint/ConstraintInterface.php new file mode 100755 index 0000000..389b935 --- /dev/null +++ b/vendor/composer/semver/src/Constraint/ConstraintInterface.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver\Constraint; + +/** + * DO NOT IMPLEMENT this interface. It is only meant for usage as a type hint + * in libraries relying on composer/semver but creating your own constraint class + * that implements this interface is not a supported use case and will cause the + * composer/semver components to return unexpected results. + */ +interface ConstraintInterface +{ + /** + * Checks whether the given constraint intersects in any way with this constraint + * + * @param ConstraintInterface $provider + * + * @return bool + */ + public function matches(ConstraintInterface $provider); + + /** + * Provides a compiled version of the constraint for the given operator + * The compiled version must be a PHP expression. + * Executor of compile version must provide 2 variables: + * - $v = the string version to compare with + * - $b = whether or not the version is a non-comparable branch (starts with "dev-") + * + * @see Constraint::OP_* for the list of available operators. + * @example return '!$b && version_compare($v, '1.0', '>')'; + * + * @param int $otherOperator one Constraint::OP_* + * + * @return string + * + * @phpstan-param Constraint::OP_* $otherOperator + */ + public function compile($otherOperator); + + /** + * @return Bound + */ + public function getUpperBound(); + + /** + * @return Bound + */ + public function getLowerBound(); + + /** + * @return string + */ + public function getPrettyString(); + + /** + * @param string|null $prettyString + * + * @return void + */ + public function setPrettyString($prettyString); + + /** + * @return string + */ + public function __toString(); +} diff --git a/vendor/composer/semver/src/Constraint/MatchAllConstraint.php b/vendor/composer/semver/src/Constraint/MatchAllConstraint.php new file mode 100755 index 0000000..5e51af9 --- /dev/null +++ b/vendor/composer/semver/src/Constraint/MatchAllConstraint.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver\Constraint; + +/** + * Defines the absence of a constraint. + * + * This constraint matches everything. + */ +class MatchAllConstraint implements ConstraintInterface +{ + /** @var string|null */ + protected $prettyString; + + /** + * @param ConstraintInterface $provider + * + * @return bool + */ + public function matches(ConstraintInterface $provider) + { + return true; + } + + /** + * {@inheritDoc} + */ + public function compile($otherOperator) + { + return 'true'; + } + + /** + * {@inheritDoc} + */ + public function setPrettyString($prettyString) + { + $this->prettyString = $prettyString; + } + + /** + * {@inheritDoc} + */ + public function getPrettyString() + { + if ($this->prettyString) { + return $this->prettyString; + } + + return (string) $this; + } + + /** + * {@inheritDoc} + */ + public function __toString() + { + return '*'; + } + + /** + * {@inheritDoc} + */ + public function getUpperBound() + { + return Bound::positiveInfinity(); + } + + /** + * {@inheritDoc} + */ + public function getLowerBound() + { + return Bound::zero(); + } +} diff --git a/vendor/composer/semver/src/Constraint/MatchNoneConstraint.php b/vendor/composer/semver/src/Constraint/MatchNoneConstraint.php new file mode 100755 index 0000000..dadcf62 --- /dev/null +++ b/vendor/composer/semver/src/Constraint/MatchNoneConstraint.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver\Constraint; + +/** + * Blackhole of constraints, nothing escapes it + */ +class MatchNoneConstraint implements ConstraintInterface +{ + /** @var string|null */ + protected $prettyString; + + /** + * @param ConstraintInterface $provider + * + * @return bool + */ + public function matches(ConstraintInterface $provider) + { + return false; + } + + /** + * {@inheritDoc} + */ + public function compile($otherOperator) + { + return 'false'; + } + + /** + * {@inheritDoc} + */ + public function setPrettyString($prettyString) + { + $this->prettyString = $prettyString; + } + + /** + * {@inheritDoc} + */ + public function getPrettyString() + { + if ($this->prettyString) { + return $this->prettyString; + } + + return (string) $this; + } + + /** + * {@inheritDoc} + */ + public function __toString() + { + return '[]'; + } + + /** + * {@inheritDoc} + */ + public function getUpperBound() + { + return new Bound('0.0.0.0-dev', false); + } + + /** + * {@inheritDoc} + */ + public function getLowerBound() + { + return new Bound('0.0.0.0-dev', false); + } +} diff --git a/vendor/composer/semver/src/Constraint/MultiConstraint.php b/vendor/composer/semver/src/Constraint/MultiConstraint.php new file mode 100755 index 0000000..1f4c006 --- /dev/null +++ b/vendor/composer/semver/src/Constraint/MultiConstraint.php @@ -0,0 +1,325 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver\Constraint; + +/** + * Defines a conjunctive or disjunctive set of constraints. + */ +class MultiConstraint implements ConstraintInterface +{ + /** + * @var ConstraintInterface[] + * @phpstan-var non-empty-array + */ + protected $constraints; + + /** @var string|null */ + protected $prettyString; + + /** @var string|null */ + protected $string; + + /** @var bool */ + protected $conjunctive; + + /** @var Bound|null */ + protected $lowerBound; + + /** @var Bound|null */ + protected $upperBound; + + /** + * @param ConstraintInterface[] $constraints A set of constraints + * @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive + * + * @throws \InvalidArgumentException If less than 2 constraints are passed + */ + public function __construct(array $constraints, $conjunctive = true) + { + if (\count($constraints) < 2) { + throw new \InvalidArgumentException( + 'Must provide at least two constraints for a MultiConstraint. Use '. + 'the regular Constraint class for one constraint only or MatchAllConstraint for none. You may use '. + 'MultiConstraint::create() which optimizes and handles those cases automatically.' + ); + } + + $this->constraints = $constraints; + $this->conjunctive = $conjunctive; + } + + /** + * @return ConstraintInterface[] + */ + public function getConstraints() + { + return $this->constraints; + } + + /** + * @return bool + */ + public function isConjunctive() + { + return $this->conjunctive; + } + + /** + * @return bool + */ + public function isDisjunctive() + { + return !$this->conjunctive; + } + + /** + * {@inheritDoc} + */ + public function compile($otherOperator) + { + $parts = array(); + foreach ($this->constraints as $constraint) { + $code = $constraint->compile($otherOperator); + if ($code === 'true') { + if (!$this->conjunctive) { + return 'true'; + } + } elseif ($code === 'false') { + if ($this->conjunctive) { + return 'false'; + } + } else { + $parts[] = '('.$code.')'; + } + } + + if (!$parts) { + return $this->conjunctive ? 'true' : 'false'; + } + + return $this->conjunctive ? implode('&&', $parts) : implode('||', $parts); + } + + /** + * @param ConstraintInterface $provider + * + * @return bool + */ + public function matches(ConstraintInterface $provider) + { + if (false === $this->conjunctive) { + foreach ($this->constraints as $constraint) { + if ($provider->matches($constraint)) { + return true; + } + } + + return false; + } + + // when matching a conjunctive and a disjunctive multi constraint we have to iterate over the disjunctive one + // otherwise we'd return true if different parts of the disjunctive constraint match the conjunctive one + // which would lead to incorrect results, e.g. [>1 and <2] would match [<1 or >2] although they do not intersect + if ($provider instanceof MultiConstraint && $provider->isDisjunctive()) { + return $provider->matches($this); + } + + foreach ($this->constraints as $constraint) { + if (!$provider->matches($constraint)) { + return false; + } + } + + return true; + } + + /** + * {@inheritDoc} + */ + public function setPrettyString($prettyString) + { + $this->prettyString = $prettyString; + } + + /** + * {@inheritDoc} + */ + public function getPrettyString() + { + if ($this->prettyString) { + return $this->prettyString; + } + + return (string) $this; + } + + /** + * {@inheritDoc} + */ + public function __toString() + { + if ($this->string !== null) { + return $this->string; + } + + $constraints = array(); + foreach ($this->constraints as $constraint) { + $constraints[] = (string) $constraint; + } + + return $this->string = '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']'; + } + + /** + * {@inheritDoc} + */ + public function getLowerBound() + { + $this->extractBounds(); + + if (null === $this->lowerBound) { + throw new \LogicException('extractBounds should have populated the lowerBound property'); + } + + return $this->lowerBound; + } + + /** + * {@inheritDoc} + */ + public function getUpperBound() + { + $this->extractBounds(); + + if (null === $this->upperBound) { + throw new \LogicException('extractBounds should have populated the upperBound property'); + } + + return $this->upperBound; + } + + /** + * Tries to optimize the constraints as much as possible, meaning + * reducing/collapsing congruent constraints etc. + * Does not necessarily return a MultiConstraint instance if + * things can be reduced to a simple constraint + * + * @param ConstraintInterface[] $constraints A set of constraints + * @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive + * + * @return ConstraintInterface + */ + public static function create(array $constraints, $conjunctive = true) + { + if (0 === \count($constraints)) { + return new MatchAllConstraint(); + } + + if (1 === \count($constraints)) { + return $constraints[0]; + } + + $optimized = self::optimizeConstraints($constraints, $conjunctive); + if ($optimized !== null) { + list($constraints, $conjunctive) = $optimized; + if (\count($constraints) === 1) { + return $constraints[0]; + } + } + + return new self($constraints, $conjunctive); + } + + /** + * @param ConstraintInterface[] $constraints + * @param bool $conjunctive + * @return ?array + * + * @phpstan-return array{0: list, 1: bool}|null + */ + private static function optimizeConstraints(array $constraints, $conjunctive) + { + // parse the two OR groups and if they are contiguous we collapse + // them into one constraint + // [>= 1 < 2] || [>= 2 < 3] || [>= 3 < 4] => [>= 1 < 4] + if (!$conjunctive) { + $left = $constraints[0]; + $mergedConstraints = array(); + $optimized = false; + for ($i = 1, $l = \count($constraints); $i < $l; $i++) { + $right = $constraints[$i]; + if ( + $left instanceof self + && $left->conjunctive + && $right instanceof self + && $right->conjunctive + && \count($left->constraints) === 2 + && \count($right->constraints) === 2 + && ($left0 = (string) $left->constraints[0]) + && $left0[0] === '>' && $left0[1] === '=' + && ($left1 = (string) $left->constraints[1]) + && $left1[0] === '<' + && ($right0 = (string) $right->constraints[0]) + && $right0[0] === '>' && $right0[1] === '=' + && ($right1 = (string) $right->constraints[1]) + && $right1[0] === '<' + && substr($left1, 2) === substr($right0, 3) + ) { + $optimized = true; + $left = new MultiConstraint( + array( + $left->constraints[0], + $right->constraints[1], + ), + true); + } else { + $mergedConstraints[] = $left; + $left = $right; + } + } + if ($optimized) { + $mergedConstraints[] = $left; + return array($mergedConstraints, false); + } + } + + // TODO: Here's the place to put more optimizations + + return null; + } + + /** + * @return void + */ + private function extractBounds() + { + if (null !== $this->lowerBound) { + return; + } + + foreach ($this->constraints as $constraint) { + if (null === $this->lowerBound || null === $this->upperBound) { + $this->lowerBound = $constraint->getLowerBound(); + $this->upperBound = $constraint->getUpperBound(); + continue; + } + + if ($constraint->getLowerBound()->compareTo($this->lowerBound, $this->isConjunctive() ? '>' : '<')) { + $this->lowerBound = $constraint->getLowerBound(); + } + + if ($constraint->getUpperBound()->compareTo($this->upperBound, $this->isConjunctive() ? '<' : '>')) { + $this->upperBound = $constraint->getUpperBound(); + } + } + } +} diff --git a/vendor/composer/semver/src/Interval.php b/vendor/composer/semver/src/Interval.php new file mode 100755 index 0000000..43d5a4f --- /dev/null +++ b/vendor/composer/semver/src/Interval.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver; + +use Composer\Semver\Constraint\Constraint; + +class Interval +{ + /** @var Constraint */ + private $start; + /** @var Constraint */ + private $end; + + public function __construct(Constraint $start, Constraint $end) + { + $this->start = $start; + $this->end = $end; + } + + /** + * @return Constraint + */ + public function getStart() + { + return $this->start; + } + + /** + * @return Constraint + */ + public function getEnd() + { + return $this->end; + } + + /** + * @return Constraint + */ + public static function fromZero() + { + static $zero; + + if (null === $zero) { + $zero = new Constraint('>=', '0.0.0.0-dev'); + } + + return $zero; + } + + /** + * @return Constraint + */ + public static function untilPositiveInfinity() + { + static $positiveInfinity; + + if (null === $positiveInfinity) { + $positiveInfinity = new Constraint('<', PHP_INT_MAX.'.0.0.0'); + } + + return $positiveInfinity; + } + + /** + * @return self + */ + public static function any() + { + return new self(self::fromZero(), self::untilPositiveInfinity()); + } + + /** + * @return array{'names': string[], 'exclude': bool} + */ + public static function anyDev() + { + // any == exclude nothing + return array('names' => array(), 'exclude' => true); + } + + /** + * @return array{'names': string[], 'exclude': bool} + */ + public static function noDev() + { + // nothing == no names included + return array('names' => array(), 'exclude' => false); + } +} diff --git a/vendor/composer/semver/src/Intervals.php b/vendor/composer/semver/src/Intervals.php new file mode 100755 index 0000000..f2e4c8c --- /dev/null +++ b/vendor/composer/semver/src/Intervals.php @@ -0,0 +1,478 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver; + +use Composer\Semver\Constraint\Constraint; +use Composer\Semver\Constraint\ConstraintInterface; +use Composer\Semver\Constraint\MatchAllConstraint; +use Composer\Semver\Constraint\MatchNoneConstraint; +use Composer\Semver\Constraint\MultiConstraint; + +/** + * Helper class generating intervals from constraints + * + * This contains utilities for: + * + * - compacting an existing constraint which can be used to combine several into one + * by creating a MultiConstraint out of the many constraints you have. + * + * - checking whether one subset is a subset of another. + * + * Note: You should call clear to free memoization memory usage when you are done using this class + */ +class Intervals +{ + /** + * @phpstan-var array + */ + private static $intervalsCache = array(); + + /** + * @phpstan-var array + */ + private static $opSortOrder = array( + '>=' => -3, + '<' => -2, + '>' => 2, + '<=' => 3, + ); + + /** + * Clears the memoization cache once you are done + * + * @return void + */ + public static function clear() + { + self::$intervalsCache = array(); + } + + /** + * Checks whether $candidate is a subset of $constraint + * + * @return bool + */ + public static function isSubsetOf(ConstraintInterface $candidate, ConstraintInterface $constraint) + { + if ($constraint instanceof MatchAllConstraint) { + return true; + } + + if ($candidate instanceof MatchNoneConstraint || $constraint instanceof MatchNoneConstraint) { + return false; + } + + $intersectionIntervals = self::get(new MultiConstraint(array($candidate, $constraint), true)); + $candidateIntervals = self::get($candidate); + if (\count($intersectionIntervals['numeric']) !== \count($candidateIntervals['numeric'])) { + return false; + } + + foreach ($intersectionIntervals['numeric'] as $index => $interval) { + if (!isset($candidateIntervals['numeric'][$index])) { + return false; + } + + if ((string) $candidateIntervals['numeric'][$index]->getStart() !== (string) $interval->getStart()) { + return false; + } + + if ((string) $candidateIntervals['numeric'][$index]->getEnd() !== (string) $interval->getEnd()) { + return false; + } + } + + if ($intersectionIntervals['branches']['exclude'] !== $candidateIntervals['branches']['exclude']) { + return false; + } + if (\count($intersectionIntervals['branches']['names']) !== \count($candidateIntervals['branches']['names'])) { + return false; + } + foreach ($intersectionIntervals['branches']['names'] as $index => $name) { + if ($name !== $candidateIntervals['branches']['names'][$index]) { + return false; + } + } + + return true; + } + + /** + * Checks whether $a and $b have any intersection, equivalent to $a->matches($b) + * + * @return bool + */ + public static function haveIntersections(ConstraintInterface $a, ConstraintInterface $b) + { + if ($a instanceof MatchAllConstraint || $b instanceof MatchAllConstraint) { + return true; + } + + if ($a instanceof MatchNoneConstraint || $b instanceof MatchNoneConstraint) { + return false; + } + + $intersectionIntervals = self::generateIntervals(new MultiConstraint(array($a, $b), true), true); + + return \count($intersectionIntervals['numeric']) > 0 || $intersectionIntervals['branches']['exclude'] || \count($intersectionIntervals['branches']['names']) > 0; + } + + /** + * Attempts to optimize a MultiConstraint + * + * When merging MultiConstraints together they can get very large, this will + * compact it by looking at the real intervals covered by all the constraints + * and then creates a new constraint containing only the smallest amount of rules + * to match the same intervals. + * + * @return ConstraintInterface + */ + public static function compactConstraint(ConstraintInterface $constraint) + { + if (!$constraint instanceof MultiConstraint) { + return $constraint; + } + + $intervals = self::generateIntervals($constraint); + $constraints = array(); + $hasNumericMatchAll = false; + + if (\count($intervals['numeric']) === 1 && (string) $intervals['numeric'][0]->getStart() === (string) Interval::fromZero() && (string) $intervals['numeric'][0]->getEnd() === (string) Interval::untilPositiveInfinity()) { + $constraints[] = $intervals['numeric'][0]->getStart(); + $hasNumericMatchAll = true; + } else { + $unEqualConstraints = array(); + for ($i = 0, $count = \count($intervals['numeric']); $i < $count; $i++) { + $interval = $intervals['numeric'][$i]; + + // if current interval ends with < N and next interval begins with > N we can swap this out for != N + // but this needs to happen as a conjunctive expression together with the start of the current interval + // and end of next interval, so [>=M, N, [>=M, !=N, getEnd()->getOperator() === '<' && $i+1 < $count) { + $nextInterval = $intervals['numeric'][$i+1]; + if ($interval->getEnd()->getVersion() === $nextInterval->getStart()->getVersion() && $nextInterval->getStart()->getOperator() === '>') { + // only add a start if we didn't already do so, can be skipped if we're looking at second + // interval in [>=M, N, P, =M, !=N] already and we only want to add !=P right now + if (\count($unEqualConstraints) === 0 && (string) $interval->getStart() !== (string) Interval::fromZero()) { + $unEqualConstraints[] = $interval->getStart(); + } + $unEqualConstraints[] = new Constraint('!=', $interval->getEnd()->getVersion()); + continue; + } + } + + if (\count($unEqualConstraints) > 0) { + // this is where the end of the following interval of a != constraint is added as explained above + if ((string) $interval->getEnd() !== (string) Interval::untilPositiveInfinity()) { + $unEqualConstraints[] = $interval->getEnd(); + } + + // count is 1 if entire constraint is just one != expression + if (\count($unEqualConstraints) > 1) { + $constraints[] = new MultiConstraint($unEqualConstraints, true); + } else { + $constraints[] = $unEqualConstraints[0]; + } + + $unEqualConstraints = array(); + continue; + } + + // convert back >= x - <= x intervals to == x + if ($interval->getStart()->getVersion() === $interval->getEnd()->getVersion() && $interval->getStart()->getOperator() === '>=' && $interval->getEnd()->getOperator() === '<=') { + $constraints[] = new Constraint('==', $interval->getStart()->getVersion()); + continue; + } + + if ((string) $interval->getStart() === (string) Interval::fromZero()) { + $constraints[] = $interval->getEnd(); + } elseif ((string) $interval->getEnd() === (string) Interval::untilPositiveInfinity()) { + $constraints[] = $interval->getStart(); + } else { + $constraints[] = new MultiConstraint(array($interval->getStart(), $interval->getEnd()), true); + } + } + } + + $devConstraints = array(); + + if (0 === \count($intervals['branches']['names'])) { + if ($intervals['branches']['exclude']) { + if ($hasNumericMatchAll) { + return new MatchAllConstraint; + } + // otherwise constraint should contain a != operator and already cover this + } + } else { + foreach ($intervals['branches']['names'] as $branchName) { + if ($intervals['branches']['exclude']) { + $devConstraints[] = new Constraint('!=', $branchName); + } else { + $devConstraints[] = new Constraint('==', $branchName); + } + } + + // excluded branches, e.g. != dev-foo are conjunctive with the interval, so + // > 2.0 != dev-foo must return a conjunctive constraint + if ($intervals['branches']['exclude']) { + if (\count($constraints) > 1) { + return new MultiConstraint(array_merge( + array(new MultiConstraint($constraints, false)), + $devConstraints + ), true); + } + + if (\count($constraints) === 1 && (string)$constraints[0] === (string)Interval::fromZero()) { + if (\count($devConstraints) > 1) { + return new MultiConstraint($devConstraints, true); + } + return $devConstraints[0]; + } + + return new MultiConstraint(array_merge($constraints, $devConstraints), true); + } + + // otherwise devConstraints contains a list of == operators for branches which are disjunctive with the + // rest of the constraint + $constraints = array_merge($constraints, $devConstraints); + } + + if (\count($constraints) > 1) { + return new MultiConstraint($constraints, false); + } + + if (\count($constraints) === 1) { + return $constraints[0]; + } + + return new MatchNoneConstraint; + } + + /** + * Creates an array of numeric intervals and branch constraints representing a given constraint + * + * if the returned numeric array is empty it means the constraint matches nothing in the numeric range (0 - +inf) + * if the returned branches array is empty it means no dev-* versions are matched + * if a constraint matches all possible dev-* versions, branches will contain Interval::anyDev() + * + * @return array + * @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}} + */ + public static function get(ConstraintInterface $constraint) + { + $key = (string) $constraint; + + if (!isset(self::$intervalsCache[$key])) { + self::$intervalsCache[$key] = self::generateIntervals($constraint); + } + + return self::$intervalsCache[$key]; + } + + /** + * @param bool $stopOnFirstValidInterval + * + * @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}} + */ + private static function generateIntervals(ConstraintInterface $constraint, $stopOnFirstValidInterval = false) + { + if ($constraint instanceof MatchAllConstraint) { + return array('numeric' => array(new Interval(Interval::fromZero(), Interval::untilPositiveInfinity())), 'branches' => Interval::anyDev()); + } + + if ($constraint instanceof MatchNoneConstraint) { + return array('numeric' => array(), 'branches' => array('names' => array(), 'exclude' => false)); + } + + if ($constraint instanceof Constraint) { + return self::generateSingleConstraintIntervals($constraint); + } + + if (!$constraint instanceof MultiConstraint) { + throw new \UnexpectedValueException('The constraint passed in should be an MatchAllConstraint, Constraint or MultiConstraint instance, got '.\get_class($constraint).'.'); + } + + $constraints = $constraint->getConstraints(); + + $numericGroups = array(); + $constraintBranches = array(); + foreach ($constraints as $c) { + $res = self::get($c); + $numericGroups[] = $res['numeric']; + $constraintBranches[] = $res['branches']; + } + + if ($constraint->isDisjunctive()) { + $branches = Interval::noDev(); + foreach ($constraintBranches as $b) { + if ($b['exclude']) { + if ($branches['exclude']) { + // disjunctive constraint, so only exclude what's excluded in all constraints + // !=a,!=b || !=b,!=c => !=b + $branches['names'] = array_intersect($branches['names'], $b['names']); + } else { + // disjunctive constraint so exclude all names which are not explicitly included in the alternative + // (==b || ==c) || !=a,!=b => !=a + $branches['exclude'] = true; + $branches['names'] = array_diff($b['names'], $branches['names']); + } + } else { + if ($branches['exclude']) { + // disjunctive constraint so exclude all names which are not explicitly included in the alternative + // !=a,!=b || (==b || ==c) => !=a + $branches['names'] = array_diff($branches['names'], $b['names']); + } else { + // disjunctive constraint, so just add all the other branches + // (==a || ==b) || ==c => ==a || ==b || ==c + $branches['names'] = array_merge($branches['names'], $b['names']); + } + } + } + } else { + $branches = Interval::anyDev(); + foreach ($constraintBranches as $b) { + if ($b['exclude']) { + if ($branches['exclude']) { + // conjunctive, so just add all branch names to be excluded + // !=a && !=b => !=a,!=b + $branches['names'] = array_merge($branches['names'], $b['names']); + } else { + // conjunctive, so only keep included names which are not excluded + // (==a||==c) && !=a,!=b => ==c + $branches['names'] = array_diff($branches['names'], $b['names']); + } + } else { + if ($branches['exclude']) { + // conjunctive, so only keep included names which are not excluded + // !=a,!=b && (==a||==c) => ==c + $branches['names'] = array_diff($b['names'], $branches['names']); + $branches['exclude'] = false; + } else { + // conjunctive, so only keep names that are included in both + // (==a||==b) && (==a||==c) => ==a + $branches['names'] = array_intersect($branches['names'], $b['names']); + } + } + } + } + + $branches['names'] = array_unique($branches['names']); + + if (\count($numericGroups) === 1) { + return array('numeric' => $numericGroups[0], 'branches' => $branches); + } + + $borders = array(); + foreach ($numericGroups as $group) { + foreach ($group as $interval) { + $borders[] = array('version' => $interval->getStart()->getVersion(), 'operator' => $interval->getStart()->getOperator(), 'side' => 'start'); + $borders[] = array('version' => $interval->getEnd()->getVersion(), 'operator' => $interval->getEnd()->getOperator(), 'side' => 'end'); + } + } + + $opSortOrder = self::$opSortOrder; + usort($borders, function ($a, $b) use ($opSortOrder) { + $order = version_compare($a['version'], $b['version']); + if ($order === 0) { + return $opSortOrder[$a['operator']] - $opSortOrder[$b['operator']]; + } + + return $order; + }); + + $activeIntervals = 0; + $intervals = array(); + $index = 0; + $activationThreshold = $constraint->isConjunctive() ? \count($numericGroups) : 1; + $start = null; + foreach ($borders as $border) { + if ($border['side'] === 'start') { + $activeIntervals++; + } else { + $activeIntervals--; + } + if (!$start && $activeIntervals >= $activationThreshold) { + $start = new Constraint($border['operator'], $border['version']); + } elseif ($start && $activeIntervals < $activationThreshold) { + // filter out invalid intervals like > x - <= x, or >= x - < x + if ( + version_compare($start->getVersion(), $border['version'], '=') + && ( + ($start->getOperator() === '>' && $border['operator'] === '<=') + || ($start->getOperator() === '>=' && $border['operator'] === '<') + ) + ) { + unset($intervals[$index]); + } else { + $intervals[$index] = new Interval($start, new Constraint($border['operator'], $border['version'])); + $index++; + + if ($stopOnFirstValidInterval) { + break; + } + } + + $start = null; + } + } + + return array('numeric' => $intervals, 'branches' => $branches); + } + + /** + * @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}}} + */ + private static function generateSingleConstraintIntervals(Constraint $constraint) + { + $op = $constraint->getOperator(); + + // handle branch constraints first + if (strpos($constraint->getVersion(), 'dev-') === 0) { + $intervals = array(); + $branches = array('names' => array(), 'exclude' => false); + + // != dev-foo means any numeric version may match, we treat >/< like != they are not really defined for branches + if ($op === '!=') { + $intervals[] = new Interval(Interval::fromZero(), Interval::untilPositiveInfinity()); + $branches = array('names' => array($constraint->getVersion()), 'exclude' => true); + } elseif ($op === '==') { + $branches['names'][] = $constraint->getVersion(); + } + + return array( + 'numeric' => $intervals, + 'branches' => $branches, + ); + } + + if ($op[0] === '>') { // > & >= + return array('numeric' => array(new Interval($constraint, Interval::untilPositiveInfinity())), 'branches' => Interval::noDev()); + } + if ($op[0] === '<') { // < & <= + return array('numeric' => array(new Interval(Interval::fromZero(), $constraint)), 'branches' => Interval::noDev()); + } + if ($op === '!=') { + // convert !=x to intervals of 0 - x - +inf + dev* + return array('numeric' => array( + new Interval(Interval::fromZero(), new Constraint('<', $constraint->getVersion())), + new Interval(new Constraint('>', $constraint->getVersion()), Interval::untilPositiveInfinity()), + ), 'branches' => Interval::anyDev()); + } + + // convert ==x to an interval of >=x - <=x + return array('numeric' => array( + new Interval(new Constraint('>=', $constraint->getVersion()), new Constraint('<=', $constraint->getVersion())), + ), 'branches' => Interval::noDev()); + } +} diff --git a/vendor/composer/semver/src/Semver.php b/vendor/composer/semver/src/Semver.php new file mode 100755 index 0000000..4d6de3c --- /dev/null +++ b/vendor/composer/semver/src/Semver.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver; + +use Composer\Semver\Constraint\Constraint; + +class Semver +{ + const SORT_ASC = 1; + const SORT_DESC = -1; + + /** @var VersionParser */ + private static $versionParser; + + /** + * Determine if given version satisfies given constraints. + * + * @param string $version + * @param string $constraints + * + * @return bool + */ + public static function satisfies($version, $constraints) + { + if (null === self::$versionParser) { + self::$versionParser = new VersionParser(); + } + + $versionParser = self::$versionParser; + $provider = new Constraint('==', $versionParser->normalize($version)); + $parsedConstraints = $versionParser->parseConstraints($constraints); + + return $parsedConstraints->matches($provider); + } + + /** + * Return all versions that satisfy given constraints. + * + * @param string[] $versions + * @param string $constraints + * + * @return string[] + */ + public static function satisfiedBy(array $versions, $constraints) + { + $versions = array_filter($versions, function ($version) use ($constraints) { + return Semver::satisfies($version, $constraints); + }); + + return array_values($versions); + } + + /** + * Sort given array of versions. + * + * @param string[] $versions + * + * @return string[] + */ + public static function sort(array $versions) + { + return self::usort($versions, self::SORT_ASC); + } + + /** + * Sort given array of versions in reverse. + * + * @param string[] $versions + * + * @return string[] + */ + public static function rsort(array $versions) + { + return self::usort($versions, self::SORT_DESC); + } + + /** + * @param string[] $versions + * @param int $direction + * + * @return string[] + */ + private static function usort(array $versions, $direction) + { + if (null === self::$versionParser) { + self::$versionParser = new VersionParser(); + } + + $versionParser = self::$versionParser; + $normalized = array(); + + // Normalize outside of usort() scope for minor performance increase. + // Creates an array of arrays: [[normalized, key], ...] + foreach ($versions as $key => $version) { + $normalizedVersion = $versionParser->normalize($version); + $normalizedVersion = $versionParser->normalizeDefaultBranch($normalizedVersion); + $normalized[] = array($normalizedVersion, $key); + } + + usort($normalized, function (array $left, array $right) use ($direction) { + if ($left[0] === $right[0]) { + return 0; + } + + if (Comparator::lessThan($left[0], $right[0])) { + return -$direction; + } + + return $direction; + }); + + // Recreate input array, using the original indexes which are now in sorted order. + $sorted = array(); + foreach ($normalized as $item) { + $sorted[] = $versions[$item[1]]; + } + + return $sorted; + } +} diff --git a/vendor/composer/semver/src/VersionParser.php b/vendor/composer/semver/src/VersionParser.php new file mode 100755 index 0000000..1754a76 --- /dev/null +++ b/vendor/composer/semver/src/VersionParser.php @@ -0,0 +1,584 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\Semver; + +use Composer\Semver\Constraint\ConstraintInterface; +use Composer\Semver\Constraint\MatchAllConstraint; +use Composer\Semver\Constraint\MultiConstraint; +use Composer\Semver\Constraint\Constraint; + +/** + * Version parser. + * + * @author Jordi Boggiano + */ +class VersionParser +{ + /** + * Regex to match pre-release data (sort of). + * + * Due to backwards compatibility: + * - Instead of enforcing hyphen, an underscore, dot or nothing at all are also accepted. + * - Only stabilities as recognized by Composer are allowed to precede a numerical identifier. + * - Numerical-only pre-release identifiers are not supported, see tests. + * + * |--------------| + * [major].[minor].[patch] -[pre-release] +[build-metadata] + * + * @var string + */ + private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?'; + + /** @var string */ + private static $stabilitiesRegex = 'stable|RC|beta|alpha|dev'; + + /** + * Returns the stability of a version. + * + * @param string $version + * + * @return string + * @phpstan-return 'stable'|'RC'|'beta'|'alpha'|'dev' + */ + public static function parseStability($version) + { + $version = (string) preg_replace('{#.+$}', '', $version); + + if (strpos($version, 'dev-') === 0 || '-dev' === substr($version, -4)) { + return 'dev'; + } + + preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match); + + if (!empty($match[3])) { + return 'dev'; + } + + if (!empty($match[1])) { + if ('beta' === $match[1] || 'b' === $match[1]) { + return 'beta'; + } + if ('alpha' === $match[1] || 'a' === $match[1]) { + return 'alpha'; + } + if ('rc' === $match[1]) { + return 'RC'; + } + } + + return 'stable'; + } + + /** + * @param string $stability + * + * @return string + */ + public static function normalizeStability($stability) + { + $stability = strtolower($stability); + + return $stability === 'rc' ? 'RC' : $stability; + } + + /** + * Normalizes a version string to be able to perform comparisons on it. + * + * @param string $version + * @param string $fullVersion optional complete version string to give more context + * + * @throws \UnexpectedValueException + * + * @return string + */ + public function normalize($version, $fullVersion = null) + { + $version = trim($version); + $origVersion = $version; + if (null === $fullVersion) { + $fullVersion = $version; + } + + // strip off aliasing + if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) { + $version = $match[1]; + } + + // strip off stability flag + if (preg_match('{@(?:' . self::$stabilitiesRegex . ')$}i', $version, $match)) { + $version = substr($version, 0, strlen($version) - strlen($match[0])); + } + + // normalize master/trunk/default branches to dev-name for BC with 1.x as these used to be valid constraints + if (\in_array($version, array('master', 'trunk', 'default'), true)) { + $version = 'dev-' . $version; + } + + // if requirement is branch-like, use full name + if (stripos($version, 'dev-') === 0) { + return 'dev-' . substr($version, 4); + } + + // strip off build metadata + if (preg_match('{^([^,\s+]++)\+[^\s]++$}', $version, $match)) { + $version = $match[1]; + } + + // match classical versioning + if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) { + $version = $matches[1] + . (!empty($matches[2]) ? $matches[2] : '.0') + . (!empty($matches[3]) ? $matches[3] : '.0') + . (!empty($matches[4]) ? $matches[4] : '.0'); + $index = 5; + // match date(time) based versioning + } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) { + $version = preg_replace('{\D}', '.', $matches[1]); + $index = 2; + } + + // add version modifiers if a version was matched + if (isset($index)) { + if (!empty($matches[$index])) { + if ('stable' === $matches[$index]) { + return $version; + } + $version .= '-' . $this->expandStability($matches[$index]) . (isset($matches[$index + 1]) && '' !== $matches[$index + 1] ? ltrim($matches[$index + 1], '.-') : ''); + } + + if (!empty($matches[$index + 2])) { + $version .= '-dev'; + } + + return $version; + } + + // match dev branches + if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) { + try { + $normalized = $this->normalizeBranch($match[1]); + // a branch ending with -dev is only valid if it is numeric + // if it gets prefixed with dev- it means the branch name should + // have had a dev- prefix already when passed to normalize + if (strpos($normalized, 'dev-') === false) { + return $normalized; + } + } catch (\Exception $e) { + } + } + + $extraMessage = ''; + if (preg_match('{ +as +' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))?$}', $fullVersion)) { + $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version'; + } elseif (preg_match('{^' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))? +as +}', $fullVersion)) { + $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-'; + } + + throw new \UnexpectedValueException('Invalid version string "' . $origVersion . '"' . $extraMessage); + } + + /** + * Extract numeric prefix from alias, if it is in numeric format, suitable for version comparison. + * + * @param string $branch Branch name (e.g. 2.1.x-dev) + * + * @return string|false Numeric prefix if present (e.g. 2.1.) or false + */ + public function parseNumericAliasPrefix($branch) + { + if (preg_match('{^(?P(\d++\\.)*\d++)(?:\.x)?-dev$}i', $branch, $matches)) { + return $matches['version'] . '.'; + } + + return false; + } + + /** + * Normalizes a branch name to be able to perform comparisons on it. + * + * @param string $name + * + * @return string + */ + public function normalizeBranch($name) + { + $name = trim($name); + + if (preg_match('{^v?(\d++)(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?$}i', $name, $matches)) { + $version = ''; + for ($i = 1; $i < 5; ++$i) { + $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x'; + } + + return str_replace('x', '9999999', $version) . '-dev'; + } + + return 'dev-' . $name; + } + + /** + * Normalizes a default branch name (i.e. master on git) to 9999999-dev. + * + * @param string $name + * + * @return string + */ + public function normalizeDefaultBranch($name) + { + if ($name === 'dev-master' || $name === 'dev-default' || $name === 'dev-trunk') { + return '9999999-dev'; + } + + return $name; + } + + /** + * Parses a constraint string into MultiConstraint and/or Constraint objects. + * + * @param string $constraints + * + * @return ConstraintInterface + */ + public function parseConstraints($constraints) + { + $prettyConstraint = $constraints; + + $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints)); + if (false === $orConstraints) { + throw new \RuntimeException('Failed to preg_split string: '.$constraints); + } + $orGroups = array(); + + foreach ($orConstraints as $constraints) { + $andConstraints = preg_split('{(?< ,]) *(? 1) { + $constraintObjects = array(); + foreach ($andConstraints as $constraint) { + foreach ($this->parseConstraint($constraint) as $parsedConstraint) { + $constraintObjects[] = $parsedConstraint; + } + } + } else { + $constraintObjects = $this->parseConstraint($andConstraints[0]); + } + + if (1 === \count($constraintObjects)) { + $constraint = $constraintObjects[0]; + } else { + $constraint = new MultiConstraint($constraintObjects); + } + + $orGroups[] = $constraint; + } + + $constraint = MultiConstraint::create($orGroups, false); + + $constraint->setPrettyString($prettyConstraint); + + return $constraint; + } + + /** + * @param string $constraint + * + * @throws \UnexpectedValueException + * + * @return array + * + * @phpstan-return non-empty-array + */ + private function parseConstraint($constraint) + { + // strip off aliasing + if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $constraint, $match)) { + $constraint = $match[1]; + } + + // strip @stability flags, and keep it for later use + if (preg_match('{^([^,\s]*?)@(' . self::$stabilitiesRegex . ')$}i', $constraint, $match)) { + $constraint = '' !== $match[1] ? $match[1] : '*'; + if ($match[2] !== 'stable') { + $stabilityModifier = $match[2]; + } + } + + // get rid of #refs as those are used by composer only + if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraint, $match)) { + $constraint = $match[1]; + } + + if (preg_match('{^(v)?[xX*](\.[xX*])*$}i', $constraint, $match)) { + if (!empty($match[1]) || !empty($match[2])) { + return array(new Constraint('>=', '0.0.0.0-dev')); + } + + return array(new MatchAllConstraint()); + } + + $versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?(?:' . self::$modifierRegex . '|\.([xX*][.-]?dev))(?:\+[^\s]+)?'; + + // Tilde Range + // + // Like wildcard constraints, unsuffixed tilde constraints say that they must be greater than the previous + // version, to ensure that unstable instances of the current version are allowed. However, if a stability + // suffix is added to the constraint, then a >= match on the current version is used instead. + if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) { + if (strpos($constraint, '~>') === 0) { + throw new \UnexpectedValueException( + 'Could not parse version constraint ' . $constraint . ': ' . + 'Invalid operator "~>", you probably meant to use the "~" operator' + ); + } + + // Work out which position in the version we are operating at + if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) { + $position = 4; + } elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) { + $position = 3; + } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) { + $position = 2; + } else { + $position = 1; + } + + // when matching 2.x-dev or 3.0.x-dev we have to shift the second or third number, despite no second/third number matching above + if (!empty($matches[8])) { + $position++; + } + + // Calculate the stability suffix + $stabilitySuffix = ''; + if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) { + $stabilitySuffix .= '-dev'; + } + + $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1)); + $lowerBound = new Constraint('>=', $lowVersion); + + // For upper bound, we increment the position of one more significance, + // but highPosition = 0 would be illegal + $highPosition = max(1, $position - 1); + $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev'; + $upperBound = new Constraint('<', $highVersion); + + return array( + $lowerBound, + $upperBound, + ); + } + + // Caret Range + // + // Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple. + // In other words, this allows patch and minor updates for versions 1.0.0 and above, patch updates for + // versions 0.X >=0.1.0, and no updates for versions 0.0.X + if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) { + // Work out which position in the version we are operating at + if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) { + $position = 1; + } elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) { + $position = 2; + } else { + $position = 3; + } + + // Calculate the stability suffix + $stabilitySuffix = ''; + if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) { + $stabilitySuffix .= '-dev'; + } + + $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1)); + $lowerBound = new Constraint('>=', $lowVersion); + + // For upper bound, we increment the position of one more significance, + // but highPosition = 0 would be illegal + $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev'; + $upperBound = new Constraint('<', $highVersion); + + return array( + $lowerBound, + $upperBound, + ); + } + + // X Range + // + // Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple. + // A partial version range is treated as an X-Range, so the special character is in fact optional. + if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) { + if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) { + $position = 3; + } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) { + $position = 2; + } else { + $position = 1; + } + + $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev'; + $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev'; + + if ($lowVersion === '0.0.0.0-dev') { + return array(new Constraint('<', $highVersion)); + } + + return array( + new Constraint('>=', $lowVersion), + new Constraint('<', $highVersion), + ); + } + + // Hyphen Range + // + // Specifies an inclusive set. If a partial version is provided as the first version in the inclusive range, + // then the missing pieces are replaced with zeroes. If a partial version is provided as the second version in + // the inclusive range, then all versions that start with the supplied parts of the tuple are accepted, but + // nothing that would be greater than the provided tuple parts. + if (preg_match('{^(?P' . $versionRegex . ') +- +(?P' . $versionRegex . ')($)}i', $constraint, $matches)) { + // Calculate the stability suffix + $lowStabilitySuffix = ''; + if (empty($matches[6]) && empty($matches[8]) && empty($matches[9])) { + $lowStabilitySuffix = '-dev'; + } + + $lowVersion = $this->normalize($matches['from']); + $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix); + + $empty = function ($x) { + return ($x === 0 || $x === '0') ? false : empty($x); + }; + + if ((!$empty($matches[12]) && !$empty($matches[13])) || !empty($matches[15]) || !empty($matches[17]) || !empty($matches[18])) { + $highVersion = $this->normalize($matches['to']); + $upperBound = new Constraint('<=', $highVersion); + } else { + $highMatch = array('', $matches[11], $matches[12], $matches[13], $matches[14]); + + // validate to version + $this->normalize($matches['to']); + + $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[12]) ? 1 : 2, 1) . '-dev'; + $upperBound = new Constraint('<', $highVersion); + } + + return array( + $lowerBound, + $upperBound, + ); + } + + // Basic Comparators + if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) { + try { + try { + $version = $this->normalize($matches[2]); + } catch (\UnexpectedValueException $e) { + // recover from an invalid constraint like foobar-dev which should be dev-foobar + // except if the constraint uses a known operator, in which case it must be a parse error + if (substr($matches[2], -4) === '-dev' && preg_match('{^[0-9a-zA-Z-./]+$}', $matches[2])) { + $version = $this->normalize('dev-'.substr($matches[2], 0, -4)); + } else { + throw $e; + } + } + + $op = $matches[1] ?: '='; + + if ($op !== '==' && $op !== '=' && !empty($stabilityModifier) && self::parseStability($version) === 'stable') { + $version .= '-' . $stabilityModifier; + } elseif ('<' === $op || '>=' === $op) { + if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) { + if (strpos($matches[2], 'dev-') !== 0) { + $version .= '-dev'; + } + } + } + + return array(new Constraint($matches[1] ?: '=', $version)); + } catch (\Exception $e) { + } + } + + $message = 'Could not parse version constraint ' . $constraint; + if (isset($e)) { + $message .= ': ' . $e->getMessage(); + } + + throw new \UnexpectedValueException($message); + } + + /** + * Increment, decrement, or simply pad a version number. + * + * Support function for {@link parseConstraint()} + * + * @param array $matches Array with version parts in array indexes 1,2,3,4 + * @param int $position 1,2,3,4 - which segment of the version to increment/decrement + * @param int $increment + * @param string $pad The string to pad version parts after $position + * + * @return string|null The new version + * + * @phpstan-param string[] $matches + */ + private function manipulateVersionString(array $matches, $position, $increment = 0, $pad = '0') + { + for ($i = 4; $i > 0; --$i) { + if ($i > $position) { + $matches[$i] = $pad; + } elseif ($i === $position && $increment) { + $matches[$i] += $increment; + // If $matches[$i] was 0, carry the decrement + if ($matches[$i] < 0) { + $matches[$i] = $pad; + --$position; + + // Return null on a carry overflow + if ($i === 1) { + return null; + } + } + } + } + + return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4]; + } + + /** + * Expand shorthand stability string to long version. + * + * @param string $stability + * + * @return string + */ + private function expandStability($stability) + { + $stability = strtolower($stability); + + switch ($stability) { + case 'a': + return 'alpha'; + case 'b': + return 'beta'; + case 'p': + case 'pl': + return 'patch'; + case 'rc': + return 'RC'; + default: + return $stability; + } + } +} diff --git a/vendor/defuse/php-encryption/LICENSE b/vendor/defuse/php-encryption/LICENSE new file mode 100755 index 0000000..f3e7c8e --- /dev/null +++ b/vendor/defuse/php-encryption/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Taylor Hornby and Paragon Initiative +Enterprises . + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/defuse/php-encryption/README.md b/vendor/defuse/php-encryption/README.md new file mode 100755 index 0000000..b16700a --- /dev/null +++ b/vendor/defuse/php-encryption/README.md @@ -0,0 +1,121 @@ +php-encryption +=============== + +[![Build Status](https://travis-ci.org/defuse/php-encryption.svg?branch=master)](https://travis-ci.org/defuse/php-encryption) +[![codecov](https://codecov.io/gh/defuse/php-encryption/branch/master/graph/badge.svg)](https://codecov.io/gh/defuse/php-encryption) +[![Latest Stable Version](https://poser.pugx.org/defuse/php-encryption/v/stable)](https://packagist.org/packages/defuse/php-encryption) +[![License](https://poser.pugx.org/defuse/php-encryption/license)](https://packagist.org/packages/defuse/php-encryption) +[![Downloads](https://img.shields.io/packagist/dt/defuse/php-encryption.svg)](https://packagist.org/packages/defuse/php-encryption) + +```terminal +composer require defuse/php-encryption +``` + +This is a library for encrypting data with a key or password in PHP. **It +requires PHP 5.6 or newer and OpenSSL 1.0.1 or newer.** We recommend using a +version of PHP that [still has security +support](https://www.php.net/supported-versions.php), which at the time of +writing means PHP 7.3 or later. Using this library with an unsupported +version of PHP could lead to security vulnerabilities. + +The current version of `php-encryption` is v2.3.1. This library is expected to +remain stable and supported by its authors with security and bugfixes until at +least January 1st, 2022. + +The library is a joint effort between [Taylor Hornby](https://defuse.ca/) and +[Scott Arciszewski](https://paragonie.com/blog/author/scott-arcizewski) as well +as numerous open-source contributors. + +What separates this library from other PHP encryption libraries is, firstly, +that it is secure. The authors used to encounter insecure PHP encryption code on +a daily basis, so they created this library to bring more security to the +ecosystem. Secondly, this library is "difficult to misuse." Like +[libsodium](https://github.com/jedisct1/libsodium), its API is designed to be +easy to use in a secure way and hard to use in an insecure way. + + +Dependencies +------------ + +This library requires no special dependencies except for PHP 5.6 or newer with +the OpenSSL extensions (version 1.0.1 or later) enabled (this is the default). +It uses [random\_compat](https://github.com/paragonie/random_compat), which is +bundled in with this library so that your users will not need to follow any +special installation steps. + +Getting Started +---------------- + +Start with the [**Tutorial**](docs/Tutorial.md). You can find instructions for +obtaining this library's code securely in the [Installing and +Verifying](docs/InstallingAndVerifying.md) documentation. + +After you've read the tutorial and got the code, refer to the formal +documentation for each of the classes this library provides: + +- [Crypto](docs/classes/Crypto.md) +- [File](docs/classes/File.md) +- [Key](docs/classes/Key.md) +- [KeyProtectedByPassword](docs/classes/KeyProtectedByPassword.md) + +If you encounter difficulties, see the [FAQ](docs/FAQ.md) answers. The fixes to +the most commonly-reported problems are explained there. + +If you're a cryptographer and want to understand the nitty-gritty details of how +this library works, look at the [Cryptography Details](docs/CryptoDetails.md) +documentation. + +If you're interested in contributing to this library, see the [Internal +Developer Documentation](docs/InternalDeveloperDocs.md). + +Other Language Support +---------------------- + +This library is intended for server-side PHP software that needs to encrypt data at rest. +If you are building software that needs to encrypt client-side, or building a system that +requires cross-platform encryption/decryption support, we strongly recommend using +[libsodium](https://download.libsodium.org/doc/bindings_for_other_languages) instead. + +Examples +--------- + +If the documentation is not enough for you to understand how to use this +library, then you can look at an example project that uses this library: + +- [encutil](https://github.com/defuse/encutil) +- [fileencrypt](https://github.com/tsusanka/fileencrypt) + +Security Audit Status +--------------------- + +This code has not been subjected to a formal, paid, security audit. However, it +has received lots of review from members of the PHP security community, and the +authors are experienced with cryptography. In all likelihood, you are safer +using this library than almost any other encryption library for PHP. + +If you use this library as a part of your business and would like to help fund +a formal audit, please [contact Taylor Hornby](https://defuse.ca/contact.htm). + +Public Keys +------------ + +The GnuPG public key used to sign current and older releases is available in +[dist/signingkey.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey.asc). Its fingerprint is: + +``` +2FA6 1D8D 99B9 2658 6BAC 3D53 385E E055 A129 1538 +``` + +You can verify it against Taylor Hornby's [contact +page](https://defuse.ca/contact.htm) and +[twitter](https://twitter.com/DefuseSec/status/723741424253059074). + +Due to the old key expiring, new releases will be signed with a new public key +available in [dist/signingkey-new.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey-new.asc). Its fingerprint is: + +``` +6DD6 E677 0281 5846 FC85 25A3 DD2E 507F 7BDB 1669 +``` + +A signature of this new key by the old key is available in +[dist/signingkey-new.asc.sig](https://github.com/defuse/php-encryption/raw/master/dist/signingkey-new.asc.sig). diff --git a/vendor/defuse/php-encryption/bin/generate-defuse-key b/vendor/defuse/php-encryption/bin/generate-defuse-key new file mode 100755 index 0000000..24e31b5 --- /dev/null +++ b/vendor/defuse/php-encryption/bin/generate-defuse-key @@ -0,0 +1,14 @@ +#!/usr/bin/env php +saveToAsciiSafeString(), "\n"; diff --git a/vendor/defuse/php-encryption/composer.json b/vendor/defuse/php-encryption/composer.json new file mode 100755 index 0000000..025f38d --- /dev/null +++ b/vendor/defuse/php-encryption/composer.json @@ -0,0 +1,34 @@ +{ + "name": "defuse/php-encryption", + "description": "Secure PHP Encryption Library", + "license": "MIT", + "keywords": ["security", "encryption", "AES", "openssl", "cipher", "cryptography", "symmetric key cryptography", "crypto", "encrypt", "authenticated encryption"], + "authors": [ + { + "name": "Taylor Hornby", + "email": "taylor@defuse.ca", + "homepage": "https://defuse.ca/" + }, + { + "name": "Scott Arciszewski", + "email": "info@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "autoload": { + "psr-4": { + "Defuse\\Crypto\\": "src" + } + }, + "require": { + "paragonie/random_compat": ">= 2", + "ext-openssl": "*", + "php": ">=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5|^6|^7|^8|^9" + }, + "bin": [ + "bin/generate-defuse-key" + ] +} diff --git a/vendor/defuse/php-encryption/dist/Makefile b/vendor/defuse/php-encryption/dist/Makefile new file mode 100755 index 0000000..833e479 --- /dev/null +++ b/vendor/defuse/php-encryption/dist/Makefile @@ -0,0 +1,39 @@ +# This builds defuse-crypto.phar. To run this Makefile, `box` and `composer` +# must be installed and in your $PATH. Run it from inside the dist/ directory. + +box := $(shell which box) +composer := $(shell which composer) +gitcommit := $(shell git rev-parse HEAD) + +.PHONY: all +all: build-phar + +.PHONY: sign-phar +sign-phar: + gpg -u DD2E507F7BDB1669 --armor --output defuse-crypto.phar.sig --detach-sig defuse-crypto.phar + +# ensure we run in clean tree. export git tree and run there. +.PHONY: build-phar +build-phar: + @echo "Creating .phar from revision $(shell git rev-parse HEAD)." + rm -rf worktree + install -d worktree + (cd $(CURDIR)/..; git archive HEAD) | tar -x -C worktree + $(MAKE) -f $(CURDIR)/Makefile -C worktree defuse-crypto.phar + mv worktree/*.phar . + rm -rf worktree + +.PHONY: clean +clean: + rm -vf defuse-crypto.phar defuse-crypto.phar.sig + +# Inside workdir/: + +defuse-crypto.phar: dist/box.json composer.lock + cp dist/box.json . + php -d phar.readonly=0 $(box) build -c box.json -v + +composer.lock: + $(composer) config autoloader-suffix $(gitcommit) + $(composer) install --no-dev + diff --git a/vendor/defuse/php-encryption/dist/box.json b/vendor/defuse/php-encryption/dist/box.json new file mode 100755 index 0000000..f225f78 --- /dev/null +++ b/vendor/defuse/php-encryption/dist/box.json @@ -0,0 +1,25 @@ +{ + "chmod": "0755", + "finder": [ + { + "in": "src", + "name": "*.php" + }, + { + "in": "vendor/composer", + "name": "*.php" + }, + { + "in": "vendor/paragonie", + "name": "*.php", + "exclude": "other" + } + ], + "compactors": [ + "Herrera\\Box\\Compactor\\Php" + ], + "main": "vendor/autoload.php", + "output": "defuse-crypto.phar", + "shebang": false, + "stub": true +} diff --git a/vendor/defuse/php-encryption/dist/signingkey-new.asc b/vendor/defuse/php-encryption/dist/signingkey-new.asc new file mode 100755 index 0000000..7e3a4a1 --- /dev/null +++ b/vendor/defuse/php-encryption/dist/signingkey-new.asc @@ -0,0 +1,53 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBF5V4TABEAC4G2BkHDaqbip3gj1oOqKh3V6LQa9QAd/f/hyhmR5hXpciPxf3 +NNHAxzoGAuB51f1YPJTNO59mGKHDuCFfr0pI94HDGoW4WgxqnUyqHBj2+/JhQPqO +lgDT0QDcfxmUd0wfZl/Ur+8SsaBYvfFWNmPaXHp9m4MMRtw9uZNIW6LlZ24JqmGy +/YUELUSH7P+uJ4HQEdixaqQ0VgIomRDI+5IwdJMtq4TSNazQm3nNmH9Em37cdi6J +NDfFRy2QxJDmuqlg8mkpS5TvrrNy/UJwIeXO9PuGaBODr8GAKWvhkpfGlxN+hWMY +01bOFnuEnOcuXw8BjPAKHqwOuGvinNmQ7lX1Rj3ssd31sTUimop0oNjOTZztpJBR +m6wO2/YGMjt+eL02NgBBDIsV837PeWuJmymTJDGQuBjZ3JWUfyT3AnkA8OU5vKjs +pM8AjIiuU7C8zQhUSHDnukTKWpBmMdOXeWNb5Ye6n60wJWzWFGlm+cYalPs+q3H8 +bxHxHEdFT0rUpxB05bc9zsZ3gGkc2NTNW/00a6gvTyX1UsBAeNgvVSHBHQGfow6o +ZKG+LnVxd+cl97ay6kP29eLypXffbXQ3hMXe9tUNBjAeiok9tssU70Epr9wTh/Fm +/iEbGc8VhS4TSk3c+3eS16rvlQ51FmAlmG6kAnN/ah+BiM4syPrWcJHIDQARAQAB +tG1kZWZ1c2UvcGhwLWVuY3J5cHRpb24gbWFpbnRhaW5lcnMgKGRlZnVzZS9waHAt +ZW5jcnlwdGlvbiByZWxlYXNlIHNpZ25pbmcga2V5KSA8cGhwLWVuY3J5cHRpb25A +ZGVmdXNlLmludmFsaWQ+iQJUBBMBCAA+FiEEbdbmdwKBWEb8hSWj3S5Qf3vbFmkF +Al5V4TACGwMFCQlmAYAFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ3S5Qf3vb +FmnQ4Q//bHAwDI7CcTlDDktdRCP0YCRtb5zMa6vSqnZLi5aTqzmL1yQCAp1/JTwf +nlHn5xt60eKwfjIKj7Kj0n8WDFYnlOu30H5fNtFHis0xeS7GkH60tIE/pQUZILlB +Wcnx/ZPnlxccjtfSbnpelSPdvIoHVRNhh1ZYG/49kuuv8TMbMIi2FBAzGEatPoLN +f4wntoOKGvl8R2rPc2geapXTz++X+HJkddHCISR61obDRl9P0t9x+0M7gGSVMGfC +GC4wh3JB6/ha8l+DI+l88/64IKRG+M33bBwLGQ0RIhotHIy442gLJTm6TeoH8iUz +xCBwPYW+Ta1wZi17PIjHdTkNGBeEj/Hr5tTVV3oxrQVgHCymzasnz9IwcCCMwpKK +ZOMFl0+PT3TSBKLnUByvOB64YOjxU7t+sRf53Biz3yKzto5VdHGW64OG2vGFy/Xz +vI5RqU34wjtEHxWfz8y2GBnhD2TzEFCIIWPAX3TDG64NBSEBjhUraOmoVoaYJlP6 +rqxIQo4yhC+f5rnr2ZA48Hnrg0jEdVvN07FegoOnQQPpYBBkOrkTDWChn8oiXMfg +9bjv19zDOBVXl9EU+P8AhwTHz/pBKmhb97N9nYp/pbmejA+I0Kw1vZo7gaMxL938 +oQkdtWT70ZzcpcZfeKVXoZa/ddAmuxzNknZA8ZnjQ9Qhv7aNX2O5Ag0EXlXhMAEQ +AM8od4/85i7ZPmM6C1M4n4XcXeKsuZKHLvLLcRHFGkjVdXRSaxpbk2yDJiLnB9hX +GSJG2gUCT+yrimjQ71bJ4q9K2+mkVHVjdtCrCtoOYEIpMLzsRtqyAWotcVmdv8Zv +4IIjxfdxpTkj9gZmUfDIe6tbN2iBCAo1HArXq1qSdof3ui8SqdWeinkd7lZMesFm +dGQaAcHbmEakO5mRzljme8IBs3UY9j/zxEG1JbsHx9ua7CVwJ7lxi2SgSW6nF9k5 +CX5zbrDqlqSJNtDs+KbjCbI2eK+qe4qZWHPiw4bNBn6EWf97/4Os8w7Vrrpyd2eO +1JENwjlG6WG9mbJdIWWwakZ0CeH5LnJo6dV47KZbbbB6ncavaL+VpfbTCgdOGsCc +GcYUVl90/v5pPm2owx4Dg9hSfcp8fesQuq4b79NAcjF7meu5wgNdvFlfuXony+UC +W2wNi0mi9lzLD0n0j0GDzWyd3r7yXmPTL4LhrQu/pIcWIljKI3GUAQZqIYbGAO3G +7hEFT8rDWg2vKRtMag4iy5FvZFqR+7TwWJAcWnHJBZ95F9NzeYIFhp9a3hxbKXqD +xEnyGgzAszUycq29BApT4/4rDZQuXuOBd4lJp8tSzctLjvo7D3la+MWD6AlDkYT4 +bGKN9NfRCzYr2Zq3jOByAV3d5hGgyzdJlZSqXAGtbHHdABEBAAGJAjwEGAEIACYW +IQRt1uZ3AoFYRvyFJaPdLlB/e9sWaQUCXlXhMAIbDAUJCWYBgAAKCRDdLlB/e9sW +aSGfD/wPeq6lGu8ocHIkO74VPioJRKRXDVLsY02xKP64p0RHUGFTOqqB3A3UV0ue +tkizoUdfF5xkgJ18gbxXo8lotBq+Ita5hoYAfqJnTnucAPGovREJ+X1HfdK4pJqW +KNJElBz+fC4chqksiUAuH7IMImmy0/lA+LqZagzkQJU10MvmiFZ6kn+X5Mb4izRl +vAHo16eI4psApdT8Bs7mwAjgCHxS9Re46uOElB4Bx3iFPd/PEwHWnfr8x9TJZYKW +fsShG31+vfBRCfGtfKGxiAkp3EEM11lzbbfMcC3lai5iJQ/FmHgoIDeIG2Ebuk4w +/PYakSrpvkEYoMP31pVHDhzopVeURS2lpvQJ4CvTP5CVQtKrbuygow6GF8N/drCE +hdEx22pzW02ADS9fgzrlDztIOlOvC9a+epISIaEjfrc9dWhrw6chZEoWIil2MVQR +Sj0jZ8w/H7P88oHTOcFVel73ZEPg9eRUkqMnIn3DWUuqLI2SX/AtVnhdYHWTiOkq +knsGofWxUSu3RZR2ZElK9hjNKdVbGDzHGAYeJihieTKIOXpCf6Ix5B32tmFpfmBV +Q9YP3JLsRTxIMbXsJImand/r6fSjdmTpk2PovYPtE1HTJKaVHeagQdsrWw5LaJv0 +ZWuwJm0y0WJXcAEjwOHhBs0nvq2CXuZi2ZTPtY+DbsSFWhaN7g== +=Ysgx +-----END PGP PUBLIC KEY BLOCK----- diff --git a/vendor/defuse/php-encryption/dist/signingkey-new.asc.sig b/vendor/defuse/php-encryption/dist/signingkey-new.asc.sig new file mode 100755 index 0000000..56e1f3a Binary files /dev/null and b/vendor/defuse/php-encryption/dist/signingkey-new.asc.sig differ diff --git a/vendor/defuse/php-encryption/dist/signingkey.asc b/vendor/defuse/php-encryption/dist/signingkey.asc new file mode 100755 index 0000000..63b6aa3 --- /dev/null +++ b/vendor/defuse/php-encryption/dist/signingkey.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +mQINBFarvO4BEACdQBaLt6SUBx1cB5liUu1qo+YwVLh9bxTregQtmEREMdTVqXYt +e5b79uL4pQp2GlKHcEyRURS+6rIIruM0oh9ZYGTJYPAkCDzJxaU2awZeFbfBvpCm +iF66/O4ZJI4mlT8dFKmxBJxDhfeOR2UmmhDiEsJK9FxBKUzvo/dWrX2pBzf8Y122 +iIaVraSo+tymaf7vriaIf/NnSKhDw8dtQYGM4NMrxxsPTfbCF8XiboDgTkoD2A+6 +NpOJYxA4Veedsf2TP9YLhljH4m5yYlfjjqBzbBCPWuE6Hhy5Xze9mncgDr7LKenm +Ctf2NxW6y4O3RCI+9eLlBfFWB+KuGV87/b5daetX7NNLbjID8z2rqEa+d6wu5xA5 +Ta2uiVkAOEovr3XnkayZ9zth+Za7w7Ai0ln0N/LVMkM+Gu4z/pJv6HjmTGDM2wJb +fs+UOM0TFdg+N81Do67XT2M4o0MeHyUqsIiWpYa2Qf1PNmqTQNJnRk8uZZ9I96Nh +eCgNuCbhsQiYBMicox+xmuWAlGAfA06y0kCtmqGhiBGArdJlWvUqPqGiZ4Hln9z0 +FJmXDOh0Q/FIPxcDg8mKRRbx+lOP389PLsPpj4b2B/4PEgfpCCOwuKpLotATZxC1 +9JwFk0Y/cvUUkq4a+nAJBNtBbtRJkEesuuUnRq6XexmnE3uUucDcV0XCSwARAQAB +tCBUYXlsb3IgSG9ybmJ5IDx0YXlsb3JAZGVmdXNlLmNhPokCPQQTAQgAJwUCVqu8 +7gIbAwUJB4TOAAULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRA4XuBVoSkVOJbx +EACG0F9blPMAsK05EWyNnnS4mw25zPfbaqqEvYbquAeM0nBpRDm7sRn2MNR0AL4g +7XrtxE/4qYkdEl6f2wFCQeRhZgxE3w22llredzLme11Hic8hn4i7ysdIw0r9dMMR +kjgR5UcWpv8iU847czyK09PkKW2EaLRbX2qbA7rNU5qCFKeD4Sy4bBTteISeVsHo +Vr9o1/bRrMhgZ++ts8hYf0LmujIf5cxp+qcdKwCXSnS/gmmXaKRMCPv/Wdlq9bt6 +LX9jZB9lXBdGxcBJeFOsTG+QRDiVjg3d6i3o3TAKV87ALBI4v2ADEYtN8lviHo3/ +SovVKv6zrUsZHxhoGiLTiksNrYsKMmiMxdJCoOazmtUPnZ4UOtT8NdqMPoKvdoRz +f4rhZ+f5jSVD9OuX2PDmfyq21Rdiym7Vcgr+uTIFJ3ShRHjWb/ytCwoB2FeGY6+G +AKY58bTQvUIqEJvSov/+TAqZ4BfOuSdTLcHglV1OdUu2SFZvU2gmyVp0l5elGv5t +FyUlBJUkQT9MtvsdLOR7vQi8QapV+9LWpqwvaj9hyEJz848DQ2sdYTphUytFHv7H +k58DAtVhTrVjHyeefjiYtMl6vSAgTjy5LWAUpo5TfhdGrAi0Tdd/GD7amHoWoDy8 +EKXKq2xPLo3JOdkWYQUi5NErzEskfsSzpCOgyDJmGetWK7kCDQRWq7zuARAAu7/i +cm8cjgLhHEX/bgfwOT2hLOLSjjve0O8YFSuJO9XqIHXqmfVOrqWtfG0Mh4bwlfqc +MAvBfF5NSSPfAE4ftBAQ1e5jEv8hJeqICpq3IHTFX4etBs49NfNkyveQl/amVTu1 ++/O5J4CuIcsEf3y0Xuu38n7EB3SfMQCWLcOR1NyZoX3bI+CGRpOVVoFse3ljSWL4 +LhLVl0WiEMXULsussEoN+c6x9KCyAi/jFOrxrTrFC//sZesKj6KucoqKGfwMWrrv +IeRT9Ga8Wn5MJnQu0aWg+zVVYqTedXZLNLODgQIInFnXO0seBXy15yDok1y5bkx2 +sinKg4+mueYaGUpoUti0hM3J3yaC34i6Cwa8MQoLNw1JIS/oNtKjpMxyV10w8aoc +PHRK3n7UYp10mJHx7aM+lldSKvVS1NTQmI4vloNLwMp324H5ANDFAlRUz7mysVnu +DEEvigPSPxs5ZYENu/i7pCQC5qHfhrlBrQwTjhegr0pQPcumy2fO5SGC9l/5B7ev +bqQSZmDeWWoTvh2w2wl5/RWAsgZKx6rDtkCqYx7sSBY17uorrxP24LP4zhq7NxRV +nfdsLogbCFNVQ66u7qvq5zFccdFtg9h1HQWdS7wbnKSBGZoo5gl6js7GGtxfGbb0 +oQ9kp6eciF4U92r6POhVgbRe4CfPo50nqgZBddkAEQEAAYkCJQQYAQgADwUCVqu8 +7gIbDAUJB4TOAAAKCRA4XuBVoSkVOFJ8D/9J8IJ4XWUU3FYIaHJ3XeSoxDmTi7d5 +WmNdf1lmwz82MQjG4uw17oCbvQzmj4/a/CM1Ly4v0WwBhUf9aiNErD0ByHASFnuc +tlQBLVJdk0vRyD0fZakGg64qCA76hiySjMhlGHkQFyP2mDORc2GNu/OqFGm79pXT +ZUplXxd431E603/agM5xJrweutMMpP1nBFTSEMJvbMNzDVN8I1A1CH4zVmAVxOUk +sQ5L5rXW+KeXWyiMF24+l2CMnkQ2CxfHpkcpfPJs1Cbt+TIBSSofIqK8QJXrb/2f +Zpl/ftqW7Xe86rJFrB/Y/77LDWx10rqWEvfCqrBxrMj7ONAQfbKQF/IjAwDN17Wf +1K74rqKnRu+KHCyNM89s1iDbQC9kzZfzYt4AEOvAH/ZQDMZffzPSbnfkBerExFpa +93XMuiR66jiBsf9IXIQeydpJD4Ogl2sSUSxFEJxJ/bBSxPxC5w7/BVMA7Am1y8Zo +3hrpqnX2PBzxG7L0FZ6fYkfR3p8JS7vI6nByBf2IDv8W32wn43olPf+u6uobHLvt +ttapOjwPAhPDalRuxs9U6WSg06QJkT/0F8TFUPWpsFmKTl+G4Ty7PHWsjeeNHJCL +7/5RQboFY3k8Jy3/sIofABO6Un9LJivDuu9PxqA0IgvaS6Mja8JdCCk9Nyk4vHB7 +IEgAL/CYqrk38w== +=lmD7 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/vendor/defuse/php-encryption/docs/CryptoDetails.md b/vendor/defuse/php-encryption/docs/CryptoDetails.md new file mode 100755 index 0000000..43abd72 --- /dev/null +++ b/vendor/defuse/php-encryption/docs/CryptoDetails.md @@ -0,0 +1,64 @@ +Cryptography Details +===================== + +Here is a high-level description of how this library works. Any discrepancy +between this documentation and the actual implementation will be considered +a security bug. + +Let's start with the following definitions: + +- HKDF-SHA256(*k*, *n*, *info*, *s*) is the key derivation function specified in + RFC 5869 (using the SHA256 hash function). The parameters are: + - *k*: The initial keying material. + - *n*: The number of output bytes. + - *info*: The info string. + - *s*: The salt. +- AES-256-CTR(*m*, *k*, *iv*) is AES-256 encryption in CTR mode. The parameters + are: + - *m*: An arbitrary-length (possibly zero-length) message. + - *k*: A 32-byte key. + - *iv*: A 16-byte initialization vector (nonce). +- PBKDF2-SHA256(*p*, *s*, *i*, *n*) is the password-based key derivation + function defined in RFC 2898 (using the SHA256 hash function). The parameters + are: + - *p*: The password string. + - *s*: The salt string. + - *i*: The iteration count. + - *n*: The output length in bytes. +- VERSION is the string `"\xDE\xF5\x02\x00"`. +- AUTHINFO is the string `"DefusePHP|V2|KeyForAuthentication"`. +- ENCRINFO is the string `"DefusePHP|V2|KeyForEncryption"`. + +To encrypt a message *m* using a 32-byte key *k*, the following steps are taken: + +1. Generate a random 32-byte string *salt*. +2. Derive the 32-byte authentication key *akey* = HKDF-SHA256(*k*, 32, AUTHINFO, *salt*). +3. Derive the 32-byte encryption key *ekey* = HKDF-SHA256(*k*, 32, ENCRINFO, *salt*). +4. Generate a random 16-byte initialization vector *iv*. +5. Compute *c* = AES-256-CTR(*m*, *ekey*, *iv*). +6. Combine *ctxt* = VERSION || *salt* || *iv* || *c*. +7. Compute *h* = HMAC-SHA256(*ctxt*, *akey*). +8. Output *ctxt* || *h*. + +Decryption is roughly the reverse process (see the code for details, since the +security of the decryption routine is highly implementation-dependent). + +For encryption using a password *p*, steps 1-3 above are replaced by: + +1. Generate a random 32-byte string *salt*. +2. Compute *k* = PBKDF2-SHA256(SHA256(*p*), *salt*, 100000, 32). +3. Derive the 32-byte authentication key *akey* = HKDF-SHA256(*k*, 32, AUTHINFO, *salt*) +4. Derive the 32-byte encryption key *ekey* = HKDF-SHA256(*k*, 32, ENCRINFO, *salt*) + +The remainder of the process is the same. Notice the reuse of the same *salt* +for PBKDF2-SHA256 and HKDF-SHA256. The prehashing of the password in step 2 is +done to prevent a [DoS attack using long +passwords](https://github.com/defuse/php-encryption/issues/230). + +For `KeyProtectedByPassword`, the serialized key is encrypted according to the +password encryption defined above. However, the actual password used for +encryption is the SHA256 hash of the password the user provided. This is done in +order to provide domain separation between the message encryption in the user's +application and the internal key encryption done by this library. It fixes +a [key replacement chosen-protocol +attack](https://github.com/defuse/php-encryption/issues/240). diff --git a/vendor/defuse/php-encryption/docs/FAQ.md b/vendor/defuse/php-encryption/docs/FAQ.md new file mode 100755 index 0000000..9f77392 --- /dev/null +++ b/vendor/defuse/php-encryption/docs/FAQ.md @@ -0,0 +1,51 @@ +Frequently Asked Questions +=========================== + +How do I use this library to encrypt passwords? +------------------------------------------------ + +Passwords should not be encrypted, they should be hashed with a *slow* password +hashing function that's designed to slow down password guessing attacks. See +[How to Safely Store Your Users' Passwords in +2016](https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016). + +How do I give it the same key every time instead of a new random key? +---------------------------------------------------------------------- + +A `Key` object can be saved to a string by calling its `saveToAsciiSafeString()` +method. You will have to save that string somewhere safe, and then load it back +into a `Key` object using `Key`'s `loadFromAsciiSafeString` static method. + +Where you store the string depends on your application. For example if you are +using `KeyProtectedByPassword` to encrypt files with a user's login password, +then you should not store the `Key` at all. If you are protecting sensitive data +on a server that may be compromised, then you should store it in a hardware +security module. When in doubt, consult a security expert. + +Why is an EnvironmentIsBrokenException getting thrown? +------------------------------------------------------- + +Either you've encountered a bug in this library, or your system doesn't support +the use of this library. For example, if your system does not have a secure +random number generator, this library will refuse to run, by throwing that +exception, instead of falling back to an insecure random number generator. + +Why am I getting a BadFormatException when loading a Key from a string? +------------------------------------------------------------------------ + +If you're getting this exception, then the string you're giving to +`loadFromAsciiSafeString()` is *not* the same as the string you got from +`saveToAsciiSafeString()`. Perhaps your database column isn't wide enough and +it's truncating the string as you insert it? + +Does encrypting hide the length of the plaintext? +-------------------------------------------------- + +Encryption does not, and is not intended to, hide the length of the data being +encrypted. For example, it is not safe to encrypt a field in which only a small +number of different-length values are possible (e.g. "male" or "female") since +it would be possible to tell what the plaintext is by looking at the length of +the ciphertext. In order to do this safely, it is your responsibility to, before +encrypting, pad the data out to the length of the longest string that will ever +be encrypted. This way, all plaintexts are the same length, and no information +about the plaintext can be gleaned from the length of the ciphertext. diff --git a/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md b/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md new file mode 100755 index 0000000..12b5fee --- /dev/null +++ b/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md @@ -0,0 +1,53 @@ +Getting The Code +================= + +There are two ways to use this library in your applications. You can either: + +1. Use [Composer](https://getcomposer.org/), or +2. `require_once` a single `.phar` file in your application. + +If you are not using either option (for example, because you're using Git submodules), you may need to write your own autoloader ([example](https://gist.github.com/paragonie-scott/949daee819bb7f19c50e5e103170b400)). + +Option 1: Using Composer +------------------------- + +Run this inside the directory of your composer-enabled project: + +```sh +composer require defuse/php-encryption +``` + +Unfortunately, composer doesn't provide a way for you to verify that the code +you're getting was signed by this library's authors. If you want a more secure +option, use the `.phar` method described below. + +Option 2: Including a PHAR +---------------------------- + +The `.phar` option lets you include this library into your project simply by +calling `require_once` on a single file. Download `defuse-crypto.phar` and +`defuse-crypto.phar.sig` from this project's +[releases](https://github.com/defuse/php-encryption/releases) page. + +You should verify the integrity of the `.phar`. The `defuse-crypto.phar.sig` +contains the signature of `defuse-crypto.phar`. It is signed with Taylor +Hornby's PGP key. You can find Taylor's public key in `dist/signingkey.asc`. You +can verify the public key's fingerprint against the Taylor Hornby's [contact +page](https://defuse.ca/contact.htm) and +[twitter](https://twitter.com/DefuseSec/status/723741424253059074). + +Once you have verified the signature, it is safe to use the `.phar`. Place it +somewhere in your file system, e.g. `/var/www/lib/defuse-crypto.phar`, and then +pass that path to `require_once`. + +```php + Whenever there is a conflict between security and some other property, + > security will be favored. For example, the library has runtime tests, + > which make it slower, but will hopefully stop it from encrypting stuff + > if the platform it's running on is broken. + +- Rule #2: It should be difficult to misuse the library. + + > We assume the developers using this library have no experience with + > cryptography. We only assume that they know that the "key" is something + > you need to encrypt and decrypt the messages, and that it must be kept + > secret. Whenever possible, the library should refuse to encrypt or decrypt + > messages when it is not being used correctly. + +- Rule #3: The library aims only to be compatible with itself. + + > Other PHP encryption libraries try to support every possible type of + > encryption, even the insecure ones (e.g. ECB mode). Because there are so + > many options, inexperienced developers must decide whether to use "CBC + > mode" or "ECB mode" when both are meaningless terms to them. This + > inevitably leads to vulnerabilities. + + > This library will only support one secure mode. A developer using this + > library will call "encrypt" and "decrypt" methods without worrying about + > how they are implemented. + +- Rule #4: The library should require no special installation. + + > Some PHP encryption libraries, like libsodium-php, are not straightforward + > to install and cannot packaged with "just download and extract" + > applications. This library will always be just a handful of PHP files that + > you can copy to your source tree and require(). + +Publishing Releases +-------------------- + +To make a release, you will need to install [composer](https://getcomposer.org/) +and [box](https://github.com/box-project/box2) on your system. They will need to +be available in your `$PATH` so that running the commands `composer` and `box` +in your terminal run them, respectively. You will also need the private key for +signing (ID: 7B4B2D98) available. + +Once you have those tools installed and the key available follow these steps: + +**Remember to set the version number in `composer.json`!** + +Make a fresh clone of the repository: + +``` +git clone +``` + +Check out the branch you want to release: + +``` +git checkout +``` + +Check that the version number in composer.json is correct: + +``` +cat composer.json +``` + +Check that the version number and support lifetime in README.md are correct: + +``` +cat README.md +``` + +Run the tests: + +``` +composer install +./test.sh +``` + +Generate the `.phar`: + +``` +cd dist +make build-phar +``` + +Test the `.phar`: + +``` +cd ../ +./test.sh dist/defuse-crypto.phar +``` + +Sign the `.phar`: + +``` +cd dist +make sign-phar +``` + +Tag the release: + +``` +git -c user.signingkey=DD2E507F7BDB1669 tag -s "" -m "" +``` + +`` should be in the format `v2.0.0` and `` should look +like "Release of v2.0.0." + +Push the tag to github, then use the +[releases](https://github.com/defuse/php-encryption/releases) page to draft +a new release for that tag. Upload the `.phar` and the `.phar.sig` file to be +included as part of that release. diff --git a/vendor/defuse/php-encryption/docs/Tutorial.md b/vendor/defuse/php-encryption/docs/Tutorial.md new file mode 100755 index 0000000..a40cac3 --- /dev/null +++ b/vendor/defuse/php-encryption/docs/Tutorial.md @@ -0,0 +1,314 @@ +Tutorial +========= + +Hello! If you're reading this file, it's because you want to add encryption to +one of your PHP projects. My job, as the person writing this documentation, is +to help you make sure you're doing the right thing and then show you how to use +this library to do it. To help me help you, please read the documentation +*carefully* and *deliberately*. + +A Word of Caution +------------------ + +Encryption is not magic dust you can sprinkle on a system to make it more +secure. The way encryption is integrated into a system's design needs to be +carefully thought out. Sometimes, encryption is the wrong thing to use. Other +times, encryption needs to be used in a very specific way in order for it to +work as intended. Even if you are sure of what you are doing, we strongly +recommend seeking advice from an expert. + +The first step is to think about your application's threat model. Ask yourself +the following questions. Who will want to attack my application, and what will +they get out of it? Are they trying to steal some information? Trying to alter +or destroy some information? Or just trying to make the system go down so people +can't access it? Then ask yourself how encryption can help combat those threats. +If you're going to add encryption to your application, you should have a very +clear idea of exactly which kinds of attacks it's helping to secure your +application against. Once you have your threat model, think about what kinds of +attacks it *does not* cover, and whether or not you should improve your threat +model to include those attacks. + +**This isn't for storing user login passwords:** The most common use of +cryptography in web applications is to protect the users' login passwords. If +you're trying to use this library to "encrypt" your users' passwords, you're in +the wrong place. Passwords shouldn't be *encrypted*, they should be *hashed* +with a slow computation-heavy function that makes password guessing attacks more +expensive. See [How to Safely Store Your Users' Passwords in +2016](https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016). + +**This isn't for encrypting network communication:** Likewise, if you're trying +to encrypt messages sent between two parties over the Internet, you don't want +to be using this library. For that, set up a TLS connection between the two +points, or, if it's a chat app, use the [Signal +Protocol](https://whispersystems.org/blog/advanced-ratcheting/). + +What this library provides is symmetric encryption for "data at rest." This +means it is not suitable for use in building protocols where "data is in motion" +(i.e. moving over a network) except in limited set of cases. + +Please note that **encryption does not, and is not intended to, hide the +*length* of the data being encrypted.** For example, it is not safe to encrypt +a field in which only a small number of different-length values are possible +(e.g. "male" or "female") since it would be possible to tell what the plaintext +is by looking at the length of the ciphertext. In order to do this safely, it is +your responsibility to, before encrypting, pad the data out to the length of the +longest string that will ever be encrypted. This way, all plaintexts are the +same length, and no information about the plaintext can be gleaned from the +length of the ciphertext. + +Getting the Code +----------------- + +There are several different ways to obtain this library's code and to add it to +your project. Even if you've already cloned the code from GitHub, you should +take steps to verify the cryptographic signatures to make sure the code you got +was not intercepted and modified by an attacker. + +Please head over to the [**Installing and +Verifying**](InstallingAndVerifying.md) documentation to get the code, and then +come back here to continue the tutorial. + +Using the Library +------------------ + +I'm going to assume you know what symmetric encryption is, and the difference +between symmetric and asymmetric encryption. If you don't, I recommend taking +[Dan Boneh's Cryptography I course](https://www.coursera.org/learn/crypto/) on +Coursera. + +To give you a quick introduction to the library, I'm going to explain how it +would be used in two sterotypical scenarios. Hopefully, one of these sterotypes +is close enough to what you want to do that you'll be able to figure out what +needs to be different on your own. + +### Formal Documentation + +While this tutorial should get you up and running fast, it's important to +understand how this library behaves. Please make sure to read the formal +documentation of all of the functions you're using, since there are some +important security warnings there. + +The following classes are available for you to use: + +- [Crypto](classes/Crypto.md): Encrypting and decrypting strings. +- [File](classes/File.md): Encrypting and decrypting files. +- [Key](classes/Key.md): Represents a secret encryption key. +- [KeyProtectedByPassword](classes/KeyProtectedByPassword.md): Represents + a secret encryption key that needs to be "unlocked" by a password before it + can be used. + +### Scenario #1: Keep data secret from the database administrator + +In this scenario, our threat model is as follows. Alice is a server +administrator responsible for managing a trusted web server. Eve is a database +administrator responsible for managing a database server. Dave is a web +developer working on code that will eventually run on the trusted web server. + +Let's say Alice and Dave trust each other, and Alice is going to host Dave's +application on her server. But both Alice and Dave don't trust Eve. They know +Eve is a good database administrator, but she might have incentive to steal the +data from the database. They want to keep some of the web application's data +secret from Eve. + +In order to do that, Alice will use the included `generate-defuse-key` script +which generates a random encryption key and prints it to standard output: + +```sh +$ composer require defuse/php-encryption +$ vendor/bin/generate-defuse-key +``` + +Alice will run this script once and save the output to a configuration file, say +in `/etc/daveapp-secret-key.txt` and set the file permissions so that only the +user that the website PHP scripts run as can access it. + +Dave will write his code to load the key from the configuration file: + +```php +saveToAsciiSafeString(); + // ... save $protected_key_encoded into the user's account record +} +``` + +**WARNING:** Because of the way `KeyProtectedByPassword` is implemented, knowing +`SHA256($password)` is enough to decrypt a `KeyProtectedByPassword`. To be +secure, your application MUST NOT EVER compute `SHA256($password)` and use or +store it for any reason. You must also make sure that other libraries your +application is using don't compute it either. + +Then, when the user logs in, Dave's code will load the protected key from the +user's account record, unlock it to get a `Key` object, and save the `Key` +object somewhere safe (like temporary memory-backed session storage or +a cookie). Note that wherever Dave's code saves the key, it must be destroyed +once the user logs out, or else the attacker might be able to find users' keys +even if they were never logged in during the attack. + +```php +unlockKey($password); +$user_key_encoded = $user_key->saveToAsciiSafeString(); +// ... save $user_key_encoded in a cookie +``` + +```php + 0, + 'Trying to increment a nonce by a nonpositive amount' + ); + + Core::ensureTrue( + $inc <= PHP_INT_MAX - 255, + 'Integer overflow may occur' + ); + + /* + * We start at the rightmost byte (big-endian) + * So, too, does OpenSSL: http://stackoverflow.com/a/3146214/2224584 + */ + for ($i = Core::BLOCK_BYTE_SIZE - 1; $i >= 0; --$i) { + $sum = \ord($ctr[$i]) + $inc; + + /* Detect integer overflow and fail. */ + Core::ensureTrue(\is_int($sum), 'Integer overflow in CTR mode nonce increment'); + + $ctr[$i] = \pack('C', $sum & 0xFF); + $inc = $sum >> 8; + } + return $ctr; + } + + /** + * Returns a random byte string of the specified length. + * + * @param int $octets + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + public static function secureRandom($octets) + { + self::ensureFunctionExists('random_bytes'); + try { + return \random_bytes($octets); + } catch (\Exception $ex) { + throw new Ex\EnvironmentIsBrokenException( + 'Your system does not have a secure random number generator.' + ); + } + } + + /** + * Computes the HKDF key derivation function specified in + * http://tools.ietf.org/html/rfc5869. + * + * @param string $hash Hash Function + * @param string $ikm Initial Keying Material + * @param int $length How many bytes? + * @param string $info What sort of key are we deriving? + * @param string $salt + * + * @throws Ex\EnvironmentIsBrokenException + * @psalm-suppress UndefinedFunction - We're checking if the function exists first. + * + * @return string + */ + public static function HKDF($hash, $ikm, $length, $info = '', $salt = null) + { + static $nativeHKDF = null; + if ($nativeHKDF === null) { + $nativeHKDF = \is_callable('\\hash_hkdf'); + } + if ($nativeHKDF) { + if (\is_null($salt)) { + $salt = ''; + } + return \hash_hkdf($hash, $ikm, $length, $info, $salt); + } + + $digest_length = Core::ourStrlen(\hash_hmac($hash, '', '', true)); + + // Sanity-check the desired output length. + Core::ensureTrue( + !empty($length) && \is_int($length) && $length >= 0 && $length <= 255 * $digest_length, + 'Bad output length requested of HDKF.' + ); + + // "if [salt] not provided, is set to a string of HashLen zeroes." + if (\is_null($salt)) { + $salt = \str_repeat("\x00", $digest_length); + } + + // HKDF-Extract: + // PRK = HMAC-Hash(salt, IKM) + // The salt is the HMAC key. + $prk = \hash_hmac($hash, $ikm, $salt, true); + + // HKDF-Expand: + + // This check is useless, but it serves as a reminder to the spec. + Core::ensureTrue(Core::ourStrlen($prk) >= $digest_length); + + // T(0) = '' + $t = ''; + $last_block = ''; + for ($block_index = 1; Core::ourStrlen($t) < $length; ++$block_index) { + // T(i) = HMAC-Hash(PRK, T(i-1) | info | 0x??) + $last_block = \hash_hmac( + $hash, + $last_block . $info . \chr($block_index), + $prk, + true + ); + // T = T(1) | T(2) | T(3) | ... | T(N) + $t .= $last_block; + } + + // ORM = first L octets of T + /** @var string $orm */ + $orm = Core::ourSubstr($t, 0, $length); + Core::ensureTrue(\is_string($orm)); + return $orm; + } + + /** + * Checks if two equal-length strings are the same without leaking + * information through side channels. + * + * @param string $expected + * @param string $given + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return bool + */ + public static function hashEquals($expected, $given) + { + static $native = null; + if ($native === null) { + $native = \function_exists('hash_equals'); + } + if ($native) { + return \hash_equals($expected, $given); + } + + // We can't just compare the strings with '==', since it would make + // timing attacks possible. We could use the XOR-OR constant-time + // comparison algorithm, but that may not be a reliable defense in an + // interpreted language. So we use the approach of HMACing both strings + // with a random key and comparing the HMACs. + + // We're not attempting to make variable-length string comparison + // secure, as that's very difficult. Make sure the strings are the same + // length. + Core::ensureTrue(Core::ourStrlen($expected) === Core::ourStrlen($given)); + + $blind = Core::secureRandom(32); + $message_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $given, $blind); + $correct_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $expected, $blind); + return $correct_compare === $message_compare; + } + /** + * Throws an exception if the constant doesn't exist. + * + * @param string $name + * @return void + * + * @throws Ex\EnvironmentIsBrokenException + */ + public static function ensureConstantExists($name) + { + Core::ensureTrue( + \defined($name), + 'Constant '.$name.' does not exists' + ); + } + + /** + * Throws an exception if the function doesn't exist. + * + * @param string $name + * @return void + * + * @throws Ex\EnvironmentIsBrokenException + */ + public static function ensureFunctionExists($name) + { + Core::ensureTrue( + \function_exists($name), + 'function '.$name.' does not exists' + ); + } + + /** + * Throws an exception if the condition is false. + * + * @param bool $condition + * @param string $message + * @return void + * + * @throws Ex\EnvironmentIsBrokenException + */ + public static function ensureTrue($condition, $message = '') + { + if (!$condition) { + throw new Ex\EnvironmentIsBrokenException($message); + } + } + + /* + * We need these strlen() and substr() functions because when + * 'mbstring.func_overload' is set in php.ini, the standard strlen() and + * substr() are replaced by mb_strlen() and mb_substr(). + */ + + /** + * Computes the length of a string in bytes. + * + * @param string $str + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return int + */ + public static function ourStrlen($str) + { + static $exists = null; + if ($exists === null) { + $exists = \extension_loaded('mbstring') && \ini_get('mbstring.func_overload') !== false && (int)\ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING; + } + if ($exists) { + $length = \mb_strlen($str, '8bit'); + Core::ensureTrue($length !== false); + return $length; + } else { + return \strlen($str); + } + } + + /** + * Behaves roughly like the function substr() in PHP 7 does. + * + * @param string $str + * @param int $start + * @param int $length + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string|bool + */ + public static function ourSubstr($str, $start, $length = null) + { + static $exists = null; + if ($exists === null) { + $exists = \extension_loaded('mbstring') && \ini_get('mbstring.func_overload') !== false && (int)\ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING; + } + + // This is required to make mb_substr behavior identical to substr. + // Without this, mb_substr() would return false, contra to what the + // PHP documentation says (it doesn't say it can return false.) + $input_len = Core::ourStrlen($str); + if ($start === $input_len && !$length) { + return ''; + } + + if ($start > $input_len) { + return false; + } + + // mb_substr($str, 0, NULL, '8bit') returns an empty string on PHP 5.3, + // so we have to find the length ourselves. Also, substr() doesn't + // accept null for the length. + if (! isset($length)) { + if ($start >= 0) { + $length = $input_len - $start; + } else { + $length = -$start; + } + } + + if ($length < 0) { + throw new \InvalidArgumentException( + "Negative lengths are not supported with ourSubstr." + ); + } + + if ($exists) { + $substr = \mb_substr($str, $start, $length, '8bit'); + // At this point there are two cases where mb_substr can + // legitimately return an empty string. Either $length is 0, or + // $start is equal to the length of the string (both mb_substr and + // substr return an empty string when this happens). It should never + // ever return a string that's longer than $length. + if (Core::ourStrlen($substr) > $length || (Core::ourStrlen($substr) === 0 && $length !== 0 && $start !== $input_len)) { + throw new Ex\EnvironmentIsBrokenException( + 'Your version of PHP has bug #66797. Its implementation of + mb_substr() is incorrect. See the details here: + https://bugs.php.net/bug.php?id=66797' + ); + } + return $substr; + } + + return \substr($str, $start, $length); + } + + /** + * Computes the PBKDF2 password-based key derivation function. + * + * The PBKDF2 function is defined in RFC 2898. Test vectors can be found in + * RFC 6070. This implementation of PBKDF2 was originally created by Taylor + * Hornby, with improvements from http://www.variations-of-shadow.com/. + * + * @param string $algorithm The hash algorithm to use. Recommended: SHA256 + * @param string $password The password. + * @param string $salt A salt that is unique to the password. + * @param int $count Iteration count. Higher is better, but slower. Recommended: At least 1000. + * @param int $key_length The length of the derived key in bytes. + * @param bool $raw_output If true, the key is returned in raw binary format. Hex encoded otherwise. + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string A $key_length-byte key derived from the password and salt. + */ + public static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false) + { + // Type checks: + if (! \is_string($algorithm)) { + throw new \InvalidArgumentException( + 'pbkdf2(): algorithm must be a string' + ); + } + if (! \is_string($password)) { + throw new \InvalidArgumentException( + 'pbkdf2(): password must be a string' + ); + } + if (! \is_string($salt)) { + throw new \InvalidArgumentException( + 'pbkdf2(): salt must be a string' + ); + } + // Coerce strings to integers with no information loss or overflow + $count += 0; + $key_length += 0; + + $algorithm = \strtolower($algorithm); + Core::ensureTrue( + \in_array($algorithm, \hash_algos(), true), + 'Invalid or unsupported hash algorithm.' + ); + + // Whitelist, or we could end up with people using CRC32. + $ok_algorithms = [ + 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', + 'ripemd160', 'ripemd256', 'ripemd320', 'whirlpool', + ]; + Core::ensureTrue( + \in_array($algorithm, $ok_algorithms, true), + 'Algorithm is not a secure cryptographic hash function.' + ); + + Core::ensureTrue($count > 0 && $key_length > 0, 'Invalid PBKDF2 parameters.'); + + if (\function_exists('hash_pbkdf2')) { + // The output length is in NIBBLES (4-bits) if $raw_output is false! + if (! $raw_output) { + $key_length = $key_length * 2; + } + return \hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output); + } + + $hash_length = Core::ourStrlen(\hash($algorithm, '', true)); + $block_count = \ceil($key_length / $hash_length); + + $output = ''; + for ($i = 1; $i <= $block_count; $i++) { + // $i encoded as 4 bytes, big endian. + $last = $salt . \pack('N', $i); + // first iteration + $last = $xorsum = \hash_hmac($algorithm, $last, $password, true); + // perform the other $count - 1 iterations + for ($j = 1; $j < $count; $j++) { + /** + * @psalm-suppress InvalidOperand + */ + $xorsum ^= ($last = \hash_hmac($algorithm, $last, $password, true)); + } + $output .= $xorsum; + } + + if ($raw_output) { + return (string) Core::ourSubstr($output, 0, $key_length); + } else { + return Encoding::binToHex((string) Core::ourSubstr($output, 0, $key_length)); + } + } +} diff --git a/vendor/defuse/php-encryption/src/Crypto.php b/vendor/defuse/php-encryption/src/Crypto.php new file mode 100755 index 0000000..86eb204 --- /dev/null +++ b/vendor/defuse/php-encryption/src/Crypto.php @@ -0,0 +1,445 @@ +deriveKeys($salt); + $ekey = $keys->getEncryptionKey(); + $akey = $keys->getAuthenticationKey(); + $iv = Core::secureRandom(Core::BLOCK_BYTE_SIZE); + + $ciphertext = Core::CURRENT_VERSION . $salt . $iv . self::plainEncrypt($plaintext, $ekey, $iv); + $auth = \hash_hmac(Core::HASH_FUNCTION_NAME, $ciphertext, $akey, true); + $ciphertext = $ciphertext . $auth; + + if ($raw_binary) { + return $ciphertext; + } + return Encoding::binToHex($ciphertext); + } + + /** + * Decrypts a ciphertext to a string with either a key or a password. + * + * @param string $ciphertext + * @param KeyOrPassword $secret + * @param bool $raw_binary + * + * @throws Ex\EnvironmentIsBrokenException + * @throws Ex\WrongKeyOrModifiedCiphertextException + * + * @return string + */ + private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw_binary) + { + RuntimeTests::runtimeTest(); + + if (! $raw_binary) { + try { + $ciphertext = Encoding::hexToBin($ciphertext); + } catch (Ex\BadFormatException $ex) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Ciphertext has invalid hex encoding.' + ); + } + } + + if (Core::ourStrlen($ciphertext) < Core::MINIMUM_CIPHERTEXT_SIZE) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Ciphertext is too short.' + ); + } + + // Get and check the version header. + /** @var string $header */ + $header = Core::ourSubstr($ciphertext, 0, Core::HEADER_VERSION_SIZE); + if ($header !== Core::CURRENT_VERSION) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Bad version header.' + ); + } + + // Get the salt. + /** @var string $salt */ + $salt = Core::ourSubstr( + $ciphertext, + Core::HEADER_VERSION_SIZE, + Core::SALT_BYTE_SIZE + ); + Core::ensureTrue(\is_string($salt)); + + // Get the IV. + /** @var string $iv */ + $iv = Core::ourSubstr( + $ciphertext, + Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE, + Core::BLOCK_BYTE_SIZE + ); + Core::ensureTrue(\is_string($iv)); + + // Get the HMAC. + /** @var string $hmac */ + $hmac = Core::ourSubstr( + $ciphertext, + Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE, + Core::MAC_BYTE_SIZE + ); + Core::ensureTrue(\is_string($hmac)); + + // Get the actual encrypted ciphertext. + /** @var string $encrypted */ + $encrypted = Core::ourSubstr( + $ciphertext, + Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + + Core::BLOCK_BYTE_SIZE, + Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE - + Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE + ); + Core::ensureTrue(\is_string($encrypted)); + + // Derive the separate encryption and authentication keys from the key + // or password, whichever it is. + $keys = $secret->deriveKeys($salt); + + if (self::verifyHMAC($hmac, $header . $salt . $iv . $encrypted, $keys->getAuthenticationKey())) { + $plaintext = self::plainDecrypt($encrypted, $keys->getEncryptionKey(), $iv, Core::CIPHER_METHOD); + return $plaintext; + } else { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Integrity check failed.' + ); + } + } + + /** + * Raw unauthenticated encryption (insecure on its own). + * + * @param string $plaintext + * @param string $key + * @param string $iv + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + protected static function plainEncrypt($plaintext, $key, $iv) + { + Core::ensureConstantExists('OPENSSL_RAW_DATA'); + Core::ensureFunctionExists('openssl_encrypt'); + /** @var string $ciphertext */ + $ciphertext = \openssl_encrypt( + $plaintext, + Core::CIPHER_METHOD, + $key, + OPENSSL_RAW_DATA, + $iv + ); + + Core::ensureTrue(\is_string($ciphertext), 'openssl_encrypt() failed'); + + return $ciphertext; + } + + /** + * Raw unauthenticated decryption (insecure on its own). + * + * @param string $ciphertext + * @param string $key + * @param string $iv + * @param string $cipherMethod + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + protected static function plainDecrypt($ciphertext, $key, $iv, $cipherMethod) + { + Core::ensureConstantExists('OPENSSL_RAW_DATA'); + Core::ensureFunctionExists('openssl_decrypt'); + + /** @var string $plaintext */ + $plaintext = \openssl_decrypt( + $ciphertext, + $cipherMethod, + $key, + OPENSSL_RAW_DATA, + $iv + ); + Core::ensureTrue(\is_string($plaintext), 'openssl_decrypt() failed.'); + + return $plaintext; + } + + /** + * Verifies an HMAC without leaking information through side-channels. + * + * @param string $expected_hmac + * @param string $message + * @param string $key + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return bool + */ + protected static function verifyHMAC($expected_hmac, $message, $key) + { + $message_hmac = \hash_hmac(Core::HASH_FUNCTION_NAME, $message, $key, true); + return Core::hashEquals($message_hmac, $expected_hmac); + } +} diff --git a/vendor/defuse/php-encryption/src/DerivedKeys.php b/vendor/defuse/php-encryption/src/DerivedKeys.php new file mode 100755 index 0000000..86a48e5 --- /dev/null +++ b/vendor/defuse/php-encryption/src/DerivedKeys.php @@ -0,0 +1,50 @@ +akey; + } + + /** + * Returns the encryption key. + * @return string + */ + public function getEncryptionKey() + { + return $this->ekey; + } + + /** + * Constructor for DerivedKeys. + * + * @param string $akey + * @param string $ekey + */ + public function __construct($akey, $ekey) + { + $this->akey = $akey; + $this->ekey = $ekey; + } +} diff --git a/vendor/defuse/php-encryption/src/Encoding.php b/vendor/defuse/php-encryption/src/Encoding.php new file mode 100755 index 0000000..30a60a8 --- /dev/null +++ b/vendor/defuse/php-encryption/src/Encoding.php @@ -0,0 +1,269 @@ +> 4; + $hex .= \pack( + 'CC', + 87 + $b + ((($b - 10) >> 8) & ~38), + 87 + $c + ((($c - 10) >> 8) & ~38) + ); + } + return $hex; + } + + /** + * Converts a hexadecimal string into a byte string without leaking + * information through side channels. + * + * @param string $hex_string + * + * @throws Ex\BadFormatException + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + * @psalm-suppress TypeDoesNotContainType + */ + public static function hexToBin($hex_string) + { + $hex_pos = 0; + $bin = ''; + $hex_len = Core::ourStrlen($hex_string); + $state = 0; + $c_acc = 0; + + while ($hex_pos < $hex_len) { + $c = \ord($hex_string[$hex_pos]); + $c_num = $c ^ 48; + $c_num0 = ($c_num - 10) >> 8; + $c_alpha = ($c & ~32) - 55; + $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8; + if (($c_num0 | $c_alpha0) === 0) { + throw new Ex\BadFormatException( + 'Encoding::hexToBin() input is not a hex string.' + ); + } + $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0); + if ($state === 0) { + $c_acc = $c_val * 16; + } else { + $bin .= \pack('C', $c_acc | $c_val); + } + $state ^= 1; + ++$hex_pos; + } + return $bin; + } + + /** + * Remove trialing whitespace without table look-ups or branches. + * + * Calling this function may leak the length of the string as well as the + * number of trailing whitespace characters through side-channels. + * + * @param string $string + * @return string + */ + public static function trimTrailingWhitespace($string = '') + { + $length = Core::ourStrlen($string); + if ($length < 1) { + return ''; + } + do { + $prevLength = $length; + $last = $length - 1; + $chr = \ord($string[$last]); + + /* Null Byte (0x00), a.k.a. \0 */ + // if ($chr === 0x00) $length -= 1; + $sub = (($chr - 1) >> 8 ) & 1; + $length -= $sub; + $last -= $sub; + + /* Horizontal Tab (0x09) a.k.a. \t */ + $chr = \ord($string[$last]); + // if ($chr === 0x09) $length -= 1; + $sub = (((0x08 - $chr) & ($chr - 0x0a)) >> 8) & 1; + $length -= $sub; + $last -= $sub; + + /* New Line (0x0a), a.k.a. \n */ + $chr = \ord($string[$last]); + // if ($chr === 0x0a) $length -= 1; + $sub = (((0x09 - $chr) & ($chr - 0x0b)) >> 8) & 1; + $length -= $sub; + $last -= $sub; + + /* Carriage Return (0x0D), a.k.a. \r */ + $chr = \ord($string[$last]); + // if ($chr === 0x0d) $length -= 1; + $sub = (((0x0c - $chr) & ($chr - 0x0e)) >> 8) & 1; + $length -= $sub; + $last -= $sub; + + /* Space */ + $chr = \ord($string[$last]); + // if ($chr === 0x20) $length -= 1; + $sub = (((0x1f - $chr) & ($chr - 0x21)) >> 8) & 1; + $length -= $sub; + } while ($prevLength !== $length && $length > 0); + return (string) Core::ourSubstr($string, 0, $length); + } + + /* + * SECURITY NOTE ON APPLYING CHECKSUMS TO SECRETS: + * + * The checksum introduces a potential security weakness. For example, + * suppose we apply a checksum to a key, and that an adversary has an + * exploit against the process containing the key, such that they can + * overwrite an arbitrary byte of memory and then cause the checksum to + * be verified and learn the result. + * + * In this scenario, the adversary can extract the key one byte at + * a time by overwriting it with their guess of its value and then + * asking if the checksum matches. If it does, their guess was right. + * This kind of attack may be more easy to implement and more reliable + * than a remote code execution attack. + * + * This attack also applies to authenticated encryption as a whole, in + * the situation where the adversary can overwrite a byte of the key + * and then cause a valid ciphertext to be decrypted, and then + * determine whether the MAC check passed or failed. + * + * By using the full SHA256 hash instead of truncating it, I'm ensuring + * that both ways of going about the attack are equivalently difficult. + * A shorter checksum of say 32 bits might be more useful to the + * adversary as an oracle in case their writes are coarser grained. + * + * Because the scenario assumes a serious vulnerability, we don't try + * to prevent attacks of this style. + */ + + /** + * INTERNAL USE ONLY: Applies a version header, applies a checksum, and + * then encodes a byte string into a range of printable ASCII characters. + * + * @param string $header + * @param string $bytes + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + public static function saveBytesToChecksummedAsciiSafeString($header, $bytes) + { + // Headers must be a constant length to prevent one type's header from + // being a prefix of another type's header, leading to ambiguity. + Core::ensureTrue( + Core::ourStrlen($header) === self::SERIALIZE_HEADER_BYTES, + 'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.' + ); + + return Encoding::binToHex( + $header . + $bytes . + \hash( + self::CHECKSUM_HASH_ALGO, + $header . $bytes, + true + ) + ); + } + + /** + * INTERNAL USE ONLY: Decodes, verifies the header and checksum, and returns + * the encoded byte string. + * + * @param string $expected_header + * @param string $string + * + * @throws Ex\EnvironmentIsBrokenException + * @throws Ex\BadFormatException + * + * @return string + */ + public static function loadBytesFromChecksummedAsciiSafeString($expected_header, $string) + { + // Headers must be a constant length to prevent one type's header from + // being a prefix of another type's header, leading to ambiguity. + Core::ensureTrue( + Core::ourStrlen($expected_header) === self::SERIALIZE_HEADER_BYTES, + 'Header must be 4 bytes.' + ); + + /* If you get an exception here when attempting to load from a file, first pass your + key to Encoding::trimTrailingWhitespace() to remove newline characters, etc. */ + $bytes = Encoding::hexToBin($string); + + /* Make sure we have enough bytes to get the version header and checksum. */ + if (Core::ourStrlen($bytes) < self::SERIALIZE_HEADER_BYTES + self::CHECKSUM_BYTE_SIZE) { + throw new Ex\BadFormatException( + 'Encoded data is shorter than expected.' + ); + } + + /* Grab the version header. */ + $actual_header = (string) Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES); + + if ($actual_header !== $expected_header) { + throw new Ex\BadFormatException( + 'Invalid header.' + ); + } + + /* Grab the bytes that are part of the checksum. */ + $checked_bytes = (string) Core::ourSubstr( + $bytes, + 0, + Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE + ); + + /* Grab the included checksum. */ + $checksum_a = (string) Core::ourSubstr( + $bytes, + Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE, + self::CHECKSUM_BYTE_SIZE + ); + + /* Re-compute the checksum. */ + $checksum_b = \hash(self::CHECKSUM_HASH_ALGO, $checked_bytes, true); + + /* Check if the checksum matches. */ + if (! Core::hashEquals($checksum_a, $checksum_b)) { + throw new Ex\BadFormatException( + "Data is corrupted, the checksum doesn't match" + ); + } + + return (string) Core::ourSubstr( + $bytes, + self::SERIALIZE_HEADER_BYTES, + Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE + ); + } +} diff --git a/vendor/defuse/php-encryption/src/Exception/BadFormatException.php b/vendor/defuse/php-encryption/src/Exception/BadFormatException.php new file mode 100755 index 0000000..804d9c1 --- /dev/null +++ b/vendor/defuse/php-encryption/src/Exception/BadFormatException.php @@ -0,0 +1,7 @@ +deriveKeys($file_salt); + $ekey = $keys->getEncryptionKey(); + $akey = $keys->getAuthenticationKey(); + + $ivsize = Core::BLOCK_BYTE_SIZE; + $iv = Core::secureRandom($ivsize); + + /* Initialize a streaming HMAC state. */ + /** @var mixed $hmac */ + $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey); + Core::ensureTrue( + \is_resource($hmac) || \is_object($hmac), + 'Cannot initialize a hash context' + ); + + /* Write the header, salt, and IV. */ + self::writeBytes( + $outputHandle, + Core::CURRENT_VERSION . $file_salt . $iv, + Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + $ivsize + ); + + /* Add the header, salt, and IV to the HMAC. */ + \hash_update($hmac, Core::CURRENT_VERSION); + \hash_update($hmac, $file_salt); + \hash_update($hmac, $iv); + + /* $thisIv will be incremented after each call to the encryption. */ + $thisIv = $iv; + + /* How many blocks do we encrypt at a time? We increment by this value. */ + /** + * @psalm-suppress RedundantCast + */ + $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE); + + /* Loop until we reach the end of the input file. */ + $at_file_end = false; + while (! (\feof($inputHandle) || $at_file_end)) { + /* Find out if we can read a full buffer, or only a partial one. */ + /** @var int */ + $pos = \ftell($inputHandle); + if (!\is_int($pos)) { + throw new Ex\IOException( + 'Could not get current position in input file during encryption' + ); + } + if ($pos + Core::BUFFER_BYTE_SIZE >= $inputSize) { + /* We're at the end of the file, so we need to break out of the loop. */ + $at_file_end = true; + $read = self::readBytes( + $inputHandle, + $inputSize - $pos + ); + } else { + $read = self::readBytes( + $inputHandle, + Core::BUFFER_BYTE_SIZE + ); + } + + /* Encrypt this buffer. */ + /** @var string */ + $encrypted = \openssl_encrypt( + $read, + Core::CIPHER_METHOD, + $ekey, + OPENSSL_RAW_DATA, + $thisIv + ); + + Core::ensureTrue(\is_string($encrypted), 'OpenSSL encryption error'); + + /* Write this buffer's ciphertext. */ + self::writeBytes($outputHandle, $encrypted, Core::ourStrlen($encrypted)); + /* Add this buffer's ciphertext to the HMAC. */ + \hash_update($hmac, $encrypted); + + /* Increment the counter by the number of blocks in a buffer. */ + $thisIv = Core::incrementCounter($thisIv, $inc); + /* WARNING: Usually, unless the file is a multiple of the buffer + * size, $thisIv will contain an incorrect value here on the last + * iteration of this loop. */ + } + + /* Get the HMAC and append it to the ciphertext. */ + $final_mac = \hash_final($hmac, true); + self::writeBytes($outputHandle, $final_mac, Core::MAC_BYTE_SIZE); + } + + /** + * Decrypts a file-backed resource with either a key or a password. + * + * @param resource $inputHandle + * @param resource $outputHandle + * @param KeyOrPassword $secret + * @return void + * + * @throws Ex\EnvironmentIsBrokenException + * @throws Ex\IOException + * @throws Ex\WrongKeyOrModifiedCiphertextException + * @psalm-suppress PossiblyInvalidArgument + * Fixes erroneous errors caused by PHP 7.2 switching the return value + * of hash_init from a resource to a HashContext. + */ + public static function decryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret) + { + if (! \is_resource($inputHandle)) { + throw new Ex\IOException( + 'Input handle must be a resource!' + ); + } + if (! \is_resource($outputHandle)) { + throw new Ex\IOException( + 'Output handle must be a resource!' + ); + } + + /* Make sure the file is big enough for all the reads we need to do. */ + $stat = \fstat($inputHandle); + if ($stat['size'] < Core::MINIMUM_CIPHERTEXT_SIZE) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Input file is too small to have been created by this library.' + ); + } + + /* Check the version header. */ + $header = self::readBytes($inputHandle, Core::HEADER_VERSION_SIZE); + if ($header !== Core::CURRENT_VERSION) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Bad version header.' + ); + } + + /* Get the salt. */ + $file_salt = self::readBytes($inputHandle, Core::SALT_BYTE_SIZE); + + /* Get the IV. */ + $ivsize = Core::BLOCK_BYTE_SIZE; + $iv = self::readBytes($inputHandle, $ivsize); + + /* Derive the authentication and encryption keys. */ + $keys = $secret->deriveKeys($file_salt); + $ekey = $keys->getEncryptionKey(); + $akey = $keys->getAuthenticationKey(); + + /* We'll store the MAC of each buffer-sized chunk as we verify the + * actual MAC, so that we can check them again when decrypting. */ + $macs = []; + + /* $thisIv will be incremented after each call to the decryption. */ + $thisIv = $iv; + + /* How many blocks do we encrypt at a time? We increment by this value. */ + /** + * @psalm-suppress RedundantCast + */ + $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE); + + /* Get the HMAC. */ + if (\fseek($inputHandle, (-1 * Core::MAC_BYTE_SIZE), SEEK_END) === -1) { + throw new Ex\IOException( + 'Cannot seek to beginning of MAC within input file' + ); + } + + /* Get the position of the last byte in the actual ciphertext. */ + /** @var int $cipher_end */ + $cipher_end = \ftell($inputHandle); + if (!\is_int($cipher_end)) { + throw new Ex\IOException( + 'Cannot read input file' + ); + } + /* We have the position of the first byte of the HMAC. Go back by one. */ + --$cipher_end; + + /* Read the HMAC. */ + /** @var string $stored_mac */ + $stored_mac = self::readBytes($inputHandle, Core::MAC_BYTE_SIZE); + + /* Initialize a streaming HMAC state. */ + /** @var mixed $hmac */ + $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey); + Core::ensureTrue(\is_resource($hmac) || \is_object($hmac), 'Cannot initialize a hash context'); + + /* Reset file pointer to the beginning of the file after the header */ + if (\fseek($inputHandle, Core::HEADER_VERSION_SIZE, SEEK_SET) === -1) { + throw new Ex\IOException( + 'Cannot read seek within input file' + ); + } + + /* Seek to the start of the actual ciphertext. */ + if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize, SEEK_CUR) === -1) { + throw new Ex\IOException( + 'Cannot seek input file to beginning of ciphertext' + ); + } + + /* PASS #1: Calculating the HMAC. */ + + \hash_update($hmac, $header); + \hash_update($hmac, $file_salt); + \hash_update($hmac, $iv); + /** @var mixed $hmac2 */ + $hmac2 = \hash_copy($hmac); + + $break = false; + while (! $break) { + /** @var int $pos */ + $pos = \ftell($inputHandle); + if (!\is_int($pos)) { + throw new Ex\IOException( + 'Could not get current position in input file during decryption' + ); + } + + /* Read the next buffer-sized chunk (or less). */ + if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) { + $break = true; + $read = self::readBytes( + $inputHandle, + $cipher_end - $pos + 1 + ); + } else { + $read = self::readBytes( + $inputHandle, + Core::BUFFER_BYTE_SIZE + ); + } + + /* Update the HMAC. */ + \hash_update($hmac, $read); + + /* Remember this buffer-sized chunk's HMAC. */ + /** @var mixed $chunk_mac */ + $chunk_mac = \hash_copy($hmac); + Core::ensureTrue(\is_resource($chunk_mac) || \is_object($chunk_mac), 'Cannot duplicate a hash context'); + $macs []= \hash_final($chunk_mac); + } + + /* Get the final HMAC, which should match the stored one. */ + /** @var string $final_mac */ + $final_mac = \hash_final($hmac, true); + + /* Verify the HMAC. */ + if (! Core::hashEquals($final_mac, $stored_mac)) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Integrity check failed.' + ); + } + + /* PASS #2: Decrypt and write output. */ + + /* Rewind to the start of the actual ciphertext. */ + if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize + Core::HEADER_VERSION_SIZE, SEEK_SET) === -1) { + throw new Ex\IOException( + 'Could not move the input file pointer during decryption' + ); + } + + $at_file_end = false; + while (! $at_file_end) { + /** @var int $pos */ + $pos = \ftell($inputHandle); + if (!\is_int($pos)) { + throw new Ex\IOException( + 'Could not get current position in input file during decryption' + ); + } + + /* Read the next buffer-sized chunk (or less). */ + if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) { + $at_file_end = true; + $read = self::readBytes( + $inputHandle, + $cipher_end - $pos + 1 + ); + } else { + $read = self::readBytes( + $inputHandle, + Core::BUFFER_BYTE_SIZE + ); + } + + /* Recalculate the MAC (so far) and compare it with the one we + * remembered from pass #1 to ensure attackers didn't change the + * ciphertext after MAC verification. */ + \hash_update($hmac2, $read); + /** @var mixed $calc_mac */ + $calc_mac = \hash_copy($hmac2); + Core::ensureTrue(\is_resource($calc_mac) || \is_object($calc_mac), 'Cannot duplicate a hash context'); + $calc = \hash_final($calc_mac); + + if (empty($macs)) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'File was modified after MAC verification' + ); + } elseif (! Core::hashEquals(\array_shift($macs), $calc)) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'File was modified after MAC verification' + ); + } + + /* Decrypt this buffer-sized chunk. */ + /** @var string $decrypted */ + $decrypted = \openssl_decrypt( + $read, + Core::CIPHER_METHOD, + $ekey, + OPENSSL_RAW_DATA, + $thisIv + ); + Core::ensureTrue(\is_string($decrypted), 'OpenSSL decryption error'); + + /* Write the plaintext to the output file. */ + self::writeBytes( + $outputHandle, + $decrypted, + Core::ourStrlen($decrypted) + ); + + /* Increment the IV by the amount of blocks in a buffer. */ + /** @var string $thisIv */ + $thisIv = Core::incrementCounter($thisIv, $inc); + /* WARNING: Usually, unless the file is a multiple of the buffer + * size, $thisIv will contain an incorrect value here on the last + * iteration of this loop. */ + } + } + + /** + * Read from a stream; prevent partial reads. + * + * @param resource $stream + * @param int $num_bytes + * @return string + * + * @throws Ex\IOException + * @throws Ex\EnvironmentIsBrokenException + */ + public static function readBytes($stream, $num_bytes) + { + Core::ensureTrue($num_bytes >= 0, 'Tried to read less than 0 bytes'); + + if ($num_bytes === 0) { + return ''; + } + + $buf = ''; + $remaining = $num_bytes; + while ($remaining > 0 && ! \feof($stream)) { + /** @var string $read */ + $read = \fread($stream, $remaining); + if (!\is_string($read)) { + throw new Ex\IOException( + 'Could not read from the file' + ); + } + $buf .= $read; + $remaining -= Core::ourStrlen($read); + } + if (Core::ourStrlen($buf) !== $num_bytes) { + throw new Ex\IOException( + 'Tried to read past the end of the file' + ); + } + return $buf; + } + + /** + * Write to a stream; prevents partial writes. + * + * @param resource $stream + * @param string $buf + * @param int $num_bytes + * @return int + * + * @throws Ex\IOException + */ + public static function writeBytes($stream, $buf, $num_bytes = null) + { + $bufSize = Core::ourStrlen($buf); + if ($num_bytes === null) { + $num_bytes = $bufSize; + } + if ($num_bytes > $bufSize) { + throw new Ex\IOException( + 'Trying to write more bytes than the buffer contains.' + ); + } + if ($num_bytes < 0) { + throw new Ex\IOException( + 'Tried to write less than 0 bytes' + ); + } + $remaining = $num_bytes; + while ($remaining > 0) { + /** @var int $written */ + $written = \fwrite($stream, $buf, $remaining); + if (!\is_int($written)) { + throw new Ex\IOException( + 'Could not write to the file' + ); + } + $buf = (string) Core::ourSubstr($buf, $written, null); + $remaining -= $written; + } + return $num_bytes; + } + + /** + * Returns the last PHP error's or warning's message string. + * + * @return string + */ + private static function getLastErrorMessage() + { + $error = error_get_last(); + if ($error === null) { + return '[no PHP error]'; + } else { + return $error['message']; + } + } +} diff --git a/vendor/defuse/php-encryption/src/Key.php b/vendor/defuse/php-encryption/src/Key.php new file mode 100755 index 0000000..27b919f --- /dev/null +++ b/vendor/defuse/php-encryption/src/Key.php @@ -0,0 +1,94 @@ +key_bytes + ); + } + + /** + * Gets the raw bytes of the key. + * + * @return string + */ + public function getRawBytes() + { + return $this->key_bytes; + } + + /** + * Constructs a new Key object from a string of raw bytes. + * + * @param string $bytes + * + * @throws Ex\EnvironmentIsBrokenException + */ + private function __construct($bytes) + { + Core::ensureTrue( + Core::ourStrlen($bytes) === self::KEY_BYTE_SIZE, + 'Bad key length.' + ); + $this->key_bytes = $bytes; + } + +} diff --git a/vendor/defuse/php-encryption/src/KeyOrPassword.php b/vendor/defuse/php-encryption/src/KeyOrPassword.php new file mode 100755 index 0000000..890b2c2 --- /dev/null +++ b/vendor/defuse/php-encryption/src/KeyOrPassword.php @@ -0,0 +1,149 @@ +secret_type === self::SECRET_TYPE_KEY) { + Core::ensureTrue($this->secret instanceof Key); + /** + * @psalm-suppress PossiblyInvalidMethodCall + */ + $akey = Core::HKDF( + Core::HASH_FUNCTION_NAME, + $this->secret->getRawBytes(), + Core::KEY_BYTE_SIZE, + Core::AUTHENTICATION_INFO_STRING, + $salt + ); + /** + * @psalm-suppress PossiblyInvalidMethodCall + */ + $ekey = Core::HKDF( + Core::HASH_FUNCTION_NAME, + $this->secret->getRawBytes(), + Core::KEY_BYTE_SIZE, + Core::ENCRYPTION_INFO_STRING, + $salt + ); + return new DerivedKeys($akey, $ekey); + } elseif ($this->secret_type === self::SECRET_TYPE_PASSWORD) { + Core::ensureTrue(\is_string($this->secret)); + /* Our PBKDF2 polyfill is vulnerable to a DoS attack documented in + * GitHub issue #230. The fix is to pre-hash the password to ensure + * it is short. We do the prehashing here instead of in pbkdf2() so + * that pbkdf2() still computes the function as defined by the + * standard. */ + + /** + * @psalm-suppress PossiblyInvalidArgument + */ + $prehash = \hash(Core::HASH_FUNCTION_NAME, $this->secret, true); + + $prekey = Core::pbkdf2( + Core::HASH_FUNCTION_NAME, + $prehash, + $salt, + self::PBKDF2_ITERATIONS, + Core::KEY_BYTE_SIZE, + true + ); + $akey = Core::HKDF( + Core::HASH_FUNCTION_NAME, + $prekey, + Core::KEY_BYTE_SIZE, + Core::AUTHENTICATION_INFO_STRING, + $salt + ); + /* Note the cryptographic re-use of $salt here. */ + $ekey = Core::HKDF( + Core::HASH_FUNCTION_NAME, + $prekey, + Core::KEY_BYTE_SIZE, + Core::ENCRYPTION_INFO_STRING, + $salt + ); + return new DerivedKeys($akey, $ekey); + } else { + throw new Ex\EnvironmentIsBrokenException('Bad secret type.'); + } + } + + /** + * Constructor for KeyOrPassword. + * + * @param int $secret_type + * @param mixed $secret (either a Key or a password string) + */ + private function __construct($secret_type, $secret) + { + // The constructor is private, so these should never throw. + if ($secret_type === self::SECRET_TYPE_KEY) { + Core::ensureTrue($secret instanceof Key); + } elseif ($secret_type === self::SECRET_TYPE_PASSWORD) { + Core::ensureTrue(\is_string($secret)); + } else { + throw new Ex\EnvironmentIsBrokenException('Bad secret type.'); + } + $this->secret_type = $secret_type; + $this->secret = $secret; + } +} diff --git a/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php b/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php new file mode 100755 index 0000000..347bdd9 --- /dev/null +++ b/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php @@ -0,0 +1,145 @@ +saveToAsciiSafeString(), + \hash(Core::HASH_FUNCTION_NAME, $password, true), + true + ); + + return new KeyProtectedByPassword($encrypted_key); + } + + /** + * Loads a KeyProtectedByPassword from its encoded form. + * + * @param string $saved_key_string + * + * @throws Ex\BadFormatException + * + * @return KeyProtectedByPassword + */ + public static function loadFromAsciiSafeString($saved_key_string) + { + $encrypted_key = Encoding::loadBytesFromChecksummedAsciiSafeString( + self::PASSWORD_KEY_CURRENT_VERSION, + $saved_key_string + ); + return new KeyProtectedByPassword($encrypted_key); + } + + /** + * Encodes the KeyProtectedByPassword into a string of printable ASCII + * characters. + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + public function saveToAsciiSafeString() + { + return Encoding::saveBytesToChecksummedAsciiSafeString( + self::PASSWORD_KEY_CURRENT_VERSION, + $this->encrypted_key + ); + } + + /** + * Decrypts the protected key, returning an unprotected Key object that can + * be used for encryption and decryption. + * + * @throws Ex\EnvironmentIsBrokenException + * @throws Ex\WrongKeyOrModifiedCiphertextException + * + * @param string $password + * @return Key + */ + public function unlockKey($password) + { + try { + $inner_key_encoded = Crypto::decryptWithPassword( + $this->encrypted_key, + \hash(Core::HASH_FUNCTION_NAME, $password, true), + true + ); + return Key::loadFromAsciiSafeString($inner_key_encoded); + } catch (Ex\BadFormatException $ex) { + /* This should never happen unless an attacker replaced the + * encrypted key ciphertext with some other ciphertext that was + * encrypted with the same password. We transform the exception type + * here in order to make the API simpler, avoiding the need to + * document that this method might throw an Ex\BadFormatException. */ + throw new Ex\WrongKeyOrModifiedCiphertextException( + "The decrypted key was found to be in an invalid format. " . + "This very likely indicates it was modified by an attacker." + ); + } + } + + /** + * Changes the password. + * + * @param string $current_password + * @param string $new_password + * + * @throws Ex\EnvironmentIsBrokenException + * @throws Ex\WrongKeyOrModifiedCiphertextException + * + * @return KeyProtectedByPassword + */ + public function changePassword($current_password, $new_password) + { + $inner_key = $this->unlockKey($current_password); + /* The password is hashed as a form of poor-man's domain separation + * between this use of encryptWithPassword() and other uses of + * encryptWithPassword() that the user may also be using as part of the + * same protocol. */ + $encrypted_key = Crypto::encryptWithPassword( + $inner_key->saveToAsciiSafeString(), + \hash(Core::HASH_FUNCTION_NAME, $new_password, true), + true + ); + + $this->encrypted_key = $encrypted_key; + + return $this; + } + + /** + * Constructor for KeyProtectedByPassword. + * + * @param string $encrypted_key + */ + private function __construct($encrypted_key) + { + $this->encrypted_key = $encrypted_key; + } +} diff --git a/vendor/defuse/php-encryption/src/RuntimeTests.php b/vendor/defuse/php-encryption/src/RuntimeTests.php new file mode 100755 index 0000000..65ce55d --- /dev/null +++ b/vendor/defuse/php-encryption/src/RuntimeTests.php @@ -0,0 +1,228 @@ +getRawBytes()) === Core::KEY_BYTE_SIZE); + + Core::ensureTrue(Core::ENCRYPTION_INFO_STRING !== Core::AUTHENTICATION_INFO_STRING); + } catch (Ex\EnvironmentIsBrokenException $ex) { + // Do this, otherwise it will stay in the "tests are running" state. + $test_state = 3; + throw $ex; + } + + // Change this to '0' make the tests always re-run (for benchmarking). + $test_state = 1; + } + + /** + * High-level tests of Crypto operations. + * + * @throws Ex\EnvironmentIsBrokenException + * @return void + */ + private static function testEncryptDecrypt() + { + $key = Key::createNewRandomKey(); + $data = "EnCrYpT EvErYThInG\x00\x00"; + + // Make sure encrypting then decrypting doesn't change the message. + $ciphertext = Crypto::encrypt($data, $key, true); + try { + $decrypted = Crypto::decrypt($ciphertext, $key, true); + } catch (Ex\WrongKeyOrModifiedCiphertextException $ex) { + // It's important to catch this and change it into a + // Ex\EnvironmentIsBrokenException, otherwise a test failure could trick + // the user into thinking it's just an invalid ciphertext! + throw new Ex\EnvironmentIsBrokenException(); + } + Core::ensureTrue($decrypted === $data); + + // Modifying the ciphertext: Appending a string. + try { + Crypto::decrypt($ciphertext . 'a', $key, true); + throw new Ex\EnvironmentIsBrokenException(); + } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */ + } + + // Modifying the ciphertext: Changing an HMAC byte. + $indices_to_change = [ + 0, // The header. + Core::HEADER_VERSION_SIZE + 1, // the salt + Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + 1, // the IV + Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + Core::BLOCK_BYTE_SIZE + 1, // the ciphertext + ]; + + foreach ($indices_to_change as $index) { + try { + $ciphertext[$index] = \chr((\ord($ciphertext[$index]) + 1) % 256); + Crypto::decrypt($ciphertext, $key, true); + throw new Ex\EnvironmentIsBrokenException(); + } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */ + } + } + + // Decrypting with the wrong key. + $key = Key::createNewRandomKey(); + $data = 'abcdef'; + $ciphertext = Crypto::encrypt($data, $key, true); + $wrong_key = Key::createNewRandomKey(); + try { + Crypto::decrypt($ciphertext, $wrong_key, true); + throw new Ex\EnvironmentIsBrokenException(); + } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */ + } + + // Ciphertext too small. + $key = Key::createNewRandomKey(); + $ciphertext = \str_repeat('A', Core::MINIMUM_CIPHERTEXT_SIZE - 1); + try { + Crypto::decrypt($ciphertext, $key, true); + throw new Ex\EnvironmentIsBrokenException(); + } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */ + } + } + + /** + * Test HKDF against test vectors. + * + * @throws Ex\EnvironmentIsBrokenException + * @return void + */ + private static function HKDFTestVector() + { + // HKDF test vectors from RFC 5869 + + // Test Case 1 + $ikm = \str_repeat("\x0b", 22); + $salt = Encoding::hexToBin('000102030405060708090a0b0c'); + $info = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9'); + $length = 42; + $okm = Encoding::hexToBin( + '3cb25f25faacd57a90434f64d0362f2a' . + '2d2d0a90cf1a5a4c5db02d56ecc4c5bf' . + '34007208d5b887185865' + ); + $computed_okm = Core::HKDF('sha256', $ikm, $length, $info, $salt); + Core::ensureTrue($computed_okm === $okm); + + // Test Case 7 + $ikm = \str_repeat("\x0c", 22); + $length = 42; + $okm = Encoding::hexToBin( + '2c91117204d745f3500d636a62f64f0a' . + 'b3bae548aa53d423b0d1f27ebba6f5e5' . + '673a081d70cce7acfc48' + ); + $computed_okm = Core::HKDF('sha1', $ikm, $length, '', null); + Core::ensureTrue($computed_okm === $okm); + } + + /** + * Test HMAC against test vectors. + * + * @throws Ex\EnvironmentIsBrokenException + * @return void + */ + private static function HMACTestVector() + { + // HMAC test vector From RFC 4231 (Test Case 1) + $key = \str_repeat("\x0b", 20); + $data = 'Hi There'; + $correct = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7'; + Core::ensureTrue( + \hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) === $correct + ); + } + + /** + * Test AES against test vectors. + * + * @throws Ex\EnvironmentIsBrokenException + * @return void + */ + private static function AESTestVector() + { + // AES CTR mode test vector from NIST SP 800-38A + $key = Encoding::hexToBin( + '603deb1015ca71be2b73aef0857d7781' . + '1f352c073b6108d72d9810a30914dff4' + ); + $iv = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'); + $plaintext = Encoding::hexToBin( + '6bc1bee22e409f96e93d7e117393172a' . + 'ae2d8a571e03ac9c9eb76fac45af8e51' . + '30c81c46a35ce411e5fbc1191a0a52ef' . + 'f69f2445df4f9b17ad2b417be66c3710' + ); + $ciphertext = Encoding::hexToBin( + '601ec313775789a5b7a7f504bbf3d228' . + 'f443e3ca4d62b59aca84e990cacaf5c5' . + '2b0930daa23de94ce87017ba2d84988d' . + 'dfc9c58db67aada613c2dd08457941a6' + ); + + $computed_ciphertext = Crypto::plainEncrypt($plaintext, $key, $iv); + Core::ensureTrue($computed_ciphertext === $ciphertext); + + $computed_plaintext = Crypto::plainDecrypt($ciphertext, $key, $iv, Core::CIPHER_METHOD); + Core::ensureTrue($computed_plaintext === $plaintext); + } +} diff --git a/vendor/dflydev/dot-access-data/CHANGELOG.md b/vendor/dflydev/dot-access-data/CHANGELOG.md new file mode 100755 index 0000000..5b86c10 --- /dev/null +++ b/vendor/dflydev/dot-access-data/CHANGELOG.md @@ -0,0 +1,59 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [3.0.1] - 2021-08-13 + +### Added + + - Adds ReturnTypeWillChange to suppress PHP 8.1 warnings (#40) + +## [3.0.0] - 2021-01-01 + +### Added + - Added support for both `.` and `/`-delimited key paths (#24) + - Added parameter and return types to everything; enabled strict type checks (#18) + - Added new exception classes to better identify certain types of errors (#20) + - `Data` now implements `ArrayAccess` (#17) + - Added ability to merge non-associative array values (#31, #32) + +### Changed + - All thrown exceptions are now instances or subclasses of `DataException` (#20) + - Calling `get()` on a missing key path without providing a default will throw a `MissingPathException` instead of returning `null` (#29) + - Bumped supported PHP versions to 7.1 - 8.x (#18) + +### Fixed + - Fixed incorrect merging of array values into string values (#32) + - Fixed `get()` method behaving as if keys with `null` values didn't exist + +## [2.0.0] - 2017-12-21 + +### Changed + - Bumped supported PHP versions to 7.0 - 7.4 (#12) + - Switched to PSR-4 autoloading + +## [1.1.0] - 2017-01-20 + +### Added + - Added new `has()` method to check for the existence of the given key (#4, #7) + +## [1.0.1] - 2015-08-12 + +### Added + - Added new optional `$default` parameter to the `get()` method (#2) + +## [1.0.0] - 2012-07-17 + +**Initial release!** + +[Unreleased]: https://github.com/dflydev/dflydev-dot-access-data/compare/v3.0.0...main +[3.0.0]: https://github.com/dflydev/dflydev-dot-access-data/compare/v2.0.0...v3.0.0 +[2.0.0]: https://github.com/dflydev/dflydev-dot-access-data/compare/v1.1.0...v2.0.0 +[1.1.0]: https://github.com/dflydev/dflydev-dot-access-data/compare/v1.0.1...v1.1.0 +[1.0.1]: https://github.com/dflydev/dflydev-dot-access-data/compare/v1.0.0...v1.0.1 +[1.0.0]: https://github.com/dflydev/dflydev-dot-access-data/releases/tag/v1.0.0 diff --git a/vendor/dflydev/dot-access-data/LICENSE b/vendor/dflydev/dot-access-data/LICENSE new file mode 100755 index 0000000..b6880d4 --- /dev/null +++ b/vendor/dflydev/dot-access-data/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 Dragonfly Development Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/dflydev/dot-access-data/README.md b/vendor/dflydev/dot-access-data/README.md new file mode 100755 index 0000000..775fbdf --- /dev/null +++ b/vendor/dflydev/dot-access-data/README.md @@ -0,0 +1,158 @@ +Dot Access Data +=============== + +[![Latest Version](https://img.shields.io/packagist/v/dflydev/dot-access-data.svg?style=flat-square)](https://packagist.org/packages/dflydev/dot-access-data) +[![Total Downloads](https://img.shields.io/packagist/dt/dflydev/dot-access-data.svg?style=flat-square)](https://packagist.org/packages/dflydev/dot-access-data) +[![Software License](https://img.shields.io/badge/License-MIT-brightgreen.svg?style=flat-square)](LICENSE) +[![Build Status](https://img.shields.io/github/workflow/status/dflydev/dflydev-dot-access-data/Tests/main.svg?style=flat-square)](https://github.com/dflydev/dflydev-dot-access-data/actions?query=workflow%3ATests+branch%3Amain) +[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/dflydev/dflydev-dot-access-data.svg?style=flat-square)](https://scrutinizer-ci.com/g/dflydev/dflydev-dot-access-data/code-structure/) +[![Quality Score](https://img.shields.io/scrutinizer/g/dflydev/dflydev-dot-access-data.svg?style=flat-square)](https://scrutinizer-ci.com/g/dflydev/dflydev-dot-access-data) + +Given a deep data structure, access data by dot notation. + + +Requirements +------------ + + * PHP (7.1+) + +> For PHP (5.3+) please refer to version `1.0`. + + +Usage +----- + +Abstract example: + +```php +use Dflydev\DotAccessData\Data; + +$data = new Data; + +$data->set('a.b.c', 'C'); +$data->set('a.b.d', 'D1'); +$data->append('a.b.d', 'D2'); +$data->set('a.b.e', ['E0', 'E1', 'E2']); + +// C +$data->get('a.b.c'); + +// ['D1', 'D2'] +$data->get('a.b.d'); + +// ['E0', 'E1', 'E2'] +$data->get('a.b.e'); + +// true +$data->has('a.b.c'); + +// false +$data->has('a.b.d.j'); + + +// 'some-default-value' +$data->get('some.path.that.does.not.exist', 'some-default-value'); + +// throws a MissingPathException because no default was given +$data->get('some.path.that.does.not.exist'); +``` + +A more concrete example: + +```php +use Dflydev\DotAccessData\Data; + +$data = new Data([ + 'hosts' => [ + 'hewey' => [ + 'username' => 'hman', + 'password' => 'HPASS', + 'roles' => ['web'], + ], + 'dewey' => [ + 'username' => 'dman', + 'password' => 'D---S', + 'roles' => ['web', 'db'], + 'nick' => 'dewey dman', + ], + 'lewey' => [ + 'username' => 'lman', + 'password' => 'LP@$$', + 'roles' => ['db'], + ], + ], +]); + +// hman +$username = $data->get('hosts.hewey.username'); +// HPASS +$password = $data->get('hosts.hewey.password'); +// ['web'] +$roles = $data->get('hosts.hewey.roles'); +// dewey dman +$nick = $data->get('hosts.dewey.nick'); +// Unknown +$nick = $data->get('hosts.lewey.nick', 'Unknown'); + +// DataInterface instance +$dewey = $data->getData('hosts.dewey'); +// dman +$username = $dewey->get('username'); +// D---S +$password = $dewey->get('password'); +// ['web', 'db'] +$roles = $dewey->get('roles'); + +// No more lewey +$data->remove('hosts.lewey'); + +// Add DB to hewey's roles +$data->append('hosts.hewey.roles', 'db'); + +$data->set('hosts.april', [ + 'username' => 'aman', + 'password' => '@---S', + 'roles' => ['web'], +]); + +// Check if a key exists (true to this case) +$hasKey = $data->has('hosts.dewey.username'); +``` + +`Data` may be used as an array, since it implements `ArrayAccess` interface: + +```php +// Get +$data->get('name') === $data['name']; // true + +$data['name'] = 'Dewey'; +// is equivalent to +$data->set($name, 'Dewey'); + +isset($data['name']) === $data->has('name'); + +// Remove key +unset($data['name']); +``` + +`/` can also be used as a path delimiter: + +```php +$data->set('a/b/c', 'd'); +echo $data->get('a/b/c'); // "d" + +$data->get('a/b/c') === $data->get('a.b.c'); // true +``` + +License +------- + +This library is licensed under the MIT License - see the LICENSE file +for details. + + +Community +--------- + +If you have questions or want to help out, join us in the +[#dflydev](irc://irc.freenode.net/#dflydev) channel on irc.freenode.net. diff --git a/vendor/dflydev/dot-access-data/composer.json b/vendor/dflydev/dot-access-data/composer.json new file mode 100755 index 0000000..565ed2d --- /dev/null +++ b/vendor/dflydev/dot-access-data/composer.json @@ -0,0 +1,67 @@ +{ + "name": "dflydev/dot-access-data", + "type": "library", + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": ["dot", "access", "data", "notation"], + "license": "MIT", + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^3.14" + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Dflydev\\DotAccessData\\": "tests/" + } + }, + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "scripts": { + "phpcs": "phpcs", + "phpstan": "phpstan analyse", + "phpunit": "phpunit --no-coverage", + "psalm": "psalm", + "test": [ + "@phpcs", + "@phpstan", + "@psalm", + "@phpunit" + ] + } +} diff --git a/vendor/dflydev/dot-access-data/src/Data.php b/vendor/dflydev/dot-access-data/src/Data.php new file mode 100755 index 0000000..4e2db4a --- /dev/null +++ b/vendor/dflydev/dot-access-data/src/Data.php @@ -0,0 +1,277 @@ + + */ +class Data implements DataInterface, ArrayAccess +{ + private const DELIMITERS = ['.', '/']; + + /** + * Internal representation of data data + * + * @var array + */ + protected $data; + + /** + * Constructor + * + * @param array $data + */ + public function __construct(array $data = []) + { + $this->data = $data; + } + + /** + * {@inheritdoc} + */ + public function append(string $key, $value = null): void + { + $currentValue =& $this->data; + $keyPath = self::keyToPathArray($key); + + $endKey = array_pop($keyPath); + foreach ($keyPath as $currentKey) { + if (! isset($currentValue[$currentKey])) { + $currentValue[$currentKey] = []; + } + $currentValue =& $currentValue[$currentKey]; + } + + if (!isset($currentValue[$endKey])) { + $currentValue[$endKey] = []; + } + + if (!is_array($currentValue[$endKey])) { + // Promote this key to an array. + // TODO: Is this really what we want to do? + $currentValue[$endKey] = [$currentValue[$endKey]]; + } + + $currentValue[$endKey][] = $value; + } + + /** + * {@inheritdoc} + */ + public function set(string $key, $value = null): void + { + $currentValue =& $this->data; + $keyPath = self::keyToPathArray($key); + + $endKey = array_pop($keyPath); + foreach ($keyPath as $currentKey) { + if (!isset($currentValue[$currentKey])) { + $currentValue[$currentKey] = []; + } + if (!is_array($currentValue[$currentKey])) { + throw new DataException(sprintf('Key path "%s" within "%s" cannot be indexed into (is not an array)', $currentKey, self::formatPath($key))); + } + $currentValue =& $currentValue[$currentKey]; + } + $currentValue[$endKey] = $value; + } + + /** + * {@inheritdoc} + */ + public function remove(string $key): void + { + $currentValue =& $this->data; + $keyPath = self::keyToPathArray($key); + + $endKey = array_pop($keyPath); + foreach ($keyPath as $currentKey) { + if (!isset($currentValue[$currentKey])) { + return; + } + $currentValue =& $currentValue[$currentKey]; + } + unset($currentValue[$endKey]); + } + + /** + * {@inheritdoc} + * + * @psalm-mutation-free + */ + public function get(string $key, $default = null) + { + /** @psalm-suppress ImpureFunctionCall */ + $hasDefault = \func_num_args() > 1; + + $currentValue = $this->data; + $keyPath = self::keyToPathArray($key); + + foreach ($keyPath as $currentKey) { + if (!is_array($currentValue) || !array_key_exists($currentKey, $currentValue)) { + if ($hasDefault) { + return $default; + } + + throw new MissingPathException($key, sprintf('No data exists at the given path: "%s"', self::formatPath($keyPath))); + } + + $currentValue = $currentValue[$currentKey]; + } + + return $currentValue === null ? $default : $currentValue; + } + + /** + * {@inheritdoc} + * + * @psalm-mutation-free + */ + public function has(string $key): bool + { + $currentValue = &$this->data; + + foreach (self::keyToPathArray($key) as $currentKey) { + if ( + !is_array($currentValue) || + !array_key_exists($currentKey, $currentValue) + ) { + return false; + } + $currentValue = &$currentValue[$currentKey]; + } + + return true; + } + + /** + * {@inheritdoc} + * + * @psalm-mutation-free + */ + public function getData(string $key): DataInterface + { + $value = $this->get($key); + if (is_array($value) && Util::isAssoc($value)) { + return new Data($value); + } + + throw new DataException(sprintf('Value at "%s" could not be represented as a DataInterface', self::formatPath($key))); + } + + /** + * {@inheritdoc} + */ + public function import(array $data, int $mode = self::REPLACE): void + { + $this->data = Util::mergeAssocArray($this->data, $data, $mode); + } + + /** + * {@inheritdoc} + */ + public function importData(DataInterface $data, int $mode = self::REPLACE): void + { + $this->import($data->export(), $mode); + } + + /** + * {@inheritdoc} + * + * @psalm-mutation-free + */ + public function export(): array + { + return $this->data; + } + + /** + * {@inheritdoc} + */ + #[\ReturnTypeWillChange] + public function offsetExists($key) + { + return $this->has($key); + } + + /** + * {@inheritdoc} + */ + #[\ReturnTypeWillChange] + public function offsetGet($key) + { + return $this->get($key, null); + } + + /** + * {@inheritdoc} + * + * @param string $key + */ + #[\ReturnTypeWillChange] + public function offsetSet($key, $value) + { + $this->set($key, $value); + } + + /** + * {@inheritdoc} + */ + #[\ReturnTypeWillChange] + public function offsetUnset($key) + { + $this->remove($key); + } + + /** + * @param string $path + * + * @return string[] + * + * @psalm-return non-empty-list + * + * @psalm-pure + */ + protected static function keyToPathArray(string $path): array + { + if (\strlen($path) === 0) { + throw new InvalidPathException('Path cannot be an empty string'); + } + + $path = \str_replace(self::DELIMITERS, '.', $path); + + return \explode('.', $path); + } + + /** + * @param string|string[] $path + * + * @return string + * + * @psalm-pure + */ + protected static function formatPath($path): string + { + if (is_string($path)) { + $path = self::keyToPathArray($path); + } + + return implode(' » ', $path); + } +} diff --git a/vendor/dflydev/dot-access-data/src/DataInterface.php b/vendor/dflydev/dot-access-data/src/DataInterface.php new file mode 100755 index 0000000..5909a8c --- /dev/null +++ b/vendor/dflydev/dot-access-data/src/DataInterface.php @@ -0,0 +1,131 @@ + $data + * @param self::PRESERVE|self::REPLACE|self::MERGE $mode + */ + public function import(array $data, int $mode = self::REPLACE): void; + + /** + * Import data from an external data into existing data + * + * @param DataInterface $data + * @param self::PRESERVE|self::REPLACE|self::MERGE $mode + */ + public function importData(DataInterface $data, int $mode = self::REPLACE): void; + + /** + * Export data as raw data + * + * @return array + * + * @psalm-mutation-free + */ + public function export(): array; +} diff --git a/vendor/dflydev/dot-access-data/src/Exception/DataException.php b/vendor/dflydev/dot-access-data/src/Exception/DataException.php new file mode 100755 index 0000000..2faf9f5 --- /dev/null +++ b/vendor/dflydev/dot-access-data/src/Exception/DataException.php @@ -0,0 +1,21 @@ +path = $path; + + parent::__construct($message, $code, $previous); + } + + public function getPath(): string + { + return $this->path; + } +} diff --git a/vendor/dflydev/dot-access-data/src/Util.php b/vendor/dflydev/dot-access-data/src/Util.php new file mode 100755 index 0000000..5634c51 --- /dev/null +++ b/vendor/dflydev/dot-access-data/src/Util.php @@ -0,0 +1,78 @@ + $arr + * + * @return bool + * + * @psalm-pure + */ + public static function isAssoc(array $arr): bool + { + return !count($arr) || count(array_filter(array_keys($arr), 'is_string')) == count($arr); + } + + /** + * Merge contents from one associtative array to another + * + * @param mixed $to + * @param mixed $from + * @param DataInterface::PRESERVE|DataInterface::REPLACE|DataInterface::MERGE $mode + * + * @return mixed + * + * @psalm-pure + */ + public static function mergeAssocArray($to, $from, int $mode = DataInterface::REPLACE) + { + if ($mode === DataInterface::MERGE && self::isList($to) && self::isList($from)) { + return array_merge($to, $from); + } + + if (is_array($from) && is_array($to)) { + foreach ($from as $k => $v) { + if (!isset($to[$k])) { + $to[$k] = $v; + } else { + $to[$k] = self::mergeAssocArray($to[$k], $v, $mode); + } + } + + return $to; + } + + return $mode === DataInterface::PRESERVE ? $to : $from; + } + + /** + * @param mixed $value + * + * @return bool + * + * @psalm-pure + */ + private static function isList($value): bool + { + return is_array($value) && array_values($value) === $value; + } +} diff --git a/vendor/doctrine/cache/LICENSE b/vendor/doctrine/cache/LICENSE new file mode 100755 index 0000000..8c38cc1 --- /dev/null +++ b/vendor/doctrine/cache/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2015 Doctrine Project + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/doctrine/cache/README.md b/vendor/doctrine/cache/README.md new file mode 100755 index 0000000..a13196d --- /dev/null +++ b/vendor/doctrine/cache/README.md @@ -0,0 +1,13 @@ +# Doctrine Cache + +[![Build Status](https://github.com/doctrine/cache/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/cache/actions) +[![Code Coverage](https://codecov.io/gh/doctrine/cache/branch/1.10.x/graph/badge.svg)](https://codecov.io/gh/doctrine/cache/branch/1.10.x) + +[![Latest Stable Version](https://img.shields.io/packagist/v/doctrine/cache.svg?style=flat-square)](https://packagist.org/packages/doctrine/cache) +[![Total Downloads](https://img.shields.io/packagist/dt/doctrine/cache.svg?style=flat-square)](https://packagist.org/packages/doctrine/cache) + +Cache component extracted from the Doctrine Common project. [Documentation](https://www.doctrine-project.org/projects/doctrine-cache/en/current/index.html) + +This library is deprecated and will no longer receive bug fixes from the +Doctrine Project. Please use a different cache library, preferably PSR-6 or +PSR-16 instead. diff --git a/vendor/doctrine/cache/UPGRADE-1.11.md b/vendor/doctrine/cache/UPGRADE-1.11.md new file mode 100755 index 0000000..a33be23 --- /dev/null +++ b/vendor/doctrine/cache/UPGRADE-1.11.md @@ -0,0 +1,15 @@ +# Upgrade to 1.11 + +doctrine/cache will no longer be maintained and all cache implementations have +been marked as deprecated. These implementations will be removed in 2.0, which +will only contain interfaces to provide a lightweight package for backward +compatibility. + +There are two new classes to use in the `Doctrine\Common\Cache\Psr6` namespace: +* The `CacheAdapter` class allows using any Doctrine Cache as PSR-6 cache. This + is useful to provide a forward compatibility layer in libraries that accept + Doctrine cache implementations and switch to PSR-6. +* The `DoctrineProvider` class allows using any PSR-6 cache as Doctrine cache. + This implementation is designed for libraries that leak the cache and want to + switch to allowing PSR-6 implementations. This class is design to be used + during the transition phase of sunsetting doctrine/cache support. diff --git a/vendor/doctrine/cache/UPGRADE-1.4.md b/vendor/doctrine/cache/UPGRADE-1.4.md new file mode 100755 index 0000000..e1f8a50 --- /dev/null +++ b/vendor/doctrine/cache/UPGRADE-1.4.md @@ -0,0 +1,16 @@ +# Upgrade to 1.4 + +## Minor BC Break: `Doctrine\Common\Cache\FileCache#$extension` is now `private`. + +If you need to override the value of `Doctrine\Common\Cache\FileCache#$extension`, then use the +second parameter of `Doctrine\Common\Cache\FileCache#__construct()` instead of overriding +the property in your own implementation. + +## Minor BC Break: file based caches paths changed + +`Doctrine\Common\Cache\FileCache`, `Doctrine\Common\Cache\PhpFileCache` and +`Doctrine\Common\Cache\FilesystemCache` are using a different cache paths structure. + +If you rely on warmed up caches for deployments, consider that caches generated +with `doctrine/cache` `<1.4` are not compatible with the new directory structure, +and will be ignored. diff --git a/vendor/doctrine/cache/composer.json b/vendor/doctrine/cache/composer.json new file mode 100755 index 0000000..ddad5f4 --- /dev/null +++ b/vendor/doctrine/cache/composer.json @@ -0,0 +1,51 @@ +{ + "name": "doctrine/cache", + "type": "library", + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "keywords": [ + "php", + "cache", + "caching", + "abstraction", + "redis", + "memcached", + "couchdb", + "xcache", + "apcu" + ], + "homepage": "https://www.doctrine-project.org/projects/cache.html", + "license": "MIT", + "authors": [ + {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, + {"name": "Roman Borschel", "email": "roman@code-factory.org"}, + {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, + {"name": "Jonathan Wage", "email": "jonwage@gmail.com"}, + {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} + ], + "require": { + "php": "~7.1 || ^8.0" + }, + "require-dev": { + "alcaeus/mongo-php-adapter": "^1.1", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "predis/predis": "~1.0", + "doctrine/coding-standard": "^8.0", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "cache/integration-tests": "dev-master", + "symfony/cache": "^4.4 || ^5.2 || ^6.0@dev", + "symfony/var-exporter": "^4.4 || ^5.2 || ^6.0@dev" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "autoload": { + "psr-4": { "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" } + }, + "autoload-dev": { + "psr-4": { "Doctrine\\Tests\\": "tests/Doctrine/Tests" } + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php new file mode 100755 index 0000000..4cfab6c --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php @@ -0,0 +1,90 @@ +hits + * Number of keys that have been requested and found present. + * + * - misses + * Number of items that have been requested and not found. + * + * - uptime + * Time that the server is running. + * + * - memory_usage + * Memory used by this server to store items. + * + * - memory_available + * Memory allowed to use for storage. + * + * @return mixed[]|null An associative array with server's statistics if available, NULL otherwise. + */ + public function getStats(); +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php new file mode 100755 index 0000000..180482a --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php @@ -0,0 +1,325 @@ +namespace = (string) $namespace; + $this->namespaceVersion = null; + } + + /** + * Retrieves the namespace that prefixes all cache ids. + * + * @return string + */ + public function getNamespace() + { + return $this->namespace; + } + + /** + * {@inheritdoc} + */ + public function fetch($id) + { + return $this->doFetch($this->getNamespacedId($id)); + } + + /** + * {@inheritdoc} + */ + public function fetchMultiple(array $keys) + { + if (empty($keys)) { + return []; + } + + // note: the array_combine() is in place to keep an association between our $keys and the $namespacedKeys + $namespacedKeys = array_combine($keys, array_map([$this, 'getNamespacedId'], $keys)); + $items = $this->doFetchMultiple($namespacedKeys); + $foundItems = []; + + // no internal array function supports this sort of mapping: needs to be iterative + // this filters and combines keys in one pass + foreach ($namespacedKeys as $requestedKey => $namespacedKey) { + if (! isset($items[$namespacedKey]) && ! array_key_exists($namespacedKey, $items)) { + continue; + } + + $foundItems[$requestedKey] = $items[$namespacedKey]; + } + + return $foundItems; + } + + /** + * {@inheritdoc} + */ + public function saveMultiple(array $keysAndValues, $lifetime = 0) + { + $namespacedKeysAndValues = []; + foreach ($keysAndValues as $key => $value) { + $namespacedKeysAndValues[$this->getNamespacedId($key)] = $value; + } + + return $this->doSaveMultiple($namespacedKeysAndValues, $lifetime); + } + + /** + * {@inheritdoc} + */ + public function contains($id) + { + return $this->doContains($this->getNamespacedId($id)); + } + + /** + * {@inheritdoc} + */ + public function save($id, $data, $lifeTime = 0) + { + return $this->doSave($this->getNamespacedId($id), $data, $lifeTime); + } + + /** + * {@inheritdoc} + */ + public function deleteMultiple(array $keys) + { + return $this->doDeleteMultiple(array_map([$this, 'getNamespacedId'], $keys)); + } + + /** + * {@inheritdoc} + */ + public function delete($id) + { + return $this->doDelete($this->getNamespacedId($id)); + } + + /** + * {@inheritdoc} + */ + public function getStats() + { + return $this->doGetStats(); + } + + /** + * {@inheritDoc} + */ + public function flushAll() + { + return $this->doFlush(); + } + + /** + * {@inheritDoc} + */ + public function deleteAll() + { + $namespaceCacheKey = $this->getNamespaceCacheKey(); + $namespaceVersion = $this->getNamespaceVersion() + 1; + + if ($this->doSave($namespaceCacheKey, $namespaceVersion)) { + $this->namespaceVersion = $namespaceVersion; + + return true; + } + + return false; + } + + /** + * Prefixes the passed id with the configured namespace value. + * + * @param string $id The id to namespace. + * + * @return string The namespaced id. + */ + private function getNamespacedId(string $id): string + { + $namespaceVersion = $this->getNamespaceVersion(); + + return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion); + } + + /** + * Returns the namespace cache key. + */ + private function getNamespaceCacheKey(): string + { + return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace); + } + + /** + * Returns the namespace version. + */ + private function getNamespaceVersion(): int + { + if ($this->namespaceVersion !== null) { + return $this->namespaceVersion; + } + + $namespaceCacheKey = $this->getNamespaceCacheKey(); + $this->namespaceVersion = (int) $this->doFetch($namespaceCacheKey) ?: 1; + + return $this->namespaceVersion; + } + + /** + * Default implementation of doFetchMultiple. Each driver that supports multi-get should owerwrite it. + * + * @param string[] $keys Array of keys to retrieve from cache + * + * @return mixed[] Array of values retrieved for the given keys. + */ + protected function doFetchMultiple(array $keys) + { + $returnValues = []; + + foreach ($keys as $key) { + $item = $this->doFetch($key); + if ($item === false && ! $this->doContains($key)) { + continue; + } + + $returnValues[$key] = $item; + } + + return $returnValues; + } + + /** + * Fetches an entry from the cache. + * + * @param string $id The id of the cache entry to fetch. + * + * @return mixed|false The cached data or FALSE, if no cache entry exists for the given id. + */ + abstract protected function doFetch($id); + + /** + * Tests if an entry exists in the cache. + * + * @param string $id The cache id of the entry to check for. + * + * @return bool TRUE if a cache entry exists for the given cache id, FALSE otherwise. + */ + abstract protected function doContains($id); + + /** + * Default implementation of doSaveMultiple. Each driver that supports multi-put should override it. + * + * @param mixed[] $keysAndValues Array of keys and values to save in cache + * @param int $lifetime The lifetime. If != 0, sets a specific lifetime for these + * cache entries (0 => infinite lifeTime). + * + * @return bool TRUE if the operation was successful, FALSE if it wasn't. + */ + protected function doSaveMultiple(array $keysAndValues, $lifetime = 0) + { + $success = true; + + foreach ($keysAndValues as $key => $value) { + if ($this->doSave($key, $value, $lifetime)) { + continue; + } + + $success = false; + } + + return $success; + } + + /** + * Puts data into the cache. + * + * @param string $id The cache id. + * @param string $data The cache entry/data. + * @param int $lifeTime The lifetime. If != 0, sets a specific lifetime for this + * cache entry (0 => infinite lifeTime). + * + * @return bool TRUE if the entry was successfully stored in the cache, FALSE otherwise. + */ + abstract protected function doSave($id, $data, $lifeTime = 0); + + /** + * Default implementation of doDeleteMultiple. Each driver that supports multi-delete should override it. + * + * @param string[] $keys Array of keys to delete from cache + * + * @return bool TRUE if the operation was successful, FALSE if it wasn't + */ + protected function doDeleteMultiple(array $keys) + { + $success = true; + + foreach ($keys as $key) { + if ($this->doDelete($key)) { + continue; + } + + $success = false; + } + + return $success; + } + + /** + * Deletes a cache entry. + * + * @param string $id The cache id. + * + * @return bool TRUE if the cache entry was successfully deleted, FALSE otherwise. + */ + abstract protected function doDelete($id); + + /** + * Flushes all cache entries. + * + * @return bool TRUE if the cache entries were successfully flushed, FALSE otherwise. + */ + abstract protected function doFlush(); + + /** + * Retrieves cached information from the data store. + * + * @return mixed[]|null An associative array with server's statistics if available, NULL otherwise. + */ + abstract protected function doGetStats(); +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ClearableCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ClearableCache.php new file mode 100755 index 0000000..b94618e --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ClearableCache.php @@ -0,0 +1,21 @@ + infinite lifeTime). + * + * @return bool TRUE if the operation was successful, FALSE if it wasn't. + */ + public function saveMultiple(array $keysAndValues, $lifetime = 0); +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheAdapter.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheAdapter.php new file mode 100755 index 0000000..d3693b7 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheAdapter.php @@ -0,0 +1,340 @@ + */ + private $deferredItems = []; + + public static function wrap(Cache $cache): CacheItemPoolInterface + { + if ($cache instanceof DoctrineProvider && ! $cache->getNamespace()) { + return $cache->getPool(); + } + + if ($cache instanceof SymfonyDoctrineProvider && ! $cache->getNamespace()) { + $getPool = function () { + // phpcs:ignore Squiz.Scope.StaticThisUsage.Found + return $this->pool; + }; + + return $getPool->bindTo($cache, SymfonyDoctrineProvider::class)(); + } + + return new self($cache); + } + + private function __construct(Cache $cache) + { + $this->cache = $cache; + } + + /** @internal */ + public function getCache(): Cache + { + return $this->cache; + } + + /** + * {@inheritDoc} + */ + public function getItem($key): CacheItemInterface + { + assert(self::validKey($key)); + + if (isset($this->deferredItems[$key])) { + $this->commit(); + } + + $value = $this->cache->fetch($key); + + if (PHP_VERSION_ID >= 80000) { + if ($value !== false) { + return new TypedCacheItem($key, $value, true); + } + + return new TypedCacheItem($key, null, false); + } + + if ($value !== false) { + return new CacheItem($key, $value, true); + } + + return new CacheItem($key, null, false); + } + + /** + * {@inheritDoc} + */ + public function getItems(array $keys = []): array + { + if ($this->deferredItems) { + $this->commit(); + } + + assert(self::validKeys($keys)); + + $values = $this->doFetchMultiple($keys); + $items = []; + + if (PHP_VERSION_ID >= 80000) { + foreach ($keys as $key) { + if (array_key_exists($key, $values)) { + $items[$key] = new TypedCacheItem($key, $values[$key], true); + } else { + $items[$key] = new TypedCacheItem($key, null, false); + } + } + + return $items; + } + + foreach ($keys as $key) { + if (array_key_exists($key, $values)) { + $items[$key] = new CacheItem($key, $values[$key], true); + } else { + $items[$key] = new CacheItem($key, null, false); + } + } + + return $items; + } + + /** + * {@inheritDoc} + */ + public function hasItem($key): bool + { + assert(self::validKey($key)); + + if (isset($this->deferredItems[$key])) { + $this->commit(); + } + + return $this->cache->contains($key); + } + + public function clear(): bool + { + $this->deferredItems = []; + + if (! $this->cache instanceof ClearableCache) { + return false; + } + + return $this->cache->deleteAll(); + } + + /** + * {@inheritDoc} + */ + public function deleteItem($key): bool + { + assert(self::validKey($key)); + unset($this->deferredItems[$key]); + + return $this->cache->delete($key); + } + + /** + * {@inheritDoc} + */ + public function deleteItems(array $keys): bool + { + foreach ($keys as $key) { + assert(self::validKey($key)); + unset($this->deferredItems[$key]); + } + + return $this->doDeleteMultiple($keys); + } + + public function save(CacheItemInterface $item): bool + { + return $this->saveDeferred($item) && $this->commit(); + } + + public function saveDeferred(CacheItemInterface $item): bool + { + if (! $item instanceof CacheItem && ! $item instanceof TypedCacheItem) { + return false; + } + + $this->deferredItems[$item->getKey()] = $item; + + return true; + } + + public function commit(): bool + { + if (! $this->deferredItems) { + return true; + } + + $now = microtime(true); + $itemsCount = 0; + $byLifetime = []; + $expiredKeys = []; + + foreach ($this->deferredItems as $key => $item) { + $lifetime = ($item->getExpiry() ?? $now) - $now; + + if ($lifetime < 0) { + $expiredKeys[] = $key; + + continue; + } + + ++$itemsCount; + $byLifetime[(int) $lifetime][$key] = $item->get(); + } + + $this->deferredItems = []; + + switch (count($expiredKeys)) { + case 0: + break; + case 1: + $this->cache->delete(current($expiredKeys)); + break; + default: + $this->doDeleteMultiple($expiredKeys); + break; + } + + if ($itemsCount === 1) { + return $this->cache->save($key, $item->get(), (int) $lifetime); + } + + $success = true; + foreach ($byLifetime as $lifetime => $values) { + $success = $this->doSaveMultiple($values, $lifetime) && $success; + } + + return $success; + } + + public function __destruct() + { + $this->commit(); + } + + /** + * @param mixed $key + */ + private static function validKey($key): bool + { + if (! is_string($key)) { + throw new InvalidArgument(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key))); + } + + if ($key === '') { + throw new InvalidArgument('Cache key length must be greater than zero.'); + } + + if (strpbrk($key, self::RESERVED_CHARACTERS) !== false) { + throw new InvalidArgument(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS)); + } + + return true; + } + + /** + * @param mixed[] $keys + */ + private static function validKeys(array $keys): bool + { + foreach ($keys as $key) { + self::validKey($key); + } + + return true; + } + + /** + * @param mixed[] $keys + */ + private function doDeleteMultiple(array $keys): bool + { + if ($this->cache instanceof MultiDeleteCache) { + return $this->cache->deleteMultiple($keys); + } + + $success = true; + foreach ($keys as $key) { + $success = $this->cache->delete($key) && $success; + } + + return $success; + } + + /** + * @param mixed[] $keys + * + * @return mixed[] + */ + private function doFetchMultiple(array $keys): array + { + if ($this->cache instanceof MultiGetCache) { + return $this->cache->fetchMultiple($keys); + } + + $values = []; + foreach ($keys as $key) { + $value = $this->cache->fetch($key); + if (! $value) { + continue; + } + + $values[$key] = $value; + } + + return $values; + } + + /** + * @param mixed[] $keysAndValues + */ + private function doSaveMultiple(array $keysAndValues, int $lifetime = 0): bool + { + if ($this->cache instanceof MultiPutCache) { + return $this->cache->saveMultiple($keysAndValues, $lifetime); + } + + $success = true; + foreach ($keysAndValues as $key => $value) { + $success = $this->cache->save($key, $value, $lifetime) && $success; + } + + return $success; + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheItem.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheItem.php new file mode 100755 index 0000000..0b6f0a2 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheItem.php @@ -0,0 +1,118 @@ +key = $key; + $this->value = $data; + $this->isHit = $isHit; + } + + public function getKey(): string + { + return $this->key; + } + + /** + * {@inheritDoc} + * + * @return mixed + */ + public function get() + { + return $this->value; + } + + public function isHit(): bool + { + return $this->isHit; + } + + /** + * {@inheritDoc} + */ + public function set($value): self + { + $this->value = $value; + + return $this; + } + + /** + * {@inheritDoc} + */ + public function expiresAt($expiration): self + { + if ($expiration === null) { + $this->expiry = null; + } elseif ($expiration instanceof DateTimeInterface) { + $this->expiry = (float) $expiration->format('U.u'); + } else { + throw new TypeError(sprintf( + 'Expected $expiration to be an instance of DateTimeInterface or null, got %s', + is_object($expiration) ? get_class($expiration) : gettype($expiration) + )); + } + + return $this; + } + + /** + * {@inheritDoc} + */ + public function expiresAfter($time): self + { + if ($time === null) { + $this->expiry = null; + } elseif ($time instanceof DateInterval) { + $this->expiry = microtime(true) + DateTime::createFromFormat('U', 0)->add($time)->format('U.u'); + } elseif (is_int($time)) { + $this->expiry = $time + microtime(true); + } else { + throw new TypeError(sprintf( + 'Expected $time to be either an integer, an instance of DateInterval or null, got %s', + is_object($time) ? get_class($time) : gettype($time) + )); + } + + return $this; + } + + /** + * @internal + */ + public function getExpiry(): ?float + { + return $this->expiry; + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/DoctrineProvider.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/DoctrineProvider.php new file mode 100755 index 0000000..c15497e --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/DoctrineProvider.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Doctrine\Common\Cache\Psr6; + +use Doctrine\Common\Cache\Cache; +use Doctrine\Common\Cache\CacheProvider; +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Cache\Adapter\DoctrineAdapter as SymfonyDoctrineAdapter; + +use function rawurlencode; + +/** + * This class was copied from the Symfony Framework, see the original copyright + * notice above. The code is distributed subject to the license terms in + * https://github.com/symfony/symfony/blob/ff0cf61278982539c49e467db9ab13cbd342f76d/LICENSE + */ +final class DoctrineProvider extends CacheProvider +{ + /** @var CacheItemPoolInterface */ + private $pool; + + public static function wrap(CacheItemPoolInterface $pool): Cache + { + if ($pool instanceof CacheAdapter) { + return $pool->getCache(); + } + + if ($pool instanceof SymfonyDoctrineAdapter) { + $getCache = function () { + // phpcs:ignore Squiz.Scope.StaticThisUsage.Found + return $this->provider; + }; + + return $getCache->bindTo($pool, SymfonyDoctrineAdapter::class)(); + } + + return new self($pool); + } + + private function __construct(CacheItemPoolInterface $pool) + { + $this->pool = $pool; + } + + /** @internal */ + public function getPool(): CacheItemPoolInterface + { + return $this->pool; + } + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + $item = $this->pool->getItem(rawurlencode($id)); + + return $item->isHit() ? $item->get() : false; + } + + /** + * {@inheritdoc} + * + * @return bool + */ + protected function doContains($id) + { + return $this->pool->hasItem(rawurlencode($id)); + } + + /** + * {@inheritdoc} + * + * @return bool + */ + protected function doSave($id, $data, $lifeTime = 0) + { + $item = $this->pool->getItem(rawurlencode($id)); + + if (0 < $lifeTime) { + $item->expiresAfter($lifeTime); + } + + return $this->pool->save($item->set($data)); + } + + /** + * {@inheritdoc} + * + * @return bool + */ + protected function doDelete($id) + { + return $this->pool->deleteItem(rawurlencode($id)); + } + + /** + * {@inheritdoc} + * + * @return bool + */ + protected function doFlush() + { + return $this->pool->clear(); + } + + /** + * {@inheritdoc} + * + * @return array|null + */ + protected function doGetStats() + { + return null; + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/InvalidArgument.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/InvalidArgument.php new file mode 100755 index 0000000..196f1bc --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/InvalidArgument.php @@ -0,0 +1,13 @@ +key; + } + + public function get(): mixed + { + return $this->value; + } + + public function isHit(): bool + { + return $this->isHit; + } + + public function set(mixed $value): static + { + $this->value = $value; + + return $this; + } + + /** + * {@inheritDoc} + */ + public function expiresAt($expiration): static + { + if ($expiration === null) { + $this->expiry = null; + } elseif ($expiration instanceof DateTimeInterface) { + $this->expiry = (float) $expiration->format('U.u'); + } else { + throw new TypeError(sprintf( + 'Expected $expiration to be an instance of DateTimeInterface or null, got %s', + get_debug_type($expiration) + )); + } + + return $this; + } + + /** + * {@inheritDoc} + */ + public function expiresAfter($time): static + { + if ($time === null) { + $this->expiry = null; + } elseif ($time instanceof DateInterval) { + $this->expiry = microtime(true) + DateTime::createFromFormat('U', 0)->add($time)->format('U.u'); + } elseif (is_int($time)) { + $this->expiry = $time + microtime(true); + } else { + throw new TypeError(sprintf( + 'Expected $time to be either an integer, an instance of DateInterval or null, got %s', + get_debug_type($time) + )); + } + + return $this; + } + + /** + * @internal + */ + public function getExpiry(): ?float + { + return $this->expiry; + } +} diff --git a/vendor/doctrine/dbal/CONTRIBUTING.md b/vendor/doctrine/dbal/CONTRIBUTING.md new file mode 100755 index 0000000..c2555eb --- /dev/null +++ b/vendor/doctrine/dbal/CONTRIBUTING.md @@ -0,0 +1,4 @@ +Doctrine has [general contributing guidelines][contributor workflow], make +sure you follow them. + +[contributor workflow]: https://www.doctrine-project.org/contribute/index.html diff --git a/vendor/doctrine/dbal/LICENSE b/vendor/doctrine/dbal/LICENSE new file mode 100755 index 0000000..e8fdec4 --- /dev/null +++ b/vendor/doctrine/dbal/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2018 Doctrine Project + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/doctrine/dbal/README.md b/vendor/doctrine/dbal/README.md new file mode 100755 index 0000000..43caa5a --- /dev/null +++ b/vendor/doctrine/dbal/README.md @@ -0,0 +1,42 @@ +# Doctrine DBAL + +| [4.0-dev][4.0] | [3.1][3.1] | [2.13][2.13] | +|:----------------:|:----------:|:----------:| +| [![GitHub Actions][GA 4.0 image]][GA 4.0] | [![GitHub Actions][GA 3.1 image]][GA 3.1] | [![GitHub Actions][GA 2.13 image]][GA 2.13] | +| [![AppVeyor][AppVeyor 4.0 image]][AppVeyor 4.0] | [![AppVeyor][AppVeyor 3.1 image]][AppVeyor 3.1] | [![AppVeyor][AppVeyor 2.13 image]][AppVeyor 2.13] | +| [![Code Coverage][Coverage image]][CodeCov 4.0] | [![Code Coverage][Coverage 3.1 image]][CodeCov 3.1] | [![Code Coverage][Coverage 2.13 image]][CodeCov 2.13] | +| N/A | [![Code Coverage][TypeCov 3.1 image]][TypeCov 3.1] | N/A | + +Powerful database abstraction layer with many features for database schema introspection, schema management and PDO abstraction. + +## More resources: + +* [Website](http://www.doctrine-project.org/projects/dbal.html) +* [Documentation](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/) +* [Issue Tracker](https://github.com/doctrine/dbal/issues) + + [Coverage image]: https://codecov.io/gh/doctrine/dbal/branch/4.0.x/graph/badge.svg + [4.0]: https://github.com/doctrine/dbal/tree/4.0.x + [CodeCov 4.0]: https://codecov.io/gh/doctrine/dbal/branch/4.0.x + [AppVeyor 4.0]: https://ci.appveyor.com/project/doctrine/dbal/branch/4.0.x + [AppVeyor 4.0 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/4.0.x?svg=true + [GA 4.0]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.0.x + [GA 4.0 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg + + [Coverage 3.1 image]: https://codecov.io/gh/doctrine/dbal/branch/3.1.x/graph/badge.svg + [3.1]: https://github.com/doctrine/dbal/tree/3.1.x + [CodeCov 3.1]: https://codecov.io/gh/doctrine/dbal/branch/3.1.x + [AppVeyor 3.1]: https://ci.appveyor.com/project/doctrine/dbal/branch/3.1.x + [AppVeyor 3.1 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/3.1.x?svg=true + [GA 3.1]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A3.1.x + [GA 3.1 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=3.1.x + + [Coverage 2.13 image]: https://codecov.io/gh/doctrine/dbal/branch/2.13.x/graph/badge.svg + [2.13]: https://github.com/doctrine/dbal/tree/2.13.x + [CodeCov 2.13]: https://codecov.io/gh/doctrine/dbal/branch/2.13.x + [AppVeyor 2.13]: https://ci.appveyor.com/project/doctrine/dbal/branch/2.13.x + [AppVeyor 2.13 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/2.13.x?svg=true + [GA 2.13]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A2.13.x + [GA 2.13 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=2.13.x + [TypeCov 3.1]: https://shepherd.dev/github/doctrine/dbal + [TypeCov 3.1 image]: https://shepherd.dev/github/doctrine/dbal/coverage.svg diff --git a/vendor/doctrine/dbal/bin/doctrine-dbal b/vendor/doctrine/dbal/bin/doctrine-dbal new file mode 100755 index 0000000..0531527 --- /dev/null +++ b/vendor/doctrine/dbal/bin/doctrine-dbal @@ -0,0 +1,4 @@ +#!/usr/bin/env php +> + * + * @throws Exception + */ + public function iterateNumeric(): Traversable; + + /** + * Returns an iterator over the result set rows represented as associative arrays. + * + * @return Traversable> + * + * @throws Exception + */ + public function iterateAssociative(): Traversable; + + /** + * Returns an iterator over the values of the first column of the result set. + * + * @return Traversable + * + * @throws Exception + */ + public function iterateColumn(): Traversable; +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ArrayStatement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ArrayStatement.php new file mode 100755 index 0000000..07c44f2 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ArrayStatement.php @@ -0,0 +1,244 @@ +data = $data; + if (! count($data)) { + return; + } + + $this->columnCount = count($data[0]); + } + + /** + * {@inheritdoc} + * + * @deprecated Use free() instead. + */ + public function closeCursor() + { + $this->free(); + + return true; + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + return count($this->data); + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + return $this->columnCount; + } + + /** + * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + if ($arg2 !== null || $arg3 !== null) { + throw new InvalidArgumentException('Caching layer does not support 2nd/3rd argument to setFetchMode()'); + } + + $this->defaultFetchMode = $fetchMode; + + return true; + } + + /** + * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. + */ + #[ReturnTypeWillChange] + public function getIterator() + { + $data = $this->fetchAll(); + + return new ArrayIterator($data); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + */ + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + if (! isset($this->data[$this->num])) { + return false; + } + + $row = $this->data[$this->num++]; + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + + if ($fetchMode === FetchMode::ASSOCIATIVE) { + return $row; + } + + if ($fetchMode === FetchMode::NUMERIC) { + return array_values($row); + } + + if ($fetchMode === FetchMode::MIXED) { + return array_merge($row, array_values($row)); + } + + if ($fetchMode === FetchMode::COLUMN) { + return reset($row); + } + + throw new InvalidArgumentException('Invalid fetch-style given for fetching result.'); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + $rows = []; + while ($row = $this->fetch($fetchMode)) { + $rows[] = $row; + } + + return $rows; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. + */ + public function fetchColumn($columnIndex = 0) + { + $row = $this->fetch(FetchMode::NUMERIC); + + // TODO: verify that return false is the correct behavior + return $row[$columnIndex] ?? false; + } + + /** + * {@inheritdoc} + */ + public function fetchNumeric() + { + $row = $this->doFetch(); + + if ($row === false) { + return false; + } + + return array_values($row); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + return $this->doFetch(); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + $row = $this->doFetch(); + + if ($row === false) { + return false; + } + + return reset($row); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric(): array + { + return FetchUtils::fetchAllNumeric($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative(): array + { + return FetchUtils::fetchAllAssociative($this); + } + + /** + * {@inheritdoc} + */ + public function fetchFirstColumn(): array + { + return FetchUtils::fetchFirstColumn($this); + } + + public function free(): void + { + $this->data = []; + } + + /** + * @return mixed|false + */ + private function doFetch() + { + if (! isset($this->data[$this->num])) { + return false; + } + + return $this->data[$this->num++]; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/CacheException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/CacheException.php new file mode 100755 index 0000000..3db115b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/CacheException.php @@ -0,0 +1,27 @@ +lifetime = $lifetime; + $this->cacheKey = $cacheKey; + $this->resultCacheDriver = $resultCache; + } + + /** + * @return Cache|null + */ + public function getResultCacheDriver() + { + return $this->resultCacheDriver; + } + + /** + * @return int + */ + public function getLifetime() + { + return $this->lifetime; + } + + /** + * @return string + * + * @throws CacheException + */ + public function getCacheKey() + { + if ($this->cacheKey === null) { + throw CacheException::noCacheKey(); + } + + return $this->cacheKey; + } + + /** + * Generates the real cache key from query, params, types and connection parameters. + * + * @param string $sql + * @param array|array $params + * @param array|array $types + * @param array $connectionParams + * + * @return string[] + */ + public function generateCacheKeys($sql, $params, $types, array $connectionParams = []) + { + $realCacheKey = 'query=' . $sql . + '¶ms=' . serialize($params) . + '&types=' . serialize($types) . + '&connectionParams=' . hash('sha256', serialize($connectionParams)); + + // should the key be automatically generated using the inputs or is the cache key set? + if ($this->cacheKey === null) { + $cacheKey = sha1($realCacheKey); + } else { + $cacheKey = $this->cacheKey; + } + + return [$cacheKey, $realCacheKey]; + } + + /** + * @return QueryCacheProfile + */ + public function setResultCacheDriver(Cache $cache) + { + return new QueryCacheProfile($this->lifetime, $this->cacheKey, $cache); + } + + /** + * @param string|null $cacheKey + * + * @return QueryCacheProfile + */ + public function setCacheKey($cacheKey) + { + return new QueryCacheProfile($this->lifetime, $cacheKey, $this->resultCacheDriver); + } + + /** + * @param int $lifetime + * + * @return QueryCacheProfile + */ + public function setLifetime($lifetime) + { + return new QueryCacheProfile($lifetime, $this->cacheKey, $this->resultCacheDriver); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php new file mode 100755 index 0000000..96e3219 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php @@ -0,0 +1,361 @@ +>|null */ + private $data; + + /** @var int */ + private $defaultFetchMode = FetchMode::MIXED; + + /** + * @param string $cacheKey + * @param string $realKey + * @param int $lifetime + */ + public function __construct(ResultStatement $stmt, Cache $resultCache, $cacheKey, $realKey, $lifetime) + { + $this->statement = $stmt; + $this->resultCache = $resultCache; + $this->cacheKey = $cacheKey; + $this->realKey = $realKey; + $this->lifetime = $lifetime; + } + + /** + * {@inheritdoc} + * + * @deprecated Use free() instead. + */ + public function closeCursor() + { + $this->free(); + + return true; + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + return $this->statement->columnCount(); + } + + /** + * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->defaultFetchMode = $fetchMode; + + return true; + } + + /** + * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. + */ + #[ReturnTypeWillChange] + public function getIterator() + { + $data = $this->fetchAll(); + + return new ArrayIterator($data); + } + + /** + * Be warned that you will need to call this method until no rows are + * available for caching to happen. + * + * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + */ + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + if ($this->data === null) { + $this->data = []; + } + + $row = $this->statement->fetch(FetchMode::ASSOCIATIVE); + + if ($row) { + $this->data[] = $row; + + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + + if ($fetchMode === FetchMode::ASSOCIATIVE) { + return $row; + } + + if ($fetchMode === FetchMode::NUMERIC) { + return array_values($row); + } + + if ($fetchMode === FetchMode::MIXED) { + return array_merge($row, array_values($row)); + } + + if ($fetchMode === FetchMode::COLUMN) { + return reset($row); + } + + throw new InvalidArgumentException('Invalid fetch-style given for caching result.'); + } + + $this->saveToCache(); + + return false; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + $data = $this->statement->fetchAll(FetchMode::ASSOCIATIVE, $fetchArgument, $ctorArgs); + + $this->data = $data; + + $this->saveToCache(); + + if ($fetchMode === FetchMode::NUMERIC) { + foreach ($data as $i => $row) { + $data[$i] = array_values($row); + } + } elseif ($fetchMode === FetchMode::MIXED) { + foreach ($data as $i => $row) { + $data[$i] = array_merge($row, array_values($row)); + } + } elseif ($fetchMode === FetchMode::COLUMN) { + foreach ($data as $i => $row) { + $data[$i] = reset($row); + } + } + + return $data; + } + + /** + * Be warned that you will need to call this method until no rows are + * available for caching to happen. + * + * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. + */ + public function fetchColumn($columnIndex = 0) + { + $row = $this->fetch(FetchMode::NUMERIC); + + // TODO: verify that return false is the correct behavior + return $row[$columnIndex] ?? false; + } + + /** + * Be warned that you will need to call this method until no rows are + * available for caching to happen. + * + * {@inheritdoc} + */ + public function fetchNumeric() + { + $row = $this->doFetch(); + + if ($row === false) { + return false; + } + + return array_values($row); + } + + /** + * Be warned that you will need to call this method until no rows are + * available for caching to happen. + * + * {@inheritdoc} + */ + public function fetchAssociative() + { + return $this->doFetch(); + } + + /** + * Be warned that you will need to call this method until no rows are + * available for caching to happen. + * + * {@inheritdoc} + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric(): array + { + if ($this->statement instanceof Result) { + $data = $this->statement->fetchAllAssociative(); + } else { + $data = $this->statement->fetchAll(FetchMode::ASSOCIATIVE); + } + + $this->data = $data; + + $this->saveToCache(); + + return array_map('array_values', $data); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative(): array + { + if ($this->statement instanceof Result) { + $data = $this->statement->fetchAllAssociative(); + } else { + $data = $this->statement->fetchAll(FetchMode::ASSOCIATIVE); + } + + $this->data = $data; + + $this->saveToCache(); + + return $data; + } + + /** + * {@inheritdoc} + */ + public function fetchFirstColumn(): array + { + return FetchUtils::fetchFirstColumn($this); + } + + /** + * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement + * executed by the corresponding object. + * + * If the last SQL statement executed by the associated Statement object was a SELECT statement, + * some databases may return the number of rows returned by that statement. However, + * this behaviour is not guaranteed for all databases and should not be + * relied on for portable applications. + * + * @return int The number of rows. + */ + public function rowCount() + { + assert($this->statement instanceof Statement); + + return $this->statement->rowCount(); + } + + public function free(): void + { + $this->data = null; + } + + /** + * @return array|false + * + * @throws Exception + */ + private function doFetch() + { + if ($this->data === null) { + $this->data = []; + } + + if ($this->statement instanceof Result) { + $row = $this->statement->fetchAssociative(); + } else { + $row = $this->statement->fetch(FetchMode::ASSOCIATIVE); + } + + if ($row !== false) { + $this->data[] = $row; + + return $row; + } + + $this->saveToCache(); + + return false; + } + + private function saveToCache(): void + { + if ($this->data === null) { + return; + } + + $data = $this->resultCache->fetch($this->cacheKey); + if (! $data) { + $data = []; + } + + $data[$this->realKey] = $this->data; + + $this->resultCache->save($this->cacheKey, $data, $this->lifetime); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/ColumnCase.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/ColumnCase.php new file mode 100755 index 0000000..c26aac1 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/ColumnCase.php @@ -0,0 +1,34 @@ +_attributes['sqlLogger'] = $logger; + } + + /** + * Gets the SQL logger that is used. + * + * @return SQLLogger|null + */ + public function getSQLLogger() + { + return $this->_attributes['sqlLogger'] ?? null; + } + + /** + * Gets the cache driver implementation that is used for query result caching. + * + * @return Cache|null + */ + public function getResultCacheImpl() + { + return $this->_attributes['resultCacheImpl'] ?? null; + } + + /** + * Sets the cache driver implementation that is used for query result caching. + * + * @return void + */ + public function setResultCacheImpl(Cache $cacheImpl) + { + $this->_attributes['resultCacheImpl'] = $cacheImpl; + } + + /** + * Sets the filter schema assets expression. + * + * Only include tables/sequences matching the filter expression regexp in + * schema instances generated for the active connection when calling + * {AbstractSchemaManager#createSchema()}. + * + * @deprecated Use Configuration::setSchemaAssetsFilter() instead + * + * @param string|null $filterExpression + * + * @return void + */ + public function setFilterSchemaAssetsExpression($filterExpression) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3316', + 'Configuration::setFilterSchemaAssetsExpression() is deprecated, use setSchemaAssetsFilter() instead.' + ); + + $this->_attributes['filterSchemaAssetsExpression'] = $filterExpression; + if ($filterExpression) { + $this->_attributes['filterSchemaAssetsExpressionCallable'] + = $this->buildSchemaAssetsFilterFromExpression($filterExpression); + } else { + $this->_attributes['filterSchemaAssetsExpressionCallable'] = null; + } + } + + /** + * Returns filter schema assets expression. + * + * @deprecated Use Configuration::getSchemaAssetsFilter() instead + * + * @return string|null + */ + public function getFilterSchemaAssetsExpression() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3316', + 'Configuration::getFilterSchemaAssetsExpression() is deprecated, use getSchemaAssetsFilter() instead.' + ); + + return $this->_attributes['filterSchemaAssetsExpression'] ?? null; + } + + /** + * @param string $filterExpression + * + * @return callable(string|AbstractAsset) + */ + private function buildSchemaAssetsFilterFromExpression($filterExpression): callable + { + return static function ($assetName) use ($filterExpression) { + if ($assetName instanceof AbstractAsset) { + $assetName = $assetName->getName(); + } + + return preg_match($filterExpression, $assetName); + }; + } + + /** + * Sets the callable to use to filter schema assets. + */ + public function setSchemaAssetsFilter(?callable $callable = null): ?callable + { + $this->_attributes['filterSchemaAssetsExpression'] = null; + + return $this->_attributes['filterSchemaAssetsExpressionCallable'] = $callable; + } + + /** + * Returns the callable to use to filter schema assets. + */ + public function getSchemaAssetsFilter(): ?callable + { + return $this->_attributes['filterSchemaAssetsExpressionCallable'] ?? null; + } + + /** + * Sets the default auto-commit mode for connections. + * + * If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual + * transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either + * the method commit or the method rollback. By default, new connections are in auto-commit mode. + * + * @see getAutoCommit + * + * @param bool $autoCommit True to enable auto-commit mode; false to disable it. + * + * @return void + */ + public function setAutoCommit($autoCommit) + { + $this->_attributes['autoCommit'] = (bool) $autoCommit; + } + + /** + * Returns the default auto-commit mode for connections. + * + * @see setAutoCommit + * + * @return bool True if auto-commit mode is enabled by default for connections, false otherwise. + */ + public function getAutoCommit() + { + return $this->_attributes['autoCommit'] ?? true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php new file mode 100755 index 0000000..68b8263 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php @@ -0,0 +1,2271 @@ + + * @phpstan-var array + * @psalm-var Params + */ + private $params; + + /** + * The database platform object used by the connection or NULL before it's initialized. + * + * @var AbstractPlatform|null + */ + private $platform; + + /** + * The schema manager. + * + * @var AbstractSchemaManager|null + */ + protected $_schemaManager; + + /** + * The used DBAL driver. + * + * @var Driver + */ + protected $_driver; + + /** + * Flag that indicates whether the current transaction is marked for rollback only. + * + * @var bool + */ + private $isRollbackOnly = false; + + /** @var int */ + protected $defaultFetchMode = FetchMode::ASSOCIATIVE; + + /** + * Initializes a new instance of the Connection class. + * + * @internal The connection can be only instantiated by the driver manager. + * + * @param array $params The connection parameters. + * @param Driver $driver The driver to use. + * @param Configuration|null $config The configuration, optional. + * @param EventManager|null $eventManager The event manager, optional. + * @psalm-param Params $params + * @phpstan-param array $params + * + * @throws Exception + */ + public function __construct( + array $params, + Driver $driver, + ?Configuration $config = null, + ?EventManager $eventManager = null + ) { + $this->_driver = $driver; + $this->params = $params; + + if (isset($params['pdo'])) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3554', + 'Passing a user provided PDO instance directly to Doctrine is deprecated.' + ); + + if (! $params['pdo'] instanceof PDO) { + throw Exception::invalidPdoInstance(); + } + + $this->_conn = $params['pdo']; + $this->_conn->setAttribute(PDO::ATTR_STATEMENT_CLASS, [PDODriverStatement::class, []]); + unset($this->params['pdo']); + } + + if (isset($params['platform'])) { + if (! $params['platform'] instanceof Platforms\AbstractPlatform) { + throw Exception::invalidPlatformType($params['platform']); + } + + $this->platform = $params['platform']; + } + + // Create default config and event manager if none given + if (! $config) { + $config = new Configuration(); + } + + if (! $eventManager) { + $eventManager = new EventManager(); + } + + $this->_config = $config; + $this->_eventManager = $eventManager; + + $this->_expr = new Query\Expression\ExpressionBuilder($this); + + $this->autoCommit = $config->getAutoCommit(); + } + + /** + * Gets the parameters used during instantiation. + * + * @internal + * + * @return array + * @psalm-return Params + * @phpstan-return array + */ + public function getParams() + { + return $this->params; + } + + /** + * Gets the name of the database this Connection is connected to. + * + * @return string + */ + public function getDatabase() + { + return $this->_driver->getDatabase($this); + } + + /** + * Gets the hostname of the currently connected database. + * + * @deprecated + * + * @return string|null + */ + public function getHost() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Connection::getHost() is deprecated, get the database server host from application config ' . + 'or as a last resort from internal Connection::getParams() API.' + ); + + return $this->params['host'] ?? null; + } + + /** + * Gets the port of the currently connected database. + * + * @deprecated + * + * @return mixed + */ + public function getPort() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Connection::getPort() is deprecated, get the database server port from application config ' . + 'or as a last resort from internal Connection::getParams() API.' + ); + + return $this->params['port'] ?? null; + } + + /** + * Gets the username used by this connection. + * + * @deprecated + * + * @return string|null + */ + public function getUsername() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Connection::getUsername() is deprecated, get the username from application config ' . + 'or as a last resort from internal Connection::getParams() API.' + ); + + return $this->params['user'] ?? null; + } + + /** + * Gets the password used by this connection. + * + * @deprecated + * + * @return string|null + */ + public function getPassword() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Connection::getPassword() is deprecated, get the password from application config ' . + 'or as a last resort from internal Connection::getParams() API.' + ); + + return $this->params['password'] ?? null; + } + + /** + * Gets the DBAL driver instance. + * + * @return Driver + */ + public function getDriver() + { + return $this->_driver; + } + + /** + * Gets the Configuration used by the Connection. + * + * @return Configuration + */ + public function getConfiguration() + { + return $this->_config; + } + + /** + * Gets the EventManager used by the Connection. + * + * @return EventManager + */ + public function getEventManager() + { + return $this->_eventManager; + } + + /** + * Gets the DatabasePlatform for the connection. + * + * @return AbstractPlatform + * + * @throws Exception + */ + public function getDatabasePlatform() + { + if ($this->platform === null) { + $this->platform = $this->detectDatabasePlatform(); + $this->platform->setEventManager($this->_eventManager); + } + + return $this->platform; + } + + /** + * Gets the ExpressionBuilder for the connection. + * + * @return ExpressionBuilder + */ + public function getExpressionBuilder() + { + return $this->_expr; + } + + /** + * Establishes the connection with the database. + * + * @return bool TRUE if the connection was successfully established, FALSE if + * the connection is already open. + */ + public function connect() + { + if ($this->_conn !== null) { + return false; + } + + $driverOptions = $this->params['driverOptions'] ?? []; + $user = $this->params['user'] ?? null; + $password = $this->params['password'] ?? null; + + $this->_conn = $this->_driver->connect($this->params, $user, $password, $driverOptions); + + $this->transactionNestingLevel = 0; + + if ($this->autoCommit === false) { + $this->beginTransaction(); + } + + if ($this->_eventManager->hasListeners(Events::postConnect)) { + $eventArgs = new Event\ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + } + + return true; + } + + /** + * Detects and sets the database platform. + * + * Evaluates custom platform class and version in order to set the correct platform. + * + * @throws Exception If an invalid platform was specified for this connection. + */ + private function detectDatabasePlatform(): AbstractPlatform + { + $version = $this->getDatabasePlatformVersion(); + + if ($version !== null) { + assert($this->_driver instanceof VersionAwarePlatformDriver); + + return $this->_driver->createDatabasePlatformForVersion($version); + } + + return $this->_driver->getDatabasePlatform(); + } + + /** + * Returns the version of the related platform if applicable. + * + * Returns null if either the driver is not capable to create version + * specific platform instances, no explicit server version was specified + * or the underlying driver connection cannot determine the platform + * version without having to query it (performance reasons). + * + * @return string|null + * + * @throws Throwable + */ + private function getDatabasePlatformVersion() + { + // Driver does not support version specific platforms. + if (! $this->_driver instanceof VersionAwarePlatformDriver) { + return null; + } + + // Explicit platform version requested (supersedes auto-detection). + if (isset($this->params['serverVersion'])) { + return $this->params['serverVersion']; + } + + // If not connected, we need to connect now to determine the platform version. + if ($this->_conn === null) { + try { + $this->connect(); + } catch (Throwable $originalException) { + if (empty($this->params['dbname'])) { + throw $originalException; + } + + // The database to connect to might not yet exist. + // Retry detection without database name connection parameter. + $params = $this->params; + + unset($this->params['dbname']); + + try { + $this->connect(); + } catch (Throwable $fallbackException) { + // Either the platform does not support database-less connections + // or something else went wrong. + throw $originalException; + } finally { + $this->params = $params; + } + + $serverVersion = $this->getServerVersion(); + + // Close "temporary" connection to allow connecting to the real database again. + $this->close(); + + return $serverVersion; + } + } + + return $this->getServerVersion(); + } + + /** + * Returns the database server version if the underlying driver supports it. + * + * @return string|null + */ + private function getServerVersion() + { + $connection = $this->getWrappedConnection(); + + // Automatic platform version detection. + if ($connection instanceof ServerInfoAwareConnection && ! $connection->requiresQueryForServerVersion()) { + return $connection->getServerVersion(); + } + + // Unable to detect platform version. + return null; + } + + /** + * Returns the current auto-commit mode for this connection. + * + * @see setAutoCommit + * + * @return bool True if auto-commit mode is currently enabled for this connection, false otherwise. + */ + public function isAutoCommit() + { + return $this->autoCommit === true; + } + + /** + * Sets auto-commit mode for this connection. + * + * If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual + * transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either + * the method commit or the method rollback. By default, new connections are in auto-commit mode. + * + * NOTE: If this method is called during a transaction and the auto-commit mode is changed, the transaction is + * committed. If this method is called and the auto-commit mode is not changed, the call is a no-op. + * + * @see isAutoCommit + * + * @param bool $autoCommit True to enable auto-commit mode; false to disable it. + * + * @return void + */ + public function setAutoCommit($autoCommit) + { + $autoCommit = (bool) $autoCommit; + + // Mode not changed, no-op. + if ($autoCommit === $this->autoCommit) { + return; + } + + $this->autoCommit = $autoCommit; + + // Commit all currently active transactions if any when switching auto-commit mode. + if ($this->_conn === null || $this->transactionNestingLevel === 0) { + return; + } + + $this->commitAll(); + } + + /** + * Sets the fetch mode. + * + * @deprecated Use one of the fetch- or iterate-related methods. + * + * @param int $fetchMode + * + * @return void + */ + public function setFetchMode($fetchMode) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Default Fetch Mode configuration is deprecated, use explicit Connection::fetch*() APIs instead.' + ); + + $this->defaultFetchMode = $fetchMode; + } + + /** + * Prepares and executes an SQL query and returns the first row of the result + * as an associative array. + * + * @deprecated Use fetchAssociative() + * + * @param string $sql SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return array|false False is returned if no rows are found. + * + * @throws Exception + */ + public function fetchAssoc($sql, array $params = [], array $types = []) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Connection::fetchAssoc() is deprecated, use Connection::fetchAssociative() API instead.' + ); + + return $this->executeQuery($sql, $params, $types)->fetch(FetchMode::ASSOCIATIVE); + } + + /** + * Prepares and executes an SQL query and returns the first row of the result + * as a numerically indexed array. + * + * @deprecated Use fetchNumeric() + * + * @param string $sql SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return array|false False is returned if no rows are found. + */ + public function fetchArray($sql, array $params = [], array $types = []) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Connection::fetchArray() is deprecated, use Connection::fetchNumeric() API instead.' + ); + + return $this->executeQuery($sql, $params, $types)->fetch(FetchMode::NUMERIC); + } + + /** + * Prepares and executes an SQL query and returns the value of a single column + * of the first row of the result. + * + * @deprecated Use fetchOne() instead. + * + * @param string $sql SQL query + * @param array|array $params Query parameters + * @param int $column 0-indexed column number + * @param array|array $types Parameter types + * + * @return mixed|false False is returned if no rows are found. + * + * @throws Exception + */ + public function fetchColumn($sql, array $params = [], $column = 0, array $types = []) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Connection::fetchColumn() is deprecated, use Connection::fetchOne() API instead.' + ); + + return $this->executeQuery($sql, $params, $types)->fetchColumn($column); + } + + /** + * Prepares and executes an SQL query and returns the first row of the result + * as an associative array. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return array|false False is returned if no rows are found. + * + * @throws Exception + */ + public function fetchAssociative(string $query, array $params = [], array $types = []) + { + try { + $stmt = $this->ensureForwardCompatibilityStatement( + $this->executeQuery($query, $params, $types) + ); + + return $stmt->fetchAssociative(); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $query, $params, $types); + } + } + + /** + * Prepares and executes an SQL query and returns the first row of the result + * as a numerically indexed array. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return array|false False is returned if no rows are found. + * + * @throws Exception + */ + public function fetchNumeric(string $query, array $params = [], array $types = []) + { + try { + $stmt = $this->ensureForwardCompatibilityStatement( + $this->executeQuery($query, $params, $types) + ); + + return $stmt->fetchNumeric(); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $query, $params, $types); + } + } + + /** + * Prepares and executes an SQL query and returns the value of a single column + * of the first row of the result. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return mixed|false False is returned if no rows are found. + * + * @throws Exception + */ + public function fetchOne(string $query, array $params = [], array $types = []) + { + try { + $stmt = $this->ensureForwardCompatibilityStatement( + $this->executeQuery($query, $params, $types) + ); + + return $stmt->fetchOne(); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $query, $params, $types); + } + } + + /** + * Whether an actual connection to the database is established. + * + * @return bool + */ + public function isConnected() + { + return $this->_conn !== null; + } + + /** + * Checks whether a transaction is currently active. + * + * @return bool TRUE if a transaction is currently active, FALSE otherwise. + */ + public function isTransactionActive() + { + return $this->transactionNestingLevel > 0; + } + + /** + * Adds condition based on the criteria to the query components + * + * @param array $criteria Map of key columns to their values + * @param string[] $columns Column names + * @param mixed[] $values Column values + * @param string[] $conditions Key conditions + * + * @throws Exception + */ + private function addCriteriaCondition( + array $criteria, + array &$columns, + array &$values, + array &$conditions + ): void { + $platform = $this->getDatabasePlatform(); + + foreach ($criteria as $columnName => $value) { + if ($value === null) { + $conditions[] = $platform->getIsNullExpression($columnName); + continue; + } + + $columns[] = $columnName; + $values[] = $value; + $conditions[] = $columnName . ' = ?'; + } + } + + /** + * Executes an SQL DELETE statement on a table. + * + * Table expression and columns are not escaped and are not safe for user-input. + * + * @param string $table Table name + * @param array $criteria Deletion criteria + * @param array|array $types Parameter types + * + * @return int The number of affected rows. + * + * @throws Exception + */ + public function delete($table, array $criteria, array $types = []) + { + if (empty($criteria)) { + throw InvalidArgumentException::fromEmptyCriteria(); + } + + $columns = $values = $conditions = []; + + $this->addCriteriaCondition($criteria, $columns, $values, $conditions); + + return $this->executeStatement( + 'DELETE FROM ' . $table . ' WHERE ' . implode(' AND ', $conditions), + $values, + is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types + ); + } + + /** + * Closes the connection. + * + * @return void + */ + public function close() + { + $this->_conn = null; + } + + /** + * Sets the transaction isolation level. + * + * @param int $level The level to set. + * + * @return int + */ + public function setTransactionIsolation($level) + { + $this->transactionIsolationLevel = $level; + + return $this->executeStatement($this->getDatabasePlatform()->getSetTransactionIsolationSQL($level)); + } + + /** + * Gets the currently active transaction isolation level. + * + * @return int The current transaction isolation level. + */ + public function getTransactionIsolation() + { + if ($this->transactionIsolationLevel === null) { + $this->transactionIsolationLevel = $this->getDatabasePlatform()->getDefaultTransactionIsolationLevel(); + } + + return $this->transactionIsolationLevel; + } + + /** + * Executes an SQL UPDATE statement on a table. + * + * Table expression and columns are not escaped and are not safe for user-input. + * + * @param string $table Table name + * @param array $data Column-value pairs + * @param array $criteria Update criteria + * @param array|array $types Parameter types + * + * @return int The number of affected rows. + * + * @throws Exception + */ + public function update($table, array $data, array $criteria, array $types = []) + { + $columns = $values = $conditions = $set = []; + + foreach ($data as $columnName => $value) { + $columns[] = $columnName; + $values[] = $value; + $set[] = $columnName . ' = ?'; + } + + $this->addCriteriaCondition($criteria, $columns, $values, $conditions); + + if (is_string(key($types))) { + $types = $this->extractTypeValues($columns, $types); + } + + $sql = 'UPDATE ' . $table . ' SET ' . implode(', ', $set) + . ' WHERE ' . implode(' AND ', $conditions); + + return $this->executeStatement($sql, $values, $types); + } + + /** + * Inserts a table row with specified data. + * + * Table expression and columns are not escaped and are not safe for user-input. + * + * @param string $table Table name + * @param array $data Column-value pairs + * @param array|array $types Parameter types + * + * @return int The number of affected rows. + * + * @throws Exception + */ + public function insert($table, array $data, array $types = []) + { + if (empty($data)) { + return $this->executeStatement('INSERT INTO ' . $table . ' () VALUES ()'); + } + + $columns = []; + $values = []; + $set = []; + + foreach ($data as $columnName => $value) { + $columns[] = $columnName; + $values[] = $value; + $set[] = '?'; + } + + return $this->executeStatement( + 'INSERT INTO ' . $table . ' (' . implode(', ', $columns) . ')' . + ' VALUES (' . implode(', ', $set) . ')', + $values, + is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types + ); + } + + /** + * Extract ordered type list from an ordered column list and type map. + * + * @param array $columnList + * @param array|array $types + * + * @return array|array + */ + private function extractTypeValues(array $columnList, array $types) + { + $typeValues = []; + + foreach ($columnList as $columnIndex => $columnName) { + $typeValues[] = $types[$columnName] ?? ParameterType::STRING; + } + + return $typeValues; + } + + /** + * Quotes a string so it can be safely used as a table or column name, even if + * it is a reserved name. + * + * Delimiting style depends on the underlying database platform that is being used. + * + * NOTE: Just because you CAN use quoted identifiers does not mean + * you SHOULD use them. In general, they end up causing way more + * problems than they solve. + * + * @param string $str The name to be quoted. + * + * @return string The quoted name. + */ + public function quoteIdentifier($str) + { + return $this->getDatabasePlatform()->quoteIdentifier($str); + } + + /** + * {@inheritDoc} + * + * @param mixed $value + * @param int|string|Type|null $type + */ + public function quote($value, $type = ParameterType::STRING) + { + $connection = $this->getWrappedConnection(); + + [$value, $bindingType] = $this->getBindingInfo($value, $type); + + return $connection->quote($value, $bindingType); + } + + /** + * Prepares and executes an SQL query and returns the result as an associative array. + * + * @deprecated Use fetchAllAssociative() + * + * @param string $sql The SQL query. + * @param mixed[] $params The query parameters. + * @param int[]|string[] $types The query parameter types. + * + * @return mixed[] + */ + public function fetchAll($sql, array $params = [], $types = []) + { + return $this->executeQuery($sql, $params, $types)->fetchAll(); + } + + /** + * Prepares and executes an SQL query and returns the result as an array of numeric arrays. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return array> + * + * @throws Exception + */ + public function fetchAllNumeric(string $query, array $params = [], array $types = []): array + { + try { + $stmt = $this->ensureForwardCompatibilityStatement( + $this->executeQuery($query, $params, $types) + ); + + return $stmt->fetchAllNumeric(); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $query, $params, $types); + } + } + + /** + * Prepares and executes an SQL query and returns the result as an array of associative arrays. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return array> + * + * @throws Exception + */ + public function fetchAllAssociative(string $query, array $params = [], array $types = []): array + { + try { + $stmt = $this->ensureForwardCompatibilityStatement( + $this->executeQuery($query, $params, $types) + ); + + return $stmt->fetchAllAssociative(); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $query, $params, $types); + } + } + + /** + * Prepares and executes an SQL query and returns the result as an associative array with the keys + * mapped to the first column and the values mapped to the second column. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return array + * + * @throws Exception + */ + public function fetchAllKeyValue(string $query, array $params = [], array $types = []): array + { + $stmt = $this->executeQuery($query, $params, $types); + + $this->ensureHasKeyValue($stmt); + + $data = []; + + foreach ($stmt->fetchAll(FetchMode::NUMERIC) as [$key, $value]) { + $data[$key] = $value; + } + + return $data; + } + + /** + * Prepares and executes an SQL query and returns the result as an associative array with the keys mapped + * to the first column and the values being an associative array representing the rest of the columns + * and their values. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return array> + * + * @throws Exception + */ + public function fetchAllAssociativeIndexed(string $query, array $params = [], array $types = []): array + { + $stmt = $this->executeQuery($query, $params, $types); + + $data = []; + + foreach ($stmt->fetchAll(FetchMode::ASSOCIATIVE) as $row) { + $data[array_shift($row)] = $row; + } + + return $data; + } + + /** + * Prepares and executes an SQL query and returns the result as an array of the first column values. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return array + * + * @throws Exception + */ + public function fetchFirstColumn(string $query, array $params = [], array $types = []): array + { + try { + $stmt = $this->ensureForwardCompatibilityStatement( + $this->executeQuery($query, $params, $types) + ); + + return $stmt->fetchFirstColumn(); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $query, $params, $types); + } + } + + /** + * Prepares and executes an SQL query and returns the result as an iterator over rows represented as numeric arrays. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return Traversable> + * + * @throws Exception + */ + public function iterateNumeric(string $query, array $params = [], array $types = []): Traversable + { + try { + $stmt = $this->ensureForwardCompatibilityStatement( + $this->executeQuery($query, $params, $types) + ); + + yield from $stmt->iterateNumeric(); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $query, $params, $types); + } + } + + /** + * Prepares and executes an SQL query and returns the result as an iterator over rows represented + * as associative arrays. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return Traversable> + * + * @throws Exception + */ + public function iterateAssociative(string $query, array $params = [], array $types = []): Traversable + { + try { + $stmt = $this->ensureForwardCompatibilityStatement( + $this->executeQuery($query, $params, $types) + ); + + yield from $stmt->iterateAssociative(); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $query, $params, $types); + } + } + + /** + * Prepares and executes an SQL query and returns the result as an iterator with the keys + * mapped to the first column and the values mapped to the second column. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return Traversable + * + * @throws Exception + */ + public function iterateKeyValue(string $query, array $params = [], array $types = []): Traversable + { + $stmt = $this->executeQuery($query, $params, $types); + + $this->ensureHasKeyValue($stmt); + + while (($row = $stmt->fetch(FetchMode::NUMERIC)) !== false) { + yield $row[0] => $row[1]; + } + } + + /** + * Prepares and executes an SQL query and returns the result as an iterator with the keys mapped + * to the first column and the values being an associative array representing the rest of the columns + * and their values. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return Traversable> + * + * @throws Exception + */ + public function iterateAssociativeIndexed(string $query, array $params = [], array $types = []): Traversable + { + $stmt = $this->executeQuery($query, $params, $types); + + while (($row = $stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) { + yield array_shift($row) => $row; + } + } + + /** + * Prepares and executes an SQL query and returns the result as an iterator over the first column values. + * + * @param string $query SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return Traversable + * + * @throws Exception + */ + public function iterateColumn(string $query, array $params = [], array $types = []): Traversable + { + try { + $stmt = $this->ensureForwardCompatibilityStatement( + $this->executeQuery($query, $params, $types) + ); + + yield from $stmt->iterateColumn(); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $query, $params, $types); + } + } + + /** + * Prepares an SQL statement. + * + * @param string $sql The SQL statement to prepare. + * + * @return Statement The prepared statement. + * + * @throws Exception + */ + public function prepare($sql) + { + try { + $stmt = new Statement($sql, $this); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $sql); + } + + $stmt->setFetchMode($this->defaultFetchMode); + + return $stmt; + } + + /** + * Executes an, optionally parametrized, SQL query. + * + * If the query is parametrized, a prepared statement is used. + * If an SQLLogger is configured, the execution is logged. + * + * @param string $sql SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return ForwardCompatibility\DriverStatement|ForwardCompatibility\DriverResultStatement + * + * The executed statement or the cached result statement if a query cache profile is used + * + * @throws Exception + */ + public function executeQuery($sql, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) + { + if ($qcp !== null) { + return $this->executeCacheQuery($sql, $params, $types, $qcp); + } + + $connection = $this->getWrappedConnection(); + + $logger = $this->_config->getSQLLogger(); + if ($logger) { + $logger->startQuery($sql, $params, $types); + } + + try { + if ($params) { + [$sql, $params, $types] = SQLParserUtils::expandListParameters($sql, $params, $types); + + $stmt = $connection->prepare($sql); + if ($types) { + $this->_bindTypedValues($stmt, $params, $types); + $stmt->execute(); + } else { + $stmt->execute($params); + } + } else { + $stmt = $connection->query($sql); + } + } catch (Throwable $e) { + $this->handleExceptionDuringQuery( + $e, + $sql, + $params, + $types + ); + } + + $stmt->setFetchMode($this->defaultFetchMode); + + if ($logger) { + $logger->stopQuery(); + } + + return $this->ensureForwardCompatibilityStatement($stmt); + } + + /** + * Executes a caching query. + * + * @param string $sql SQL query + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return ForwardCompatibility\DriverResultStatement + * + * @throws CacheException + */ + public function executeCacheQuery($sql, $params, $types, QueryCacheProfile $qcp) + { + $resultCache = $qcp->getResultCacheDriver() ?? $this->_config->getResultCacheImpl(); + + if ($resultCache === null) { + throw CacheException::noResultDriverConfigured(); + } + + $connectionParams = $this->params; + unset($connectionParams['platform']); + + [$cacheKey, $realKey] = $qcp->generateCacheKeys($sql, $params, $types, $connectionParams); + + // fetch the row pointers entry + $data = $resultCache->fetch($cacheKey); + + if ($data !== false) { + // is the real key part of this row pointers map or is the cache only pointing to other cache keys? + if (isset($data[$realKey])) { + $stmt = new ArrayStatement($data[$realKey]); + } elseif (array_key_exists($realKey, $data)) { + $stmt = new ArrayStatement([]); + } + } + + if (! isset($stmt)) { + $stmt = new ResultCacheStatement( + $this->executeQuery($sql, $params, $types), + $resultCache, + $cacheKey, + $realKey, + $qcp->getLifetime() + ); + } + + $stmt->setFetchMode($this->defaultFetchMode); + + return $this->ensureForwardCompatibilityStatement($stmt); + } + + /** + * @return ForwardCompatibility\Result + */ + private function ensureForwardCompatibilityStatement(ResultStatement $stmt) + { + return ForwardCompatibility\Result::ensure($stmt); + } + + /** + * Executes an, optionally parametrized, SQL query and returns the result, + * applying a given projection/transformation function on each row of the result. + * + * @deprecated + * + * @param string $sql The SQL query to execute. + * @param mixed[] $params The parameters, if any. + * @param Closure $function The transformation function that is applied on each row. + * The function receives a single parameter, an array, that + * represents a row of the result set. + * + * @return mixed[] The projected result of the query. + */ + public function project($sql, array $params, Closure $function) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3823', + 'Connection::project() is deprecated without replacement, implement data projections in your own code.' + ); + + $result = []; + $stmt = $this->executeQuery($sql, $params); + + while ($row = $stmt->fetch()) { + $result[] = $function($row); + } + + $stmt->closeCursor(); + + return $result; + } + + /** + * Executes an SQL statement, returning a result set as a Statement object. + * + * @deprecated Use {@link executeQuery()} instead. + * + * @return \Doctrine\DBAL\Driver\Statement + * + * @throws Exception + */ + public function query() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4163', + 'Connection::query() is deprecated, use Connection::executeQuery() instead.' + ); + + $connection = $this->getWrappedConnection(); + + $args = func_get_args(); + + $logger = $this->_config->getSQLLogger(); + if ($logger) { + $logger->startQuery($args[0]); + } + + try { + $statement = $connection->query(...$args); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $args[0]); + } + + $statement->setFetchMode($this->defaultFetchMode); + + if ($logger) { + $logger->stopQuery(); + } + + return $statement; + } + + /** + * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters + * and returns the number of affected rows. + * + * This method supports PDO binding types as well as DBAL mapping types. + * + * @deprecated Use {@link executeStatement()} instead. + * + * @param string $sql SQL statement + * @param array|array $params Statement parameters + * @param array|array $types Parameter types + * + * @return int The number of affected rows. + * + * @throws Exception + */ + public function executeUpdate($sql, array $params = [], array $types = []) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4163', + 'Connection::executeUpdate() is deprecated, use Connection::executeStatement() instead.' + ); + + return $this->executeStatement($sql, $params, $types); + } + + /** + * Executes an SQL statement with the given parameters and returns the number of affected rows. + * + * Could be used for: + * - DML statements: INSERT, UPDATE, DELETE, etc. + * - DDL statements: CREATE, DROP, ALTER, etc. + * - DCL statements: GRANT, REVOKE, etc. + * - Session control statements: ALTER SESSION, SET, DECLARE, etc. + * - Other statements that don't yield a row set. + * + * This method supports PDO binding types as well as DBAL mapping types. + * + * @param string $sql SQL statement + * @param array|array $params Statement parameters + * @param array|array $types Parameter types + * + * @return int The number of affected rows. + * + * @throws Exception + */ + public function executeStatement($sql, array $params = [], array $types = []) + { + $connection = $this->getWrappedConnection(); + + $logger = $this->_config->getSQLLogger(); + if ($logger) { + $logger->startQuery($sql, $params, $types); + } + + try { + if ($params) { + [$sql, $params, $types] = SQLParserUtils::expandListParameters($sql, $params, $types); + + $stmt = $connection->prepare($sql); + + if ($types) { + $this->_bindTypedValues($stmt, $params, $types); + $stmt->execute(); + } else { + $stmt->execute($params); + } + + $result = $stmt->rowCount(); + } else { + $result = $connection->exec($sql); + } + } catch (Throwable $e) { + $this->handleExceptionDuringQuery( + $e, + $sql, + $params, + $types + ); + } + + if ($logger) { + $logger->stopQuery(); + } + + return $result; + } + + /** + * Executes an SQL statement and return the number of affected rows. + * + * @deprecated Use {@link executeStatement()} instead. + * + * @param string $sql + * + * @return int The number of affected rows. + * + * @throws Exception + */ + public function exec($sql) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4163', + 'Connection::exec() is deprecated, use Connection::executeStatement() instead.' + ); + + $connection = $this->getWrappedConnection(); + + $logger = $this->_config->getSQLLogger(); + if ($logger) { + $logger->startQuery($sql); + } + + try { + $result = $connection->exec($sql); + } catch (Throwable $e) { + $this->handleExceptionDuringQuery($e, $sql); + } + + if ($logger) { + $logger->stopQuery(); + } + + return $result; + } + + /** + * Returns the current transaction nesting level. + * + * @return int The nesting level. A value of 0 means there's no active transaction. + */ + public function getTransactionNestingLevel() + { + return $this->transactionNestingLevel; + } + + /** + * Fetches the SQLSTATE associated with the last database operation. + * + * @deprecated The error information is available via exceptions. + * + * @return string|null The last error code. + */ + public function errorCode() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3507', + 'Connection::errorCode() is deprecated, use getCode() or getSQLState() on Exception instead.' + ); + + return $this->getWrappedConnection()->errorCode(); + } + + /** + * {@inheritDoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3507', + 'Connection::errorInfo() is deprecated, use getCode() or getSQLState() on Exception instead.' + ); + + return $this->getWrappedConnection()->errorInfo(); + } + + /** + * Returns the ID of the last inserted row, or the last value from a sequence object, + * depending on the underlying driver. + * + * Note: This method may not return a meaningful or consistent result across different drivers, + * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY + * columns or sequences. + * + * @param string|null $name Name of the sequence object from which the ID should be returned. + * + * @return string|int|false A string representation of the last inserted ID. + */ + public function lastInsertId($name = null) + { + return $this->getWrappedConnection()->lastInsertId($name); + } + + /** + * Executes a function in a transaction. + * + * The function gets passed this Connection instance as an (optional) parameter. + * + * If an exception occurs during execution of the function or transaction commit, + * the transaction is rolled back and the exception re-thrown. + * + * @param Closure $func The function to execute transactionally. + * + * @return mixed The value returned by $func + * + * @throws Throwable + */ + public function transactional(Closure $func) + { + $this->beginTransaction(); + try { + $res = $func($this); + $this->commit(); + + return $res; + } catch (Throwable $e) { + $this->rollBack(); + + throw $e; + } + } + + /** + * Sets if nested transactions should use savepoints. + * + * @param bool $nestTransactionsWithSavepoints + * + * @return void + * + * @throws ConnectionException + */ + public function setNestTransactionsWithSavepoints($nestTransactionsWithSavepoints) + { + if ($this->transactionNestingLevel > 0) { + throw ConnectionException::mayNotAlterNestedTransactionWithSavepointsInTransaction(); + } + + if (! $this->getDatabasePlatform()->supportsSavepoints()) { + throw ConnectionException::savepointsNotSupported(); + } + + $this->nestTransactionsWithSavepoints = (bool) $nestTransactionsWithSavepoints; + } + + /** + * Gets if nested transactions should use savepoints. + * + * @return bool + */ + public function getNestTransactionsWithSavepoints() + { + return $this->nestTransactionsWithSavepoints; + } + + /** + * Returns the savepoint name to use for nested transactions are false if they are not supported + * "savepointFormat" parameter is not set + * + * @return mixed A string with the savepoint name or false. + */ + protected function _getNestedTransactionSavePointName() + { + return 'DOCTRINE2_SAVEPOINT_' . $this->transactionNestingLevel; + } + + /** + * {@inheritDoc} + */ + public function beginTransaction() + { + $connection = $this->getWrappedConnection(); + + ++$this->transactionNestingLevel; + + $logger = $this->_config->getSQLLogger(); + + if ($this->transactionNestingLevel === 1) { + if ($logger) { + $logger->startQuery('"START TRANSACTION"'); + } + + $connection->beginTransaction(); + + if ($logger) { + $logger->stopQuery(); + } + } elseif ($this->nestTransactionsWithSavepoints) { + if ($logger) { + $logger->startQuery('"SAVEPOINT"'); + } + + $this->createSavepoint($this->_getNestedTransactionSavePointName()); + if ($logger) { + $logger->stopQuery(); + } + } + + return true; + } + + /** + * {@inheritDoc} + * + * @throws ConnectionException If the commit failed due to no active transaction or + * because the transaction was marked for rollback only. + */ + public function commit() + { + if ($this->transactionNestingLevel === 0) { + throw ConnectionException::noActiveTransaction(); + } + + if ($this->isRollbackOnly) { + throw ConnectionException::commitFailedRollbackOnly(); + } + + $result = true; + + $connection = $this->getWrappedConnection(); + + $logger = $this->_config->getSQLLogger(); + + if ($this->transactionNestingLevel === 1) { + if ($logger) { + $logger->startQuery('"COMMIT"'); + } + + $result = $connection->commit(); + + if ($logger) { + $logger->stopQuery(); + } + } elseif ($this->nestTransactionsWithSavepoints) { + if ($logger) { + $logger->startQuery('"RELEASE SAVEPOINT"'); + } + + $this->releaseSavepoint($this->_getNestedTransactionSavePointName()); + if ($logger) { + $logger->stopQuery(); + } + } + + --$this->transactionNestingLevel; + + if ($this->autoCommit !== false || $this->transactionNestingLevel !== 0) { + return $result; + } + + $this->beginTransaction(); + + return $result; + } + + /** + * Commits all current nesting transactions. + */ + private function commitAll(): void + { + while ($this->transactionNestingLevel !== 0) { + if ($this->autoCommit === false && $this->transactionNestingLevel === 1) { + // When in no auto-commit mode, the last nesting commit immediately starts a new transaction. + // Therefore we need to do the final commit here and then leave to avoid an infinite loop. + $this->commit(); + + return; + } + + $this->commit(); + } + } + + /** + * Cancels any database changes done during the current transaction. + * + * @return bool + * + * @throws ConnectionException If the rollback operation failed. + */ + public function rollBack() + { + if ($this->transactionNestingLevel === 0) { + throw ConnectionException::noActiveTransaction(); + } + + $connection = $this->getWrappedConnection(); + + $logger = $this->_config->getSQLLogger(); + + if ($this->transactionNestingLevel === 1) { + if ($logger) { + $logger->startQuery('"ROLLBACK"'); + } + + $this->transactionNestingLevel = 0; + $connection->rollBack(); + $this->isRollbackOnly = false; + if ($logger) { + $logger->stopQuery(); + } + + if ($this->autoCommit === false) { + $this->beginTransaction(); + } + } elseif ($this->nestTransactionsWithSavepoints) { + if ($logger) { + $logger->startQuery('"ROLLBACK TO SAVEPOINT"'); + } + + $this->rollbackSavepoint($this->_getNestedTransactionSavePointName()); + --$this->transactionNestingLevel; + if ($logger) { + $logger->stopQuery(); + } + } else { + $this->isRollbackOnly = true; + --$this->transactionNestingLevel; + } + + return true; + } + + /** + * Creates a new savepoint. + * + * @param string $savepoint The name of the savepoint to create. + * + * @return void + * + * @throws ConnectionException + */ + public function createSavepoint($savepoint) + { + $platform = $this->getDatabasePlatform(); + + if (! $platform->supportsSavepoints()) { + throw ConnectionException::savepointsNotSupported(); + } + + $this->getWrappedConnection()->exec($platform->createSavePoint($savepoint)); + } + + /** + * Releases the given savepoint. + * + * @param string $savepoint The name of the savepoint to release. + * + * @return void + * + * @throws ConnectionException + */ + public function releaseSavepoint($savepoint) + { + $platform = $this->getDatabasePlatform(); + + if (! $platform->supportsSavepoints()) { + throw ConnectionException::savepointsNotSupported(); + } + + if (! $platform->supportsReleaseSavepoints()) { + return; + } + + $this->getWrappedConnection()->exec($platform->releaseSavePoint($savepoint)); + } + + /** + * Rolls back to the given savepoint. + * + * @param string $savepoint The name of the savepoint to rollback to. + * + * @return void + * + * @throws ConnectionException + */ + public function rollbackSavepoint($savepoint) + { + $platform = $this->getDatabasePlatform(); + + if (! $platform->supportsSavepoints()) { + throw ConnectionException::savepointsNotSupported(); + } + + $this->getWrappedConnection()->exec($platform->rollbackSavePoint($savepoint)); + } + + /** + * Gets the wrapped driver connection. + * + * @return DriverConnection + */ + public function getWrappedConnection() + { + $this->connect(); + + assert($this->_conn !== null); + + return $this->_conn; + } + + /** + * Gets the SchemaManager that can be used to inspect or change the + * database schema through the connection. + * + * @return AbstractSchemaManager + */ + public function getSchemaManager() + { + if ($this->_schemaManager === null) { + $this->_schemaManager = $this->_driver->getSchemaManager($this); + } + + return $this->_schemaManager; + } + + /** + * Marks the current transaction so that the only possible + * outcome for the transaction to be rolled back. + * + * @return void + * + * @throws ConnectionException If no transaction is active. + */ + public function setRollbackOnly() + { + if ($this->transactionNestingLevel === 0) { + throw ConnectionException::noActiveTransaction(); + } + + $this->isRollbackOnly = true; + } + + /** + * Checks whether the current transaction is marked for rollback only. + * + * @return bool + * + * @throws ConnectionException If no transaction is active. + */ + public function isRollbackOnly() + { + if ($this->transactionNestingLevel === 0) { + throw ConnectionException::noActiveTransaction(); + } + + return $this->isRollbackOnly; + } + + /** + * Converts a given value to its database representation according to the conversion + * rules of a specific DBAL mapping type. + * + * @param mixed $value The value to convert. + * @param string $type The name of the DBAL mapping type. + * + * @return mixed The converted value. + */ + public function convertToDatabaseValue($value, $type) + { + return Type::getType($type)->convertToDatabaseValue($value, $this->getDatabasePlatform()); + } + + /** + * Converts a given value to its PHP representation according to the conversion + * rules of a specific DBAL mapping type. + * + * @param mixed $value The value to convert. + * @param string $type The name of the DBAL mapping type. + * + * @return mixed The converted type. + */ + public function convertToPHPValue($value, $type) + { + return Type::getType($type)->convertToPHPValue($value, $this->getDatabasePlatform()); + } + + /** + * Binds a set of parameters, some or all of which are typed with a PDO binding type + * or DBAL mapping type, to a given statement. + * + * @internal Duck-typing used on the $stmt parameter to support driver statements as well as + * raw PDOStatement instances. + * + * @param \Doctrine\DBAL\Driver\Statement $stmt Prepared statement + * @param array|array $params Statement parameters + * @param array|array $types Parameter types + * + * @return void + */ + private function _bindTypedValues($stmt, array $params, array $types) + { + // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO. + if (is_int(key($params))) { + // Positional parameters + $typeOffset = array_key_exists(0, $types) ? -1 : 0; + $bindIndex = 1; + foreach ($params as $value) { + $typeIndex = $bindIndex + $typeOffset; + if (isset($types[$typeIndex])) { + $type = $types[$typeIndex]; + [$value, $bindingType] = $this->getBindingInfo($value, $type); + $stmt->bindValue($bindIndex, $value, $bindingType); + } else { + $stmt->bindValue($bindIndex, $value); + } + + ++$bindIndex; + } + } else { + // Named parameters + foreach ($params as $name => $value) { + if (isset($types[$name])) { + $type = $types[$name]; + [$value, $bindingType] = $this->getBindingInfo($value, $type); + $stmt->bindValue($name, $value, $bindingType); + } else { + $stmt->bindValue($name, $value); + } + } + } + } + + /** + * Gets the binding type of a given type. The given type can be a PDO or DBAL mapping type. + * + * @param mixed $value The value to bind. + * @param int|string|Type|null $type The type to bind (PDO or DBAL). + * + * @return array{mixed, int} [0] => the (escaped) value, [1] => the binding type. + */ + private function getBindingInfo($value, $type): array + { + if (is_string($type)) { + $type = Type::getType($type); + } + + if ($type instanceof Type) { + $value = $type->convertToDatabaseValue($value, $this->getDatabasePlatform()); + $bindingType = $type->getBindingType(); + } else { + $bindingType = $type ?? ParameterType::STRING; + } + + return [$value, $bindingType]; + } + + /** + * Resolves the parameters to a format which can be displayed. + * + * @internal This is a purely internal method. If you rely on this method, you are advised to + * copy/paste the code as this method may change, or be removed without prior notice. + * + * @param array|array $params Query parameters + * @param array|array $types Parameter types + * + * @return array|array + */ + public function resolveParams(array $params, array $types) + { + $resolvedParams = []; + + // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO. + if (is_int(key($params))) { + // Positional parameters + $typeOffset = array_key_exists(0, $types) ? -1 : 0; + $bindIndex = 1; + foreach ($params as $value) { + $typeIndex = $bindIndex + $typeOffset; + if (isset($types[$typeIndex])) { + $type = $types[$typeIndex]; + [$value] = $this->getBindingInfo($value, $type); + $resolvedParams[$bindIndex] = $value; + } else { + $resolvedParams[$bindIndex] = $value; + } + + ++$bindIndex; + } + } else { + // Named parameters + foreach ($params as $name => $value) { + if (isset($types[$name])) { + $type = $types[$name]; + [$value] = $this->getBindingInfo($value, $type); + $resolvedParams[$name] = $value; + } else { + $resolvedParams[$name] = $value; + } + } + } + + return $resolvedParams; + } + + /** + * Creates a new instance of a SQL query builder. + * + * @return QueryBuilder + */ + public function createQueryBuilder() + { + return new Query\QueryBuilder($this); + } + + /** + * Ping the server + * + * When the server is not available the method returns FALSE. + * It is responsibility of the developer to handle this case + * and abort the request or reconnect manually: + * + * @deprecated + * + * @return bool + * + * @example + * + * if ($conn->ping() === false) { + * $conn->close(); + * $conn->connect(); + * } + * + * It is undefined if the underlying driver attempts to reconnect + * or disconnect when the connection is not available anymore + * as long it returns TRUE when a reconnect succeeded and + * FALSE when the connection was dropped. + */ + public function ping() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4119', + 'Retry and reconnecting lost connections now happens automatically, ping() will be removed in DBAL 3.' + ); + + $connection = $this->getWrappedConnection(); + + if ($connection instanceof PingableConnection) { + return $connection->ping(); + } + + try { + $this->query($this->getDatabasePlatform()->getDummySelectSQL()); + + return true; + } catch (DBALException $e) { + return false; + } + } + + /** + * @internal + * + * @param array|array $params + * @param array|array $types + * + * @psalm-return never-return + * + * @throws Exception + */ + public function handleExceptionDuringQuery(Throwable $e, string $sql, array $params = [], array $types = []): void + { + $this->throw( + Exception::driverExceptionDuringQuery( + $this->_driver, + $e, + $sql, + $this->resolveParams($params, $types) + ) + ); + } + + /** + * @internal + * + * @psalm-return never-return + * + * @throws Exception + */ + public function handleDriverException(Throwable $e): void + { + $this->throw( + Exception::driverException( + $this->_driver, + $e + ) + ); + } + + /** + * @internal + * + * @psalm-return never-return + * + * @throws Exception + */ + private function throw(Exception $e): void + { + if ($e instanceof ConnectionLost) { + $this->close(); + } + + throw $e; + } + + private function ensureHasKeyValue(ResultStatement $stmt): void + { + $columnCount = $stmt->columnCount(); + + if ($columnCount < 2) { + throw NoKeyValue::fromColumnCount($columnCount); + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/ConnectionException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/ConnectionException.php new file mode 100755 index 0000000..8426ca2 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/ConnectionException.php @@ -0,0 +1,41 @@ + $params + * @psalm-param Params $params + * @phpstan-param array $params + * + * @throws InvalidArgumentException + */ + public function __construct( + array $params, + Driver $driver, + ?Configuration $config = null, + ?EventManager $eventManager = null + ) { + $this->deprecated(self::class, PrimaryReadReplicaConnection::class); + + if (isset($params['master'])) { + $this->deprecated('Params key "master"', '"primary"'); + + $params['primary'] = $params['master']; + } + + if (isset($params['slaves'])) { + $this->deprecated('Params key "slaves"', '"replica"'); + + $params['replica'] = $params['slaves']; + } + + if (isset($params['keepSlave'])) { + $this->deprecated('Params key "keepSlave"', '"keepReplica"'); + + $params['keepReplica'] = $params['keepSlave']; + } + + parent::__construct($params, $driver, $config, $eventManager); + } + + /** + * Checks if the connection is currently towards the primary or not. + */ + public function isConnectedToMaster(): bool + { + $this->deprecated('isConnectedtoMaster()', 'isConnectedToPrimary()'); + + return $this->isConnectedToPrimary(); + } + + /** + * @param string|null $connectionName + * + * @return bool + */ + public function connect($connectionName = null) + { + if ($connectionName === 'master') { + $connectionName = 'primary'; + + $this->deprecated('connect("master")', 'ensureConnectedToPrimary()'); + } + + if ($connectionName === 'slave') { + $connectionName = 'replica'; + + $this->deprecated('connect("slave")', 'ensureConnectedToReplica()'); + } + + return $this->performConnect($connectionName); + } + + private function deprecated(string $thing, string $instead): void + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4054', + '%s is deprecated since doctrine/dbal 2.11 and will be removed in 3.0, use %s instead.', + $thing, + $instead + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connections/PrimaryReadReplicaConnection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connections/PrimaryReadReplicaConnection.php new file mode 100755 index 0000000..e2606e7 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connections/PrimaryReadReplicaConnection.php @@ -0,0 +1,442 @@ +executeQuery("DELETE FROM table"); + * + * Be aware that Connection#executeQuery is a method specifically for READ + * operations only. + * + * Use Connection#executeStatement for any SQL statement that changes/updates + * state in the database (UPDATE, INSERT, DELETE or DDL statements). + * + * This connection is limited to replica operations using the + * Connection#executeQuery operation only, because it wouldn't be compatible + * with the ORM or SchemaManager code otherwise. Both use all the other + * operations in a context where writes could happen to a replica, which makes + * this restricted approach necessary. + * + * You can manually connect to the primary at any time by calling: + * + * $conn->ensureConnectedToPrimary(); + * + * Instantiation through the DriverManager looks like: + * + * @psalm-import-type Params from DriverManager + * @example + * + * $conn = DriverManager::getConnection(array( + * 'wrapperClass' => 'Doctrine\DBAL\Connections\PrimaryReadReplicaConnection', + * 'driver' => 'pdo_mysql', + * 'primary' => array('user' => '', 'password' => '', 'host' => '', 'dbname' => ''), + * 'replica' => array( + * array('user' => 'replica1', 'password', 'host' => '', 'dbname' => ''), + * array('user' => 'replica2', 'password', 'host' => '', 'dbname' => ''), + * ) + * )); + * + * You can also pass 'driverOptions' and any other documented option to each of this drivers + * to pass additional information. + */ +class PrimaryReadReplicaConnection extends Connection +{ + /** + * Primary and Replica connection (one of the randomly picked replicas). + * + * @var DriverConnection[]|null[] + */ + protected $connections = ['primary' => null, 'replica' => null]; + + /** + * You can keep the replica connection and then switch back to it + * during the request if you know what you are doing. + * + * @var bool + */ + protected $keepReplica = false; + + /** + * Creates Primary Replica Connection. + * + * @internal The connection can be only instantiated by the driver manager. + * + * @param array $params + * @psalm-param Params $params + * @phpstan-param array $params + * + * @throws InvalidArgumentException + */ + public function __construct( + array $params, + Driver $driver, + ?Configuration $config = null, + ?EventManager $eventManager = null + ) { + if (! isset($params['replica'], $params['primary'])) { + throw new InvalidArgumentException('primary or replica configuration missing'); + } + + if (count($params['replica']) === 0) { + throw new InvalidArgumentException('You have to configure at least one replica.'); + } + + if (isset($params['driver'])) { + $params['primary']['driver'] = $params['driver']; + + foreach ($params['replica'] as $replicaKey => $replica) { + $params['replica'][$replicaKey]['driver'] = $params['driver']; + } + } + + $this->keepReplica = (bool) ($params['keepReplica'] ?? false); + + parent::__construct($params, $driver, $config, $eventManager); + } + + /** + * Checks if the connection is currently towards the primary or not. + */ + public function isConnectedToPrimary(): bool + { + return $this->_conn !== null && $this->_conn === $this->connections['primary']; + } + + /** + * @param string|null $connectionName + * + * @return bool + */ + public function connect($connectionName = null) + { + if ($connectionName !== null) { + throw new InvalidArgumentException( + 'Passing a connection name as first argument is not supported anymore.' + . ' Use ensureConnectedToPrimary()/ensureConnectedToReplica() instead.' + ); + } + + return $this->performConnect(); + } + + protected function performConnect(?string $connectionName = null): bool + { + $requestedConnectionChange = ($connectionName !== null); + $connectionName = $connectionName ?: 'replica'; + + if ($connectionName !== 'replica' && $connectionName !== 'primary') { + throw new InvalidArgumentException('Invalid option to connect(), only primary or replica allowed.'); + } + + // If we have a connection open, and this is not an explicit connection + // change request, then abort right here, because we are already done. + // This prevents writes to the replica in case of "keepReplica" option enabled. + if ($this->_conn !== null && ! $requestedConnectionChange) { + return false; + } + + $forcePrimaryAsReplica = false; + + if ($this->getTransactionNestingLevel() > 0) { + $connectionName = 'primary'; + $forcePrimaryAsReplica = true; + } + + if (isset($this->connections[$connectionName])) { + $this->_conn = $this->connections[$connectionName]; + + if ($forcePrimaryAsReplica && ! $this->keepReplica) { + $this->connections['replica'] = $this->_conn; + } + + return false; + } + + if ($connectionName === 'primary') { + $this->connections['primary'] = $this->_conn = $this->connectTo($connectionName); + + // Set replica connection to primary to avoid invalid reads + if (! $this->keepReplica) { + $this->connections['replica'] = $this->connections['primary']; + } + } else { + $this->connections['replica'] = $this->_conn = $this->connectTo($connectionName); + } + + if ($this->_eventManager->hasListeners(Events::postConnect)) { + $eventArgs = new ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + } + + return true; + } + + /** + * Connects to the primary node of the database cluster. + * + * All following statements after this will be executed against the primary node. + */ + public function ensureConnectedToPrimary(): bool + { + return $this->performConnect('primary'); + } + + /** + * Connects to a replica node of the database cluster. + * + * All following statements after this will be executed against the replica node, + * unless the keepReplica option is set to false and a primary connection + * was already opened. + */ + public function ensureConnectedToReplica(): bool + { + return $this->performConnect('replica'); + } + + /** + * Connects to a specific connection. + * + * @param string $connectionName + * + * @return DriverConnection + */ + protected function connectTo($connectionName) + { + $params = $this->getParams(); + + $driverOptions = $params['driverOptions'] ?? []; + + $connectionParams = $this->chooseConnectionConfiguration($connectionName, $params); + + $user = $connectionParams['user'] ?? null; + $password = $connectionParams['password'] ?? null; + + return $this->_driver->connect($connectionParams, $user, $password, $driverOptions); + } + + /** + * @param string $connectionName + * @param mixed[] $params + * + * @return mixed + */ + protected function chooseConnectionConfiguration($connectionName, $params) + { + if ($connectionName === 'primary') { + return $params['primary']; + } + + $config = $params['replica'][array_rand($params['replica'])]; + + if (! isset($config['charset']) && isset($params['primary']['charset'])) { + $config['charset'] = $params['primary']['charset']; + } + + return $config; + } + + /** + * {@inheritDoc} + * + * @deprecated Use {@link executeStatement()} instead. + */ + public function executeUpdate($sql, array $params = [], array $types = []) + { + $this->ensureConnectedToPrimary(); + + return parent::executeUpdate($sql, $params, $types); + } + + /** + * {@inheritDoc} + */ + public function executeStatement($sql, array $params = [], array $types = []) + { + $this->ensureConnectedToPrimary(); + + return parent::executeStatement($sql, $params, $types); + } + + /** + * {@inheritDoc} + */ + public function beginTransaction() + { + $this->ensureConnectedToPrimary(); + + return parent::beginTransaction(); + } + + /** + * {@inheritDoc} + */ + public function commit() + { + $this->ensureConnectedToPrimary(); + + return parent::commit(); + } + + /** + * {@inheritDoc} + */ + public function rollBack() + { + $this->ensureConnectedToPrimary(); + + return parent::rollBack(); + } + + /** + * {@inheritDoc} + */ + public function delete($table, array $criteria, array $types = []) + { + $this->ensureConnectedToPrimary(); + + return parent::delete($table, $criteria, $types); + } + + /** + * {@inheritDoc} + */ + public function close() + { + unset($this->connections['primary'], $this->connections['replica']); + + parent::close(); + + $this->_conn = null; + $this->connections = ['primary' => null, 'replica' => null]; + } + + /** + * {@inheritDoc} + */ + public function update($table, array $data, array $criteria, array $types = []) + { + $this->ensureConnectedToPrimary(); + + return parent::update($table, $data, $criteria, $types); + } + + /** + * {@inheritDoc} + */ + public function insert($table, array $data, array $types = []) + { + $this->ensureConnectedToPrimary(); + + return parent::insert($table, $data, $types); + } + + /** + * {@inheritDoc} + */ + public function exec($sql) + { + $this->ensureConnectedToPrimary(); + + return parent::exec($sql); + } + + /** + * {@inheritDoc} + */ + public function createSavepoint($savepoint) + { + $this->ensureConnectedToPrimary(); + + parent::createSavepoint($savepoint); + } + + /** + * {@inheritDoc} + */ + public function releaseSavepoint($savepoint) + { + $this->ensureConnectedToPrimary(); + + parent::releaseSavepoint($savepoint); + } + + /** + * {@inheritDoc} + */ + public function rollbackSavepoint($savepoint) + { + $this->ensureConnectedToPrimary(); + + parent::rollbackSavepoint($savepoint); + } + + /** + * {@inheritDoc} + */ + public function query() + { + $this->ensureConnectedToPrimary(); + assert($this->_conn instanceof DriverConnection); + + $args = func_get_args(); + + $logger = $this->getConfiguration()->getSQLLogger(); + if ($logger) { + $logger->startQuery($args[0]); + } + + $statement = $this->_conn->query(...$args); + + $statement->setFetchMode($this->defaultFetchMode); + + if ($logger) { + $logger->stopQuery(); + } + + return $statement; + } + + /** + * {@inheritDoc} + */ + public function prepare($sql) + { + $this->ensureConnectedToPrimary(); + + return parent::prepare($sql); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php new file mode 100755 index 0000000..2de5824 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php @@ -0,0 +1,314 @@ +getMessage(); + + return self::wrapException($driver, $driverEx, $msg); + } + + /** + * @deprecated + * + * @return Exception + */ + public static function driverException(Driver $driver, Throwable $driverEx) + { + return self::wrapException($driver, $driverEx, 'An exception occurred in driver: ' . $driverEx->getMessage()); + } + + /** + * @return Exception + */ + private static function wrapException(Driver $driver, Throwable $driverEx, string $msg) + { + if ($driverEx instanceof DriverException) { + return $driverEx; + } + + if ($driver instanceof ExceptionConverterDriver && $driverEx instanceof DeprecatedDriverException) { + return $driver->convertException($msg, $driverEx); + } + + return new Exception($msg, 0, $driverEx); + } + + /** + * Returns a human-readable representation of an array of parameters. + * This properly handles binary data by returning a hex representation. + * + * @param mixed[] $params + * + * @return string + */ + private static function formatParameters(array $params) + { + return '[' . implode(', ', array_map(static function ($param) { + if (is_resource($param)) { + return (string) $param; + } + + $json = @json_encode($param); + + if (! is_string($json) || $json === 'null' && is_string($param)) { + // JSON encoding failed, this is not a UTF-8 string. + return sprintf('"%s"', preg_replace('/.{2}/', '\\x$0', bin2hex($param))); + } + + return $json; + }, $params)) . ']'; + } + + /** + * @param string $wrapperClass + * + * @return Exception + */ + public static function invalidWrapperClass($wrapperClass) + { + return new Exception("The given 'wrapperClass' " . $wrapperClass . ' has to be a ' . + 'subtype of \Doctrine\DBAL\Connection.'); + } + + /** + * @param string $driverClass + * + * @return Exception + */ + public static function invalidDriverClass($driverClass) + { + return new Exception( + "The given 'driverClass' " . $driverClass . ' has to implement the ' . Driver::class . ' interface.' + ); + } + + /** + * @param string $tableName + * + * @return Exception + */ + public static function invalidTableName($tableName) + { + return new Exception('Invalid table name specified: ' . $tableName); + } + + /** + * @param string $tableName + * + * @return Exception + */ + public static function noColumnsSpecifiedForTable($tableName) + { + return new Exception('No columns specified for table ' . $tableName); + } + + /** + * @return Exception + */ + public static function limitOffsetInvalid() + { + return new Exception('Invalid Offset in Limit Query, it has to be larger than or equal to 0.'); + } + + /** + * @param string $name + * + * @return Exception + */ + public static function typeExists($name) + { + return new Exception('Type ' . $name . ' already exists.'); + } + + /** + * @param string $name + * + * @return Exception + */ + public static function unknownColumnType($name) + { + return new Exception('Unknown column type "' . $name . '" requested. Any Doctrine type that you use has ' . + 'to be registered with \Doctrine\DBAL\Types\Type::addType(). You can get a list of all the ' . + 'known types with \Doctrine\DBAL\Types\Type::getTypesMap(). If this error occurs during database ' . + 'introspection then you might have forgotten to register all database types for a Doctrine Type. Use ' . + 'AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement ' . + 'Type#getMappedDatabaseTypes(). If the type name is empty you might ' . + 'have a problem with the cache or forgot some mapping information.'); + } + + /** + * @param string $name + * + * @return Exception + */ + public static function typeNotFound($name) + { + return new Exception('Type to be overwritten ' . $name . ' does not exist.'); + } + + public static function typeNotRegistered(Type $type): self + { + return new Exception( + sprintf('Type of the class %s@%s is not registered.', get_class($type), spl_object_hash($type)) + ); + } + + public static function typeAlreadyRegistered(Type $type): self + { + return new Exception( + sprintf('Type of the class %s@%s is already registered.', get_class($type), spl_object_hash($type)) + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver.php new file mode 100755 index 0000000..6f8afbf --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver.php @@ -0,0 +1,61 @@ +getParams(); + + return $params['dbname']; + } + + /** + * {@inheritdoc} + */ + public function getDatabasePlatform() + { + return new DB2Platform(); + } + + /** + * {@inheritdoc} + */ + public function getSchemaManager(Connection $conn) + { + return new DB2SchemaManager($conn); + } + + /** + * @param string $message + * + * @return DriverException + */ + public function convertException($message, TheDriverException $exception) + { + return new DriverException($message, $exception); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractDriverException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractDriverException.php new file mode 100755 index 0000000..bf10454 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractDriverException.php @@ -0,0 +1,12 @@ +errorCode = $errorCode; + $this->sqlState = $sqlState; + } + + /** + * {@inheritdoc} + */ + public function getErrorCode() + { + /** @psalm-suppress ImpureMethodCall */ + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4112', + 'Driver\AbstractException::getErrorCode() is deprecated, use getSQLState() or getCode() instead.' + ); + + return $this->errorCode; + } + + /** + * {@inheritdoc} + */ + public function getSQLState() + { + return $this->sqlState; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php new file mode 100755 index 0000000..5869cd7 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php @@ -0,0 +1,256 @@ +getErrorCode()) { + case '1213': + return new DeadlockException($message, $exception); + + case '1205': + return new LockWaitTimeoutException($message, $exception); + + case '1050': + return new TableExistsException($message, $exception); + + case '1051': + case '1146': + return new TableNotFoundException($message, $exception); + + case '1216': + case '1217': + case '1451': + case '1452': + case '1701': + return new ForeignKeyConstraintViolationException($message, $exception); + + case '1062': + case '1557': + case '1569': + case '1586': + return new UniqueConstraintViolationException($message, $exception); + + case '1054': + case '1166': + case '1611': + return new InvalidFieldNameException($message, $exception); + + case '1052': + case '1060': + case '1110': + return new NonUniqueFieldNameException($message, $exception); + + case '1064': + case '1149': + case '1287': + case '1341': + case '1342': + case '1343': + case '1344': + case '1382': + case '1479': + case '1541': + case '1554': + case '1626': + return new SyntaxErrorException($message, $exception); + + case '1044': + case '1045': + case '1046': + case '1049': + case '1095': + case '1142': + case '1143': + case '1227': + case '1370': + case '1429': + case '2002': + case '2005': + return new ConnectionException($message, $exception); + + case '2006': + return new ConnectionLost($message, $exception); + + case '1048': + case '1121': + case '1138': + case '1171': + case '1252': + case '1263': + case '1364': + case '1566': + return new NotNullConstraintViolationException($message, $exception); + } + + return new DriverException($message, $exception); + } + + /** + * {@inheritdoc} + * + * @throws Exception + */ + public function createDatabasePlatformForVersion($version) + { + $mariadb = stripos($version, 'mariadb') !== false; + if ($mariadb && version_compare($this->getMariaDbMysqlVersionNumber($version), '10.2.7', '>=')) { + return new MariaDb1027Platform(); + } + + if (! $mariadb) { + $oracleMysqlVersion = $this->getOracleMysqlVersionNumber($version); + if (version_compare($oracleMysqlVersion, '8', '>=')) { + return new MySQL80Platform(); + } + + if (version_compare($oracleMysqlVersion, '5.7.9', '>=')) { + return new MySQL57Platform(); + } + } + + return $this->getDatabasePlatform(); + } + + /** + * Get a normalized 'version number' from the server string + * returned by Oracle MySQL servers. + * + * @param string $versionString Version string returned by the driver, i.e. '5.7.10' + * + * @throws Exception + */ + private function getOracleMysqlVersionNumber(string $versionString): string + { + if ( + ! preg_match( + '/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?/', + $versionString, + $versionParts + ) + ) { + throw Exception::invalidPlatformVersionSpecified( + $versionString, + '..' + ); + } + + $majorVersion = $versionParts['major']; + $minorVersion = $versionParts['minor'] ?? 0; + $patchVersion = $versionParts['patch'] ?? null; + + if ($majorVersion === '5' && $minorVersion === '7' && $patchVersion === null) { + $patchVersion = '9'; + } + + return $majorVersion . '.' . $minorVersion . '.' . $patchVersion; + } + + /** + * Detect MariaDB server version, including hack for some mariadb distributions + * that starts with the prefix '5.5.5-' + * + * @param string $versionString Version string as returned by mariadb server, i.e. '5.5.5-Mariadb-10.0.8-xenial' + * + * @throws Exception + */ + private function getMariaDbMysqlVersionNumber(string $versionString): string + { + if ( + ! preg_match( + '/^(?:5\.5\.5-)?(mariadb-)?(?P\d+)\.(?P\d+)\.(?P\d+)/i', + $versionString, + $versionParts + ) + ) { + throw Exception::invalidPlatformVersionSpecified( + $versionString, + '^(?:5\.5\.5-)?(mariadb-)?..' + ); + } + + return $versionParts['major'] . '.' . $versionParts['minor'] . '.' . $versionParts['patch']; + } + + /** + * {@inheritdoc} + * + * @deprecated Use Connection::getDatabase() instead. + */ + public function getDatabase(Connection $conn) + { + $params = $conn->getParams(); + + if (isset($params['dbname'])) { + return $params['dbname']; + } + + $database = $conn->query('SELECT DATABASE()')->fetchColumn(); + + assert($database !== false); + + return $database; + } + + /** + * {@inheritdoc} + * + * @return MySqlPlatform + */ + public function getDatabasePlatform() + { + return new MySqlPlatform(); + } + + /** + * {@inheritdoc} + * + * @return MySqlSchemaManager + */ + public function getSchemaManager(Connection $conn) + { + return new MySqlSchemaManager($conn); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php new file mode 100755 index 0000000..be58266 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php @@ -0,0 +1,111 @@ +getErrorCode()) { + case '1': + case '2299': + case '38911': + return new UniqueConstraintViolationException($message, $exception); + + case '904': + return new InvalidFieldNameException($message, $exception); + + case '918': + case '960': + return new NonUniqueFieldNameException($message, $exception); + + case '923': + return new SyntaxErrorException($message, $exception); + + case '942': + return new TableNotFoundException($message, $exception); + + case '955': + return new TableExistsException($message, $exception); + + case '1017': + case '12545': + return new ConnectionException($message, $exception); + + case '1400': + return new NotNullConstraintViolationException($message, $exception); + + case '2266': + case '2291': + case '2292': + return new ForeignKeyConstraintViolationException($message, $exception); + } + + return new DriverException($message, $exception); + } + + /** + * {@inheritdoc} + * + * @deprecated Use Connection::getDatabase() instead. + */ + public function getDatabase(Connection $conn) + { + $params = $conn->getParams(); + + return $params['user']; + } + + /** + * {@inheritdoc} + */ + public function getDatabasePlatform() + { + return new OraclePlatform(); + } + + /** + * {@inheritdoc} + */ + public function getSchemaManager(Connection $conn) + { + return new OracleSchemaManager($conn); + } + + /** + * Returns an appropriate Easy Connect String for the given parameters. + * + * @param mixed[] $params The connection parameters to return the Easy Connect String for. + * + * @return string + */ + protected function getEasyConnectString(array $params) + { + return (string) EasyConnectString::fromConnectionParameters($params); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractOracleDriver/EasyConnectString.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractOracleDriver/EasyConnectString.php new file mode 100755 index 0000000..ba43974 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractOracleDriver/EasyConnectString.php @@ -0,0 +1,121 @@ +string = $string; + } + + public function __toString(): string + { + return $this->string; + } + + /** + * Creates the object from an array representation + * + * @param mixed[] $params + */ + public static function fromArray(array $params): self + { + return new self(self::renderParams($params)); + } + + /** + * Creates the object from the given DBAL connection parameters. + * + * @param mixed[] $params + */ + public static function fromConnectionParameters(array $params): self + { + if (! empty($params['connectstring'])) { + return new self($params['connectstring']); + } + + if (empty($params['host'])) { + return new self($params['dbname'] ?? ''); + } + + $connectData = []; + + if (isset($params['servicename']) || isset($params['dbname'])) { + $serviceKey = 'SID'; + + if (! empty($params['service'])) { + $serviceKey = 'SERVICE_NAME'; + } + + $serviceName = $params['servicename'] ?? $params['dbname']; + + $connectData[$serviceKey] = $serviceName; + } + + if (! empty($params['instancename'])) { + $connectData['INSTANCE_NAME'] = $params['instancename']; + } + + if (! empty($params['pooled'])) { + $connectData['SERVER'] = 'POOLED'; + } + + return self::fromArray([ + 'DESCRIPTION' => [ + 'ADDRESS' => [ + 'PROTOCOL' => 'TCP', + 'HOST' => $params['host'], + 'PORT' => $params['port'] ?? 1521, + ], + 'CONNECT_DATA' => $connectData, + ], + ]); + } + + /** + * @param mixed[] $params + */ + private static function renderParams(array $params): string + { + $chunks = []; + + foreach ($params as $key => $value) { + $string = self::renderValue($value); + + if ($string === '') { + continue; + } + + $chunks[] = sprintf('(%s=%s)', $key, $string); + } + + return implode('', $chunks); + } + + /** + * @param mixed $value + */ + private static function renderValue($value): string + { + if (is_array($value)) { + return self::renderParams($value); + } + + return (string) $value; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php new file mode 100755 index 0000000..b961025 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php @@ -0,0 +1,171 @@ +getSQLState(); + + switch ($sqlState) { + case '40001': + case '40P01': + return new DeadlockException($message, $exception); + + case '0A000': + // Foreign key constraint violations during a TRUNCATE operation + // are considered "feature not supported" in PostgreSQL. + if (strpos($exception->getMessage(), 'truncate') !== false) { + return new ForeignKeyConstraintViolationException($message, $exception); + } + + break; + + case '23502': + return new NotNullConstraintViolationException($message, $exception); + + case '23503': + return new ForeignKeyConstraintViolationException($message, $exception); + + case '23505': + return new UniqueConstraintViolationException($message, $exception); + + case '42601': + return new SyntaxErrorException($message, $exception); + + case '42702': + return new NonUniqueFieldNameException($message, $exception); + + case '42703': + return new InvalidFieldNameException($message, $exception); + + case '42P01': + return new TableNotFoundException($message, $exception); + + case '42P07': + return new TableExistsException($message, $exception); + + case '08006': + return new Exception\ConnectionException($message, $exception); + + case '7': + // Prior to fixing https://bugs.php.net/bug.php?id=64705 (PHP 7.3.22 and PHP 7.4.10), + // in some cases (mainly connection errors) the PDO exception wouldn't provide a SQLSTATE via its code. + // The exception code would be always set to 7 here. + // We have to match against the SQLSTATE in the error message in these cases. + if (strpos($exception->getMessage(), 'SQLSTATE[08006]') !== false) { + return new ConnectionException($message, $exception); + } + + break; + } + + return new DriverException($message, $exception); + } + + /** + * {@inheritdoc} + */ + public function createDatabasePlatformForVersion($version) + { + if (! preg_match('/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?/', $version, $versionParts)) { + throw Exception::invalidPlatformVersionSpecified( + $version, + '..' + ); + } + + $majorVersion = $versionParts['major']; + $minorVersion = $versionParts['minor'] ?? 0; + $patchVersion = $versionParts['patch'] ?? 0; + $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion; + + switch (true) { + case version_compare($version, '10.0', '>='): + return new PostgreSQL100Platform(); + case version_compare($version, '9.4', '>='): + return new PostgreSQL94Platform(); + case version_compare($version, '9.2', '>='): + return new PostgreSQL92Platform(); + case version_compare($version, '9.1', '>='): + return new PostgreSQL91Platform(); + default: + return new PostgreSqlPlatform(); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use Connection::getDatabase() instead. + */ + public function getDatabase(Connection $conn) + { + $params = $conn->getParams(); + + if (isset($params['dbname'])) { + return $params['dbname']; + } + + $database = $conn->query('SELECT CURRENT_DATABASE()')->fetchColumn(); + + assert($database !== false); + + return $database; + } + + /** + * {@inheritdoc} + */ + public function getDatabasePlatform() + { + return new PostgreSqlPlatform(); + } + + /** + * {@inheritdoc} + */ + public function getSchemaManager(Connection $conn) + { + return new PostgreSqlSchemaManager($conn); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php new file mode 100755 index 0000000..59ab872 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php @@ -0,0 +1,170 @@ +getErrorCode()) { + case '-306': + case '-307': + case '-684': + return new DeadlockException($message, $exception); + + case '-210': + case '-1175': + case '-1281': + return new LockWaitTimeoutException($message, $exception); + + case '-100': + case '-103': + case '-832': + return new ConnectionException($message, $exception); + + case '-143': + return new InvalidFieldNameException($message, $exception); + + case '-193': + case '-196': + return new UniqueConstraintViolationException($message, $exception); + + case '-194': + case '-198': + return new ForeignKeyConstraintViolationException($message, $exception); + + case '-144': + return new NonUniqueFieldNameException($message, $exception); + + case '-184': + case '-195': + return new NotNullConstraintViolationException($message, $exception); + + case '-131': + return new SyntaxErrorException($message, $exception); + + case '-110': + return new TableExistsException($message, $exception); + + case '-141': + case '-1041': + return new TableNotFoundException($message, $exception); + } + + return new DriverException($message, $exception); + } + + /** + * {@inheritdoc} + */ + public function createDatabasePlatformForVersion($version) + { + if ( + ! preg_match( + '/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?)?/', + $version, + $versionParts + ) + ) { + throw Exception::invalidPlatformVersionSpecified( + $version, + '...' + ); + } + + $majorVersion = $versionParts['major']; + $minorVersion = $versionParts['minor'] ?? 0; + $patchVersion = $versionParts['patch'] ?? 0; + $buildVersion = $versionParts['build'] ?? 0; + $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion . '.' . $buildVersion; + + switch (true) { + case version_compare($version, '16', '>='): + return new SQLAnywhere16Platform(); + + case version_compare($version, '12', '>='): + return new SQLAnywhere12Platform(); + + case version_compare($version, '11', '>='): + return new SQLAnywhere11Platform(); + + default: + return new SQLAnywherePlatform(); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use Connection::getDatabase() instead. + */ + public function getDatabase(Connection $conn) + { + $params = $conn->getParams(); + + if (isset($params['dbname'])) { + return $params['dbname']; + } + + $database = $conn->query('SELECT DB_NAME()')->fetchColumn(); + + assert($database !== false); + + return $database; + } + + /** + * {@inheritdoc} + */ + public function getDatabasePlatform() + { + return new SQLAnywhere12Platform(); + } + + /** + * {@inheritdoc} + */ + public function getSchemaManager(Connection $conn) + { + return new SQLAnywhereSchemaManager($conn); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php new file mode 100755 index 0000000..2550ec5 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php @@ -0,0 +1,107 @@ +\d+)(?:\.(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?)?/', + $version, + $versionParts + ) + ) { + throw Exception::invalidPlatformVersionSpecified( + $version, + '...' + ); + } + + $majorVersion = $versionParts['major']; + $minorVersion = $versionParts['minor'] ?? 0; + $patchVersion = $versionParts['patch'] ?? 0; + $buildVersion = $versionParts['build'] ?? 0; + $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion . '.' . $buildVersion; + + switch (true) { + case version_compare($version, '11.00.2100', '>='): + return new SQLServer2012Platform(); + case version_compare($version, '10.00.1600', '>='): + return new SQLServer2008Platform(); + case version_compare($version, '9.00.1399', '>='): + return new SQLServer2005Platform(); + default: + return new SQLServerPlatform(); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use Connection::getDatabase() instead. + */ + public function getDatabase(Connection $conn) + { + $params = $conn->getParams(); + + if (isset($params['dbname'])) { + return $params['dbname']; + } + + $database = $conn->query('SELECT DB_NAME()')->fetchColumn(); + + assert($database !== false); + + return $database; + } + + /** + * {@inheritdoc} + */ + public function getDatabasePlatform() + { + return new SQLServer2008Platform(); + } + + /** + * {@inheritdoc} + */ + public function getSchemaManager(Connection $conn) + { + return new SQLServerSchemaManager($conn); + } + + /** + * @param string $message + * + * @return DriverException + */ + public function convertException($message, TheDriverException $exception) + { + return new DriverException($message, $exception); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver/Exception/PortWithoutHost.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver/Exception/PortWithoutHost.php new file mode 100755 index 0000000..c6dbf34 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver/Exception/PortWithoutHost.php @@ -0,0 +1,20 @@ +getMessage(), 'database is locked') !== false) { + return new LockWaitTimeoutException($message, $exception); + } + + if ( + strpos($exception->getMessage(), 'must be unique') !== false || + strpos($exception->getMessage(), 'is not unique') !== false || + strpos($exception->getMessage(), 'are not unique') !== false || + strpos($exception->getMessage(), 'UNIQUE constraint failed') !== false + ) { + return new UniqueConstraintViolationException($message, $exception); + } + + if ( + strpos($exception->getMessage(), 'may not be NULL') !== false || + strpos($exception->getMessage(), 'NOT NULL constraint failed') !== false + ) { + return new NotNullConstraintViolationException($message, $exception); + } + + if (strpos($exception->getMessage(), 'no such table:') !== false) { + return new TableNotFoundException($message, $exception); + } + + if (strpos($exception->getMessage(), 'already exists') !== false) { + return new TableExistsException($message, $exception); + } + + if (strpos($exception->getMessage(), 'has no column named') !== false) { + return new InvalidFieldNameException($message, $exception); + } + + if (strpos($exception->getMessage(), 'ambiguous column name') !== false) { + return new NonUniqueFieldNameException($message, $exception); + } + + if (strpos($exception->getMessage(), 'syntax error') !== false) { + return new SyntaxErrorException($message, $exception); + } + + if (strpos($exception->getMessage(), 'attempt to write a readonly database') !== false) { + return new ReadOnlyException($message, $exception); + } + + if (strpos($exception->getMessage(), 'unable to open database file') !== false) { + return new ConnectionException($message, $exception); + } + + return new DriverException($message, $exception); + } + + /** + * {@inheritdoc} + * + * @deprecated Use Connection::getDatabase() instead. + */ + public function getDatabase(Connection $conn) + { + $params = $conn->getParams(); + + return $params['path'] ?? null; + } + + /** + * {@inheritdoc} + */ + public function getDatabasePlatform() + { + return new SqlitePlatform(); + } + + /** + * {@inheritdoc} + */ + public function getSchemaManager(Connection $conn) + { + return new SqliteSchemaManager($conn); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Connection.php new file mode 100755 index 0000000..2dc5e73 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Connection.php @@ -0,0 +1,97 @@ +constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + } + + /** + * {@inheritdoc} + */ + public function createDatabasePlatformForVersion($version) + { + return $this->getDatabasePlatform(); + } + + /** + * {@inheritdoc} + * + * @return DrizzlePlatform + */ + public function getDatabasePlatform() + { + return new DrizzlePlatform(); + } + + /** + * {@inheritdoc} + * + * @return DrizzleSchemaManager + */ + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new DrizzleSchemaManager($conn); + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + return 'drizzle_pdo_mysql'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Exception.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Exception.php new file mode 100755 index 0000000..a16db4f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Exception.php @@ -0,0 +1,34 @@ +fetchNumeric(); + + if ($row === false) { + return false; + } + + return $row[0]; + } + + /** + * @return array> + * + * @throws Exception + */ + public static function fetchAllNumeric(Result $result): array + { + $rows = []; + + while (($row = $result->fetchNumeric()) !== false) { + $rows[] = $row; + } + + return $rows; + } + + /** + * @return array> + * + * @throws Exception + */ + public static function fetchAllAssociative(Result $result): array + { + $rows = []; + + while (($row = $result->fetchAssociative()) !== false) { + $rows[] = $row; + } + + return $rows; + } + + /** + * @return array + * + * @throws Exception + */ + public static function fetchFirstColumn(Result $result): array + { + $rows = []; + + while (($row = $result->fetchOne()) !== false) { + $rows[] = $row; + } + + return $rows; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/Connection.php new file mode 100755 index 0000000..b054757 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/Connection.php @@ -0,0 +1,7 @@ +conn = $conn; + } + + /** + * {@inheritdoc} + */ + public function getServerVersion() + { + $serverInfo = db2_server_info($this->conn); + assert($serverInfo instanceof stdClass); + + return $serverInfo->DBMS_VER; + } + + /** + * {@inheritdoc} + */ + public function requiresQueryForServerVersion() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4114', + 'ServerInfoAwareConnection::requiresQueryForServerVersion() is deprecated and removed in DBAL 3.' + ); + + return false; + } + + /** + * {@inheritdoc} + */ + public function prepare($sql) + { + $stmt = @db2_prepare($this->conn, $sql); + + if ($stmt === false) { + throw PrepareFailed::new(error_get_last()); + } + + return new Statement($stmt); + } + + /** + * {@inheritdoc} + */ + public function query() + { + $args = func_get_args(); + $sql = $args[0]; + $stmt = $this->prepare($sql); + $stmt->execute(); + + return $stmt; + } + + /** + * {@inheritdoc} + */ + public function quote($value, $type = ParameterType::STRING) + { + $value = db2_escape_string($value); + + if ($type === ParameterType::INTEGER) { + return $value; + } + + return "'" . $value . "'"; + } + + /** + * {@inheritdoc} + */ + public function exec($sql) + { + $stmt = @db2_exec($this->conn, $sql); + + if ($stmt === false) { + throw ConnectionError::new($this->conn); + } + + return db2_num_rows($stmt); + } + + /** + * {@inheritdoc} + */ + public function lastInsertId($name = null) + { + return db2_last_insert_id($this->conn); + } + + /** + * {@inheritdoc} + */ + public function beginTransaction() + { + $result = db2_autocommit($this->conn, DB2_AUTOCOMMIT_OFF); + assert(is_bool($result)); + + return $result; + } + + /** + * {@inheritdoc} + */ + public function commit() + { + if (! db2_commit($this->conn)) { + throw ConnectionError::new($this->conn); + } + + $result = db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON); + assert(is_bool($result)); + + return $result; + } + + /** + * {@inheritdoc} + */ + public function rollBack() + { + if (! db2_rollback($this->conn)) { + throw ConnectionError::new($this->conn); + } + + $result = db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON); + assert(is_bool($result)); + + return $result; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorCode() + { + return db2_conn_error($this->conn); + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + return [ + 0 => db2_conn_errormsg($this->conn), + 1 => $this->errorCode(), + ]; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php new file mode 100755 index 0000000..f4e50c9 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php @@ -0,0 +1,47 @@ +toString(); + + return new Connection( + $params, + (string) $username, + (string) $password, + $driverOptions + ); + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Driver::getName() is deprecated' + ); + + return 'ibm_db2'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php new file mode 100755 index 0000000..5297d70 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php @@ -0,0 +1,14 @@ +stmt = $stmt; + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, $type = ParameterType::STRING) + { + assert(is_int($param)); + + return $this->bindParam($param, $value, $type); + } + + /** + * {@inheritdoc} + */ + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) + { + assert(is_int($param)); + + switch ($type) { + case ParameterType::INTEGER: + $this->bind($param, $variable, DB2_PARAM_IN, DB2_LONG); + break; + + case ParameterType::LARGE_OBJECT: + if (isset($this->lobs[$param])) { + [, $handle] = $this->lobs[$param]; + fclose($handle); + } + + $handle = $this->createTemporaryFile(); + $path = stream_get_meta_data($handle)['uri']; + + $this->bind($param, $path, DB2_PARAM_FILE, DB2_BINARY); + + $this->lobs[$param] = [&$variable, $handle]; + break; + + default: + $this->bind($param, $variable, DB2_PARAM_IN, DB2_CHAR); + break; + } + + return true; + } + + /** + * @param int $position Parameter position + * @param mixed $variable + * + * @throws DB2Exception + */ + private function bind($position, &$variable, int $parameterType, int $dataType): void + { + $this->bindParam[$position] =& $variable; + + if (! db2_bind_param($this->stmt, $position, 'variable', $parameterType, $dataType)) { + throw StatementError::new($this->stmt); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use free() instead. + */ + public function closeCursor() + { + $this->bindParam = []; + + if (! db2_free_result($this->stmt)) { + return false; + } + + $this->result = false; + + return true; + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + return db2_num_fields($this->stmt) ?: 0; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorCode() + { + return db2_stmt_error(); + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + return [ + db2_stmt_errormsg(), + db2_stmt_error(), + ]; + } + + /** + * {@inheritdoc} + */ + public function execute($params = null) + { + if ($params === null) { + ksort($this->bindParam); + + $params = []; + + foreach ($this->bindParam as $column => $value) { + $params[] = $value; + } + } + + foreach ($this->lobs as [$source, $target]) { + if (is_resource($source)) { + $this->copyStreamToStream($source, $target); + + continue; + } + + $this->writeStringToStream($source, $target); + } + + $retval = db2_execute($this->stmt, $params); + + foreach ($this->lobs as [, $handle]) { + fclose($handle); + } + + $this->lobs = []; + + if ($retval === false) { + throw StatementError::new($this->stmt); + } + + $this->result = true; + + return $retval; + } + + /** + * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->defaultFetchMode = $fetchMode; + $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; + $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; + + return true; + } + + /** + * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. + */ + #[ReturnTypeWillChange] + public function getIterator() + { + return new StatementIterator($this); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + */ + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + // do not try fetching from the statement if it's not expected to contain result + // in order to prevent exceptional situation + if (! $this->result) { + return false; + } + + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + switch ($fetchMode) { + case FetchMode::COLUMN: + return $this->fetchColumn(); + + case FetchMode::MIXED: + return db2_fetch_both($this->stmt); + + case FetchMode::ASSOCIATIVE: + return db2_fetch_assoc($this->stmt); + + case FetchMode::CUSTOM_OBJECT: + $className = $this->defaultFetchClass; + $ctorArgs = $this->defaultFetchClassCtorArgs; + + if (func_num_args() >= 2) { + $args = func_get_args(); + $className = $args[1]; + $ctorArgs = $args[2] ?? []; + } + + $result = db2_fetch_object($this->stmt); + + if ($result instanceof stdClass) { + $result = $this->castObject($result, $className, $ctorArgs); + } + + return $result; + + case FetchMode::NUMERIC: + return db2_fetch_array($this->stmt); + + case FetchMode::STANDARD_OBJECT: + return db2_fetch_object($this->stmt); + + default: + throw new DB2Exception('Given Fetch-Style ' . $fetchMode . ' is not supported.'); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + $rows = []; + + switch ($fetchMode) { + case FetchMode::CUSTOM_OBJECT: + while (($row = $this->fetch(...func_get_args())) !== false) { + $rows[] = $row; + } + + break; + + case FetchMode::COLUMN: + while (($row = $this->fetchColumn()) !== false) { + $rows[] = $row; + } + + break; + + default: + while (($row = $this->fetch($fetchMode)) !== false) { + $rows[] = $row; + } + } + + return $rows; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. + */ + public function fetchColumn($columnIndex = 0) + { + $row = $this->fetch(FetchMode::NUMERIC); + + if ($row === false) { + return false; + } + + return $row[$columnIndex] ?? null; + } + + /** + * {@inheritDoc} + */ + public function fetchNumeric() + { + if (! $this->result) { + return false; + } + + return db2_fetch_array($this->stmt); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + // do not try fetching from the statement if it's not expected to contain the result + // in order to prevent exceptional situation + if (! $this->result) { + return false; + } + + return db2_fetch_assoc($this->stmt); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric(): array + { + return FetchUtils::fetchAllNumeric($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative(): array + { + return FetchUtils::fetchAllAssociative($this); + } + + /** + * {@inheritdoc} + */ + public function fetchFirstColumn(): array + { + return FetchUtils::fetchFirstColumn($this); + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + return @db2_num_rows($this->stmt) ? : 0; + } + + public function free(): void + { + $this->bindParam = []; + + db2_free_result($this->stmt); + + $this->result = false; + } + + /** + * Casts a stdClass object to the given class name mapping its' properties. + * + * @param stdClass $sourceObject Object to cast from. + * @param class-string|object $destinationClass Name of the class or class instance to cast to. + * @param mixed[] $ctorArgs Arguments to use for constructing the destination class instance. + * + * @return object + * + * @throws DB2Exception + */ + private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = []) + { + if (! is_string($destinationClass)) { + if (! is_object($destinationClass)) { + throw new DB2Exception(sprintf( + 'Destination class has to be of type string or object, %s given.', + gettype($destinationClass) + )); + } + } else { + $destinationClass = new ReflectionClass($destinationClass); + $destinationClass = $destinationClass->newInstanceArgs($ctorArgs); + } + + $sourceReflection = new ReflectionObject($sourceObject); + $destinationClassReflection = new ReflectionObject($destinationClass); + /** @var ReflectionProperty[] $destinationProperties */ + $destinationProperties = array_change_key_case($destinationClassReflection->getProperties(), CASE_LOWER); + + foreach ($sourceReflection->getProperties() as $sourceProperty) { + $sourceProperty->setAccessible(true); + + $name = $sourceProperty->getName(); + $value = $sourceProperty->getValue($sourceObject); + + // Try to find a case-matching property. + if ($destinationClassReflection->hasProperty($name)) { + $destinationProperty = $destinationClassReflection->getProperty($name); + + $destinationProperty->setAccessible(true); + $destinationProperty->setValue($destinationClass, $value); + + continue; + } + + $name = strtolower($name); + + // Try to find a property without matching case. + // Fallback for the driver returning either all uppercase or all lowercase column names. + if (isset($destinationProperties[$name])) { + $destinationProperty = $destinationProperties[$name]; + + $destinationProperty->setAccessible(true); + $destinationProperty->setValue($destinationClass, $value); + + continue; + } + + $destinationClass->$name = $value; + } + + return $destinationClass; + } + + /** + * @return resource + * + * @throws DB2Exception + */ + private function createTemporaryFile() + { + $handle = @tmpfile(); + + if ($handle === false) { + throw CannotCreateTemporaryFile::new(error_get_last()); + } + + return $handle; + } + + /** + * @param resource $source + * @param resource $target + * + * @throws DB2Exception + */ + private function copyStreamToStream($source, $target): void + { + if (@stream_copy_to_stream($source, $target) === false) { + throw CannotCopyStreamToStream::new(error_get_last()); + } + } + + /** + * @param resource $target + * + * @throws DB2Exception + */ + private function writeStringToStream(string $string, $target): void + { + if (@fwrite($target, $string) === false) { + throw CannotWriteToTemporaryFile::new(error_get_last()); + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DataSourceName.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DataSourceName.php new file mode 100755 index 0000000..e1ec42f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DataSourceName.php @@ -0,0 +1,77 @@ +string = $string; + } + + public function toString(): string + { + return $this->string; + } + + /** + * Creates the object from an array representation + * + * @param array $params + */ + public static function fromArray(array $params): self + { + $chunks = []; + + foreach ($params as $key => $value) { + $chunks[] = sprintf('%s=%s', $key, $value); + } + + return new self(implode(';', $chunks)); + } + + /** + * Creates the object from the given DBAL connection parameters. + * + * @param array $params + */ + public static function fromConnectionParameters(array $params): self + { + if (isset($params['dbname']) && strpos($params['dbname'], '=') !== false) { + return new self($params['dbname']); + } + + $dsnParams = []; + + foreach ( + [ + 'host' => 'HOSTNAME', + 'port' => 'PORT', + 'protocol' => 'PROTOCOL', + 'dbname' => 'DATABASE', + 'user' => 'UID', + 'password' => 'PWD', + ] as $dbalParam => $dsnParam + ) { + if (! isset($params[$dbalParam])) { + continue; + } + + $dsnParams[$dsnParam] = $params[$dbalParam]; + } + + return self::fromArray($dsnParams); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/Driver.php new file mode 100755 index 0000000..dcc84b3 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/Driver.php @@ -0,0 +1,9 @@ +error, $connection->sqlstate, $connection->errno); + } + + public static function upcast(mysqli_sql_exception $exception): self + { + $p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate'); + $p->setAccessible(true); + + return new self($exception->getMessage(), $p->getValue($exception), $exception->getCode(), $exception); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Exception/ConnectionFailed.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Exception/ConnectionFailed.php new file mode 100755 index 0000000..6abdbda --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Exception/ConnectionFailed.php @@ -0,0 +1,31 @@ +connect_error, 'HY000', $connection->connect_errno); + } + + public static function upcast(mysqli_sql_exception $exception): self + { + $p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate'); + $p->setAccessible(true); + + return new self($exception->getMessage(), $p->getValue($exception), $exception->getCode(), $exception); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Exception/FailedReadingStreamOffset.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Exception/FailedReadingStreamOffset.php new file mode 100755 index 0000000..d3aaf8f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Exception/FailedReadingStreamOffset.php @@ -0,0 +1,22 @@ +error, $statement->sqlstate, $statement->errno); + } + + public static function upcast(mysqli_sql_exception $exception): self + { + $p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate'); + $p->setAccessible(true); + + return new self($exception->getMessage(), $p->getValue($exception), $exception->getCode(), $exception); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Exception/UnknownType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Exception/UnknownType.php new file mode 100755 index 0000000..0282b4d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Exception/UnknownType.php @@ -0,0 +1,25 @@ +conn = $conn; + + $this->setSecureConnection($params); + $this->setDriverOptions($driverOptions); + + try { + $success = @$this->conn + ->real_connect($params['host'], $username, $password, $dbname, $port, $socket, $flags); + } catch (mysqli_sql_exception $e) { + throw ConnectionFailed::upcast($e); + } + + if (! $success) { + throw ConnectionFailed::new($this->conn); + } + + if (! isset($params['charset'])) { + return; + } + + $this->conn->set_charset($params['charset']); + } + + /** + * Retrieves mysqli native resource handle. + * + * Could be used if part of your application is not using DBAL. + * + * @return mysqli + */ + public function getWrappedResourceHandle() + { + return $this->conn; + } + + /** + * {@inheritdoc} + * + * The server version detection includes a special case for MariaDB + * to support '5.5.5-' prefixed versions introduced in Maria 10+ + * + * @link https://jira.mariadb.org/browse/MDEV-4088 + */ + public function getServerVersion() + { + $serverInfos = $this->conn->get_server_info(); + if (stripos($serverInfos, 'mariadb') !== false) { + return $serverInfos; + } + + $majorVersion = floor($this->conn->server_version / 10000); + $minorVersion = floor(($this->conn->server_version - $majorVersion * 10000) / 100); + $patchVersion = floor($this->conn->server_version - $majorVersion * 10000 - $minorVersion * 100); + + return $majorVersion . '.' . $minorVersion . '.' . $patchVersion; + } + + /** + * {@inheritdoc} + */ + public function requiresQueryForServerVersion() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4114', + 'ServerInfoAwareConnection::requiresQueryForServerVersion() is deprecated and removed in DBAL 3.' + ); + + return false; + } + + /** + * {@inheritdoc} + */ + public function prepare($sql) + { + return new Statement($this->conn, $sql); + } + + /** + * {@inheritdoc} + */ + public function query() + { + $args = func_get_args(); + $sql = $args[0]; + $stmt = $this->prepare($sql); + $stmt->execute(); + + return $stmt; + } + + /** + * {@inheritdoc} + */ + public function quote($value, $type = ParameterType::STRING) + { + return "'" . $this->conn->escape_string($value) . "'"; + } + + /** + * {@inheritdoc} + */ + public function exec($sql) + { + try { + $result = $this->conn->query($sql); + } catch (mysqli_sql_exception $e) { + throw ConnectionError::upcast($e); + } + + if ($result === false) { + throw ConnectionError::new($this->conn); + } + + return $this->conn->affected_rows; + } + + /** + * {@inheritdoc} + */ + public function lastInsertId($name = null) + { + return $this->conn->insert_id; + } + + /** + * {@inheritdoc} + */ + public function beginTransaction() + { + $this->conn->query('START TRANSACTION'); + + return true; + } + + /** + * {@inheritdoc} + */ + public function commit() + { + try { + return $this->conn->commit(); + } catch (mysqli_sql_exception $e) { + return false; + } + } + + /** + * {@inheritdoc}non-PHPdoc) + */ + public function rollBack() + { + try { + return $this->conn->rollback(); + } catch (mysqli_sql_exception $e) { + return false; + } + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + * + * @return int + */ + public function errorCode() + { + return $this->conn->errno; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + * + * @return string + */ + public function errorInfo() + { + return $this->conn->error; + } + + /** + * Apply the driver options to the connection. + * + * @param mixed[] $driverOptions + * + * @throws MysqliException When one of of the options is not supported. + * @throws MysqliException When applying doesn't work - e.g. due to incorrect value. + */ + private function setDriverOptions(array $driverOptions = []): void + { + $supportedDriverOptions = [ + MYSQLI_OPT_CONNECT_TIMEOUT, + MYSQLI_OPT_LOCAL_INFILE, + MYSQLI_OPT_READ_TIMEOUT, + MYSQLI_INIT_COMMAND, + MYSQLI_READ_DEFAULT_FILE, + MYSQLI_READ_DEFAULT_GROUP, + MYSQLI_SERVER_PUBLIC_KEY, + ]; + + $exceptionMsg = "%s option '%s' with value '%s'"; + + foreach ($driverOptions as $option => $value) { + if ($option === static::OPTION_FLAGS) { + continue; + } + + if (! in_array($option, $supportedDriverOptions, true)) { + throw InvalidOption::fromOption($option, $value); + } + + if (@mysqli_options($this->conn, $option, $value)) { + continue; + } + + $msg = sprintf($exceptionMsg, 'Failed to set', $option, $value); + $msg .= sprintf(', error: %s (%d)', mysqli_error($this->conn), mysqli_errno($this->conn)); + + throw new MysqliException( + $msg, + $this->conn->sqlstate, + $this->conn->errno + ); + } + } + + /** + * Pings the server and re-connects when `mysqli.reconnect = 1` + * + * @deprecated + * + * @return bool + */ + public function ping() + { + return $this->conn->ping(); + } + + /** + * Establish a secure connection + * + * @param array $params + * + * @throws MysqliException + */ + private function setSecureConnection(array $params): void + { + if ( + ! isset($params['ssl_key']) && + ! isset($params['ssl_cert']) && + ! isset($params['ssl_ca']) && + ! isset($params['ssl_capath']) && + ! isset($params['ssl_cipher']) + ) { + return; + } + + $this->conn->ssl_set( + $params['ssl_key'] ?? '', + $params['ssl_cert'] ?? '', + $params['ssl_ca'] ?? '', + $params['ssl_capath'] ?? '', + $params['ssl_cipher'] ?? '' + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php new file mode 100755 index 0000000..f583ed3 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php @@ -0,0 +1,14 @@ + 's', + ParameterType::STRING => 's', + ParameterType::BINARY => 's', + ParameterType::BOOLEAN => 'i', + ParameterType::NULL => 's', + ParameterType::INTEGER => 'i', + ParameterType::LARGE_OBJECT => 'b', + ]; + + /** @var mysqli */ + protected $_conn; + + /** @var mysqli_stmt */ + protected $_stmt; + + /** @var string[]|false|null */ + protected $_columnNames; + + /** @var mixed[] */ + protected $_rowBindedValues = []; + + /** @var mixed[] */ + protected $_bindedValues; + + /** @var string */ + protected $types; + + /** + * Contains ref values for bindValue(). + * + * @var mixed[] + */ + protected $_values = []; + + /** @var int */ + protected $_defaultFetchMode = FetchMode::MIXED; + + /** + * Indicates whether the statement is in the state when fetching results is possible + * + * @var bool + */ + private $result = false; + + /** + * @internal The statement can be only instantiated by its driver connection. + * + * @param string $prepareString + * + * @throws MysqliException + */ + public function __construct(mysqli $conn, $prepareString) + { + $this->_conn = $conn; + + try { + $stmt = $conn->prepare($prepareString); + } catch (mysqli_sql_exception $e) { + throw ConnectionError::upcast($e); + } + + if ($stmt === false) { + throw ConnectionError::new($this->_conn); + } + + $this->_stmt = $stmt; + + $paramCount = $this->_stmt->param_count; + $this->types = str_repeat('s', $paramCount); + $this->_bindedValues = array_fill(1, $paramCount, null); + } + + /** + * {@inheritdoc} + */ + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) + { + assert(is_int($param)); + + if (! isset(self::$_paramTypeMap[$type])) { + throw UnknownType::new($type); + } + + $this->_bindedValues[$param] =& $variable; + $this->types[$param - 1] = self::$_paramTypeMap[$type]; + + return true; + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, $type = ParameterType::STRING) + { + assert(is_int($param)); + + if (! isset(self::$_paramTypeMap[$type])) { + throw UnknownType::new($type); + } + + $this->_values[$param] = $value; + $this->_bindedValues[$param] =& $this->_values[$param]; + $this->types[$param - 1] = self::$_paramTypeMap[$type]; + + return true; + } + + /** + * {@inheritdoc} + */ + public function execute($params = null) + { + if ($params !== null && count($params) > 0) { + if (! $this->bindUntypedValues($params)) { + throw StatementError::new($this->_stmt); + } + } elseif (count($this->_bindedValues) > 0) { + $this->bindTypedParameters(); + } + + try { + $result = $this->_stmt->execute(); + } catch (mysqli_sql_exception $e) { + throw StatementError::upcast($e); + } + + if (! $result) { + throw StatementError::new($this->_stmt); + } + + if ($this->_columnNames === null) { + $meta = $this->_stmt->result_metadata(); + if ($meta !== false) { + $fields = $meta->fetch_fields(); + assert(is_array($fields)); + + $columnNames = []; + foreach ($fields as $col) { + $columnNames[] = $col->name; + } + + $meta->free(); + + $this->_columnNames = $columnNames; + } else { + $this->_columnNames = false; + } + } + + if ($this->_columnNames !== false) { + // Store result of every execution which has it. Otherwise it will be impossible + // to execute a new statement in case if the previous one has non-fetched rows + // @link http://dev.mysql.com/doc/refman/5.7/en/commands-out-of-sync.html + $this->_stmt->store_result(); + + // Bind row values _after_ storing the result. Otherwise, if mysqli is compiled with libmysql, + // it will have to allocate as much memory as it may be needed for the given column type + // (e.g. for a LONGBLOB column it's 4 gigabytes) + // @link https://bugs.php.net/bug.php?id=51386#1270673122 + // + // Make sure that the values are bound after each execution. Otherwise, if closeCursor() has been + // previously called on the statement, the values are unbound making the statement unusable. + // + // It's also important that row values are bound after _each_ call to store_result(). Otherwise, + // if mysqli is compiled with libmysql, subsequently fetched string values will get truncated + // to the length of the ones fetched during the previous execution. + $this->_rowBindedValues = array_fill(0, count($this->_columnNames), null); + + $refs = []; + foreach ($this->_rowBindedValues as $key => &$value) { + $refs[$key] =& $value; + } + + if (! $this->_stmt->bind_result(...$refs)) { + throw StatementError::new($this->_stmt); + } + } + + $this->result = true; + + return true; + } + + /** + * Binds parameters with known types previously bound to the statement + */ + private function bindTypedParameters(): void + { + $streams = $values = []; + $types = $this->types; + + foreach ($this->_bindedValues as $parameter => $value) { + assert(is_int($parameter)); + + if (! isset($types[$parameter - 1])) { + $types[$parameter - 1] = static::$_paramTypeMap[ParameterType::STRING]; + } + + if ($types[$parameter - 1] === static::$_paramTypeMap[ParameterType::LARGE_OBJECT]) { + if (is_resource($value)) { + if (get_resource_type($value) !== 'stream') { + throw new InvalidArgumentException( + 'Resources passed with the LARGE_OBJECT parameter type must be stream resources.' + ); + } + + $streams[$parameter] = $value; + $values[$parameter] = null; + continue; + } + + $types[$parameter - 1] = static::$_paramTypeMap[ParameterType::STRING]; + } + + $values[$parameter] = $value; + } + + if (! $this->_stmt->bind_param($types, ...$values)) { + throw StatementError::new($this->_stmt); + } + + $this->sendLongData($streams); + } + + /** + * Handle $this->_longData after regular query parameters have been bound + * + * @param array $streams + * + * @throws MysqliException + */ + private function sendLongData(array $streams): void + { + foreach ($streams as $paramNr => $stream) { + while (! feof($stream)) { + $chunk = fread($stream, 8192); + + if ($chunk === false) { + throw FailedReadingStreamOffset::new($paramNr); + } + + if (! $this->_stmt->send_long_data($paramNr - 1, $chunk)) { + throw StatementError::new($this->_stmt); + } + } + } + } + + /** + * Binds a array of values to bound parameters. + * + * @param mixed[] $values + * + * @return bool + */ + private function bindUntypedValues(array $values) + { + $params = []; + $types = str_repeat('s', count($values)); + + foreach ($values as &$v) { + $params[] =& $v; + } + + return $this->_stmt->bind_param($types, ...$params); + } + + /** + * @return mixed[]|false|null + * + * @throws StatementError + */ + private function _fetch() + { + try { + $ret = $this->_stmt->fetch(); + } catch (mysqli_sql_exception $e) { + throw StatementError::upcast($e); + } + + if ($ret === true) { + $values = []; + foreach ($this->_rowBindedValues as $v) { + $values[] = $v; + } + + return $values; + } + + return $ret; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + */ + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + // do not try fetching from the statement if it's not expected to contain result + // in order to prevent exceptional situation + if (! $this->result) { + return false; + } + + $fetchMode = $fetchMode ?: $this->_defaultFetchMode; + + if ($fetchMode === FetchMode::COLUMN) { + return $this->fetchColumn(); + } + + $values = $this->_fetch(); + + if ($values === null) { + return false; + } + + if ($values === false) { + throw StatementError::new($this->_stmt); + } + + if ($fetchMode === FetchMode::NUMERIC) { + return $values; + } + + assert(is_array($this->_columnNames)); + $assoc = array_combine($this->_columnNames, $values); + assert(is_array($assoc)); + + switch ($fetchMode) { + case FetchMode::ASSOCIATIVE: + return $assoc; + + case FetchMode::MIXED: + return $assoc + $values; + + case FetchMode::STANDARD_OBJECT: + return (object) $assoc; + + default: + throw new MysqliException(sprintf("Unknown fetch type '%s'", $fetchMode)); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + $fetchMode = $fetchMode ?: $this->_defaultFetchMode; + + $rows = []; + + if ($fetchMode === FetchMode::COLUMN) { + while (($row = $this->fetchColumn()) !== false) { + $rows[] = $row; + } + } else { + while (($row = $this->fetch($fetchMode)) !== false) { + $rows[] = $row; + } + } + + return $rows; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. + */ + public function fetchColumn($columnIndex = 0) + { + $row = $this->fetch(FetchMode::NUMERIC); + + if ($row === false) { + return false; + } + + return $row[$columnIndex] ?? null; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function fetchNumeric() + { + // do not try fetching from the statement if it's not expected to contain the result + // in order to prevent exceptional situation + if (! $this->result) { + return false; + } + + $values = $this->_fetch(); + + if ($values === null) { + return false; + } + + if ($values === false) { + throw StatementError::new($this->_stmt); + } + + return $values; + } + + /** + * {@inheritDoc} + */ + public function fetchAssociative() + { + $values = $this->fetchNumeric(); + + if ($values === false) { + return false; + } + + assert(is_array($this->_columnNames)); + $row = array_combine($this->_columnNames, $values); + assert(is_array($row)); + + return $row; + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric(): array + { + return FetchUtils::fetchAllNumeric($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative(): array + { + return FetchUtils::fetchAllAssociative($this); + } + + /** + * {@inheritdoc} + */ + public function fetchFirstColumn(): array + { + return FetchUtils::fetchFirstColumn($this); + } + + /** + * {@inheritdoc} + */ + public function errorCode() + { + return $this->_stmt->errno; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + * + * @return string + */ + public function errorInfo() + { + return $this->_stmt->error; + } + + /** + * {@inheritdoc} + * + * @deprecated Use free() instead. + */ + public function closeCursor() + { + $this->free(); + + return true; + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + if ($this->_columnNames === false) { + return $this->_stmt->affected_rows; + } + + return $this->_stmt->num_rows; + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + return $this->_stmt->field_count; + } + + public function free(): void + { + $this->_stmt->free_result(); + $this->result = false; + } + + /** + * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->_defaultFetchMode = $fetchMode; + + return true; + } + + /** + * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. + */ + #[ReturnTypeWillChange] + public function getIterator() + { + return new StatementIterator($this); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Statement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Statement.php new file mode 100755 index 0000000..bfd6ae9 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Statement.php @@ -0,0 +1,7 @@ +_constructDsn($params), + $params['charset'] ?? '', + $params['sessionMode'] ?? OCI_NO_AUTO_COMMIT, + $params['persistent'] ?? false + ); + } catch (OCI8Exception $e) { + throw Exception::driverException($this, $e); + } + } + + /** + * Constructs the Oracle DSN. + * + * @param mixed[] $params + * + * @return string The DSN. + */ + protected function _constructDsn(array $params) + { + return $this->getEasyConnectString($params); + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Driver::getName() is deprecated' + ); + + return 'oci8'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/Exception/NonTerminatedStringLiteral.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/Exception/NonTerminatedStringLiteral.php new file mode 100755 index 0000000..870e413 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/Exception/NonTerminatedStringLiteral.php @@ -0,0 +1,27 @@ +dbh = $dbh; + } + + /** + * {@inheritdoc} + * + * @throws UnexpectedValueException If the version string returned by the database server + * does not contain a parsable version number. + */ + public function getServerVersion() + { + $version = oci_server_version($this->dbh); + + if ($version === false) { + throw OCI8Exception::fromErrorInfo(oci_error($this->dbh)); + } + + if (! preg_match('/\s+(\d+\.\d+\.\d+\.\d+\.\d+)\s+/', $version, $matches)) { + throw new UnexpectedValueException( + sprintf( + 'Unexpected database version string "%s". Cannot parse an appropriate version number from it. ' . + 'Please report this database version string to the Doctrine team.', + $version + ) + ); + } + + return $matches[1]; + } + + /** + * {@inheritdoc} + */ + public function requiresQueryForServerVersion() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4114', + 'ServerInfoAwareConnection::requiresQueryForServerVersion() is deprecated and removed in DBAL 3.' + ); + + return false; + } + + /** + * {@inheritdoc} + */ + public function prepare($sql) + { + return new Statement($this->dbh, $sql, $this); + } + + /** + * {@inheritdoc} + */ + public function query() + { + $args = func_get_args(); + $sql = $args[0]; + //$fetchMode = $args[1]; + $stmt = $this->prepare($sql); + $stmt->execute(); + + return $stmt; + } + + /** + * {@inheritdoc} + */ + public function quote($value, $type = ParameterType::STRING) + { + if (is_int($value) || is_float($value)) { + return $value; + } + + $value = str_replace("'", "''", $value); + + return "'" . addcslashes($value, "\000\n\r\\\032") . "'"; + } + + /** + * {@inheritdoc} + */ + public function exec($sql) + { + $stmt = $this->prepare($sql); + $stmt->execute(); + + return $stmt->rowCount(); + } + + /** + * {@inheritdoc} + * + * @param string|null $name + * + * @return int|false + */ + public function lastInsertId($name = null) + { + if ($name === null) { + return false; + } + + $sql = 'SELECT ' . $name . '.CURRVAL FROM DUAL'; + $stmt = $this->query($sql); + $result = $stmt->fetchColumn(); + + if ($result === false) { + throw SequenceDoesNotExist::new(); + } + + return (int) $result; + } + + /** + * Returns the current execution mode. + * + * @internal + * + * @return int + */ + public function getExecuteMode() + { + return $this->executeMode; + } + + /** + * {@inheritdoc} + */ + public function beginTransaction() + { + $this->executeMode = OCI_NO_AUTO_COMMIT; + + return true; + } + + /** + * {@inheritdoc} + */ + public function commit() + { + if (! oci_commit($this->dbh)) { + throw OCI8Exception::fromErrorInfo($this->errorInfo()); + } + + $this->executeMode = OCI_COMMIT_ON_SUCCESS; + + return true; + } + + /** + * {@inheritdoc} + */ + public function rollBack() + { + if (! oci_rollback($this->dbh)) { + throw OCI8Exception::fromErrorInfo($this->errorInfo()); + } + + $this->executeMode = OCI_COMMIT_ON_SUCCESS; + + return true; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorCode() + { + $error = oci_error($this->dbh); + + if ($error !== false) { + return $error['code']; + } + + return null; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + $error = oci_error($this->dbh); + + if ($error === false) { + return []; + } + + return $error; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php new file mode 100755 index 0000000..64de019 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php @@ -0,0 +1,27 @@ + OCI_BOTH, + FetchMode::ASSOCIATIVE => OCI_ASSOC, + FetchMode::NUMERIC => OCI_NUM, + FetchMode::COLUMN => OCI_NUM, + ]; + + /** @var int */ + protected $_defaultFetchMode = FetchMode::MIXED; + + /** @var string[] */ + protected $_paramMap = []; + + /** + * Holds references to bound parameter values. + * + * This is a new requirement for PHP7's oci8 extension that prevents bound values from being garbage collected. + * + * @var mixed[] + */ + private $boundValues = []; + + /** + * Indicates whether the statement is in the state when fetching results is possible + * + * @var bool + */ + private $result = false; + + /** + * Creates a new OCI8Statement that uses the given connection handle and SQL statement. + * + * @internal The statement can be only instantiated by its driver connection. + * + * @param resource $dbh The connection handle. + * @param string $query The SQL query. + */ + public function __construct($dbh, $query, OCI8Connection $conn) + { + [$query, $paramMap] = self::convertPositionalToNamedPlaceholders($query); + + $stmt = oci_parse($dbh, $query); + assert(is_resource($stmt)); + + $this->_sth = $stmt; + $this->_dbh = $dbh; + $this->_paramMap = $paramMap; + $this->_conn = $conn; + } + + /** + * Converts positional (?) into named placeholders (:param). + * + * Oracle does not support positional parameters, hence this method converts all + * positional parameters into artificially named parameters. Note that this conversion + * is not perfect. All question marks (?) in the original statement are treated as + * placeholders and converted to a named parameter. + * + * The algorithm uses a state machine with two possible states: InLiteral and NotInLiteral. + * Question marks inside literal strings are therefore handled correctly by this method. + * This comes at a cost, the whole sql statement has to be looped over. + * + * @internal + * + * @param string $statement The SQL statement to convert. + * + * @return mixed[] [0] => the statement value (string), [1] => the paramMap value (array). + * + * @throws OCI8Exception + * + * @todo extract into utility class in Doctrine\DBAL\Util namespace + * @todo review and test for lost spaces. we experienced missing spaces with oci8 in some sql statements. + */ + public static function convertPositionalToNamedPlaceholders($statement) + { + $fragmentOffset = $tokenOffset = 0; + $fragments = $paramMap = []; + $currentLiteralDelimiter = null; + + do { + if (! $currentLiteralDelimiter) { + $result = self::findPlaceholderOrOpeningQuote( + $statement, + $tokenOffset, + $fragmentOffset, + $fragments, + $currentLiteralDelimiter, + $paramMap + ); + } else { + $result = self::findClosingQuote($statement, $tokenOffset, $currentLiteralDelimiter); + } + } while ($result); + + if ($currentLiteralDelimiter !== null) { + throw NonTerminatedStringLiteral::new($tokenOffset - 1); + } + + $fragments[] = substr($statement, $fragmentOffset); + $statement = implode('', $fragments); + + return [$statement, $paramMap]; + } + + /** + * Finds next placeholder or opening quote. + * + * @param string $statement The SQL statement to parse + * @param int $tokenOffset The offset to start searching from + * @param int $fragmentOffset The offset to build the next fragment from + * @param string[] $fragments Fragments of the original statement + * not containing placeholders + * @param string|null $currentLiteralDelimiter The delimiter of the current string literal + * or NULL if not currently in a literal + * @param array $paramMap Mapping of the original parameter positions + * to their named replacements + * + * @return bool Whether the token was found + */ + private static function findPlaceholderOrOpeningQuote( + $statement, + &$tokenOffset, + &$fragmentOffset, + &$fragments, + &$currentLiteralDelimiter, + &$paramMap + ) { + $token = self::findToken($statement, $tokenOffset, '/[?\'"]/'); + + if (! $token) { + return false; + } + + if ($token === '?') { + $position = count($paramMap) + 1; + $param = ':param' . $position; + $fragments[] = substr($statement, $fragmentOffset, $tokenOffset - $fragmentOffset); + $fragments[] = $param; + $paramMap[$position] = $param; + $tokenOffset += 1; + $fragmentOffset = $tokenOffset; + + return true; + } + + $currentLiteralDelimiter = $token; + ++$tokenOffset; + + return true; + } + + /** + * Finds closing quote + * + * @param string $statement The SQL statement to parse + * @param int $tokenOffset The offset to start searching from + * @param string $currentLiteralDelimiter The delimiter of the current string literal + * + * @return bool Whether the token was found + * + * @param-out string|null $currentLiteralDelimiter + */ + private static function findClosingQuote( + $statement, + &$tokenOffset, + &$currentLiteralDelimiter + ) { + $token = self::findToken( + $statement, + $tokenOffset, + '/' . preg_quote($currentLiteralDelimiter, '/') . '/' + ); + + if (! $token) { + return false; + } + + $currentLiteralDelimiter = null; + ++$tokenOffset; + + return true; + } + + /** + * Finds the token described by regex starting from the given offset. Updates the offset with the position + * where the token was found. + * + * @param string $statement The SQL statement to parse + * @param int $offset The offset to start searching from + * @param string $regex The regex containing token pattern + * + * @return string|null Token or NULL if not found + */ + private static function findToken($statement, &$offset, $regex) + { + if (preg_match($regex, $statement, $matches, PREG_OFFSET_CAPTURE, $offset)) { + $offset = $matches[0][1]; + + return $matches[0][0]; + } + + return null; + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, $type = ParameterType::STRING) + { + return $this->bindParam($param, $value, $type, null); + } + + /** + * {@inheritdoc} + */ + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) + { + if (is_int($param)) { + if (! isset($this->_paramMap[$param])) { + throw UnknownParameterIndex::new($param); + } + + $param = $this->_paramMap[$param]; + } + + if ($type === ParameterType::LARGE_OBJECT) { + $lob = oci_new_descriptor($this->_dbh, OCI_D_LOB); + $lob->writeTemporary($variable, OCI_TEMP_BLOB); + + $variable =& $lob; + } + + $this->boundValues[$param] =& $variable; + + return oci_bind_by_name( + $this->_sth, + $param, + $variable, + $length ?? -1, + $this->convertParameterType($type) + ); + } + + /** + * Converts DBAL parameter type to oci8 parameter type + */ + private function convertParameterType(int $type): int + { + switch ($type) { + case ParameterType::BINARY: + return OCI_B_BIN; + + case ParameterType::LARGE_OBJECT: + return OCI_B_BLOB; + + default: + return SQLT_CHR; + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use free() instead. + */ + public function closeCursor() + { + $this->free(); + + return true; + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + return oci_num_fields($this->_sth) ?: 0; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorCode() + { + $error = oci_error($this->_sth); + if ($error !== false) { + $error = $error['code']; + } + + return $error; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + $error = oci_error($this->_sth); + + if ($error === false) { + return []; + } + + return $error; + } + + /** + * {@inheritdoc} + */ + public function execute($params = null) + { + if ($params) { + $hasZeroIndex = array_key_exists(0, $params); + + foreach ($params as $key => $val) { + if ($hasZeroIndex && is_int($key)) { + $this->bindValue($key + 1, $val); + } else { + $this->bindValue($key, $val); + } + } + } + + $ret = @oci_execute($this->_sth, $this->_conn->getExecuteMode()); + if (! $ret) { + throw OCI8Exception::fromErrorInfo($this->errorInfo()); + } + + $this->result = true; + + return $ret; + } + + /** + * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->_defaultFetchMode = $fetchMode; + + return true; + } + + /** + * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. + */ + #[ReturnTypeWillChange] + public function getIterator() + { + return new StatementIterator($this); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + */ + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + // do not try fetching from the statement if it's not expected to contain result + // in order to prevent exceptional situation + if (! $this->result) { + return false; + } + + $fetchMode = $fetchMode ?: $this->_defaultFetchMode; + + if ($fetchMode === FetchMode::COLUMN) { + return $this->fetchColumn(); + } + + if ($fetchMode === FetchMode::STANDARD_OBJECT) { + return oci_fetch_object($this->_sth); + } + + if (! isset(self::$fetchModeMap[$fetchMode])) { + throw new InvalidArgumentException('Invalid fetch style: ' . $fetchMode); + } + + return oci_fetch_array( + $this->_sth, + self::$fetchModeMap[$fetchMode] | OCI_RETURN_NULLS | OCI_RETURN_LOBS + ); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + $fetchMode = $fetchMode ?: $this->_defaultFetchMode; + + $result = []; + + if ($fetchMode === FetchMode::STANDARD_OBJECT) { + while ($row = $this->fetch($fetchMode)) { + $result[] = $row; + } + + return $result; + } + + if (! isset(self::$fetchModeMap[$fetchMode])) { + throw new InvalidArgumentException('Invalid fetch style: ' . $fetchMode); + } + + if (self::$fetchModeMap[$fetchMode] === OCI_BOTH) { + while ($row = $this->fetch($fetchMode)) { + $result[] = $row; + } + } else { + $fetchStructure = OCI_FETCHSTATEMENT_BY_ROW; + + if ($fetchMode === FetchMode::COLUMN) { + $fetchStructure = OCI_FETCHSTATEMENT_BY_COLUMN; + } + + // do not try fetching from the statement if it's not expected to contain result + // in order to prevent exceptional situation + if (! $this->result) { + return []; + } + + oci_fetch_all( + $this->_sth, + $result, + 0, + -1, + self::$fetchModeMap[$fetchMode] | OCI_RETURN_NULLS | $fetchStructure | OCI_RETURN_LOBS + ); + + if ($fetchMode === FetchMode::COLUMN) { + $result = $result[0]; + } + } + + return $result; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. + */ + public function fetchColumn($columnIndex = 0) + { + // do not try fetching from the statement if it's not expected to contain result + // in order to prevent exceptional situation + if (! $this->result) { + return false; + } + + $row = oci_fetch_array($this->_sth, OCI_NUM | OCI_RETURN_NULLS | OCI_RETURN_LOBS); + + if ($row === false) { + return false; + } + + return $row[$columnIndex] ?? null; + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + return oci_num_rows($this->_sth) ?: 0; + } + + /** + * {@inheritdoc} + */ + public function fetchNumeric() + { + return $this->doFetch(OCI_NUM); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + return $this->doFetch(OCI_ASSOC); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric(): array + { + return $this->doFetchAll(OCI_NUM, OCI_FETCHSTATEMENT_BY_ROW); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative(): array + { + return $this->doFetchAll(OCI_ASSOC, OCI_FETCHSTATEMENT_BY_ROW); + } + + /** + * {@inheritdoc} + */ + public function fetchFirstColumn(): array + { + return $this->doFetchAll(OCI_NUM, OCI_FETCHSTATEMENT_BY_COLUMN)[0]; + } + + public function free(): void + { + // not having the result means there's nothing to close + if (! $this->result) { + return; + } + + oci_cancel($this->_sth); + + $this->result = false; + } + + /** + * @return mixed|false + */ + private function doFetch(int $mode) + { + // do not try fetching from the statement if it's not expected to contain the result + // in order to prevent exceptional situation + if (! $this->result) { + return false; + } + + return oci_fetch_array( + $this->_sth, + $mode | OCI_RETURN_NULLS | OCI_RETURN_LOBS + ); + } + + /** + * @return array + */ + private function doFetchAll(int $mode, int $fetchStructure): array + { + // do not try fetching from the statement if it's not expected to contain the result + // in order to prevent exceptional situation + if (! $this->result) { + return []; + } + + oci_fetch_all( + $this->_sth, + $result, + 0, + -1, + $mode | OCI_RETURN_NULLS | $fetchStructure | OCI_RETURN_LOBS + ); + + return $result; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/Statement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/Statement.php new file mode 100755 index 0000000..2cab1e5 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/Statement.php @@ -0,0 +1,7 @@ +setAttribute(PDO::ATTR_STATEMENT_CLASS, [Statement::class, []]); + $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * {@inheritdoc} + */ + #[ReturnTypeWillChange] + public function exec($sql) + { + try { + $result = parent::exec($sql); + assert($result !== false); + + return $result; + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * {@inheritdoc} + */ + public function getServerVersion() + { + return PDO::getAttribute(PDO::ATTR_SERVER_VERSION); + } + + /** + * @param string $sql + * @param array $driverOptions + * + * @return PDOStatement + */ + #[ReturnTypeWillChange] + public function prepare($sql, $driverOptions = []) + { + try { + $statement = parent::prepare($sql, $driverOptions); + assert($statement instanceof PDOStatement); + + return $statement; + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * {@inheritdoc} + */ + #[ReturnTypeWillChange] + public function quote($value, $type = ParameterType::STRING) + { + return parent::quote($value, $type); + } + + /** + * {@inheritdoc} + * + * @param string|null $name + * + * @return string|int|false + */ + #[ReturnTypeWillChange] + public function lastInsertId($name = null) + { + try { + if ($name === null) { + return parent::lastInsertId(); + } + + return parent::lastInsertId($name); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * {@inheritdoc} + */ + public function requiresQueryForServerVersion() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4114', + 'ServerInfoAwareConnection::requiresQueryForServerVersion() is deprecated and removed in DBAL 3.' + ); + + return false; + } + + /** + * @param mixed ...$args + */ + private function doQuery(...$args): PDOStatement + { + try { + $stmt = parent::query(...$args); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + + assert($stmt instanceof PDOStatement); + + return $stmt; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOException.php new file mode 100755 index 0000000..8c0d05d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOException.php @@ -0,0 +1,64 @@ +getMessage(), 0, $exception); + + $this->code = $exception->getCode(); + $this->errorInfo = $exception->errorInfo; + $this->errorCode = $exception->errorInfo[1] ?? $exception->getCode(); + $this->sqlState = $exception->errorInfo[0] ?? $exception->getCode(); + } + + /** + * {@inheritdoc} + */ + public function getErrorCode() + { + /** @psalm-suppress ImpureMethodCall */ + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4112', + 'Driver\AbstractException::getErrorCode() is deprecated, use getSQLState() or getCode() instead.' + ); + + return $this->errorCode; + } + + /** + * {@inheritdoc} + */ + public function getSQLState() + { + return $this->sqlState; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php new file mode 100755 index 0000000..875310e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php @@ -0,0 +1,70 @@ +_constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + } + + /** + * Constructs the IBM PDO DSN. + * + * @param mixed[] $params + * + * @return string The DSN. + */ + private function _constructPdoDsn(array $params) + { + $dsn = 'ibm:'; + if (isset($params['host'])) { + $dsn .= 'HOSTNAME=' . $params['host'] . ';'; + } + + if (isset($params['port'])) { + $dsn .= 'PORT=' . $params['port'] . ';'; + } + + $dsn .= 'PROTOCOL=TCPIP;'; + if (isset($params['dbname'])) { + $dsn .= 'DATABASE=' . $params['dbname'] . ';'; + } + + return $dsn; + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Driver::getName() is deprecated' + ); + + return 'pdo_ibm'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php new file mode 100755 index 0000000..70d5677 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php @@ -0,0 +1,85 @@ +constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + } catch (PDOException $e) { + throw Exception::driverException($this, $e); + } + + return $conn; + } + + /** + * Constructs the MySql PDO DSN. + * + * @param mixed[] $params + * + * @return string The DSN. + */ + protected function constructPdoDsn(array $params) + { + $dsn = 'mysql:'; + if (isset($params['host']) && $params['host'] !== '') { + $dsn .= 'host=' . $params['host'] . ';'; + } + + if (isset($params['port'])) { + $dsn .= 'port=' . $params['port'] . ';'; + } + + if (isset($params['dbname'])) { + $dsn .= 'dbname=' . $params['dbname'] . ';'; + } + + if (isset($params['unix_socket'])) { + $dsn .= 'unix_socket=' . $params['unix_socket'] . ';'; + } + + if (isset($params['charset'])) { + $dsn .= 'charset=' . $params['charset'] . ';'; + } + + return $dsn; + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Driver::getName() is deprecated' + ); + + return 'pdo_mysql'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php new file mode 100755 index 0000000..a84c67f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php @@ -0,0 +1,66 @@ +constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + } catch (PDOException $e) { + throw Exception::driverException($this, $e); + } + } + + /** + * Constructs the Oracle PDO DSN. + * + * @param mixed[] $params + * + * @return string The DSN. + */ + private function constructPdoDsn(array $params) + { + $dsn = 'oci:dbname=' . $this->getEasyConnectString($params); + + if (isset($params['charset'])) { + $dsn .= ';charset=' . $params['charset']; + } + + return $dsn; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Driver::getName() is deprecated' + ); + + return 'pdo_oracle'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php new file mode 100755 index 0000000..bbdf23f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php @@ -0,0 +1,128 @@ +_constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + + if ( + defined('PDO::PGSQL_ATTR_DISABLE_PREPARES') + && (! isset($driverOptions[\PDO::PGSQL_ATTR_DISABLE_PREPARES]) + || $driverOptions[\PDO::PGSQL_ATTR_DISABLE_PREPARES] === true + ) + ) { + $pdo->setAttribute(\PDO::PGSQL_ATTR_DISABLE_PREPARES, true); + } + + /* defining client_encoding via SET NAMES to avoid inconsistent DSN support + * - the 'client_encoding' connection param only works with postgres >= 9.1 + * - passing client_encoding via the 'options' param breaks pgbouncer support + */ + if (isset($params['charset'])) { + $pdo->exec('SET NAMES \'' . $params['charset'] . '\''); + } + + return $pdo; + } catch (PDOException $e) { + throw Exception::driverException($this, $e); + } + } + + /** + * Constructs the Postgres PDO DSN. + * + * @param mixed[] $params + * + * @return string The DSN. + */ + private function _constructPdoDsn(array $params) + { + $dsn = 'pgsql:'; + + if (isset($params['host']) && $params['host'] !== '') { + $dsn .= 'host=' . $params['host'] . ';'; + } + + if (isset($params['port']) && $params['port'] !== '') { + $dsn .= 'port=' . $params['port'] . ';'; + } + + if (isset($params['dbname'])) { + $dsn .= 'dbname=' . $params['dbname'] . ';'; + } elseif (isset($params['default_dbname'])) { + $dsn .= 'dbname=' . $params['default_dbname'] . ';'; + } else { + // Used for temporary connections to allow operations like dropping the database currently connected to. + // Connecting without an explicit database does not work, therefore "postgres" database is used + // as it is mostly present in every server setup. + $dsn .= 'dbname=postgres;'; + } + + if (isset($params['sslmode'])) { + $dsn .= 'sslmode=' . $params['sslmode'] . ';'; + } + + if (isset($params['sslrootcert'])) { + $dsn .= 'sslrootcert=' . $params['sslrootcert'] . ';'; + } + + if (isset($params['sslcert'])) { + $dsn .= 'sslcert=' . $params['sslcert'] . ';'; + } + + if (isset($params['sslkey'])) { + $dsn .= 'sslkey=' . $params['sslkey'] . ';'; + } + + if (isset($params['sslcrl'])) { + $dsn .= 'sslcrl=' . $params['sslcrl'] . ';'; + } + + if (isset($params['application_name'])) { + $dsn .= 'application_name=' . $params['application_name'] . ';'; + } + + return $dsn; + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Driver::getName() is deprecated' + ); + + return 'pdo_pgsql'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php new file mode 100755 index 0000000..68003d1 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php @@ -0,0 +1,41 @@ += 80000) { + /** + * @internal + */ + trait PDOQueryImplementation + { + /** + * @return PDOStatement + */ + #[ReturnTypeWillChange] + public function query(?string $query = null, ?int $fetchMode = null, mixed ...$fetchModeArgs) + { + return $this->doQuery($query, $fetchMode, ...$fetchModeArgs); + } + } +} else { + /** + * @internal + */ + trait PDOQueryImplementation + { + /** + * @return PDOStatement + */ + public function query() + { + return $this->doQuery(...func_get_args()); + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php new file mode 100755 index 0000000..efced0c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php @@ -0,0 +1,93 @@ + ['callback' => [SqlitePlatform::class, 'udfSqrt'], 'numArgs' => 1], + 'mod' => ['callback' => [SqlitePlatform::class, 'udfMod'], 'numArgs' => 2], + 'locate' => ['callback' => [SqlitePlatform::class, 'udfLocate'], 'numArgs' => -1], + ]; + + /** + * {@inheritdoc} + */ + public function connect(array $params, $username = null, $password = null, array $driverOptions = []) + { + if (isset($driverOptions['userDefinedFunctions'])) { + $this->_userDefinedFunctions = array_merge( + $this->_userDefinedFunctions, + $driverOptions['userDefinedFunctions'] + ); + unset($driverOptions['userDefinedFunctions']); + } + + try { + $pdo = new PDO\Connection( + $this->_constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + } catch (PDOException $ex) { + throw Exception::driverException($this, $ex); + } + + foreach ($this->_userDefinedFunctions as $fn => $data) { + $pdo->sqliteCreateFunction($fn, $data['callback'], $data['numArgs']); + } + + return $pdo; + } + + /** + * Constructs the Sqlite PDO DSN. + * + * @param mixed[] $params + * + * @return string The DSN. + */ + protected function _constructPdoDsn(array $params) + { + $dsn = 'sqlite:'; + if (isset($params['path'])) { + $dsn .= $params['path']; + } elseif (isset($params['memory'])) { + $dsn .= ':memory:'; + } + + return $dsn; + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Driver::getName() is deprecated' + ); + + return 'pdo_sqlite'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php new file mode 100755 index 0000000..efc483c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php @@ -0,0 +1,49 @@ +setAttribute(\PDO::ATTR_STATEMENT_CLASS, [PDO\SQLSrv\Statement::class, []]); + } + + /** + * {@inheritDoc} + */ + public function lastInsertId($name = null) + { + if ($name === null) { + return parent::lastInsertId($name); + } + + $stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?'); + $stmt->execute([$name]); + + if ($stmt instanceof Result) { + return $stmt->fetchOne(); + } + + return $stmt->fetchColumn(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php new file mode 100755 index 0000000..8784582 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php @@ -0,0 +1,107 @@ + $value) { + if (is_int($option)) { + $pdoOptions[$option] = $value; + } else { + $dsnOptions[$option] = $value; + } + } + + return new PDO\SQLSrv\Connection( + $this->_constructPdoDsn($params, $dsnOptions), + $username, + $password, + $pdoOptions + ); + } + + /** + * Constructs the Sqlsrv PDO DSN. + * + * @param mixed[] $params + * @param string[] $connectionOptions + * + * @return string The DSN. + */ + private function _constructPdoDsn(array $params, array $connectionOptions) + { + $dsn = 'sqlsrv:server='; + + if (isset($params['host'])) { + $dsn .= $params['host']; + + if (isset($params['port'])) { + $dsn .= ',' . $params['port']; + } + } elseif (isset($params['port'])) { + throw PortWithoutHost::new(); + } + + if (isset($params['dbname'])) { + $connectionOptions['Database'] = $params['dbname']; + } + + if (isset($params['MultipleActiveResultSets'])) { + $connectionOptions['MultipleActiveResultSets'] = $params['MultipleActiveResultSets'] ? 'true' : 'false'; + } + + return $dsn . $this->getConnectionOptionsDsn($connectionOptions); + } + + /** + * Converts a connection options array to the DSN + * + * @param string[] $connectionOptions + */ + private function getConnectionOptionsDsn(array $connectionOptions): string + { + $connectionOptionsDsn = ''; + + foreach ($connectionOptions as $paramName => $paramValue) { + $connectionOptionsDsn .= sprintf(';%s=%s', $paramName, $paramValue); + } + + return $connectionOptionsDsn; + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Driver::getName() is deprecated' + ); + + return 'pdo_sqlsrv'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php new file mode 100755 index 0000000..6f5871e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php @@ -0,0 +1,46 @@ +bindParam($param, $value, $type); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php new file mode 100755 index 0000000..84f6b81 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -0,0 +1,316 @@ + PDO::PARAM_NULL, + ParameterType::INTEGER => PDO::PARAM_INT, + ParameterType::STRING => PDO::PARAM_STR, + ParameterType::ASCII => PDO::PARAM_STR, + ParameterType::BINARY => PDO::PARAM_LOB, + ParameterType::LARGE_OBJECT => PDO::PARAM_LOB, + ParameterType::BOOLEAN => PDO::PARAM_BOOL, + ]; + + private const FETCH_MODE_MAP = [ + FetchMode::ASSOCIATIVE => PDO::FETCH_ASSOC, + FetchMode::NUMERIC => PDO::FETCH_NUM, + FetchMode::MIXED => PDO::FETCH_BOTH, + FetchMode::STANDARD_OBJECT => PDO::FETCH_OBJ, + FetchMode::COLUMN => PDO::FETCH_COLUMN, + FetchMode::CUSTOM_OBJECT => PDO::FETCH_CLASS, + ]; + + /** + * Protected constructor. + * + * @internal The statement can be only instantiated by its driver connection. + */ + protected function __construct() + { + } + + /** + * {@inheritdoc} + */ + #[ReturnTypeWillChange] + public function bindValue($param, $value, $type = ParameterType::STRING) + { + $type = $this->convertParamType($type); + + try { + return parent::bindValue($param, $value, $type); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * @param mixed $param + * @param mixed $variable + * @param int $type + * @param int|null $length + * @param mixed $driverOptions + * + * @return bool + */ + #[ReturnTypeWillChange] + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null, $driverOptions = null) + { + $type = $this->convertParamType($type); + + try { + return parent::bindParam($param, $variable, $type, ...array_slice(func_get_args(), 3)); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use free() instead. + */ + #[ReturnTypeWillChange] + public function closeCursor() + { + try { + return parent::closeCursor(); + } catch (PDOException $exception) { + // Exceptions not allowed by the interface. + // In case driver implementations do not adhere to the interface, silence exceptions here. + return true; + } + } + + /** + * {@inheritdoc} + */ + #[ReturnTypeWillChange] + public function execute($params = null) + { + try { + return parent::execute($params); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + */ + #[ReturnTypeWillChange] + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + $args = func_get_args(); + + if (isset($args[0])) { + $args[0] = $this->convertFetchMode($args[0]); + } + + try { + return parent::fetch(...$args); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. + */ + #[ReturnTypeWillChange] + public function fetchColumn($columnIndex = 0) + { + try { + return parent::fetchColumn($columnIndex); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * {@inheritdoc} + */ + public function fetchNumeric() + { + return $this->fetch(PDO::FETCH_NUM); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + return $this->fetch(PDO::FETCH_ASSOC); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + return $this->fetch(PDO::FETCH_COLUMN); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric(): array + { + return $this->fetchAll(PDO::FETCH_NUM); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative(): array + { + return $this->fetchAll(PDO::FETCH_ASSOC); + } + + /** + * {@inheritdoc} + */ + public function fetchFirstColumn(): array + { + return $this->fetchAll(PDO::FETCH_COLUMN); + } + + public function free(): void + { + parent::closeCursor(); + } + + /** + * @param mixed ...$args + */ + private function doSetFetchMode(int $fetchMode, ...$args): bool + { + $fetchMode = $this->convertFetchMode($fetchMode); + + // This thin wrapper is necessary to shield against the weird signature + // of PDOStatement::setFetchMode(): even if the second and third + // parameters are optional, PHP will not let us remove it from this + // declaration. + $slice = []; + + foreach ($args as $arg) { + if ($arg === null) { + break; + } + + $slice[] = $arg; + } + + try { + return parent::setFetchMode($fetchMode, ...$slice); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + } + + /** + * @param mixed ...$args + * + * @return mixed[] + */ + private function doFetchAll(...$args): array + { + if (isset($args[0])) { + $args[0] = $this->convertFetchMode($args[0]); + } + + $slice = []; + + foreach ($args as $arg) { + if ($arg === null) { + break; + } + + $slice[] = $arg; + } + + try { + $data = parent::fetchAll(...$slice); + } catch (PDOException $exception) { + throw Exception::new($exception); + } + + assert(is_array($data)); + + return $data; + } + + /** + * Converts DBAL parameter type to PDO parameter type + * + * @param int $type Parameter type + */ + private function convertParamType(int $type): int + { + if (! isset(self::PARAM_TYPE_MAP[$type])) { + // TODO: next major: throw an exception + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3088', + 'Using a PDO parameter type (%d given) is deprecated, ' . + 'use \Doctrine\DBAL\Types\Types constants instead.', + $type + ); + + return $type; + } + + return self::PARAM_TYPE_MAP[$type]; + } + + /** + * Converts DBAL fetch mode to PDO fetch mode + * + * @param int $fetchMode Fetch mode + */ + private function convertFetchMode(int $fetchMode): int + { + if (! isset(self::FETCH_MODE_MAP[$fetchMode])) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3088', + 'Using an unsupported PDO fetch mode or a bitmask of fetch modes (%d given)' . + ' is deprecated and will cause an error in Doctrine DBAL 3.0', + $fetchMode + ); + + return $fetchMode; + } + + return self::FETCH_MODE_MAP[$fetchMode]; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatementImplementations.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatementImplementations.php new file mode 100755 index 0000000..a1f9ae6 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatementImplementations.php @@ -0,0 +1,77 @@ += 80000) { + /** + * @internal + */ + trait PDOStatementImplementations + { + /** + * @deprecated Use one of the fetch- or iterate-related methods. + * + * @param int $mode + * @param mixed ...$args + * + * @return bool + */ + #[ReturnTypeWillChange] + public function setFetchMode($mode, ...$args) + { + return $this->doSetFetchMode($mode, ...$args); + } + + /** + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + * + * @param int|null $mode + * @param mixed ...$args + * + * @return mixed[] + */ + #[ReturnTypeWillChange] + public function fetchAll($mode = null, ...$args) + { + return $this->doFetchAll($mode, ...$args); + } + } +} else { + /** + * @internal + */ + trait PDOStatementImplementations + { + /** + * @deprecated Use one of the fetch- or iterate-related methods. + * + * @param int $fetchMode + * @param mixed $arg2 + * @param mixed $arg3 + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null): bool + { + return $this->doSetFetchMode(...func_get_args()); + } + + /** + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + * + * @param int|null $fetchMode + * @param mixed $fetchArgument + * @param mixed $ctorArgs + * + * @return mixed[] + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + return $this->doFetchAll(...func_get_args()); + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PingableConnection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PingableConnection.php new file mode 100755 index 0000000..42202e7 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PingableConnection.php @@ -0,0 +1,19 @@ +|false + * + * @throws Exception + */ + public function fetchNumeric(); + + /** + * Returns the next row of the result as an associative array or FALSE if there are no more rows. + * + * @return array|false + * + * @throws Exception + */ + public function fetchAssociative(); + + /** + * Returns the first value of the next row of the result or FALSE if there are no more rows. + * + * @return mixed|false + * + * @throws Exception + */ + public function fetchOne(); + + /** + * Returns an array containing all of the result rows represented as numeric arrays. + * + * @return array> + * + * @throws Exception + */ + public function fetchAllNumeric(): array; + + /** + * Returns an array containing all of the result rows represented as associative arrays. + * + * @return array> + * + * @throws Exception + */ + public function fetchAllAssociative(): array; + + /** + * Returns an array containing the values of the first column of the result. + * + * @return array + * + * @throws Exception + */ + public function fetchFirstColumn(): array; + + /** + * Returns the number of rows affected by the DELETE, INSERT, or UPDATE statement that produced the result. + * + * If the statement executed a SELECT query or a similar platform-specific SQL (e.g. DESCRIBE, SHOW, etc.), + * some database drivers may return the number of rows returned by that query. However, this behaviour + * is not guaranteed for all drivers and should not be relied on in portable applications. + * + * @return int The number of rows. + */ + public function rowCount(); + + /** + * Returns the number of columns in the result + * + * @return int The number of columns in the result. If the columns cannot be counted, + * this method must return 0. + */ + public function columnCount(); + + /** + * Discards the non-fetched portion of the result, enabling the originating statement to be executed again. + */ + public function free(): void; +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/ResultStatement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/ResultStatement.php new file mode 100755 index 0000000..5373ee3 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/ResultStatement.php @@ -0,0 +1,110 @@ +buildDsn( + $params['host'] ?? null, + $params['port'] ?? null, + $params['server'] ?? null, + $params['dbname'] ?? null, + $username, + $password, + $driverOptions + ), + $params['persistent'] ?? false + ); + } catch (SQLAnywhereException $e) { + throw Exception::driverException($this, $e); + } + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + public function getName() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Driver::getName() is deprecated' + ); + + return 'sqlanywhere'; + } + + /** + * Build the connection string for given connection parameters and driver options. + * + * @param string|null $host Host address to connect to. + * @param int|null $port Port to use for the connection (default to SQL Anywhere standard port 2638). + * @param string|null $server Database server name on the host to connect to. + * SQL Anywhere allows multiple database server instances on the same host, + * therefore specifying the server instance name to use is mandatory. + * @param string|null $dbname Name of the database on the server instance to connect to. + * @param string $username User name to use for connection authentication. + * @param string $password Password to use for connection authentication. + * @param mixed[] $driverOptions Additional parameters to use for the connection. + * + * @return string + */ + private function buildDsn( + $host, + $port, + $server, + $dbname, + $username = null, + $password = null, + array $driverOptions = [] + ) { + $host = $host ?: 'localhost'; + $port = $port ?: 2638; + + if (! empty($server)) { + $server = ';ServerName=' . $server; + } + + return 'HOST=' . $host . ':' . $port . + $server . + ';DBN=' . $dbname . + ';UID=' . $username . + ';PWD=' . $password . + ';' . implode( + ';', + array_map(static function ($key, $value) { + return $key . '=' . $value; + }, array_keys($driverOptions), $driverOptions) + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php new file mode 100755 index 0000000..3c98026 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php @@ -0,0 +1,250 @@ +connection = $persistent ? @sasql_pconnect($dsn) : @sasql_connect($dsn); + + if (! is_resource($this->connection)) { + throw SQLAnywhereException::fromSQLAnywhereError(); + } + + // Disable PHP warnings on error. + if (! sasql_set_option($this->connection, 'verbose_errors', false)) { + throw SQLAnywhereException::fromSQLAnywhereError($this->connection); + } + + // Enable auto committing by default. + if (! sasql_set_option($this->connection, 'auto_commit', 'on')) { + throw SQLAnywhereException::fromSQLAnywhereError($this->connection); + } + } + + /** + * {@inheritdoc} + * + * @throws SQLAnywhereException + */ + public function beginTransaction() + { + if (! sasql_set_option($this->connection, 'auto_commit', 'off')) { + throw SQLAnywhereException::fromSQLAnywhereError($this->connection); + } + + return true; + } + + /** + * {@inheritdoc} + * + * @throws SQLAnywhereException + */ + public function commit() + { + if (! sasql_commit($this->connection)) { + throw SQLAnywhereException::fromSQLAnywhereError($this->connection); + } + + $this->endTransaction(); + + return true; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorCode() + { + return sasql_errorcode($this->connection); + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + return sasql_error($this->connection); + } + + /** + * {@inheritdoc} + */ + public function exec($sql) + { + if (sasql_real_query($this->connection, $sql) === false) { + throw SQLAnywhereException::fromSQLAnywhereError($this->connection); + } + + return sasql_affected_rows($this->connection); + } + + /** + * {@inheritdoc} + */ + public function getServerVersion() + { + $stmt = $this->query("SELECT PROPERTY('ProductVersion')"); + + if ($stmt instanceof Result) { + $version = $stmt->fetchOne(); + } else { + $version = $stmt->fetchColumn(); + } + + assert(is_string($version)); + + return $version; + } + + /** + * {@inheritdoc} + */ + public function lastInsertId($name = null) + { + if ($name === null) { + return sasql_insert_id($this->connection); + } + + $stmt = $this->query('SELECT ' . $name . '.CURRVAL'); + + if ($stmt instanceof Result) { + return $stmt->fetchOne(); + } + + return $stmt->fetchColumn(); + } + + /** + * {@inheritdoc} + */ + public function prepare($sql) + { + return new SQLAnywhereStatement($this->connection, $sql); + } + + /** + * {@inheritdoc} + */ + public function query() + { + $args = func_get_args(); + $stmt = $this->prepare($args[0]); + + $stmt->execute(); + + return $stmt; + } + + /** + * {@inheritdoc} + */ + public function quote($value, $type = ParameterType::STRING) + { + if (is_int($value) || is_float($value)) { + return $value; + } + + return "'" . sasql_escape_string($this->connection, $value) . "'"; + } + + /** + * {@inheritdoc} + */ + public function requiresQueryForServerVersion() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4114', + 'ServerInfoAwareConnection::requiresQueryForServerVersion() is deprecated and removed in DBAL 3.' + ); + + return true; + } + + /** + * {@inheritdoc} + * + * @throws SQLAnywhereException + */ + public function rollBack() + { + if (! sasql_rollback($this->connection)) { + throw SQLAnywhereException::fromSQLAnywhereError($this->connection); + } + + $this->endTransaction(); + + return true; + } + + /** + * Ends transactional mode and enables auto commit again. + * + * @return bool Whether or not ending transactional mode succeeded. + * + * @throws SQLAnywhereException + */ + private function endTransaction() + { + if (! sasql_set_option($this->connection, 'auto_commit', 'on')) { + throw SQLAnywhereException::fromSQLAnywhereError($this->connection); + } + + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php new file mode 100755 index 0000000..0edfa4f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php @@ -0,0 +1,76 @@ +conn = $conn; + $this->stmt = sasql_prepare($conn, $sql); + + if (! is_resource($this->stmt)) { + throw SQLAnywhereException::fromSQLAnywhereError($conn); + } + } + + /** + * {@inheritdoc} + * + * @throws SQLAnywhereException + */ + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) + { + assert(is_int($param)); + + switch ($type) { + case ParameterType::INTEGER: + case ParameterType::BOOLEAN: + $type = 'i'; + break; + + case ParameterType::LARGE_OBJECT: + $type = 'b'; + break; + + case ParameterType::NULL: + case ParameterType::STRING: + case ParameterType::BINARY: + $type = 's'; + break; + + default: + throw new SQLAnywhereException('Unknown type: ' . $type); + } + + $this->boundValues[$param] =& $variable; + + if (! sasql_stmt_bind_param_ex($this->stmt, $param - 1, $variable, $type, $variable === null)) { + throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, $type = ParameterType::STRING) + { + assert(is_int($param)); + + return $this->bindParam($param, $value, $type); + } + + /** + * {@inheritdoc} + * + * @deprecated Use free() instead. + * + * @throws SQLAnywhereException + */ + public function closeCursor() + { + if (! sasql_stmt_reset($this->stmt)) { + throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + return sasql_stmt_field_count($this->stmt); + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorCode() + { + return sasql_stmt_errno($this->stmt); + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + return sasql_stmt_error($this->stmt); + } + + /** + * {@inheritdoc} + * + * @throws SQLAnywhereException + */ + public function execute($params = null) + { + if (is_array($params)) { + $hasZeroIndex = array_key_exists(0, $params); + + foreach ($params as $key => $val) { + if ($hasZeroIndex && is_int($key)) { + $this->bindValue($key + 1, $val); + } else { + $this->bindValue($key, $val); + } + } + } + + if (! sasql_stmt_execute($this->stmt)) { + throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt); + } + + $this->result = sasql_stmt_result_metadata($this->stmt); + + return true; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + * + * @throws SQLAnywhereException + */ + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + if (! is_resource($this->result)) { + return false; + } + + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + + switch ($fetchMode) { + case FetchMode::COLUMN: + return $this->fetchColumn(); + + case FetchMode::ASSOCIATIVE: + return sasql_fetch_assoc($this->result); + + case FetchMode::MIXED: + return sasql_fetch_array($this->result, SASQL_BOTH); + + case FetchMode::CUSTOM_OBJECT: + $className = $this->defaultFetchClass; + $ctorArgs = $this->defaultFetchClassCtorArgs; + + if (func_num_args() >= 2) { + $args = func_get_args(); + $className = $args[1]; + $ctorArgs = $args[2] ?? []; + } + + $result = sasql_fetch_object($this->result); + + if ($result instanceof stdClass) { + $result = $this->castObject($result, $className, $ctorArgs); + } + + return $result; + + case FetchMode::NUMERIC: + return sasql_fetch_row($this->result); + + case FetchMode::STANDARD_OBJECT: + return sasql_fetch_object($this->result); + + default: + throw new SQLAnywhereException('Fetch mode is not supported: ' . $fetchMode); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + $rows = []; + + switch ($fetchMode) { + case FetchMode::CUSTOM_OBJECT: + while (($row = $this->fetch(...func_get_args())) !== false) { + $rows[] = $row; + } + + break; + + case FetchMode::COLUMN: + while (($row = $this->fetchColumn()) !== false) { + $rows[] = $row; + } + + break; + + default: + while (($row = $this->fetch($fetchMode)) !== false) { + $rows[] = $row; + } + } + + return $rows; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. + */ + public function fetchColumn($columnIndex = 0) + { + $row = $this->fetch(FetchMode::NUMERIC); + + if ($row === false) { + return false; + } + + return $row[$columnIndex] ?? null; + } + + /** + * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. + */ + #[ReturnTypeWillChange] + public function getIterator() + { + return new StatementIterator($this); + } + + /** + * {@inheritDoc} + */ + public function fetchNumeric() + { + if (! is_resource($this->result)) { + return false; + } + + return sasql_fetch_row($this->result); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + if (! is_resource($this->result)) { + return false; + } + + return sasql_fetch_assoc($this->result); + } + + /** + * {@inheritdoc} + * + * @throws Exception + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * @return array> + * + * @throws Exception + */ + public function fetchAllNumeric(): array + { + return FetchUtils::fetchAllNumeric($this); + } + + /** + * @return array> + * + * @throws Exception + */ + public function fetchAllAssociative(): array + { + return FetchUtils::fetchAllAssociative($this); + } + + /** + * @return array + * + * @throws Exception + */ + public function fetchFirstColumn(): array + { + return FetchUtils::fetchFirstColumn($this); + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + return sasql_stmt_affected_rows($this->stmt); + } + + public function free(): void + { + sasql_stmt_reset($this->stmt); + } + + /** + * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->defaultFetchMode = $fetchMode; + $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; + $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; + + return true; + } + + /** + * Casts a stdClass object to the given class name mapping its' properties. + * + * @param stdClass $sourceObject Object to cast from. + * @param class-string|object $destinationClass Name of the class or class instance to cast to. + * @param mixed[] $ctorArgs Arguments to use for constructing the destination class instance. + * + * @return object + * + * @throws SQLAnywhereException + */ + private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = []) + { + if (! is_string($destinationClass)) { + if (! is_object($destinationClass)) { + throw new SQLAnywhereException(sprintf( + 'Destination class has to be of type string or object, %s given.', + gettype($destinationClass) + )); + } + } else { + $destinationClass = new ReflectionClass($destinationClass); + $destinationClass = $destinationClass->newInstanceArgs($ctorArgs); + } + + $sourceReflection = new ReflectionObject($sourceObject); + $destinationClassReflection = new ReflectionObject($destinationClass); + + foreach ($sourceReflection->getProperties() as $sourceProperty) { + $sourceProperty->setAccessible(true); + + $name = $sourceProperty->getName(); + $value = $sourceProperty->getValue($sourceObject); + + if ($destinationClassReflection->hasProperty($name)) { + $destinationProperty = $destinationClassReflection->getProperty($name); + + $destinationProperty->setAccessible(true); + $destinationProperty->setValue($destinationClass, $value); + } else { + $destinationClass->$name = $value; + } + } + + return $destinationClass; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/Connection.php new file mode 100755 index 0000000..6e009b5 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/Connection.php @@ -0,0 +1,7 @@ +id = $id; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php new file mode 100755 index 0000000..f1974ee --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php @@ -0,0 +1,226 @@ +conn = $conn; + $this->lastInsertId = new LastInsertId(); + } + + /** + * {@inheritdoc} + */ + public function getServerVersion() + { + $serverInfo = sqlsrv_server_info($this->conn); + + return $serverInfo['SQLServerVersion']; + } + + /** + * {@inheritdoc} + */ + public function requiresQueryForServerVersion() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4114', + 'ServerInfoAwareConnection::requiresQueryForServerVersion() is deprecated and removed in DBAL 3.' + ); + + return false; + } + + /** + * {@inheritDoc} + */ + public function prepare($sql) + { + return new Statement($this->conn, $sql, $this->lastInsertId); + } + + /** + * {@inheritDoc} + */ + public function query() + { + $args = func_get_args(); + $sql = $args[0]; + $stmt = $this->prepare($sql); + $stmt->execute(); + + return $stmt; + } + + /** + * {@inheritDoc} + */ + public function quote($value, $type = ParameterType::STRING) + { + if (is_int($value)) { + return $value; + } + + if (is_float($value)) { + return sprintf('%F', $value); + } + + return "'" . str_replace("'", "''", $value) . "'"; + } + + /** + * {@inheritDoc} + */ + public function exec($sql) + { + $stmt = sqlsrv_query($this->conn, $sql); + + if ($stmt === false) { + throw Error::new(); + } + + $rowsAffected = sqlsrv_rows_affected($stmt); + + if ($rowsAffected === false) { + throw Error::new(); + } + + return $rowsAffected; + } + + /** + * {@inheritDoc} + */ + public function lastInsertId($name = null) + { + if ($name !== null) { + $stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?'); + $stmt->execute([$name]); + } else { + $stmt = $this->query('SELECT @@IDENTITY'); + } + + if ($stmt instanceof Result) { + return $stmt->fetchOne(); + } + + return $stmt->fetchColumn(); + } + + /** + * {@inheritDoc} + */ + public function beginTransaction() + { + if (! sqlsrv_begin_transaction($this->conn)) { + throw Error::new(); + } + + return true; + } + + /** + * {@inheritDoc} + */ + public function commit() + { + if (! sqlsrv_commit($this->conn)) { + throw Error::new(); + } + + return true; + } + + /** + * {@inheritDoc} + */ + public function rollBack() + { + if (! sqlsrv_rollback($this->conn)) { + throw Error::new(); + } + + return true; + } + + /** + * {@inheritDoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorCode() + { + $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); + if ($errors) { + return $errors[0]['code']; + } + + return null; + } + + /** + * {@inheritDoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php new file mode 100755 index 0000000..312ef6b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php @@ -0,0 +1,24 @@ + SQLSRV_FETCH_BOTH, + FetchMode::ASSOCIATIVE => SQLSRV_FETCH_ASSOC, + FetchMode::NUMERIC => SQLSRV_FETCH_NUMERIC, + ]; + + /** + * The name of the default class to instantiate when fetching class instances. + * + * @var string + */ + private $defaultFetchClass = '\stdClass'; + + /** + * The constructor arguments for the default class to instantiate when fetching class instances. + * + * @var mixed[] + */ + private $defaultFetchClassCtorArgs = []; + + /** + * The fetch style. + * + * @var int + */ + private $defaultFetchMode = FetchMode::MIXED; + + /** + * The last insert ID. + * + * @var LastInsertId|null + */ + private $lastInsertId; + + /** + * Indicates whether the statement is in the state when fetching results is possible + * + * @var bool + */ + private $result = false; + + /** + * Append to any INSERT query to retrieve the last insert id. + * + * @deprecated This constant has been deprecated and will be made private in 3.0 + */ + public const LAST_INSERT_ID_SQL = ';SELECT SCOPE_IDENTITY() AS LastInsertId;'; + + /** + * @internal The statement can be only instantiated by its driver connection. + * + * @param resource $conn + * @param string $sql + */ + public function __construct($conn, $sql, ?LastInsertId $lastInsertId = null) + { + $this->conn = $conn; + $this->sql = $sql; + + if (stripos($sql, 'INSERT INTO ') !== 0) { + return; + } + + $this->sql .= self::LAST_INSERT_ID_SQL; + $this->lastInsertId = $lastInsertId; + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, $type = ParameterType::STRING) + { + if (! is_numeric($param)) { + throw new SQLSrvException( + 'sqlsrv does not support named parameters to queries, use question mark (?) placeholders instead.' + ); + } + + $this->variables[$param] = $value; + $this->types[$param] = $type; + + return true; + } + + /** + * {@inheritdoc} + */ + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) + { + if (! is_numeric($param)) { + throw new SQLSrvException( + 'sqlsrv does not support named parameters to queries, use question mark (?) placeholders instead.' + ); + } + + $this->variables[$param] =& $variable; + $this->types[$param] = $type; + + // unset the statement resource if it exists as the new one will need to be bound to the new variable + $this->stmt = null; + + return true; + } + + /** + * {@inheritdoc} + * + * @deprecated Use free() instead. + */ + public function closeCursor() + { + $this->free(); + + return true; + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + if ($this->stmt === null) { + return 0; + } + + return sqlsrv_num_fields($this->stmt) ?: 0; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorCode() + { + $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); + if ($errors) { + return $errors[0]['code']; + } + + return false; + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS); + } + + /** + * {@inheritdoc} + */ + public function execute($params = null) + { + if ($params) { + $hasZeroIndex = array_key_exists(0, $params); + + foreach ($params as $key => $val) { + if ($hasZeroIndex && is_int($key)) { + $this->bindValue($key + 1, $val); + } else { + $this->bindValue($key, $val); + } + } + } + + if (! $this->stmt) { + $this->stmt = $this->prepare(); + } + + if (! sqlsrv_execute($this->stmt)) { + throw Error::new(); + } + + if ($this->lastInsertId) { + sqlsrv_next_result($this->stmt); + sqlsrv_fetch($this->stmt); + $this->lastInsertId->setId(sqlsrv_get_field($this->stmt, 0)); + } + + $this->result = true; + + return true; + } + + /** + * Prepares SQL Server statement resource + * + * @return resource + * + * @throws SQLSrvException + */ + private function prepare() + { + $params = []; + + foreach ($this->variables as $column => &$variable) { + switch ($this->types[$column]) { + case ParameterType::LARGE_OBJECT: + $params[$column - 1] = [ + &$variable, + SQLSRV_PARAM_IN, + SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY), + SQLSRV_SQLTYPE_VARBINARY('max'), + ]; + break; + + case ParameterType::BINARY: + $params[$column - 1] = [ + &$variable, + SQLSRV_PARAM_IN, + SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY), + ]; + break; + + case ParameterType::ASCII: + $params[$column - 1] = [ + &$variable, + SQLSRV_PARAM_IN, + SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), + ]; + break; + + default: + $params[$column - 1] =& $variable; + break; + } + } + + $stmt = sqlsrv_prepare($this->conn, $this->sql, $params); + + if (! $stmt) { + throw Error::new(); + } + + return $stmt; + } + + /** + * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->defaultFetchMode = $fetchMode; + $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; + $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; + + return true; + } + + /** + * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. + */ + #[ReturnTypeWillChange] + public function getIterator() + { + return new StatementIterator($this); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + * + * @throws SQLSrvException + */ + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + // do not try fetching from the statement if it's not expected to contain result + // in order to prevent exceptional situation + if ($this->stmt === null || ! $this->result) { + return false; + } + + $args = func_get_args(); + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + + if ($fetchMode === FetchMode::COLUMN) { + return $this->fetchColumn(); + } + + if (isset(self::$fetchMap[$fetchMode])) { + return sqlsrv_fetch_array($this->stmt, self::$fetchMap[$fetchMode]) ?: false; + } + + if (in_array($fetchMode, [FetchMode::STANDARD_OBJECT, FetchMode::CUSTOM_OBJECT], true)) { + $className = $this->defaultFetchClass; + $ctorArgs = $this->defaultFetchClassCtorArgs; + + if (count($args) >= 2) { + $className = $args[1]; + $ctorArgs = $args[2] ?? []; + } + + return sqlsrv_fetch_object($this->stmt, $className, $ctorArgs) ?: false; + } + + throw new SQLSrvException('Fetch mode is not supported!'); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + $rows = []; + + switch ($fetchMode) { + case FetchMode::CUSTOM_OBJECT: + while (($row = $this->fetch(...func_get_args())) !== false) { + $rows[] = $row; + } + + break; + + case FetchMode::COLUMN: + while (($row = $this->fetchColumn()) !== false) { + $rows[] = $row; + } + + break; + + default: + while (($row = $this->fetch($fetchMode)) !== false) { + $rows[] = $row; + } + } + + return $rows; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. + */ + public function fetchColumn($columnIndex = 0) + { + $row = $this->fetch(FetchMode::NUMERIC); + + if ($row === false) { + return false; + } + + return $row[$columnIndex] ?? null; + } + + /** + * {@inheritdoc} + */ + public function fetchNumeric() + { + return $this->doFetch(SQLSRV_FETCH_NUMERIC); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + return $this->doFetch(SQLSRV_FETCH_ASSOC); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric(): array + { + return FetchUtils::fetchAllNumeric($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative(): array + { + return FetchUtils::fetchAllAssociative($this); + } + + /** + * {@inheritdoc} + */ + public function fetchFirstColumn(): array + { + return FetchUtils::fetchFirstColumn($this); + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + if ($this->stmt === null) { + return 0; + } + + return sqlsrv_rows_affected($this->stmt) ?: 0; + } + + public function free(): void + { + // not having the result means there's nothing to close + if ($this->stmt === null || ! $this->result) { + return; + } + + // emulate it by fetching and discarding rows, similarly to what PDO does in this case + // @link http://php.net/manual/en/pdostatement.closecursor.php + // @link https://github.com/php/php-src/blob/php-7.0.11/ext/pdo/pdo_stmt.c#L2075 + // deliberately do not consider multiple result sets, since doctrine/dbal doesn't support them + while (sqlsrv_fetch($this->stmt)) { + } + + $this->result = false; + } + + /** + * @return mixed|false + */ + private function doFetch(int $fetchType) + { + // do not try fetching from the statement if it's not expected to contain the result + // in order to prevent exceptional situation + if ($this->stmt === null || ! $this->result) { + return false; + } + + return sqlsrv_fetch_array($this->stmt, $fetchType) ?? false; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/Statement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/Statement.php new file mode 100755 index 0000000..6a96b87 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/Statement.php @@ -0,0 +1,7 @@ +bindValue(), + * the variable is bound as a reference and will only be evaluated at the time + * that PDOStatement->execute() is called. + * + * As mentioned above, the named parameters are not natively supported by the mysqli driver, use executeQuery(), + * fetchAll(), fetchArray(), fetchColumn(), fetchAssoc() methods to have the named parameter emulated by doctrine. + * + * Most parameters are input parameters, that is, parameters that are + * used in a read-only fashion to build up the query. Some drivers support the invocation + * of stored procedures that return data as output parameters, and some also as input/output + * parameters that both send in data and are updated to receive it. + * + * @param int|string $param Parameter identifier. For a prepared statement using named placeholders, + * this will be a parameter name of the form :name. For a prepared statement using + * question mark placeholders, this will be the 1-indexed position of the parameter. + * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. + * @param int $type Explicit data type for the parameter using the {@link ParameterType} + * constants. To return an INOUT parameter from a stored procedure, use the bitwise + * OR operator to set the PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter. + * @param int|null $length You must specify maxlength when using an OUT bind + * so that PHP allocates enough memory to hold the returned value. + * + * @return bool TRUE on success or FALSE on failure. + */ + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null); + + /** + * Fetches the SQLSTATE associated with the last operation on the statement handle. + * + * @deprecated The error information is available via exceptions. + * + * @see Doctrine_Adapter_Interface::errorCode() + * + * @return string|int|bool The error code string. + */ + public function errorCode(); + + /** + * Fetches extended error information associated with the last operation on the statement handle. + * + * @deprecated The error information is available via exceptions. + * + * @return mixed[] The error info array. + */ + public function errorInfo(); + + /** + * Executes a prepared statement + * + * If the prepared statement included parameter markers, you must either: + * call PDOStatement->bindParam() to bind PHP variables to the parameter markers: + * bound variables pass their value as input and receive the output value, + * if any, of their associated parameter markers or pass an array of input-only + * parameter values. + * + * @param mixed[]|null $params An array of values with as many elements as there are + * bound parameters in the SQL statement being executed. + * + * @return bool TRUE on success or FALSE on failure. + */ + public function execute($params = null); + + /** + * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement + * executed by the corresponding object. + * + * If the last SQL statement executed by the associated Statement object was a SELECT statement, + * some databases may return the number of rows returned by that statement. However, + * this behaviour is not guaranteed for all databases and should not be + * relied on for portable applications. + * + * @return int The number of rows. + */ + public function rowCount(); +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/StatementIterator.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/StatementIterator.php new file mode 100755 index 0000000..d447ca6 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/StatementIterator.php @@ -0,0 +1,31 @@ +statement = $statement; + } + + /** + * {@inheritdoc} + */ + #[ReturnTypeWillChange] + public function getIterator() + { + while (($result = $this->statement->fetch()) !== false) { + yield $result; + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/DriverManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/DriverManager.php new file mode 100755 index 0000000..fd4544a --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/DriverManager.php @@ -0,0 +1,517 @@ +, + * driverClass?: class-string, + * driverOptions?: array, + * host?: string, + * password?: string, + * path?: string, + * pdo?: \PDO, + * platform?: Platforms\AbstractPlatform, + * port?: int, + * user?: string, + * } + * @psalm-type Params = array{ + * charset?: string, + * dbname?: string, + * default_dbname?: string, + * driver?: key-of, + * driverClass?: class-string, + * driverOptions?: array, + * host?: string, + * keepSlave?: bool, + * keepReplica?: bool, + * master?: OverrideParams, + * memory?: bool, + * password?: string, + * path?: string, + * pdo?: \PDO, + * platform?: Platforms\AbstractPlatform, + * port?: int, + * primary?: OverrideParams, + * replica?: array, + * sharding?: array, + * slaves?: array, + * user?: string, + * wrapperClass?: class-string, + * } + */ +final class DriverManager +{ + /** + * List of supported drivers and their mappings to the driver classes. + * + * To add your own driver use the 'driverClass' parameter to {@link DriverManager::getConnection()}. + */ + private const DRIVER_MAP = [ + 'pdo_mysql' => PDO\MySQL\Driver::class, + 'pdo_sqlite' => PDO\SQLite\Driver::class, + 'pdo_pgsql' => PDO\PgSQL\Driver::class, + 'pdo_oci' => PDO\OCI\Driver::class, + 'oci8' => OCI8\Driver::class, + 'ibm_db2' => IBMDB2\Driver::class, + 'pdo_sqlsrv' => PDO\SQLSrv\Driver::class, + 'mysqli' => Mysqli\Driver::class, + 'drizzle_pdo_mysql' => DrizzlePDOMySql\Driver::class, + 'sqlanywhere' => SQLAnywhere\Driver::class, + 'sqlsrv' => SQLSrv\Driver::class, + ]; + + /** + * List of URL schemes from a database URL and their mappings to driver. + * + * @var string[] + */ + private static $driverSchemeAliases = [ + 'db2' => 'ibm_db2', + 'mssql' => 'pdo_sqlsrv', + 'mysql' => 'pdo_mysql', + 'mysql2' => 'pdo_mysql', // Amazon RDS, for some weird reason + 'postgres' => 'pdo_pgsql', + 'postgresql' => 'pdo_pgsql', + 'pgsql' => 'pdo_pgsql', + 'sqlite' => 'pdo_sqlite', + 'sqlite3' => 'pdo_sqlite', + ]; + + /** + * Private constructor. This class cannot be instantiated. + * + * @codeCoverageIgnore + */ + private function __construct() + { + } + + /** + * Creates a connection object based on the specified parameters. + * This method returns a Doctrine\DBAL\Connection which wraps the underlying + * driver connection. + * + * $params must contain at least one of the following. + * + * Either 'driver' with one of the array keys of {@link DRIVER_MAP}, + * OR 'driverClass' that contains the full class name (with namespace) of the + * driver class to instantiate. + * + * Other (optional) parameters: + * + * user (string): + * The username to use when connecting. + * + * password (string): + * The password to use when connecting. + * + * driverOptions (array): + * Any additional driver-specific options for the driver. These are just passed + * through to the driver. + * + * pdo: + * You can pass an existing PDO instance through this parameter. The PDO + * instance will be wrapped in a Doctrine\DBAL\Connection. + * This feature is deprecated and no longer supported in 3.0.x version. + * + * wrapperClass: + * You may specify a custom wrapper class through the 'wrapperClass' + * parameter but this class MUST inherit from Doctrine\DBAL\Connection. + * + * driverClass: + * The driver class to use. + * + * @param array $params + * @param Configuration|null $config The configuration to use. + * @param EventManager|null $eventManager The event manager to use. + * @psalm-param array{ + * charset?: string, + * dbname?: string, + * default_dbname?: string, + * driver?: key-of, + * driverClass?: class-string, + * driverOptions?: array, + * host?: string, + * keepSlave?: bool, + * keepReplica?: bool, + * master?: OverrideParams, + * memory?: bool, + * password?: string, + * path?: string, + * pdo?: \PDO, + * platform?: Platforms\AbstractPlatform, + * port?: int, + * primary?: OverrideParams, + * replica?: array, + * sharding?: array, + * slaves?: array, + * user?: string, + * wrapperClass?: class-string, + * } $params + * @phpstan-param array $params + * + * @psalm-return ($params is array{wrapperClass:mixed} ? T : Connection) + * + * @throws Exception + * + * @template T of Connection + */ + public static function getConnection( + array $params, + ?Configuration $config = null, + ?EventManager $eventManager = null + ): Connection { + // create default config and event manager, if not set + if (! $config) { + $config = new Configuration(); + } + + if (! $eventManager) { + $eventManager = new EventManager(); + } + + $params = self::parseDatabaseUrl($params); + + // @todo: deprecated, notice thrown by connection constructor + if (isset($params['master'])) { + $params['master'] = self::parseDatabaseUrl($params['master']); + } + + // @todo: deprecated, notice thrown by connection constructor + if (isset($params['slaves'])) { + foreach ($params['slaves'] as $key => $slaveParams) { + $params['slaves'][$key] = self::parseDatabaseUrl($slaveParams); + } + } + + // URL support for PrimaryReplicaConnection + if (isset($params['primary'])) { + $params['primary'] = self::parseDatabaseUrl($params['primary']); + } + + if (isset($params['replica'])) { + foreach ($params['replica'] as $key => $replicaParams) { + $params['replica'][$key] = self::parseDatabaseUrl($replicaParams); + } + } + + // URL support for PoolingShardConnection + if (isset($params['global'])) { + $params['global'] = self::parseDatabaseUrl($params['global']); + } + + if (isset($params['shards'])) { + foreach ($params['shards'] as $key => $shardParams) { + $params['shards'][$key] = self::parseDatabaseUrl($shardParams); + } + } + + // check for existing pdo object + if (isset($params['pdo']) && ! $params['pdo'] instanceof \PDO) { + throw Exception::invalidPdoInstance(); + } + + if (isset($params['pdo'])) { + $params['pdo']->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + $params['driver'] = 'pdo_' . $params['pdo']->getAttribute(\PDO::ATTR_DRIVER_NAME); + } + + $driver = self::createDriver($params); + + $wrapperClass = Connection::class; + if (isset($params['wrapperClass'])) { + if (! is_subclass_of($params['wrapperClass'], $wrapperClass)) { + throw Exception::invalidWrapperClass($params['wrapperClass']); + } + + /** @var class-string $wrapperClass */ + $wrapperClass = $params['wrapperClass']; + } + + return new $wrapperClass($params, $driver, $config, $eventManager); + } + + /** + * Returns the list of supported drivers. + * + * @return string[] + */ + public static function getAvailableDrivers(): array + { + return array_keys(self::DRIVER_MAP); + } + + /** + * @param array $params + * @psalm-param Params $params + * @phpstan-param array $params + * + * @throws Exception + */ + private static function createDriver(array $params): Driver + { + if (isset($params['driverClass'])) { + $interfaces = class_implements($params['driverClass'], true); + + if ($interfaces === false || ! in_array(Driver::class, $interfaces)) { + throw Exception::invalidDriverClass($params['driverClass']); + } + + return new $params['driverClass'](); + } + + if (isset($params['driver'])) { + if (! isset(self::DRIVER_MAP[$params['driver']])) { + throw Exception::unknownDriver($params['driver'], array_keys(self::DRIVER_MAP)); + } + + $class = self::DRIVER_MAP[$params['driver']]; + + return new $class(); + } + + throw Exception::driverRequired(); + } + + /** + * Normalizes the given connection URL path. + * + * @return string The normalized connection URL path + */ + private static function normalizeDatabaseUrlPath(string $urlPath): string + { + // Trim leading slash from URL path. + return substr($urlPath, 1); + } + + /** + * Extracts parts from a database URL, if present, and returns an + * updated list of parameters. + * + * @param mixed[] $params The list of parameters. + * @psalm-param Params $params + * @phpstan-param array $params + * + * @return mixed[] A modified list of parameters with info from a database + * URL extracted into indidivual parameter parts. + * @psalm-return Params + * @phpstan-return array + * + * @throws Exception + */ + private static function parseDatabaseUrl(array $params): array + { + if (! isset($params['url'])) { + return $params; + } + + // (pdo_)?sqlite3?:///... => (pdo_)?sqlite3?://localhost/... or else the URL will be invalid + $url = preg_replace('#^((?:pdo_)?sqlite3?):///#', '$1://localhost/', $params['url']); + $url = parse_url($url); + + if ($url === false) { + throw new Exception('Malformed parameter "url".'); + } + + foreach ($url as $param => $value) { + if (! is_string($value)) { + continue; + } + + $url[$param] = rawurldecode($value); + } + + // If we have a connection URL, we have to unset the default PDO instance connection parameter (if any) + // as we cannot merge connection details from the URL into the PDO instance (URL takes precedence). + unset($params['pdo']); + + $params = self::parseDatabaseUrlScheme($url['scheme'] ?? null, $params); + + if (isset($url['host'])) { + $params['host'] = $url['host']; + } + + if (isset($url['port'])) { + $params['port'] = $url['port']; + } + + if (isset($url['user'])) { + $params['user'] = $url['user']; + } + + if (isset($url['pass'])) { + $params['password'] = $url['pass']; + } + + $params = self::parseDatabaseUrlPath($url, $params); + $params = self::parseDatabaseUrlQuery($url, $params); + + return $params; + } + + /** + * Parses the given connection URL and resolves the given connection parameters. + * + * Assumes that the connection URL scheme is already parsed and resolved into the given connection parameters + * via {@link parseDatabaseUrlScheme}. + * + * @see parseDatabaseUrlScheme + * + * @param mixed[] $url The URL parts to evaluate. + * @param mixed[] $params The connection parameters to resolve. + * + * @return mixed[] The resolved connection parameters. + */ + private static function parseDatabaseUrlPath(array $url, array $params): array + { + if (! isset($url['path'])) { + return $params; + } + + $url['path'] = self::normalizeDatabaseUrlPath($url['path']); + + // If we do not have a known DBAL driver, we do not know any connection URL path semantics to evaluate + // and therefore treat the path as regular DBAL connection URL path. + if (! isset($params['driver'])) { + return self::parseRegularDatabaseUrlPath($url, $params); + } + + if (strpos($params['driver'], 'sqlite') !== false) { + return self::parseSqliteDatabaseUrlPath($url, $params); + } + + return self::parseRegularDatabaseUrlPath($url, $params); + } + + /** + * Parses the query part of the given connection URL and resolves the given connection parameters. + * + * @param mixed[] $url The connection URL parts to evaluate. + * @param mixed[] $params The connection parameters to resolve. + * + * @return mixed[] The resolved connection parameters. + */ + private static function parseDatabaseUrlQuery(array $url, array $params): array + { + if (! isset($url['query'])) { + return $params; + } + + $query = []; + + parse_str($url['query'], $query); // simply ingest query as extra params, e.g. charset or sslmode + + return array_merge($params, $query); // parse_str wipes existing array elements + } + + /** + * Parses the given regular connection URL and resolves the given connection parameters. + * + * Assumes that the "path" URL part is already normalized via {@link normalizeDatabaseUrlPath}. + * + * @see normalizeDatabaseUrlPath + * + * @param mixed[] $url The regular connection URL parts to evaluate. + * @param mixed[] $params The connection parameters to resolve. + * + * @return mixed[] The resolved connection parameters. + */ + private static function parseRegularDatabaseUrlPath(array $url, array $params): array + { + $params['dbname'] = $url['path']; + + return $params; + } + + /** + * Parses the given SQLite connection URL and resolves the given connection parameters. + * + * Assumes that the "path" URL part is already normalized via {@link normalizeDatabaseUrlPath}. + * + * @see normalizeDatabaseUrlPath + * + * @param mixed[] $url The SQLite connection URL parts to evaluate. + * @param mixed[] $params The connection parameters to resolve. + * + * @return mixed[] The resolved connection parameters. + */ + private static function parseSqliteDatabaseUrlPath(array $url, array $params): array + { + if ($url['path'] === ':memory:') { + $params['memory'] = true; + + return $params; + } + + $params['path'] = $url['path']; // pdo_sqlite driver uses 'path' instead of 'dbname' key + + return $params; + } + + /** + * Parses the scheme part from given connection URL and resolves the given connection parameters. + * + * @param string|null $scheme The connection URL scheme, if available + * @param mixed[] $params The connection parameters to resolve. + * + * @return mixed[] The resolved connection parameters. + * + * @throws Exception If parsing failed or resolution is not possible. + */ + private static function parseDatabaseUrlScheme($scheme, array $params): array + { + if ($scheme !== null) { + // The requested driver from the URL scheme takes precedence + // over the default custom driver from the connection parameters (if any). + unset($params['driverClass']); + + // URL schemes must not contain underscores, but dashes are ok + $driver = str_replace('-', '_', $scheme); + + // The requested driver from the URL scheme takes precedence over the + // default driver from the connection parameters. If the driver is + // an alias (e.g. "postgres"), map it to the actual name ("pdo-pgsql"). + // Otherwise, let checkParams decide later if the driver exists. + $params['driver'] = self::$driverSchemeAliases[$driver] ?? $driver; + + return $params; + } + + // If a schemeless connection URL is given, we require a default driver or default custom driver + // as connection parameter. + if (! isset($params['driverClass']) && ! isset($params['driver'])) { + throw Exception::driverRequired($params['url']); + } + + return $params; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php new file mode 100755 index 0000000..35fadc4 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php @@ -0,0 +1,83 @@ +connection = $connection; + } + + /** + * @return Connection + */ + public function getConnection() + { + return $this->connection; + } + + /** + * @deprecated Use ConnectionEventArgs::getConnection() and Connection::getDriver() instead. + * + * @return Driver + */ + public function getDriver() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'ConnectionEventArgs::getDriver() is deprecated, ' . + 'use ConnectionEventArgs::getConnection()->getDriver() instead.' + ); + + return $this->connection->getDriver(); + } + + /** + * @deprecated Use ConnectionEventArgs::getConnection() and Connection::getDatabasePlatform() instead. + * + * @return AbstractPlatform + */ + public function getDatabasePlatform() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'ConnectionEventArgs::getDatabasePlatform() is deprecated, ' . + 'use ConnectionEventArgs::getConnection()->getDatabasePlatform() instead.' + ); + + return $this->connection->getDatabasePlatform(); + } + + /** + * @deprecated Use ConnectionEventArgs::getConnection() and Connection::getSchemaManager() instead. + * + * @return AbstractSchemaManager + */ + public function getSchemaManager() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'ConnectionEventArgs::getSchemaManager() is deprecated, ' . + 'use ConnectionEventArgs::getConnection()->getSchemaManager() instead.' + ); + + return $this->connection->getSchemaManager(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php new file mode 100755 index 0000000..8748dd1 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php @@ -0,0 +1,58 @@ +charset = $charset; + $this->collation = $collation; + } + + /** + * @return void + */ + public function postConnect(ConnectionEventArgs $args) + { + $collation = $this->collation ? ' COLLATE ' . $this->collation : ''; + $args->getConnection()->executeStatement('SET NAMES ' . $this->charset . $collation); + } + + /** + * {@inheritdoc} + */ + public function getSubscribedEvents() + { + return [Events::postConnect]; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php new file mode 100755 index 0000000..a907716 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php @@ -0,0 +1,74 @@ + 'HH24:MI:SS', + 'NLS_DATE_FORMAT' => 'YYYY-MM-DD HH24:MI:SS', + 'NLS_TIMESTAMP_FORMAT' => 'YYYY-MM-DD HH24:MI:SS', + 'NLS_TIMESTAMP_TZ_FORMAT' => 'YYYY-MM-DD HH24:MI:SS TZH:TZM', + 'NLS_NUMERIC_CHARACTERS' => '.,', + ]; + + /** + * @param string[] $oracleSessionVars + */ + public function __construct(array $oracleSessionVars = []) + { + $this->_defaultSessionVars = array_merge($this->_defaultSessionVars, $oracleSessionVars); + } + + /** + * @return void + */ + public function postConnect(ConnectionEventArgs $args) + { + if (! count($this->_defaultSessionVars)) { + return; + } + + $vars = []; + foreach (array_change_key_case($this->_defaultSessionVars, CASE_UPPER) as $option => $value) { + if ($option === 'CURRENT_SCHEMA') { + $vars[] = $option . ' = ' . $value; + } else { + $vars[] = $option . " = '" . $value . "'"; + } + } + + $sql = 'ALTER SESSION SET ' . implode(' ', $vars); + $args->getConnection()->executeStatement($sql); + } + + /** + * {@inheritdoc} + */ + public function getSubscribedEvents() + { + return [Events::postConnect]; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php new file mode 100755 index 0000000..ea63cab --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php @@ -0,0 +1,41 @@ +sql = $sql; + } + + /** + * @return void + */ + public function postConnect(ConnectionEventArgs $args) + { + $conn = $args->getConnection(); + $conn->exec($this->sql); + } + + /** + * {@inheritdoc} + */ + public function getSubscribedEvents() + { + return [Events::postConnect]; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php new file mode 100755 index 0000000..e61a48d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php @@ -0,0 +1,92 @@ +column = $column; + $this->tableDiff = $tableDiff; + $this->platform = $platform; + } + + /** + * @return Column + */ + public function getColumn() + { + return $this->column; + } + + /** + * @return TableDiff + */ + public function getTableDiff() + { + return $this->tableDiff; + } + + /** + * @return AbstractPlatform + */ + public function getPlatform() + { + return $this->platform; + } + + /** + * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. + * + * @param string|string[] $sql + * + * @return SchemaAlterTableAddColumnEventArgs + */ + public function addSql($sql) + { + if (is_array($sql)) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'Passing multiple SQL statements as an array to SchemaAlterTableAddColumnEventaArrgs::addSql() ' . + 'is deprecated. Pass each statement as an individual argument instead.' + ); + } + + $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); + + return $this; + } + + /** + * @return string[] + */ + public function getSql() + { + return $this->sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php new file mode 100755 index 0000000..e9ebb66 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php @@ -0,0 +1,82 @@ +columnDiff = $columnDiff; + $this->tableDiff = $tableDiff; + $this->platform = $platform; + } + + /** + * @return ColumnDiff + */ + public function getColumnDiff() + { + return $this->columnDiff; + } + + /** + * @return TableDiff + */ + public function getTableDiff() + { + return $this->tableDiff; + } + + /** + * @return AbstractPlatform + */ + public function getPlatform() + { + return $this->platform; + } + + /** + * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. + * + * @param string|string[] $sql + * + * @return SchemaAlterTableChangeColumnEventArgs + */ + public function addSql($sql) + { + $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); + + return $this; + } + + /** + * @return string[] + */ + public function getSql() + { + return $this->sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php new file mode 100755 index 0000000..9c2b9b3 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php @@ -0,0 +1,69 @@ +tableDiff = $tableDiff; + $this->platform = $platform; + } + + /** + * @return TableDiff + */ + public function getTableDiff() + { + return $this->tableDiff; + } + + /** + * @return AbstractPlatform + */ + public function getPlatform() + { + return $this->platform; + } + + /** + * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. + * + * @param string|string[] $sql + * + * @return SchemaAlterTableEventArgs + */ + public function addSql($sql) + { + $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); + + return $this; + } + + /** + * @return string[] + */ + public function getSql() + { + return $this->sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php new file mode 100755 index 0000000..d32af59 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php @@ -0,0 +1,82 @@ +column = $column; + $this->tableDiff = $tableDiff; + $this->platform = $platform; + } + + /** + * @return Column + */ + public function getColumn() + { + return $this->column; + } + + /** + * @return TableDiff + */ + public function getTableDiff() + { + return $this->tableDiff; + } + + /** + * @return AbstractPlatform + */ + public function getPlatform() + { + return $this->platform; + } + + /** + * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. + * + * @param string|string[] $sql + * + * @return SchemaAlterTableRemoveColumnEventArgs + */ + public function addSql($sql) + { + $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); + + return $this; + } + + /** + * @return string[] + */ + public function getSql() + { + return $this->sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php new file mode 100755 index 0000000..6d52b6c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php @@ -0,0 +1,97 @@ +oldColumnName = $oldColumnName; + $this->column = $column; + $this->tableDiff = $tableDiff; + $this->platform = $platform; + } + + /** + * @return string + */ + public function getOldColumnName() + { + return $this->oldColumnName; + } + + /** + * @return Column + */ + public function getColumn() + { + return $this->column; + } + + /** + * @return TableDiff + */ + public function getTableDiff() + { + return $this->tableDiff; + } + + /** + * @return AbstractPlatform + */ + public function getPlatform() + { + return $this->platform; + } + + /** + * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. + * + * @param string|string[] $sql + * + * @return SchemaAlterTableRenameColumnEventArgs + */ + public function addSql($sql) + { + $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); + + return $this; + } + + /** + * @return string[] + */ + public function getSql() + { + return $this->sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php new file mode 100755 index 0000000..4264e4b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php @@ -0,0 +1,116 @@ +tableColumn = $tableColumn; + $this->table = $table; + $this->database = $database; + $this->connection = $connection; + } + + /** + * Allows to clear the column which means the column will be excluded from + * tables column list. + * + * @return SchemaColumnDefinitionEventArgs + */ + public function setColumn(?Column $column = null) + { + $this->column = $column; + + return $this; + } + + /** + * @return Column|null + */ + public function getColumn() + { + return $this->column; + } + + /** + * @return mixed[] + */ + public function getTableColumn() + { + return $this->tableColumn; + } + + /** + * @return string + */ + public function getTable() + { + return $this->table; + } + + /** + * @return string + */ + public function getDatabase() + { + return $this->database; + } + + /** + * @return Connection + */ + public function getConnection() + { + return $this->connection; + } + + /** + * @deprecated Use SchemaColumnDefinitionEventArgs::getConnection() and Connection::getDatabasePlatform() instead. + * + * @return AbstractPlatform + */ + public function getDatabasePlatform() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'SchemaColumnDefinitionEventArgs::getDatabasePlatform() is deprecated, ' . + 'use SchemaColumnDefinitionEventArgs::getConnection()->getDatabasePlatform() instead.' + ); + + return $this->connection->getDatabasePlatform(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php new file mode 100755 index 0000000..246d2de --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php @@ -0,0 +1,82 @@ +column = $column; + $this->table = $table; + $this->platform = $platform; + } + + /** + * @return Column + */ + public function getColumn() + { + return $this->column; + } + + /** + * @return Table + */ + public function getTable() + { + return $this->table; + } + + /** + * @return AbstractPlatform + */ + public function getPlatform() + { + return $this->platform; + } + + /** + * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. + * + * @param string|string[] $sql + * + * @return SchemaCreateTableColumnEventArgs + */ + public function addSql($sql) + { + $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); + + return $this; + } + + /** + * @return string[] + */ + public function getSql() + { + return $this->sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php new file mode 100755 index 0000000..e9829a6 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php @@ -0,0 +1,97 @@ +table = $table; + $this->columns = $columns; + $this->options = $options; + $this->platform = $platform; + } + + /** + * @return Table + */ + public function getTable() + { + return $this->table; + } + + /** + * @return mixed[][] + */ + public function getColumns() + { + return $this->columns; + } + + /** + * @return mixed[] + */ + public function getOptions() + { + return $this->options; + } + + /** + * @return AbstractPlatform + */ + public function getPlatform() + { + return $this->platform; + } + + /** + * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. + * + * @param string|string[] $sql + * + * @return SchemaCreateTableEventArgs + */ + public function addSql($sql) + { + $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); + + return $this; + } + + /** + * @return string[] + */ + public function getSql() + { + return $this->sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php new file mode 100755 index 0000000..072e1ef --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php @@ -0,0 +1,69 @@ +table = $table; + $this->platform = $platform; + } + + /** + * @return string|Table + */ + public function getTable() + { + return $this->table; + } + + /** + * @return AbstractPlatform + */ + public function getPlatform() + { + return $this->platform; + } + + /** + * @param string $sql + * + * @return SchemaDropTableEventArgs + */ + public function setSql($sql) + { + $this->sql = $sql; + + return $this; + } + + /** + * @return string|null + */ + public function getSql() + { + return $this->sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaEventArgs.php new file mode 100755 index 0000000..df2bdae --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaEventArgs.php @@ -0,0 +1,32 @@ +preventDefault = true; + + return $this; + } + + /** + * @return bool + */ + public function isDefaultPrevented() + { + return $this->preventDefault; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php new file mode 100755 index 0000000..868243c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php @@ -0,0 +1,102 @@ +tableIndex = $tableIndex; + $this->table = $table; + $this->connection = $connection; + } + + /** + * Allows to clear the index which means the index will be excluded from tables index list. + * + * @return SchemaIndexDefinitionEventArgs + */ + public function setIndex(?Index $index = null) + { + $this->index = $index; + + return $this; + } + + /** + * @return Index|null + */ + public function getIndex() + { + return $this->index; + } + + /** + * @return mixed[] + */ + public function getTableIndex() + { + return $this->tableIndex; + } + + /** + * @return string + */ + public function getTable() + { + return $this->table; + } + + /** + * @return Connection + */ + public function getConnection() + { + return $this->connection; + } + + /** + * @deprecated Use SchemaIndexDefinitionEventArgs::getConnection() and Connection::getDatabasePlatform() instead. + * + * @return AbstractPlatform + */ + public function getDatabasePlatform() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'SchemaIndexDefinitionEventArgs::getDatabasePlatform() is deprecated, ' . + 'use SchemaIndexDefinitionEventArgs::getConnection()->getDatabasePlatform() instead.' + ); + + return $this->connection->getDatabasePlatform(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Events.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Events.php new file mode 100755 index 0000000..de30815 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Events.php @@ -0,0 +1,33 @@ +driverException = $driverException; + } + + /** + * Returns the driver specific error code if given. + * + * Returns null if no error code was given by the driver. + * + * @return int|string|null + */ + public function getErrorCode() + { + return $this->driverException->getErrorCode(); + } + + /** + * Returns the SQLSTATE the driver was in at the time the error occurred, if given. + * + * Returns null if no SQLSTATE was given by the driver. + * + * @return string|null + */ + public function getSQLState() + { + return $this->driverException->getSQLState(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Exception/ForeignKeyConstraintViolationException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Exception/ForeignKeyConstraintViolationException.php new file mode 100755 index 0000000..f1a612b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Exception/ForeignKeyConstraintViolationException.php @@ -0,0 +1,12 @@ +stmt = $stmt; + } + + /** + * @return Driver\ResultStatement + */ + #[ReturnTypeWillChange] + public function getIterator() + { + return $this->stmt; + } + + /** + * {@inheritDoc} + * + * @deprecated Use Result::free() instead. + */ + public function closeCursor() + { + return $this->stmt->closeCursor(); + } + + /** + * {@inheritDoc} + */ + public function columnCount() + { + return $this->stmt->columnCount(); + } + + /** + * {@inheritDoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + return $this->stmt->setFetchMode($fetchMode, $arg2, $arg3); + } + + /** + * {@inheritDoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + */ + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Result::fetch() is deprecated, use Result::fetchNumeric(), fetchAssociative() or fetchOne() instead.' + ); + + return $this->stmt->fetch(...func_get_args()); + } + + /** + * {@inheritDoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Result::fetchAll() is deprecated, use Result::fetchAllNumeric(), fetchAllAssociative() or ' . + 'fetchFirstColumn() instead.' + ); + + return $this->stmt->fetchAll($fetchMode, $fetchArgument, $ctorArgs); + } + + /** + * {@inheritDoc} + * + * @deprecated Use fetchOne() instead. + */ + public function fetchColumn($columnIndex = 0) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Result::fetchColumn() is deprecated, use Result::fetchOne() instead.' + ); + + return $this->stmt->fetchColumn($columnIndex); + } + + /** + * {@inheritDoc} + */ + public function fetchNumeric() + { + return $this->stmt->fetch(PDO::FETCH_NUM); + } + + /** + * {@inheritDoc} + */ + public function fetchAssociative() + { + return $this->stmt->fetch(PDO::FETCH_ASSOC); + } + + /** + * {@inheritDoc} + */ + public function fetchOne() + { + $row = $this->fetchNumeric(); + + if ($row === false) { + return false; + } + + return $row[0]; + } + + /** + * {@inheritDoc} + */ + public function fetchAllNumeric(): array + { + $rows = []; + + while (($row = $this->fetchNumeric()) !== false) { + $rows[] = $row; + } + + return $rows; + } + + /** + * {@inheritDoc} + */ + public function fetchAllAssociative(): array + { + $rows = []; + + while (($row = $this->fetchAssociative()) !== false) { + $rows[] = $row; + } + + return $rows; + } + + /** + * {@inheritDoc} + */ + public function fetchAllKeyValue(): array + { + $this->ensureHasKeyValue(); + $data = []; + + foreach ($this->fetchAllNumeric() as [$key, $value]) { + $data[$key] = $value; + } + + return $data; + } + + /** + * {@inheritDoc} + */ + public function fetchAllAssociativeIndexed(): array + { + $data = []; + + foreach ($this->fetchAllAssociative() as $row) { + $data[array_shift($row)] = $row; + } + + return $data; + } + + /** + * {@inheritDoc} + */ + public function fetchFirstColumn(): array + { + $rows = []; + + while (($row = $this->fetchOne()) !== false) { + $rows[] = $row; + } + + return $rows; + } + + /** + * {@inheritdoc} + * + * @return Traversable> + */ + public function iterateNumeric(): Traversable + { + while (($row = $this->fetchNumeric()) !== false) { + yield $row; + } + } + + /** + * {@inheritDoc} + * + * @return Traversable> + */ + public function iterateAssociative(): Traversable + { + while (($row = $this->fetchAssociative()) !== false) { + yield $row; + } + } + + /** + * {@inheritDoc} + * + * @return Traversable + */ + public function iterateKeyValue(): Traversable + { + $this->ensureHasKeyValue(); + + foreach ($this->iterateNumeric() as [$key, $value]) { + yield $key => $value; + } + } + + /** + * {@inheritDoc} + * + * @return Traversable> + */ + public function iterateAssociativeIndexed(): Traversable + { + foreach ($this->iterateAssociative() as $row) { + yield array_shift($row) => $row; + } + } + + /** + * {@inheritDoc} + * + * @return Traversable + */ + public function iterateColumn(): Traversable + { + while (($value = $this->fetchOne()) !== false) { + yield $value; + } + } + + /** + * {@inheritDoc} + */ + public function rowCount() + { + if (method_exists($this->stmt, 'rowCount')) { + return $this->stmt->rowCount(); + } + + throw Exception::notSupported('rowCount'); + } + + public function free(): void + { + $this->closeCursor(); + } + + private function ensureHasKeyValue(): void + { + $columnCount = $this->columnCount(); + + if ($columnCount < 2) { + throw NoKeyValue::fromColumnCount($columnCount); + } + } + + /** + * {@inheritDoc} + * + * @deprecated This feature will no longer be available on Result object in 3.0.x version. + */ + public function bindValue($param, $value, $type = ParameterType::STRING) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Result::bindValue() is deprecated, no replacement.' + ); + + if ($this->stmt instanceof Driver\Statement) { + return $this->stmt->bindValue($param, $value, $type); + } + + throw Exception::notSupported('bindValue'); + } + + /** + * {@inheritDoc} + * + * @deprecated This feature will no longer be available on Result object in 3.0.x version. + */ + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Result::bindParam() is deprecated, no replacement.' + ); + + if ($this->stmt instanceof Driver\Statement) { + return $this->stmt->bindParam($param, $variable, $type, $length); + } + + throw Exception::notSupported('bindParam'); + } + + /** + * {@inheritDoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorCode() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Result::errorCode() is deprecated, the error information is available via exceptions.' + ); + + if ($this->stmt instanceof Driver\Statement) { + return $this->stmt->errorCode(); + } + + throw Exception::notSupported('errorCode'); + } + + /** + * {@inheritDoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Result::errorInfo() is deprecated, the error information is available via exceptions.' + ); + + if ($this->stmt instanceof Driver\Statement) { + return $this->stmt->errorInfo(); + } + + throw Exception::notSupported('errorInfo'); + } + + /** + * {@inheritDoc} + * + * @deprecated This feature will no longer be available on Result object in 3.0.x version. + */ + public function execute($params = null) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Result::execute() is deprecated, no replacement.' + ); + + if ($this->stmt instanceof Driver\Statement) { + return $this->stmt->execute($params); + } + + throw Exception::notSupported('execute'); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGenerator.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGenerator.php new file mode 100755 index 0000000..c17caad --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGenerator.php @@ -0,0 +1,160 @@ +getDriver() instanceof Driver\PDOSqlite\Driver) { + throw new Exception('Cannot use TableGenerator with SQLite.'); + } + + $this->conn = DriverManager::getConnection( + $conn->getParams(), + $conn->getConfiguration(), + $conn->getEventManager() + ); + + $this->generatorTableName = $generatorTableName; + } + + /** + * Generates the next unused value for the given sequence name. + * + * @param string $sequence + * + * @return int + * + * @throws Exception + */ + public function nextValue($sequence) + { + if (isset($this->sequences[$sequence])) { + $value = $this->sequences[$sequence]['value']; + $this->sequences[$sequence]['value']++; + if ($this->sequences[$sequence]['value'] >= $this->sequences[$sequence]['max']) { + unset($this->sequences[$sequence]); + } + + return $value; + } + + $this->conn->beginTransaction(); + + try { + $platform = $this->conn->getDatabasePlatform(); + $sql = 'SELECT sequence_value, sequence_increment_by' + . ' FROM ' . $platform->appendLockHint($this->generatorTableName, LockMode::PESSIMISTIC_WRITE) + . ' WHERE sequence_name = ? ' . $platform->getWriteLockSQL(); + $row = $this->conn->fetchAssociative($sql, [$sequence]); + + if ($row !== false) { + $row = array_change_key_case($row, CASE_LOWER); + + $value = $row['sequence_value']; + $value++; + + assert(is_int($value)); + + if ($row['sequence_increment_by'] > 1) { + $this->sequences[$sequence] = [ + 'value' => $value, + 'max' => $row['sequence_value'] + $row['sequence_increment_by'], + ]; + } + + $sql = 'UPDATE ' . $this->generatorTableName . ' ' . + 'SET sequence_value = sequence_value + sequence_increment_by ' . + 'WHERE sequence_name = ? AND sequence_value = ?'; + $rows = $this->conn->executeStatement($sql, [$sequence, $row['sequence_value']]); + + if ($rows !== 1) { + throw new Exception('Race-condition detected while updating sequence. Aborting generation'); + } + } else { + $this->conn->insert( + $this->generatorTableName, + ['sequence_name' => $sequence, 'sequence_value' => 1, 'sequence_increment_by' => 1] + ); + $value = 1; + } + + $this->conn->commit(); + } catch (Throwable $e) { + $this->conn->rollBack(); + + throw new Exception( + 'Error occurred while generating ID with TableGenerator, aborted generation: ' . $e->getMessage(), + 0, + $e + ); + } + + return $value; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php new file mode 100755 index 0000000..3ec22f3 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php @@ -0,0 +1,71 @@ +generatorTableName = $generatorTableName; + } + + /** + * {@inheritdoc} + */ + public function acceptSchema(Schema $schema) + { + $table = $schema->createTable($this->generatorTableName); + $table->addColumn('sequence_name', 'string'); + $table->addColumn('sequence_value', 'integer', ['default' => 1]); + $table->addColumn('sequence_increment_by', 'integer', ['default' => 1]); + } + + /** + * {@inheritdoc} + */ + public function acceptTable(Table $table) + { + } + + /** + * {@inheritdoc} + */ + public function acceptColumn(Table $table, Column $column) + { + } + + /** + * {@inheritdoc} + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + } + + /** + * {@inheritdoc} + */ + public function acceptIndex(Table $table, Index $index) + { + } + + /** + * {@inheritdoc} + */ + public function acceptSequence(Sequence $sequence) + { + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/LockMode.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/LockMode.php new file mode 100755 index 0000000..1a7ed23 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/LockMode.php @@ -0,0 +1,23 @@ +> + */ + public $queries = []; + + /** + * If Debug Stack is enabled (log queries) or not. + * + * @var bool + */ + public $enabled = true; + + /** @var float|null */ + public $start = null; + + /** @var int */ + public $currentQuery = 0; + + /** + * {@inheritdoc} + */ + public function startQuery($sql, ?array $params = null, ?array $types = null) + { + if (! $this->enabled) { + return; + } + + $this->start = microtime(true); + + $this->queries[++$this->currentQuery] = [ + 'sql' => $sql, + 'params' => $params, + 'types' => $types, + 'executionMS' => 0, + ]; + } + + /** + * {@inheritdoc} + */ + public function stopQuery() + { + if (! $this->enabled) { + return; + } + + $this->queries[$this->currentQuery]['executionMS'] = microtime(true) - $this->start; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php new file mode 100755 index 0000000..1acd4e3 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php @@ -0,0 +1,51 @@ +loggers = $loggers; + } + + /** + * Adds a logger in the chain. + * + * @deprecated Inject list of loggers via constructor instead + * + * @return void + */ + public function addLogger(SQLLogger $logger) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3572', + 'LoggerChain::addLogger() is deprecated, use LoggerChain constructor instead.' + ); + + $this->loggers[] = $logger; + } + + /** + * {@inheritdoc} + */ + public function startQuery($sql, ?array $params = null, ?array $types = null) + { + foreach ($this->loggers as $logger) { + $logger->startQuery($sql, $params, $types); + } + } + + /** + * {@inheritdoc} + */ + public function stopQuery() + { + foreach ($this->loggers as $logger) { + $logger->stopQuery(); + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/SQLLogger.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/SQLLogger.php new file mode 100755 index 0000000..8328a71 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/SQLLogger.php @@ -0,0 +1,29 @@ +|array|null $params Statement parameters + * @param array|array|null $types Parameter types + * + * @return void + */ + public function startQuery($sql, ?array $params = null, ?array $types = null); + + /** + * Marks the last started query as stopped. This can be used for timing of queries. + * + * @return void + */ + public function stopQuery(); +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/ParameterType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/ParameterType.php new file mode 100755 index 0000000..2c4c3ad --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/ParameterType.php @@ -0,0 +1,65 @@ +_eventManager = $eventManager; + } + + /** + * Gets the EventManager used by the Platform. + * + * @return EventManager|null + */ + public function getEventManager() + { + return $this->_eventManager; + } + + /** + * Returns the SQL snippet that declares a boolean column. + * + * @param mixed[] $column + * + * @return string + */ + abstract public function getBooleanTypeDeclarationSQL(array $column); + + /** + * Returns the SQL snippet that declares a 4 byte integer column. + * + * @param mixed[] $column + * + * @return string + */ + abstract public function getIntegerTypeDeclarationSQL(array $column); + + /** + * Returns the SQL snippet that declares an 8 byte integer column. + * + * @param mixed[] $column + * + * @return string + */ + abstract public function getBigIntTypeDeclarationSQL(array $column); + + /** + * Returns the SQL snippet that declares a 2 byte integer column. + * + * @param mixed[] $column + * + * @return string + */ + abstract public function getSmallIntTypeDeclarationSQL(array $column); + + /** + * Returns the SQL snippet that declares common properties of an integer column. + * + * @param mixed[] $column + * + * @return string + */ + abstract protected function _getCommonIntegerTypeDeclarationSQL(array $column); + + /** + * Lazy load Doctrine Type Mappings. + * + * @return void + */ + abstract protected function initializeDoctrineTypeMappings(); + + /** + * Initializes Doctrine Type Mappings with the platform defaults + * and with all additional type mappings. + * + * @return void + */ + private function initializeAllDoctrineTypeMappings() + { + $this->initializeDoctrineTypeMappings(); + + foreach (Type::getTypesMap() as $typeName => $className) { + foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) { + $this->doctrineTypeMapping[$dbType] = $typeName; + } + } + } + + /** + * Returns the SQL snippet used to declare a column that can + * store characters in the ASCII character set + * + * @param mixed[] $column + */ + public function getAsciiStringTypeDeclarationSQL(array $column): string + { + return $this->getVarcharTypeDeclarationSQL($column); + } + + /** + * Returns the SQL snippet used to declare a VARCHAR column type. + * + * @param mixed[] $column + * + * @return string + */ + public function getVarcharTypeDeclarationSQL(array $column) + { + if (! isset($column['length'])) { + $column['length'] = $this->getVarcharDefaultLength(); + } + + $fixed = $column['fixed'] ?? false; + + $maxLength = $fixed + ? $this->getCharMaxLength() + : $this->getVarcharMaxLength(); + + if ($column['length'] > $maxLength) { + return $this->getClobTypeDeclarationSQL($column); + } + + return $this->getVarcharTypeDeclarationSQLSnippet($column['length'], $fixed); + } + + /** + * Returns the SQL snippet used to declare a BINARY/VARBINARY column type. + * + * @param mixed[] $column The column definition. + * + * @return string + */ + public function getBinaryTypeDeclarationSQL(array $column) + { + if (! isset($column['length'])) { + $column['length'] = $this->getBinaryDefaultLength(); + } + + $fixed = $column['fixed'] ?? false; + + $maxLength = $this->getBinaryMaxLength(); + + if ($column['length'] > $maxLength) { + if ($maxLength > 0) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3187', + 'Binary column length %d is greater than supported by the platform (%d).' + . ' Reduce the column length or use a BLOB column instead.', + $column['length'], + $maxLength + ); + } + + return $this->getBlobTypeDeclarationSQL($column); + } + + return $this->getBinaryTypeDeclarationSQLSnippet($column['length'], $fixed); + } + + /** + * Returns the SQL snippet to declare a GUID/UUID column. + * + * By default this maps directly to a CHAR(36) and only maps to more + * special datatypes when the underlying databases support this datatype. + * + * @param mixed[] $column + * + * @return string + */ + public function getGuidTypeDeclarationSQL(array $column) + { + $column['length'] = 36; + $column['fixed'] = true; + + return $this->getVarcharTypeDeclarationSQL($column); + } + + /** + * Returns the SQL snippet to declare a JSON column. + * + * By default this maps directly to a CLOB and only maps to more + * special datatypes when the underlying databases support this datatype. + * + * @param mixed[] $column + * + * @return string + */ + public function getJsonTypeDeclarationSQL(array $column) + { + return $this->getClobTypeDeclarationSQL($column); + } + + /** + * @param int $length + * @param bool $fixed + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + throw Exception::notSupported('VARCHARs not supported by Platform.'); + } + + /** + * Returns the SQL snippet used to declare a BINARY/VARBINARY column type. + * + * @param int $length The length of the column. + * @param bool $fixed Whether the column length is fixed. + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + { + throw Exception::notSupported('BINARY/VARBINARY column types are not supported by this platform.'); + } + + /** + * Returns the SQL snippet used to declare a CLOB column type. + * + * @param mixed[] $column + * + * @return string + */ + abstract public function getClobTypeDeclarationSQL(array $column); + + /** + * Returns the SQL Snippet used to declare a BLOB column type. + * + * @param mixed[] $column + * + * @return string + */ + abstract public function getBlobTypeDeclarationSQL(array $column); + + /** + * Gets the name of the platform. + * + * @return string + */ + abstract public function getName(); + + /** + * Registers a doctrine type to be used in conjunction with a column type of this platform. + * + * @param string $dbType + * @param string $doctrineType + * + * @return void + * + * @throws Exception If the type is not found. + */ + public function registerDoctrineTypeMapping($dbType, $doctrineType) + { + if ($this->doctrineTypeMapping === null) { + $this->initializeAllDoctrineTypeMappings(); + } + + if (! Types\Type::hasType($doctrineType)) { + throw Exception::typeNotFound($doctrineType); + } + + $dbType = strtolower($dbType); + $this->doctrineTypeMapping[$dbType] = $doctrineType; + + $doctrineType = Type::getType($doctrineType); + + if (! $doctrineType->requiresSQLCommentHint($this)) { + return; + } + + $this->markDoctrineTypeCommented($doctrineType); + } + + /** + * Gets the Doctrine type that is mapped for the given database column type. + * + * @param string $dbType + * + * @return string + * + * @throws Exception + */ + public function getDoctrineTypeMapping($dbType) + { + if ($this->doctrineTypeMapping === null) { + $this->initializeAllDoctrineTypeMappings(); + } + + $dbType = strtolower($dbType); + + if (! isset($this->doctrineTypeMapping[$dbType])) { + throw new Exception( + 'Unknown database type ' . $dbType . ' requested, ' . static::class . ' may not support it.' + ); + } + + return $this->doctrineTypeMapping[$dbType]; + } + + /** + * Checks if a database type is currently supported by this platform. + * + * @param string $dbType + * + * @return bool + */ + public function hasDoctrineTypeMappingFor($dbType) + { + if ($this->doctrineTypeMapping === null) { + $this->initializeAllDoctrineTypeMappings(); + } + + $dbType = strtolower($dbType); + + return isset($this->doctrineTypeMapping[$dbType]); + } + + /** + * Initializes the Doctrine Type comments instance variable for in_array() checks. + * + * @return void + */ + protected function initializeCommentedDoctrineTypes() + { + $this->doctrineTypeComments = []; + + foreach (Type::getTypesMap() as $typeName => $className) { + $type = Type::getType($typeName); + + if (! $type->requiresSQLCommentHint($this)) { + continue; + } + + $this->doctrineTypeComments[] = $typeName; + } + } + + /** + * Is it necessary for the platform to add a parsable type comment to allow reverse engineering the given type? + * + * @return bool + */ + public function isCommentedDoctrineType(Type $doctrineType) + { + if ($this->doctrineTypeComments === null) { + $this->initializeCommentedDoctrineTypes(); + } + + assert(is_array($this->doctrineTypeComments)); + + return in_array($doctrineType->getName(), $this->doctrineTypeComments); + } + + /** + * Marks this type as to be commented in ALTER TABLE and CREATE TABLE statements. + * + * @param string|Type $doctrineType + * + * @return void + */ + public function markDoctrineTypeCommented($doctrineType) + { + if ($this->doctrineTypeComments === null) { + $this->initializeCommentedDoctrineTypes(); + } + + assert(is_array($this->doctrineTypeComments)); + + $this->doctrineTypeComments[] = $doctrineType instanceof Type ? $doctrineType->getName() : $doctrineType; + } + + /** + * Gets the comment to append to a column comment that helps parsing this type in reverse engineering. + * + * @return string + */ + public function getDoctrineTypeComment(Type $doctrineType) + { + return '(DC2Type:' . $doctrineType->getName() . ')'; + } + + /** + * Gets the comment of a passed column modified by potential doctrine type comment hints. + * + * @return string|null + */ + protected function getColumnComment(Column $column) + { + $comment = $column->getComment(); + + if ($this->isCommentedDoctrineType($column->getType())) { + $comment .= $this->getDoctrineTypeComment($column->getType()); + } + + return $comment; + } + + /** + * Gets the character used for identifier quoting. + * + * @return string + */ + public function getIdentifierQuoteCharacter() + { + return '"'; + } + + /** + * Gets the string portion that starts an SQL comment. + * + * @return string + */ + public function getSqlCommentStartString() + { + return '--'; + } + + /** + * Gets the string portion that ends an SQL comment. + * + * @return string + */ + public function getSqlCommentEndString() + { + return "\n"; + } + + /** + * Gets the maximum length of a char column. + */ + public function getCharMaxLength(): int + { + return $this->getVarcharMaxLength(); + } + + /** + * Gets the maximum length of a varchar column. + * + * @return int + */ + public function getVarcharMaxLength() + { + return 4000; + } + + /** + * Gets the default length of a varchar column. + * + * @return int + */ + public function getVarcharDefaultLength() + { + return 255; + } + + /** + * Gets the maximum length of a binary column. + * + * @return int + */ + public function getBinaryMaxLength() + { + return 4000; + } + + /** + * Gets the default length of a binary column. + * + * @return int + */ + public function getBinaryDefaultLength() + { + return 255; + } + + /** + * Gets all SQL wildcard characters of the platform. + * + * @return string[] + */ + public function getWildcards() + { + return ['%', '_']; + } + + /** + * Returns the regular expression operator. + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getRegexpExpression() + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the global unique identifier expression. + * + * @deprecated Use application-generated UUIDs instead + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getGuidExpression() + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the SQL snippet to get the average value of a column. + * + * @param string $column The column to use. + * + * @return string Generated SQL including an AVG aggregate function. + */ + public function getAvgExpression($column) + { + return 'AVG(' . $column . ')'; + } + + /** + * Returns the SQL snippet to get the number of rows (without a NULL value) of a column. + * + * If a '*' is used instead of a column the number of selected rows is returned. + * + * @param string|int $column The column to use. + * + * @return string Generated SQL including a COUNT aggregate function. + */ + public function getCountExpression($column) + { + return 'COUNT(' . $column . ')'; + } + + /** + * Returns the SQL snippet to get the highest value of a column. + * + * @param string $column The column to use. + * + * @return string Generated SQL including a MAX aggregate function. + */ + public function getMaxExpression($column) + { + return 'MAX(' . $column . ')'; + } + + /** + * Returns the SQL snippet to get the lowest value of a column. + * + * @param string $column The column to use. + * + * @return string Generated SQL including a MIN aggregate function. + */ + public function getMinExpression($column) + { + return 'MIN(' . $column . ')'; + } + + /** + * Returns the SQL snippet to get the total sum of a column. + * + * @param string $column The column to use. + * + * @return string Generated SQL including a SUM aggregate function. + */ + public function getSumExpression($column) + { + return 'SUM(' . $column . ')'; + } + + // scalar functions + + /** + * Returns the SQL snippet to get the md5 sum of a column. + * + * Note: Not SQL92, but common functionality. + * + * @param string $column + * + * @return string + */ + public function getMd5Expression($column) + { + return 'MD5(' . $column . ')'; + } + + /** + * Returns the SQL snippet to get the length of a text column. + * + * @param string $column + * + * @return string + */ + public function getLengthExpression($column) + { + return 'LENGTH(' . $column . ')'; + } + + /** + * Returns the SQL snippet to get the squared value of a column. + * + * @param string $column The column to use. + * + * @return string Generated SQL including an SQRT aggregate function. + */ + public function getSqrtExpression($column) + { + return 'SQRT(' . $column . ')'; + } + + /** + * Returns the SQL snippet to round a numeric column to the number of decimals specified. + * + * @param string $column + * @param int $decimals + * + * @return string + */ + public function getRoundExpression($column, $decimals = 0) + { + return 'ROUND(' . $column . ', ' . $decimals . ')'; + } + + /** + * Returns the SQL snippet to get the remainder of the division operation $expression1 / $expression2. + * + * @param string $expression1 + * @param string $expression2 + * + * @return string + */ + public function getModExpression($expression1, $expression2) + { + return 'MOD(' . $expression1 . ', ' . $expression2 . ')'; + } + + /** + * Returns the SQL snippet to trim a string. + * + * @param string $str The expression to apply the trim to. + * @param int $mode The position of the trim (leading/trailing/both). + * @param string|bool $char The char to trim, has to be quoted already. Defaults to space. + * + * @return string + */ + public function getTrimExpression($str, $mode = TrimMode::UNSPECIFIED, $char = false) + { + $expression = ''; + + switch ($mode) { + case TrimMode::LEADING: + $expression = 'LEADING '; + break; + + case TrimMode::TRAILING: + $expression = 'TRAILING '; + break; + + case TrimMode::BOTH: + $expression = 'BOTH '; + break; + } + + if ($char !== false) { + $expression .= $char . ' '; + } + + if ($mode || $char !== false) { + $expression .= 'FROM '; + } + + return 'TRIM(' . $expression . $str . ')'; + } + + /** + * Returns the SQL snippet to trim trailing space characters from the expression. + * + * @param string $str Literal string or column name. + * + * @return string + */ + public function getRtrimExpression($str) + { + return 'RTRIM(' . $str . ')'; + } + + /** + * Returns the SQL snippet to trim leading space characters from the expression. + * + * @param string $str Literal string or column name. + * + * @return string + */ + public function getLtrimExpression($str) + { + return 'LTRIM(' . $str . ')'; + } + + /** + * Returns the SQL snippet to change all characters from the expression to uppercase, + * according to the current character set mapping. + * + * @param string $str Literal string or column name. + * + * @return string + */ + public function getUpperExpression($str) + { + return 'UPPER(' . $str . ')'; + } + + /** + * Returns the SQL snippet to change all characters from the expression to lowercase, + * according to the current character set mapping. + * + * @param string $str Literal string or column name. + * + * @return string + */ + public function getLowerExpression($str) + { + return 'LOWER(' . $str . ')'; + } + + /** + * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str. + * + * @param string $str Literal string. + * @param string $substr Literal string to find. + * @param int|false $startPos Position to start at, beginning of string by default. + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the SQL snippet to get the current system date. + * + * @return string + */ + public function getNowExpression() + { + return 'NOW()'; + } + + /** + * Returns a SQL snippet to get a substring inside an SQL statement. + * + * Note: Not SQL92, but common functionality. + * + * SQLite only supports the 2 parameter variant of this function. + * + * @param string $string An sql string literal or column name/alias. + * @param int $start Where to start the substring portion. + * @param int|null $length The substring portion length. + * + * @return string + */ + public function getSubstringExpression($string, $start, $length = null) + { + if ($length === null) { + return 'SUBSTRING(' . $string . ' FROM ' . $start . ')'; + } + + return 'SUBSTRING(' . $string . ' FROM ' . $start . ' FOR ' . $length . ')'; + } + + /** + * Returns a SQL snippet to concatenate the given expressions. + * + * Accepts an arbitrary number of string parameters. Each parameter must contain an expression. + * + * @return string + */ + public function getConcatExpression() + { + return implode(' || ', func_get_args()); + } + + /** + * Returns the SQL for a logical not. + * + * Example: + * + * $q = new Doctrine_Query(); + * $e = $q->expr; + * $q->select('*')->from('table') + * ->where($e->eq('id', $e->not('null')); + * + * + * @param string $expression + * + * @return string The logical expression. + */ + public function getNotExpression($expression) + { + return 'NOT(' . $expression . ')'; + } + + /** + * Returns the SQL that checks if an expression is null. + * + * @param string $expression The expression that should be compared to null. + * + * @return string The logical expression. + */ + public function getIsNullExpression($expression) + { + return $expression . ' IS NULL'; + } + + /** + * Returns the SQL that checks if an expression is not null. + * + * @param string $expression The expression that should be compared to null. + * + * @return string The logical expression. + */ + public function getIsNotNullExpression($expression) + { + return $expression . ' IS NOT NULL'; + } + + /** + * Returns the SQL that checks if an expression evaluates to a value between two values. + * + * The parameter $expression is checked if it is between $value1 and $value2. + * + * Note: There is a slight difference in the way BETWEEN works on some databases. + * http://www.w3schools.com/sql/sql_between.asp. If you want complete database + * independence you should avoid using between(). + * + * @param string $expression The value to compare to. + * @param string $value1 The lower value to compare with. + * @param string $value2 The higher value to compare with. + * + * @return string The logical expression. + */ + public function getBetweenExpression($expression, $value1, $value2) + { + return $expression . ' BETWEEN ' . $value1 . ' AND ' . $value2; + } + + /** + * Returns the SQL to get the arccosine of a value. + * + * @param string $value + * + * @return string + */ + public function getAcosExpression($value) + { + return 'ACOS(' . $value . ')'; + } + + /** + * Returns the SQL to get the sine of a value. + * + * @param string $value + * + * @return string + */ + public function getSinExpression($value) + { + return 'SIN(' . $value . ')'; + } + + /** + * Returns the SQL to get the PI value. + * + * @return string + */ + public function getPiExpression() + { + return 'PI()'; + } + + /** + * Returns the SQL to get the cosine of a value. + * + * @param string $value + * + * @return string + */ + public function getCosExpression($value) + { + return 'COS(' . $value . ')'; + } + + /** + * Returns the SQL to calculate the difference in days between the two passed dates. + * + * Computes diff = date1 - date2. + * + * @param string $date1 + * @param string $date2 + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateDiffExpression($date1, $date2) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the SQL to add the number of given seconds to a date. + * + * @param string $date + * @param int $seconds + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateAddSecondsExpression($date, $seconds) + { + return $this->getDateArithmeticIntervalExpression($date, '+', $seconds, DateIntervalUnit::SECOND); + } + + /** + * Returns the SQL to subtract the number of given seconds from a date. + * + * @param string $date + * @param int $seconds + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateSubSecondsExpression($date, $seconds) + { + return $this->getDateArithmeticIntervalExpression($date, '-', $seconds, DateIntervalUnit::SECOND); + } + + /** + * Returns the SQL to add the number of given minutes to a date. + * + * @param string $date + * @param int $minutes + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateAddMinutesExpression($date, $minutes) + { + return $this->getDateArithmeticIntervalExpression($date, '+', $minutes, DateIntervalUnit::MINUTE); + } + + /** + * Returns the SQL to subtract the number of given minutes from a date. + * + * @param string $date + * @param int $minutes + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateSubMinutesExpression($date, $minutes) + { + return $this->getDateArithmeticIntervalExpression($date, '-', $minutes, DateIntervalUnit::MINUTE); + } + + /** + * Returns the SQL to add the number of given hours to a date. + * + * @param string $date + * @param int $hours + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateAddHourExpression($date, $hours) + { + return $this->getDateArithmeticIntervalExpression($date, '+', $hours, DateIntervalUnit::HOUR); + } + + /** + * Returns the SQL to subtract the number of given hours to a date. + * + * @param string $date + * @param int $hours + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateSubHourExpression($date, $hours) + { + return $this->getDateArithmeticIntervalExpression($date, '-', $hours, DateIntervalUnit::HOUR); + } + + /** + * Returns the SQL to add the number of given days to a date. + * + * @param string $date + * @param int $days + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateAddDaysExpression($date, $days) + { + return $this->getDateArithmeticIntervalExpression($date, '+', $days, DateIntervalUnit::DAY); + } + + /** + * Returns the SQL to subtract the number of given days to a date. + * + * @param string $date + * @param int $days + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateSubDaysExpression($date, $days) + { + return $this->getDateArithmeticIntervalExpression($date, '-', $days, DateIntervalUnit::DAY); + } + + /** + * Returns the SQL to add the number of given weeks to a date. + * + * @param string $date + * @param int $weeks + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateAddWeeksExpression($date, $weeks) + { + return $this->getDateArithmeticIntervalExpression($date, '+', $weeks, DateIntervalUnit::WEEK); + } + + /** + * Returns the SQL to subtract the number of given weeks from a date. + * + * @param string $date + * @param int $weeks + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateSubWeeksExpression($date, $weeks) + { + return $this->getDateArithmeticIntervalExpression($date, '-', $weeks, DateIntervalUnit::WEEK); + } + + /** + * Returns the SQL to add the number of given months to a date. + * + * @param string $date + * @param int $months + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateAddMonthExpression($date, $months) + { + return $this->getDateArithmeticIntervalExpression($date, '+', $months, DateIntervalUnit::MONTH); + } + + /** + * Returns the SQL to subtract the number of given months to a date. + * + * @param string $date + * @param int $months + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateSubMonthExpression($date, $months) + { + return $this->getDateArithmeticIntervalExpression($date, '-', $months, DateIntervalUnit::MONTH); + } + + /** + * Returns the SQL to add the number of given quarters to a date. + * + * @param string $date + * @param int $quarters + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateAddQuartersExpression($date, $quarters) + { + return $this->getDateArithmeticIntervalExpression($date, '+', $quarters, DateIntervalUnit::QUARTER); + } + + /** + * Returns the SQL to subtract the number of given quarters from a date. + * + * @param string $date + * @param int $quarters + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateSubQuartersExpression($date, $quarters) + { + return $this->getDateArithmeticIntervalExpression($date, '-', $quarters, DateIntervalUnit::QUARTER); + } + + /** + * Returns the SQL to add the number of given years to a date. + * + * @param string $date + * @param int $years + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateAddYearsExpression($date, $years) + { + return $this->getDateArithmeticIntervalExpression($date, '+', $years, DateIntervalUnit::YEAR); + } + + /** + * Returns the SQL to subtract the number of given years from a date. + * + * @param string $date + * @param int $years + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateSubYearsExpression($date, $years) + { + return $this->getDateArithmeticIntervalExpression($date, '-', $years, DateIntervalUnit::YEAR); + } + + /** + * Returns the SQL for a date arithmetic expression. + * + * @param string $date The column or literal representing a date to perform the arithmetic operation on. + * @param string $operator The arithmetic operator (+ or -). + * @param int $interval The interval that shall be calculated into the date. + * @param string $unit The unit of the interval that shall be calculated into the date. + * One of the DATE_INTERVAL_UNIT_* constants. + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the SQL bit AND comparison expression. + * + * @param string $value1 + * @param string $value2 + * + * @return string + */ + public function getBitAndComparisonExpression($value1, $value2) + { + return '(' . $value1 . ' & ' . $value2 . ')'; + } + + /** + * Returns the SQL bit OR comparison expression. + * + * @param string $value1 + * @param string $value2 + * + * @return string + */ + public function getBitOrComparisonExpression($value1, $value2) + { + return '(' . $value1 . ' | ' . $value2 . ')'; + } + + /** + * Returns the FOR UPDATE expression. + * + * @return string + */ + public function getForUpdateSQL() + { + return 'FOR UPDATE'; + } + + /** + * Honors that some SQL vendors such as MsSql use table hints for locking instead of the + * ANSI SQL FOR UPDATE specification. + * + * @param string $fromClause The FROM clause to append the hint for the given lock mode to. + * @param int|null $lockMode One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will + * be appended to the FROM clause. + * + * @return string + */ + public function appendLockHint($fromClause, $lockMode) + { + return $fromClause; + } + + /** + * Returns the SQL snippet to append to any SELECT statement which locks rows in shared read lock. + * + * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database + * vendors allow to lighten this constraint up to be a real read lock. + * + * @return string + */ + public function getReadLockSQL() + { + return $this->getForUpdateSQL(); + } + + /** + * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows. + * + * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard. + * + * @return string + */ + public function getWriteLockSQL() + { + return $this->getForUpdateSQL(); + } + + /** + * Returns the SQL snippet to drop an existing database. + * + * @param string $name The name of the database that should be dropped. + * + * @return string + */ + public function getDropDatabaseSQL($name) + { + return 'DROP DATABASE ' . $name; + } + + /** + * Returns the SQL snippet to drop an existing table. + * + * @param Table|string $table + * + * @return string + * + * @throws InvalidArgumentException + */ + public function getDropTableSQL($table) + { + $tableArg = $table; + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + if (! is_string($table)) { + throw new InvalidArgumentException( + __METHOD__ . '() expects $table parameter to be string or ' . Table::class . '.' + ); + } + + if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaDropTable)) { + $eventArgs = new SchemaDropTableEventArgs($tableArg, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaDropTable, $eventArgs); + + if ($eventArgs->isDefaultPrevented()) { + $sql = $eventArgs->getSql(); + + if ($sql === null) { + throw new UnexpectedValueException('Default implementation of DROP TABLE was overridden with NULL'); + } + + return $sql; + } + } + + return 'DROP TABLE ' . $table; + } + + /** + * Returns the SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction. + * + * @param Table|string $table + * + * @return string + */ + public function getDropTemporaryTableSQL($table) + { + return $this->getDropTableSQL($table); + } + + /** + * Returns the SQL to drop an index from a table. + * + * @param Index|string $index + * @param Table|string $table + * + * @return string + * + * @throws InvalidArgumentException + */ + public function getDropIndexSQL($index, $table = null) + { + if ($index instanceof Index) { + $index = $index->getQuotedName($this); + } elseif (! is_string($index)) { + throw new InvalidArgumentException( + __METHOD__ . '() expects $index parameter to be string or ' . Index::class . '.' + ); + } + + return 'DROP INDEX ' . $index; + } + + /** + * Returns the SQL to drop a constraint. + * + * @param Constraint|string $constraint + * @param Table|string $table + * + * @return string + */ + public function getDropConstraintSQL($constraint, $table) + { + if (! $constraint instanceof Constraint) { + $constraint = new Identifier($constraint); + } + + if (! $table instanceof Table) { + $table = new Identifier($table); + } + + $constraint = $constraint->getQuotedName($this); + $table = $table->getQuotedName($this); + + return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint; + } + + /** + * Returns the SQL to drop a foreign key. + * + * @param ForeignKeyConstraint|string $foreignKey + * @param Table|string $table + * + * @return string + */ + public function getDropForeignKeySQL($foreignKey, $table) + { + if (! $foreignKey instanceof ForeignKeyConstraint) { + $foreignKey = new Identifier($foreignKey); + } + + if (! $table instanceof Table) { + $table = new Identifier($table); + } + + $foreignKey = $foreignKey->getQuotedName($this); + $table = $table->getQuotedName($this); + + return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey; + } + + /** + * Returns the SQL statement(s) to create a table with the specified name, columns and constraints + * on this platform. + * + * @param int $createFlags + * + * @return string[] The sequence of SQL statements. + * + * @throws Exception + * @throws InvalidArgumentException + */ + public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES) + { + if (! is_int($createFlags)) { + throw new InvalidArgumentException( + 'Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.' + ); + } + + if (count($table->getColumns()) === 0) { + throw Exception::noColumnsSpecifiedForTable($table->getName()); + } + + $tableName = $table->getQuotedName($this); + $options = $table->getOptions(); + $options['uniqueConstraints'] = []; + $options['indexes'] = []; + $options['primary'] = []; + + if (($createFlags & self::CREATE_INDEXES) > 0) { + foreach ($table->getIndexes() as $index) { + if ($index->isPrimary()) { + $options['primary'] = $index->getQuotedColumns($this); + $options['primary_index'] = $index; + } else { + $options['indexes'][$index->getQuotedName($this)] = $index; + } + } + } + + $columnSql = []; + $columns = []; + + foreach ($table->getColumns() as $column) { + if ( + $this->_eventManager !== null + && $this->_eventManager->hasListeners(Events::onSchemaCreateTableColumn) + ) { + $eventArgs = new SchemaCreateTableColumnEventArgs($column, $table, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaCreateTableColumn, $eventArgs); + + $columnSql = array_merge($columnSql, $eventArgs->getSql()); + + if ($eventArgs->isDefaultPrevented()) { + continue; + } + } + + $name = $column->getQuotedName($this); + + $columnData = array_merge($column->toArray(), [ + 'name' => $name, + 'version' => $column->hasPlatformOption('version') ? $column->getPlatformOption('version') : false, + 'comment' => $this->getColumnComment($column), + ]); + + if ($columnData['type'] instanceof Types\StringType && $columnData['length'] === null) { + $columnData['length'] = 255; + } + + if (in_array($column->getName(), $options['primary'])) { + $columnData['primary'] = true; + } + + $columns[$name] = $columnData; + } + + if (($createFlags & self::CREATE_FOREIGNKEYS) > 0) { + $options['foreignKeys'] = []; + foreach ($table->getForeignKeys() as $fkConstraint) { + $options['foreignKeys'][] = $fkConstraint; + } + } + + if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) { + $eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs); + + if ($eventArgs->isDefaultPrevented()) { + return array_merge($eventArgs->getSql(), $columnSql); + } + } + + $sql = $this->_getCreateTableSQL($tableName, $columns, $options); + if ($this->supportsCommentOnStatement()) { + if ($table->hasOption('comment')) { + $sql[] = $this->getCommentOnTableSQL($tableName, $table->getOption('comment')); + } + + foreach ($table->getColumns() as $column) { + $comment = $this->getColumnComment($column); + + if ($comment === null || $comment === '') { + continue; + } + + $sql[] = $this->getCommentOnColumnSQL($tableName, $column->getQuotedName($this), $comment); + } + } + + return array_merge($sql, $columnSql); + } + + protected function getCommentOnTableSQL(string $tableName, ?string $comment): string + { + $tableName = new Identifier($tableName); + + return sprintf( + 'COMMENT ON TABLE %s IS %s', + $tableName->getQuotedName($this), + $this->quoteStringLiteral((string) $comment) + ); + } + + /** + * @param string $tableName + * @param string $columnName + * @param string|null $comment + * + * @return string + */ + public function getCommentOnColumnSQL($tableName, $columnName, $comment) + { + $tableName = new Identifier($tableName); + $columnName = new Identifier($columnName); + + return sprintf( + 'COMMENT ON COLUMN %s.%s IS %s', + $tableName->getQuotedName($this), + $columnName->getQuotedName($this), + $this->quoteStringLiteral((string) $comment) + ); + } + + /** + * Returns the SQL to create inline comment on a column. + * + * @param string $comment + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getInlineColumnCommentSQL($comment) + { + if (! $this->supportsInlineColumnComments()) { + throw Exception::notSupported(__METHOD__); + } + + return 'COMMENT ' . $this->quoteStringLiteral($comment); + } + + /** + * Returns the SQL used to create a table. + * + * @param string $name + * @param mixed[][] $columns + * @param mixed[] $options + * + * @return string[] + */ + protected function _getCreateTableSQL($name, array $columns, array $options = []) + { + $columnListSql = $this->getColumnDeclarationListSQL($columns); + + if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { + foreach ($options['uniqueConstraints'] as $index => $definition) { + $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition); + } + } + + if (isset($options['primary']) && ! empty($options['primary'])) { + $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')'; + } + + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach ($options['indexes'] as $index => $definition) { + $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition); + } + } + + $query = 'CREATE TABLE ' . $name . ' (' . $columnListSql; + + $check = $this->getCheckDeclarationSQL($columns); + if (! empty($check)) { + $query .= ', ' . $check; + } + + $query .= ')'; + + $sql = [$query]; + + if (isset($options['foreignKeys'])) { + foreach ((array) $options['foreignKeys'] as $definition) { + $sql[] = $this->getCreateForeignKeySQL($definition, $name); + } + } + + return $sql; + } + + /** + * @return string + */ + public function getCreateTemporaryTableSnippetSQL() + { + return 'CREATE TEMPORARY TABLE'; + } + + /** + * Returns the SQL to create a sequence on this platform. + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getCreateSequenceSQL(Sequence $sequence) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the SQL to change a sequence on this platform. + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getAlterSequenceSQL(Sequence $sequence) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the SQL to create a constraint on a table on this platform. + * + * @param Table|string $table + * + * @return string + * + * @throws InvalidArgumentException + */ + public function getCreateConstraintSQL(Constraint $constraint, $table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this); + + $columnList = '(' . implode(', ', $constraint->getQuotedColumns($this)) . ')'; + + $referencesClause = ''; + if ($constraint instanceof Index) { + if ($constraint->isPrimary()) { + $query .= ' PRIMARY KEY'; + } elseif ($constraint->isUnique()) { + $query .= ' UNIQUE'; + } else { + throw new InvalidArgumentException( + 'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().' + ); + } + } elseif ($constraint instanceof ForeignKeyConstraint) { + $query .= ' FOREIGN KEY'; + + $referencesClause = ' REFERENCES ' . $constraint->getQuotedForeignTableName($this) . + ' (' . implode(', ', $constraint->getQuotedForeignColumns($this)) . ')'; + } + + $query .= ' ' . $columnList . $referencesClause; + + return $query; + } + + /** + * Returns the SQL to create an index on a table on this platform. + * + * @param Table|string $table The name of the table on which the index is to be created. + * + * @return string + * + * @throws InvalidArgumentException + */ + public function getCreateIndexSQL(Index $index, $table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + $name = $index->getQuotedName($this); + $columns = $index->getColumns(); + + if (count($columns) === 0) { + throw new InvalidArgumentException("Incomplete definition. 'columns' required."); + } + + if ($index->isPrimary()) { + return $this->getCreatePrimaryKeySQL($index, $table); + } + + $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table; + $query .= ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index); + + return $query; + } + + /** + * Adds condition for partial index. + * + * @return string + */ + protected function getPartialIndexSQL(Index $index) + { + if ($this->supportsPartialIndexes() && $index->hasOption('where')) { + return ' WHERE ' . $index->getOption('where'); + } + + return ''; + } + + /** + * Adds additional flags for index generation. + * + * @return string + */ + protected function getCreateIndexSQLFlags(Index $index) + { + return $index->isUnique() ? 'UNIQUE ' : ''; + } + + /** + * Returns the SQL to create an unnamed primary key constraint. + * + * @param Table|string $table + * + * @return string + */ + public function getCreatePrimaryKeySQL(Index $index, $table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index) . ')'; + } + + /** + * Returns the SQL to create a named schema. + * + * @param string $schemaName + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getCreateSchemaSQL($schemaName) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Quotes a string so that it can be safely used as a table or column name, + * even if it is a reserved word of the platform. This also detects identifier + * chains separated by dot and quotes them independently. + * + * NOTE: Just because you CAN use quoted identifiers doesn't mean + * you SHOULD use them. In general, they end up causing way more + * problems than they solve. + * + * @param string $str The identifier name to be quoted. + * + * @return string The quoted identifier string. + */ + public function quoteIdentifier($str) + { + if (strpos($str, '.') !== false) { + $parts = array_map([$this, 'quoteSingleIdentifier'], explode('.', $str)); + + return implode('.', $parts); + } + + return $this->quoteSingleIdentifier($str); + } + + /** + * Quotes a single identifier (no dot chain separation). + * + * @param string $str The identifier name to be quoted. + * + * @return string The quoted identifier string. + */ + public function quoteSingleIdentifier($str) + { + $c = $this->getIdentifierQuoteCharacter(); + + return $c . str_replace($c, $c . $c, $str) . $c; + } + + /** + * Returns the SQL to create a new foreign key. + * + * @param ForeignKeyConstraint $foreignKey The foreign key constraint. + * @param Table|string $table The name of the table on which the foreign key is to be created. + * + * @return string + */ + public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + return 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey); + } + + /** + * Gets the SQL statements for altering an existing table. + * + * This method returns an array of SQL statements, since some platforms need several statements. + * + * @return string[] + * + * @throws Exception If not supported on this platform. + */ + public function getAlterTableSQL(TableDiff $diff) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * @param mixed[] $columnSql + * + * @return bool + */ + protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, &$columnSql) + { + if ($this->_eventManager === null) { + return false; + } + + if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) { + return false; + } + + $eventArgs = new SchemaAlterTableAddColumnEventArgs($column, $diff, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn, $eventArgs); + + $columnSql = array_merge($columnSql, $eventArgs->getSql()); + + return $eventArgs->isDefaultPrevented(); + } + + /** + * @param string[] $columnSql + * + * @return bool + */ + protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $diff, &$columnSql) + { + if ($this->_eventManager === null) { + return false; + } + + if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) { + return false; + } + + $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column, $diff, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn, $eventArgs); + + $columnSql = array_merge($columnSql, $eventArgs->getSql()); + + return $eventArgs->isDefaultPrevented(); + } + + /** + * @param string[] $columnSql + * + * @return bool + */ + protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableDiff $diff, &$columnSql) + { + if ($this->_eventManager === null) { + return false; + } + + if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) { + return false; + } + + $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff, $diff, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn, $eventArgs); + + $columnSql = array_merge($columnSql, $eventArgs->getSql()); + + return $eventArgs->isDefaultPrevented(); + } + + /** + * @param string $oldColumnName + * @param string[] $columnSql + * + * @return bool + */ + protected function onSchemaAlterTableRenameColumn($oldColumnName, Column $column, TableDiff $diff, &$columnSql) + { + if ($this->_eventManager === null) { + return false; + } + + if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) { + return false; + } + + $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName, $column, $diff, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn, $eventArgs); + + $columnSql = array_merge($columnSql, $eventArgs->getSql()); + + return $eventArgs->isDefaultPrevented(); + } + + /** + * @param string[] $sql + * + * @return bool + */ + protected function onSchemaAlterTable(TableDiff $diff, &$sql) + { + if ($this->_eventManager === null) { + return false; + } + + if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) { + return false; + } + + $eventArgs = new SchemaAlterTableEventArgs($diff, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs); + + $sql = array_merge($sql, $eventArgs->getSql()); + + return $eventArgs->isDefaultPrevented(); + } + + /** + * @return string[] + */ + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + { + $tableName = $diff->getName($this)->getQuotedName($this); + + $sql = []; + if ($this->supportsForeignKeyConstraints()) { + foreach ($diff->removedForeignKeys as $foreignKey) { + $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); + } + + foreach ($diff->changedForeignKeys as $foreignKey) { + $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); + } + } + + foreach ($diff->removedIndexes as $index) { + $sql[] = $this->getDropIndexSQL($index, $tableName); + } + + foreach ($diff->changedIndexes as $index) { + $sql[] = $this->getDropIndexSQL($index, $tableName); + } + + return $sql; + } + + /** + * @return string[] + */ + protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) + { + $sql = []; + $newName = $diff->getNewName(); + + if ($newName !== false) { + $tableName = $newName->getQuotedName($this); + } else { + $tableName = $diff->getName($this)->getQuotedName($this); + } + + if ($this->supportsForeignKeyConstraints()) { + foreach ($diff->addedForeignKeys as $foreignKey) { + $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName); + } + + foreach ($diff->changedForeignKeys as $foreignKey) { + $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName); + } + } + + foreach ($diff->addedIndexes as $index) { + $sql[] = $this->getCreateIndexSQL($index, $tableName); + } + + foreach ($diff->changedIndexes as $index) { + $sql[] = $this->getCreateIndexSQL($index, $tableName); + } + + foreach ($diff->renamedIndexes as $oldIndexName => $index) { + $oldIndexName = new Identifier($oldIndexName); + $sql = array_merge( + $sql, + $this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index, $tableName) + ); + } + + return $sql; + } + + /** + * Returns the SQL for renaming an index on a table. + * + * @param string $oldIndexName The name of the index to rename from. + * @param Index $index The definition of the index to rename to. + * @param string $tableName The table to rename the given index on. + * + * @return string[] The sequence of SQL statements for renaming the given index. + */ + protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + { + return [ + $this->getDropIndexSQL($oldIndexName, $tableName), + $this->getCreateIndexSQL($index, $tableName), + ]; + } + + /** + * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions. + * + * @deprecated + * + * @return string[] + */ + protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff) + { + return array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); + } + + /** + * Gets declaration of a number of columns in bulk. + * + * @param mixed[][] $columns A multidimensional associative array. + * The first dimension determines the column name, while the second + * dimension is keyed with the name of the properties + * of the column being declared as array indexes. Currently, the types + * of supported column properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * column. If this argument is missing the column should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this column. + * + * notnull + * Boolean flag that indicates whether this column is constrained + * to not be set to null. + * charset + * Text value with the default CHARACTER SET for this column. + * collation + * Text value with the default COLLATION for this column. + * unique + * unique constraint + * + * @return string + */ + public function getColumnDeclarationListSQL(array $columns) + { + $declarations = []; + + foreach ($columns as $name => $column) { + $declarations[] = $this->getColumnDeclarationSQL($name, $column); + } + + return implode(', ', $declarations); + } + + /** + * Obtains DBMS specific SQL code portion needed to declare a generic type + * column to be used in statements like CREATE TABLE. + * + * @param string $name The name the column to be declared. + * @param mixed[] $column An associative array with the name of the properties + * of the column being declared as array indexes. Currently, the types + * of supported column properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * column. If this argument is missing the column should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this column. + * + * notnull + * Boolean flag that indicates whether this column is constrained + * to not be set to null. + * charset + * Text value with the default CHARACTER SET for this column. + * collation + * Text value with the default COLLATION for this column. + * unique + * unique constraint + * check + * column check constraint + * columnDefinition + * a string that defines the complete column + * + * @return string DBMS specific SQL code portion that should be used to declare the column. + */ + public function getColumnDeclarationSQL($name, array $column) + { + if (isset($column['columnDefinition'])) { + $declaration = $this->getCustomTypeDeclarationSQL($column); + } else { + $default = $this->getDefaultValueDeclarationSQL($column); + + $charset = isset($column['charset']) && $column['charset'] ? + ' ' . $this->getColumnCharsetDeclarationSQL($column['charset']) : ''; + + $collation = isset($column['collation']) && $column['collation'] ? + ' ' . $this->getColumnCollationDeclarationSQL($column['collation']) : ''; + + $notnull = isset($column['notnull']) && $column['notnull'] ? ' NOT NULL' : ''; + + $unique = isset($column['unique']) && $column['unique'] ? + ' ' . $this->getUniqueFieldDeclarationSQL() : ''; + + $check = isset($column['check']) && $column['check'] ? + ' ' . $column['check'] : ''; + + $typeDecl = $column['type']->getSQLDeclaration($column, $this); + $declaration = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation; + + if ($this->supportsInlineColumnComments() && isset($column['comment']) && $column['comment'] !== '') { + $declaration .= ' ' . $this->getInlineColumnCommentSQL($column['comment']); + } + } + + return $name . ' ' . $declaration; + } + + /** + * Returns the SQL snippet that declares a floating point column of arbitrary precision. + * + * @param mixed[] $column + * + * @return string + */ + public function getDecimalTypeDeclarationSQL(array $column) + { + $column['precision'] = ! isset($column['precision']) || empty($column['precision']) + ? 10 : $column['precision']; + $column['scale'] = ! isset($column['scale']) || empty($column['scale']) + ? 0 : $column['scale']; + + return 'NUMERIC(' . $column['precision'] . ', ' . $column['scale'] . ')'; + } + + /** + * Obtains DBMS specific SQL code portion needed to set a default value + * declaration to be used in statements like CREATE TABLE. + * + * @param mixed[] $column The column definition array. + * + * @return string DBMS specific SQL code portion needed to set a default value. + */ + public function getDefaultValueDeclarationSQL($column) + { + if (! isset($column['default'])) { + return empty($column['notnull']) ? ' DEFAULT NULL' : ''; + } + + $default = $column['default']; + + if (! isset($column['type'])) { + return " DEFAULT '" . $default . "'"; + } + + $type = $column['type']; + + if ($type instanceof Types\PhpIntegerMappingType) { + return ' DEFAULT ' . $default; + } + + if ($type instanceof Types\PhpDateTimeMappingType && $default === $this->getCurrentTimestampSQL()) { + return ' DEFAULT ' . $this->getCurrentTimestampSQL(); + } + + if ($type instanceof Types\TimeType && $default === $this->getCurrentTimeSQL()) { + return ' DEFAULT ' . $this->getCurrentTimeSQL(); + } + + if ($type instanceof Types\DateType && $default === $this->getCurrentDateSQL()) { + return ' DEFAULT ' . $this->getCurrentDateSQL(); + } + + if ($type instanceof Types\BooleanType) { + return " DEFAULT '" . $this->convertBooleans($default) . "'"; + } + + return ' DEFAULT ' . $this->quoteStringLiteral($default); + } + + /** + * Obtains DBMS specific SQL code portion needed to set a CHECK constraint + * declaration to be used in statements like CREATE TABLE. + * + * @param string[]|mixed[][] $definition The check definition. + * + * @return string DBMS specific SQL code portion needed to set a CHECK constraint. + */ + public function getCheckDeclarationSQL(array $definition) + { + $constraints = []; + foreach ($definition as $column => $def) { + if (is_string($def)) { + $constraints[] = 'CHECK (' . $def . ')'; + } else { + if (isset($def['min'])) { + $constraints[] = 'CHECK (' . $column . ' >= ' . $def['min'] . ')'; + } + + if (isset($def['max'])) { + $constraints[] = 'CHECK (' . $column . ' <= ' . $def['max'] . ')'; + } + } + } + + return implode(', ', $constraints); + } + + /** + * Obtains DBMS specific SQL code portion needed to set a unique + * constraint declaration to be used in statements like CREATE TABLE. + * + * @param string $name The name of the unique constraint. + * @param Index $index The index definition. + * + * @return string DBMS specific SQL code portion needed to set a constraint. + * + * @throws InvalidArgumentException + */ + public function getUniqueConstraintDeclarationSQL($name, Index $index) + { + $columns = $index->getColumns(); + $name = new Identifier($name); + + if (count($columns) === 0) { + throw new InvalidArgumentException("Incomplete definition. 'columns' required."); + } + + return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE (' + . $this->getIndexFieldDeclarationListSQL($index) + . ')' . $this->getPartialIndexSQL($index); + } + + /** + * Obtains DBMS specific SQL code portion needed to set an index + * declaration to be used in statements like CREATE TABLE. + * + * @param string $name The name of the index. + * @param Index $index The index definition. + * + * @return string DBMS specific SQL code portion needed to set an index. + * + * @throws InvalidArgumentException + */ + public function getIndexDeclarationSQL($name, Index $index) + { + $columns = $index->getColumns(); + $name = new Identifier($name); + + if (count($columns) === 0) { + throw new InvalidArgumentException("Incomplete definition. 'columns' required."); + } + + return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name->getQuotedName($this) . ' (' + . $this->getIndexFieldDeclarationListSQL($index) + . ')' . $this->getPartialIndexSQL($index); + } + + /** + * Obtains SQL code portion needed to create a custom column, + * e.g. when a column has the "columnDefinition" keyword. + * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate. + * + * @param mixed[] $column + * + * @return string + */ + public function getCustomTypeDeclarationSQL(array $column) + { + return $column['columnDefinition']; + } + + /** + * Obtains DBMS specific SQL code portion needed to set an index + * declaration to be used in statements like CREATE TABLE. + * + * @param mixed[]|Index $columnsOrIndex array declaration is deprecated, prefer passing Index to this method + */ + public function getIndexFieldDeclarationListSQL($columnsOrIndex): string + { + if ($columnsOrIndex instanceof Index) { + return implode(', ', $columnsOrIndex->getQuotedColumns($this)); + } + + if (! is_array($columnsOrIndex)) { + throw new InvalidArgumentException('Fields argument should be an Index or array.'); + } + + $ret = []; + + foreach ($columnsOrIndex as $column => $definition) { + if (is_array($definition)) { + $ret[] = $column; + } else { + $ret[] = $definition; + } + } + + return implode(', ', $ret); + } + + /** + * Returns the required SQL string that fits between CREATE ... TABLE + * to create the table as a temporary table. + * + * Should be overridden in driver classes to return the correct string for the + * specific database type. + * + * The default is to return the string "TEMPORARY" - this will result in a + * SQL error for any database that does not support temporary tables, or that + * requires a different SQL command from "CREATE TEMPORARY TABLE". + * + * @return string The string required to be placed between "CREATE" and "TABLE" + * to generate a temporary table, if possible. + */ + public function getTemporaryTableSQL() + { + return 'TEMPORARY'; + } + + /** + * Some vendors require temporary table names to be qualified specially. + * + * @param string $tableName + * + * @return string + */ + public function getTemporaryTableName($tableName) + { + return $tableName; + } + + /** + * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint + * of a column declaration to be used in statements like CREATE TABLE. + * + * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint + * of a column declaration. + */ + public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) + { + $sql = $this->getForeignKeyBaseDeclarationSQL($foreignKey); + $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey); + + return $sql; + } + + /** + * Returns the FOREIGN KEY query section dealing with non-standard options + * as MATCH, INITIALLY DEFERRED, ON UPDATE, ... + * + * @param ForeignKeyConstraint $foreignKey The foreign key definition. + * + * @return string + */ + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + { + $query = ''; + if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) { + $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate')); + } + + if ($foreignKey->hasOption('onDelete')) { + $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete')); + } + + return $query; + } + + /** + * Returns the given referential action in uppercase if valid, otherwise throws an exception. + * + * @param string $action The foreign key referential action. + * + * @return string + * + * @throws InvalidArgumentException If unknown referential action given. + */ + public function getForeignKeyReferentialActionSQL($action) + { + $upper = strtoupper($action); + switch ($upper) { + case 'CASCADE': + case 'SET NULL': + case 'NO ACTION': + case 'RESTRICT': + case 'SET DEFAULT': + return $upper; + + default: + throw new InvalidArgumentException('Invalid foreign key action: ' . $upper); + } + } + + /** + * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint + * of a column declaration to be used in statements like CREATE TABLE. + * + * @return string + * + * @throws InvalidArgumentException + */ + public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey) + { + $sql = ''; + if (strlen($foreignKey->getName())) { + $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' '; + } + + $sql .= 'FOREIGN KEY ('; + + if (count($foreignKey->getLocalColumns()) === 0) { + throw new InvalidArgumentException("Incomplete definition. 'local' required."); + } + + if (count($foreignKey->getForeignColumns()) === 0) { + throw new InvalidArgumentException("Incomplete definition. 'foreign' required."); + } + + if (strlen($foreignKey->getForeignTableName()) === 0) { + throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required."); + } + + return $sql . implode(', ', $foreignKey->getQuotedLocalColumns($this)) + . ') REFERENCES ' + . $foreignKey->getQuotedForeignTableName($this) . ' (' + . implode(', ', $foreignKey->getQuotedForeignColumns($this)) . ')'; + } + + /** + * Obtains DBMS specific SQL code portion needed to set the UNIQUE constraint + * of a column declaration to be used in statements like CREATE TABLE. + * + * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint + * of a column declaration. + */ + public function getUniqueFieldDeclarationSQL() + { + return 'UNIQUE'; + } + + /** + * Obtains DBMS specific SQL code portion needed to set the CHARACTER SET + * of a column declaration to be used in statements like CREATE TABLE. + * + * @param string $charset The name of the charset. + * + * @return string DBMS specific SQL code portion needed to set the CHARACTER SET + * of a column declaration. + */ + public function getColumnCharsetDeclarationSQL($charset) + { + return ''; + } + + /** + * Obtains DBMS specific SQL code portion needed to set the COLLATION + * of a column declaration to be used in statements like CREATE TABLE. + * + * @param string $collation The name of the collation. + * + * @return string DBMS specific SQL code portion needed to set the COLLATION + * of a column declaration. + */ + public function getColumnCollationDeclarationSQL($collation) + { + return $this->supportsColumnCollation() ? 'COLLATE ' . $collation : ''; + } + + /** + * Whether the platform prefers sequences for ID generation. + * Subclasses should override this method to return TRUE if they prefer sequences. + * + * @deprecated + * + * @return bool + */ + public function prefersSequences() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4229', + 'AbstractPlatform::prefersSequences() is deprecated without replacement and removed in DBAL 3.0' + ); + + return false; + } + + /** + * Whether the platform prefers identity columns (eg. autoincrement) for ID generation. + * Subclasses should override this method to return TRUE if they prefer identity columns. + * + * @return bool + */ + public function prefersIdentityColumns() + { + return false; + } + + /** + * Some platforms need the boolean values to be converted. + * + * The default conversion in this implementation converts to integers (false => 0, true => 1). + * + * Note: if the input is not a boolean the original input might be returned. + * + * There are two contexts when converting booleans: Literals and Prepared Statements. + * This method should handle the literal case + * + * @param mixed $item A boolean or an array of them. + * + * @return mixed A boolean database value or an array of them. + */ + public function convertBooleans($item) + { + if (is_array($item)) { + foreach ($item as $k => $value) { + if (! is_bool($value)) { + continue; + } + + $item[$k] = (int) $value; + } + } elseif (is_bool($item)) { + $item = (int) $item; + } + + return $item; + } + + /** + * Some platforms have boolean literals that needs to be correctly converted + * + * The default conversion tries to convert value into bool "(bool)$item" + * + * @param mixed $item + * + * @return bool|null + */ + public function convertFromBoolean($item) + { + return $item === null ? null : (bool) $item; + } + + /** + * This method should handle the prepared statements case. When there is no + * distinction, it's OK to use the same method. + * + * Note: if the input is not a boolean the original input might be returned. + * + * @param mixed $item A boolean or an array of them. + * + * @return mixed A boolean database value or an array of them. + */ + public function convertBooleansToDatabaseValue($item) + { + return $this->convertBooleans($item); + } + + /** + * Returns the SQL specific for the platform to get the current date. + * + * @return string + */ + public function getCurrentDateSQL() + { + return 'CURRENT_DATE'; + } + + /** + * Returns the SQL specific for the platform to get the current time. + * + * @return string + */ + public function getCurrentTimeSQL() + { + return 'CURRENT_TIME'; + } + + /** + * Returns the SQL specific for the platform to get the current timestamp + * + * @return string + */ + public function getCurrentTimestampSQL() + { + return 'CURRENT_TIMESTAMP'; + } + + /** + * Returns the SQL for a given transaction isolation level Connection constant. + * + * @param int $level + * + * @return string + * + * @throws InvalidArgumentException + */ + protected function _getTransactionIsolationLevelSQL($level) + { + switch ($level) { + case TransactionIsolationLevel::READ_UNCOMMITTED: + return 'READ UNCOMMITTED'; + + case TransactionIsolationLevel::READ_COMMITTED: + return 'READ COMMITTED'; + + case TransactionIsolationLevel::REPEATABLE_READ: + return 'REPEATABLE READ'; + + case TransactionIsolationLevel::SERIALIZABLE: + return 'SERIALIZABLE'; + + default: + throw new InvalidArgumentException('Invalid isolation level:' . $level); + } + } + + /** + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getListDatabasesSQL() + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the SQL statement for retrieving the namespaces defined in the database. + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getListNamespacesSQL() + { + throw Exception::notSupported(__METHOD__); + } + + /** + * @param string $database + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getListSequencesSQL($database) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * @param string $table + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getListTableConstraintsSQL($table) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * @param string $table + * @param string $database + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getListTableColumnsSQL($table, $database = null) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getListTablesSQL() + { + throw Exception::notSupported(__METHOD__); + } + + /** + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getListUsersSQL() + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the SQL to list all views of a database or user. + * + * @param string $database + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getListViewsSQL($database) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the list of indexes for the current database. + * + * The current database parameter is optional but will always be passed + * when using the SchemaManager API and is the database the given table is in. + * + * Attention: Some platforms only support currentDatabase when they + * are connected with that database. Cross-database information schema + * requests may be impossible. + * + * @param string $table + * @param string $database + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getListTableIndexesSQL($table, $database = null) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * @param string $table + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getListTableForeignKeysSQL($table) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * @param string $name + * @param string $sql + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getCreateViewSQL($name, $sql) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * @param string $name + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDropViewSQL($name) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the SQL snippet to drop an existing sequence. + * + * @param Sequence|string $sequence + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDropSequenceSQL($sequence) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * @param string $sequence + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getSequenceNextValSQL($sequence) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the SQL to create a new database. + * + * @param string $name The name of the database that should be created. + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getCreateDatabaseSQL($name) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Returns the SQL to set the transaction isolation level. + * + * @param int $level + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getSetTransactionIsolationSQL($level) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Obtains DBMS specific SQL to be used to create datetime columns in + * statements like CREATE TABLE. + * + * @param mixed[] $column + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateTimeTypeDeclarationSQL(array $column) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Obtains DBMS specific SQL to be used to create datetime with timezone offset columns. + * + * @param mixed[] $column + * + * @return string + */ + public function getDateTimeTzTypeDeclarationSQL(array $column) + { + return $this->getDateTimeTypeDeclarationSQL($column); + } + + /** + * Obtains DBMS specific SQL to be used to create date columns in statements + * like CREATE TABLE. + * + * @param mixed[] $column + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDateTypeDeclarationSQL(array $column) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Obtains DBMS specific SQL to be used to create time columns in statements + * like CREATE TABLE. + * + * @param mixed[] $column + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getTimeTypeDeclarationSQL(array $column) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * @param mixed[] $column + * + * @return string + */ + public function getFloatDeclarationSQL(array $column) + { + return 'DOUBLE PRECISION'; + } + + /** + * Gets the default transaction isolation level of the platform. + * + * @see TransactionIsolationLevel + * + * @return int The default isolation level. + */ + public function getDefaultTransactionIsolationLevel() + { + return TransactionIsolationLevel::READ_COMMITTED; + } + + /* supports*() methods */ + + /** + * Whether the platform supports sequences. + * + * @return bool + */ + public function supportsSequences() + { + return false; + } + + /** + * Whether the platform supports identity columns. + * + * Identity columns are columns that receive an auto-generated value from the + * database on insert of a row. + * + * @return bool + */ + public function supportsIdentityColumns() + { + return false; + } + + /** + * Whether the platform emulates identity columns through sequences. + * + * Some platforms that do not support identity columns natively + * but support sequences can emulate identity columns by using + * sequences. + * + * @return bool + */ + public function usesSequenceEmulatedIdentityColumns() + { + return false; + } + + /** + * Returns the name of the sequence for a particular identity column in a particular table. + * + * @see usesSequenceEmulatedIdentityColumns + * + * @param string $tableName The name of the table to return the sequence name for. + * @param string $columnName The name of the identity column in the table to return the sequence name for. + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getIdentitySequenceName($tableName, $columnName) + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Whether the platform supports indexes. + * + * @return bool + */ + public function supportsIndexes() + { + return true; + } + + /** + * Whether the platform supports partial indexes. + * + * @return bool + */ + public function supportsPartialIndexes() + { + return false; + } + + /** + * Whether the platform supports indexes with column length definitions. + */ + public function supportsColumnLengthIndexes(): bool + { + return false; + } + + /** + * Whether the platform supports altering tables. + * + * @return bool + */ + public function supportsAlterTable() + { + return true; + } + + /** + * Whether the platform supports transactions. + * + * @return bool + */ + public function supportsTransactions() + { + return true; + } + + /** + * Whether the platform supports savepoints. + * + * @return bool + */ + public function supportsSavepoints() + { + return true; + } + + /** + * Whether the platform supports releasing savepoints. + * + * @return bool + */ + public function supportsReleaseSavepoints() + { + return $this->supportsSavepoints(); + } + + /** + * Whether the platform supports primary key constraints. + * + * @return bool + */ + public function supportsPrimaryConstraints() + { + return true; + } + + /** + * Whether the platform supports foreign key constraints. + * + * @return bool + */ + public function supportsForeignKeyConstraints() + { + return true; + } + + /** + * Whether this platform supports onUpdate in foreign key constraints. + * + * @deprecated + * + * @return bool + */ + public function supportsForeignKeyOnUpdate() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4229', + 'AbstractPlatform::supportsForeignKeyOnUpdate() is deprecated without replacement and removed in DBAL 3.0' + ); + + return $this->supportsForeignKeyConstraints(); + } + + /** + * Whether the platform supports database schemas. + * + * @return bool + */ + public function supportsSchemas() + { + return false; + } + + /** + * Whether this platform can emulate schemas. + * + * Platforms that either support or emulate schemas don't automatically + * filter a schema for the namespaced elements in {@link AbstractManager::createSchema()}. + * + * @return bool + */ + public function canEmulateSchemas() + { + return false; + } + + /** + * Returns the default schema name. + * + * @return string + * + * @throws Exception If not supported on this platform. + */ + public function getDefaultSchemaName() + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Whether this platform supports create database. + * + * Some databases don't allow to create and drop databases at all or only with certain tools. + * + * @return bool + */ + public function supportsCreateDropDatabase() + { + return true; + } + + /** + * Whether the platform supports getting the affected rows of a recent update/delete type query. + * + * @return bool + */ + public function supportsGettingAffectedRows() + { + return true; + } + + /** + * Whether this platform support to add inline column comments as postfix. + * + * @return bool + */ + public function supportsInlineColumnComments() + { + return false; + } + + /** + * Whether this platform support the proprietary syntax "COMMENT ON asset". + * + * @return bool + */ + public function supportsCommentOnStatement() + { + return false; + } + + /** + * Does this platform have native guid type. + * + * @return bool + */ + public function hasNativeGuidType() + { + return false; + } + + /** + * Does this platform have native JSON type. + * + * @return bool + */ + public function hasNativeJsonType() + { + return false; + } + + /** + * @deprecated + * + * @return string + * + * @todo Remove in 3.0 + */ + public function getIdentityColumnNullInsertSQL() + { + return ''; + } + + /** + * Whether this platform supports views. + * + * @return bool + */ + public function supportsViews() + { + return true; + } + + /** + * Does this platform support column collation? + * + * @return bool + */ + public function supportsColumnCollation() + { + return false; + } + + /** + * Gets the format string, as accepted by the date() function, that describes + * the format of a stored datetime value of this platform. + * + * @return string The format string. + */ + public function getDateTimeFormatString() + { + return 'Y-m-d H:i:s'; + } + + /** + * Gets the format string, as accepted by the date() function, that describes + * the format of a stored datetime with timezone value of this platform. + * + * @return string The format string. + */ + public function getDateTimeTzFormatString() + { + return 'Y-m-d H:i:s'; + } + + /** + * Gets the format string, as accepted by the date() function, that describes + * the format of a stored date value of this platform. + * + * @return string The format string. + */ + public function getDateFormatString() + { + return 'Y-m-d'; + } + + /** + * Gets the format string, as accepted by the date() function, that describes + * the format of a stored time value of this platform. + * + * @return string The format string. + */ + public function getTimeFormatString() + { + return 'H:i:s'; + } + + /** + * Adds an driver-specific LIMIT clause to the query. + * + * @param string $query + * @param int|null $limit + * @param int|null $offset + * + * @return string + * + * @throws Exception + */ + final public function modifyLimitQuery($query, $limit, $offset = null) + { + if ($limit !== null) { + $limit = (int) $limit; + } + + $offset = (int) $offset; + + if ($offset < 0) { + throw new Exception(sprintf( + 'Offset must be a positive integer or zero, %d given', + $offset + )); + } + + if ($offset > 0 && ! $this->supportsLimitOffset()) { + throw new Exception(sprintf( + 'Platform %s does not support offset values in limit queries.', + $this->getName() + )); + } + + return $this->doModifyLimitQuery($query, $limit, $offset); + } + + /** + * Adds an platform-specific LIMIT clause to the query. + * + * @param string $query + * @param int|null $limit + * @param int|null $offset + * + * @return string + */ + protected function doModifyLimitQuery($query, $limit, $offset) + { + if ($limit !== null) { + $query .= ' LIMIT ' . $limit; + } + + if ($offset > 0) { + $query .= ' OFFSET ' . $offset; + } + + return $query; + } + + /** + * Whether the database platform support offsets in modify limit clauses. + * + * @return bool + */ + public function supportsLimitOffset() + { + return true; + } + + /** + * Gets the character casing of a column in an SQL result set of this platform. + * + * @deprecated + * + * @param string $column The column name for which to get the correct character casing. + * + * @return string The column name in the character casing used in SQL result sets. + */ + public function getSQLResultCasing($column) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4229', + 'AbstractPlatform::getSQLResultCasing is deprecated without replacement and removed in DBAL 3.' . + 'Use Portability\Connection with PORTABILITY_FIX_CASE to get portable result cases.' + ); + + return $column; + } + + /** + * Makes any fixes to a name of a schema element (table, sequence, ...) that are required + * by restrictions of the platform, like a maximum length. + * + * @deprecated + * + * @param string $schemaElementName + * + * @return string + */ + public function fixSchemaElementName($schemaElementName) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4132', + 'AbstractPlatform::fixSchemaElementName is deprecated with no replacement and removed in DBAL 3.0' + ); + + return $schemaElementName; + } + + /** + * Maximum length of any given database identifier, like tables or column names. + * + * @return int + */ + public function getMaxIdentifierLength() + { + return 63; + } + + /** + * Returns the insert SQL for an empty insert statement. + * + * @param string $quotedTableName + * @param string $quotedIdentifierColumnName + * + * @return string + */ + public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) + { + return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (null)'; + } + + /** + * Generates a Truncate Table SQL statement for a given table. + * + * Cascade is not supported on many platforms but would optionally cascade the truncate by + * following the foreign keys. + * + * @param string $tableName + * @param bool $cascade + * + * @return string + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + $tableIdentifier = new Identifier($tableName); + + return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this); + } + + /** + * This is for test reasons, many vendors have special requirements for dummy statements. + * + * @return string + */ + public function getDummySelectSQL() + { + $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; + + return sprintf('SELECT %s', $expression); + } + + /** + * Returns the SQL to create a new savepoint. + * + * @param string $savepoint + * + * @return string + */ + public function createSavePoint($savepoint) + { + return 'SAVEPOINT ' . $savepoint; + } + + /** + * Returns the SQL to release a savepoint. + * + * @param string $savepoint + * + * @return string + */ + public function releaseSavePoint($savepoint) + { + return 'RELEASE SAVEPOINT ' . $savepoint; + } + + /** + * Returns the SQL to rollback a savepoint. + * + * @param string $savepoint + * + * @return string + */ + public function rollbackSavePoint($savepoint) + { + return 'ROLLBACK TO SAVEPOINT ' . $savepoint; + } + + /** + * Returns the keyword list instance of this platform. + * + * @return KeywordList + * + * @throws Exception If no keyword list is specified. + */ + final public function getReservedKeywordsList() + { + // Check for an existing instantiation of the keywords class. + if ($this->_keywords) { + return $this->_keywords; + } + + $class = $this->getReservedKeywordsClass(); + $keywords = new $class(); + if (! $keywords instanceof KeywordList) { + throw Exception::notSupported(__METHOD__); + } + + // Store the instance so it doesn't need to be generated on every request. + $this->_keywords = $keywords; + + return $keywords; + } + + /** + * Returns the class name of the reserved keywords list. + * + * @return string + * @psalm-return class-string + * + * @throws Exception If not supported on this platform. + */ + protected function getReservedKeywordsClass() + { + throw Exception::notSupported(__METHOD__); + } + + /** + * Quotes a literal string. + * This method is NOT meant to fix SQL injections! + * It is only meant to escape this platform's string literal + * quote character inside the given literal string. + * + * @param string $str The literal string to be quoted. + * + * @return string The quoted literal string. + */ + public function quoteStringLiteral($str) + { + $c = $this->getStringLiteralQuoteCharacter(); + + return $c . str_replace($c, $c . $c, $str) . $c; + } + + /** + * Gets the character used for string literal quoting. + * + * @return string + */ + public function getStringLiteralQuoteCharacter() + { + return "'"; + } + + /** + * Escapes metacharacters in a string intended to be used with a LIKE + * operator. + * + * @param string $inputString a literal, unquoted string + * @param string $escapeChar should be reused by the caller in the LIKE + * expression. + */ + final public function escapeStringForLike(string $inputString, string $escapeChar): string + { + return preg_replace( + '~([' . preg_quote($this->getLikeWildcardCharacters() . $escapeChar, '~') . '])~u', + addcslashes($escapeChar, '\\') . '$1', + $inputString + ); + } + + protected function getLikeWildcardCharacters(): string + { + return '%_'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DB2Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DB2Platform.php new file mode 100755 index 0000000..28f76ca --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DB2Platform.php @@ -0,0 +1,925 @@ +getCharMaxLength(); + } + + return parent::getVarcharTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $column) + { + // todo blob(n) with $column['length']; + return 'BLOB(1M)'; + } + + /** + * {@inheritDoc} + */ + public function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = [ + 'smallint' => 'smallint', + 'bigint' => 'bigint', + 'integer' => 'integer', + 'time' => 'time', + 'date' => 'date', + 'varchar' => 'string', + 'character' => 'string', + 'varbinary' => 'binary', + 'binary' => 'binary', + 'clob' => 'text', + 'blob' => 'blob', + 'decimal' => 'decimal', + 'double' => 'float', + 'real' => 'float', + 'timestamp' => 'datetime', + ]; + } + + /** + * {@inheritdoc} + */ + public function isCommentedDoctrineType(Type $doctrineType) + { + if ($doctrineType->getName() === Types::BOOLEAN) { + // We require a commented boolean type in order to distinguish between boolean and smallint + // as both (have to) map to the same native type. + return true; + } + + return parent::isCommentedDoctrineType($doctrineType); + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(254)') + : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); + } + + /** + * {@inheritdoc} + */ + protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + { + return $this->getVarcharTypeDeclarationSQLSnippet($length, $fixed) . ' FOR BIT DATA'; + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $column) + { + // todo clob(n) with $column['length']; + return 'CLOB(1M)'; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'db2'; + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $column) + { + return 'SMALLINT'; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $column) + { + return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $column) + { + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $column) + { + return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $column) + { + $autoinc = ''; + if (! empty($column['autoincrement'])) { + $autoinc = ' GENERATED BY DEFAULT AS IDENTITY'; + } + + return $autoinc; + } + + /** + * {@inheritdoc} + */ + public function getBitAndComparisonExpression($value1, $value2) + { + return 'BITAND(' . $value1 . ', ' . $value2 . ')'; + } + + /** + * {@inheritdoc} + */ + public function getBitOrComparisonExpression($value1, $value2) + { + return 'BITOR(' . $value1 . ', ' . $value2 . ')'; + } + + /** + * {@inheritdoc} + */ + protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + { + switch ($unit) { + case DateIntervalUnit::WEEK: + $interval *= 7; + $unit = DateIntervalUnit::DAY; + break; + + case DateIntervalUnit::QUARTER: + $interval *= 3; + $unit = DateIntervalUnit::MONTH; + break; + } + + return $date . ' ' . $operator . ' ' . $interval . ' ' . $unit; + } + + /** + * {@inheritdoc} + */ + public function getDateDiffExpression($date1, $date2) + { + return 'DAYS(' . $date1 . ') - DAYS(' . $date2 . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $column) + { + if (isset($column['version']) && $column['version'] === true) { + return 'TIMESTAMP(0) WITH DEFAULT'; + } + + return 'TIMESTAMP(0)'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $column) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $column) + { + return 'TIME'; + } + + /** + * {@inheritdoc} + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + $tableIdentifier = new Identifier($tableName); + + return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this) . ' IMMEDIATE'; + } + + /** + * This code fragment is originally from the Zend_Db_Adapter_Db2 class, but has been edited. + * + * @param string $table + * @param string $database + * + * @return string + */ + public function getListTableColumnsSQL($table, $database = null) + { + $table = $this->quoteStringLiteral($table); + + // We do the funky subquery and join syscat.columns.default this crazy way because + // as of db2 v10, the column is CLOB(64k) and the distinct operator won't allow a CLOB, + // it wants shorter stuff like a varchar. + return " + SELECT + cols.default, + subq.* + FROM ( + SELECT DISTINCT + c.tabschema, + c.tabname, + c.colname, + c.colno, + c.typename, + c.nulls, + c.length, + c.scale, + c.identity, + tc.type AS tabconsttype, + c.remarks AS comment, + k.colseq, + CASE + WHEN c.generated = 'D' THEN 1 + ELSE 0 + END AS autoincrement + FROM syscat.columns c + LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc + ON (k.tabschema = tc.tabschema + AND k.tabname = tc.tabname + AND tc.type = 'P')) + ON (c.tabschema = k.tabschema + AND c.tabname = k.tabname + AND c.colname = k.colname) + WHERE UPPER(c.tabname) = UPPER(" . $table . ') + ORDER BY c.colno + ) subq + JOIN syscat.columns cols + ON subq.tabschema = cols.tabschema + AND subq.tabname = cols.tabname + AND subq.colno = cols.colno + ORDER BY subq.colno + '; + } + + /** + * {@inheritDoc} + */ + public function getListTablesSQL() + { + return "SELECT NAME FROM SYSIBM.SYSTABLES WHERE TYPE = 'T'"; + } + + /** + * {@inheritDoc} + */ + public function getListViewsSQL($database) + { + return 'SELECT NAME, TEXT FROM SYSIBM.SYSVIEWS'; + } + + /** + * {@inheritDoc} + */ + public function getListTableIndexesSQL($table, $database = null) + { + $table = $this->quoteStringLiteral($table); + + return "SELECT idx.INDNAME AS key_name, + idxcol.COLNAME AS column_name, + CASE + WHEN idx.UNIQUERULE = 'P' THEN 1 + ELSE 0 + END AS primary, + CASE + WHEN idx.UNIQUERULE = 'D' THEN 1 + ELSE 0 + END AS non_unique + FROM SYSCAT.INDEXES AS idx + JOIN SYSCAT.INDEXCOLUSE AS idxcol + ON idx.INDSCHEMA = idxcol.INDSCHEMA AND idx.INDNAME = idxcol.INDNAME + WHERE idx.TABNAME = UPPER(" . $table . ') + ORDER BY idxcol.COLSEQ ASC'; + } + + /** + * {@inheritDoc} + */ + public function getListTableForeignKeysSQL($table) + { + $table = $this->quoteStringLiteral($table); + + return "SELECT fkcol.COLNAME AS local_column, + fk.REFTABNAME AS foreign_table, + pkcol.COLNAME AS foreign_column, + fk.CONSTNAME AS index_name, + CASE + WHEN fk.UPDATERULE = 'R' THEN 'RESTRICT' + ELSE NULL + END AS on_update, + CASE + WHEN fk.DELETERULE = 'C' THEN 'CASCADE' + WHEN fk.DELETERULE = 'N' THEN 'SET NULL' + WHEN fk.DELETERULE = 'R' THEN 'RESTRICT' + ELSE NULL + END AS on_delete + FROM SYSCAT.REFERENCES AS fk + JOIN SYSCAT.KEYCOLUSE AS fkcol + ON fk.CONSTNAME = fkcol.CONSTNAME + AND fk.TABSCHEMA = fkcol.TABSCHEMA + AND fk.TABNAME = fkcol.TABNAME + JOIN SYSCAT.KEYCOLUSE AS pkcol + ON fk.REFKEYNAME = pkcol.CONSTNAME + AND fk.REFTABSCHEMA = pkcol.TABSCHEMA + AND fk.REFTABNAME = pkcol.TABNAME + WHERE fk.TABNAME = UPPER(" . $table . ') + ORDER BY fkcol.COLSEQ ASC'; + } + + /** + * {@inheritDoc} + */ + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + /** + * {@inheritDoc} + */ + public function getDropViewSQL($name) + { + return 'DROP VIEW ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getCreateDatabaseSQL($name) + { + return 'CREATE DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getDropDatabaseSQL($name) + { + return 'DROP DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + public function supportsCreateDropDatabase() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function supportsReleaseSavepoints() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function supportsCommentOnStatement() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getCurrentDateSQL() + { + return 'CURRENT DATE'; + } + + /** + * {@inheritDoc} + */ + public function getCurrentTimeSQL() + { + return 'CURRENT TIME'; + } + + /** + * {@inheritDoc} + */ + public function getCurrentTimestampSQL() + { + return 'CURRENT TIMESTAMP'; + } + + /** + * {@inheritDoc} + */ + public function getIndexDeclarationSQL($name, Index $index) + { + // Index declaration in statements like CREATE TABLE is not supported. + throw Exception::notSupported(__METHOD__); + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($name, array $columns, array $options = []) + { + $indexes = []; + if (isset($options['indexes'])) { + $indexes = $options['indexes']; + } + + $options['indexes'] = []; + + $sqls = parent::_getCreateTableSQL($name, $columns, $options); + + foreach ($indexes as $definition) { + $sqls[] = $this->getCreateIndexSQL($definition, $name); + } + + return $sqls; + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $sql = []; + $columnSql = []; + $commentsSQL = []; + + $queryParts = []; + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $columnDef = $column->toArray(); + $queryPart = 'ADD COLUMN ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnDef); + + // Adding non-nullable columns to a table requires a default value to be specified. + if ( + ! empty($columnDef['notnull']) && + ! isset($columnDef['default']) && + empty($columnDef['autoincrement']) + ) { + $queryPart .= ' WITH DEFAULT'; + } + + $queryParts[] = $queryPart; + + $comment = $this->getColumnComment($column); + + if ($comment === null || $comment === '') { + continue; + } + + $commentsSQL[] = $this->getCommentOnColumnSQL( + $diff->getName($this)->getQuotedName($this), + $column->getQuotedName($this), + $comment + ); + } + + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $queryParts[] = 'DROP COLUMN ' . $column->getQuotedName($this); + } + + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + if ($columnDiff->hasChanged('comment')) { + $commentsSQL[] = $this->getCommentOnColumnSQL( + $diff->getName($this)->getQuotedName($this), + $columnDiff->column->getQuotedName($this), + $this->getColumnComment($columnDiff->column) + ); + + if (count($columnDiff->changedProperties) === 1) { + continue; + } + } + + $this->gatherAlterColumnSQL($diff->getName($this), $columnDiff, $sql, $queryParts); + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $oldColumnName = new Identifier($oldColumnName); + + $queryParts[] = 'RENAME COLUMN ' . $oldColumnName->getQuotedName($this) . + ' TO ' . $column->getQuotedName($this); + } + + $tableSql = []; + + if (! $this->onSchemaAlterTable($diff, $tableSql)) { + if (count($queryParts) > 0) { + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . implode(' ', $queryParts); + } + + // Some table alteration operations require a table reorganization. + if (! empty($diff->removedColumns) || ! empty($diff->changedColumns)) { + $sql[] = "CALL SYSPROC.ADMIN_CMD ('REORG TABLE " . $diff->getName($this)->getQuotedName($this) . "')"; + } + + $sql = array_merge($sql, $commentsSQL); + + $newName = $diff->getNewName(); + + if ($newName !== false) { + $sql[] = sprintf( + 'RENAME TABLE %s TO %s', + $diff->getName($this)->getQuotedName($this), + $newName->getQuotedName($this) + ); + } + + $sql = array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * Gathers the table alteration SQL for a given column diff. + * + * @param Identifier $table The table to gather the SQL for. + * @param ColumnDiff $columnDiff The column diff to evaluate. + * @param string[] $sql The sequence of table alteration statements to fill. + * @param mixed[] $queryParts The sequence of column alteration clauses to fill. + */ + private function gatherAlterColumnSQL( + Identifier $table, + ColumnDiff $columnDiff, + array &$sql, + array &$queryParts + ): void { + $alterColumnClauses = $this->getAlterColumnClausesSQL($columnDiff); + + if (empty($alterColumnClauses)) { + return; + } + + // If we have a single column alteration, we can append the clause to the main query. + if (count($alterColumnClauses) === 1) { + $queryParts[] = current($alterColumnClauses); + + return; + } + + // We have multiple alterations for the same column, + // so we need to trigger a complete ALTER TABLE statement + // for each ALTER COLUMN clause. + foreach ($alterColumnClauses as $alterColumnClause) { + $sql[] = 'ALTER TABLE ' . $table->getQuotedName($this) . ' ' . $alterColumnClause; + } + } + + /** + * Returns the ALTER COLUMN SQL clauses for altering a column described by the given column diff. + * + * @param ColumnDiff $columnDiff The column diff to evaluate. + * + * @return string[] + */ + private function getAlterColumnClausesSQL(ColumnDiff $columnDiff) + { + $column = $columnDiff->column->toArray(); + + $alterClause = 'ALTER COLUMN ' . $columnDiff->column->getQuotedName($this); + + if ($column['columnDefinition']) { + return [$alterClause . ' ' . $column['columnDefinition']]; + } + + $clauses = []; + + if ( + $columnDiff->hasChanged('type') || + $columnDiff->hasChanged('length') || + $columnDiff->hasChanged('precision') || + $columnDiff->hasChanged('scale') || + $columnDiff->hasChanged('fixed') + ) { + $clauses[] = $alterClause . ' SET DATA TYPE ' . $column['type']->getSQLDeclaration($column, $this); + } + + if ($columnDiff->hasChanged('notnull')) { + $clauses[] = $column['notnull'] ? $alterClause . ' SET NOT NULL' : $alterClause . ' DROP NOT NULL'; + } + + if ($columnDiff->hasChanged('default')) { + if (isset($column['default'])) { + $defaultClause = $this->getDefaultValueDeclarationSQL($column); + + if ($defaultClause) { + $clauses[] = $alterClause . ' SET' . $defaultClause; + } + } else { + $clauses[] = $alterClause . ' DROP DEFAULT'; + } + } + + return $clauses; + } + + /** + * {@inheritDoc} + */ + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + { + $sql = []; + $table = $diff->getName($this)->getQuotedName($this); + + foreach ($diff->removedIndexes as $remKey => $remIndex) { + foreach ($diff->addedIndexes as $addKey => $addIndex) { + if ($remIndex->getColumns() !== $addIndex->getColumns()) { + continue; + } + + if ($remIndex->isPrimary()) { + $sql[] = 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; + } elseif ($remIndex->isUnique()) { + $sql[] = 'ALTER TABLE ' . $table . ' DROP UNIQUE ' . $remIndex->getQuotedName($this); + } else { + $sql[] = $this->getDropIndexSQL($remIndex, $table); + } + + $sql[] = $this->getCreateIndexSQL($addIndex, $table); + + unset($diff->removedIndexes[$remKey], $diff->addedIndexes[$addKey]); + + break; + } + } + + $sql = array_merge($sql, parent::getPreAlterTableIndexForeignKeySQL($diff)); + + return $sql; + } + + /** + * {@inheritdoc} + */ + protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + { + if (strpos($tableName, '.') !== false) { + [$schema] = explode('.', $tableName); + $oldIndexName = $schema . '.' . $oldIndexName; + } + + return ['RENAME INDEX ' . $oldIndexName . ' TO ' . $index->getQuotedName($this)]; + } + + /** + * {@inheritDoc} + */ + public function getDefaultValueDeclarationSQL($column) + { + if (! empty($column['autoincrement'])) { + return ''; + } + + if (isset($column['version']) && $column['version']) { + if ((string) $column['type'] !== 'DateTime') { + $column['default'] = '1'; + } + } + + return parent::getDefaultValueDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) + { + return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (DEFAULT)'; + } + + /** + * {@inheritDoc} + */ + public function getCreateTemporaryTableSnippetSQL() + { + return 'DECLARE GLOBAL TEMPORARY TABLE'; + } + + /** + * {@inheritDoc} + */ + public function getTemporaryTableName($tableName) + { + return 'SESSION.' . $tableName; + } + + /** + * {@inheritDoc} + */ + protected function doModifyLimitQuery($query, $limit, $offset = null) + { + $where = []; + + if ($offset > 0) { + $where[] = sprintf('db22.DC_ROWNUM >= %d', $offset + 1); + } + + if ($limit !== null) { + $where[] = sprintf('db22.DC_ROWNUM <= %d', $offset + $limit); + } + + if (empty($where)) { + return $query; + } + + // Todo OVER() needs ORDER BY data! + return sprintf( + 'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (%s) db21) db22 WHERE %s', + $query, + implode(' AND ', $where) + ); + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos === false) { + return 'LOCATE(' . $substr . ', ' . $str . ')'; + } + + return 'LOCATE(' . $substr . ', ' . $str . ', ' . $startPos . ')'; + } + + /** + * {@inheritDoc} + */ + public function getSubstringExpression($string, $start, $length = null) + { + if ($length === null) { + return 'SUBSTR(' . $string . ', ' . $start . ')'; + } + + return 'SUBSTR(' . $string . ', ' . $start . ', ' . $length . ')'; + } + + /** + * {@inheritDoc} + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function prefersIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + * + * DB2 returns all column names in SQL result sets in uppercase. + * + * @deprecated + */ + public function getSQLResultCasing($column) + { + return strtoupper($column); + } + + /** + * {@inheritDoc} + */ + public function getForUpdateSQL() + { + return ' WITH RR USE AND KEEP UPDATE LOCKS'; + } + + /** + * {@inheritDoc} + */ + public function getDummySelectSQL() + { + $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; + + return sprintf('SELECT %s FROM sysibm.sysdummy1', $expression); + } + + /** + * {@inheritDoc} + * + * DB2 supports savepoints, but they work semantically different than on other vendor platforms. + * + * TODO: We have to investigate how to get DB2 up and running with savepoints. + */ + public function supportsSavepoints() + { + return false; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return Keywords\DB2Keywords::class; + } + + public function getListTableCommentsSQL(string $table): string + { + return sprintf( + <<<'SQL' +SELECT REMARKS + FROM SYSIBM.SYSTABLES + WHERE NAME = UPPER( %s ) +SQL + , + $this->quoteStringLiteral($table) + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DateIntervalUnit.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DateIntervalUnit.php new file mode 100755 index 0000000..c1f3ca5 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DateIntervalUnit.php @@ -0,0 +1,31 @@ +_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $column) + { + $autoinc = ''; + if (! empty($column['autoincrement'])) { + $autoinc = ' AUTO_INCREMENT'; + } + + return $autoinc; + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $column) + { + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $column) + { + return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'; + } + + /** + * {@inheritdoc} + */ + protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + { + return 'VARBINARY(' . ($length ?: 255) . ')'; + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = [ + 'boolean' => 'boolean', + 'varchar' => 'string', + 'varbinary' => 'binary', + 'integer' => 'integer', + 'blob' => 'blob', + 'decimal' => 'decimal', + 'datetime' => 'datetime', + 'date' => 'date', + 'time' => 'time', + 'text' => 'text', + 'timestamp' => 'datetime', + 'double' => 'float', + 'bigint' => 'bigint', + ]; + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $column) + { + return 'TEXT'; + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $column) + { + return 'BLOB'; + } + + /** + * {@inheritDoc} + */ + public function getCreateDatabaseSQL($name) + { + return 'CREATE DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getDropDatabaseSQL($name) + { + return 'DROP DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($name, array $columns, array $options = []) + { + $queryFields = $this->getColumnDeclarationListSQL($columns); + + if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { + foreach ($options['uniqueConstraints'] as $index => $definition) { + $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition); + } + } + + // add all indexes + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach ($options['indexes'] as $index => $definition) { + $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition); + } + } + + // attach all primary keys + if (isset($options['primary']) && ! empty($options['primary'])) { + $keyColumns = array_unique(array_values($options['primary'])); + $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; + } + + $query = 'CREATE '; + + if (! empty($options['temporary'])) { + $query .= 'TEMPORARY '; + } + + $query .= 'TABLE ' . $name . ' (' . $queryFields . ') '; + $query .= $this->buildTableOptions($options); + $query .= $this->buildPartitionOptions($options); + + $sql = [$query]; + + if (isset($options['foreignKeys'])) { + foreach ((array) $options['foreignKeys'] as $definition) { + $sql[] = $this->getCreateForeignKeySQL($definition, $name); + } + } + + return $sql; + } + + /** + * Build SQL for table options + * + * @param mixed[] $options + * + * @return string + */ + private function buildTableOptions(array $options) + { + if (isset($options['table_options'])) { + return $options['table_options']; + } + + $tableOptions = []; + + // Collate + if (! isset($options['collate'])) { + $options['collate'] = 'utf8_unicode_ci'; + } + + $tableOptions[] = sprintf('COLLATE %s', $options['collate']); + + // Engine + if (! isset($options['engine'])) { + $options['engine'] = 'InnoDB'; + } + + $tableOptions[] = sprintf('ENGINE = %s', $options['engine']); + + // Auto increment + if (isset($options['auto_increment'])) { + $tableOptions[] = sprintf('AUTO_INCREMENT = %s', $options['auto_increment']); + } + + // Comment + if (isset($options['comment'])) { + $comment = trim($options['comment'], " '"); + + $tableOptions[] = sprintf('COMMENT = %s ', $this->quoteStringLiteral($comment)); + } + + // Row format + if (isset($options['row_format'])) { + $tableOptions[] = sprintf('ROW_FORMAT = %s', $options['row_format']); + } + + return implode(' ', $tableOptions); + } + + /** + * Build SQL for partition options. + * + * @param mixed[] $options + * + * @return string + */ + private function buildPartitionOptions(array $options) + { + return isset($options['partition_options']) + ? ' ' . $options['partition_options'] + : ''; + } + + /** + * {@inheritDoc} + */ + public function getListDatabasesSQL() + { + return "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE CATALOG_NAME='LOCAL'"; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return Keywords\DrizzleKeywords::class; + } + + /** + * {@inheritDoc} + */ + public function getListTablesSQL() + { + return "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE' AND TABLE_SCHEMA=DATABASE()"; + } + + /** + * {@inheritDoc} + */ + public function getListTableColumnsSQL($table, $database = null) + { + if ($database) { + $databaseSQL = $this->quoteStringLiteral($database); + } else { + $databaseSQL = 'DATABASE()'; + } + + return 'SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT, IS_NULLABLE, IS_AUTO_INCREMENT,' . + ' CHARACTER_MAXIMUM_LENGTH, COLUMN_DEFAULT, NUMERIC_PRECISION, NUMERIC_SCALE, COLLATION_NAME' . + ' FROM DATA_DICTIONARY.COLUMNS' . + ' WHERE TABLE_SCHEMA=' . $databaseSQL . ' AND TABLE_NAME = ' . $this->quoteStringLiteral($table); + } + + /** + * @param string $table + * @param string|null $database + * + * @return string + */ + public function getListTableForeignKeysSQL($table, $database = null) + { + if ($database) { + $databaseSQL = $this->quoteStringLiteral($database); + } else { + $databaseSQL = 'DATABASE()'; + } + + return 'SELECT CONSTRAINT_NAME, CONSTRAINT_COLUMNS, REFERENCED_TABLE_NAME, REFERENCED_TABLE_COLUMNS,' + . ' UPDATE_RULE, DELETE_RULE' + . ' FROM DATA_DICTIONARY.FOREIGN_KEYS' + . ' WHERE CONSTRAINT_SCHEMA=' . $databaseSQL + . ' AND CONSTRAINT_TABLE=' . $this->quoteStringLiteral($table); + } + + /** + * {@inheritDoc} + */ + public function getListTableIndexesSQL($table, $database = null) + { + if ($database) { + $databaseSQL = $this->quoteStringLiteral($database); + } else { + $databaseSQL = 'DATABASE()'; + } + + return "SELECT INDEX_NAME AS 'key_name'," + . " COLUMN_NAME AS 'column_name'," + . " IS_USED_IN_PRIMARY AS 'primary'," + . " IS_UNIQUE=0 AS 'non_unique'" + . ' FROM DATA_DICTIONARY.INDEX_PARTS' + . ' WHERE TABLE_SCHEMA=' . $databaseSQL . ' AND TABLE_NAME=' . $this->quoteStringLiteral($table); + } + + /** + * {@inheritDoc} + */ + public function prefersIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsInlineColumnComments() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsViews() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function supportsColumnCollation() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getDropIndexSQL($index, $table = null) + { + if ($index instanceof Index) { + $indexName = $index->getQuotedName($this); + } elseif (is_string($index)) { + $indexName = $index; + } else { + throw new InvalidArgumentException( + __METHOD__ . '() expects $index parameter to be string or ' . Index::class . '.' + ); + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } elseif (! is_string($table)) { + throw new InvalidArgumentException( + __METHOD__ . '() expects $table parameter to be string or ' . Table::class . '.' + ); + } + + if ($index instanceof Index && $index->isPrimary()) { + // drizzle primary keys are always named "PRIMARY", + // so we cannot use them in statements because of them being keyword. + return $this->getDropPrimaryKeySQL($table); + } + + return 'DROP INDEX ' . $indexName . ' ON ' . $table; + } + + /** + * @param string $table + * + * @return string + */ + protected function getDropPrimaryKeySQL($table) + { + return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $column) + { + if (isset($column['version']) && $column['version'] === true) { + return 'TIMESTAMP'; + } + + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $column) + { + return 'TIME'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $column) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $columnSql = []; + $queryParts = []; + + $newName = $diff->getNewName(); + + if ($newName !== false) { + $queryParts[] = 'RENAME TO ' . $newName->getQuotedName($this); + } + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $columnArray = array_merge($column->toArray(), [ + 'comment' => $this->getColumnComment($column), + ]); + + $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $queryParts[] = 'DROP ' . $column->getQuotedName($this); + } + + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + $column = $columnDiff->column; + $columnArray = $column->toArray(); + + // Do not generate column alteration clause if type is binary and only fixed property has changed. + // Drizzle only supports binary type columns with variable length. + // Avoids unnecessary table alteration statements. + if ( + $columnArray['type'] instanceof BinaryType && + $columnDiff->hasChanged('fixed') && + count($columnDiff->changedProperties) === 1 + ) { + continue; + } + + $columnArray['comment'] = $this->getColumnComment($column); + $queryParts[] = 'CHANGE ' . ($columnDiff->getOldColumnName()->getQuotedName($this)) . ' ' + . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $oldColumnName = new Identifier($oldColumnName); + + $columnArray = $column->toArray(); + $columnArray['comment'] = $this->getColumnComment($column); + $queryParts[] = 'CHANGE ' . $oldColumnName->getQuotedName($this) . ' ' + . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + $sql = []; + $tableSql = []; + + if (! $this->onSchemaAlterTable($diff, $tableSql)) { + if (count($queryParts) > 0) { + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) + . ' ' . implode(', ', $queryParts); + } + + $sql = array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * {@inheritDoc} + */ + public function getDropTemporaryTableSQL($table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } elseif (! is_string($table)) { + throw new InvalidArgumentException( + __METHOD__ . '() expects $table parameter to be string or ' . Table::class . '.' + ); + } + + return 'DROP TEMPORARY TABLE ' . $table; + } + + /** + * {@inheritDoc} + */ + public function convertBooleans($item) + { + if (is_array($item)) { + foreach ($item as $key => $value) { + if (! is_bool($value) && ! is_numeric($value)) { + continue; + } + + $item[$key] = $value ? 'true' : 'false'; + } + } elseif (is_bool($item) || is_numeric($item)) { + $item = $item ? 'true' : 'false'; + } + + return $item; + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos === false) { + return 'LOCATE(' . $substr . ', ' . $str . ')'; + } + + return 'LOCATE(' . $substr . ', ' . $str . ', ' . $startPos . ')'; + } + + /** + * {@inheritDoc} + * + * @deprecated Use application-generated UUIDs instead + */ + public function getGuidExpression() + { + return 'UUID()'; + } + + /** + * {@inheritDoc} + */ + public function getRegexpExpression() + { + return 'RLIKE'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php new file mode 100755 index 0000000..8533f57 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php @@ -0,0 +1,420 @@ +keywords === null) { + $this->initializeKeywords(); + } + + return isset($this->keywords[strtoupper($word)]); + } + + /** + * @return void + */ + protected function initializeKeywords() + { + $this->keywords = array_flip(array_map('strtoupper', $this->getKeywords())); + } + + /** + * Returns the list of keywords. + * + * @return string[] + */ + abstract protected function getKeywords(); + + /** + * Returns the name of this keyword list. + * + * @return string + */ + abstract public function getName(); +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MariaDb102Keywords.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MariaDb102Keywords.php new file mode 100755 index 0000000..8cb2bef --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MariaDb102Keywords.php @@ -0,0 +1,271 @@ +keywordLists = $keywordLists; + } + + /** + * @return string[] + */ + public function getViolations() + { + return $this->violations; + } + + /** + * @param string $word + * + * @return string[] + */ + private function isReservedWord($word) + { + if ($word[0] === '`') { + $word = str_replace('`', '', $word); + } + + $keywordLists = []; + foreach ($this->keywordLists as $keywordList) { + if (! $keywordList->isKeyword($word)) { + continue; + } + + $keywordLists[] = $keywordList->getName(); + } + + return $keywordLists; + } + + /** + * @param string $asset + * @param string[] $violatedPlatforms + * + * @return void + */ + private function addViolation($asset, $violatedPlatforms) + { + if (! $violatedPlatforms) { + return; + } + + $this->violations[] = $asset . ' keyword violations: ' . implode(', ', $violatedPlatforms); + } + + /** + * {@inheritdoc} + */ + public function acceptColumn(Table $table, Column $column) + { + $this->addViolation( + 'Table ' . $table->getName() . ' column ' . $column->getName(), + $this->isReservedWord($column->getName()) + ); + } + + /** + * {@inheritdoc} + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + } + + /** + * {@inheritdoc} + */ + public function acceptIndex(Table $table, Index $index) + { + } + + /** + * {@inheritdoc} + */ + public function acceptSchema(Schema $schema) + { + } + + /** + * {@inheritdoc} + */ + public function acceptSequence(Sequence $sequence) + { + } + + /** + * {@inheritdoc} + */ + public function acceptTable(Table $table) + { + $this->addViolation( + 'Table ' . $table->getName(), + $this->isReservedWord($table->getName()) + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere11Keywords.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere11Keywords.php new file mode 100755 index 0000000..09513c5 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere11Keywords.php @@ -0,0 +1,39 @@ +doctrineTypeMapping['json'] = Types::JSON; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQL57Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQL57Platform.php new file mode 100755 index 0000000..5ef44b2 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQL57Platform.php @@ -0,0 +1,71 @@ +getQuotedName($this)]; + } + + /** + * {@inheritdoc} + */ + protected function getReservedKeywordsClass() + { + return Keywords\MySQL57Keywords::class; + } + + /** + * {@inheritdoc} + */ + protected function initializeDoctrineTypeMappings() + { + parent::initializeDoctrineTypeMappings(); + + $this->doctrineTypeMapping['json'] = Types::JSON; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQL80Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQL80Platform.php new file mode 100755 index 0000000..f6d4be9 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQL80Platform.php @@ -0,0 +1,17 @@ + 0) { + $query .= ' OFFSET ' . $offset; + } + } elseif ($offset > 0) { + // 2^64-1 is the maximum of unsigned BIGINT, the biggest limit possible + $query .= ' LIMIT 18446744073709551615 OFFSET ' . $offset; + } + + return $query; + } + + /** + * {@inheritDoc} + */ + public function getIdentifierQuoteCharacter() + { + return '`'; + } + + /** + * {@inheritDoc} + */ + public function getRegexpExpression() + { + return 'RLIKE'; + } + + /** + * {@inheritDoc} + * + * @deprecated Use application-generated UUIDs instead + */ + public function getGuidExpression() + { + return 'UUID()'; + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos === false) { + return 'LOCATE(' . $substr . ', ' . $str . ')'; + } + + return 'LOCATE(' . $substr . ', ' . $str . ', ' . $startPos . ')'; + } + + /** + * {@inheritDoc} + */ + public function getConcatExpression() + { + return sprintf('CONCAT(%s)', implode(', ', func_get_args())); + } + + /** + * {@inheritdoc} + */ + protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + { + $function = $operator === '+' ? 'DATE_ADD' : 'DATE_SUB'; + + return $function . '(' . $date . ', INTERVAL ' . $interval . ' ' . $unit . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateDiffExpression($date1, $date2) + { + return 'DATEDIFF(' . $date1 . ', ' . $date2 . ')'; + } + + /** + * {@inheritDoc} + */ + public function getListDatabasesSQL() + { + return 'SHOW DATABASES'; + } + + /** + * {@inheritDoc} + */ + public function getListTableConstraintsSQL($table) + { + return 'SHOW INDEX FROM ' . $table; + } + + /** + * {@inheritDoc} + * + * Two approaches to listing the table indexes. The information_schema is + * preferred, because it doesn't cause problems with SQL keywords such as "order" or "table". + */ + public function getListTableIndexesSQL($table, $database = null) + { + if ($database) { + $database = $this->quoteStringLiteral($database); + $table = $this->quoteStringLiteral($table); + + return 'SELECT NON_UNIQUE AS Non_Unique, INDEX_NAME AS Key_name, COLUMN_NAME AS Column_Name,' . + ' SUB_PART AS Sub_Part, INDEX_TYPE AS Index_Type' . + ' FROM information_schema.STATISTICS WHERE TABLE_NAME = ' . $table . + ' AND TABLE_SCHEMA = ' . $database . + ' ORDER BY SEQ_IN_INDEX ASC'; + } + + return 'SHOW INDEX FROM ' . $table; + } + + /** + * {@inheritDoc} + */ + public function getListViewsSQL($database) + { + $database = $this->quoteStringLiteral($database); + + return 'SELECT * FROM information_schema.VIEWS WHERE TABLE_SCHEMA = ' . $database; + } + + /** + * @param string $table + * @param string|null $database + * + * @return string + */ + public function getListTableForeignKeysSQL($table, $database = null) + { + $table = $this->quoteStringLiteral($table); + + if ($database !== null) { + $database = $this->quoteStringLiteral($database); + } + + $sql = 'SELECT DISTINCT k.`CONSTRAINT_NAME`, k.`COLUMN_NAME`, k.`REFERENCED_TABLE_NAME`, ' . + 'k.`REFERENCED_COLUMN_NAME` /*!50116 , c.update_rule, c.delete_rule */ ' . + 'FROM information_schema.key_column_usage k /*!50116 ' . + 'INNER JOIN information_schema.referential_constraints c ON ' . + ' c.constraint_name = k.constraint_name AND ' . + ' c.table_name = ' . $table . ' */ WHERE k.table_name = ' . $table; + + $databaseNameSql = $database ?? 'DATABASE()'; + + return $sql . ' AND k.table_schema = ' . $databaseNameSql + . ' /*!50116 AND c.constraint_schema = ' . $databaseNameSql . ' */' + . ' AND k.`REFERENCED_COLUMN_NAME` is not NULL'; + } + + /** + * {@inheritDoc} + */ + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + /** + * {@inheritDoc} + */ + public function getDropViewSQL($name) + { + return 'DROP VIEW ' . $name; + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') + : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); + } + + /** + * {@inheritdoc} + */ + protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? 'BINARY(' . ($length ?: 255) . ')' : 'VARBINARY(' . ($length ?: 255) . ')'; + } + + /** + * Gets the SQL snippet used to declare a CLOB column type. + * TINYTEXT : 2 ^ 8 - 1 = 255 + * TEXT : 2 ^ 16 - 1 = 65535 + * MEDIUMTEXT : 2 ^ 24 - 1 = 16777215 + * LONGTEXT : 2 ^ 32 - 1 = 4294967295 + * + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $column) + { + if (! empty($column['length']) && is_numeric($column['length'])) { + $length = $column['length']; + + if ($length <= static::LENGTH_LIMIT_TINYTEXT) { + return 'TINYTEXT'; + } + + if ($length <= static::LENGTH_LIMIT_TEXT) { + return 'TEXT'; + } + + if ($length <= static::LENGTH_LIMIT_MEDIUMTEXT) { + return 'MEDIUMTEXT'; + } + } + + return 'LONGTEXT'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $column) + { + if (isset($column['version']) && $column['version'] === true) { + return 'TIMESTAMP'; + } + + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $column) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $column) + { + return 'TIME'; + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $column) + { + return 'TINYINT(1)'; + } + + /** + * Obtain DBMS specific SQL code portion needed to set the COLLATION + * of a column declaration to be used in statements like CREATE TABLE. + * + * @deprecated Deprecated since version 2.5, Use {@link self::getColumnCollationDeclarationSQL()} instead. + * + * @param string $collation name of the collation + * + * @return string DBMS specific SQL code portion needed to set the COLLATION + * of a column declaration. + */ + public function getCollationFieldDeclaration($collation) + { + return $this->getColumnCollationDeclarationSQL($collation); + } + + /** + * {@inheritDoc} + * + * MySql prefers "autoincrement" identity columns since sequences can only + * be emulated with a table. + */ + public function prefersIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + * + * MySql supports this through AUTO_INCREMENT columns. + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsInlineColumnComments() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsColumnCollation() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getListTablesSQL() + { + return "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"; + } + + /** + * {@inheritDoc} + */ + public function getListTableColumnsSQL($table, $database = null) + { + $table = $this->quoteStringLiteral($table); + + if ($database) { + $database = $this->quoteStringLiteral($database); + } else { + $database = 'DATABASE()'; + } + + return 'SELECT COLUMN_NAME AS Field, COLUMN_TYPE AS Type, IS_NULLABLE AS `Null`, ' . + 'COLUMN_KEY AS `Key`, COLUMN_DEFAULT AS `Default`, EXTRA AS Extra, COLUMN_COMMENT AS Comment, ' . + 'CHARACTER_SET_NAME AS CharacterSet, COLLATION_NAME AS Collation ' . + 'FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ' . $database . ' AND TABLE_NAME = ' . $table . + ' ORDER BY ORDINAL_POSITION ASC'; + } + + public function getListTableMetadataSQL(string $table, ?string $database = null): string + { + return sprintf( + <<<'SQL' +SELECT ENGINE, AUTO_INCREMENT, TABLE_COLLATION, TABLE_COMMENT, CREATE_OPTIONS +FROM information_schema.TABLES +WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA = %s AND TABLE_NAME = %s +SQL + , + $database ? $this->quoteStringLiteral($database) : 'DATABASE()', + $this->quoteStringLiteral($table) + ); + } + + /** + * {@inheritDoc} + */ + public function getCreateDatabaseSQL($name) + { + return 'CREATE DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getDropDatabaseSQL($name) + { + return 'DROP DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($name, array $columns, array $options = []) + { + $queryFields = $this->getColumnDeclarationListSQL($columns); + + if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { + foreach ($options['uniqueConstraints'] as $index => $definition) { + $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition); + } + } + + // add all indexes + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach ($options['indexes'] as $index => $definition) { + $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition); + } + } + + // attach all primary keys + if (isset($options['primary']) && ! empty($options['primary'])) { + $keyColumns = array_unique(array_values($options['primary'])); + $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; + } + + $query = 'CREATE '; + + if (! empty($options['temporary'])) { + $query .= 'TEMPORARY '; + } + + $query .= 'TABLE ' . $name . ' (' . $queryFields . ') '; + $query .= $this->buildTableOptions($options); + $query .= $this->buildPartitionOptions($options); + + $sql = [$query]; + $engine = 'INNODB'; + + if (isset($options['engine'])) { + $engine = strtoupper(trim($options['engine'])); + } + + // Propagate foreign key constraints only for InnoDB. + if (isset($options['foreignKeys']) && $engine === 'INNODB') { + foreach ((array) $options['foreignKeys'] as $definition) { + $sql[] = $this->getCreateForeignKeySQL($definition, $name); + } + } + + return $sql; + } + + /** + * {@inheritdoc} + */ + public function getDefaultValueDeclarationSQL($column) + { + // Unset the default value if the given column definition does not allow default values. + if ($column['type'] instanceof TextType || $column['type'] instanceof BlobType) { + $column['default'] = null; + } + + return parent::getDefaultValueDeclarationSQL($column); + } + + /** + * Build SQL for table options + * + * @param mixed[] $options + * + * @return string + */ + private function buildTableOptions(array $options) + { + if (isset($options['table_options'])) { + return $options['table_options']; + } + + $tableOptions = []; + + // Charset + if (! isset($options['charset'])) { + $options['charset'] = 'utf8'; + } + + $tableOptions[] = sprintf('DEFAULT CHARACTER SET %s', $options['charset']); + + // Collate + if (! isset($options['collate'])) { + $options['collate'] = $options['charset'] . '_unicode_ci'; + } + + $tableOptions[] = $this->getColumnCollationDeclarationSQL($options['collate']); + + // Engine + if (! isset($options['engine'])) { + $options['engine'] = 'InnoDB'; + } + + $tableOptions[] = sprintf('ENGINE = %s', $options['engine']); + + // Auto increment + if (isset($options['auto_increment'])) { + $tableOptions[] = sprintf('AUTO_INCREMENT = %s', $options['auto_increment']); + } + + // Comment + if (isset($options['comment'])) { + $tableOptions[] = sprintf('COMMENT = %s ', $this->quoteStringLiteral($options['comment'])); + } + + // Row format + if (isset($options['row_format'])) { + $tableOptions[] = sprintf('ROW_FORMAT = %s', $options['row_format']); + } + + return implode(' ', $tableOptions); + } + + /** + * Build SQL for partition options. + * + * @param mixed[] $options + * + * @return string + */ + private function buildPartitionOptions(array $options) + { + return isset($options['partition_options']) + ? ' ' . $options['partition_options'] + : ''; + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $columnSql = []; + $queryParts = []; + $newName = $diff->getNewName(); + + if ($newName !== false) { + $queryParts[] = 'RENAME TO ' . $newName->getQuotedName($this); + } + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $columnArray = array_merge($column->toArray(), [ + 'comment' => $this->getColumnComment($column), + ]); + + $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $queryParts[] = 'DROP ' . $column->getQuotedName($this); + } + + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + $column = $columnDiff->column; + $columnArray = $column->toArray(); + + // Don't propagate default value changes for unsupported column types. + if ( + $columnDiff->hasChanged('default') && + count($columnDiff->changedProperties) === 1 && + ($columnArray['type'] instanceof TextType || $columnArray['type'] instanceof BlobType) + ) { + continue; + } + + $columnArray['comment'] = $this->getColumnComment($column); + $queryParts[] = 'CHANGE ' . ($columnDiff->getOldColumnName()->getQuotedName($this)) . ' ' + . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $oldColumnName = new Identifier($oldColumnName); + $columnArray = $column->toArray(); + $columnArray['comment'] = $this->getColumnComment($column); + $queryParts[] = 'CHANGE ' . $oldColumnName->getQuotedName($this) . ' ' + . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + if (isset($diff->addedIndexes['primary'])) { + $keyColumns = array_unique(array_values($diff->addedIndexes['primary']->getColumns())); + $queryParts[] = 'ADD PRIMARY KEY (' . implode(', ', $keyColumns) . ')'; + unset($diff->addedIndexes['primary']); + } elseif (isset($diff->changedIndexes['primary'])) { + // Necessary in case the new primary key includes a new auto_increment column + foreach ($diff->changedIndexes['primary']->getColumns() as $columnName) { + if (isset($diff->addedColumns[$columnName]) && $diff->addedColumns[$columnName]->getAutoincrement()) { + $keyColumns = array_unique(array_values($diff->changedIndexes['primary']->getColumns())); + $queryParts[] = 'DROP PRIMARY KEY'; + $queryParts[] = 'ADD PRIMARY KEY (' . implode(', ', $keyColumns) . ')'; + unset($diff->changedIndexes['primary']); + break; + } + } + } + + $sql = []; + $tableSql = []; + + if (! $this->onSchemaAlterTable($diff, $tableSql)) { + if (count($queryParts) > 0) { + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' + . implode(', ', $queryParts); + } + + $sql = array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * {@inheritDoc} + */ + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + { + $sql = []; + $table = $diff->getName($this)->getQuotedName($this); + + foreach ($diff->changedIndexes as $changedIndex) { + $sql = array_merge($sql, $this->getPreAlterTableAlterPrimaryKeySQL($diff, $changedIndex)); + } + + foreach ($diff->removedIndexes as $remKey => $remIndex) { + $sql = array_merge($sql, $this->getPreAlterTableAlterPrimaryKeySQL($diff, $remIndex)); + + foreach ($diff->addedIndexes as $addKey => $addIndex) { + if ($remIndex->getColumns() !== $addIndex->getColumns()) { + continue; + } + + $indexClause = 'INDEX ' . $addIndex->getName(); + + if ($addIndex->isPrimary()) { + $indexClause = 'PRIMARY KEY'; + } elseif ($addIndex->isUnique()) { + $indexClause = 'UNIQUE INDEX ' . $addIndex->getName(); + } + + $query = 'ALTER TABLE ' . $table . ' DROP INDEX ' . $remIndex->getName() . ', '; + $query .= 'ADD ' . $indexClause; + $query .= ' (' . $this->getIndexFieldDeclarationListSQL($addIndex) . ')'; + + $sql[] = $query; + + unset($diff->removedIndexes[$remKey], $diff->addedIndexes[$addKey]); + + break; + } + } + + $engine = 'INNODB'; + + if ($diff->fromTable instanceof Table && $diff->fromTable->hasOption('engine')) { + $engine = strtoupper(trim($diff->fromTable->getOption('engine'))); + } + + // Suppress foreign key constraint propagation on non-supporting engines. + if ($engine !== 'INNODB') { + $diff->addedForeignKeys = []; + $diff->changedForeignKeys = []; + $diff->removedForeignKeys = []; + } + + $sql = array_merge( + $sql, + $this->getPreAlterTableAlterIndexForeignKeySQL($diff), + parent::getPreAlterTableIndexForeignKeySQL($diff), + $this->getPreAlterTableRenameIndexForeignKeySQL($diff) + ); + + return $sql; + } + + /** + * @return string[] + */ + private function getPreAlterTableAlterPrimaryKeySQL(TableDiff $diff, Index $index) + { + $sql = []; + + if (! $index->isPrimary() || ! $diff->fromTable instanceof Table) { + return $sql; + } + + $tableName = $diff->getName($this)->getQuotedName($this); + + // Dropping primary keys requires to unset autoincrement attribute on the particular column first. + foreach ($index->getColumns() as $columnName) { + if (! $diff->fromTable->hasColumn($columnName)) { + continue; + } + + $column = $diff->fromTable->getColumn($columnName); + + if ($column->getAutoincrement() !== true) { + continue; + } + + $column->setAutoincrement(false); + + $sql[] = 'ALTER TABLE ' . $tableName . ' MODIFY ' . + $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + + // original autoincrement information might be needed later on by other parts of the table alteration + $column->setAutoincrement(true); + } + + return $sql; + } + + /** + * @param TableDiff $diff The table diff to gather the SQL for. + * + * @return string[] + */ + private function getPreAlterTableAlterIndexForeignKeySQL(TableDiff $diff) + { + $sql = []; + $table = $diff->getName($this)->getQuotedName($this); + + foreach ($diff->changedIndexes as $changedIndex) { + // Changed primary key + if (! $changedIndex->isPrimary() || ! ($diff->fromTable instanceof Table)) { + continue; + } + + foreach ($diff->fromTable->getPrimaryKeyColumns() as $columnName) { + $column = $diff->fromTable->getColumn($columnName); + + // Check if an autoincrement column was dropped from the primary key. + if (! $column->getAutoincrement() || in_array($columnName, $changedIndex->getColumns())) { + continue; + } + + // The autoincrement attribute needs to be removed from the dropped column + // before we can drop and recreate the primary key. + $column->setAutoincrement(false); + + $sql[] = 'ALTER TABLE ' . $table . ' MODIFY ' . + $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + + // Restore the autoincrement attribute as it might be needed later on + // by other parts of the table alteration. + $column->setAutoincrement(true); + } + } + + return $sql; + } + + /** + * @param TableDiff $diff The table diff to gather the SQL for. + * + * @return string[] + */ + protected function getPreAlterTableRenameIndexForeignKeySQL(TableDiff $diff) + { + $sql = []; + $tableName = $diff->getName($this)->getQuotedName($this); + + foreach ($this->getRemainingForeignKeyConstraintsRequiringRenamedIndexes($diff) as $foreignKey) { + if (in_array($foreignKey, $diff->changedForeignKeys, true)) { + continue; + } + + $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); + } + + return $sql; + } + + /** + * Returns the remaining foreign key constraints that require one of the renamed indexes. + * + * "Remaining" here refers to the diff between the foreign keys currently defined in the associated + * table and the foreign keys to be removed. + * + * @param TableDiff $diff The table diff to evaluate. + * + * @return ForeignKeyConstraint[] + */ + private function getRemainingForeignKeyConstraintsRequiringRenamedIndexes(TableDiff $diff) + { + if (empty($diff->renamedIndexes) || ! $diff->fromTable instanceof Table) { + return []; + } + + $foreignKeys = []; + /** @var ForeignKeyConstraint[] $remainingForeignKeys */ + $remainingForeignKeys = array_diff_key( + $diff->fromTable->getForeignKeys(), + $diff->removedForeignKeys + ); + + foreach ($remainingForeignKeys as $foreignKey) { + foreach ($diff->renamedIndexes as $index) { + if ($foreignKey->intersectsIndexColumns($index)) { + $foreignKeys[] = $foreignKey; + + break; + } + } + } + + return $foreignKeys; + } + + /** + * {@inheritdoc} + */ + protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) + { + return array_merge( + parent::getPostAlterTableIndexForeignKeySQL($diff), + $this->getPostAlterTableRenameIndexForeignKeySQL($diff) + ); + } + + /** + * @param TableDiff $diff The table diff to gather the SQL for. + * + * @return string[] + */ + protected function getPostAlterTableRenameIndexForeignKeySQL(TableDiff $diff) + { + $sql = []; + $newName = $diff->getNewName(); + + if ($newName !== false) { + $tableName = $newName->getQuotedName($this); + } else { + $tableName = $diff->getName($this)->getQuotedName($this); + } + + foreach ($this->getRemainingForeignKeyConstraintsRequiringRenamedIndexes($diff) as $foreignKey) { + if (in_array($foreignKey, $diff->changedForeignKeys, true)) { + continue; + } + + $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName); + } + + return $sql; + } + + /** + * {@inheritDoc} + */ + protected function getCreateIndexSQLFlags(Index $index) + { + $type = ''; + if ($index->isUnique()) { + $type .= 'UNIQUE '; + } elseif ($index->hasFlag('fulltext')) { + $type .= 'FULLTEXT '; + } elseif ($index->hasFlag('spatial')) { + $type .= 'SPATIAL '; + } + + return $type; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $column) + { + return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $column) + { + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $column) + { + return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function getFloatDeclarationSQL(array $column) + { + return 'DOUBLE PRECISION' . $this->getUnsignedDeclaration($column); + } + + /** + * {@inheritdoc} + */ + public function getDecimalTypeDeclarationSQL(array $column) + { + return parent::getDecimalTypeDeclarationSQL($column) . $this->getUnsignedDeclaration($column); + } + + /** + * Get unsigned declaration for a column. + * + * @param mixed[] $columnDef + * + * @return string + */ + private function getUnsignedDeclaration(array $columnDef) + { + return ! empty($columnDef['unsigned']) ? ' UNSIGNED' : ''; + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $column) + { + $autoinc = ''; + if (! empty($column['autoincrement'])) { + $autoinc = ' AUTO_INCREMENT'; + } + + return $this->getUnsignedDeclaration($column) . $autoinc; + } + + /** + * {@inheritDoc} + */ + public function getColumnCharsetDeclarationSQL($charset) + { + return 'CHARACTER SET ' . $charset; + } + + /** + * {@inheritDoc} + */ + public function getColumnCollationDeclarationSQL($collation) + { + return 'COLLATE ' . $this->quoteSingleIdentifier($collation); + } + + /** + * {@inheritDoc} + */ + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + { + $query = ''; + if ($foreignKey->hasOption('match')) { + $query .= ' MATCH ' . $foreignKey->getOption('match'); + } + + $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey); + + return $query; + } + + /** + * {@inheritDoc} + */ + public function getDropIndexSQL($index, $table = null) + { + if ($index instanceof Index) { + $indexName = $index->getQuotedName($this); + } elseif (is_string($index)) { + $indexName = $index; + } else { + throw new InvalidArgumentException( + __METHOD__ . '() expects $index parameter to be string or ' . Index::class . '.' + ); + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } elseif (! is_string($table)) { + throw new InvalidArgumentException( + __METHOD__ . '() expects $table parameter to be string or ' . Table::class . '.' + ); + } + + if ($index instanceof Index && $index->isPrimary()) { + // mysql primary keys are always named "PRIMARY", + // so we cannot use them in statements because of them being keyword. + return $this->getDropPrimaryKeySQL($table); + } + + return 'DROP INDEX ' . $indexName . ' ON ' . $table; + } + + /** + * @param string $table + * + * @return string + */ + protected function getDropPrimaryKeySQL($table) + { + return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; + } + + /** + * {@inheritDoc} + */ + public function getSetTransactionIsolationSQL($level) + { + return 'SET SESSION TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'mysql'; + } + + /** + * {@inheritDoc} + */ + public function getReadLockSQL() + { + return 'LOCK IN SHARE MODE'; + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = [ + 'tinyint' => 'boolean', + 'smallint' => 'smallint', + 'mediumint' => 'integer', + 'int' => 'integer', + 'integer' => 'integer', + 'bigint' => 'bigint', + 'tinytext' => 'text', + 'mediumtext' => 'text', + 'longtext' => 'text', + 'text' => 'text', + 'varchar' => 'string', + 'string' => 'string', + 'char' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'timestamp' => 'datetime', + 'time' => 'time', + 'float' => 'float', + 'double' => 'float', + 'real' => 'float', + 'decimal' => 'decimal', + 'numeric' => 'decimal', + 'year' => 'date', + 'longblob' => 'blob', + 'blob' => 'blob', + 'mediumblob' => 'blob', + 'tinyblob' => 'blob', + 'binary' => 'binary', + 'varbinary' => 'binary', + 'set' => 'simple_array', + ]; + } + + /** + * {@inheritDoc} + */ + public function getVarcharMaxLength() + { + return 65535; + } + + /** + * {@inheritdoc} + */ + public function getBinaryMaxLength() + { + return 65535; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return Keywords\MySQLKeywords::class; + } + + /** + * {@inheritDoc} + * + * MySQL commits a transaction implicitly when DROP TABLE is executed, however not + * if DROP TEMPORARY TABLE is executed. + */ + public function getDropTemporaryTableSQL($table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } elseif (! is_string($table)) { + throw new InvalidArgumentException( + __METHOD__ . '() expects $table parameter to be string or ' . Table::class . '.' + ); + } + + return 'DROP TEMPORARY TABLE ' . $table; + } + + /** + * Gets the SQL Snippet used to declare a BLOB column type. + * TINYBLOB : 2 ^ 8 - 1 = 255 + * BLOB : 2 ^ 16 - 1 = 65535 + * MEDIUMBLOB : 2 ^ 24 - 1 = 16777215 + * LONGBLOB : 2 ^ 32 - 1 = 4294967295 + * + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $column) + { + if (! empty($column['length']) && is_numeric($column['length'])) { + $length = $column['length']; + + if ($length <= static::LENGTH_LIMIT_TINYBLOB) { + return 'TINYBLOB'; + } + + if ($length <= static::LENGTH_LIMIT_BLOB) { + return 'BLOB'; + } + + if ($length <= static::LENGTH_LIMIT_MEDIUMBLOB) { + return 'MEDIUMBLOB'; + } + } + + return 'LONGBLOB'; + } + + /** + * {@inheritdoc} + */ + public function quoteStringLiteral($str) + { + $str = str_replace('\\', '\\\\', $str); // MySQL requires backslashes to be escaped aswell. + + return parent::quoteStringLiteral($str); + } + + /** + * {@inheritdoc} + */ + public function getDefaultTransactionIsolationLevel() + { + return TransactionIsolationLevel::REPEATABLE_READ; + } + + public function supportsColumnLengthIndexes(): bool + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php new file mode 100755 index 0000000..a05937d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -0,0 +1,1268 @@ +getBitAndComparisonExpression($value1, $value2) + . '+' . $value2 . ')'; + } + + /** + * {@inheritDoc} + * + * Need to specifiy minvalue, since start with is hidden in the system and MINVALUE <= START WITH. + * Therefore we can use MINVALUE to be able to get a hint what START WITH was for later introspection + * in {@see listSequences()} + */ + public function getCreateSequenceSQL(Sequence $sequence) + { + return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . + ' START WITH ' . $sequence->getInitialValue() . + ' MINVALUE ' . $sequence->getInitialValue() . + ' INCREMENT BY ' . $sequence->getAllocationSize() . + $this->getSequenceCacheSQL($sequence); + } + + /** + * {@inheritDoc} + */ + public function getAlterSequenceSQL(Sequence $sequence) + { + return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize() + . $this->getSequenceCacheSQL($sequence); + } + + /** + * Cache definition for sequences + * + * @return string + */ + private function getSequenceCacheSQL(Sequence $sequence) + { + if ($sequence->getCache() === 0) { + return ' NOCACHE'; + } + + if ($sequence->getCache() === 1) { + return ' NOCACHE'; + } + + if ($sequence->getCache() > 1) { + return ' CACHE ' . $sequence->getCache(); + } + + return ''; + } + + /** + * {@inheritDoc} + */ + public function getSequenceNextValSQL($sequence) + { + return 'SELECT ' . $sequence . '.nextval FROM DUAL'; + } + + /** + * {@inheritDoc} + */ + public function getSetTransactionIsolationSQL($level) + { + return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); + } + + /** + * {@inheritDoc} + */ + protected function _getTransactionIsolationLevelSQL($level) + { + switch ($level) { + case TransactionIsolationLevel::READ_UNCOMMITTED: + return 'READ UNCOMMITTED'; + + case TransactionIsolationLevel::READ_COMMITTED: + return 'READ COMMITTED'; + + case TransactionIsolationLevel::REPEATABLE_READ: + case TransactionIsolationLevel::SERIALIZABLE: + return 'SERIALIZABLE'; + + default: + return parent::_getTransactionIsolationLevelSQL($level); + } + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $column) + { + return 'NUMBER(1)'; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $column) + { + return 'NUMBER(10)'; + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $column) + { + return 'NUMBER(20)'; + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $column) + { + return 'NUMBER(5)'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $column) + { + return 'TIMESTAMP(0)'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzTypeDeclarationSQL(array $column) + { + return 'TIMESTAMP(0) WITH TIME ZONE'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $column) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $column) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $column) + { + return ''; + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(2000)') + : ($length ? 'VARCHAR2(' . $length . ')' : 'VARCHAR2(4000)'); + } + + /** + * {@inheritdoc} + */ + protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + { + return 'RAW(' . ($length ?: $this->getBinaryMaxLength()) . ')'; + } + + /** + * {@inheritdoc} + */ + public function getBinaryMaxLength() + { + return 2000; + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $column) + { + return 'CLOB'; + } + + /** + * {@inheritDoc} + */ + public function getListDatabasesSQL() + { + return 'SELECT username FROM all_users'; + } + + /** + * {@inheritDoc} + */ + public function getListSequencesSQL($database) + { + $database = $this->normalizeIdentifier($database); + $database = $this->quoteStringLiteral($database->getName()); + + return 'SELECT sequence_name, min_value, increment_by FROM sys.all_sequences ' . + 'WHERE SEQUENCE_OWNER = ' . $database; + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($name, array $columns, array $options = []) + { + $indexes = $options['indexes'] ?? []; + $options['indexes'] = []; + $sql = parent::_getCreateTableSQL($name, $columns, $options); + + foreach ($columns as $columnName => $column) { + if (isset($column['sequence'])) { + $sql[] = $this->getCreateSequenceSQL($column['sequence']); + } + + if ( + ! isset($column['autoincrement']) || ! $column['autoincrement'] && + (! isset($column['autoinc']) || ! $column['autoinc']) + ) { + continue; + } + + $sql = array_merge($sql, $this->getCreateAutoincrementSql($columnName, $name)); + } + + if (isset($indexes) && ! empty($indexes)) { + foreach ($indexes as $index) { + $sql[] = $this->getCreateIndexSQL($index, $name); + } + } + + return $sql; + } + + /** + * {@inheritDoc} + * + * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaOracleReader.html + */ + public function getListTableIndexesSQL($table, $database = null) + { + $table = $this->normalizeIdentifier($table); + $table = $this->quoteStringLiteral($table->getName()); + + return "SELECT uind_col.index_name AS name, + ( + SELECT uind.index_type + FROM user_indexes uind + WHERE uind.index_name = uind_col.index_name + ) AS type, + decode( + ( + SELECT uind.uniqueness + FROM user_indexes uind + WHERE uind.index_name = uind_col.index_name + ), + 'NONUNIQUE', + 0, + 'UNIQUE', + 1 + ) AS is_unique, + uind_col.column_name AS column_name, + uind_col.column_position AS column_pos, + ( + SELECT ucon.constraint_type + FROM user_constraints ucon + WHERE ucon.index_name = uind_col.index_name + ) AS is_primary + FROM user_ind_columns uind_col + WHERE uind_col.table_name = " . $table . ' + ORDER BY uind_col.column_position ASC'; + } + + /** + * {@inheritDoc} + */ + public function getListTablesSQL() + { + return 'SELECT * FROM sys.user_tables'; + } + + /** + * {@inheritDoc} + */ + public function getListViewsSQL($database) + { + return 'SELECT view_name, text FROM sys.user_views'; + } + + /** + * {@inheritDoc} + */ + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + /** + * {@inheritDoc} + */ + public function getDropViewSQL($name) + { + return 'DROP VIEW ' . $name; + } + + /** + * @param string $name + * @param string $table + * @param int $start + * + * @return string[] + */ + public function getCreateAutoincrementSql($name, $table, $start = 1) + { + $tableIdentifier = $this->normalizeIdentifier($table); + $quotedTableName = $tableIdentifier->getQuotedName($this); + $unquotedTableName = $tableIdentifier->getName(); + + $nameIdentifier = $this->normalizeIdentifier($name); + $quotedName = $nameIdentifier->getQuotedName($this); + $unquotedName = $nameIdentifier->getName(); + + $sql = []; + + $autoincrementIdentifierName = $this->getAutoincrementIdentifierName($tableIdentifier); + + $idx = new Index($autoincrementIdentifierName, [$quotedName], true, true); + + $sql[] = "DECLARE + constraints_Count NUMBER; +BEGIN + SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count + FROM USER_CONSTRAINTS + WHERE TABLE_NAME = '" . $unquotedTableName . "' + AND CONSTRAINT_TYPE = 'P'; + IF constraints_Count = 0 OR constraints_Count = '' THEN + EXECUTE IMMEDIATE '" . $this->getCreateConstraintSQL($idx, $quotedTableName) . "'; + END IF; +END;"; + + $sequenceName = $this->getIdentitySequenceName( + $tableIdentifier->isQuoted() ? $quotedTableName : $unquotedTableName, + $nameIdentifier->isQuoted() ? $quotedName : $unquotedName + ); + $sequence = new Sequence($sequenceName, $start); + $sql[] = $this->getCreateSequenceSQL($sequence); + + $sql[] = 'CREATE TRIGGER ' . $autoincrementIdentifierName . ' + BEFORE INSERT + ON ' . $quotedTableName . ' + FOR EACH ROW +DECLARE + last_Sequence NUMBER; + last_InsertID NUMBER; +BEGIN + SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $quotedName . ' FROM DUAL; + IF (:NEW.' . $quotedName . ' IS NULL OR :NEW.' . $quotedName . ' = 0) THEN + SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $quotedName . ' FROM DUAL; + ELSE + SELECT NVL(Last_Number, 0) INTO last_Sequence + FROM User_Sequences + WHERE Sequence_Name = \'' . $sequence->getName() . '\'; + SELECT :NEW.' . $quotedName . ' INTO last_InsertID FROM DUAL; + WHILE (last_InsertID > last_Sequence) LOOP + SELECT ' . $sequenceName . '.NEXTVAL INTO last_Sequence FROM DUAL; + END LOOP; + END IF; +END;'; + + return $sql; + } + + /** + * Returns the SQL statements to drop the autoincrement for the given table name. + * + * @param string $table The table name to drop the autoincrement for. + * + * @return string[] + */ + public function getDropAutoincrementSql($table) + { + $table = $this->normalizeIdentifier($table); + $autoincrementIdentifierName = $this->getAutoincrementIdentifierName($table); + $identitySequenceName = $this->getIdentitySequenceName( + $table->isQuoted() ? $table->getQuotedName($this) : $table->getName(), + '' + ); + + return [ + 'DROP TRIGGER ' . $autoincrementIdentifierName, + $this->getDropSequenceSQL($identitySequenceName), + $this->getDropConstraintSQL($autoincrementIdentifierName, $table->getQuotedName($this)), + ]; + } + + /** + * Normalizes the given identifier. + * + * Uppercases the given identifier if it is not quoted by intention + * to reflect Oracle's internal auto uppercasing strategy of unquoted identifiers. + * + * @param string $name The identifier to normalize. + * + * @return Identifier The normalized identifier. + */ + private function normalizeIdentifier($name) + { + $identifier = new Identifier($name); + + return $identifier->isQuoted() ? $identifier : new Identifier(strtoupper($name)); + } + + /** + * Adds suffix to identifier, + * + * if the new string exceeds max identifier length, + * keeps $suffix, cuts from $identifier as much as the part exceeding. + */ + private function addSuffix(string $identifier, string $suffix): string + { + $maxPossibleLengthWithoutSuffix = $this->getMaxIdentifierLength() - strlen($suffix); + if (strlen($identifier) > $maxPossibleLengthWithoutSuffix) { + $identifier = substr($identifier, 0, $maxPossibleLengthWithoutSuffix); + } + + return $identifier . $suffix; + } + + /** + * Returns the autoincrement primary key identifier name for the given table identifier. + * + * Quotes the autoincrement primary key identifier name + * if the given table name is quoted by intention. + * + * @param Identifier $table The table identifier to return the autoincrement primary key identifier name for. + * + * @return string + */ + private function getAutoincrementIdentifierName(Identifier $table) + { + $identifierName = $this->addSuffix($table->getName(), '_AI_PK'); + + return $table->isQuoted() + ? $this->quoteSingleIdentifier($identifierName) + : $identifierName; + } + + /** + * {@inheritDoc} + */ + public function getListTableForeignKeysSQL($table) + { + $table = $this->normalizeIdentifier($table); + $table = $this->quoteStringLiteral($table->getName()); + + return "SELECT alc.constraint_name, + alc.DELETE_RULE, + cols.column_name \"local_column\", + cols.position, + ( + SELECT r_cols.table_name + FROM user_cons_columns r_cols + WHERE alc.r_constraint_name = r_cols.constraint_name + AND r_cols.position = cols.position + ) AS \"references_table\", + ( + SELECT r_cols.column_name + FROM user_cons_columns r_cols + WHERE alc.r_constraint_name = r_cols.constraint_name + AND r_cols.position = cols.position + ) AS \"foreign_column\" + FROM user_cons_columns cols + JOIN user_constraints alc + ON alc.constraint_name = cols.constraint_name + AND alc.constraint_type = 'R' + AND alc.table_name = " . $table . ' + ORDER BY cols.constraint_name ASC, cols.position ASC'; + } + + /** + * {@inheritDoc} + */ + public function getListTableConstraintsSQL($table) + { + $table = $this->normalizeIdentifier($table); + $table = $this->quoteStringLiteral($table->getName()); + + return 'SELECT * FROM user_constraints WHERE table_name = ' . $table; + } + + /** + * {@inheritDoc} + */ + public function getListTableColumnsSQL($table, $database = null) + { + $table = $this->normalizeIdentifier($table); + $table = $this->quoteStringLiteral($table->getName()); + + $tabColumnsTableName = 'user_tab_columns'; + $colCommentsTableName = 'user_col_comments'; + $tabColumnsOwnerCondition = ''; + $colCommentsOwnerCondition = ''; + + if ($database !== null && $database !== '/') { + $database = $this->normalizeIdentifier($database); + $database = $this->quoteStringLiteral($database->getName()); + $tabColumnsTableName = 'all_tab_columns'; + $colCommentsTableName = 'all_col_comments'; + $tabColumnsOwnerCondition = ' AND c.owner = ' . $database; + $colCommentsOwnerCondition = ' AND d.OWNER = c.OWNER'; + } + + return sprintf( + <<<'SQL' +SELECT c.*, + ( + SELECT d.comments + FROM %s d + WHERE d.TABLE_NAME = c.TABLE_NAME%s + AND d.COLUMN_NAME = c.COLUMN_NAME + ) AS comments +FROM %s c +WHERE c.table_name = %s%s +ORDER BY c.column_id +SQL + , + $colCommentsTableName, + $colCommentsOwnerCondition, + $tabColumnsTableName, + $table, + $tabColumnsOwnerCondition + ); + } + + /** + * {@inheritDoc} + */ + public function getDropSequenceSQL($sequence) + { + if ($sequence instanceof Sequence) { + $sequence = $sequence->getQuotedName($this); + } + + return 'DROP SEQUENCE ' . $sequence; + } + + /** + * {@inheritDoc} + */ + public function getDropForeignKeySQL($foreignKey, $table) + { + if (! $foreignKey instanceof ForeignKeyConstraint) { + $foreignKey = new Identifier($foreignKey); + } + + if (! $table instanceof Table) { + $table = new Identifier($table); + } + + $foreignKey = $foreignKey->getQuotedName($this); + $table = $table->getQuotedName($this); + + return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey; + } + + /** + * {@inheritdoc} + */ + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + { + $referentialAction = null; + + if ($foreignKey->hasOption('onDelete')) { + $referentialAction = $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete')); + } + + return $referentialAction ? ' ON DELETE ' . $referentialAction : ''; + } + + /** + * {@inheritdoc} + */ + public function getForeignKeyReferentialActionSQL($action) + { + $action = strtoupper($action); + + switch ($action) { + case 'RESTRICT': // RESTRICT is not supported, therefore falling back to NO ACTION. + case 'NO ACTION': + // NO ACTION cannot be declared explicitly, + // therefore returning empty string to indicate to OMIT the referential clause. + return ''; + + case 'CASCADE': + case 'SET NULL': + return $action; + + default: + // SET DEFAULT is not supported, throw exception instead. + throw new InvalidArgumentException('Invalid foreign key action: ' . $action); + } + } + + /** + * {@inheritDoc} + */ + public function getDropDatabaseSQL($name) + { + return 'DROP USER ' . $name . ' CASCADE'; + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $sql = []; + $commentsSQL = []; + $columnSql = []; + + $fields = []; + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $fields[] = $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + $comment = $this->getColumnComment($column); + + if (! $comment) { + continue; + } + + $commentsSQL[] = $this->getCommentOnColumnSQL( + $diff->getName($this)->getQuotedName($this), + $column->getQuotedName($this), + $comment + ); + } + + if (count($fields)) { + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) + . ' ADD (' . implode(', ', $fields) . ')'; + } + + $fields = []; + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + $column = $columnDiff->column; + + // Do not generate column alteration clause if type is binary and only fixed property has changed. + // Oracle only supports binary type columns with variable length. + // Avoids unnecessary table alteration statements. + if ( + $column->getType() instanceof BinaryType && + $columnDiff->hasChanged('fixed') && + count($columnDiff->changedProperties) === 1 + ) { + continue; + } + + $columnHasChangedComment = $columnDiff->hasChanged('comment'); + + /** + * Do not add query part if only comment has changed + */ + if (! ($columnHasChangedComment && count($columnDiff->changedProperties) === 1)) { + $columnInfo = $column->toArray(); + + if (! $columnDiff->hasChanged('notnull')) { + unset($columnInfo['notnull']); + } + + $fields[] = $column->getQuotedName($this) . $this->getColumnDeclarationSQL('', $columnInfo); + } + + if (! $columnHasChangedComment) { + continue; + } + + $commentsSQL[] = $this->getCommentOnColumnSQL( + $diff->getName($this)->getQuotedName($this), + $column->getQuotedName($this), + $this->getColumnComment($column) + ); + } + + if (count($fields)) { + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) + . ' MODIFY (' . implode(', ', $fields) . ')'; + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $oldColumnName = new Identifier($oldColumnName); + + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . + ' RENAME COLUMN ' . $oldColumnName->getQuotedName($this) . ' TO ' . $column->getQuotedName($this); + } + + $fields = []; + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $fields[] = $column->getQuotedName($this); + } + + if (count($fields)) { + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) + . ' DROP (' . implode(', ', $fields) . ')'; + } + + $tableSql = []; + + if (! $this->onSchemaAlterTable($diff, $tableSql)) { + $sql = array_merge($sql, $commentsSQL); + + $newName = $diff->getNewName(); + + if ($newName !== false) { + $sql[] = sprintf( + 'ALTER TABLE %s RENAME TO %s', + $diff->getName($this)->getQuotedName($this), + $newName->getQuotedName($this) + ); + } + + $sql = array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * {@inheritdoc} + */ + public function getColumnDeclarationSQL($name, array $column) + { + if (isset($column['columnDefinition'])) { + $columnDef = $this->getCustomTypeDeclarationSQL($column); + } else { + $default = $this->getDefaultValueDeclarationSQL($column); + + $notnull = ''; + + if (isset($column['notnull'])) { + $notnull = $column['notnull'] ? ' NOT NULL' : ' NULL'; + } + + $unique = isset($column['unique']) && $column['unique'] ? + ' ' . $this->getUniqueFieldDeclarationSQL() : ''; + + $check = isset($column['check']) && $column['check'] ? + ' ' . $column['check'] : ''; + + $typeDecl = $column['type']->getSQLDeclaration($column, $this); + $columnDef = $typeDecl . $default . $notnull . $unique . $check; + } + + return $name . ' ' . $columnDef; + } + + /** + * {@inheritdoc} + */ + protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + { + if (strpos($tableName, '.') !== false) { + [$schema] = explode('.', $tableName); + $oldIndexName = $schema . '.' . $oldIndexName; + } + + return ['ALTER INDEX ' . $oldIndexName . ' RENAME TO ' . $index->getQuotedName($this)]; + } + + /** + * {@inheritDoc} + * + * @deprecated + */ + public function prefersSequences() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4229', + 'AbstractPlatform::prefersSequences() is deprecated without replacement and removed in DBAL 3.0' + ); + + return true; + } + + /** + * {@inheritdoc} + */ + public function usesSequenceEmulatedIdentityColumns() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getIdentitySequenceName($tableName, $columnName) + { + $table = new Identifier($tableName); + + // No usage of column name to preserve BC compatibility with <2.5 + $identitySequenceName = $this->addSuffix($table->getName(), '_SEQ'); + + if ($table->isQuoted()) { + $identitySequenceName = '"' . $identitySequenceName . '"'; + } + + $identitySequenceIdentifier = $this->normalizeIdentifier($identitySequenceName); + + return $identitySequenceIdentifier->getQuotedName($this); + } + + /** + * {@inheritDoc} + */ + public function supportsCommentOnStatement() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'oracle'; + } + + /** + * {@inheritDoc} + */ + protected function doModifyLimitQuery($query, $limit, $offset = null) + { + if ($limit === null && $offset <= 0) { + return $query; + } + + if (preg_match('/^\s*SELECT/i', $query)) { + if (! preg_match('/\sFROM\s/i', $query)) { + $query .= ' FROM dual'; + } + + $columns = ['a.*']; + + if ($offset > 0) { + $columns[] = 'ROWNUM AS doctrine_rownum'; + } + + $query = sprintf('SELECT %s FROM (%s) a', implode(', ', $columns), $query); + + if ($limit !== null) { + $query .= sprintf(' WHERE ROWNUM <= %d', $offset + $limit); + } + + if ($offset > 0) { + $query = sprintf('SELECT * FROM (%s) WHERE doctrine_rownum >= %d', $query, $offset + 1); + } + } + + return $query; + } + + /** + * {@inheritDoc} + * + * Oracle returns all column names in SQL result sets in uppercase. + * + * @deprecated + */ + public function getSQLResultCasing($column) + { + return strtoupper($column); + } + + /** + * {@inheritDoc} + */ + public function getCreateTemporaryTableSnippetSQL() + { + return 'CREATE GLOBAL TEMPORARY TABLE'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzFormatString() + { + return 'Y-m-d H:i:sP'; + } + + /** + * {@inheritDoc} + */ + public function getDateFormatString() + { + return 'Y-m-d 00:00:00'; + } + + /** + * {@inheritDoc} + */ + public function getTimeFormatString() + { + return '1900-01-01 H:i:s'; + } + + /** + * {@inheritDoc} + * + * @deprecated + */ + public function fixSchemaElementName($schemaElementName) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4132', + 'AbstractPlatform::fixSchemaElementName is deprecated with no replacement and removed in DBAL 3.0' + ); + + if (strlen($schemaElementName) > 30) { + // Trim it + return substr($schemaElementName, 0, 30); + } + + return $schemaElementName; + } + + /** + * {@inheritDoc} + */ + public function getMaxIdentifierLength() + { + return 30; + } + + /** + * {@inheritDoc} + */ + public function supportsSequences() + { + return true; + } + + /** + * {@inheritDoc} + * + * @deprecated + */ + public function supportsForeignKeyOnUpdate() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4229', + 'AbstractPlatform::supportsForeignKeyOnUpdate() is deprecated without replacement and removed in DBAL 3.0' + ); + + return false; + } + + /** + * {@inheritDoc} + */ + public function supportsReleaseSavepoints() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + $tableIdentifier = new Identifier($tableName); + + return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this); + } + + /** + * {@inheritDoc} + */ + public function getDummySelectSQL() + { + $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; + + return sprintf('SELECT %s FROM DUAL', $expression); + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = [ + 'integer' => 'integer', + 'number' => 'integer', + 'pls_integer' => 'boolean', + 'binary_integer' => 'boolean', + 'varchar' => 'string', + 'varchar2' => 'string', + 'nvarchar2' => 'string', + 'char' => 'string', + 'nchar' => 'string', + 'date' => 'date', + 'timestamp' => 'datetime', + 'timestamptz' => 'datetimetz', + 'float' => 'float', + 'binary_float' => 'float', + 'binary_double' => 'float', + 'long' => 'string', + 'clob' => 'text', + 'nclob' => 'text', + 'raw' => 'binary', + 'long raw' => 'blob', + 'rowid' => 'string', + 'urowid' => 'string', + 'blob' => 'blob', + ]; + } + + /** + * {@inheritDoc} + */ + public function releaseSavePoint($savepoint) + { + return ''; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return Keywords\OracleKeywords::class; + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $column) + { + return 'BLOB'; + } + + public function getListTableCommentsSQL(string $table, ?string $database = null): string + { + $tableCommentsName = 'user_tab_comments'; + $ownerCondition = ''; + + if ($database !== null && $database !== '/') { + $tableCommentsName = 'all_tab_comments'; + $ownerCondition = ' AND owner = ' . $this->quoteStringLiteral( + $this->normalizeIdentifier($database)->getName() + ); + } + + return sprintf( + <<<'SQL' +SELECT comments FROM %s WHERE table_name = %s%s +SQL + , + $tableCommentsName, + $this->quoteStringLiteral($this->normalizeIdentifier($table)->getName()), + $ownerCondition + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL100Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL100Platform.php new file mode 100755 index 0000000..f561005 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL100Platform.php @@ -0,0 +1,33 @@ +quoteStringLiteral($database) . " + AND sequence_schema NOT LIKE 'pg\_%' + AND sequence_schema != 'information_schema'"; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL91Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL91Platform.php new file mode 100755 index 0000000..494a69c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL91Platform.php @@ -0,0 +1,50 @@ +quoteSingleIdentifier($collation); + } + + /** + * {@inheritDoc} + */ + public function getListTableColumnsSQL($table, $database = null) + { + $sql = parent::getListTableColumnsSQL($table, $database); + $parts = explode('AS complete_type,', $sql, 2); + + return $parts[0] . 'AS complete_type, ' + . '(SELECT tc.collcollate FROM pg_catalog.pg_collation tc WHERE tc.oid = a.attcollation) AS collation,' + . $parts[1]; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php new file mode 100755 index 0000000..9a1784a --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php @@ -0,0 +1,72 @@ +doctrineTypeMapping['json'] = Types::JSON; + } + + /** + * {@inheritdoc} + */ + public function getCloseActiveDatabaseConnectionsSQL($database) + { + return sprintf( + 'SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = %s', + $this->quoteStringLiteral($database) + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php new file mode 100755 index 0000000..c17020f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php @@ -0,0 +1,41 @@ +doctrineTypeMapping['jsonb'] = Types::JSON; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php new file mode 100755 index 0000000..7888030 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php @@ -0,0 +1,1310 @@ + [ + 't', + 'true', + 'y', + 'yes', + 'on', + '1', + ], + 'false' => [ + 'f', + 'false', + 'n', + 'no', + 'off', + '0', + ], + ]; + + /** + * PostgreSQL has different behavior with some drivers + * with regard to how booleans have to be handled. + * + * Enables use of 'true'/'false' or otherwise 1 and 0 instead. + * + * @param bool $flag + * + * @return void + */ + public function setUseBooleanTrueFalseStrings($flag) + { + $this->useBooleanTrueFalseStrings = (bool) $flag; + } + + /** + * {@inheritDoc} + */ + public function getSubstringExpression($string, $start, $length = null) + { + if ($length === null) { + return 'SUBSTRING(' . $string . ' FROM ' . $start . ')'; + } + + return 'SUBSTRING(' . $string . ' FROM ' . $start . ' FOR ' . $length . ')'; + } + + /** + * {@inheritDoc} + */ + public function getNowExpression() + { + return 'LOCALTIMESTAMP(0)'; + } + + /** + * {@inheritDoc} + */ + public function getRegexpExpression() + { + return 'SIMILAR TO'; + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos !== false) { + $str = $this->getSubstringExpression($str, $startPos); + + return 'CASE WHEN (POSITION(' . $substr . ' IN ' . $str . ') = 0) THEN 0' + . ' ELSE (POSITION(' . $substr . ' IN ' . $str . ') + ' . ($startPos - 1) . ') END'; + } + + return 'POSITION(' . $substr . ' IN ' . $str . ')'; + } + + /** + * {@inheritdoc} + */ + protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + { + if ($unit === DateIntervalUnit::QUARTER) { + $interval *= 3; + $unit = DateIntervalUnit::MONTH; + } + + return '(' . $date . ' ' . $operator . ' (' . $interval . " || ' " . $unit . "')::interval)"; + } + + /** + * {@inheritDoc} + */ + public function getDateDiffExpression($date1, $date2) + { + return '(DATE(' . $date1 . ')-DATE(' . $date2 . '))'; + } + + /** + * {@inheritDoc} + */ + public function supportsSequences() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsSchemas() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getDefaultSchemaName() + { + return 'public'; + } + + /** + * {@inheritDoc} + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function supportsPartialIndexes() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function usesSequenceEmulatedIdentityColumns() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getIdentitySequenceName($tableName, $columnName) + { + return $tableName . '_' . $columnName . '_seq'; + } + + /** + * {@inheritDoc} + */ + public function supportsCommentOnStatement() + { + return true; + } + + /** + * {@inheritDoc} + * + * @deprecated + */ + public function prefersSequences() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4229', + 'AbstractPlatform::prefersSequences() is deprecated without replacement and removed in DBAL 3.0' + ); + + return true; + } + + /** + * {@inheritDoc} + */ + public function hasNativeGuidType() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getListDatabasesSQL() + { + return 'SELECT datname FROM pg_database'; + } + + /** + * {@inheritDoc} + */ + public function getListNamespacesSQL() + { + return "SELECT schema_name AS nspname + FROM information_schema.schemata + WHERE schema_name NOT LIKE 'pg\_%' + AND schema_name != 'information_schema'"; + } + + /** + * {@inheritDoc} + */ + public function getListSequencesSQL($database) + { + return "SELECT sequence_name AS relname, + sequence_schema AS schemaname + FROM information_schema.sequences + WHERE sequence_schema NOT LIKE 'pg\_%' + AND sequence_schema != 'information_schema'"; + } + + /** + * {@inheritDoc} + */ + public function getListTablesSQL() + { + return "SELECT quote_ident(table_name) AS table_name, + table_schema AS schema_name + FROM information_schema.tables + WHERE table_schema NOT LIKE 'pg\_%' + AND table_schema != 'information_schema' + AND table_name != 'geometry_columns' + AND table_name != 'spatial_ref_sys' + AND table_type != 'VIEW'"; + } + + /** + * {@inheritDoc} + */ + public function getListViewsSQL($database) + { + return 'SELECT quote_ident(table_name) AS viewname, + table_schema AS schemaname, + view_definition AS definition + FROM information_schema.views + WHERE view_definition IS NOT NULL'; + } + + /** + * @param string $table + * @param string|null $database + * + * @return string + */ + public function getListTableForeignKeysSQL($table, $database = null) + { + return 'SELECT quote_ident(r.conname) as conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef + FROM pg_catalog.pg_constraint r + WHERE r.conrelid = + ( + SELECT c.oid + FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n + WHERE ' . $this->getTableWhereClause($table) . " AND n.oid = c.relnamespace + ) + AND r.contype = 'f'"; + } + + /** + * {@inheritDoc} + */ + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + /** + * {@inheritDoc} + */ + public function getDropViewSQL($name) + { + return 'DROP VIEW ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getListTableConstraintsSQL($table) + { + $table = new Identifier($table); + $table = $this->quoteStringLiteral($table->getName()); + + return sprintf( + <<<'SQL' +SELECT + quote_ident(relname) as relname +FROM + pg_class +WHERE oid IN ( + SELECT indexrelid + FROM pg_index, pg_class + WHERE pg_class.relname = %s + AND pg_class.oid = pg_index.indrelid + AND (indisunique = 't' OR indisprimary = 't') + ) +SQL + , + $table + ); + } + + /** + * {@inheritDoc} + * + * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html + */ + public function getListTableIndexesSQL($table, $database = null) + { + return 'SELECT quote_ident(relname) as relname, pg_index.indisunique, pg_index.indisprimary, + pg_index.indkey, pg_index.indrelid, + pg_get_expr(indpred, indrelid) AS where + FROM pg_class, pg_index + WHERE oid IN ( + SELECT indexrelid + FROM pg_index si, pg_class sc, pg_namespace sn + WHERE ' . $this->getTableWhereClause($table, 'sc', 'sn') . ' + AND sc.oid=si.indrelid AND sc.relnamespace = sn.oid + ) AND pg_index.indexrelid = oid'; + } + + /** + * @param string $table + * @param string $classAlias + * @param string $namespaceAlias + * + * @return string + */ + private function getTableWhereClause($table, $classAlias = 'c', $namespaceAlias = 'n') + { + $whereClause = $namespaceAlias . ".nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast') AND "; + if (strpos($table, '.') !== false) { + [$schema, $table] = explode('.', $table); + $schema = $this->quoteStringLiteral($schema); + } else { + $schema = 'ANY(current_schemas(false))'; + } + + $table = new Identifier($table); + $table = $this->quoteStringLiteral($table->getName()); + + return $whereClause . sprintf( + '%s.relname = %s AND %s.nspname = %s', + $classAlias, + $table, + $namespaceAlias, + $schema + ); + } + + /** + * {@inheritDoc} + */ + public function getListTableColumnsSQL($table, $database = null) + { + return "SELECT + a.attnum, + quote_ident(a.attname) AS field, + t.typname AS type, + format_type(a.atttypid, a.atttypmod) AS complete_type, + (SELECT t1.typname FROM pg_catalog.pg_type t1 WHERE t1.oid = t.typbasetype) AS domain_type, + (SELECT format_type(t2.typbasetype, t2.typtypmod) FROM + pg_catalog.pg_type t2 WHERE t2.typtype = 'd' AND t2.oid = a.atttypid) AS domain_complete_type, + a.attnotnull AS isnotnull, + (SELECT 't' + FROM pg_index + WHERE c.oid = pg_index.indrelid + AND pg_index.indkey[0] = a.attnum + AND pg_index.indisprimary = 't' + ) AS pri, + (SELECT pg_get_expr(adbin, adrelid) + FROM pg_attrdef + WHERE c.oid = pg_attrdef.adrelid + AND pg_attrdef.adnum=a.attnum + ) AS default, + (SELECT pg_description.description + FROM pg_description WHERE pg_description.objoid = c.oid AND a.attnum = pg_description.objsubid + ) AS comment + FROM pg_attribute a, pg_class c, pg_type t, pg_namespace n + WHERE " . $this->getTableWhereClause($table, 'c', 'n') . ' + AND a.attnum > 0 + AND a.attrelid = c.oid + AND a.atttypid = t.oid + AND n.oid = c.relnamespace + ORDER BY a.attnum'; + } + + /** + * {@inheritDoc} + */ + public function getCreateDatabaseSQL($name) + { + return 'CREATE DATABASE ' . $name; + } + + /** + * Returns the SQL statement for disallowing new connections on the given database. + * + * This is useful to force DROP DATABASE operations which could fail because of active connections. + * + * @deprecated + * + * @param string $database The name of the database to disallow new connections for. + * + * @return string + */ + public function getDisallowDatabaseConnectionsSQL($database) + { + return "UPDATE pg_database SET datallowconn = 'false' WHERE datname = " . $this->quoteStringLiteral($database); + } + + /** + * Returns the SQL statement for closing currently active connections on the given database. + * + * This is useful to force DROP DATABASE operations which could fail because of active connections. + * + * @deprecated + * + * @param string $database The name of the database to close currently active connections for. + * + * @return string + */ + public function getCloseActiveDatabaseConnectionsSQL($database) + { + return 'SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = ' + . $this->quoteStringLiteral($database); + } + + /** + * {@inheritDoc} + */ + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + { + $query = ''; + + if ($foreignKey->hasOption('match')) { + $query .= ' MATCH ' . $foreignKey->getOption('match'); + } + + $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey); + + if ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false) { + $query .= ' DEFERRABLE'; + } else { + $query .= ' NOT DEFERRABLE'; + } + + if ( + ($foreignKey->hasOption('feferred') && $foreignKey->getOption('feferred') !== false) + || ($foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false) + ) { + $query .= ' INITIALLY DEFERRED'; + } else { + $query .= ' INITIALLY IMMEDIATE'; + } + + return $query; + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $sql = []; + $commentsSQL = []; + $columnSql = []; + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $query = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; + + $comment = $this->getColumnComment($column); + + if ($comment === null || $comment === '') { + continue; + } + + $commentsSQL[] = $this->getCommentOnColumnSQL( + $diff->getName($this)->getQuotedName($this), + $column->getQuotedName($this), + $comment + ); + } + + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $query = 'DROP ' . $column->getQuotedName($this); + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; + } + + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + if ($this->isUnchangedBinaryColumn($columnDiff)) { + continue; + } + + $oldColumnName = $columnDiff->getOldColumnName()->getQuotedName($this); + $column = $columnDiff->column; + + if ( + $columnDiff->hasChanged('type') + || $columnDiff->hasChanged('precision') + || $columnDiff->hasChanged('scale') + || $columnDiff->hasChanged('fixed') + ) { + $type = $column->getType(); + + // SERIAL/BIGSERIAL are not "real" types and we can't alter a column to that type + $columnDefinition = $column->toArray(); + $columnDefinition['autoincrement'] = false; + + // here was a server version check before, but DBAL API does not support this anymore. + $query = 'ALTER ' . $oldColumnName . ' TYPE ' . $type->getSQLDeclaration($columnDefinition, $this); + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; + } + + if ($columnDiff->hasChanged('default') || $this->typeChangeBreaksDefaultValue($columnDiff)) { + $defaultClause = $column->getDefault() === null + ? ' DROP DEFAULT' + : ' SET' . $this->getDefaultValueDeclarationSQL($column->toArray()); + $query = 'ALTER ' . $oldColumnName . $defaultClause; + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; + } + + if ($columnDiff->hasChanged('notnull')) { + $query = 'ALTER ' . $oldColumnName . ' ' . ($column->getNotnull() ? 'SET' : 'DROP') . ' NOT NULL'; + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; + } + + if ($columnDiff->hasChanged('autoincrement')) { + if ($column->getAutoincrement()) { + // add autoincrement + $seqName = $this->getIdentitySequenceName($diff->name, $oldColumnName); + + $sql[] = 'CREATE SEQUENCE ' . $seqName; + $sql[] = "SELECT setval('" . $seqName . "', (SELECT MAX(" . $oldColumnName . ') FROM ' + . $diff->getName($this)->getQuotedName($this) . '))'; + $query = 'ALTER ' . $oldColumnName . " SET DEFAULT nextval('" . $seqName . "')"; + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; + } else { + // Drop autoincrement, but do NOT drop the sequence. It might be re-used by other tables or have + $query = 'ALTER ' . $oldColumnName . ' DROP DEFAULT'; + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; + } + } + + $newComment = $this->getColumnComment($column); + $oldComment = $this->getOldColumnComment($columnDiff); + + if ( + $columnDiff->hasChanged('comment') + || ($columnDiff->fromColumn !== null && $oldComment !== $newComment) + ) { + $commentsSQL[] = $this->getCommentOnColumnSQL( + $diff->getName($this)->getQuotedName($this), + $column->getQuotedName($this), + $newComment + ); + } + + if (! $columnDiff->hasChanged('length')) { + continue; + } + + $query = 'ALTER ' . $oldColumnName . ' TYPE ' + . $column->getType()->getSQLDeclaration($column->toArray(), $this); + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $oldColumnName = new Identifier($oldColumnName); + + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . + ' RENAME COLUMN ' . $oldColumnName->getQuotedName($this) . ' TO ' . $column->getQuotedName($this); + } + + $tableSql = []; + + if (! $this->onSchemaAlterTable($diff, $tableSql)) { + $sql = array_merge($sql, $commentsSQL); + + $newName = $diff->getNewName(); + + if ($newName !== false) { + $sql[] = sprintf( + 'ALTER TABLE %s RENAME TO %s', + $diff->getName($this)->getQuotedName($this), + $newName->getQuotedName($this) + ); + } + + $sql = array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * Checks whether a given column diff is a logically unchanged binary type column. + * + * Used to determine whether a column alteration for a binary type column can be skipped. + * Doctrine's {@link BinaryType} and {@link BlobType} are mapped to the same database column type on this platform + * as this platform does not have a native VARBINARY/BINARY column type. Therefore the comparator + * might detect differences for binary type columns which do not have to be propagated + * to database as there actually is no difference at database level. + * + * @param ColumnDiff $columnDiff The column diff to check against. + * + * @return bool True if the given column diff is an unchanged binary type column, false otherwise. + */ + private function isUnchangedBinaryColumn(ColumnDiff $columnDiff) + { + $columnType = $columnDiff->column->getType(); + + if (! $columnType instanceof BinaryType && ! $columnType instanceof BlobType) { + return false; + } + + $fromColumn = $columnDiff->fromColumn instanceof Column ? $columnDiff->fromColumn : null; + + if ($fromColumn) { + $fromColumnType = $fromColumn->getType(); + + if (! $fromColumnType instanceof BinaryType && ! $fromColumnType instanceof BlobType) { + return false; + } + + return count(array_diff($columnDiff->changedProperties, ['type', 'length', 'fixed'])) === 0; + } + + if ($columnDiff->hasChanged('type')) { + return false; + } + + return count(array_diff($columnDiff->changedProperties, ['length', 'fixed'])) === 0; + } + + /** + * {@inheritdoc} + */ + protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + { + if (strpos($tableName, '.') !== false) { + [$schema] = explode('.', $tableName); + $oldIndexName = $schema . '.' . $oldIndexName; + } + + return ['ALTER INDEX ' . $oldIndexName . ' RENAME TO ' . $index->getQuotedName($this)]; + } + + /** + * {@inheritdoc} + */ + public function getCommentOnColumnSQL($tableName, $columnName, $comment) + { + $tableName = new Identifier($tableName); + $columnName = new Identifier($columnName); + $comment = $comment === null ? 'NULL' : $this->quoteStringLiteral($comment); + + return sprintf( + 'COMMENT ON COLUMN %s.%s IS %s', + $tableName->getQuotedName($this), + $columnName->getQuotedName($this), + $comment + ); + } + + /** + * {@inheritDoc} + */ + public function getCreateSequenceSQL(Sequence $sequence) + { + return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize() . + ' MINVALUE ' . $sequence->getInitialValue() . + ' START ' . $sequence->getInitialValue() . + $this->getSequenceCacheSQL($sequence); + } + + /** + * {@inheritDoc} + */ + public function getAlterSequenceSQL(Sequence $sequence) + { + return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize() . + $this->getSequenceCacheSQL($sequence); + } + + /** + * Cache definition for sequences + * + * @return string + */ + private function getSequenceCacheSQL(Sequence $sequence) + { + if ($sequence->getCache() > 1) { + return ' CACHE ' . $sequence->getCache(); + } + + return ''; + } + + /** + * {@inheritDoc} + */ + public function getDropSequenceSQL($sequence) + { + if ($sequence instanceof Sequence) { + $sequence = $sequence->getQuotedName($this); + } + + return 'DROP SEQUENCE ' . $sequence . ' CASCADE'; + } + + /** + * {@inheritDoc} + */ + public function getCreateSchemaSQL($schemaName) + { + return 'CREATE SCHEMA ' . $schemaName; + } + + /** + * {@inheritDoc} + */ + public function getDropForeignKeySQL($foreignKey, $table) + { + return $this->getDropConstraintSQL($foreignKey, $table); + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($name, array $columns, array $options = []) + { + $queryFields = $this->getColumnDeclarationListSQL($columns); + + if (isset($options['primary']) && ! empty($options['primary'])) { + $keyColumns = array_unique(array_values($options['primary'])); + $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; + } + + $query = 'CREATE TABLE ' . $name . ' (' . $queryFields . ')'; + + $sql = [$query]; + + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach ($options['indexes'] as $index) { + $sql[] = $this->getCreateIndexSQL($index, $name); + } + } + + if (isset($options['foreignKeys'])) { + foreach ((array) $options['foreignKeys'] as $definition) { + $sql[] = $this->getCreateForeignKeySQL($definition, $name); + } + } + + return $sql; + } + + /** + * Converts a single boolean value. + * + * First converts the value to its native PHP boolean type + * and passes it to the given callback function to be reconverted + * into any custom representation. + * + * @param mixed $value The value to convert. + * @param callable $callback The callback function to use for converting the real boolean value. + * + * @return mixed + * + * @throws UnexpectedValueException + */ + private function convertSingleBooleanValue($value, $callback) + { + if ($value === null) { + return $callback(null); + } + + if (is_bool($value) || is_numeric($value)) { + return $callback((bool) $value); + } + + if (! is_string($value)) { + return $callback(true); + } + + /** + * Better safe than sorry: http://php.net/in_array#106319 + */ + if (in_array(strtolower(trim($value)), $this->booleanLiterals['false'], true)) { + return $callback(false); + } + + if (in_array(strtolower(trim($value)), $this->booleanLiterals['true'], true)) { + return $callback(true); + } + + throw new UnexpectedValueException("Unrecognized boolean literal '${value}'"); + } + + /** + * Converts one or multiple boolean values. + * + * First converts the value(s) to their native PHP boolean type + * and passes them to the given callback function to be reconverted + * into any custom representation. + * + * @param mixed $item The value(s) to convert. + * @param callable $callback The callback function to use for converting the real boolean value(s). + * + * @return mixed + */ + private function doConvertBooleans($item, $callback) + { + if (is_array($item)) { + foreach ($item as $key => $value) { + $item[$key] = $this->convertSingleBooleanValue($value, $callback); + } + + return $item; + } + + return $this->convertSingleBooleanValue($item, $callback); + } + + /** + * {@inheritDoc} + * + * Postgres wants boolean values converted to the strings 'true'/'false'. + */ + public function convertBooleans($item) + { + if (! $this->useBooleanTrueFalseStrings) { + return parent::convertBooleans($item); + } + + return $this->doConvertBooleans( + $item, + /** + * @param mixed $value + */ + static function ($value) { + if ($value === null) { + return 'NULL'; + } + + return $value === true ? 'true' : 'false'; + } + ); + } + + /** + * {@inheritDoc} + */ + public function convertBooleansToDatabaseValue($item) + { + if (! $this->useBooleanTrueFalseStrings) { + return parent::convertBooleansToDatabaseValue($item); + } + + return $this->doConvertBooleans( + $item, + /** + * @param mixed $value + */ + static function ($value) { + return $value === null ? null : (int) $value; + } + ); + } + + /** + * {@inheritDoc} + */ + public function convertFromBoolean($item) + { + if ($item !== null && in_array(strtolower($item), $this->booleanLiterals['false'], true)) { + return false; + } + + return parent::convertFromBoolean($item); + } + + /** + * {@inheritDoc} + */ + public function getSequenceNextValSQL($sequence) + { + return "SELECT NEXTVAL('" . $sequence . "')"; + } + + /** + * {@inheritDoc} + */ + public function getSetTransactionIsolationSQL($level) + { + return 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL ' + . $this->_getTransactionIsolationLevelSQL($level); + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $column) + { + return 'BOOLEAN'; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $column) + { + if (! empty($column['autoincrement'])) { + return 'SERIAL'; + } + + return 'INT'; + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $column) + { + if (! empty($column['autoincrement'])) { + return 'BIGSERIAL'; + } + + return 'BIGINT'; + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $column) + { + return 'SMALLINT'; + } + + /** + * {@inheritDoc} + */ + public function getGuidTypeDeclarationSQL(array $column) + { + return 'UUID'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $column) + { + return 'TIMESTAMP(0) WITHOUT TIME ZONE'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzTypeDeclarationSQL(array $column) + { + return 'TIMESTAMP(0) WITH TIME ZONE'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $column) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $column) + { + return 'TIME(0) WITHOUT TIME ZONE'; + } + + /** + * {@inheritDoc} + * + * @deprecated Use application-generated UUIDs instead + */ + public function getGuidExpression() + { + return 'UUID_GENERATE_V4()'; + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $column) + { + return ''; + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') + : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); + } + + /** + * {@inheritdoc} + */ + protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + { + return 'BYTEA'; + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $column) + { + return 'TEXT'; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'postgresql'; + } + + /** + * {@inheritDoc} + * + * PostgreSQL returns all column names in SQL result sets in lowercase. + * + * @deprecated + */ + public function getSQLResultCasing($column) + { + return strtolower($column); + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzFormatString() + { + return 'Y-m-d H:i:sO'; + } + + /** + * {@inheritDoc} + */ + public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) + { + return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (DEFAULT)'; + } + + /** + * {@inheritDoc} + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + $tableIdentifier = new Identifier($tableName); + $sql = 'TRUNCATE ' . $tableIdentifier->getQuotedName($this); + + if ($cascade) { + $sql .= ' CASCADE'; + } + + return $sql; + } + + /** + * {@inheritDoc} + */ + public function getReadLockSQL() + { + return 'FOR SHARE'; + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = [ + 'smallint' => 'smallint', + 'int2' => 'smallint', + 'serial' => 'integer', + 'serial4' => 'integer', + 'int' => 'integer', + 'int4' => 'integer', + 'integer' => 'integer', + 'bigserial' => 'bigint', + 'serial8' => 'bigint', + 'bigint' => 'bigint', + 'int8' => 'bigint', + 'bool' => 'boolean', + 'boolean' => 'boolean', + 'text' => 'text', + 'tsvector' => 'text', + 'varchar' => 'string', + 'interval' => 'string', + '_varchar' => 'string', + 'char' => 'string', + 'bpchar' => 'string', + 'inet' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'timestamp' => 'datetime', + 'timestamptz' => 'datetimetz', + 'time' => 'time', + 'timetz' => 'time', + 'float' => 'float', + 'float4' => 'float', + 'float8' => 'float', + 'double' => 'float', + 'double precision' => 'float', + 'real' => 'float', + 'decimal' => 'decimal', + 'money' => 'decimal', + 'numeric' => 'decimal', + 'year' => 'date', + 'uuid' => 'guid', + 'bytea' => 'blob', + ]; + } + + /** + * {@inheritDoc} + */ + public function getVarcharMaxLength() + { + return 65535; + } + + /** + * {@inheritdoc} + */ + public function getBinaryMaxLength() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function getBinaryDefaultLength() + { + return 0; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return Keywords\PostgreSQLKeywords::class; + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $column) + { + return 'BYTEA'; + } + + /** + * {@inheritdoc} + */ + public function getDefaultValueDeclarationSQL($column) + { + if ($this->isSerialColumn($column)) { + return ''; + } + + return parent::getDefaultValueDeclarationSQL($column); + } + + /** + * @param mixed[] $column + */ + private function isSerialColumn(array $column): bool + { + return isset($column['type'], $column['autoincrement']) + && $column['autoincrement'] === true + && $this->isNumericType($column['type']); + } + + /** + * Check whether the type of a column is changed in a way that invalidates the default value for the column + */ + private function typeChangeBreaksDefaultValue(ColumnDiff $columnDiff): bool + { + if (! $columnDiff->fromColumn) { + return $columnDiff->hasChanged('type'); + } + + $oldTypeIsNumeric = $this->isNumericType($columnDiff->fromColumn->getType()); + $newTypeIsNumeric = $this->isNumericType($columnDiff->column->getType()); + + // default should not be changed when switching between numeric types and the default comes from a sequence + return $columnDiff->hasChanged('type') + && ! ($oldTypeIsNumeric && $newTypeIsNumeric && $columnDiff->column->getAutoincrement()); + } + + private function isNumericType(Type $type): bool + { + return $type instanceof IntegerType || $type instanceof BigIntType; + } + + private function getOldColumnComment(ColumnDiff $columnDiff): ?string + { + return $columnDiff->fromColumn ? $this->getColumnComment($columnDiff->fromColumn) : null; + } + + public function getListTableMetadataSQL(string $table, ?string $schema = null): string + { + if ($schema !== null) { + $table = $schema . '.' . $table; + } + + return sprintf( + <<<'SQL' +SELECT obj_description(%s::regclass) AS table_comment; +SQL + , + $this->quoteStringLiteral($table) + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAnywhere11Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAnywhere11Platform.php new file mode 100755 index 0000000..9448718 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAnywhere11Platform.php @@ -0,0 +1,28 @@ +getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize() . + ' START WITH ' . $sequence->getInitialValue() . + ' MINVALUE ' . $sequence->getInitialValue(); + } + + /** + * {@inheritdoc} + */ + public function getAlterSequenceSQL(Sequence $sequence) + { + return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize(); + } + + /** + * {@inheritdoc} + */ + public function getDateTimeTzFormatString() + { + return 'Y-m-d H:i:s.uP'; + } + + /** + * {@inheritdoc} + */ + public function getDateTimeTzTypeDeclarationSQL(array $column) + { + return 'TIMESTAMP WITH TIME ZONE'; + } + + /** + * {@inheritdoc} + */ + public function getDropSequenceSQL($sequence) + { + if ($sequence instanceof Sequence) { + $sequence = $sequence->getQuotedName($this); + } + + return 'DROP SEQUENCE ' . $sequence; + } + + /** + * {@inheritdoc} + */ + public function getListSequencesSQL($database) + { + return 'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE'; + } + + /** + * {@inheritdoc} + */ + public function getSequenceNextValSQL($sequence) + { + return 'SELECT ' . $sequence . '.NEXTVAL'; + } + + /** + * {@inheritdoc} + */ + public function supportsSequences() + { + return true; + } + + /** + * {@inheritdoc} + */ + protected function getAdvancedIndexOptionsSQL(Index $index) + { + if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_not_distinct')) { + return ' WITH NULLS NOT DISTINCT' . parent::getAdvancedIndexOptionsSQL($index); + } + + return parent::getAdvancedIndexOptionsSQL($index); + } + + /** + * {@inheritdoc} + */ + protected function getReservedKeywordsClass() + { + return Keywords\SQLAnywhere12Keywords::class; + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + parent::initializeDoctrineTypeMappings(); + $this->doctrineTypeMapping['timestamp with time zone'] = 'datetime'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAnywhere16Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAnywhere16Platform.php new file mode 100755 index 0000000..c278cf6 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAnywhere16Platform.php @@ -0,0 +1,41 @@ +hasFlag('with_nulls_distinct') && $index->hasFlag('with_nulls_not_distinct')) { + throw new UnexpectedValueException( + 'An Index can either have a "with_nulls_distinct" or "with_nulls_not_distinct" flag but not both.' + ); + } + + if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_distinct')) { + return ' WITH NULLS DISTINCT' . parent::getAdvancedIndexOptionsSQL($index); + } + + return parent::getAdvancedIndexOptionsSQL($index); + } + + /** + * {@inheritdoc} + */ + protected function getReservedKeywordsClass() + { + return Keywords\SQLAnywhere16Keywords::class; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php new file mode 100755 index 0000000..49eecfd --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -0,0 +1,1532 @@ +getMaxIdentifierLength(); + + if (strlen($schemaElementName) > $maxIdentifierLength) { + return substr($schemaElementName, 0, $maxIdentifierLength); + } + + return $schemaElementName; + } + + /** + * {@inheritdoc} + */ + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + { + $query = ''; + + if ($foreignKey->hasOption('match')) { + $query = ' MATCH ' . $this->getForeignKeyMatchClauseSQL($foreignKey->getOption('match')); + } + + $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey); + + if ($foreignKey->hasOption('check_on_commit') && (bool) $foreignKey->getOption('check_on_commit')) { + $query .= ' CHECK ON COMMIT'; + } + + if ($foreignKey->hasOption('clustered') && (bool) $foreignKey->getOption('clustered')) { + $query .= ' CLUSTERED'; + } + + if ($foreignKey->hasOption('for_olap_workload') && (bool) $foreignKey->getOption('for_olap_workload')) { + $query .= ' FOR OLAP WORKLOAD'; + } + + return $query; + } + + /** + * {@inheritdoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $sql = []; + $columnSql = []; + $commentsSQL = []; + $tableSql = []; + $alterClauses = []; + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $alterClauses[] = $this->getAlterTableAddColumnClause($column); + + $comment = $this->getColumnComment($column); + + if ($comment === null || $comment === '') { + continue; + } + + $commentsSQL[] = $this->getCommentOnColumnSQL( + $diff->getName($this)->getQuotedName($this), + $column->getQuotedName($this), + $comment + ); + } + + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $alterClauses[] = $this->getAlterTableRemoveColumnClause($column); + } + + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + $alterClause = $this->getAlterTableChangeColumnClause($columnDiff); + + if ($alterClause !== null) { + $alterClauses[] = $alterClause; + } + + if (! $columnDiff->hasChanged('comment')) { + continue; + } + + $column = $columnDiff->column; + + $commentsSQL[] = $this->getCommentOnColumnSQL( + $diff->getName($this)->getQuotedName($this), + $column->getQuotedName($this), + $this->getColumnComment($column) + ); + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' . + $this->getAlterTableRenameColumnClause($oldColumnName, $column); + } + + if (! $this->onSchemaAlterTable($diff, $tableSql)) { + if (! empty($alterClauses)) { + $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' . implode(', ', $alterClauses); + } + + $sql = array_merge($sql, $commentsSQL); + + $newName = $diff->getNewName(); + + if ($newName !== false) { + $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' . + $this->getAlterTableRenameTableClause($newName); + } + + $sql = array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * Returns the SQL clause for creating a column in a table alteration. + * + * @param Column $column The column to add. + * + * @return string + */ + protected function getAlterTableAddColumnClause(Column $column) + { + return 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + } + + /** + * Returns the SQL clause for altering a table. + * + * @param Identifier $tableName The quoted name of the table to alter. + * + * @return string + */ + protected function getAlterTableClause(Identifier $tableName) + { + return 'ALTER TABLE ' . $tableName->getQuotedName($this); + } + + /** + * Returns the SQL clause for dropping a column in a table alteration. + * + * @param Column $column The column to drop. + * + * @return string + */ + protected function getAlterTableRemoveColumnClause(Column $column) + { + return 'DROP ' . $column->getQuotedName($this); + } + + /** + * Returns the SQL clause for renaming a column in a table alteration. + * + * @param string $oldColumnName The quoted name of the column to rename. + * @param Column $column The column to rename to. + * + * @return string + */ + protected function getAlterTableRenameColumnClause($oldColumnName, Column $column) + { + $oldColumnName = new Identifier($oldColumnName); + + return 'RENAME ' . $oldColumnName->getQuotedName($this) . ' TO ' . $column->getQuotedName($this); + } + + /** + * Returns the SQL clause for renaming a table in a table alteration. + * + * @param Identifier $newTableName The quoted name of the table to rename to. + * + * @return string + */ + protected function getAlterTableRenameTableClause(Identifier $newTableName) + { + return 'RENAME ' . $newTableName->getQuotedName($this); + } + + /** + * Returns the SQL clause for altering a column in a table alteration. + * + * This method returns null in case that only the column comment has changed. + * Changes in column comments have to be handled differently. + * + * @param ColumnDiff $columnDiff The diff of the column to alter. + * + * @return string|null + */ + protected function getAlterTableChangeColumnClause(ColumnDiff $columnDiff) + { + $column = $columnDiff->column; + + // Do not return alter clause if only comment has changed. + if (! ($columnDiff->hasChanged('comment') && count($columnDiff->changedProperties) === 1)) { + $columnAlterationClause = 'ALTER ' . + $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + + if ($columnDiff->hasChanged('default') && $column->getDefault() === null) { + $columnAlterationClause .= ', ALTER ' . $column->getQuotedName($this) . ' DROP DEFAULT'; + } + + return $columnAlterationClause; + } + + return null; + } + + /** + * {@inheritdoc} + */ + public function getBigIntTypeDeclarationSQL(array $column) + { + $column['integer_type'] = 'BIGINT'; + + return $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function getBinaryDefaultLength() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function getBinaryMaxLength() + { + return 32767; + } + + /** + * {@inheritdoc} + */ + public function getBlobTypeDeclarationSQL(array $column) + { + return 'LONG BINARY'; + } + + /** + * {@inheritdoc} + * + * BIT type columns require an explicit NULL declaration + * in SQL Anywhere if they shall be nullable. + * Otherwise by just omitting the NOT NULL clause, + * SQL Anywhere will declare them NOT NULL nonetheless. + */ + public function getBooleanTypeDeclarationSQL(array $column) + { + $nullClause = isset($column['notnull']) && (bool) $column['notnull'] === false ? ' NULL' : ''; + + return 'BIT' . $nullClause; + } + + /** + * {@inheritdoc} + */ + public function getClobTypeDeclarationSQL(array $column) + { + return 'TEXT'; + } + + /** + * {@inheritdoc} + */ + public function getCommentOnColumnSQL($tableName, $columnName, $comment) + { + $tableName = new Identifier($tableName); + $columnName = new Identifier($columnName); + $comment = $comment === null ? 'NULL' : $this->quoteStringLiteral($comment); + + return sprintf( + 'COMMENT ON COLUMN %s.%s IS %s', + $tableName->getQuotedName($this), + $columnName->getQuotedName($this), + $comment + ); + } + + /** + * {@inheritdoc} + */ + public function getConcatExpression() + { + return 'STRING(' . implode(', ', func_get_args()) . ')'; + } + + /** + * {@inheritdoc} + */ + public function getCreateConstraintSQL(Constraint $constraint, $table) + { + if ($constraint instanceof ForeignKeyConstraint) { + return $this->getCreateForeignKeySQL($constraint, $table); + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + return 'ALTER TABLE ' . $table . + ' ADD ' . $this->getTableConstraintDeclarationSQL($constraint, $constraint->getQuotedName($this)); + } + + /** + * {@inheritdoc} + */ + public function getCreateDatabaseSQL($name) + { + $name = new Identifier($name); + + return "CREATE DATABASE '" . $name->getName() . "'"; + } + + /** + * {@inheritdoc} + * + * Appends SQL Anywhere specific flags if given. + */ + public function getCreateIndexSQL(Index $index, $table) + { + return parent::getCreateIndexSQL($index, $table) . $this->getAdvancedIndexOptionsSQL($index); + } + + /** + * {@inheritdoc} + */ + public function getCreatePrimaryKeySQL(Index $index, $table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + return 'ALTER TABLE ' . $table . ' ADD ' . $this->getPrimaryKeyDeclarationSQL($index); + } + + /** + * {@inheritdoc} + */ + public function getCreateTemporaryTableSnippetSQL() + { + return 'CREATE ' . $this->getTemporaryTableSQL() . ' TABLE'; + } + + /** + * {@inheritdoc} + */ + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + /** + * {@inheritdoc} + */ + public function getCurrentDateSQL() + { + return 'CURRENT DATE'; + } + + /** + * {@inheritdoc} + */ + public function getCurrentTimeSQL() + { + return 'CURRENT TIME'; + } + + /** + * {@inheritdoc} + */ + public function getCurrentTimestampSQL() + { + return 'CURRENT TIMESTAMP'; + } + + /** + * {@inheritdoc} + */ + protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + { + $factorClause = ''; + + if ($operator === '-') { + $factorClause = '-1 * '; + } + + return 'DATEADD(' . $unit . ', ' . $factorClause . $interval . ', ' . $date . ')'; + } + + /** + * {@inheritdoc} + */ + public function getDateDiffExpression($date1, $date2) + { + return 'DATEDIFF(day, ' . $date2 . ', ' . $date1 . ')'; + } + + /** + * {@inheritdoc} + */ + public function getDateTimeFormatString() + { + return 'Y-m-d H:i:s.u'; + } + + /** + * {@inheritdoc} + */ + public function getDateTimeTypeDeclarationSQL(array $column) + { + return 'DATETIME'; + } + + /** + * {@inheritdoc} + */ + public function getDateTimeTzFormatString() + { + return $this->getDateTimeFormatString(); + } + + /** + * {@inheritdoc} + */ + public function getDateTypeDeclarationSQL(array $column) + { + return 'DATE'; + } + + /** + * {@inheritdoc} + */ + public function getDefaultTransactionIsolationLevel() + { + return TransactionIsolationLevel::READ_UNCOMMITTED; + } + + /** + * {@inheritdoc} + */ + public function getDropDatabaseSQL($name) + { + $name = new Identifier($name); + + return "DROP DATABASE '" . $name->getName() . "'"; + } + + /** + * {@inheritdoc} + */ + public function getDropIndexSQL($index, $table = null) + { + if ($index instanceof Index) { + $index = $index->getQuotedName($this); + } + + if (! is_string($index)) { + throw new InvalidArgumentException( + __METHOD__ . '() expects $index parameter to be string or ' . Index::class . '.' + ); + } + + if (! isset($table)) { + return 'DROP INDEX ' . $index; + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + if (! is_string($table)) { + throw new InvalidArgumentException( + __METHOD__ . '() expects $table parameter to be string or ' . Index::class . '.' + ); + } + + return 'DROP INDEX ' . $table . '.' . $index; + } + + /** + * {@inheritdoc} + */ + public function getDropViewSQL($name) + { + return 'DROP VIEW ' . $name; + } + + /** + * {@inheritdoc} + */ + public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey) + { + $sql = ''; + $foreignKeyName = $foreignKey->getName(); + $localColumns = $foreignKey->getQuotedLocalColumns($this); + $foreignColumns = $foreignKey->getQuotedForeignColumns($this); + $foreignTableName = $foreignKey->getQuotedForeignTableName($this); + + if (! empty($foreignKeyName)) { + $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' '; + } + + if (empty($localColumns)) { + throw new InvalidArgumentException("Incomplete definition. 'local' required."); + } + + if (empty($foreignColumns)) { + throw new InvalidArgumentException("Incomplete definition. 'foreign' required."); + } + + if (empty($foreignTableName)) { + throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required."); + } + + if ($foreignKey->hasOption('notnull') && (bool) $foreignKey->getOption('notnull')) { + $sql .= 'NOT NULL '; + } + + return $sql . + 'FOREIGN KEY (' . $this->getIndexFieldDeclarationListSQL($localColumns) . ') ' . + 'REFERENCES ' . $foreignKey->getQuotedForeignTableName($this) . + ' (' . $this->getIndexFieldDeclarationListSQL($foreignColumns) . ')'; + } + + /** + * Returns foreign key MATCH clause for given type. + * + * @param int $type The foreign key match type + * + * @return string + * + * @throws InvalidArgumentException If unknown match type given. + */ + public function getForeignKeyMatchClauseSQL($type) + { + switch ((int) $type) { + case self::FOREIGN_KEY_MATCH_SIMPLE: + return 'SIMPLE'; + + case self::FOREIGN_KEY_MATCH_FULL: + return 'FULL'; + + case self::FOREIGN_KEY_MATCH_SIMPLE_UNIQUE: + return 'UNIQUE SIMPLE'; + + case self::FOREIGN_KEY_MATCH_FULL_UNIQUE: + return 'UNIQUE FULL'; + + default: + throw new InvalidArgumentException('Invalid foreign key match type: ' . $type); + } + } + + /** + * {@inheritdoc} + */ + public function getForeignKeyReferentialActionSQL($action) + { + // NO ACTION is not supported, therefore falling back to RESTRICT. + if (strtoupper($action) === 'NO ACTION') { + return 'RESTRICT'; + } + + return parent::getForeignKeyReferentialActionSQL($action); + } + + /** + * {@inheritdoc} + */ + public function getForUpdateSQL() + { + return ''; + } + + /** + * {@inheritdoc} + * + * @deprecated Use application-generated UUIDs instead + */ + public function getGuidExpression() + { + return 'NEWID()'; + } + + /** + * {@inheritdoc} + */ + public function getGuidTypeDeclarationSQL(array $column) + { + return 'UNIQUEIDENTIFIER'; + } + + /** + * {@inheritdoc} + */ + public function getIndexDeclarationSQL($name, Index $index) + { + // Index declaration in statements like CREATE TABLE is not supported. + throw Exception::notSupported(__METHOD__); + } + + /** + * {@inheritdoc} + */ + public function getIntegerTypeDeclarationSQL(array $column) + { + $column['integer_type'] = 'INT'; + + return $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function getListDatabasesSQL() + { + return 'SELECT db_name(number) AS name FROM sa_db_list()'; + } + + /** + * {@inheritdoc} + */ + public function getListTableColumnsSQL($table, $database = null) + { + $user = 'USER_NAME()'; + + if (strpos($table, '.') !== false) { + [$user, $table] = explode('.', $table); + $user = $this->quoteStringLiteral($user); + } + + return sprintf( + <<<'SQL' +SELECT col.column_name, + COALESCE(def.user_type_name, def.domain_name) AS 'type', + def.declared_width AS 'length', + def.scale, + CHARINDEX('unsigned', def.domain_name) AS 'unsigned', + IF col.nulls = 'Y' THEN 0 ELSE 1 ENDIF AS 'notnull', + col."default", + def.is_autoincrement AS 'autoincrement', + rem.remarks AS 'comment' +FROM sa_describe_query('SELECT * FROM "%s"') AS def +JOIN SYS.SYSTABCOL AS col +ON col.table_id = def.base_table_id AND col.column_id = def.base_column_id +LEFT JOIN SYS.SYSREMARK AS rem +ON col.object_id = rem.object_id +WHERE def.base_owner_name = %s +ORDER BY def.base_column_id ASC +SQL + , + $table, + $user + ); + } + + /** + * {@inheritdoc} + * + * @todo Where is this used? Which information should be retrieved? + */ + public function getListTableConstraintsSQL($table) + { + $user = ''; + + if (strpos($table, '.') !== false) { + [$user, $table] = explode('.', $table); + $user = $this->quoteStringLiteral($user); + $table = $this->quoteStringLiteral($table); + } else { + $table = $this->quoteStringLiteral($table); + } + + return sprintf( + <<<'SQL' +SELECT con.* +FROM SYS.SYSCONSTRAINT AS con +JOIN SYS.SYSTAB AS tab ON con.table_object_id = tab.object_id +WHERE tab.table_name = %s +AND tab.creator = USER_ID(%s) +SQL + , + $table, + $user + ); + } + + /** + * {@inheritdoc} + */ + public function getListTableForeignKeysSQL($table) + { + $user = ''; + + if (strpos($table, '.') !== false) { + [$user, $table] = explode('.', $table); + $user = $this->quoteStringLiteral($user); + $table = $this->quoteStringLiteral($table); + } else { + $table = $this->quoteStringLiteral($table); + } + + return sprintf( + <<<'SQL' +SELECT fcol.column_name AS local_column, + ptbl.table_name AS foreign_table, + pcol.column_name AS foreign_column, + idx.index_name, + IF fk.nulls = 'N' + THEN 1 + ELSE NULL + ENDIF AS notnull, + CASE ut.referential_action + WHEN 'C' THEN 'CASCADE' + WHEN 'D' THEN 'SET DEFAULT' + WHEN 'N' THEN 'SET NULL' + WHEN 'R' THEN 'RESTRICT' + ELSE NULL + END AS on_update, + CASE dt.referential_action + WHEN 'C' THEN 'CASCADE' + WHEN 'D' THEN 'SET DEFAULT' + WHEN 'N' THEN 'SET NULL' + WHEN 'R' THEN 'RESTRICT' + ELSE NULL + END AS on_delete, + IF fk.check_on_commit = 'Y' + THEN 1 + ELSE NULL + ENDIF AS check_on_commit, -- check_on_commit flag + IF ftbl.clustered_index_id = idx.index_id + THEN 1 + ELSE NULL + ENDIF AS 'clustered', -- clustered flag + IF fk.match_type = 0 + THEN NULL + ELSE fk.match_type + ENDIF AS 'match', -- match option + IF pidx.max_key_distance = 1 + THEN 1 + ELSE NULL + ENDIF AS for_olap_workload -- for_olap_workload flag +FROM SYS.SYSFKEY AS fk +JOIN SYS.SYSIDX AS idx +ON fk.foreign_table_id = idx.table_id +AND fk.foreign_index_id = idx.index_id +JOIN SYS.SYSPHYSIDX pidx +ON idx.table_id = pidx.table_id +AND idx.phys_index_id = pidx.phys_index_id +JOIN SYS.SYSTAB AS ptbl +ON fk.primary_table_id = ptbl.table_id +JOIN SYS.SYSTAB AS ftbl +ON fk.foreign_table_id = ftbl.table_id +JOIN SYS.SYSIDXCOL AS idxcol +ON idx.table_id = idxcol.table_id +AND idx.index_id = idxcol.index_id +JOIN SYS.SYSTABCOL AS pcol +ON ptbl.table_id = pcol.table_id +AND idxcol.primary_column_id = pcol.column_id +JOIN SYS.SYSTABCOL AS fcol +ON ftbl.table_id = fcol.table_id +AND idxcol.column_id = fcol.column_id +LEFT JOIN SYS.SYSTRIGGER ut +ON fk.foreign_table_id = ut.foreign_table_id +AND fk.foreign_index_id = ut.foreign_key_id +AND ut.event = 'C' +LEFT JOIN SYS.SYSTRIGGER dt +ON fk.foreign_table_id = dt.foreign_table_id +AND fk.foreign_index_id = dt.foreign_key_id +AND dt.event = 'D' +WHERE ftbl.table_name = %s +AND ftbl.creator = USER_ID(%s) +ORDER BY fk.foreign_index_id ASC, idxcol.sequence ASC +SQL + , + $table, + $user + ); + } + + /** + * {@inheritdoc} + */ + public function getListTableIndexesSQL($table, $database = null) + { + $user = ''; + + if (strpos($table, '.') !== false) { + [$user, $table] = explode('.', $table); + $user = $this->quoteStringLiteral($user); + $table = $this->quoteStringLiteral($table); + } else { + $table = $this->quoteStringLiteral($table); + } + + return sprintf( + <<<'SQL' +SELECT idx.index_name AS key_name, + IF idx.index_category = 1 + THEN 1 + ELSE 0 + ENDIF AS 'primary', + col.column_name, + IF idx."unique" IN(1, 2, 5) + THEN 0 + ELSE 1 + ENDIF AS non_unique, + IF tbl.clustered_index_id = idx.index_id + THEN 1 + ELSE NULL + ENDIF AS 'clustered', -- clustered flag + IF idx."unique" = 5 + THEN 1 + ELSE NULL + ENDIF AS with_nulls_not_distinct, -- with_nulls_not_distinct flag + IF pidx.max_key_distance = 1 + THEN 1 + ELSE NULL + ENDIF AS for_olap_workload -- for_olap_workload flag +FROM SYS.SYSIDX AS idx +JOIN SYS.SYSPHYSIDX pidx +ON idx.table_id = pidx.table_id +AND idx.phys_index_id = pidx.phys_index_id +JOIN SYS.SYSIDXCOL AS idxcol +ON idx.table_id = idxcol.table_id AND idx.index_id = idxcol.index_id +JOIN SYS.SYSTABCOL AS col +ON idxcol.table_id = col.table_id AND idxcol.column_id = col.column_id +JOIN SYS.SYSTAB AS tbl +ON idx.table_id = tbl.table_id +WHERE tbl.table_name = %s +AND tbl.creator = USER_ID(%s) +AND idx.index_category != 2 -- exclude indexes implicitly created by foreign key constraints +ORDER BY idx.index_id ASC, idxcol.sequence ASC +SQL + , + $table, + $user + ); + } + + /** + * {@inheritdoc} + */ + public function getListTablesSQL() + { + return "SELECT tbl.table_name + FROM SYS.SYSTAB AS tbl + JOIN SYS.SYSUSER AS usr ON tbl.creator = usr.user_id + JOIN dbo.SYSOBJECTS AS obj ON tbl.object_id = obj.id + WHERE tbl.table_type IN(1, 3) -- 'BASE', 'GBL TEMP' + AND usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users + AND obj.type = 'U' -- user created tables only + ORDER BY tbl.table_name ASC"; + } + + /** + * {@inheritdoc} + * + * @todo Where is this used? Which information should be retrieved? + */ + public function getListUsersSQL() + { + return 'SELECT * FROM SYS.SYSUSER ORDER BY user_name ASC'; + } + + /** + * {@inheritdoc} + */ + public function getListViewsSQL($database) + { + return "SELECT tbl.table_name, v.view_def + FROM SYS.SYSVIEW v + JOIN SYS.SYSTAB tbl ON v.view_object_id = tbl.object_id + JOIN SYS.SYSUSER usr ON tbl.creator = usr.user_id + JOIN dbo.SYSOBJECTS obj ON tbl.object_id = obj.id + WHERE usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users + ORDER BY tbl.table_name ASC"; + } + + /** + * {@inheritdoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos === false) { + return 'LOCATE(' . $str . ', ' . $substr . ')'; + } + + return 'LOCATE(' . $str . ', ' . $substr . ', ' . $startPos . ')'; + } + + /** + * {@inheritdoc} + */ + public function getMaxIdentifierLength() + { + return 128; + } + + /** + * {@inheritdoc} + */ + public function getMd5Expression($column) + { + return 'HASH(' . $column . ", 'MD5')"; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'sqlanywhere'; + } + + /** + * Obtain DBMS specific SQL code portion needed to set a primary key + * declaration to be used in statements like ALTER TABLE. + * + * @param Index $index Index definition + * @param string $name Name of the primary key + * + * @return string DBMS specific SQL code portion needed to set a primary key + * + * @throws InvalidArgumentException If the given index is not a primary key. + */ + public function getPrimaryKeyDeclarationSQL(Index $index, $name = null) + { + if (! $index->isPrimary()) { + throw new InvalidArgumentException( + 'Can only create primary key declarations with getPrimaryKeyDeclarationSQL()' + ); + } + + return $this->getTableConstraintDeclarationSQL($index, $name); + } + + /** + * {@inheritdoc} + */ + public function getSetTransactionIsolationSQL($level) + { + return 'SET TEMPORARY OPTION isolation_level = ' . $this->_getTransactionIsolationLevelSQL($level); + } + + /** + * {@inheritdoc} + */ + public function getSmallIntTypeDeclarationSQL(array $column) + { + $column['integer_type'] = 'SMALLINT'; + + return $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * Returns the SQL statement for starting an existing database. + * + * In SQL Anywhere you can start and stop databases on a + * database server instance. + * This is a required statement after having created a new database + * as it has to be explicitly started to be usable. + * SQL Anywhere does not automatically start a database after creation! + * + * @param string $database Name of the database to start. + * + * @return string + */ + public function getStartDatabaseSQL($database) + { + $database = new Identifier($database); + + return "START DATABASE '" . $database->getName() . "' AUTOSTOP OFF"; + } + + /** + * Returns the SQL statement for stopping a running database. + * + * In SQL Anywhere you can start and stop databases on a + * database server instance. + * This is a required statement before dropping an existing database + * as it has to be explicitly stopped before it can be dropped. + * + * @param string $database Name of the database to stop. + * + * @return string + */ + public function getStopDatabaseSQL($database) + { + $database = new Identifier($database); + + return 'STOP DATABASE "' . $database->getName() . '" UNCONDITIONALLY'; + } + + /** + * {@inheritdoc} + */ + public function getSubstringExpression($string, $start, $length = null) + { + if ($length === null) { + return 'SUBSTRING(' . $string . ', ' . $start . ')'; + } + + return 'SUBSTRING(' . $string . ', ' . $start . ', ' . $length . ')'; + } + + /** + * {@inheritdoc} + */ + public function getTemporaryTableSQL() + { + return 'GLOBAL TEMPORARY'; + } + + /** + * {@inheritdoc} + */ + public function getTimeFormatString() + { + return 'H:i:s.u'; + } + + /** + * {@inheritdoc} + */ + public function getTimeTypeDeclarationSQL(array $column) + { + return 'TIME'; + } + + /** + * {@inheritdoc} + */ + public function getTrimExpression($str, $mode = TrimMode::UNSPECIFIED, $char = false) + { + if (! $char) { + switch ($mode) { + case TrimMode::LEADING: + return $this->getLtrimExpression($str); + + case TrimMode::TRAILING: + return $this->getRtrimExpression($str); + + default: + return 'TRIM(' . $str . ')'; + } + } + + $pattern = "'%[^' + " . $char . " + ']%'"; + + switch ($mode) { + case TrimMode::LEADING: + return 'SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))'; + + case TrimMode::TRAILING: + return 'REVERSE(SUBSTR(REVERSE(' . $str . '), PATINDEX(' . $pattern . ', REVERSE(' . $str . '))))'; + + default: + return 'REVERSE(SUBSTR(REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))), ' . + 'PATINDEX(' . $pattern . ', ' . + 'REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))))))'; + } + } + + /** + * {@inheritdoc} + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + $tableIdentifier = new Identifier($tableName); + + return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this); + } + + /** + * {@inheritdoc} + */ + public function getUniqueConstraintDeclarationSQL($name, Index $index) + { + if ($index->isPrimary()) { + throw new InvalidArgumentException( + 'Cannot create primary key constraint declarations with getUniqueConstraintDeclarationSQL().' + ); + } + + if (! $index->isUnique()) { + throw new InvalidArgumentException( + 'Can only create unique constraint declarations, no common index declarations with ' . + 'getUniqueConstraintDeclarationSQL().' + ); + } + + return $this->getTableConstraintDeclarationSQL($index, $name); + } + + /** + * {@inheritdoc} + */ + public function getVarcharDefaultLength() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function getVarcharMaxLength() + { + return 32767; + } + + /** + * {@inheritdoc} + */ + public function hasNativeGuidType() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function prefersIdentityColumns() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function supportsCommentOnStatement() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritdoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $column) + { + $unsigned = ! empty($column['unsigned']) ? 'UNSIGNED ' : ''; + $autoincrement = ! empty($column['autoincrement']) ? ' IDENTITY' : ''; + + return $unsigned . $column['integer_type'] . $autoincrement; + } + + /** + * {@inheritdoc} + */ + protected function _getCreateTableSQL($name, array $columns, array $options = []) + { + $columnListSql = $this->getColumnDeclarationListSQL($columns); + $indexSql = []; + + if (! empty($options['uniqueConstraints'])) { + foreach ((array) $options['uniqueConstraints'] as $name => $definition) { + $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); + } + } + + if (! empty($options['indexes'])) { + foreach ((array) $options['indexes'] as $index) { + assert($index instanceof Index); + $indexSql[] = $this->getCreateIndexSQL($index, $name); + } + } + + if (! empty($options['primary'])) { + $flags = ''; + + if (isset($options['primary_index']) && $options['primary_index']->hasFlag('clustered')) { + $flags = ' CLUSTERED '; + } + + $columnListSql .= ', PRIMARY KEY' . $flags + . ' (' . implode(', ', array_unique(array_values((array) $options['primary']))) . ')'; + } + + if (! empty($options['foreignKeys'])) { + foreach ((array) $options['foreignKeys'] as $definition) { + $columnListSql .= ', ' . $this->getForeignKeyDeclarationSQL($definition); + } + } + + $query = 'CREATE TABLE ' . $name . ' (' . $columnListSql; + $check = $this->getCheckDeclarationSQL($columns); + + if (! empty($check)) { + $query .= ', ' . $check; + } + + $query .= ')'; + + return array_merge([$query], $indexSql); + } + + /** + * {@inheritdoc} + */ + protected function _getTransactionIsolationLevelSQL($level) + { + switch ($level) { + case TransactionIsolationLevel::READ_UNCOMMITTED: + return '0'; + + case TransactionIsolationLevel::READ_COMMITTED: + return '1'; + + case TransactionIsolationLevel::REPEATABLE_READ: + return '2'; + + case TransactionIsolationLevel::SERIALIZABLE: + return '3'; + + default: + throw new InvalidArgumentException('Invalid isolation level:' . $level); + } + } + + /** + * {@inheritdoc} + */ + protected function doModifyLimitQuery($query, $limit, $offset) + { + $limitOffsetClause = $this->getTopClauseSQL($limit, $offset); + + if ($limitOffsetClause === '') { + return $query; + } + + if (! preg_match('/^\s*(SELECT\s+(DISTINCT\s+)?)(.*)/i', $query, $matches)) { + return $query; + } + + return $matches[1] . $limitOffsetClause . ' ' . $matches[3]; + } + + private function getTopClauseSQL(?int $limit, ?int $offset): string + { + if ($offset > 0) { + return sprintf('TOP %s START AT %d', $limit ?? 'ALL', $offset + 1); + } + + return $limit === null ? '' : 'TOP ' . $limit; + } + + /** + * Return the INDEX query section dealing with non-standard + * SQL Anywhere options. + * + * @param Index $index Index definition + * + * @return string + */ + protected function getAdvancedIndexOptionsSQL(Index $index) + { + $sql = ''; + + if (! $index->isPrimary() && $index->hasFlag('for_olap_workload')) { + $sql .= ' FOR OLAP WORKLOAD'; + } + + return $sql; + } + + /** + * {@inheritdoc} + */ + protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed + ? 'BINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')' + : 'VARBINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')'; + } + + /** + * Returns the SQL snippet for creating a table constraint. + * + * @param Constraint $constraint The table constraint to create the SQL snippet for. + * @param string|null $name The table constraint name to use if any. + * + * @return string + * + * @throws InvalidArgumentException If the given table constraint type is not supported by this method. + */ + protected function getTableConstraintDeclarationSQL(Constraint $constraint, $name = null) + { + if ($constraint instanceof ForeignKeyConstraint) { + return $this->getForeignKeyDeclarationSQL($constraint); + } + + if (! $constraint instanceof Index) { + throw new InvalidArgumentException('Unsupported constraint type: ' . get_class($constraint)); + } + + if (! $constraint->isPrimary() && ! $constraint->isUnique()) { + throw new InvalidArgumentException( + 'Can only create primary, unique or foreign key constraint declarations, no common index declarations' + . ' with getTableConstraintDeclarationSQL().' + ); + } + + $constraintColumns = $constraint->getQuotedColumns($this); + + if (empty($constraintColumns)) { + throw new InvalidArgumentException("Incomplete definition. 'columns' required."); + } + + $sql = ''; + $flags = ''; + + if (! empty($name)) { + $name = new Identifier($name); + $sql .= 'CONSTRAINT ' . $name->getQuotedName($this) . ' '; + } + + if ($constraint->hasFlag('clustered')) { + $flags = 'CLUSTERED '; + } + + if ($constraint->isPrimary()) { + return $sql . 'PRIMARY KEY ' . $flags + . '(' . $this->getIndexFieldDeclarationListSQL($constraintColumns) . ')'; + } + + return $sql . 'UNIQUE ' . $flags . '(' . $this->getIndexFieldDeclarationListSQL($constraintColumns) . ')'; + } + + /** + * {@inheritdoc} + */ + protected function getCreateIndexSQLFlags(Index $index) + { + $type = ''; + if ($index->hasFlag('virtual')) { + $type .= 'VIRTUAL '; + } + + if ($index->isUnique()) { + $type .= 'UNIQUE '; + } + + if ($index->hasFlag('clustered')) { + $type .= 'CLUSTERED '; + } + + return $type; + } + + /** + * {@inheritdoc} + */ + protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + { + return ['ALTER INDEX ' . $oldIndexName . ' ON ' . $tableName . ' RENAME TO ' . $index->getQuotedName($this)]; + } + + /** + * {@inheritdoc} + */ + protected function getReservedKeywordsClass() + { + return Keywords\SQLAnywhereKeywords::class; + } + + /** + * {@inheritdoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed + ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(' . $this->getVarcharDefaultLength() . ')') + : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(' . $this->getVarcharDefaultLength() . ')'); + } + + /** + * {@inheritdoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = [ + 'char' => 'string', + 'long nvarchar' => 'text', + 'long varchar' => 'text', + 'nchar' => 'string', + 'ntext' => 'text', + 'nvarchar' => 'string', + 'text' => 'text', + 'uniqueidentifierstr' => 'guid', + 'varchar' => 'string', + 'xml' => 'text', + 'bigint' => 'bigint', + 'unsigned bigint' => 'bigint', + 'bit' => 'boolean', + 'decimal' => 'decimal', + 'double' => 'float', + 'float' => 'float', + 'int' => 'integer', + 'integer' => 'integer', + 'unsigned int' => 'integer', + 'numeric' => 'decimal', + 'smallint' => 'smallint', + 'unsigned smallint' => 'smallint', + 'tinyint' => 'smallint', + 'unsigned tinyint' => 'smallint', + 'money' => 'decimal', + 'smallmoney' => 'decimal', + 'long varbit' => 'text', + 'varbit' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'smalldatetime' => 'datetime', + 'time' => 'time', + 'timestamp' => 'datetime', + 'binary' => 'binary', + 'image' => 'blob', + 'long binary' => 'blob', + 'uniqueidentifier' => 'guid', + 'varbinary' => 'binary', + ]; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php new file mode 100755 index 0000000..f281f4f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php @@ -0,0 +1,35 @@ +hasOption('azure.federatedOnColumnName')) { + $distributionName = $table->getOption('azure.federatedOnDistributionName'); + $columnName = $table->getOption('azure.federatedOnColumnName'); + $stmt = ' FEDERATED ON (' . $distributionName . ' = ' . $columnName . ')'; + + $sql[0] .= $stmt; + } + + return $sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php new file mode 100755 index 0000000..6f02bb8 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php @@ -0,0 +1,48 @@ +doctrineTypeMapping['datetime2'] = 'datetime'; + $this->doctrineTypeMapping['date'] = 'date'; + $this->doctrineTypeMapping['time'] = 'time'; + $this->doctrineTypeMapping['datetimeoffset'] = 'datetimetz'; + } + + /** + * {@inheritdoc} + * + * Returns Microsoft SQL Server 2008 specific keywords class + */ + protected function getReservedKeywordsClass() + { + return Keywords\SQLServer2008Keywords::class; + } + + protected function getLikeWildcardCharacters(): string + { + return parent::getLikeWildcardCharacters() . '[]^'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php new file mode 100755 index 0000000..0bd70d3 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php @@ -0,0 +1,165 @@ +getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize(); + } + + /** + * {@inheritdoc} + */ + public function getCreateSequenceSQL(Sequence $sequence) + { + return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . + ' START WITH ' . $sequence->getInitialValue() . + ' INCREMENT BY ' . $sequence->getAllocationSize() . + ' MINVALUE ' . $sequence->getInitialValue(); + } + + /** + * {@inheritdoc} + */ + public function getDropSequenceSQL($sequence) + { + if ($sequence instanceof Sequence) { + $sequence = $sequence->getQuotedName($this); + } + + return 'DROP SEQUENCE ' . $sequence; + } + + /** + * {@inheritdoc} + */ + public function getListSequencesSQL($database) + { + return 'SELECT seq.name, + CAST( + seq.increment AS VARCHAR(MAX) + ) AS increment, -- CAST avoids driver error for sql_variant type + CAST( + seq.start_value AS VARCHAR(MAX) + ) AS start_value -- CAST avoids driver error for sql_variant type + FROM sys.sequences AS seq'; + } + + /** + * {@inheritdoc} + */ + public function getSequenceNextValSQL($sequence) + { + return 'SELECT NEXT VALUE FOR ' . $sequence; + } + + /** + * {@inheritdoc} + */ + public function supportsSequences() + { + return true; + } + + /** + * {@inheritdoc} + * + * Returns Microsoft SQL Server 2012 specific keywords class + */ + protected function getReservedKeywordsClass() + { + return Keywords\SQLServer2012Keywords::class; + } + + /** + * {@inheritdoc} + */ + protected function doModifyLimitQuery($query, $limit, $offset = null) + { + if ($limit === null && $offset <= 0) { + return $query; + } + + // Queries using OFFSET... FETCH MUST have an ORDER BY clause + if ($this->shouldAddOrderBy($query)) { + if (preg_match('/^SELECT\s+DISTINCT/im', $query)) { + // SQL Server won't let us order by a non-selected column in a DISTINCT query, + // so we have to do this madness. This says, order by the first column in the + // result. SQL Server's docs say that a nonordered query's result order is non- + // deterministic anyway, so this won't do anything that a bunch of update and + // deletes to the table wouldn't do anyway. + $query .= ' ORDER BY 1'; + } else { + // In another DBMS, we could do ORDER BY 0, but SQL Server gets angry if you + // use constant expressions in the order by list. + $query .= ' ORDER BY (SELECT 0)'; + } + } + + if ($offset === null) { + $offset = 0; + } + + // This looks somewhat like MYSQL, but limit/offset are in inverse positions + // Supposedly SQL:2008 core standard. + // Per TSQL spec, FETCH NEXT n ROWS ONLY is not valid without OFFSET n ROWS. + $query .= ' OFFSET ' . (int) $offset . ' ROWS'; + + if ($limit !== null) { + $query .= ' FETCH NEXT ' . (int) $limit . ' ROWS ONLY'; + } + + return $query; + } + + /** + * @param string $query + */ + private function shouldAddOrderBy($query): bool + { + // Find the position of the last instance of ORDER BY and ensure it is not within a parenthetical statement + // but can be in a newline + $matches = []; + $matchesCount = preg_match_all('/[\\s]+order\\s+by\\s/im', $query, $matches, PREG_OFFSET_CAPTURE); + if ($matchesCount === 0) { + return true; + } + + // ORDER BY instance may be in a subquery after ORDER BY + // e.g. SELECT col1 FROM test ORDER BY (SELECT col2 from test ORDER BY col2) + // if in the searched query ORDER BY clause was found where + // number of open parentheses after the occurrence of the clause is equal to + // number of closed brackets after the occurrence of the clause, + // it means that ORDER BY is included in the query being checked + while ($matchesCount > 0) { + $orderByPos = $matches[0][--$matchesCount][1]; + $openBracketsCount = substr_count($query, '(', $orderByPos); + $closedBracketsCount = substr_count($query, ')', $orderByPos); + if ($openBracketsCount === $closedBracketsCount) { + return false; + } + } + + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php new file mode 100755 index 0000000..2b95801 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -0,0 +1,1718 @@ +getConvertExpression('date', 'GETDATE()'); + } + + /** + * {@inheritdoc} + */ + public function getCurrentTimeSQL() + { + return $this->getConvertExpression('time', 'GETDATE()'); + } + + /** + * Returns an expression that converts an expression of one data type to another. + * + * @param string $dataType The target native data type. Alias data types cannot be used. + * @param string $expression The SQL expression to convert. + * + * @return string + */ + private function getConvertExpression($dataType, $expression) + { + return sprintf('CONVERT(%s, %s)', $dataType, $expression); + } + + /** + * {@inheritdoc} + */ + protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + { + $factorClause = ''; + + if ($operator === '-') { + $factorClause = '-1 * '; + } + + return 'DATEADD(' . $unit . ', ' . $factorClause . $interval . ', ' . $date . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateDiffExpression($date1, $date2) + { + return 'DATEDIFF(day, ' . $date2 . ',' . $date1 . ')'; + } + + /** + * {@inheritDoc} + * + * Microsoft SQL Server prefers "autoincrement" identity columns + * since sequences can only be emulated with a table. + */ + public function prefersIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + * + * Microsoft SQL Server supports this through AUTO_INCREMENT columns. + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsReleaseSavepoints() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function supportsSchemas() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getDefaultSchemaName() + { + return 'dbo'; + } + + /** + * {@inheritDoc} + */ + public function supportsColumnCollation() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function hasNativeGuidType() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getCreateDatabaseSQL($name) + { + return 'CREATE DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getDropDatabaseSQL($name) + { + return 'DROP DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + public function supportsCreateDropDatabase() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getCreateSchemaSQL($schemaName) + { + return 'CREATE SCHEMA ' . $schemaName; + } + + /** + * {@inheritDoc} + */ + public function getDropForeignKeySQL($foreignKey, $table) + { + if (! $foreignKey instanceof ForeignKeyConstraint) { + $foreignKey = new Identifier($foreignKey); + } + + if (! $table instanceof Table) { + $table = new Identifier($table); + } + + $foreignKey = $foreignKey->getQuotedName($this); + $table = $table->getQuotedName($this); + + return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey; + } + + /** + * {@inheritDoc} + */ + public function getDropIndexSQL($index, $table = null) + { + if ($index instanceof Index) { + $index = $index->getQuotedName($this); + } elseif (! is_string($index)) { + throw new InvalidArgumentException( + __METHOD__ . '() expects $index parameter to be string or ' . Index::class . '.' + ); + } + + if (! isset($table)) { + return 'DROP INDEX ' . $index; + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + return sprintf( + " + IF EXISTS (SELECT * FROM sysobjects WHERE name = '%s') + ALTER TABLE %s DROP CONSTRAINT %s + ELSE + DROP INDEX %s ON %s + ", + $index, + $table, + $index, + $index, + $table + ); + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($name, array $columns, array $options = []) + { + $defaultConstraintsSql = []; + $commentsSql = []; + + $tableComment = $options['comment'] ?? null; + if ($tableComment !== null) { + $commentsSql[] = $this->getCommentOnTableSQL($name, $tableComment); + } + + // @todo does other code breaks because of this? + // force primary keys to be not null + foreach ($columns as &$column) { + if (isset($column['primary']) && $column['primary']) { + $column['notnull'] = true; + } + + // Build default constraints SQL statements. + if (isset($column['default'])) { + $defaultConstraintsSql[] = 'ALTER TABLE ' . $name . + ' ADD' . $this->getDefaultConstraintDeclarationSQL($name, $column); + } + + if (empty($column['comment']) && ! is_numeric($column['comment'])) { + continue; + } + + $commentsSql[] = $this->getCreateColumnCommentSQL($name, $column['name'], $column['comment']); + } + + $columnListSql = $this->getColumnDeclarationListSQL($columns); + + if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { + foreach ($options['uniqueConstraints'] as $name => $definition) { + $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); + } + } + + if (isset($options['primary']) && ! empty($options['primary'])) { + $flags = ''; + if (isset($options['primary_index']) && $options['primary_index']->hasFlag('nonclustered')) { + $flags = ' NONCLUSTERED'; + } + + $columnListSql .= ', PRIMARY KEY' . $flags + . ' (' . implode(', ', array_unique(array_values($options['primary']))) . ')'; + } + + $query = 'CREATE TABLE ' . $name . ' (' . $columnListSql; + + $check = $this->getCheckDeclarationSQL($columns); + if (! empty($check)) { + $query .= ', ' . $check; + } + + $query .= ')'; + + $sql = [$query]; + + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach ($options['indexes'] as $index) { + $sql[] = $this->getCreateIndexSQL($index, $name); + } + } + + if (isset($options['foreignKeys'])) { + foreach ((array) $options['foreignKeys'] as $definition) { + $sql[] = $this->getCreateForeignKeySQL($definition, $name); + } + } + + return array_merge($sql, $commentsSql, $defaultConstraintsSql); + } + + /** + * {@inheritDoc} + */ + public function getCreatePrimaryKeySQL(Index $index, $table) + { + if ($table instanceof Table) { + $identifier = $table->getQuotedName($this); + } else { + $identifier = $table; + } + + $sql = 'ALTER TABLE ' . $identifier . ' ADD PRIMARY KEY'; + + if ($index->hasFlag('nonclustered')) { + $sql .= ' NONCLUSTERED'; + } + + return $sql . ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')'; + } + + /** + * Returns the SQL statement for creating a column comment. + * + * SQL Server does not support native column comments, + * therefore the extended properties functionality is used + * as a workaround to store them. + * The property name used to store column comments is "MS_Description" + * which provides compatibility with SQL Server Management Studio, + * as column comments are stored in the same property there when + * specifying a column's "Description" attribute. + * + * @param string $tableName The quoted table name to which the column belongs. + * @param string $columnName The quoted column name to create the comment for. + * @param string|null $comment The column's comment. + * + * @return string + */ + protected function getCreateColumnCommentSQL($tableName, $columnName, $comment) + { + if (strpos($tableName, '.') !== false) { + [$schemaSQL, $tableSQL] = explode('.', $tableName); + $schemaSQL = $this->quoteStringLiteral($schemaSQL); + $tableSQL = $this->quoteStringLiteral($tableSQL); + } else { + $schemaSQL = "'dbo'"; + $tableSQL = $this->quoteStringLiteral($tableName); + } + + return $this->getAddExtendedPropertySQL( + 'MS_Description', + $comment, + 'SCHEMA', + $schemaSQL, + 'TABLE', + $tableSQL, + 'COLUMN', + $columnName + ); + } + + /** + * Returns the SQL snippet for declaring a default constraint. + * + * @param string $table Name of the table to return the default constraint declaration for. + * @param mixed[] $column Column definition. + * + * @return string + * + * @throws InvalidArgumentException + */ + public function getDefaultConstraintDeclarationSQL($table, array $column) + { + if (! isset($column['default'])) { + throw new InvalidArgumentException("Incomplete column definition. 'default' required."); + } + + $columnName = new Identifier($column['name']); + + return ' CONSTRAINT ' . + $this->generateDefaultConstraintName($table, $column['name']) . + $this->getDefaultValueDeclarationSQL($column) . + ' FOR ' . $columnName->getQuotedName($this); + } + + /** + * {@inheritDoc} + */ + public function getUniqueConstraintDeclarationSQL($name, Index $index) + { + $constraint = parent::getUniqueConstraintDeclarationSQL($name, $index); + + $constraint = $this->_appendUniqueConstraintDefinition($constraint, $index); + + return $constraint; + } + + /** + * {@inheritDoc} + */ + public function getCreateIndexSQL(Index $index, $table) + { + $constraint = parent::getCreateIndexSQL($index, $table); + + if ($index->isUnique() && ! $index->isPrimary()) { + $constraint = $this->_appendUniqueConstraintDefinition($constraint, $index); + } + + return $constraint; + } + + /** + * {@inheritDoc} + */ + protected function getCreateIndexSQLFlags(Index $index) + { + $type = ''; + if ($index->isUnique()) { + $type .= 'UNIQUE '; + } + + if ($index->hasFlag('clustered')) { + $type .= 'CLUSTERED '; + } elseif ($index->hasFlag('nonclustered')) { + $type .= 'NONCLUSTERED '; + } + + return $type; + } + + /** + * Extend unique key constraint with required filters + * + * @param string $sql + * + * @return string + */ + private function _appendUniqueConstraintDefinition($sql, Index $index) + { + $fields = []; + + foreach ($index->getQuotedColumns($this) as $field) { + $fields[] = $field . ' IS NOT NULL'; + } + + return $sql . ' WHERE ' . implode(' AND ', $fields); + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $queryParts = []; + $sql = []; + $columnSql = []; + $commentsSql = []; + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $columnDef = $column->toArray(); + $addColumnSql = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnDef); + if (isset($columnDef['default'])) { + $addColumnSql .= ' CONSTRAINT ' . + $this->generateDefaultConstraintName($diff->name, $column->getQuotedName($this)) . + $this->getDefaultValueDeclarationSQL($columnDef); + } + + $queryParts[] = $addColumnSql; + + $comment = $this->getColumnComment($column); + + if (empty($comment) && ! is_numeric($comment)) { + continue; + } + + $commentsSql[] = $this->getCreateColumnCommentSQL( + $diff->name, + $column->getQuotedName($this), + $comment + ); + } + + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $queryParts[] = 'DROP COLUMN ' . $column->getQuotedName($this); + } + + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + $column = $columnDiff->column; + $comment = $this->getColumnComment($column); + $hasComment = ! empty($comment) || is_numeric($comment); + + if ($columnDiff->fromColumn instanceof Column) { + $fromComment = $this->getColumnComment($columnDiff->fromColumn); + $hasFromComment = ! empty($fromComment) || is_numeric($fromComment); + + if ($hasFromComment && $hasComment && $fromComment !== $comment) { + $commentsSql[] = $this->getAlterColumnCommentSQL( + $diff->name, + $column->getQuotedName($this), + $comment + ); + } elseif ($hasFromComment && ! $hasComment) { + $commentsSql[] = $this->getDropColumnCommentSQL($diff->name, $column->getQuotedName($this)); + } elseif (! $hasFromComment && $hasComment) { + $commentsSql[] = $this->getCreateColumnCommentSQL( + $diff->name, + $column->getQuotedName($this), + $comment + ); + } + } + + // Do not add query part if only comment has changed. + if ($columnDiff->hasChanged('comment') && count($columnDiff->changedProperties) === 1) { + continue; + } + + $requireDropDefaultConstraint = $this->alterColumnRequiresDropDefaultConstraint($columnDiff); + + if ($requireDropDefaultConstraint) { + $queryParts[] = $this->getAlterTableDropDefaultConstraintClause( + $diff->name, + $columnDiff->oldColumnName + ); + } + + $columnDef = $column->toArray(); + + $queryParts[] = 'ALTER COLUMN ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnDef); + + if ( + ! isset($columnDef['default']) + || (! $requireDropDefaultConstraint && ! $columnDiff->hasChanged('default')) + ) { + continue; + } + + $queryParts[] = $this->getAlterTableAddDefaultConstraintClause($diff->name, $column); + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $oldColumnName = new Identifier($oldColumnName); + + $sql[] = "sp_rename '" . + $diff->getName($this)->getQuotedName($this) . '.' . $oldColumnName->getQuotedName($this) . + "', '" . $column->getQuotedName($this) . "', 'COLUMN'"; + + // Recreate default constraint with new column name if necessary (for future reference). + if ($column->getDefault() === null) { + continue; + } + + $queryParts[] = $this->getAlterTableDropDefaultConstraintClause( + $diff->name, + $oldColumnName->getQuotedName($this) + ); + $queryParts[] = $this->getAlterTableAddDefaultConstraintClause($diff->name, $column); + } + + $tableSql = []; + + if ($this->onSchemaAlterTable($diff, $tableSql)) { + return array_merge($tableSql, $columnSql); + } + + foreach ($queryParts as $query) { + $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; + } + + $sql = array_merge($sql, $commentsSql); + + $newName = $diff->getNewName(); + + if ($newName !== false) { + $sql[] = "sp_rename '" . $diff->getName($this)->getQuotedName($this) . "', '" . $newName->getName() . "'"; + + /** + * Rename table's default constraints names + * to match the new table name. + * This is necessary to ensure that the default + * constraints can be referenced in future table + * alterations as the table name is encoded in + * default constraints' names. + */ + $sql[] = "DECLARE @sql NVARCHAR(MAX) = N''; " . + "SELECT @sql += N'EXEC sp_rename N''' + dc.name + ''', N''' " . + "+ REPLACE(dc.name, '" . $this->generateIdentifierName($diff->name) . "', " . + "'" . $this->generateIdentifierName($newName->getName()) . "') + ''', ''OBJECT'';' " . + 'FROM sys.default_constraints dc ' . + 'JOIN sys.tables tbl ON dc.parent_object_id = tbl.object_id ' . + "WHERE tbl.name = '" . $newName->getName() . "';" . + 'EXEC sp_executesql @sql'; + } + + $sql = array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * Returns the SQL clause for adding a default constraint in an ALTER TABLE statement. + * + * @param string $tableName The name of the table to generate the clause for. + * @param Column $column The column to generate the clause for. + * + * @return string + */ + private function getAlterTableAddDefaultConstraintClause($tableName, Column $column) + { + $columnDef = $column->toArray(); + $columnDef['name'] = $column->getQuotedName($this); + + return 'ADD' . $this->getDefaultConstraintDeclarationSQL($tableName, $columnDef); + } + + /** + * Returns the SQL clause for dropping an existing default constraint in an ALTER TABLE statement. + * + * @param string $tableName The name of the table to generate the clause for. + * @param string $columnName The name of the column to generate the clause for. + * + * @return string + */ + private function getAlterTableDropDefaultConstraintClause($tableName, $columnName) + { + return 'DROP CONSTRAINT ' . $this->generateDefaultConstraintName($tableName, $columnName); + } + + /** + * Checks whether a column alteration requires dropping its default constraint first. + * + * Different to other database vendors SQL Server implements column default values + * as constraints and therefore changes in a column's default value as well as changes + * in a column's type require dropping the default constraint first before being to + * alter the particular column to the new definition. + * + * @param ColumnDiff $columnDiff The column diff to evaluate. + * + * @return bool True if the column alteration requires dropping its default constraint first, false otherwise. + */ + private function alterColumnRequiresDropDefaultConstraint(ColumnDiff $columnDiff) + { + // We can only decide whether to drop an existing default constraint + // if we know the original default value. + if (! $columnDiff->fromColumn instanceof Column) { + return false; + } + + // We only need to drop an existing default constraint if we know the + // column was defined with a default value before. + if ($columnDiff->fromColumn->getDefault() === null) { + return false; + } + + // We need to drop an existing default constraint if the column was + // defined with a default value before and it has changed. + if ($columnDiff->hasChanged('default')) { + return true; + } + + // We need to drop an existing default constraint if the column was + // defined with a default value before and the native column type has changed. + return $columnDiff->hasChanged('type') || $columnDiff->hasChanged('fixed'); + } + + /** + * Returns the SQL statement for altering a column comment. + * + * SQL Server does not support native column comments, + * therefore the extended properties functionality is used + * as a workaround to store them. + * The property name used to store column comments is "MS_Description" + * which provides compatibility with SQL Server Management Studio, + * as column comments are stored in the same property there when + * specifying a column's "Description" attribute. + * + * @param string $tableName The quoted table name to which the column belongs. + * @param string $columnName The quoted column name to alter the comment for. + * @param string|null $comment The column's comment. + * + * @return string + */ + protected function getAlterColumnCommentSQL($tableName, $columnName, $comment) + { + if (strpos($tableName, '.') !== false) { + [$schemaSQL, $tableSQL] = explode('.', $tableName); + $schemaSQL = $this->quoteStringLiteral($schemaSQL); + $tableSQL = $this->quoteStringLiteral($tableSQL); + } else { + $schemaSQL = "'dbo'"; + $tableSQL = $this->quoteStringLiteral($tableName); + } + + return $this->getUpdateExtendedPropertySQL( + 'MS_Description', + $comment, + 'SCHEMA', + $schemaSQL, + 'TABLE', + $tableSQL, + 'COLUMN', + $columnName + ); + } + + /** + * Returns the SQL statement for dropping a column comment. + * + * SQL Server does not support native column comments, + * therefore the extended properties functionality is used + * as a workaround to store them. + * The property name used to store column comments is "MS_Description" + * which provides compatibility with SQL Server Management Studio, + * as column comments are stored in the same property there when + * specifying a column's "Description" attribute. + * + * @param string $tableName The quoted table name to which the column belongs. + * @param string $columnName The quoted column name to drop the comment for. + * + * @return string + */ + protected function getDropColumnCommentSQL($tableName, $columnName) + { + if (strpos($tableName, '.') !== false) { + [$schemaSQL, $tableSQL] = explode('.', $tableName); + $schemaSQL = $this->quoteStringLiteral($schemaSQL); + $tableSQL = $this->quoteStringLiteral($tableSQL); + } else { + $schemaSQL = "'dbo'"; + $tableSQL = $this->quoteStringLiteral($tableName); + } + + return $this->getDropExtendedPropertySQL( + 'MS_Description', + 'SCHEMA', + $schemaSQL, + 'TABLE', + $tableSQL, + 'COLUMN', + $columnName + ); + } + + /** + * {@inheritdoc} + */ + protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + { + return [sprintf( + "EXEC sp_rename N'%s.%s', N'%s', N'INDEX'", + $tableName, + $oldIndexName, + $index->getQuotedName($this) + ), + ]; + } + + /** + * Returns the SQL statement for adding an extended property to a database object. + * + * @link http://msdn.microsoft.com/en-us/library/ms180047%28v=sql.90%29.aspx + * + * @param string $name The name of the property to add. + * @param string|null $value The value of the property to add. + * @param string|null $level0Type The type of the object at level 0 the property belongs to. + * @param string|null $level0Name The name of the object at level 0 the property belongs to. + * @param string|null $level1Type The type of the object at level 1 the property belongs to. + * @param string|null $level1Name The name of the object at level 1 the property belongs to. + * @param string|null $level2Type The type of the object at level 2 the property belongs to. + * @param string|null $level2Name The name of the object at level 2 the property belongs to. + * + * @return string + */ + public function getAddExtendedPropertySQL( + $name, + $value = null, + $level0Type = null, + $level0Name = null, + $level1Type = null, + $level1Name = null, + $level2Type = null, + $level2Name = null + ) { + return 'EXEC sp_addextendedproperty ' . + 'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral((string) $value) . ', ' . + 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . + 'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' . + 'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name; + } + + /** + * Returns the SQL statement for dropping an extended property from a database object. + * + * @link http://technet.microsoft.com/en-gb/library/ms178595%28v=sql.90%29.aspx + * + * @param string $name The name of the property to drop. + * @param string|null $level0Type The type of the object at level 0 the property belongs to. + * @param string|null $level0Name The name of the object at level 0 the property belongs to. + * @param string|null $level1Type The type of the object at level 1 the property belongs to. + * @param string|null $level1Name The name of the object at level 1 the property belongs to. + * @param string|null $level2Type The type of the object at level 2 the property belongs to. + * @param string|null $level2Name The name of the object at level 2 the property belongs to. + * + * @return string + */ + public function getDropExtendedPropertySQL( + $name, + $level0Type = null, + $level0Name = null, + $level1Type = null, + $level1Name = null, + $level2Type = null, + $level2Name = null + ) { + return 'EXEC sp_dropextendedproperty ' . + 'N' . $this->quoteStringLiteral($name) . ', ' . + 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . + 'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' . + 'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name; + } + + /** + * Returns the SQL statement for updating an extended property of a database object. + * + * @link http://msdn.microsoft.com/en-us/library/ms186885%28v=sql.90%29.aspx + * + * @param string $name The name of the property to update. + * @param string|null $value The value of the property to update. + * @param string|null $level0Type The type of the object at level 0 the property belongs to. + * @param string|null $level0Name The name of the object at level 0 the property belongs to. + * @param string|null $level1Type The type of the object at level 1 the property belongs to. + * @param string|null $level1Name The name of the object at level 1 the property belongs to. + * @param string|null $level2Type The type of the object at level 2 the property belongs to. + * @param string|null $level2Name The name of the object at level 2 the property belongs to. + * + * @return string + */ + public function getUpdateExtendedPropertySQL( + $name, + $value = null, + $level0Type = null, + $level0Name = null, + $level1Type = null, + $level1Name = null, + $level2Type = null, + $level2Name = null + ) { + return 'EXEC sp_updateextendedproperty ' . + 'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral((string) $value) . ', ' . + 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . + 'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' . + 'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name; + } + + /** + * {@inheritDoc} + */ + public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) + { + return 'INSERT INTO ' . $quotedTableName . ' DEFAULT VALUES'; + } + + /** + * {@inheritDoc} + */ + public function getListTablesSQL() + { + // "sysdiagrams" table must be ignored as it's internal SQL Server table for Database Diagrams + // Category 2 must be ignored as it is "MS SQL Server 'pseudo-system' object[s]" for replication + return "SELECT name FROM sysobjects WHERE type = 'U' AND name != 'sysdiagrams' AND category != 2 ORDER BY name"; + } + + /** + * {@inheritDoc} + */ + public function getListTableColumnsSQL($table, $database = null) + { + return "SELECT col.name, + type.name AS type, + col.max_length AS length, + ~col.is_nullable AS notnull, + def.definition AS [default], + col.scale, + col.precision, + col.is_identity AS autoincrement, + col.collation_name AS collation, + CAST(prop.value AS NVARCHAR(MAX)) AS comment -- CAST avoids driver error for sql_variant type + FROM sys.columns AS col + JOIN sys.types AS type + ON col.user_type_id = type.user_type_id + JOIN sys.objects AS obj + ON col.object_id = obj.object_id + JOIN sys.schemas AS scm + ON obj.schema_id = scm.schema_id + LEFT JOIN sys.default_constraints def + ON col.default_object_id = def.object_id + AND col.object_id = def.parent_object_id + LEFT JOIN sys.extended_properties AS prop + ON obj.object_id = prop.major_id + AND col.column_id = prop.minor_id + AND prop.name = 'MS_Description' + WHERE obj.type = 'U' + AND " . $this->getTableWhereClause($table, 'scm.name', 'obj.name'); + } + + /** + * @param string $table + * @param string|null $database + * + * @return string + */ + public function getListTableForeignKeysSQL($table, $database = null) + { + return 'SELECT f.name AS ForeignKey, + SCHEMA_NAME (f.SCHEMA_ID) AS SchemaName, + OBJECT_NAME (f.parent_object_id) AS TableName, + COL_NAME (fc.parent_object_id,fc.parent_column_id) AS ColumnName, + SCHEMA_NAME (o.SCHEMA_ID) ReferenceSchemaName, + OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName, + COL_NAME(fc.referenced_object_id,fc.referenced_column_id) AS ReferenceColumnName, + f.delete_referential_action_desc, + f.update_referential_action_desc + FROM sys.foreign_keys AS f + INNER JOIN sys.foreign_key_columns AS fc + INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id + ON f.OBJECT_ID = fc.constraint_object_id + WHERE ' . + $this->getTableWhereClause($table, 'SCHEMA_NAME (f.schema_id)', 'OBJECT_NAME (f.parent_object_id)'); + } + + /** + * {@inheritDoc} + */ + public function getListTableIndexesSQL($table, $database = null) + { + return "SELECT idx.name AS key_name, + col.name AS column_name, + ~idx.is_unique AS non_unique, + idx.is_primary_key AS [primary], + CASE idx.type + WHEN '1' THEN 'clustered' + WHEN '2' THEN 'nonclustered' + ELSE NULL + END AS flags + FROM sys.tables AS tbl + JOIN sys.schemas AS scm ON tbl.schema_id = scm.schema_id + JOIN sys.indexes AS idx ON tbl.object_id = idx.object_id + JOIN sys.index_columns AS idxcol ON idx.object_id = idxcol.object_id AND idx.index_id = idxcol.index_id + JOIN sys.columns AS col ON idxcol.object_id = col.object_id AND idxcol.column_id = col.column_id + WHERE " . $this->getTableWhereClause($table, 'scm.name', 'tbl.name') . ' + ORDER BY idx.index_id ASC, idxcol.key_ordinal ASC'; + } + + /** + * {@inheritDoc} + */ + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + /** + * {@inheritDoc} + */ + public function getListViewsSQL($database) + { + return "SELECT name FROM sysobjects WHERE type = 'V' ORDER BY name"; + } + + /** + * Returns the where clause to filter schema and table name in a query. + * + * @param string $table The full qualified name of the table. + * @param string $schemaColumn The name of the column to compare the schema to in the where clause. + * @param string $tableColumn The name of the column to compare the table to in the where clause. + * + * @return string + */ + private function getTableWhereClause($table, $schemaColumn, $tableColumn) + { + if (strpos($table, '.') !== false) { + [$schema, $table] = explode('.', $table); + $schema = $this->quoteStringLiteral($schema); + $table = $this->quoteStringLiteral($table); + } else { + $schema = 'SCHEMA_NAME()'; + $table = $this->quoteStringLiteral($table); + } + + return sprintf('(%s = %s AND %s = %s)', $tableColumn, $table, $schemaColumn, $schema); + } + + /** + * {@inheritDoc} + */ + public function getDropViewSQL($name) + { + return 'DROP VIEW ' . $name; + } + + /** + * {@inheritDoc} + * + * @deprecated Use application-generated UUIDs instead + */ + public function getGuidExpression() + { + return 'NEWID()'; + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos === false) { + return 'CHARINDEX(' . $substr . ', ' . $str . ')'; + } + + return 'CHARINDEX(' . $substr . ', ' . $str . ', ' . $startPos . ')'; + } + + /** + * {@inheritDoc} + */ + public function getModExpression($expression1, $expression2) + { + return $expression1 . ' % ' . $expression2; + } + + /** + * {@inheritDoc} + */ + public function getTrimExpression($str, $mode = TrimMode::UNSPECIFIED, $char = false) + { + if (! $char) { + switch ($mode) { + case TrimMode::LEADING: + $trimFn = 'LTRIM'; + break; + + case TrimMode::TRAILING: + $trimFn = 'RTRIM'; + break; + + default: + return 'LTRIM(RTRIM(' . $str . '))'; + } + + return $trimFn . '(' . $str . ')'; + } + + $pattern = "'%[^' + " . $char . " + ']%'"; + + if ($mode === TrimMode::LEADING) { + return 'stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null)'; + } + + if ($mode === TrimMode::TRAILING) { + return 'reverse(stuff(reverse(' . $str . '), 1, ' + . 'patindex(' . $pattern . ', reverse(' . $str . ')) - 1, null))'; + } + + return 'reverse(stuff(reverse(stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null)), 1, ' + . 'patindex(' . $pattern . ', reverse(stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str + . ') - 1, null))) - 1, null))'; + } + + /** + * {@inheritDoc} + */ + public function getConcatExpression() + { + $args = func_get_args(); + + return '(' . implode(' + ', $args) . ')'; + } + + /** + * {@inheritDoc} + */ + public function getListDatabasesSQL() + { + return 'SELECT * FROM sys.databases'; + } + + /** + * {@inheritDoc} + */ + public function getListNamespacesSQL() + { + return "SELECT name FROM sys.schemas WHERE name NOT IN('guest', 'INFORMATION_SCHEMA', 'sys')"; + } + + /** + * {@inheritDoc} + */ + public function getSubstringExpression($string, $start, $length = null) + { + if ($length !== null) { + return 'SUBSTRING(' . $string . ', ' . $start . ', ' . $length . ')'; + } + + return 'SUBSTRING(' . $string . ', ' . $start . ', LEN(' . $string . ') - ' . $start . ' + 1)'; + } + + /** + * {@inheritDoc} + */ + public function getLengthExpression($column) + { + return 'LEN(' . $column . ')'; + } + + /** + * {@inheritDoc} + */ + public function getSetTransactionIsolationSQL($level) + { + return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $column) + { + return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $column) + { + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $column) + { + return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getGuidTypeDeclarationSQL(array $column) + { + return 'UNIQUEIDENTIFIER'; + } + + /** + * {@inheritDoc} + */ + public function getAsciiStringTypeDeclarationSQL(array $column): string + { + $length = $column['length'] ?? null; + + if (! isset($column['fixed'])) { + return sprintf('VARCHAR(%d)', $length ?? 255); + } + + return sprintf('CHAR(%d)', $length ?? 255); + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed + ? ($length ? 'NCHAR(' . $length . ')' : 'CHAR(255)') + : ($length ? 'NVARCHAR(' . $length . ')' : 'NVARCHAR(255)'); + } + + /** + * {@inheritdoc} + */ + protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? 'BINARY(' . ($length ?: 255) . ')' : 'VARBINARY(' . ($length ?: 255) . ')'; + } + + /** + * {@inheritdoc} + */ + public function getBinaryMaxLength() + { + return 8000; + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $column) + { + return 'VARCHAR(MAX)'; + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $column) + { + return ! empty($column['autoincrement']) ? ' IDENTITY' : ''; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $column) + { + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $column) + { + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $column) + { + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $column) + { + return 'BIT'; + } + + /** + * {@inheritDoc} + */ + protected function doModifyLimitQuery($query, $limit, $offset = null) + { + $where = []; + + if ($offset > 0) { + $where[] = sprintf('doctrine_rownum >= %d', $offset + 1); + } + + if ($limit !== null) { + $where[] = sprintf('doctrine_rownum <= %d', $offset + $limit); + $top = sprintf('TOP %d', $offset + $limit); + } else { + $top = 'TOP 9223372036854775807'; + } + + if (empty($where)) { + return $query; + } + + // We'll find a SELECT or SELECT distinct and prepend TOP n to it + // Even if the TOP n is very large, the use of a CTE will + // allow the SQL Server query planner to optimize it so it doesn't + // actually scan the entire range covered by the TOP clause. + if (! preg_match('/^(\s*SELECT\s+(?:DISTINCT\s+)?)(.*)$/is', $query, $matches)) { + return $query; + } + + $query = $matches[1] . $top . ' ' . $matches[2]; + + if (stristr($query, 'ORDER BY')) { + // Inner order by is not valid in SQL Server for our purposes + // unless it's in a TOP N subquery. + $query = $this->scrubInnerOrderBy($query); + } + + // Build a new limited query around the original, using a CTE + return sprintf( + 'WITH dctrn_cte AS (%s) ' + . 'SELECT * FROM (' + . 'SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte' + . ') AS doctrine_tbl ' + . 'WHERE %s ORDER BY doctrine_rownum ASC', + $query, + implode(' AND ', $where) + ); + } + + /** + * Remove ORDER BY clauses in subqueries - they're not supported by SQL Server. + * Caveat: will leave ORDER BY in TOP N subqueries. + * + * @param string $query + * + * @return string + */ + private function scrubInnerOrderBy($query) + { + $count = substr_count(strtoupper($query), 'ORDER BY'); + $offset = 0; + + while ($count-- > 0) { + $orderByPos = stripos($query, ' ORDER BY', $offset); + if ($orderByPos === false) { + break; + } + + $qLen = strlen($query); + $parenCount = 0; + $currentPosition = $orderByPos; + + while ($parenCount >= 0 && $currentPosition < $qLen) { + if ($query[$currentPosition] === '(') { + $parenCount++; + } elseif ($query[$currentPosition] === ')') { + $parenCount--; + } + + $currentPosition++; + } + + if ($this->isOrderByInTopNSubquery($query, $orderByPos)) { + // If the order by clause is in a TOP N subquery, do not remove + // it and continue iteration from the current position. + $offset = $currentPosition; + continue; + } + + if ($currentPosition >= $qLen - 1) { + continue; + } + + $query = substr($query, 0, $orderByPos) . substr($query, $currentPosition - 1); + $offset = $orderByPos; + } + + return $query; + } + + /** + * Check an ORDER BY clause to see if it is in a TOP N query or subquery. + * + * @param string $query The query + * @param int $currentPosition Start position of ORDER BY clause + * + * @return bool true if ORDER BY is in a TOP N query, false otherwise + */ + private function isOrderByInTopNSubquery($query, $currentPosition) + { + // Grab query text on the same nesting level as the ORDER BY clause we're examining. + $subQueryBuffer = ''; + $parenCount = 0; + + // If $parenCount goes negative, we've exited the subquery we're examining. + // If $currentPosition goes negative, we've reached the beginning of the query. + while ($parenCount >= 0 && $currentPosition >= 0) { + if ($query[$currentPosition] === '(') { + $parenCount--; + } elseif ($query[$currentPosition] === ')') { + $parenCount++; + } + + // Only yank query text on the same nesting level as the ORDER BY clause. + $subQueryBuffer = ($parenCount === 0 ? $query[$currentPosition] : ' ') . $subQueryBuffer; + + $currentPosition--; + } + + return (bool) preg_match('/SELECT\s+(DISTINCT\s+)?TOP\s/i', $subQueryBuffer); + } + + /** + * {@inheritDoc} + */ + public function supportsLimitOffset() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function convertBooleans($item) + { + if (is_array($item)) { + foreach ($item as $key => $value) { + if (! is_bool($value) && ! is_numeric($value)) { + continue; + } + + $item[$key] = $value ? 1 : 0; + } + } elseif (is_bool($item) || is_numeric($item)) { + $item = $item ? 1 : 0; + } + + return $item; + } + + /** + * {@inheritDoc} + */ + public function getCreateTemporaryTableSnippetSQL() + { + return 'CREATE TABLE'; + } + + /** + * {@inheritDoc} + */ + public function getTemporaryTableName($tableName) + { + return '#' . $tableName; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeFormatString() + { + return 'Y-m-d H:i:s.000'; + } + + /** + * {@inheritDoc} + */ + public function getDateFormatString() + { + return 'Y-m-d H:i:s.000'; + } + + /** + * {@inheritDoc} + */ + public function getTimeFormatString() + { + return 'Y-m-d H:i:s.000'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzFormatString() + { + return $this->getDateTimeFormatString(); + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'mssql'; + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = [ + 'bigint' => 'bigint', + 'numeric' => 'decimal', + 'bit' => 'boolean', + 'smallint' => 'smallint', + 'decimal' => 'decimal', + 'smallmoney' => 'integer', + 'int' => 'integer', + 'tinyint' => 'smallint', + 'money' => 'integer', + 'float' => 'float', + 'real' => 'float', + 'double' => 'float', + 'double precision' => 'float', + 'smalldatetime' => 'datetime', + 'datetime' => 'datetime', + 'char' => 'string', + 'varchar' => 'string', + 'text' => 'text', + 'nchar' => 'string', + 'nvarchar' => 'string', + 'ntext' => 'text', + 'binary' => 'binary', + 'varbinary' => 'binary', + 'image' => 'blob', + 'uniqueidentifier' => 'guid', + ]; + } + + /** + * {@inheritDoc} + */ + public function createSavePoint($savepoint) + { + return 'SAVE TRANSACTION ' . $savepoint; + } + + /** + * {@inheritDoc} + */ + public function releaseSavePoint($savepoint) + { + return ''; + } + + /** + * {@inheritDoc} + */ + public function rollbackSavePoint($savepoint) + { + return 'ROLLBACK TRANSACTION ' . $savepoint; + } + + /** + * {@inheritdoc} + */ + public function getForeignKeyReferentialActionSQL($action) + { + // RESTRICT is not supported, therefore falling back to NO ACTION. + if (strtoupper($action) === 'RESTRICT') { + return 'NO ACTION'; + } + + return parent::getForeignKeyReferentialActionSQL($action); + } + + /** + * {@inheritDoc} + */ + public function appendLockHint($fromClause, $lockMode) + { + switch (true) { + case $lockMode === LockMode::NONE: + return $fromClause; + + case $lockMode === LockMode::PESSIMISTIC_READ: + return $fromClause . ' WITH (HOLDLOCK, ROWLOCK)'; + + case $lockMode === LockMode::PESSIMISTIC_WRITE: + return $fromClause . ' WITH (UPDLOCK, ROWLOCK)'; + + default: + return $fromClause; + } + } + + /** + * {@inheritDoc} + */ + public function getForUpdateSQL() + { + return ' '; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return Keywords\SQLServerKeywords::class; + } + + /** + * {@inheritDoc} + */ + public function quoteSingleIdentifier($str) + { + return '[' . str_replace(']', ']]', $str) . ']'; + } + + /** + * {@inheritDoc} + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + $tableIdentifier = new Identifier($tableName); + + return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this); + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $column) + { + return 'VARBINARY(MAX)'; + } + + /** + * {@inheritdoc} + * + * Modifies column declaration order as it differs in Microsoft SQL Server. + */ + public function getColumnDeclarationSQL($name, array $column) + { + if (isset($column['columnDefinition'])) { + $columnDef = $this->getCustomTypeDeclarationSQL($column); + } else { + $collation = isset($column['collation']) && $column['collation'] ? + ' ' . $this->getColumnCollationDeclarationSQL($column['collation']) : ''; + + $notnull = isset($column['notnull']) && $column['notnull'] ? ' NOT NULL' : ''; + + $unique = isset($column['unique']) && $column['unique'] ? + ' ' . $this->getUniqueFieldDeclarationSQL() : ''; + + $check = isset($column['check']) && $column['check'] ? + ' ' . $column['check'] : ''; + + $typeDecl = $column['type']->getSQLDeclaration($column, $this); + $columnDef = $typeDecl . $collation . $notnull . $unique . $check; + } + + return $name . ' ' . $columnDef; + } + + /** + * Returns a unique default constraint name for a table and column. + * + * @param string $table Name of the table to generate the unique default constraint name for. + * @param string $column Name of the column in the table to generate the unique default constraint name for. + * + * @return string + */ + private function generateDefaultConstraintName($table, $column) + { + return 'DF_' . $this->generateIdentifierName($table) . '_' . $this->generateIdentifierName($column); + } + + /** + * Returns a hash value for a given identifier. + * + * @param string $identifier Identifier to generate a hash value for. + * + * @return string + */ + private function generateIdentifierName($identifier) + { + // Always generate name for unquoted identifiers to ensure consistency. + $identifier = new Identifier($identifier); + + return strtoupper(dechex(crc32($identifier->getName()))); + } + + protected function getCommentOnTableSQL(string $tableName, ?string $comment): string + { + return sprintf( + " + EXEC sys.sp_addextendedproperty @name=N'MS_Description', + @value=N%s, @level0type=N'SCHEMA', @level0name=N'dbo', + @level1type=N'TABLE', @level1name=N%s + ", + $this->quoteStringLiteral((string) $comment), + $this->quoteStringLiteral($tableName) + ); + } + + public function getListTableMetadataSQL(string $table): string + { + return sprintf( + " + SELECT + p.value AS [table_comment] + FROM + sys.tables AS tbl + INNER JOIN sys.extended_properties AS p ON p.major_id=tbl.object_id AND p.minor_id=0 AND p.class=1 + WHERE + (tbl.name=N%s and SCHEMA_NAME(tbl.schema_id)=N'dbo' and p.name=N'MS_Description') + ", + $this->quoteStringLiteral($table) + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php new file mode 100755 index 0000000..e42a6bd --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -0,0 +1,1283 @@ +_getTransactionIsolationLevelSQL($level); + } + + /** + * {@inheritDoc} + */ + public function prefersIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $column) + { + return 'BOOLEAN'; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $column) + { + return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $column) + { + // SQLite autoincrement is implicit for INTEGER PKs, but not for BIGINT columns + if (! empty($column['autoincrement'])) { + return $this->getIntegerTypeDeclarationSQL($column); + } + + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * @param array $column + * + * @return string + */ + public function getTinyIntTypeDeclarationSql(array $column) + { + // SQLite autoincrement is implicit for INTEGER PKs, but not for TINYINT columns + if (! empty($column['autoincrement'])) { + return $this->getIntegerTypeDeclarationSQL($column); + } + + return 'TINYINT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $column) + { + // SQLite autoincrement is implicit for INTEGER PKs, but not for SMALLINT columns + if (! empty($column['autoincrement'])) { + return $this->getIntegerTypeDeclarationSQL($column); + } + + return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * @param array $column + * + * @return string + */ + public function getMediumIntTypeDeclarationSql(array $column) + { + // SQLite autoincrement is implicit for INTEGER PKs, but not for MEDIUMINT columns + if (! empty($column['autoincrement'])) { + return $this->getIntegerTypeDeclarationSQL($column); + } + + return 'MEDIUMINT' . $this->_getCommonIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $column) + { + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $column) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $column) + { + return 'TIME'; + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $column) + { + // sqlite autoincrement is only possible for the primary key + if (! empty($column['autoincrement'])) { + return ' PRIMARY KEY AUTOINCREMENT'; + } + + return ! empty($column['unsigned']) ? ' UNSIGNED' : ''; + } + + /** + * {@inheritDoc} + */ + public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) + { + return parent::getForeignKeyDeclarationSQL(new ForeignKeyConstraint( + $foreignKey->getQuotedLocalColumns($this), + str_replace('.', '__', $foreignKey->getQuotedForeignTableName($this)), + $foreignKey->getQuotedForeignColumns($this), + $foreignKey->getName(), + $foreignKey->getOptions() + )); + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($name, array $columns, array $options = []) + { + $name = str_replace('.', '__', $name); + $queryFields = $this->getColumnDeclarationListSQL($columns); + + if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { + foreach ($options['uniqueConstraints'] as $name => $definition) { + $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); + } + } + + $queryFields .= $this->getNonAutoincrementPrimaryKeyDefinition($columns, $options); + + if (isset($options['foreignKeys'])) { + foreach ($options['foreignKeys'] as $foreignKey) { + $queryFields .= ', ' . $this->getForeignKeyDeclarationSQL($foreignKey); + } + } + + $tableComment = ''; + if (isset($options['comment'])) { + $comment = trim($options['comment'], " '"); + + $tableComment = $this->getInlineTableCommentSQL($comment); + } + + $query = ['CREATE TABLE ' . $name . ' ' . $tableComment . '(' . $queryFields . ')']; + + if (isset($options['alter']) && $options['alter'] === true) { + return $query; + } + + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach ($options['indexes'] as $indexDef) { + $query[] = $this->getCreateIndexSQL($indexDef, $name); + } + } + + if (isset($options['unique']) && ! empty($options['unique'])) { + foreach ($options['unique'] as $indexDef) { + $query[] = $this->getCreateIndexSQL($indexDef, $name); + } + } + + return $query; + } + + /** + * Generate a PRIMARY KEY definition if no autoincrement value is used + * + * @param mixed[][] $columns + * @param mixed[] $options + */ + private function getNonAutoincrementPrimaryKeyDefinition(array $columns, array $options): string + { + if (empty($options['primary'])) { + return ''; + } + + $keyColumns = array_unique(array_values($options['primary'])); + + foreach ($keyColumns as $keyColumn) { + if (! empty($columns[$keyColumn]['autoincrement'])) { + return ''; + } + } + + return ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') + : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT'); + } + + /** + * {@inheritdoc} + */ + protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + { + return 'BLOB'; + } + + /** + * {@inheritdoc} + */ + public function getBinaryMaxLength() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function getBinaryDefaultLength() + { + return 0; + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $column) + { + return 'CLOB'; + } + + /** + * {@inheritDoc} + */ + public function getListTableConstraintsSQL($table) + { + $table = str_replace('.', '__', $table); + + return sprintf( + "SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name = %s AND sql NOT NULL ORDER BY name", + $this->quoteStringLiteral($table) + ); + } + + /** + * {@inheritDoc} + */ + public function getListTableColumnsSQL($table, $database = null) + { + $table = str_replace('.', '__', $table); + + return sprintf('PRAGMA table_info(%s)', $this->quoteStringLiteral($table)); + } + + /** + * {@inheritDoc} + */ + public function getListTableIndexesSQL($table, $database = null) + { + $table = str_replace('.', '__', $table); + + return sprintf('PRAGMA index_list(%s)', $this->quoteStringLiteral($table)); + } + + /** + * {@inheritDoc} + */ + public function getListTablesSQL() + { + return 'SELECT name FROM sqlite_master' + . " WHERE type = 'table'" + . " AND name != 'sqlite_sequence'" + . " AND name != 'geometry_columns'" + . " AND name != 'spatial_ref_sys'" + . ' UNION ALL SELECT name FROM sqlite_temp_master' + . " WHERE type = 'table' ORDER BY name"; + } + + /** + * {@inheritDoc} + */ + public function getListViewsSQL($database) + { + return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL"; + } + + /** + * {@inheritDoc} + */ + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + /** + * {@inheritDoc} + */ + public function getDropViewSQL($name) + { + return 'DROP VIEW ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + { + $query = parent::getAdvancedForeignKeyOptionsSQL($foreignKey); + + if (! $foreignKey->hasOption('deferrable') || $foreignKey->getOption('deferrable') === false) { + $query .= ' NOT'; + } + + $query .= ' DEFERRABLE'; + $query .= ' INITIALLY'; + + if ($foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false) { + $query .= ' DEFERRED'; + } else { + $query .= ' IMMEDIATE'; + } + + return $query; + } + + /** + * {@inheritDoc} + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsColumnCollation() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsInlineColumnComments() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'sqlite'; + } + + /** + * {@inheritDoc} + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + $tableIdentifier = new Identifier($tableName); + $tableName = str_replace('.', '__', $tableIdentifier->getQuotedName($this)); + + return 'DELETE FROM ' . $tableName; + } + + /** + * User-defined function for Sqlite that is used with PDO::sqliteCreateFunction(). + * + * @param int|float $value + * + * @return float + */ + public static function udfSqrt($value) + { + return sqrt($value); + } + + /** + * User-defined function for Sqlite that implements MOD(a, b). + * + * @param int $a + * @param int $b + * + * @return int + */ + public static function udfMod($a, $b) + { + return $a % $b; + } + + /** + * @param string $str + * @param string $substr + * @param int $offset + * + * @return int + */ + public static function udfLocate($str, $substr, $offset = 0) + { + // SQL's LOCATE function works on 1-based positions, while PHP's strpos works on 0-based positions. + // So we have to make them compatible if an offset is given. + if ($offset > 0) { + $offset -= 1; + } + + $pos = strpos($str, $substr, $offset); + + if ($pos !== false) { + return $pos + 1; + } + + return 0; + } + + /** + * {@inheritDoc} + */ + public function getForUpdateSQL() + { + return ''; + } + + /** + * {@inheritDoc} + */ + public function getInlineColumnCommentSQL($comment) + { + return '--' . str_replace("\n", "\n--", $comment) . "\n"; + } + + private function getInlineTableCommentSQL(string $comment): string + { + return $this->getInlineColumnCommentSQL($comment); + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = [ + 'boolean' => 'boolean', + 'tinyint' => 'boolean', + 'smallint' => 'smallint', + 'mediumint' => 'integer', + 'int' => 'integer', + 'integer' => 'integer', + 'serial' => 'integer', + 'bigint' => 'bigint', + 'bigserial' => 'bigint', + 'clob' => 'text', + 'tinytext' => 'text', + 'mediumtext' => 'text', + 'longtext' => 'text', + 'text' => 'text', + 'varchar' => 'string', + 'longvarchar' => 'string', + 'varchar2' => 'string', + 'nvarchar' => 'string', + 'image' => 'string', + 'ntext' => 'string', + 'char' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'timestamp' => 'datetime', + 'time' => 'time', + 'float' => 'float', + 'double' => 'float', + 'double precision' => 'float', + 'real' => 'float', + 'decimal' => 'decimal', + 'numeric' => 'decimal', + 'blob' => 'blob', + ]; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return Keywords\SQLiteKeywords::class; + } + + /** + * {@inheritDoc} + */ + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + { + if (! $diff->fromTable instanceof Table) { + throw new Exception( + 'Sqlite platform requires for alter table the table diff with reference to original table schema' + ); + } + + $sql = []; + foreach ($diff->fromTable->getIndexes() as $index) { + if ($index->isPrimary()) { + continue; + } + + $sql[] = $this->getDropIndexSQL($index, $diff->name); + } + + return $sql; + } + + /** + * {@inheritDoc} + */ + protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) + { + $fromTable = $diff->fromTable; + + if (! $fromTable instanceof Table) { + throw new Exception( + 'Sqlite platform requires for alter table the table diff with reference to original table schema' + ); + } + + $sql = []; + $tableName = $diff->getNewName(); + + if ($tableName === false) { + $tableName = $diff->getName($this); + } + + foreach ($this->getIndexesInAlteredTable($diff, $fromTable) as $index) { + if ($index->isPrimary()) { + continue; + } + + $sql[] = $this->getCreateIndexSQL($index, $tableName->getQuotedName($this)); + } + + return $sql; + } + + /** + * {@inheritDoc} + */ + protected function doModifyLimitQuery($query, $limit, $offset) + { + if ($limit === null && $offset > 0) { + return $query . ' LIMIT -1 OFFSET ' . $offset; + } + + return parent::doModifyLimitQuery($query, $limit, $offset); + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $column) + { + return 'BLOB'; + } + + /** + * {@inheritDoc} + */ + public function getTemporaryTableName($tableName) + { + $tableName = str_replace('.', '__', $tableName); + + return $tableName; + } + + /** + * {@inheritDoc} + * + * Sqlite Platform emulates schema by underscoring each dot and generating tables + * into the default database. + * + * This hack is implemented to be able to use SQLite as testdriver when + * using schema supporting databases. + */ + public function canEmulateSchemas() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsForeignKeyConstraints() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function getCreatePrimaryKeySQL(Index $index, $table) + { + throw new Exception('Sqlite platform does not support alter primary key.'); + } + + /** + * {@inheritdoc} + */ + public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) + { + throw new Exception('Sqlite platform does not support alter foreign key.'); + } + + /** + * {@inheritdoc} + */ + public function getDropForeignKeySQL($foreignKey, $table) + { + throw new Exception('Sqlite platform does not support alter foreign key.'); + } + + /** + * {@inheritDoc} + */ + public function getCreateConstraintSQL(Constraint $constraint, $table) + { + throw new Exception('Sqlite platform does not support alter constraint.'); + } + + /** + * {@inheritDoc} + * + * @param int|null $createFlags + */ + public function getCreateTableSQL(Table $table, $createFlags = null) + { + $createFlags = $createFlags ?? self::CREATE_INDEXES | self::CREATE_FOREIGNKEYS; + + return parent::getCreateTableSQL($table, $createFlags); + } + + /** + * @param string $table + * @param string|null $database + * + * @return string + */ + public function getListTableForeignKeysSQL($table, $database = null) + { + $table = str_replace('.', '__', $table); + + return sprintf('PRAGMA foreign_key_list(%s)', $this->quoteStringLiteral($table)); + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $sql = $this->getSimpleAlterTableSQL($diff); + if ($sql !== false) { + return $sql; + } + + $fromTable = $diff->fromTable; + if (! $fromTable instanceof Table) { + throw new Exception( + 'Sqlite platform requires for alter table the table diff with reference to original table schema' + ); + } + + $table = clone $fromTable; + + $columns = []; + $oldColumnNames = []; + $newColumnNames = []; + $columnSql = []; + + foreach ($table->getColumns() as $columnName => $column) { + $columnName = strtolower($columnName); + $columns[$columnName] = $column; + $oldColumnNames[$columnName] = $newColumnNames[$columnName] = $column->getQuotedName($this); + } + + foreach ($diff->removedColumns as $columnName => $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $columnName = strtolower($columnName); + if (! isset($columns[$columnName])) { + continue; + } + + unset( + $columns[$columnName], + $oldColumnNames[$columnName], + $newColumnNames[$columnName] + ); + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $oldColumnName = strtolower($oldColumnName); + if (isset($columns[$oldColumnName])) { + unset($columns[$oldColumnName]); + } + + $columns[strtolower($column->getName())] = $column; + + if (! isset($newColumnNames[$oldColumnName])) { + continue; + } + + $newColumnNames[$oldColumnName] = $column->getQuotedName($this); + } + + foreach ($diff->changedColumns as $oldColumnName => $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + if (isset($columns[$oldColumnName])) { + unset($columns[$oldColumnName]); + } + + $columns[strtolower($columnDiff->column->getName())] = $columnDiff->column; + + if (! isset($newColumnNames[$oldColumnName])) { + continue; + } + + $newColumnNames[$oldColumnName] = $columnDiff->column->getQuotedName($this); + } + + foreach ($diff->addedColumns as $columnName => $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $columns[strtolower($columnName)] = $column; + } + + $sql = []; + $tableSql = []; + if (! $this->onSchemaAlterTable($diff, $tableSql)) { + $dataTable = new Table('__temp__' . $table->getName()); + + $newTable = new Table( + $table->getQuotedName($this), + $columns, + $this->getPrimaryIndexInAlteredTable($diff, $fromTable), + $this->getForeignKeysInAlteredTable($diff, $fromTable), + 0, + $table->getOptions() + ); + $newTable->addOption('alter', true); + + $sql = $this->getPreAlterTableIndexForeignKeySQL($diff); + + $sql[] = sprintf( + 'CREATE TEMPORARY TABLE %s AS SELECT %s FROM %s', + $dataTable->getQuotedName($this), + implode(', ', $oldColumnNames), + $table->getQuotedName($this) + ); + $sql[] = $this->getDropTableSQL($fromTable); + + $sql = array_merge($sql, $this->getCreateTableSQL($newTable)); + $sql[] = sprintf( + 'INSERT INTO %s (%s) SELECT %s FROM %s', + $newTable->getQuotedName($this), + implode(', ', $newColumnNames), + implode(', ', $oldColumnNames), + $dataTable->getQuotedName($this) + ); + $sql[] = $this->getDropTableSQL($dataTable); + + $newName = $diff->getNewName(); + + if ($newName !== false) { + $sql[] = sprintf( + 'ALTER TABLE %s RENAME TO %s', + $newTable->getQuotedName($this), + $newName->getQuotedName($this) + ); + } + + $sql = array_merge($sql, $this->getPostAlterTableIndexForeignKeySQL($diff)); + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * @return string[]|false + */ + private function getSimpleAlterTableSQL(TableDiff $diff) + { + // Suppress changes on integer type autoincrement columns. + foreach ($diff->changedColumns as $oldColumnName => $columnDiff) { + if ( + ! $columnDiff->fromColumn instanceof Column || + ! $columnDiff->column instanceof Column || + ! $columnDiff->column->getAutoincrement() || + ! $columnDiff->column->getType() instanceof Types\IntegerType + ) { + continue; + } + + if (! $columnDiff->hasChanged('type') && $columnDiff->hasChanged('unsigned')) { + unset($diff->changedColumns[$oldColumnName]); + + continue; + } + + $fromColumnType = $columnDiff->fromColumn->getType(); + + if (! ($fromColumnType instanceof Types\SmallIntType) && ! ($fromColumnType instanceof Types\BigIntType)) { + continue; + } + + unset($diff->changedColumns[$oldColumnName]); + } + + if ( + ! empty($diff->renamedColumns) + || ! empty($diff->addedForeignKeys) + || ! empty($diff->addedIndexes) + || ! empty($diff->changedColumns) + || ! empty($diff->changedForeignKeys) + || ! empty($diff->changedIndexes) + || ! empty($diff->removedColumns) + || ! empty($diff->removedForeignKeys) + || ! empty($diff->removedIndexes) + || ! empty($diff->renamedIndexes) + ) { + return false; + } + + $table = new Table($diff->name); + + $sql = []; + $tableSql = []; + $columnSql = []; + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $definition = array_merge([ + 'unique' => null, + 'autoincrement' => null, + 'default' => null, + ], $column->toArray()); + + $type = $definition['type']; + + switch (true) { + case isset($definition['columnDefinition']) || $definition['autoincrement'] || $definition['unique']: + case $type instanceof Types\DateTimeType && $definition['default'] === $this->getCurrentTimestampSQL(): + case $type instanceof Types\DateType && $definition['default'] === $this->getCurrentDateSQL(): + case $type instanceof Types\TimeType && $definition['default'] === $this->getCurrentTimeSQL(): + return false; + } + + $definition['name'] = $column->getQuotedName($this); + if ($type instanceof Types\StringType && $definition['length'] === null) { + $definition['length'] = 255; + } + + $sql[] = 'ALTER TABLE ' . $table->getQuotedName($this) . ' ADD COLUMN ' + . $this->getColumnDeclarationSQL($definition['name'], $definition); + } + + if (! $this->onSchemaAlterTable($diff, $tableSql)) { + if ($diff->newName !== false) { + $newTable = new Identifier($diff->newName); + + $sql[] = 'ALTER TABLE ' . $table->getQuotedName($this) . ' RENAME TO ' + . $newTable->getQuotedName($this); + } + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * @return string[] + */ + private function getColumnNamesInAlteredTable(TableDiff $diff, Table $fromTable) + { + $columns = []; + + foreach ($fromTable->getColumns() as $columnName => $column) { + $columns[strtolower($columnName)] = $column->getName(); + } + + foreach ($diff->removedColumns as $columnName => $column) { + $columnName = strtolower($columnName); + if (! isset($columns[$columnName])) { + continue; + } + + unset($columns[$columnName]); + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + $columnName = $column->getName(); + $columns[strtolower($oldColumnName)] = $columnName; + $columns[strtolower($columnName)] = $columnName; + } + + foreach ($diff->changedColumns as $oldColumnName => $columnDiff) { + $columnName = $columnDiff->column->getName(); + $columns[strtolower($oldColumnName)] = $columnName; + $columns[strtolower($columnName)] = $columnName; + } + + foreach ($diff->addedColumns as $column) { + $columnName = $column->getName(); + $columns[strtolower($columnName)] = $columnName; + } + + return $columns; + } + + /** + * @return Index[] + */ + private function getIndexesInAlteredTable(TableDiff $diff, Table $fromTable) + { + $indexes = $fromTable->getIndexes(); + $columnNames = $this->getColumnNamesInAlteredTable($diff, $fromTable); + + foreach ($indexes as $key => $index) { + foreach ($diff->renamedIndexes as $oldIndexName => $renamedIndex) { + if (strtolower($key) !== strtolower($oldIndexName)) { + continue; + } + + unset($indexes[$key]); + } + + $changed = false; + $indexColumns = []; + foreach ($index->getColumns() as $columnName) { + $normalizedColumnName = strtolower($columnName); + if (! isset($columnNames[$normalizedColumnName])) { + unset($indexes[$key]); + continue 2; + } + + $indexColumns[] = $columnNames[$normalizedColumnName]; + if ($columnName === $columnNames[$normalizedColumnName]) { + continue; + } + + $changed = true; + } + + if (! $changed) { + continue; + } + + $indexes[$key] = new Index( + $index->getName(), + $indexColumns, + $index->isUnique(), + $index->isPrimary(), + $index->getFlags() + ); + } + + foreach ($diff->removedIndexes as $index) { + $indexName = strtolower($index->getName()); + if (! strlen($indexName) || ! isset($indexes[$indexName])) { + continue; + } + + unset($indexes[$indexName]); + } + + foreach (array_merge($diff->changedIndexes, $diff->addedIndexes, $diff->renamedIndexes) as $index) { + $indexName = strtolower($index->getName()); + if (strlen($indexName)) { + $indexes[$indexName] = $index; + } else { + $indexes[] = $index; + } + } + + return $indexes; + } + + /** + * @return ForeignKeyConstraint[] + */ + private function getForeignKeysInAlteredTable(TableDiff $diff, Table $fromTable) + { + $foreignKeys = $fromTable->getForeignKeys(); + $columnNames = $this->getColumnNamesInAlteredTable($diff, $fromTable); + + foreach ($foreignKeys as $key => $constraint) { + $changed = false; + $localColumns = []; + foreach ($constraint->getLocalColumns() as $columnName) { + $normalizedColumnName = strtolower($columnName); + if (! isset($columnNames[$normalizedColumnName])) { + unset($foreignKeys[$key]); + continue 2; + } + + $localColumns[] = $columnNames[$normalizedColumnName]; + if ($columnName === $columnNames[$normalizedColumnName]) { + continue; + } + + $changed = true; + } + + if (! $changed) { + continue; + } + + $foreignKeys[$key] = new ForeignKeyConstraint( + $localColumns, + $constraint->getForeignTableName(), + $constraint->getForeignColumns(), + $constraint->getName(), + $constraint->getOptions() + ); + } + + foreach ($diff->removedForeignKeys as $constraint) { + if (! $constraint instanceof ForeignKeyConstraint) { + $constraint = new Identifier($constraint); + } + + $constraintName = strtolower($constraint->getName()); + if (! strlen($constraintName) || ! isset($foreignKeys[$constraintName])) { + continue; + } + + unset($foreignKeys[$constraintName]); + } + + foreach (array_merge($diff->changedForeignKeys, $diff->addedForeignKeys) as $constraint) { + $constraintName = strtolower($constraint->getName()); + if (strlen($constraintName)) { + $foreignKeys[$constraintName] = $constraint; + } else { + $foreignKeys[] = $constraint; + } + } + + return $foreignKeys; + } + + /** + * @return Index[] + */ + private function getPrimaryIndexInAlteredTable(TableDiff $diff, Table $fromTable) + { + $primaryIndex = []; + + foreach ($this->getIndexesInAlteredTable($diff, $fromTable) as $index) { + if (! $index->isPrimary()) { + continue; + } + + $primaryIndex = [$index->getName() => $index]; + } + + return $primaryIndex; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/TrimMode.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/TrimMode.php new file mode 100755 index 0000000..eb499ee --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/TrimMode.php @@ -0,0 +1,23 @@ +getParams(); + if (isset($params['portability'])) { + $this->portability = $params['portability'] = (new OptimizeFlags())( + $this->getDatabasePlatform(), + $params['portability'] + ); + } + + if (isset($params['fetch_case']) && $this->portability & self::PORTABILITY_FIX_CASE) { + if ($this->_conn instanceof PDOConnection) { + // make use of c-level support for case handling + $this->_conn->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); + } else { + $this->case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER; + } + } + } + + return $ret; + } + + /** + * @return int + */ + public function getPortability() + { + return $this->portability; + } + + /** + * @return int|null + */ + public function getFetchCase() + { + return $this->case; + } + + /** + * {@inheritdoc} + */ + public function executeQuery($sql, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) + { + $stmt = new Statement(parent::executeQuery($sql, $params, $types, $qcp), $this); + $stmt->setFetchMode($this->defaultFetchMode); + + return new ForwardCompatibility\Result($stmt); + } + + /** + * {@inheritdoc} + * + * @param string $sql + * + * @return Statement + */ + public function prepare($sql) + { + $stmt = new Statement(parent::prepare($sql), $this); + $stmt->setFetchMode($this->defaultFetchMode); + + return $stmt; + } + + /** + * {@inheritdoc} + */ + public function query() + { + $connection = $this->getWrappedConnection(); + + $stmt = $connection->query(...func_get_args()); + $stmt = new Statement($stmt, $this); + $stmt->setFetchMode($this->defaultFetchMode); + + return $stmt; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/OptimizeFlags.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/OptimizeFlags.php new file mode 100755 index 0000000..7d8e55d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/OptimizeFlags.php @@ -0,0 +1,44 @@ + + */ + private static $platforms = [ + DB2Platform::class => 0, + OraclePlatform::class => Connection::PORTABILITY_EMPTY_TO_NULL, + PostgreSQL94Platform::class => 0, + SQLAnywhere16Platform::class => 0, + SqlitePlatform::class => 0, + SQLServer2012Platform::class => 0, + ]; + + public function __invoke(AbstractPlatform $platform, int $flags): int + { + foreach (self::$platforms as $class => $mask) { + if ($platform instanceof $class) { + $flags &= ~$mask; + + break; + } + } + + return $flags; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Statement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Statement.php new file mode 100755 index 0000000..c97c205 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Statement.php @@ -0,0 +1,403 @@ +Statement and applies portability measures. + * + * @param DriverStatement|ResultStatement $stmt + */ + public function __construct($stmt, Connection $conn) + { + $this->stmt = $stmt; + $this->portability = $conn->getPortability(); + $this->case = $conn->getFetchCase(); + } + + /** + * {@inheritdoc} + */ + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->bindParam($param, $variable, $type, $length); + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, $type = ParameterType::STRING) + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->bindValue($param, $value, $type); + } + + /** + * {@inheritdoc} + * + * @deprecated Use free() instead. + */ + public function closeCursor() + { + return $this->stmt->closeCursor(); + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + return $this->stmt->columnCount(); + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorCode() + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->errorCode(); + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->errorInfo(); + } + + /** + * {@inheritdoc} + */ + public function execute($params = null) + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->execute($params); + } + + /** + * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->defaultFetchMode = $fetchMode; + + return $this->stmt->setFetchMode($fetchMode, $arg2, $arg3); + } + + /** + * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. + */ + #[ReturnTypeWillChange] + public function getIterator() + { + return new StatementIterator($this); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + */ + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + + $row = $this->stmt->fetch($fetchMode); + + $iterateRow = ( + $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL | Connection::PORTABILITY_RTRIM) + ) !== 0; + + $fixCase = $this->case !== null + && ($fetchMode === FetchMode::ASSOCIATIVE || $fetchMode === FetchMode::MIXED) + && ($this->portability & Connection::PORTABILITY_FIX_CASE); + + $row = $this->fixRow($row, $iterateRow, $fixCase); + + return $row; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + + if ($fetchArgument) { + $rows = $this->stmt->fetchAll($fetchMode, $fetchArgument); + } else { + $rows = $this->stmt->fetchAll($fetchMode); + } + + $fixCase = $this->case !== null + && ($fetchMode === FetchMode::ASSOCIATIVE || $fetchMode === FetchMode::MIXED) + && ($this->portability & Connection::PORTABILITY_FIX_CASE); + + return $this->fixResultSet($rows, $fixCase, $fetchMode !== FetchMode::COLUMN); + } + + /** + * {@inheritdoc} + */ + public function fetchNumeric() + { + if ($this->stmt instanceof Result) { + $row = $this->stmt->fetchNumeric(); + } else { + $row = $this->stmt->fetch(FetchMode::NUMERIC); + } + + return $this->fixResult($row, false); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + if ($this->stmt instanceof Result) { + $row = $this->stmt->fetchAssociative(); + } else { + $row = $this->stmt->fetch(FetchMode::ASSOCIATIVE); + } + + return $this->fixResult($row, true); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + if ($this->stmt instanceof Result) { + $value = $this->stmt->fetchOne(); + } else { + $value = $this->stmt->fetch(FetchMode::COLUMN); + } + + if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) !== 0 && $value === '') { + $value = null; + } elseif (($this->portability & Connection::PORTABILITY_RTRIM) !== 0 && is_string($value)) { + $value = rtrim($value); + } + + return $value; + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric(): array + { + if ($this->stmt instanceof Result) { + $data = $this->stmt->fetchAllNumeric(); + } else { + $data = $this->stmt->fetchAll(FetchMode::NUMERIC); + } + + return $this->fixResultSet($data, false, true); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative(): array + { + if ($this->stmt instanceof Result) { + $data = $this->stmt->fetchAllAssociative(); + } else { + $data = $this->stmt->fetchAll(FetchMode::ASSOCIATIVE); + } + + return $this->fixResultSet($data, true, true); + } + + /** + * {@inheritdoc} + */ + public function fetchFirstColumn(): array + { + if ($this->stmt instanceof Result) { + $data = $this->stmt->fetchFirstColumn(); + } else { + $data = $this->stmt->fetchAll(FetchMode::COLUMN); + } + + return $this->fixResultSet($data, true, false); + } + + public function free(): void + { + if ($this->stmt instanceof Result) { + $this->stmt->free(); + + return; + } + + $this->stmt->closeCursor(); + } + + /** + * @param mixed $result + * + * @return mixed + */ + private function fixResult($result, bool $fixCase) + { + $iterateRow = ( + $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL | Connection::PORTABILITY_RTRIM) + ) !== 0; + + $fixCase = $fixCase && $this->case !== null && ($this->portability & Connection::PORTABILITY_FIX_CASE) !== 0; + + return $this->fixRow($result, $iterateRow, $fixCase); + } + + /** + * @param array $resultSet + * + * @return array + */ + private function fixResultSet(array $resultSet, bool $fixCase, bool $isArray): array + { + $iterateRow = ( + $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL | Connection::PORTABILITY_RTRIM) + ) !== 0; + + $fixCase = $fixCase && $this->case !== null && ($this->portability & Connection::PORTABILITY_FIX_CASE) !== 0; + + if (! $iterateRow && ! $fixCase) { + return $resultSet; + } + + if (! $isArray) { + foreach ($resultSet as $num => $value) { + $resultSet[$num] = [$value]; + } + } + + foreach ($resultSet as $num => $row) { + $resultSet[$num] = $this->fixRow($row, $iterateRow, $fixCase); + } + + if (! $isArray) { + foreach ($resultSet as $num => $row) { + $resultSet[$num] = $row[0]; + } + } + + return $resultSet; + } + + /** + * @param mixed $row + * @param bool $iterateRow + * @param bool $fixCase + * + * @return mixed + */ + protected function fixRow($row, $iterateRow, $fixCase) + { + if (! $row) { + return $row; + } + + if ($fixCase) { + assert($this->case !== null); + $row = array_change_key_case($row, $this->case); + } + + if ($iterateRow) { + foreach ($row as $k => $v) { + if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) && $v === '') { + $row[$k] = null; + } elseif (($this->portability & Connection::PORTABILITY_RTRIM) && is_string($v)) { + $row[$k] = rtrim($v); + } + } + } + + return $row; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. + */ + public function fetchColumn($columnIndex = 0) + { + $value = $this->stmt->fetchColumn($columnIndex); + + if ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL | Connection::PORTABILITY_RTRIM)) { + if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) && $value === '') { + $value = null; + } elseif (($this->portability & Connection::PORTABILITY_RTRIM) && is_string($value)) { + $value = rtrim($value); + } + } + + return $value; + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->rowCount(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php new file mode 100755 index 0000000..e0194c2 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php @@ -0,0 +1,186 @@ +type = $type; + + $this->addMultiple($parts); + + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3864', + 'Do not use CompositeExpression constructor directly, use static and() and or() factory methods.' + ); + } + + /** + * @param self|string $part + * @param self|string ...$parts + */ + public static function and($part, ...$parts): self + { + return new self(self::TYPE_AND, array_merge([$part], $parts)); + } + + /** + * @param self|string $part + * @param self|string ...$parts + */ + public static function or($part, ...$parts): self + { + return new self(self::TYPE_OR, array_merge([$part], $parts)); + } + + /** + * Adds multiple parts to composite expression. + * + * @deprecated This class will be made immutable. Use with() instead. + * + * @param self[]|string[] $parts + * + * @return CompositeExpression + */ + public function addMultiple(array $parts = []) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3844', + 'CompositeExpression::addMultiple() is deprecated, use CompositeExpression::with() instead.' + ); + + foreach ($parts as $part) { + $this->add($part); + } + + return $this; + } + + /** + * Adds an expression to composite expression. + * + * @deprecated This class will be made immutable. Use with() instead. + * + * @param mixed $part + * + * @return CompositeExpression + */ + public function add($part) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3844', + 'CompositeExpression::add() is deprecated, use CompositeExpression::with() instead.' + ); + + if (empty($part)) { + return $this; + } + + if ($part instanceof self && count($part) === 0) { + return $this; + } + + $this->parts[] = $part; + + return $this; + } + + /** + * Returns a new CompositeExpression with the given parts added. + * + * @param self|string $part + * @param self|string ...$parts + */ + public function with($part, ...$parts): self + { + $that = clone $this; + + $that->parts[] = $part; + + foreach ($parts as $part) { + $that->parts[] = $part; + } + + return $that; + } + + /** + * Retrieves the amount of expressions on composite expression. + * + * @return int + */ + #[ReturnTypeWillChange] + public function count() + { + return count($this->parts); + } + + /** + * Retrieves the string representation of this composite expression. + * + * @return string + */ + public function __toString() + { + if ($this->count() === 1) { + return (string) $this->parts[0]; + } + + return '(' . implode(') ' . $this->type . ' (', $this->parts) . ')'; + } + + /** + * Returns the type of this composite expression (AND/OR). + * + * @return string + */ + public function getType() + { + return $this->type; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php new file mode 100755 index 0000000..c86cfc3 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php @@ -0,0 +1,322 @@ +'; + public const LT = '<'; + public const LTE = '<='; + public const GT = '>'; + public const GTE = '>='; + + /** + * The DBAL Connection. + * + * @var Connection + */ + private $connection; + + /** + * Initializes a new ExpressionBuilder. + * + * @param Connection $connection The DBAL Connection. + */ + public function __construct(Connection $connection) + { + $this->connection = $connection; + } + + /** + * Creates a conjunction of the given expressions. + * + * @param string|CompositeExpression $expression + * @param string|CompositeExpression ...$expressions + */ + public function and($expression, ...$expressions): CompositeExpression + { + return CompositeExpression::and($expression, ...$expressions); + } + + /** + * Creates a disjunction of the given expressions. + * + * @param string|CompositeExpression $expression + * @param string|CompositeExpression ...$expressions + */ + public function or($expression, ...$expressions): CompositeExpression + { + return CompositeExpression::or($expression, ...$expressions); + } + + /** + * @deprecated Use `and()` instead. + * + * @param mixed $x Optional clause. Defaults = null, but requires + * at least one defined when converting to string. + * + * @return CompositeExpression + */ + public function andX($x = null) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3851', + 'ExpressionBuilder::andX() is deprecated, use ExpressionBuilder::and() instead.' + ); + + return new CompositeExpression(CompositeExpression::TYPE_AND, func_get_args()); + } + + /** + * @deprecated Use `or()` instead. + * + * @param mixed $x Optional clause. Defaults = null, but requires + * at least one defined when converting to string. + * + * @return CompositeExpression + */ + public function orX($x = null) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3851', + 'ExpressionBuilder::orX() is deprecated, use ExpressionBuilder::or() instead.' + ); + + return new CompositeExpression(CompositeExpression::TYPE_OR, func_get_args()); + } + + /** + * Creates a comparison expression. + * + * @param mixed $x The left expression. + * @param string $operator One of the ExpressionBuilder::* constants. + * @param mixed $y The right expression. + * + * @return string + */ + public function comparison($x, $operator, $y) + { + return $x . ' ' . $operator . ' ' . $y; + } + + /** + * Creates an equality comparison expression with the given arguments. + * + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a = . Example: + * + * [php] + * // u.id = ? + * $expr->eq('u.id', '?'); + * + * @param mixed $x The left expression. + * @param mixed $y The right expression. + * + * @return string + */ + public function eq($x, $y) + { + return $this->comparison($x, self::EQ, $y); + } + + /** + * Creates a non equality comparison expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a <> . Example: + * + * [php] + * // u.id <> 1 + * $q->where($q->expr()->neq('u.id', '1')); + * + * @param mixed $x The left expression. + * @param mixed $y The right expression. + * + * @return string + */ + public function neq($x, $y) + { + return $this->comparison($x, self::NEQ, $y); + } + + /** + * Creates a lower-than comparison expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a < . Example: + * + * [php] + * // u.id < ? + * $q->where($q->expr()->lt('u.id', '?')); + * + * @param mixed $x The left expression. + * @param mixed $y The right expression. + * + * @return string + */ + public function lt($x, $y) + { + return $this->comparison($x, self::LT, $y); + } + + /** + * Creates a lower-than-equal comparison expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a <= . Example: + * + * [php] + * // u.id <= ? + * $q->where($q->expr()->lte('u.id', '?')); + * + * @param mixed $x The left expression. + * @param mixed $y The right expression. + * + * @return string + */ + public function lte($x, $y) + { + return $this->comparison($x, self::LTE, $y); + } + + /** + * Creates a greater-than comparison expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a > . Example: + * + * [php] + * // u.id > ? + * $q->where($q->expr()->gt('u.id', '?')); + * + * @param mixed $x The left expression. + * @param mixed $y The right expression. + * + * @return string + */ + public function gt($x, $y) + { + return $this->comparison($x, self::GT, $y); + } + + /** + * Creates a greater-than-equal comparison expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a >= . Example: + * + * [php] + * // u.id >= ? + * $q->where($q->expr()->gte('u.id', '?')); + * + * @param mixed $x The left expression. + * @param mixed $y The right expression. + * + * @return string + */ + public function gte($x, $y) + { + return $this->comparison($x, self::GTE, $y); + } + + /** + * Creates an IS NULL expression with the given arguments. + * + * @param string $x The expression to be restricted by IS NULL. + * + * @return string + */ + public function isNull($x) + { + return $x . ' IS NULL'; + } + + /** + * Creates an IS NOT NULL expression with the given arguments. + * + * @param string $x The expression to be restricted by IS NOT NULL. + * + * @return string + */ + public function isNotNull($x) + { + return $x . ' IS NOT NULL'; + } + + /** + * Creates a LIKE() comparison expression with the given arguments. + * + * @param string $x Field in string format to be inspected by LIKE() comparison. + * @param mixed $y Argument to be used in LIKE() comparison. + * + * @return string + */ + public function like($x, $y/*, ?string $escapeChar = null */) + { + return $this->comparison($x, 'LIKE', $y) . + (func_num_args() >= 3 ? sprintf(' ESCAPE %s', func_get_arg(2)) : ''); + } + + /** + * Creates a NOT LIKE() comparison expression with the given arguments. + * + * @param string $x Field in string format to be inspected by NOT LIKE() comparison. + * @param mixed $y Argument to be used in NOT LIKE() comparison. + * + * @return string + */ + public function notLike($x, $y/*, ?string $escapeChar = null */) + { + return $this->comparison($x, 'NOT LIKE', $y) . + (func_num_args() >= 3 ? sprintf(' ESCAPE %s', func_get_arg(2)) : ''); + } + + /** + * Creates a IN () comparison expression with the given arguments. + * + * @param string $x The field in string format to be inspected by IN() comparison. + * @param string|string[] $y The placeholder or the array of values to be used by IN() comparison. + * + * @return string + */ + public function in($x, $y) + { + return $this->comparison($x, 'IN', '(' . implode(', ', (array) $y) . ')'); + } + + /** + * Creates a NOT IN () comparison expression with the given arguments. + * + * @param string $x The expression to be inspected by NOT IN() comparison. + * @param string|string[] $y The placeholder or the array of values to be used by NOT IN() comparison. + * + * @return string + */ + public function notIn($x, $y) + { + return $this->comparison($x, 'NOT IN', '(' . implode(', ', (array) $y) . ')'); + } + + /** + * Quotes a given input parameter. + * + * @param mixed $input The parameter to be quoted. + * @param int|null $type The type of the parameter. + * + * @return string + */ + public function literal($input, $type = null) + { + return $this->connection->quote($input, $type); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php new file mode 100755 index 0000000..419937d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php @@ -0,0 +1,1450 @@ + [], + 'distinct' => false, + 'from' => [], + 'join' => [], + 'set' => [], + 'where' => null, + 'groupBy' => [], + 'having' => null, + 'orderBy' => [], + 'values' => [], + ]; + + /** + * The array of SQL parts collected. + * + * @var mixed[] + */ + private $sqlParts = self::SQL_PARTS_DEFAULTS; + + /** + * The complete SQL string for this query. + * + * @var string|null + */ + private $sql; + + /** + * The query parameters. + * + * @var array|array + */ + private $params = []; + + /** + * The parameter type map of this query. + * + * @var array|array + */ + private $paramTypes = []; + + /** + * The type of query this is. Can be select, update or delete. + * + * @var int + */ + private $type = self::SELECT; + + /** + * The state of the query object. Can be dirty or clean. + * + * @var int + */ + private $state = self::STATE_CLEAN; + + /** + * The index of the first result to retrieve. + * + * @var int + */ + private $firstResult = 0; + + /** + * The maximum number of results to retrieve or NULL to retrieve all results. + * + * @var int|null + */ + private $maxResults; + + /** + * The counter of bound parameters used with {@see bindValue). + * + * @var int + */ + private $boundCounter = 0; + + /** + * Initializes a new QueryBuilder. + * + * @param Connection $connection The DBAL Connection. + */ + public function __construct(Connection $connection) + { + $this->connection = $connection; + } + + /** + * Gets an ExpressionBuilder used for object-oriented construction of query expressions. + * This producer method is intended for convenient inline usage. Example: + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u') + * ->from('users', 'u') + * ->where($qb->expr()->eq('u.id', 1)); + * + * + * For more complex expression construction, consider storing the expression + * builder object in a local variable. + * + * @return ExpressionBuilder + */ + public function expr() + { + return $this->connection->getExpressionBuilder(); + } + + /** + * Gets the type of the currently built query. + * + * @return int + */ + public function getType() + { + return $this->type; + } + + /** + * Gets the associated DBAL Connection for this query builder. + * + * @return Connection + */ + public function getConnection() + { + return $this->connection; + } + + /** + * Gets the state of this query builder instance. + * + * @return int Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN. + */ + public function getState() + { + return $this->state; + } + + /** + * Executes this query using the bound parameters and their types. + * + * @return ForwardCompatibility\DriverStatement|int + * + * @throws Exception + */ + public function execute() + { + if ($this->type === self::SELECT) { + return ForwardCompatibility\Result::ensure( + $this->connection->executeQuery($this->getSQL(), $this->params, $this->paramTypes) + ); + } + + return $this->connection->executeStatement($this->getSQL(), $this->params, $this->paramTypes); + } + + /** + * Gets the complete SQL string formed by the current specifications of this QueryBuilder. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * echo $qb->getSQL(); // SELECT u FROM User u + * + * + * @return string The SQL query string. + */ + public function getSQL() + { + if ($this->sql !== null && $this->state === self::STATE_CLEAN) { + return $this->sql; + } + + switch ($this->type) { + case self::INSERT: + $sql = $this->getSQLForInsert(); + break; + + case self::DELETE: + $sql = $this->getSQLForDelete(); + break; + + case self::UPDATE: + $sql = $this->getSQLForUpdate(); + break; + + case self::SELECT: + default: + $sql = $this->getSQLForSelect(); + break; + } + + $this->state = self::STATE_CLEAN; + $this->sql = $sql; + + return $sql; + } + + /** + * Sets a query parameter for the query being constructed. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u') + * ->from('users', 'u') + * ->where('u.id = :user_id') + * ->setParameter(':user_id', 1); + * + * + * @param int|string $key Parameter position or name + * @param mixed $value Parameter value + * @param int|string|Type|null $type Parameter type + * + * @return $this This QueryBuilder instance. + */ + public function setParameter($key, $value, $type = null) + { + if ($type !== null) { + $this->paramTypes[$key] = $type; + } + + $this->params[$key] = $value; + + return $this; + } + + /** + * Sets a collection of query parameters for the query being constructed. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u') + * ->from('users', 'u') + * ->where('u.id = :user_id1 OR u.id = :user_id2') + * ->setParameters(array( + * ':user_id1' => 1, + * ':user_id2' => 2 + * )); + * + * + * @param array|array $params Parameters to set + * @param array|array $types Parameter types + * + * @return $this This QueryBuilder instance. + */ + public function setParameters(array $params, array $types = []) + { + $this->paramTypes = $types; + $this->params = $params; + + return $this; + } + + /** + * Gets all defined query parameters for the query being constructed indexed by parameter index or name. + * + * @return array|array The currently defined query parameters + */ + public function getParameters() + { + return $this->params; + } + + /** + * Gets a (previously set) query parameter of the query being constructed. + * + * @param mixed $key The key (index or name) of the bound parameter. + * + * @return mixed The value of the bound parameter. + */ + public function getParameter($key) + { + return $this->params[$key] ?? null; + } + + /** + * Gets all defined query parameter types for the query being constructed indexed by parameter index or name. + * + * @return array|array The currently defined + * query parameter types + */ + public function getParameterTypes() + { + return $this->paramTypes; + } + + /** + * Gets a (previously set) query parameter type of the query being constructed. + * + * @param int|string $key The key of the bound parameter type + * + * @return int|string|Type|null The value of the bound parameter type + */ + public function getParameterType($key) + { + return $this->paramTypes[$key] ?? null; + } + + /** + * Sets the position of the first result to retrieve (the "offset"). + * + * @param int $firstResult The first result to return. + * + * @return $this This QueryBuilder instance. + */ + public function setFirstResult($firstResult) + { + $this->state = self::STATE_DIRTY; + $this->firstResult = $firstResult; + + return $this; + } + + /** + * Gets the position of the first result the query object was set to retrieve (the "offset"). + * + * @return int The position of the first result. + */ + public function getFirstResult() + { + return $this->firstResult; + } + + /** + * Sets the maximum number of results to retrieve (the "limit"). + * + * @param int|null $maxResults The maximum number of results to retrieve or NULL to retrieve all results. + * + * @return $this This QueryBuilder instance. + */ + public function setMaxResults($maxResults) + { + $this->state = self::STATE_DIRTY; + $this->maxResults = $maxResults; + + return $this; + } + + /** + * Gets the maximum number of results the query object was set to retrieve (the "limit"). + * Returns NULL if all results will be returned. + * + * @return int|null The maximum number of results. + */ + public function getMaxResults() + { + return $this->maxResults; + } + + /** + * Either appends to or replaces a single, generic query part. + * + * The available parts are: 'select', 'from', 'set', 'where', + * 'groupBy', 'having' and 'orderBy'. + * + * @param string $sqlPartName + * @param mixed $sqlPart + * @param bool $append + * + * @return $this This QueryBuilder instance. + */ + public function add($sqlPartName, $sqlPart, $append = false) + { + $isArray = is_array($sqlPart); + $isMultiple = is_array($this->sqlParts[$sqlPartName]); + + if ($isMultiple && ! $isArray) { + $sqlPart = [$sqlPart]; + } + + $this->state = self::STATE_DIRTY; + + if ($append) { + if ( + $sqlPartName === 'orderBy' + || $sqlPartName === 'groupBy' + || $sqlPartName === 'select' + || $sqlPartName === 'set' + ) { + foreach ($sqlPart as $part) { + $this->sqlParts[$sqlPartName][] = $part; + } + } elseif ($isArray && is_array($sqlPart[key($sqlPart)])) { + $key = key($sqlPart); + $this->sqlParts[$sqlPartName][$key][] = $sqlPart[$key]; + } elseif ($isMultiple) { + $this->sqlParts[$sqlPartName][] = $sqlPart; + } else { + $this->sqlParts[$sqlPartName] = $sqlPart; + } + + return $this; + } + + $this->sqlParts[$sqlPartName] = $sqlPart; + + return $this; + } + + /** + * Specifies an item that is to be returned in the query result. + * Replaces any previously specified selections, if any. + * + * USING AN ARRAY ARGUMENT IS DEPRECATED. Pass each value as an individual argument. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.id', 'p.id') + * ->from('users', 'u') + * ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id'); + * + * + * @param string|string[]|null $select The selection expression. USING AN ARRAY OR NULL IS DEPRECATED. + * Pass each value as an individual argument. + * + * @return $this This QueryBuilder instance. + */ + public function select($select = null/*, string ...$selects*/) + { + $this->type = self::SELECT; + + if (empty($select)) { + return $this; + } + + if (is_array($select)) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3837', + 'Passing an array for the first argument to QueryBuilder::select is deprecated, ' . + 'pass each value as an individual variadic argument instead.' + ); + } + + $selects = is_array($select) ? $select : func_get_args(); + + return $this->add('select', $selects); + } + + /** + * Adds DISTINCT to the query. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.id') + * ->distinct() + * ->from('users', 'u') + * + * + * @return $this This QueryBuilder instance. + */ + public function distinct(): self + { + $this->sqlParts['distinct'] = true; + + return $this; + } + + /** + * Adds an item that is to be returned in the query result. + * + * USING AN ARRAY ARGUMENT IS DEPRECATED. Pass each value as an individual argument. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.id') + * ->addSelect('p.id') + * ->from('users', 'u') + * ->leftJoin('u', 'phonenumbers', 'u.id = p.user_id'); + * + * + * @param string|string[]|null $select The selection expression. USING AN ARRAY OR NULL IS DEPRECATED. + * Pass each value as an individual argument. + * + * @return $this This QueryBuilder instance. + */ + public function addSelect($select = null/*, string ...$selects*/) + { + $this->type = self::SELECT; + + if (empty($select)) { + return $this; + } + + if (is_array($select)) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3837', + 'Passing an array for the first argument to QueryBuilder::addSelect is deprecated, ' . + 'pass each value as an individual variadic argument instead.' + ); + } + + $selects = is_array($select) ? $select : func_get_args(); + + return $this->add('select', $selects, true); + } + + /** + * Turns the query being built into a bulk delete query that ranges over + * a certain table. + * + * + * $qb = $conn->createQueryBuilder() + * ->delete('users', 'u') + * ->where('u.id = :user_id') + * ->setParameter(':user_id', 1); + * + * + * @param string $delete The table whose rows are subject to the deletion. + * @param string $alias The table alias used in the constructed query. + * + * @return $this This QueryBuilder instance. + */ + public function delete($delete = null, $alias = null) + { + $this->type = self::DELETE; + + if (! $delete) { + return $this; + } + + return $this->add('from', [ + 'table' => $delete, + 'alias' => $alias, + ]); + } + + /** + * Turns the query being built into a bulk update query that ranges over + * a certain table + * + * + * $qb = $conn->createQueryBuilder() + * ->update('counters', 'c') + * ->set('c.value', 'c.value + 1') + * ->where('c.id = ?'); + * + * + * @param string $update The table whose rows are subject to the update. + * @param string $alias The table alias used in the constructed query. + * + * @return $this This QueryBuilder instance. + */ + public function update($update = null, $alias = null) + { + $this->type = self::UPDATE; + + if (! $update) { + return $this; + } + + return $this->add('from', [ + 'table' => $update, + 'alias' => $alias, + ]); + } + + /** + * Turns the query being built into an insert query that inserts into + * a certain table + * + * + * $qb = $conn->createQueryBuilder() + * ->insert('users') + * ->values( + * array( + * 'name' => '?', + * 'password' => '?' + * ) + * ); + * + * + * @param string $insert The table into which the rows should be inserted. + * + * @return $this This QueryBuilder instance. + */ + public function insert($insert = null) + { + $this->type = self::INSERT; + + if (! $insert) { + return $this; + } + + return $this->add('from', ['table' => $insert]); + } + + /** + * Creates and adds a query root corresponding to the table identified by the + * given alias, forming a cartesian product with any existing query roots. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.id') + * ->from('users', 'u') + * + * + * @param string $from The table. + * @param string|null $alias The alias of the table. + * + * @return $this This QueryBuilder instance. + */ + public function from($from, $alias = null) + { + return $this->add('from', [ + 'table' => $from, + 'alias' => $alias, + ], true); + } + + /** + * Creates and adds a join to the query. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->join('u', 'phonenumbers', 'p', 'p.is_primary = 1'); + * + * + * @param string $fromAlias The alias that points to a from clause. + * @param string $join The table name to join. + * @param string $alias The alias of the join table. + * @param string $condition The condition for the join. + * + * @return $this This QueryBuilder instance. + */ + public function join($fromAlias, $join, $alias, $condition = null) + { + return $this->innerJoin($fromAlias, $join, $alias, $condition); + } + + /** + * Creates and adds a join to the query. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->innerJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); + * + * + * @param string $fromAlias The alias that points to a from clause. + * @param string $join The table name to join. + * @param string $alias The alias of the join table. + * @param string $condition The condition for the join. + * + * @return $this This QueryBuilder instance. + */ + public function innerJoin($fromAlias, $join, $alias, $condition = null) + { + return $this->add('join', [ + $fromAlias => [ + 'joinType' => 'inner', + 'joinTable' => $join, + 'joinAlias' => $alias, + 'joinCondition' => $condition, + ], + ], true); + } + + /** + * Creates and adds a left join to the query. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->leftJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); + * + * + * @param string $fromAlias The alias that points to a from clause. + * @param string $join The table name to join. + * @param string $alias The alias of the join table. + * @param string $condition The condition for the join. + * + * @return $this This QueryBuilder instance. + */ + public function leftJoin($fromAlias, $join, $alias, $condition = null) + { + return $this->add('join', [ + $fromAlias => [ + 'joinType' => 'left', + 'joinTable' => $join, + 'joinAlias' => $alias, + 'joinCondition' => $condition, + ], + ], true); + } + + /** + * Creates and adds a right join to the query. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->rightJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); + * + * + * @param string $fromAlias The alias that points to a from clause. + * @param string $join The table name to join. + * @param string $alias The alias of the join table. + * @param string $condition The condition for the join. + * + * @return $this This QueryBuilder instance. + */ + public function rightJoin($fromAlias, $join, $alias, $condition = null) + { + return $this->add('join', [ + $fromAlias => [ + 'joinType' => 'right', + 'joinTable' => $join, + 'joinAlias' => $alias, + 'joinCondition' => $condition, + ], + ], true); + } + + /** + * Sets a new value for a column in a bulk update query. + * + * + * $qb = $conn->createQueryBuilder() + * ->update('counters', 'c') + * ->set('c.value', 'c.value + 1') + * ->where('c.id = ?'); + * + * + * @param string $key The column to set. + * @param string $value The value, expression, placeholder, etc. + * + * @return $this This QueryBuilder instance. + */ + public function set($key, $value) + { + return $this->add('set', $key . ' = ' . $value, true); + } + + /** + * Specifies one or more restrictions to the query result. + * Replaces any previously specified restrictions, if any. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('c.value') + * ->from('counters', 'c') + * ->where('c.id = ?'); + * + * // You can optionally programatically build and/or expressions + * $qb = $conn->createQueryBuilder(); + * + * $or = $qb->expr()->orx(); + * $or->add($qb->expr()->eq('c.id', 1)); + * $or->add($qb->expr()->eq('c.id', 2)); + * + * $qb->update('counters', 'c') + * ->set('c.value', 'c.value + 1') + * ->where($or); + * + * + * @param mixed $predicates The restriction predicates. + * + * @return $this This QueryBuilder instance. + */ + public function where($predicates) + { + if (! (func_num_args() === 1 && $predicates instanceof CompositeExpression)) { + $predicates = CompositeExpression::and(...func_get_args()); + } + + return $this->add('where', $predicates); + } + + /** + * Adds one or more restrictions to the query results, forming a logical + * conjunction with any previously specified restrictions. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u') + * ->from('users', 'u') + * ->where('u.username LIKE ?') + * ->andWhere('u.is_active = 1'); + * + * + * @see where() + * + * @param mixed $where The query restrictions. + * + * @return $this This QueryBuilder instance. + */ + public function andWhere($where) + { + $args = func_get_args(); + $args = array_filter($args); // https://github.com/doctrine/dbal/issues/4282 + $where = $this->getQueryPart('where'); + + if ($where instanceof CompositeExpression && $where->getType() === CompositeExpression::TYPE_AND) { + if (count($args) > 0) { + $where = $where->with(...$args); + } + } else { + array_unshift($args, $where); + $where = CompositeExpression::and(...$args); + } + + return $this->add('where', $where, true); + } + + /** + * Adds one or more restrictions to the query results, forming a logical + * disjunction with any previously specified restrictions. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->where('u.id = 1') + * ->orWhere('u.id = 2'); + * + * + * @see where() + * + * @param mixed $where The WHERE statement. + * + * @return $this This QueryBuilder instance. + */ + public function orWhere($where) + { + $args = func_get_args(); + $args = array_filter($args); // https://github.com/doctrine/dbal/issues/4282 + $where = $this->getQueryPart('where'); + + if ($where instanceof CompositeExpression && $where->getType() === CompositeExpression::TYPE_OR) { + if (count($args) > 0) { + $where = $where->with(...$args); + } + } else { + array_unshift($args, $where); + $where = CompositeExpression::or(...$args); + } + + return $this->add('where', $where, true); + } + + /** + * Specifies a grouping over the results of the query. + * Replaces any previously specified groupings, if any. + * + * USING AN ARRAY ARGUMENT IS DEPRECATED. Pass each value as an individual argument. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->groupBy('u.id'); + * + * + * @param string|string[] $groupBy The grouping expression. USING AN ARRAY IS DEPRECATED. + * Pass each value as an individual argument. + * + * @return $this This QueryBuilder instance. + */ + public function groupBy($groupBy/*, string ...$groupBys*/) + { + if (empty($groupBy)) { + return $this; + } + + if (is_array($groupBy)) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3837', + 'Passing an array for the first argument to QueryBuilder::groupBy is deprecated, ' . + 'pass each value as an individual variadic argument instead.' + ); + } + + $groupBy = is_array($groupBy) ? $groupBy : func_get_args(); + + return $this->add('groupBy', $groupBy, false); + } + + /** + * Adds a grouping expression to the query. + * + * USING AN ARRAY ARGUMENT IS DEPRECATED. Pass each value as an individual argument. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->groupBy('u.lastLogin') + * ->addGroupBy('u.createdAt'); + * + * + * @param string|string[] $groupBy The grouping expression. USING AN ARRAY IS DEPRECATED. + * Pass each value as an individual argument. + * + * @return $this This QueryBuilder instance. + */ + public function addGroupBy($groupBy/*, string ...$groupBys*/) + { + if (empty($groupBy)) { + return $this; + } + + if (is_array($groupBy)) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3837', + 'Passing an array for the first argument to QueryBuilder::addGroupBy is deprecated, ' . + 'pass each value as an individual variadic argument instead.' + ); + } + + $groupBy = is_array($groupBy) ? $groupBy : func_get_args(); + + return $this->add('groupBy', $groupBy, true); + } + + /** + * Sets a value for a column in an insert query. + * + * + * $qb = $conn->createQueryBuilder() + * ->insert('users') + * ->values( + * array( + * 'name' => '?' + * ) + * ) + * ->setValue('password', '?'); + * + * + * @param string $column The column into which the value should be inserted. + * @param string $value The value that should be inserted into the column. + * + * @return $this This QueryBuilder instance. + */ + public function setValue($column, $value) + { + $this->sqlParts['values'][$column] = $value; + + return $this; + } + + /** + * Specifies values for an insert query indexed by column names. + * Replaces any previous values, if any. + * + * + * $qb = $conn->createQueryBuilder() + * ->insert('users') + * ->values( + * array( + * 'name' => '?', + * 'password' => '?' + * ) + * ); + * + * + * @param mixed[] $values The values to specify for the insert query indexed by column names. + * + * @return $this This QueryBuilder instance. + */ + public function values(array $values) + { + return $this->add('values', $values); + } + + /** + * Specifies a restriction over the groups of the query. + * Replaces any previous having restrictions, if any. + * + * @param mixed $having The restriction over the groups. + * + * @return $this This QueryBuilder instance. + */ + public function having($having) + { + if (! (func_num_args() === 1 && $having instanceof CompositeExpression)) { + $having = CompositeExpression::and(...func_get_args()); + } + + return $this->add('having', $having); + } + + /** + * Adds a restriction over the groups of the query, forming a logical + * conjunction with any existing having restrictions. + * + * @param mixed $having The restriction to append. + * + * @return $this This QueryBuilder instance. + */ + public function andHaving($having) + { + $args = func_get_args(); + $args = array_filter($args); // https://github.com/doctrine/dbal/issues/4282 + $having = $this->getQueryPart('having'); + + if ($having instanceof CompositeExpression && $having->getType() === CompositeExpression::TYPE_AND) { + $having = $having->with(...$args); + } else { + array_unshift($args, $having); + $having = CompositeExpression::and(...$args); + } + + return $this->add('having', $having); + } + + /** + * Adds a restriction over the groups of the query, forming a logical + * disjunction with any existing having restrictions. + * + * @param mixed $having The restriction to add. + * + * @return $this This QueryBuilder instance. + */ + public function orHaving($having) + { + $args = func_get_args(); + $args = array_filter($args); // https://github.com/doctrine/dbal/issues/4282 + $having = $this->getQueryPart('having'); + + if ($having instanceof CompositeExpression && $having->getType() === CompositeExpression::TYPE_OR) { + $having = $having->with(...$args); + } else { + array_unshift($args, $having); + $having = CompositeExpression::or(...$args); + } + + return $this->add('having', $having); + } + + /** + * Specifies an ordering for the query results. + * Replaces any previously specified orderings, if any. + * + * @param string $sort The ordering expression. + * @param string $order The ordering direction. + * + * @return $this This QueryBuilder instance. + */ + public function orderBy($sort, $order = null) + { + return $this->add('orderBy', $sort . ' ' . (! $order ? 'ASC' : $order), false); + } + + /** + * Adds an ordering to the query results. + * + * @param string $sort The ordering expression. + * @param string $order The ordering direction. + * + * @return $this This QueryBuilder instance. + */ + public function addOrderBy($sort, $order = null) + { + return $this->add('orderBy', $sort . ' ' . (! $order ? 'ASC' : $order), true); + } + + /** + * Gets a query part by its name. + * + * @param string $queryPartName + * + * @return mixed + */ + public function getQueryPart($queryPartName) + { + return $this->sqlParts[$queryPartName]; + } + + /** + * Gets all query parts. + * + * @return mixed[] + */ + public function getQueryParts() + { + return $this->sqlParts; + } + + /** + * Resets SQL parts. + * + * @param string[]|null $queryPartNames + * + * @return $this This QueryBuilder instance. + */ + public function resetQueryParts($queryPartNames = null) + { + if ($queryPartNames === null) { + $queryPartNames = array_keys($this->sqlParts); + } + + foreach ($queryPartNames as $queryPartName) { + $this->resetQueryPart($queryPartName); + } + + return $this; + } + + /** + * Resets a single SQL part. + * + * @param string $queryPartName + * + * @return $this This QueryBuilder instance. + */ + public function resetQueryPart($queryPartName) + { + $this->sqlParts[$queryPartName] = self::SQL_PARTS_DEFAULTS[$queryPartName]; + + $this->state = self::STATE_DIRTY; + + return $this; + } + + /** + * @return string + * + * @throws QueryException + */ + private function getSQLForSelect() + { + $query = 'SELECT ' . ($this->sqlParts['distinct'] ? 'DISTINCT ' : '') . + implode(', ', $this->sqlParts['select']); + + $query .= ($this->sqlParts['from'] ? ' FROM ' . implode(', ', $this->getFromClauses()) : '') + . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : '') + . ($this->sqlParts['groupBy'] ? ' GROUP BY ' . implode(', ', $this->sqlParts['groupBy']) : '') + . ($this->sqlParts['having'] !== null ? ' HAVING ' . ((string) $this->sqlParts['having']) : '') + . ($this->sqlParts['orderBy'] ? ' ORDER BY ' . implode(', ', $this->sqlParts['orderBy']) : ''); + + if ($this->isLimitQuery()) { + return $this->connection->getDatabasePlatform()->modifyLimitQuery( + $query, + $this->maxResults, + $this->firstResult + ); + } + + return $query; + } + + /** + * @return string[] + */ + private function getFromClauses() + { + $fromClauses = []; + $knownAliases = []; + + // Loop through all FROM clauses + foreach ($this->sqlParts['from'] as $from) { + if ($from['alias'] === null) { + $tableSql = $from['table']; + $tableReference = $from['table']; + } else { + $tableSql = $from['table'] . ' ' . $from['alias']; + $tableReference = $from['alias']; + } + + $knownAliases[$tableReference] = true; + + $fromClauses[$tableReference] = $tableSql . $this->getSQLForJoins($tableReference, $knownAliases); + } + + $this->verifyAllAliasesAreKnown($knownAliases); + + return $fromClauses; + } + + /** + * @param array $knownAliases + * + * @throws QueryException + */ + private function verifyAllAliasesAreKnown(array $knownAliases): void + { + foreach ($this->sqlParts['join'] as $fromAlias => $joins) { + if (! isset($knownAliases[$fromAlias])) { + throw QueryException::unknownAlias($fromAlias, array_keys($knownAliases)); + } + } + } + + /** + * @return bool + */ + private function isLimitQuery() + { + return $this->maxResults !== null || $this->firstResult !== 0; + } + + /** + * Converts this instance into an INSERT string in SQL. + * + * @return string + */ + private function getSQLForInsert() + { + return 'INSERT INTO ' . $this->sqlParts['from']['table'] . + ' (' . implode(', ', array_keys($this->sqlParts['values'])) . ')' . + ' VALUES(' . implode(', ', $this->sqlParts['values']) . ')'; + } + + /** + * Converts this instance into an UPDATE string in SQL. + * + * @return string + */ + private function getSQLForUpdate() + { + $table = $this->sqlParts['from']['table'] + . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); + + return 'UPDATE ' . $table + . ' SET ' . implode(', ', $this->sqlParts['set']) + . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : ''); + } + + /** + * Converts this instance into a DELETE string in SQL. + * + * @return string + */ + private function getSQLForDelete() + { + $table = $this->sqlParts['from']['table'] + . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); + + return 'DELETE FROM ' . $table + . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : ''); + } + + /** + * Gets a string representation of this QueryBuilder which corresponds to + * the final SQL query being constructed. + * + * @return string The string representation of this QueryBuilder. + */ + public function __toString() + { + return $this->getSQL(); + } + + /** + * Creates a new named parameter and bind the value $value to it. + * + * This method provides a shortcut for PDOStatement::bindValue + * when using prepared statements. + * + * The parameter $value specifies the value that you want to bind. If + * $placeholder is not provided bindValue() will automatically create a + * placeholder for you. An automatic placeholder will be of the name + * ':dcValue1', ':dcValue2' etc. + * + * For more information see {@link http://php.net/pdostatement-bindparam} + * + * Example: + * + * $value = 2; + * $q->eq( 'id', $q->bindValue( $value ) ); + * $stmt = $q->executeQuery(); // executed with 'id = 2' + * + * + * @link http://www.zetacomponents.org + * + * @param mixed $value + * @param int|string|Type|null $type + * @param string $placeHolder The name to bind with. The string must start with a colon ':'. + * + * @return string the placeholder name used. + */ + public function createNamedParameter($value, $type = ParameterType::STRING, $placeHolder = null) + { + if ($placeHolder === null) { + $this->boundCounter++; + $placeHolder = ':dcValue' . $this->boundCounter; + } + + $this->setParameter(substr($placeHolder, 1), $value, $type); + + return $placeHolder; + } + + /** + * Creates a new positional parameter and bind the given value to it. + * + * Attention: If you are using positional parameters with the query builder you have + * to be very careful to bind all parameters in the order they appear in the SQL + * statement , otherwise they get bound in the wrong order which can lead to serious + * bugs in your code. + * + * Example: + * + * $qb = $conn->createQueryBuilder(); + * $qb->select('u.*') + * ->from('users', 'u') + * ->where('u.username = ' . $qb->createPositionalParameter('Foo', ParameterType::STRING)) + * ->orWhere('u.username = ' . $qb->createPositionalParameter('Bar', ParameterType::STRING)) + * + * + * @param mixed $value + * @param int|string|Type|null $type + * + * @return string + */ + public function createPositionalParameter($value, $type = ParameterType::STRING) + { + $this->boundCounter++; + $this->setParameter($this->boundCounter, $value, $type); + + return '?'; + } + + /** + * @param string $fromAlias + * @param array $knownAliases + * + * @return string + * + * @throws QueryException + */ + private function getSQLForJoins($fromAlias, array &$knownAliases) + { + $sql = ''; + + if (isset($this->sqlParts['join'][$fromAlias])) { + foreach ($this->sqlParts['join'][$fromAlias] as $join) { + if (array_key_exists($join['joinAlias'], $knownAliases)) { + throw QueryException::nonUniqueAlias($join['joinAlias'], array_keys($knownAliases)); + } + + $sql .= ' ' . strtoupper($join['joinType']) + . ' JOIN ' . $join['joinTable'] . ' ' . $join['joinAlias']; + if ($join['joinCondition'] !== null) { + $sql .= ' ON ' . $join['joinCondition']; + } + + $knownAliases[$join['joinAlias']] = true; + } + + foreach ($this->sqlParts['join'][$fromAlias] as $join) { + $sql .= $this->getSQLForJoins($join['joinAlias'], $knownAliases); + } + } + + return $sql; + } + + /** + * Deep clone of all expression objects in the SQL parts. + * + * @return void + */ + public function __clone() + { + foreach ($this->sqlParts as $part => $elements) { + if (is_array($this->sqlParts[$part])) { + foreach ($this->sqlParts[$part] as $idx => $element) { + if (! is_object($element)) { + continue; + } + + $this->sqlParts[$part][$idx] = clone $element; + } + } elseif (is_object($elements)) { + $this->sqlParts[$part] = clone $elements; + } + } + + foreach ($this->params as $name => $param) { + if (! is_object($param)) { + continue; + } + + $this->params[$name] = clone $param; + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryException.php new file mode 100755 index 0000000..58e941e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryException.php @@ -0,0 +1,39 @@ + + * + * @throws Exception + */ + public function fetchAllKeyValue(): array; + + /** + * Returns an associative array with the keys mapped to the first column and the values being + * an associative array representing the rest of the columns and their values. + * + * @return array> + * + * @throws Exception + */ + public function fetchAllAssociativeIndexed(): array; + + /** + * Returns an iterator over the result set with the values of the first column of the result + * + * @return Traversable + * + * @throws Exception + */ + public function iterateKeyValue(): Traversable; + + /** + * Returns an iterator over the result set with the keys mapped to the first column and the values being + * an associative array representing the rest of the columns and their values. + * + * @return Traversable> + * + * @throws Exception + */ + public function iterateAssociativeIndexed(): Traversable; +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtils.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtils.php new file mode 100755 index 0000000..e31f331 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtils.php @@ -0,0 +1,311 @@ + + */ + private static function getPositionalPlaceholderPositions(string $statement): array + { + return self::collectPlaceholders( + $statement, + '?', + self::POSITIONAL_TOKEN, + static function (string $_, int $placeholderPosition, int $fragmentPosition, array &$carry): void { + $carry[] = $placeholderPosition + $fragmentPosition; + } + ); + } + + /** + * Returns a map of placeholder positions to their parameter names. + * + * @return array + */ + private static function getNamedPlaceholderPositions(string $statement): array + { + return self::collectPlaceholders( + $statement, + ':', + self::NAMED_TOKEN, + static function ( + string $placeholder, + int $placeholderPosition, + int $fragmentPosition, + array &$carry + ): void { + $carry[$placeholderPosition + $fragmentPosition] = substr($placeholder, 1); + } + ); + } + + /** + * @return mixed[] + */ + private static function collectPlaceholders( + string $statement, + string $match, + string $token, + callable $collector + ): array { + if (strpos($statement, $match) === false) { + return []; + } + + $carry = []; + + foreach (self::getUnquotedStatementFragments($statement) as $fragment) { + preg_match_all('/' . $token . '/', $fragment[0], $matches, PREG_OFFSET_CAPTURE); + foreach ($matches[0] as $placeholder) { + $collector($placeholder[0], $placeholder[1], $fragment[1], $carry); + } + } + + return $carry; + } + + /** + * For a positional query this method can rewrite the sql statement with regard to array parameters. + * + * @param string $query SQL query + * @param mixed[] $params Query parameters + * @param array|array $types Parameter types + * + * @return mixed[] + * + * @throws SQLParserUtilsException + */ + public static function expandListParameters($query, $params, $types) + { + $isPositional = is_int(key($params)); + $arrayPositions = []; + $bindIndex = -1; + + if ($isPositional) { + // make sure that $types has the same keys as $params + // to allow omitting parameters with unspecified types + $types += array_fill_keys(array_keys($params), null); + + ksort($params); + ksort($types); + } + + foreach ($types as $name => $type) { + ++$bindIndex; + + if ($type !== Connection::PARAM_INT_ARRAY && $type !== Connection::PARAM_STR_ARRAY) { + continue; + } + + if ($isPositional) { + $name = $bindIndex; + } + + $arrayPositions[$name] = false; + } + + if (( ! $arrayPositions && $isPositional)) { + return [$query, $params, $types]; + } + + if ($isPositional) { + $paramOffset = 0; + $queryOffset = 0; + $params = array_values($params); + $types = array_values($types); + + $paramPos = self::getPositionalPlaceholderPositions($query); + + foreach ($paramPos as $needle => $needlePos) { + if (! isset($arrayPositions[$needle])) { + continue; + } + + $needle += $paramOffset; + $needlePos += $queryOffset; + $count = count($params[$needle]); + + $params = array_merge( + array_slice($params, 0, $needle), + $params[$needle], + array_slice($params, $needle + 1) + ); + + $types = array_merge( + array_slice($types, 0, $needle), + $count ? + // array needles are at {@link \Doctrine\DBAL\ParameterType} constants + // + {@link \Doctrine\DBAL\Connection::ARRAY_PARAM_OFFSET} + array_fill(0, $count, $types[$needle] - Connection::ARRAY_PARAM_OFFSET) : + [], + array_slice($types, $needle + 1) + ); + + $expandStr = $count ? implode(', ', array_fill(0, $count, '?')) : 'NULL'; + $query = substr($query, 0, $needlePos) . $expandStr . substr($query, $needlePos + 1); + + $paramOffset += $count - 1; // Grows larger by number of parameters minus the replaced needle. + $queryOffset += strlen($expandStr) - 1; + } + + return [$query, $params, $types]; + } + + $queryOffset = 0; + $typesOrd = []; + $paramsOrd = []; + + $paramPos = self::getNamedPlaceholderPositions($query); + + foreach ($paramPos as $pos => $paramName) { + $paramLen = strlen($paramName) + 1; + $value = self::extractParam($paramName, $params, true); + + if (! isset($arrayPositions[$paramName]) && ! isset($arrayPositions[':' . $paramName])) { + $pos += $queryOffset; + $queryOffset -= $paramLen - 1; + $paramsOrd[] = $value; + $typesOrd[] = self::extractParam($paramName, $types, false, ParameterType::STRING); + $query = substr($query, 0, $pos) . '?' . substr($query, $pos + $paramLen); + + continue; + } + + $count = count($value); + $expandStr = $count > 0 ? implode(', ', array_fill(0, $count, '?')) : 'NULL'; + + foreach ($value as $val) { + $paramsOrd[] = $val; + $typesOrd[] = self::extractParam($paramName, $types, false) - Connection::ARRAY_PARAM_OFFSET; + } + + $pos += $queryOffset; + $queryOffset += strlen($expandStr) - $paramLen; + $query = substr($query, 0, $pos) . $expandStr . substr($query, $pos + $paramLen); + } + + return [$query, $paramsOrd, $typesOrd]; + } + + /** + * Slice the SQL statement around pairs of quotes and + * return string fragments of SQL outside of quoted literals. + * Each fragment is captured as a 2-element array: + * + * 0 => matched fragment string, + * 1 => offset of fragment in $statement + * + * @param string $statement + * + * @return mixed[][] + */ + private static function getUnquotedStatementFragments($statement) + { + $literal = self::ESCAPED_SINGLE_QUOTED_TEXT . '|' . + self::ESCAPED_DOUBLE_QUOTED_TEXT . '|' . + self::ESCAPED_BACKTICK_QUOTED_TEXT . '|' . + self::ESCAPED_BRACKET_QUOTED_TEXT; + $expression = sprintf('/((.+(?i:ARRAY)\\[.+\\])|([^\'"`\\[]+))(?:%s)?/s', $literal); + + preg_match_all($expression, $statement, $fragments, PREG_OFFSET_CAPTURE); + + return $fragments[1]; + } + + /** + * @param string $paramName The name of the parameter (without a colon in front) + * @param mixed $paramsOrTypes A hash of parameters or types + * @param bool $isParam + * @param mixed $defaultValue An optional default value. If omitted, an exception is thrown + * + * @return mixed + * + * @throws SQLParserUtilsException + */ + private static function extractParam($paramName, $paramsOrTypes, $isParam, $defaultValue = null) + { + if (array_key_exists($paramName, $paramsOrTypes)) { + return $paramsOrTypes[$paramName]; + } + + // Hash keys can be prefixed with a colon for compatibility + if (array_key_exists(':' . $paramName, $paramsOrTypes)) { + return $paramsOrTypes[':' . $paramName]; + } + + if ($defaultValue !== null) { + return $defaultValue; + } + + if ($isParam) { + throw SQLParserUtilsException::missingParam($paramName); + } + + throw SQLParserUtilsException::missingType($paramName); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtilsException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtilsException.php new file mode 100755 index 0000000..297b076 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtilsException.php @@ -0,0 +1,37 @@ + Table($tableName)); if you want to rename the table, you have to make sure + */ +abstract class AbstractAsset +{ + /** @var string */ + protected $_name = ''; + + /** + * Namespace of the asset. If none isset the default namespace is assumed. + * + * @var string|null + */ + protected $_namespace; + + /** @var bool */ + protected $_quoted = false; + + /** + * Sets the name of this asset. + * + * @param string $name + * + * @return void + */ + protected function _setName($name) + { + if ($this->isIdentifierQuoted($name)) { + $this->_quoted = true; + $name = $this->trimQuotes($name); + } + + if (strpos($name, '.') !== false) { + $parts = explode('.', $name); + $this->_namespace = $parts[0]; + $name = $parts[1]; + } + + $this->_name = $name; + } + + /** + * Is this asset in the default namespace? + * + * @param string $defaultNamespaceName + * + * @return bool + */ + public function isInDefaultNamespace($defaultNamespaceName) + { + return $this->_namespace === $defaultNamespaceName || $this->_namespace === null; + } + + /** + * Gets the namespace name of this asset. + * + * If NULL is returned this means the default namespace is used. + * + * @return string|null + */ + public function getNamespaceName() + { + return $this->_namespace; + } + + /** + * The shortest name is stripped of the default namespace. All other + * namespaced elements are returned as full-qualified names. + * + * @param string|null $defaultNamespaceName + * + * @return string + */ + public function getShortestName($defaultNamespaceName) + { + $shortestName = $this->getName(); + if ($this->_namespace === $defaultNamespaceName) { + $shortestName = $this->_name; + } + + return strtolower($shortestName); + } + + /** + * The normalized name is full-qualified and lower-cased. Lower-casing is + * actually wrong, but we have to do it to keep our sanity. If you are + * using database objects that only differentiate in the casing (FOO vs + * Foo) then you will NOT be able to use Doctrine Schema abstraction. + * + * Every non-namespaced element is prefixed with the default namespace + * name which is passed as argument to this method. + * + * @param string $defaultNamespaceName + * + * @return string + */ + public function getFullQualifiedName($defaultNamespaceName) + { + $name = $this->getName(); + if (! $this->_namespace) { + $name = $defaultNamespaceName . '.' . $name; + } + + return strtolower($name); + } + + /** + * Checks if this asset's name is quoted. + * + * @return bool + */ + public function isQuoted() + { + return $this->_quoted; + } + + /** + * Checks if this identifier is quoted. + * + * @param string $identifier + * + * @return bool + */ + protected function isIdentifierQuoted($identifier) + { + return isset($identifier[0]) && ($identifier[0] === '`' || $identifier[0] === '"' || $identifier[0] === '['); + } + + /** + * Trim quotes from the identifier. + * + * @param string $identifier + * + * @return string + */ + protected function trimQuotes($identifier) + { + return str_replace(['`', '"', '[', ']'], '', $identifier); + } + + /** + * Returns the name of this schema asset. + * + * @return string + */ + public function getName() + { + if ($this->_namespace) { + return $this->_namespace . '.' . $this->_name; + } + + return $this->_name; + } + + /** + * Gets the quoted representation of this asset but only if it was defined with one. Otherwise + * return the plain unquoted value as inserted. + * + * @return string + */ + public function getQuotedName(AbstractPlatform $platform) + { + $keywords = $platform->getReservedKeywordsList(); + $parts = explode('.', $this->getName()); + foreach ($parts as $k => $v) { + $parts[$k] = $this->_quoted || $keywords->isKeyword($v) ? $platform->quoteIdentifier($v) : $v; + } + + return implode('.', $parts); + } + + /** + * Generates an identifier from a list of column names obeying a certain string length. + * + * This is especially important for Oracle, since it does not allow identifiers larger than 30 chars, + * however building idents automatically for foreign keys, composite keys or such can easily create + * very long names. + * + * @param string[] $columnNames + * @param string $prefix + * @param int $maxSize + * + * @return string + */ + protected function _generateIdentifierName($columnNames, $prefix = '', $maxSize = 30) + { + $hash = implode('', array_map(static function ($column) { + return dechex(crc32($column)); + }, $columnNames)); + + return strtoupper(substr($prefix . '_' . $hash, 0, $maxSize)); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php new file mode 100755 index 0000000..2cad11a --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -0,0 +1,1155 @@ +_conn = $conn; + $this->_platform = $platform ?: $this->_conn->getDatabasePlatform(); + } + + /** + * Returns the associated platform. + * + * @return AbstractPlatform + */ + public function getDatabasePlatform() + { + return $this->_platform; + } + + /** + * Tries any method on the schema manager. Normally a method throws an + * exception when your DBMS doesn't support it or if an error occurs. + * This method allows you to try and method on your SchemaManager + * instance and will return false if it does not work or is not supported. + * + * + * $result = $sm->tryMethod('dropView', 'view_name'); + * + * + * @return mixed + */ + public function tryMethod() + { + $args = func_get_args(); + $method = $args[0]; + unset($args[0]); + $args = array_values($args); + + $callback = [$this, $method]; + assert(is_callable($callback)); + + try { + return call_user_func_array($callback, $args); + } catch (Throwable $e) { + return false; + } + } + + /** + * Lists the available databases for this connection. + * + * @return string[] + */ + public function listDatabases() + { + $sql = $this->_platform->getListDatabasesSQL(); + + $databases = $this->_conn->fetchAllAssociative($sql); + + return $this->_getPortableDatabasesList($databases); + } + + /** + * Returns a list of all namespaces in the current database. + * + * @return string[] + */ + public function listNamespaceNames() + { + $sql = $this->_platform->getListNamespacesSQL(); + + $namespaces = $this->_conn->fetchAllAssociative($sql); + + return $this->getPortableNamespacesList($namespaces); + } + + /** + * Lists the available sequences for this connection. + * + * @param string|null $database + * + * @return Sequence[] + */ + public function listSequences($database = null) + { + if ($database === null) { + $database = $this->_conn->getDatabase(); + } + + $sql = $this->_platform->getListSequencesSQL($database); + + $sequences = $this->_conn->fetchAllAssociative($sql); + + return $this->filterAssetNames($this->_getPortableSequencesList($sequences)); + } + + /** + * Lists the columns for a given table. + * + * In contrast to other libraries and to the old version of Doctrine, + * this column definition does try to contain the 'primary' column for + * the reason that it is not portable across different RDBMS. Use + * {@see listTableIndexes($tableName)} to retrieve the primary key + * of a table. Where a RDBMS specifies more details, these are held + * in the platformDetails array. + * + * @param string $table The name of the table. + * @param string|null $database + * + * @return Column[] + */ + public function listTableColumns($table, $database = null) + { + if (! $database) { + $database = $this->_conn->getDatabase(); + } + + $sql = $this->_platform->getListTableColumnsSQL($table, $database); + + $tableColumns = $this->_conn->fetchAllAssociative($sql); + + return $this->_getPortableTableColumnList($table, $database, $tableColumns); + } + + /** + * Lists the indexes for a given table returning an array of Index instances. + * + * Keys of the portable indexes list are all lower-cased. + * + * @param string $table The name of the table. + * + * @return Index[] + */ + public function listTableIndexes($table) + { + $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase()); + + $tableIndexes = $this->_conn->fetchAllAssociative($sql); + + return $this->_getPortableTableIndexesList($tableIndexes, $table); + } + + /** + * Returns true if all the given tables exist. + * + * The usage of a string $tableNames is deprecated. Pass a one-element array instead. + * + * @param string|string[] $names + * + * @return bool + */ + public function tablesExist($names) + { + if (is_string($names)) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/3580', + 'The usage of a string $tableNames in AbstractSchemaManager::tablesExist is deprecated. ' . + 'Pass a one-element array instead.' + ); + } + + $names = array_map('strtolower', (array) $names); + + return count($names) === count(array_intersect($names, array_map('strtolower', $this->listTableNames()))); + } + + /** + * Returns a list of all tables in the current database. + * + * @return string[] + */ + public function listTableNames() + { + $sql = $this->_platform->getListTablesSQL(); + + $tables = $this->_conn->fetchAllAssociative($sql); + $tableNames = $this->_getPortableTablesList($tables); + + return $this->filterAssetNames($tableNames); + } + + /** + * Filters asset names if they are configured to return only a subset of all + * the found elements. + * + * @param mixed[] $assetNames + * + * @return mixed[] + */ + protected function filterAssetNames($assetNames) + { + $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter(); + if (! $filter) { + return $assetNames; + } + + return array_values(array_filter($assetNames, $filter)); + } + + /** + * @deprecated Use Configuration::getSchemaAssetsFilter() instead + * + * @return string|null + */ + protected function getFilterSchemaAssetsExpression() + { + return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression(); + } + + /** + * Lists the tables for this connection. + * + * @return Table[] + */ + public function listTables() + { + $tableNames = $this->listTableNames(); + + $tables = []; + foreach ($tableNames as $tableName) { + $tables[] = $this->listTableDetails($tableName); + } + + return $tables; + } + + /** + * @param string $name + * + * @return Table + */ + public function listTableDetails($name) + { + $columns = $this->listTableColumns($name); + $foreignKeys = []; + if ($this->_platform->supportsForeignKeyConstraints()) { + $foreignKeys = $this->listTableForeignKeys($name); + } + + $indexes = $this->listTableIndexes($name); + + return new Table($name, $columns, $indexes, $foreignKeys); + } + + /** + * Lists the views this connection has. + * + * @return View[] + */ + public function listViews() + { + $database = $this->_conn->getDatabase(); + $sql = $this->_platform->getListViewsSQL($database); + $views = $this->_conn->fetchAllAssociative($sql); + + return $this->_getPortableViewsList($views); + } + + /** + * Lists the foreign keys for the given table. + * + * @param string $table The name of the table. + * @param string|null $database + * + * @return ForeignKeyConstraint[] + */ + public function listTableForeignKeys($table, $database = null) + { + if ($database === null) { + $database = $this->_conn->getDatabase(); + } + + $sql = $this->_platform->getListTableForeignKeysSQL($table, $database); + $tableForeignKeys = $this->_conn->fetchAllAssociative($sql); + + return $this->_getPortableTableForeignKeysList($tableForeignKeys); + } + + /* drop*() Methods */ + + /** + * Drops a database. + * + * NOTE: You can not drop the database this SchemaManager is currently connected to. + * + * @param string $database The name of the database to drop. + * + * @return void + */ + public function dropDatabase($database) + { + $this->_execSql($this->_platform->getDropDatabaseSQL($database)); + } + + /** + * Drops the given table. + * + * @param string $name The name of the table to drop. + * + * @return void + */ + public function dropTable($name) + { + $this->_execSql($this->_platform->getDropTableSQL($name)); + } + + /** + * Drops the index from the given table. + * + * @param Index|string $index The name of the index. + * @param Table|string $table The name of the table. + * + * @return void + */ + public function dropIndex($index, $table) + { + if ($index instanceof Index) { + $index = $index->getQuotedName($this->_platform); + } + + $this->_execSql($this->_platform->getDropIndexSQL($index, $table)); + } + + /** + * Drops the constraint from the given table. + * + * @param Table|string $table The name of the table. + * + * @return void + */ + public function dropConstraint(Constraint $constraint, $table) + { + $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table)); + } + + /** + * Drops a foreign key from a table. + * + * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key. + * @param Table|string $table The name of the table with the foreign key. + * + * @return void + */ + public function dropForeignKey($foreignKey, $table) + { + $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table)); + } + + /** + * Drops a sequence with a given name. + * + * @param string $name The name of the sequence to drop. + * + * @return void + */ + public function dropSequence($name) + { + $this->_execSql($this->_platform->getDropSequenceSQL($name)); + } + + /** + * Drops a view. + * + * @param string $name The name of the view. + * + * @return void + */ + public function dropView($name) + { + $this->_execSql($this->_platform->getDropViewSQL($name)); + } + + /* create*() Methods */ + + /** + * Creates a new database. + * + * @param string $database The name of the database to create. + * + * @return void + */ + public function createDatabase($database) + { + $this->_execSql($this->_platform->getCreateDatabaseSQL($database)); + } + + /** + * Creates a new table. + * + * @return void + */ + public function createTable(Table $table) + { + $createFlags = AbstractPlatform::CREATE_INDEXES | AbstractPlatform::CREATE_FOREIGNKEYS; + $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags)); + } + + /** + * Creates a new sequence. + * + * @param Sequence $sequence + * + * @return void + * + * @throws ConnectionException If something fails at database level. + */ + public function createSequence($sequence) + { + $this->_execSql($this->_platform->getCreateSequenceSQL($sequence)); + } + + /** + * Creates a constraint on a table. + * + * @param Table|string $table + * + * @return void + */ + public function createConstraint(Constraint $constraint, $table) + { + $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table)); + } + + /** + * Creates a new index on a table. + * + * @param Table|string $table The name of the table on which the index is to be created. + * + * @return void + */ + public function createIndex(Index $index, $table) + { + $this->_execSql($this->_platform->getCreateIndexSQL($index, $table)); + } + + /** + * Creates a new foreign key. + * + * @param ForeignKeyConstraint $foreignKey The ForeignKey instance. + * @param Table|string $table The name of the table on which the foreign key is to be created. + * + * @return void + */ + public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) + { + $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table)); + } + + /** + * Creates a new view. + * + * @return void + */ + public function createView(View $view) + { + $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql())); + } + + /* dropAndCreate*() Methods */ + + /** + * Drops and creates a constraint. + * + * @see dropConstraint() + * @see createConstraint() + * + * @param Table|string $table + * + * @return void + */ + public function dropAndCreateConstraint(Constraint $constraint, $table) + { + $this->tryMethod('dropConstraint', $constraint, $table); + $this->createConstraint($constraint, $table); + } + + /** + * Drops and creates a new index on a table. + * + * @param Table|string $table The name of the table on which the index is to be created. + * + * @return void + */ + public function dropAndCreateIndex(Index $index, $table) + { + $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table); + $this->createIndex($index, $table); + } + + /** + * Drops and creates a new foreign key. + * + * @param ForeignKeyConstraint $foreignKey An associative array that defines properties + * of the foreign key to be created. + * @param Table|string $table The name of the table on which the foreign key is to be created. + * + * @return void + */ + public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) + { + $this->tryMethod('dropForeignKey', $foreignKey, $table); + $this->createForeignKey($foreignKey, $table); + } + + /** + * Drops and create a new sequence. + * + * @return void + * + * @throws ConnectionException If something fails at database level. + */ + public function dropAndCreateSequence(Sequence $sequence) + { + $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform)); + $this->createSequence($sequence); + } + + /** + * Drops and creates a new table. + * + * @return void + */ + public function dropAndCreateTable(Table $table) + { + $this->tryMethod('dropTable', $table->getQuotedName($this->_platform)); + $this->createTable($table); + } + + /** + * Drops and creates a new database. + * + * @param string $database The name of the database to create. + * + * @return void + */ + public function dropAndCreateDatabase($database) + { + $this->tryMethod('dropDatabase', $database); + $this->createDatabase($database); + } + + /** + * Drops and creates a new view. + * + * @return void + */ + public function dropAndCreateView(View $view) + { + $this->tryMethod('dropView', $view->getQuotedName($this->_platform)); + $this->createView($view); + } + + /* alterTable() Methods */ + + /** + * Alters an existing tables schema. + * + * @return void + */ + public function alterTable(TableDiff $tableDiff) + { + foreach ($this->_platform->getAlterTableSQL($tableDiff) as $ddlQuery) { + $this->_execSql($ddlQuery); + } + } + + /** + * Renames a given table to another name. + * + * @param string $name The current name of the table. + * @param string $newName The new name of the table. + * + * @return void + */ + public function renameTable($name, $newName) + { + $tableDiff = new TableDiff($name); + $tableDiff->newName = $newName; + $this->alterTable($tableDiff); + } + + /** + * Methods for filtering return values of list*() methods to convert + * the native DBMS data definition to a portable Doctrine definition + */ + + /** + * @param mixed[] $databases + * + * @return string[] + */ + protected function _getPortableDatabasesList($databases) + { + $list = []; + foreach ($databases as $value) { + $value = $this->_getPortableDatabaseDefinition($value); + + if (! $value) { + continue; + } + + $list[] = $value; + } + + return $list; + } + + /** + * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition. + * + * @param mixed[][] $namespaces The list of namespace names in the native DBMS data definition. + * + * @return string[] + */ + protected function getPortableNamespacesList(array $namespaces) + { + $namespacesList = []; + + foreach ($namespaces as $namespace) { + $namespacesList[] = $this->getPortableNamespaceDefinition($namespace); + } + + return $namespacesList; + } + + /** + * @param mixed $database + * + * @return mixed + */ + protected function _getPortableDatabaseDefinition($database) + { + return $database; + } + + /** + * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition. + * + * @param mixed[] $namespace The native DBMS namespace definition. + * + * @return mixed + */ + protected function getPortableNamespaceDefinition(array $namespace) + { + return $namespace; + } + + /** + * @deprecated + * + * @param mixed[][] $functions + * + * @return mixed[][] + */ + protected function _getPortableFunctionsList($functions) + { + $list = []; + foreach ($functions as $value) { + $value = $this->_getPortableFunctionDefinition($value); + + if (! $value) { + continue; + } + + $list[] = $value; + } + + return $list; + } + + /** + * @deprecated + * + * @param mixed[] $function + * + * @return mixed + */ + protected function _getPortableFunctionDefinition($function) + { + return $function; + } + + /** + * @param mixed[][] $triggers + * + * @return mixed[][] + */ + protected function _getPortableTriggersList($triggers) + { + $list = []; + foreach ($triggers as $value) { + $value = $this->_getPortableTriggerDefinition($value); + + if (! $value) { + continue; + } + + $list[] = $value; + } + + return $list; + } + + /** + * @param mixed[] $trigger + * + * @return mixed + */ + protected function _getPortableTriggerDefinition($trigger) + { + return $trigger; + } + + /** + * @param mixed[][] $sequences + * + * @return Sequence[] + */ + protected function _getPortableSequencesList($sequences) + { + $list = []; + + foreach ($sequences as $value) { + $list[] = $this->_getPortableSequenceDefinition($value); + } + + return $list; + } + + /** + * @param mixed[] $sequence + * + * @return Sequence + * + * @throws Exception + */ + protected function _getPortableSequenceDefinition($sequence) + { + throw Exception::notSupported('Sequences'); + } + + /** + * Independent of the database the keys of the column list result are lowercased. + * + * The name of the created column instance however is kept in its case. + * + * @param string $table The name of the table. + * @param string $database + * @param mixed[][] $tableColumns + * + * @return Column[] + */ + protected function _getPortableTableColumnList($table, $database, $tableColumns) + { + $eventManager = $this->_platform->getEventManager(); + + $list = []; + foreach ($tableColumns as $tableColumn) { + $column = null; + $defaultPrevented = false; + + if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) { + $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn); + $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs); + + $defaultPrevented = $eventArgs->isDefaultPrevented(); + $column = $eventArgs->getColumn(); + } + + if (! $defaultPrevented) { + $column = $this->_getPortableTableColumnDefinition($tableColumn); + } + + if (! $column) { + continue; + } + + $name = strtolower($column->getQuotedName($this->_platform)); + $list[$name] = $column; + } + + return $list; + } + + /** + * Gets Table Column Definition. + * + * @param mixed[] $tableColumn + * + * @return Column + */ + abstract protected function _getPortableTableColumnDefinition($tableColumn); + + /** + * Aggregates and groups the index results according to the required data result. + * + * @param mixed[][] $tableIndexes + * @param string|null $tableName + * + * @return Index[] + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + { + $result = []; + foreach ($tableIndexes as $tableIndex) { + $indexName = $keyName = $tableIndex['key_name']; + if ($tableIndex['primary']) { + $keyName = 'primary'; + } + + $keyName = strtolower($keyName); + + if (! isset($result[$keyName])) { + $options = [ + 'lengths' => [], + ]; + + if (isset($tableIndex['where'])) { + $options['where'] = $tableIndex['where']; + } + + $result[$keyName] = [ + 'name' => $indexName, + 'columns' => [], + 'unique' => ! $tableIndex['non_unique'], + 'primary' => $tableIndex['primary'], + 'flags' => $tableIndex['flags'] ?? [], + 'options' => $options, + ]; + } + + $result[$keyName]['columns'][] = $tableIndex['column_name']; + $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null; + } + + $eventManager = $this->_platform->getEventManager(); + + $indexes = []; + foreach ($result as $indexKey => $data) { + $index = null; + $defaultPrevented = false; + + if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) { + $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn); + $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs); + + $defaultPrevented = $eventArgs->isDefaultPrevented(); + $index = $eventArgs->getIndex(); + } + + if (! $defaultPrevented) { + $index = new Index( + $data['name'], + $data['columns'], + $data['unique'], + $data['primary'], + $data['flags'], + $data['options'] + ); + } + + if (! $index) { + continue; + } + + $indexes[$indexKey] = $index; + } + + return $indexes; + } + + /** + * @param mixed[][] $tables + * + * @return string[] + */ + protected function _getPortableTablesList($tables) + { + $list = []; + foreach ($tables as $value) { + $value = $this->_getPortableTableDefinition($value); + + if (! $value) { + continue; + } + + $list[] = $value; + } + + return $list; + } + + /** + * @param mixed $table + * + * @return string + */ + protected function _getPortableTableDefinition($table) + { + return $table; + } + + /** + * @param mixed[][] $users + * + * @return string[][] + */ + protected function _getPortableUsersList($users) + { + $list = []; + foreach ($users as $value) { + $value = $this->_getPortableUserDefinition($value); + + if (! $value) { + continue; + } + + $list[] = $value; + } + + return $list; + } + + /** + * @param string[] $user + * + * @return string[] + */ + protected function _getPortableUserDefinition($user) + { + return $user; + } + + /** + * @param mixed[][] $views + * + * @return View[] + */ + protected function _getPortableViewsList($views) + { + $list = []; + foreach ($views as $value) { + $view = $this->_getPortableViewDefinition($value); + + if (! $view) { + continue; + } + + $viewName = strtolower($view->getQuotedName($this->_platform)); + $list[$viewName] = $view; + } + + return $list; + } + + /** + * @param mixed[] $view + * + * @return View|false + */ + protected function _getPortableViewDefinition($view) + { + return false; + } + + /** + * @param mixed[][] $tableForeignKeys + * + * @return ForeignKeyConstraint[] + */ + protected function _getPortableTableForeignKeysList($tableForeignKeys) + { + $list = []; + + foreach ($tableForeignKeys as $value) { + $list[] = $this->_getPortableTableForeignKeyDefinition($value); + } + + return $list; + } + + /** + * @param mixed $tableForeignKey + * + * @return ForeignKeyConstraint + */ + protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + { + return $tableForeignKey; + } + + /** + * @param string[]|string $sql + * + * @return void + */ + protected function _execSql($sql) + { + foreach ((array) $sql as $query) { + $this->_conn->executeStatement($query); + } + } + + /** + * Creates a schema instance for the current database. + * + * @return Schema + */ + public function createSchema() + { + $namespaces = []; + + if ($this->_platform->supportsSchemas()) { + $namespaces = $this->listNamespaceNames(); + } + + $sequences = []; + + if ($this->_platform->supportsSequences()) { + $sequences = $this->listSequences(); + } + + $tables = $this->listTables(); + + return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces); + } + + /** + * Creates the configuration for this schema. + * + * @return SchemaConfig + */ + public function createSchemaConfig() + { + $schemaConfig = new SchemaConfig(); + $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength()); + + $searchPaths = $this->getSchemaSearchPaths(); + if (isset($searchPaths[0])) { + $schemaConfig->setName($searchPaths[0]); + } + + $params = $this->_conn->getParams(); + if (! isset($params['defaultTableOptions'])) { + $params['defaultTableOptions'] = []; + } + + if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) { + $params['defaultTableOptions']['charset'] = $params['charset']; + } + + $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']); + + return $schemaConfig; + } + + /** + * The search path for namespaces in the currently connected database. + * + * The first entry is usually the default namespace in the Schema. All + * further namespaces contain tables/sequences which can also be addressed + * with a short, not full-qualified name. + * + * For databases that don't support subschema/namespaces this method + * returns the name of the currently connected database. + * + * @return string[] + */ + public function getSchemaSearchPaths() + { + return [$this->_conn->getDatabase()]; + } + + /** + * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns + * the type given as default. + * + * @param string|null $comment + * @param string $currentType + * + * @return string + */ + public function extractDoctrineTypeFromComment($comment, $currentType) + { + if ($comment !== null && preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match)) { + return $match[1]; + } + + return $currentType; + } + + /** + * @param string|null $comment + * @param string|null $type + * + * @return string|null + */ + public function removeDoctrineTypeFromComment($comment, $type) + { + if ($comment === null) { + return null; + } + + return str_replace('(DC2Type:' . $type . ')', '', $comment); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Column.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Column.php new file mode 100755 index 0000000..b2392d4 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Column.php @@ -0,0 +1,453 @@ +_setName($name); + $this->setType($type); + $this->setOptions($options); + } + + /** + * @param mixed[] $options + * + * @return Column + */ + public function setOptions(array $options) + { + foreach ($options as $name => $value) { + $method = 'set' . $name; + if (! method_exists($this, $method)) { + // next major: throw an exception + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/2846', + 'The "%s" column option is not supported,' . + ' setting unknown options is deprecated and will cause an error in Doctrine DBAL 3.0', + $name + ); + + continue; + } + + $this->$method($value); + } + + return $this; + } + + /** + * @return Column + */ + public function setType(Type $type) + { + $this->_type = $type; + + return $this; + } + + /** + * @param int|null $length + * + * @return Column + */ + public function setLength($length) + { + if ($length !== null) { + $this->_length = (int) $length; + } else { + $this->_length = null; + } + + return $this; + } + + /** + * @param int $precision + * + * @return Column + */ + public function setPrecision($precision) + { + if (! is_numeric($precision)) { + $precision = 10; // defaults to 10 when no valid precision is given. + } + + $this->_precision = (int) $precision; + + return $this; + } + + /** + * @param int $scale + * + * @return Column + */ + public function setScale($scale) + { + if (! is_numeric($scale)) { + $scale = 0; + } + + $this->_scale = (int) $scale; + + return $this; + } + + /** + * @param bool $unsigned + * + * @return Column + */ + public function setUnsigned($unsigned) + { + $this->_unsigned = (bool) $unsigned; + + return $this; + } + + /** + * @param bool $fixed + * + * @return Column + */ + public function setFixed($fixed) + { + $this->_fixed = (bool) $fixed; + + return $this; + } + + /** + * @param bool $notnull + * + * @return Column + */ + public function setNotnull($notnull) + { + $this->_notnull = (bool) $notnull; + + return $this; + } + + /** + * @param mixed $default + * + * @return Column + */ + public function setDefault($default) + { + $this->_default = $default; + + return $this; + } + + /** + * @param mixed[] $platformOptions + * + * @return Column + */ + public function setPlatformOptions(array $platformOptions) + { + $this->_platformOptions = $platformOptions; + + return $this; + } + + /** + * @param string $name + * @param mixed $value + * + * @return Column + */ + public function setPlatformOption($name, $value) + { + $this->_platformOptions[$name] = $value; + + return $this; + } + + /** + * @param string $value + * + * @return Column + */ + public function setColumnDefinition($value) + { + $this->_columnDefinition = $value; + + return $this; + } + + /** + * @return Type + */ + public function getType() + { + return $this->_type; + } + + /** + * @return int|null + */ + public function getLength() + { + return $this->_length; + } + + /** + * @return int + */ + public function getPrecision() + { + return $this->_precision; + } + + /** + * @return int + */ + public function getScale() + { + return $this->_scale; + } + + /** + * @return bool + */ + public function getUnsigned() + { + return $this->_unsigned; + } + + /** + * @return bool + */ + public function getFixed() + { + return $this->_fixed; + } + + /** + * @return bool + */ + public function getNotnull() + { + return $this->_notnull; + } + + /** + * @return string|null + */ + public function getDefault() + { + return $this->_default; + } + + /** + * @return mixed[] + */ + public function getPlatformOptions() + { + return $this->_platformOptions; + } + + /** + * @param string $name + * + * @return bool + */ + public function hasPlatformOption($name) + { + return isset($this->_platformOptions[$name]); + } + + /** + * @param string $name + * + * @return mixed + */ + public function getPlatformOption($name) + { + return $this->_platformOptions[$name]; + } + + /** + * @return string|null + */ + public function getColumnDefinition() + { + return $this->_columnDefinition; + } + + /** + * @return bool + */ + public function getAutoincrement() + { + return $this->_autoincrement; + } + + /** + * @param bool $flag + * + * @return Column + */ + public function setAutoincrement($flag) + { + $this->_autoincrement = $flag; + + return $this; + } + + /** + * @param string|null $comment + * + * @return Column + */ + public function setComment($comment) + { + $this->_comment = $comment; + + return $this; + } + + /** + * @return string|null + */ + public function getComment() + { + return $this->_comment; + } + + /** + * @param string $name + * @param mixed $value + * + * @return Column + */ + public function setCustomSchemaOption($name, $value) + { + $this->_customSchemaOptions[$name] = $value; + + return $this; + } + + /** + * @param string $name + * + * @return bool + */ + public function hasCustomSchemaOption($name) + { + return isset($this->_customSchemaOptions[$name]); + } + + /** + * @param string $name + * + * @return mixed + */ + public function getCustomSchemaOption($name) + { + return $this->_customSchemaOptions[$name]; + } + + /** + * @param mixed[] $customSchemaOptions + * + * @return Column + */ + public function setCustomSchemaOptions(array $customSchemaOptions) + { + $this->_customSchemaOptions = $customSchemaOptions; + + return $this; + } + + /** + * @return mixed[] + */ + public function getCustomSchemaOptions() + { + return $this->_customSchemaOptions; + } + + /** + * @return mixed[] + */ + public function toArray() + { + return array_merge([ + 'name' => $this->_name, + 'type' => $this->_type, + 'default' => $this->_default, + 'notnull' => $this->_notnull, + 'length' => $this->_length, + 'precision' => $this->_precision, + 'scale' => $this->_scale, + 'fixed' => $this->_fixed, + 'unsigned' => $this->_unsigned, + 'autoincrement' => $this->_autoincrement, + 'columnDefinition' => $this->_columnDefinition, + 'comment' => $this->_comment, + ], $this->_platformOptions, $this->_customSchemaOptions); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ColumnDiff.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ColumnDiff.php new file mode 100755 index 0000000..2f6ae65 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ColumnDiff.php @@ -0,0 +1,59 @@ +oldColumnName = $oldColumnName; + $this->column = $column; + $this->changedProperties = $changedProperties; + $this->fromColumn = $fromColumn; + } + + /** + * @param string $propertyName + * + * @return bool + */ + public function hasChanged($propertyName) + { + return in_array($propertyName, $this->changedProperties); + } + + /** + * @return Identifier + */ + public function getOldColumnName() + { + $quote = $this->fromColumn && $this->fromColumn->isQuoted(); + + return new Identifier($this->oldColumnName, $quote); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Comparator.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Comparator.php new file mode 100755 index 0000000..7e24b3e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Comparator.php @@ -0,0 +1,556 @@ +compare($fromSchema, $toSchema); + } + + /** + * Returns a SchemaDiff object containing the differences between the schemas $fromSchema and $toSchema. + * + * The returned differences are returned in such a way that they contain the + * operations to change the schema stored in $fromSchema to the schema that is + * stored in $toSchema. + * + * @return SchemaDiff + */ + public function compare(Schema $fromSchema, Schema $toSchema) + { + $diff = new SchemaDiff(); + $diff->fromSchema = $fromSchema; + + $foreignKeysToTable = []; + + foreach ($toSchema->getNamespaces() as $namespace) { + if ($fromSchema->hasNamespace($namespace)) { + continue; + } + + $diff->newNamespaces[$namespace] = $namespace; + } + + foreach ($fromSchema->getNamespaces() as $namespace) { + if ($toSchema->hasNamespace($namespace)) { + continue; + } + + $diff->removedNamespaces[$namespace] = $namespace; + } + + foreach ($toSchema->getTables() as $table) { + $tableName = $table->getShortestName($toSchema->getName()); + if (! $fromSchema->hasTable($tableName)) { + $diff->newTables[$tableName] = $toSchema->getTable($tableName); + } else { + $tableDifferences = $this->diffTable( + $fromSchema->getTable($tableName), + $toSchema->getTable($tableName) + ); + + if ($tableDifferences !== false) { + $diff->changedTables[$tableName] = $tableDifferences; + } + } + } + + /* Check if there are tables removed */ + foreach ($fromSchema->getTables() as $table) { + $tableName = $table->getShortestName($fromSchema->getName()); + + $table = $fromSchema->getTable($tableName); + if (! $toSchema->hasTable($tableName)) { + $diff->removedTables[$tableName] = $table; + } + + // also remember all foreign keys that point to a specific table + foreach ($table->getForeignKeys() as $foreignKey) { + $foreignTable = strtolower($foreignKey->getForeignTableName()); + if (! isset($foreignKeysToTable[$foreignTable])) { + $foreignKeysToTable[$foreignTable] = []; + } + + $foreignKeysToTable[$foreignTable][] = $foreignKey; + } + } + + foreach ($diff->removedTables as $tableName => $table) { + if (! isset($foreignKeysToTable[$tableName])) { + continue; + } + + $diff->orphanedForeignKeys = array_merge($diff->orphanedForeignKeys, $foreignKeysToTable[$tableName]); + + // deleting duplicated foreign keys present on both on the orphanedForeignKey + // and the removedForeignKeys from changedTables + foreach ($foreignKeysToTable[$tableName] as $foreignKey) { + // strtolower the table name to make if compatible with getShortestName + $localTableName = strtolower($foreignKey->getLocalTableName()); + if (! isset($diff->changedTables[$localTableName])) { + continue; + } + + foreach ($diff->changedTables[$localTableName]->removedForeignKeys as $key => $removedForeignKey) { + assert($removedForeignKey instanceof ForeignKeyConstraint); + + // We check if the key is from the removed table if not we skip. + if ($tableName !== strtolower($removedForeignKey->getForeignTableName())) { + continue; + } + + unset($diff->changedTables[$localTableName]->removedForeignKeys[$key]); + } + } + } + + foreach ($toSchema->getSequences() as $sequence) { + $sequenceName = $sequence->getShortestName($toSchema->getName()); + if (! $fromSchema->hasSequence($sequenceName)) { + if (! $this->isAutoIncrementSequenceInSchema($fromSchema, $sequence)) { + $diff->newSequences[] = $sequence; + } + } else { + if ($this->diffSequence($sequence, $fromSchema->getSequence($sequenceName))) { + $diff->changedSequences[] = $toSchema->getSequence($sequenceName); + } + } + } + + foreach ($fromSchema->getSequences() as $sequence) { + if ($this->isAutoIncrementSequenceInSchema($toSchema, $sequence)) { + continue; + } + + $sequenceName = $sequence->getShortestName($fromSchema->getName()); + + if ($toSchema->hasSequence($sequenceName)) { + continue; + } + + $diff->removedSequences[] = $sequence; + } + + return $diff; + } + + /** + * @param Schema $schema + * @param Sequence $sequence + * + * @return bool + */ + private function isAutoIncrementSequenceInSchema($schema, $sequence) + { + foreach ($schema->getTables() as $table) { + if ($sequence->isAutoIncrementsFor($table)) { + return true; + } + } + + return false; + } + + /** + * @return bool + */ + public function diffSequence(Sequence $sequence1, Sequence $sequence2) + { + if ($sequence1->getAllocationSize() !== $sequence2->getAllocationSize()) { + return true; + } + + return $sequence1->getInitialValue() !== $sequence2->getInitialValue(); + } + + /** + * Returns the difference between the tables $fromTable and $toTable. + * + * If there are no differences this method returns the boolean false. + * + * @return TableDiff|false + */ + public function diffTable(Table $fromTable, Table $toTable) + { + $changes = 0; + $tableDifferences = new TableDiff($fromTable->getName()); + $tableDifferences->fromTable = $fromTable; + + $fromTableColumns = $fromTable->getColumns(); + $toTableColumns = $toTable->getColumns(); + + /* See if all the columns in "from" table exist in "to" table */ + foreach ($toTableColumns as $columnName => $column) { + if ($fromTable->hasColumn($columnName)) { + continue; + } + + $tableDifferences->addedColumns[$columnName] = $column; + $changes++; + } + + /* See if there are any removed columns in "to" table */ + foreach ($fromTableColumns as $columnName => $column) { + // See if column is removed in "to" table. + if (! $toTable->hasColumn($columnName)) { + $tableDifferences->removedColumns[$columnName] = $column; + $changes++; + continue; + } + + // See if column has changed properties in "to" table. + $changedProperties = $this->diffColumn($column, $toTable->getColumn($columnName)); + + if (empty($changedProperties)) { + continue; + } + + $columnDiff = new ColumnDiff($column->getName(), $toTable->getColumn($columnName), $changedProperties); + + $columnDiff->fromColumn = $column; + $tableDifferences->changedColumns[$column->getName()] = $columnDiff; + $changes++; + } + + $this->detectColumnRenamings($tableDifferences); + + $fromTableIndexes = $fromTable->getIndexes(); + $toTableIndexes = $toTable->getIndexes(); + + /* See if all the indexes in "from" table exist in "to" table */ + foreach ($toTableIndexes as $indexName => $index) { + if (($index->isPrimary() && $fromTable->hasPrimaryKey()) || $fromTable->hasIndex($indexName)) { + continue; + } + + $tableDifferences->addedIndexes[$indexName] = $index; + $changes++; + } + + /* See if there are any removed indexes in "to" table */ + foreach ($fromTableIndexes as $indexName => $index) { + // See if index is removed in "to" table. + if ( + ($index->isPrimary() && ! $toTable->hasPrimaryKey()) || + ! $index->isPrimary() && ! $toTable->hasIndex($indexName) + ) { + $tableDifferences->removedIndexes[$indexName] = $index; + $changes++; + continue; + } + + // See if index has changed in "to" table. + $toTableIndex = $index->isPrimary() ? $toTable->getPrimaryKey() : $toTable->getIndex($indexName); + assert($toTableIndex instanceof Index); + + if (! $this->diffIndex($index, $toTableIndex)) { + continue; + } + + $tableDifferences->changedIndexes[$indexName] = $toTableIndex; + $changes++; + } + + $this->detectIndexRenamings($tableDifferences); + + $fromForeignKeys = $fromTable->getForeignKeys(); + $toForeignKeys = $toTable->getForeignKeys(); + + foreach ($fromForeignKeys as $fromKey => $fromConstraint) { + foreach ($toForeignKeys as $toKey => $toConstraint) { + if ($this->diffForeignKey($fromConstraint, $toConstraint) === false) { + unset($fromForeignKeys[$fromKey], $toForeignKeys[$toKey]); + } else { + if (strtolower($fromConstraint->getName()) === strtolower($toConstraint->getName())) { + $tableDifferences->changedForeignKeys[] = $toConstraint; + $changes++; + unset($fromForeignKeys[$fromKey], $toForeignKeys[$toKey]); + } + } + } + } + + foreach ($fromForeignKeys as $fromConstraint) { + $tableDifferences->removedForeignKeys[] = $fromConstraint; + $changes++; + } + + foreach ($toForeignKeys as $toConstraint) { + $tableDifferences->addedForeignKeys[] = $toConstraint; + $changes++; + } + + return $changes ? $tableDifferences : false; + } + + /** + * Try to find columns that only changed their name, rename operations maybe cheaper than add/drop + * however ambiguities between different possibilities should not lead to renaming at all. + * + * @return void + */ + private function detectColumnRenamings(TableDiff $tableDifferences) + { + $renameCandidates = []; + foreach ($tableDifferences->addedColumns as $addedColumnName => $addedColumn) { + foreach ($tableDifferences->removedColumns as $removedColumn) { + if (count($this->diffColumn($addedColumn, $removedColumn)) !== 0) { + continue; + } + + $renameCandidates[$addedColumn->getName()][] = [$removedColumn, $addedColumn, $addedColumnName]; + } + } + + foreach ($renameCandidates as $candidateColumns) { + if (count($candidateColumns) !== 1) { + continue; + } + + [$removedColumn, $addedColumn] = $candidateColumns[0]; + $removedColumnName = strtolower($removedColumn->getName()); + $addedColumnName = strtolower($addedColumn->getName()); + + if (isset($tableDifferences->renamedColumns[$removedColumnName])) { + continue; + } + + $tableDifferences->renamedColumns[$removedColumnName] = $addedColumn; + unset( + $tableDifferences->addedColumns[$addedColumnName], + $tableDifferences->removedColumns[$removedColumnName] + ); + } + } + + /** + * Try to find indexes that only changed their name, rename operations maybe cheaper than add/drop + * however ambiguities between different possibilities should not lead to renaming at all. + * + * @return void + */ + private function detectIndexRenamings(TableDiff $tableDifferences) + { + $renameCandidates = []; + + // Gather possible rename candidates by comparing each added and removed index based on semantics. + foreach ($tableDifferences->addedIndexes as $addedIndexName => $addedIndex) { + foreach ($tableDifferences->removedIndexes as $removedIndex) { + if ($this->diffIndex($addedIndex, $removedIndex)) { + continue; + } + + $renameCandidates[$addedIndex->getName()][] = [$removedIndex, $addedIndex, $addedIndexName]; + } + } + + foreach ($renameCandidates as $candidateIndexes) { + // If the current rename candidate contains exactly one semantically equal index, + // we can safely rename it. + // Otherwise it is unclear if a rename action is really intended, + // therefore we let those ambiguous indexes be added/dropped. + if (count($candidateIndexes) !== 1) { + continue; + } + + [$removedIndex, $addedIndex] = $candidateIndexes[0]; + + $removedIndexName = strtolower($removedIndex->getName()); + $addedIndexName = strtolower($addedIndex->getName()); + + if (isset($tableDifferences->renamedIndexes[$removedIndexName])) { + continue; + } + + $tableDifferences->renamedIndexes[$removedIndexName] = $addedIndex; + unset( + $tableDifferences->addedIndexes[$addedIndexName], + $tableDifferences->removedIndexes[$removedIndexName] + ); + } + } + + /** + * @return bool + */ + public function diffForeignKey(ForeignKeyConstraint $key1, ForeignKeyConstraint $key2) + { + if ( + array_map('strtolower', $key1->getUnquotedLocalColumns()) + !== array_map('strtolower', $key2->getUnquotedLocalColumns()) + ) { + return true; + } + + if ( + array_map('strtolower', $key1->getUnquotedForeignColumns()) + !== array_map('strtolower', $key2->getUnquotedForeignColumns()) + ) { + return true; + } + + if ($key1->getUnqualifiedForeignTableName() !== $key2->getUnqualifiedForeignTableName()) { + return true; + } + + if ($key1->onUpdate() !== $key2->onUpdate()) { + return true; + } + + return $key1->onDelete() !== $key2->onDelete(); + } + + /** + * Returns the difference between the columns + * + * If there are differences this method returns $field2, otherwise the + * boolean false. + * + * @return string[] + */ + public function diffColumn(Column $column1, Column $column2) + { + $properties1 = $column1->toArray(); + $properties2 = $column2->toArray(); + + $changedProperties = []; + + if (get_class($properties1['type']) !== get_class($properties2['type'])) { + $changedProperties[] = 'type'; + } + + foreach (['notnull', 'unsigned', 'autoincrement'] as $property) { + if ($properties1[$property] === $properties2[$property]) { + continue; + } + + $changedProperties[] = $property; + } + + // This is a very nasty hack to make comparator work with the legacy json_array type, + // which should be killed in v3 + if ($this->isALegacyJsonComparison($properties1['type'], $properties2['type'])) { + array_shift($changedProperties); + + $changedProperties[] = 'comment'; + } + + // Null values need to be checked additionally as they tell whether to create or drop a default value. + // null != 0, null != false, null != '' etc. This affects platform's table alteration SQL generation. + if ( + ($properties1['default'] === null) !== ($properties2['default'] === null) + || $properties1['default'] != $properties2['default'] + ) { + $changedProperties[] = 'default'; + } + + if ( + ($properties1['type'] instanceof Types\StringType && ! $properties1['type'] instanceof Types\GuidType) || + $properties1['type'] instanceof Types\BinaryType + ) { + // check if value of length is set at all, default value assumed otherwise. + $length1 = $properties1['length'] ?: 255; + $length2 = $properties2['length'] ?: 255; + if ($length1 !== $length2) { + $changedProperties[] = 'length'; + } + + if ($properties1['fixed'] !== $properties2['fixed']) { + $changedProperties[] = 'fixed'; + } + } elseif ($properties1['type'] instanceof Types\DecimalType) { + if (($properties1['precision'] ?: 10) !== ($properties2['precision'] ?: 10)) { + $changedProperties[] = 'precision'; + } + + if ($properties1['scale'] !== $properties2['scale']) { + $changedProperties[] = 'scale'; + } + } + + // A null value and an empty string are actually equal for a comment so they should not trigger a change. + if ( + $properties1['comment'] !== $properties2['comment'] && + ! ($properties1['comment'] === null && $properties2['comment'] === '') && + ! ($properties2['comment'] === null && $properties1['comment'] === '') + ) { + $changedProperties[] = 'comment'; + } + + $customOptions1 = $column1->getCustomSchemaOptions(); + $customOptions2 = $column2->getCustomSchemaOptions(); + + foreach (array_merge(array_keys($customOptions1), array_keys($customOptions2)) as $key) { + if (! array_key_exists($key, $properties1) || ! array_key_exists($key, $properties2)) { + $changedProperties[] = $key; + } elseif ($properties1[$key] !== $properties2[$key]) { + $changedProperties[] = $key; + } + } + + $platformOptions1 = $column1->getPlatformOptions(); + $platformOptions2 = $column2->getPlatformOptions(); + + foreach (array_keys(array_intersect_key($platformOptions1, $platformOptions2)) as $key) { + if ($properties1[$key] === $properties2[$key]) { + continue; + } + + $changedProperties[] = $key; + } + + return array_unique($changedProperties); + } + + /** + * TODO: kill with fire on v3.0 + * + * @deprecated + */ + private function isALegacyJsonComparison(Types\Type $one, Types\Type $other): bool + { + if (! $one instanceof Types\JsonType || ! $other instanceof Types\JsonType) { + return false; + } + + return (! $one instanceof Types\JsonArrayType && $other instanceof Types\JsonArrayType) + || (! $other instanceof Types\JsonArrayType && $one instanceof Types\JsonArrayType); + } + + /** + * Finds the difference between the indexes $index1 and $index2. + * + * Compares $index1 with $index2 and returns $index2 if there are any + * differences or false in case there are no differences. + * + * @return bool + */ + public function diffIndex(Index $index1, Index $index2) + { + return ! ($index1->isFullfilledBy($index2) && $index2->isFullfilledBy($index1)); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Constraint.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Constraint.php new file mode 100755 index 0000000..65e239e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Constraint.php @@ -0,0 +1,43 @@ +_platform->getListTablesSQL(); + $sql .= ' AND CREATOR = UPPER(' . $this->_conn->quote($this->_conn->getUsername()) . ')'; + + $tables = $this->_conn->fetchAllAssociative($sql); + + return $this->filterAssetNames($this->_getPortableTablesList($tables)); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableColumnDefinition($tableColumn) + { + $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); + + $length = null; + $fixed = null; + $scale = false; + $precision = false; + + $default = null; + + if ($tableColumn['default'] !== null && $tableColumn['default'] !== 'NULL') { + $default = $tableColumn['default']; + + if (preg_match('/^\'(.*)\'$/s', $default, $matches)) { + $default = str_replace("''", "'", $matches[1]); + } + } + + $type = $this->_platform->getDoctrineTypeMapping($tableColumn['typename']); + + if (isset($tableColumn['comment'])) { + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); + $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); + } + + switch (strtolower($tableColumn['typename'])) { + case 'varchar': + $length = $tableColumn['length']; + $fixed = false; + break; + + case 'character': + $length = $tableColumn['length']; + $fixed = true; + break; + + case 'clob': + $length = $tableColumn['length']; + break; + + case 'decimal': + case 'double': + case 'real': + $scale = $tableColumn['scale']; + $precision = $tableColumn['length']; + break; + } + + $options = [ + 'length' => $length, + 'unsigned' => false, + 'fixed' => (bool) $fixed, + 'default' => $default, + 'autoincrement' => (bool) $tableColumn['autoincrement'], + 'notnull' => $tableColumn['nulls'] === 'N', + 'scale' => null, + 'precision' => null, + 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' + ? $tableColumn['comment'] + : null, + 'platformOptions' => [], + ]; + + if ($scale !== null && $precision !== null) { + $options['scale'] = $scale; + $options['precision'] = $precision; + } + + return new Column($tableColumn['colname'], Type::getType($type), $options); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTablesList($tables) + { + $tableNames = []; + foreach ($tables as $tableRow) { + $tableRow = array_change_key_case($tableRow, CASE_LOWER); + $tableNames[] = $tableRow['name']; + } + + return $tableNames; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + { + foreach ($tableIndexes as &$tableIndexRow) { + $tableIndexRow = array_change_key_case($tableIndexRow, CASE_LOWER); + $tableIndexRow['primary'] = (bool) $tableIndexRow['primary']; + } + + return parent::_getPortableTableIndexesList($tableIndexes, $tableName); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + { + return new ForeignKeyConstraint( + $tableForeignKey['local_columns'], + $tableForeignKey['foreign_table'], + $tableForeignKey['foreign_columns'], + $tableForeignKey['name'], + $tableForeignKey['options'] + ); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableForeignKeysList($tableForeignKeys) + { + $foreignKeys = []; + + foreach ($tableForeignKeys as $tableForeignKey) { + $tableForeignKey = array_change_key_case($tableForeignKey, CASE_LOWER); + + if (! isset($foreignKeys[$tableForeignKey['index_name']])) { + $foreignKeys[$tableForeignKey['index_name']] = [ + 'local_columns' => [$tableForeignKey['local_column']], + 'foreign_table' => $tableForeignKey['foreign_table'], + 'foreign_columns' => [$tableForeignKey['foreign_column']], + 'name' => $tableForeignKey['index_name'], + 'options' => [ + 'onUpdate' => $tableForeignKey['on_update'], + 'onDelete' => $tableForeignKey['on_delete'], + ], + ]; + } else { + $foreignKeys[$tableForeignKey['index_name']]['local_columns'][] = $tableForeignKey['local_column']; + $foreignKeys[$tableForeignKey['index_name']]['foreign_columns'][] = $tableForeignKey['foreign_column']; + } + } + + return parent::_getPortableTableForeignKeysList($foreignKeys); + } + + /** + * @param string $def + * + * @return string|null + */ + protected function _getPortableForeignKeyRuleDef($def) + { + if ($def === 'C') { + return 'CASCADE'; + } + + if ($def === 'N') { + return 'SET NULL'; + } + + return null; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableViewDefinition($view) + { + $view = array_change_key_case($view, CASE_LOWER); + + $sql = ''; + $pos = strpos($view['text'], ' AS '); + + if ($pos !== false) { + $sql = substr($view['text'], $pos + 4); + } + + return new View($view['name'], $sql); + } + + /** + * {@inheritdoc} + */ + public function listTableDetails($name): Table + { + $table = parent::listTableDetails($name); + + $platform = $this->_platform; + assert($platform instanceof DB2Platform); + $sql = $platform->getListTableCommentsSQL($name); + + $tableOptions = $this->_conn->fetchAssociative($sql); + + if ($tableOptions !== false) { + $table->addOption('comment', $tableOptions['REMARKS']); + } + + return $table; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php new file mode 100755 index 0000000..47a2e2f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php @@ -0,0 +1,104 @@ +_platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['COLUMN_COMMENT'], $type); + $tableColumn['COLUMN_COMMENT'] = $this->removeDoctrineTypeFromComment($tableColumn['COLUMN_COMMENT'], $type); + + $options = [ + 'notnull' => ! (bool) $tableColumn['IS_NULLABLE'], + 'length' => (int) $tableColumn['CHARACTER_MAXIMUM_LENGTH'], + 'default' => $tableColumn['COLUMN_DEFAULT'] ?? null, + 'autoincrement' => (bool) $tableColumn['IS_AUTO_INCREMENT'], + 'scale' => (int) $tableColumn['NUMERIC_SCALE'], + 'precision' => (int) $tableColumn['NUMERIC_PRECISION'], + 'comment' => isset($tableColumn['COLUMN_COMMENT']) && $tableColumn['COLUMN_COMMENT'] !== '' + ? $tableColumn['COLUMN_COMMENT'] + : null, + ]; + + $column = new Column($tableColumn['COLUMN_NAME'], Type::getType($type), $options); + + if (! empty($tableColumn['COLLATION_NAME'])) { + $column->setPlatformOption('collation', $tableColumn['COLLATION_NAME']); + } + + return $column; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableDatabaseDefinition($database) + { + return $database['SCHEMA_NAME']; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableDefinition($table) + { + return $table['TABLE_NAME']; + } + + /** + * {@inheritdoc} + */ + public function _getPortableTableForeignKeyDefinition($tableForeignKey) + { + $columns = []; + foreach (explode(',', $tableForeignKey['CONSTRAINT_COLUMNS']) as $value) { + $columns[] = trim($value, ' `'); + } + + $refColumns = []; + foreach (explode(',', $tableForeignKey['REFERENCED_TABLE_COLUMNS']) as $value) { + $refColumns[] = trim($value, ' `'); + } + + return new ForeignKeyConstraint( + $columns, + $tableForeignKey['REFERENCED_TABLE_NAME'], + $refColumns, + $tableForeignKey['CONSTRAINT_NAME'], + [ + 'onUpdate' => $tableForeignKey['UPDATE_RULE'], + 'onDelete' => $tableForeignKey['DELETE_RULE'], + ] + ); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + { + $indexes = []; + foreach ($tableIndexes as $k) { + $k['primary'] = (bool) $k['primary']; + $indexes[] = $k; + } + + return parent::_getPortableTableIndexesList($indexes, $tableName); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php new file mode 100755 index 0000000..6cb7ce0 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php @@ -0,0 +1,399 @@ + Identifier) + * + * @var Identifier[] + */ + protected $_localColumnNames; + + /** + * Table or asset identifier instance of the referenced table name the foreign key constraint is associated with. + * + * @var Table|Identifier + */ + protected $_foreignTableName; + + /** + * Asset identifier instances of the referenced table column names the foreign key constraint is associated with. + * array($columnName => Identifier) + * + * @var Identifier[] + */ + protected $_foreignColumnNames; + + /** + * Options associated with the foreign key constraint. + * + * @var mixed[] + */ + protected $_options; + + /** + * Initializes the foreign key constraint. + * + * @param string[] $localColumnNames Names of the referencing table columns. + * @param Table|string $foreignTableName Referenced table. + * @param string[] $foreignColumnNames Names of the referenced table columns. + * @param string|null $name Name of the foreign key constraint. + * @param mixed[] $options Options associated with the foreign key constraint. + */ + public function __construct( + array $localColumnNames, + $foreignTableName, + array $foreignColumnNames, + $name = null, + array $options = [] + ) { + if ($name !== null) { + $this->_setName($name); + } + + $this->_localColumnNames = $this->createIdentifierMap($localColumnNames); + + if ($foreignTableName instanceof Table) { + $this->_foreignTableName = $foreignTableName; + } else { + $this->_foreignTableName = new Identifier($foreignTableName); + } + + $this->_foreignColumnNames = $this->createIdentifierMap($foreignColumnNames); + $this->_options = $options; + } + + /** + * @param string[] $names + * + * @return Identifier[] + */ + private function createIdentifierMap(array $names): array + { + $identifiers = []; + + foreach ($names as $name) { + $identifiers[$name] = new Identifier($name); + } + + return $identifiers; + } + + /** + * Returns the name of the referencing table + * the foreign key constraint is associated with. + * + * @return string + */ + public function getLocalTableName() + { + return $this->_localTable->getName(); + } + + /** + * Sets the Table instance of the referencing table + * the foreign key constraint is associated with. + * + * @param Table $table Instance of the referencing table. + * + * @return void + */ + public function setLocalTable(Table $table) + { + $this->_localTable = $table; + } + + /** + * @return Table + */ + public function getLocalTable() + { + return $this->_localTable; + } + + /** + * Returns the names of the referencing table columns + * the foreign key constraint is associated with. + * + * @return string[] + */ + public function getLocalColumns() + { + return array_keys($this->_localColumnNames); + } + + /** + * Returns the quoted representation of the referencing table column names + * the foreign key constraint is associated with. + * + * But only if they were defined with one or the referencing table column name + * is a keyword reserved by the platform. + * Otherwise the plain unquoted value as inserted is returned. + * + * @param AbstractPlatform $platform The platform to use for quotation. + * + * @return string[] + */ + public function getQuotedLocalColumns(AbstractPlatform $platform) + { + $columns = []; + + foreach ($this->_localColumnNames as $column) { + $columns[] = $column->getQuotedName($platform); + } + + return $columns; + } + + /** + * Returns unquoted representation of local table column names for comparison with other FK + * + * @return string[] + */ + public function getUnquotedLocalColumns() + { + return array_map([$this, 'trimQuotes'], $this->getLocalColumns()); + } + + /** + * Returns unquoted representation of foreign table column names for comparison with other FK + * + * @return string[] + */ + public function getUnquotedForeignColumns() + { + return array_map([$this, 'trimQuotes'], $this->getForeignColumns()); + } + + /** + * {@inheritdoc} + * + * @see getLocalColumns + */ + public function getColumns() + { + return $this->getLocalColumns(); + } + + /** + * Returns the quoted representation of the referencing table column names + * the foreign key constraint is associated with. + * + * But only if they were defined with one or the referencing table column name + * is a keyword reserved by the platform. + * Otherwise the plain unquoted value as inserted is returned. + * + * @see getQuotedLocalColumns + * + * @param AbstractPlatform $platform The platform to use for quotation. + * + * @return string[] + */ + public function getQuotedColumns(AbstractPlatform $platform) + { + return $this->getQuotedLocalColumns($platform); + } + + /** + * Returns the name of the referenced table + * the foreign key constraint is associated with. + * + * @return string + */ + public function getForeignTableName() + { + return $this->_foreignTableName->getName(); + } + + /** + * Returns the non-schema qualified foreign table name. + * + * @return string + */ + public function getUnqualifiedForeignTableName() + { + $name = $this->_foreignTableName->getName(); + $position = strrpos($name, '.'); + + if ($position !== false) { + $name = substr($name, $position + 1); + } + + return strtolower($name); + } + + /** + * Returns the quoted representation of the referenced table name + * the foreign key constraint is associated with. + * + * But only if it was defined with one or the referenced table name + * is a keyword reserved by the platform. + * Otherwise the plain unquoted value as inserted is returned. + * + * @param AbstractPlatform $platform The platform to use for quotation. + * + * @return string + */ + public function getQuotedForeignTableName(AbstractPlatform $platform) + { + return $this->_foreignTableName->getQuotedName($platform); + } + + /** + * Returns the names of the referenced table columns + * the foreign key constraint is associated with. + * + * @return string[] + */ + public function getForeignColumns() + { + return array_keys($this->_foreignColumnNames); + } + + /** + * Returns the quoted representation of the referenced table column names + * the foreign key constraint is associated with. + * + * But only if they were defined with one or the referenced table column name + * is a keyword reserved by the platform. + * Otherwise the plain unquoted value as inserted is returned. + * + * @param AbstractPlatform $platform The platform to use for quotation. + * + * @return string[] + */ + public function getQuotedForeignColumns(AbstractPlatform $platform) + { + $columns = []; + + foreach ($this->_foreignColumnNames as $column) { + $columns[] = $column->getQuotedName($platform); + } + + return $columns; + } + + /** + * Returns whether or not a given option + * is associated with the foreign key constraint. + * + * @param string $name Name of the option to check. + * + * @return bool + */ + public function hasOption($name) + { + return isset($this->_options[$name]); + } + + /** + * Returns an option associated with the foreign key constraint. + * + * @param string $name Name of the option the foreign key constraint is associated with. + * + * @return mixed + */ + public function getOption($name) + { + return $this->_options[$name]; + } + + /** + * Returns the options associated with the foreign key constraint. + * + * @return mixed[] + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Returns the referential action for UPDATE operations + * on the referenced table the foreign key constraint is associated with. + * + * @return string|null + */ + public function onUpdate() + { + return $this->onEvent('onUpdate'); + } + + /** + * Returns the referential action for DELETE operations + * on the referenced table the foreign key constraint is associated with. + * + * @return string|null + */ + public function onDelete() + { + return $this->onEvent('onDelete'); + } + + /** + * Returns the referential action for a given database operation + * on the referenced table the foreign key constraint is associated with. + * + * @param string $event Name of the database operation/event to return the referential action for. + * + * @return string|null + */ + private function onEvent($event) + { + if (isset($this->_options[$event])) { + $onEvent = strtoupper($this->_options[$event]); + + if (! in_array($onEvent, ['NO ACTION', 'RESTRICT'])) { + return $onEvent; + } + } + + return null; + } + + /** + * Checks whether this foreign key constraint intersects the given index columns. + * + * Returns `true` if at least one of this foreign key's local columns + * matches one of the given index's columns, `false` otherwise. + * + * @param Index $index The index to be checked against. + * + * @return bool + */ + public function intersectsIndexColumns(Index $index) + { + foreach ($index->getColumns() as $indexColumn) { + foreach ($this->_localColumnNames as $localColumn) { + if (strtolower($indexColumn) === strtolower($localColumn->getName())) { + return true; + } + } + } + + return false; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Identifier.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Identifier.php new file mode 100755 index 0000000..f34465e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Identifier.php @@ -0,0 +1,27 @@ +_setName($identifier); + + if (! $quote || $this->_quoted) { + return; + } + + $this->_setName('"' . $this->getName() . '"'); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Index.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Index.php new file mode 100755 index 0000000..4880da7 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Index.php @@ -0,0 +1,376 @@ + Identifier) + * + * @var Identifier[] + */ + protected $_columns = []; + + /** @var bool */ + protected $_isUnique = false; + + /** @var bool */ + protected $_isPrimary = false; + + /** + * Platform specific flags for indexes. + * array($flagName => true) + * + * @var true[] + */ + protected $_flags = []; + + /** + * Platform specific options + * + * @todo $_flags should eventually be refactored into options + * @var mixed[] + */ + private $options = []; + + /** + * @param string $name + * @param string[] $columns + * @param bool $isUnique + * @param bool $isPrimary + * @param string[] $flags + * @param mixed[] $options + */ + public function __construct( + $name, + array $columns, + $isUnique = false, + $isPrimary = false, + array $flags = [], + array $options = [] + ) { + $isUnique = $isUnique || $isPrimary; + + $this->_setName($name); + $this->_isUnique = $isUnique; + $this->_isPrimary = $isPrimary; + $this->options = $options; + + foreach ($columns as $column) { + $this->_addColumn($column); + } + + foreach ($flags as $flag) { + $this->addFlag($flag); + } + } + + /** + * @param string $column + * + * @return void + * + * @throws InvalidArgumentException + */ + protected function _addColumn($column) + { + if (! is_string($column)) { + throw new InvalidArgumentException('Expecting a string as Index Column'); + } + + $this->_columns[$column] = new Identifier($column); + } + + /** + * {@inheritdoc} + */ + public function getColumns() + { + return array_keys($this->_columns); + } + + /** + * {@inheritdoc} + */ + public function getQuotedColumns(AbstractPlatform $platform) + { + $subParts = $platform->supportsColumnLengthIndexes() && $this->hasOption('lengths') + ? $this->getOption('lengths') : []; + + $columns = []; + + foreach ($this->_columns as $column) { + $length = array_shift($subParts); + + $quotedColumn = $column->getQuotedName($platform); + + if ($length !== null) { + $quotedColumn .= '(' . $length . ')'; + } + + $columns[] = $quotedColumn; + } + + return $columns; + } + + /** + * @return string[] + */ + public function getUnquotedColumns() + { + return array_map([$this, 'trimQuotes'], $this->getColumns()); + } + + /** + * Is the index neither unique nor primary key? + * + * @return bool + */ + public function isSimpleIndex() + { + return ! $this->_isPrimary && ! $this->_isUnique; + } + + /** + * @return bool + */ + public function isUnique() + { + return $this->_isUnique; + } + + /** + * @return bool + */ + public function isPrimary() + { + return $this->_isPrimary; + } + + /** + * @param string $name + * @param int $pos + * + * @return bool + */ + public function hasColumnAtPosition($name, $pos = 0) + { + $name = $this->trimQuotes(strtolower($name)); + $indexColumns = array_map('strtolower', $this->getUnquotedColumns()); + + return array_search($name, $indexColumns) === $pos; + } + + /** + * Checks if this index exactly spans the given column names in the correct order. + * + * @param string[] $columnNames + * + * @return bool + */ + public function spansColumns(array $columnNames) + { + $columns = $this->getColumns(); + $numberOfColumns = count($columns); + $sameColumns = true; + + for ($i = 0; $i < $numberOfColumns; $i++) { + if ( + isset($columnNames[$i]) + && $this->trimQuotes(strtolower($columns[$i])) === $this->trimQuotes(strtolower($columnNames[$i])) + ) { + continue; + } + + $sameColumns = false; + } + + return $sameColumns; + } + + /** + * Checks if the other index already fulfills all the indexing and constraint needs of the current one. + * + * @return bool + */ + public function isFullfilledBy(Index $other) + { + // allow the other index to be equally large only. It being larger is an option + // but it creates a problem with scenarios of the kind PRIMARY KEY(foo,bar) UNIQUE(foo) + if (count($other->getColumns()) !== count($this->getColumns())) { + return false; + } + + // Check if columns are the same, and even in the same order + $sameColumns = $this->spansColumns($other->getColumns()); + + if ($sameColumns) { + if (! $this->samePartialIndex($other)) { + return false; + } + + if (! $this->hasSameColumnLengths($other)) { + return false; + } + + if (! $this->isUnique() && ! $this->isPrimary()) { + // this is a special case: If the current key is neither primary or unique, any unique or + // primary key will always have the same effect for the index and there cannot be any constraint + // overlaps. This means a primary or unique index can always fulfill the requirements of just an + // index that has no constraints. + return true; + } + + if ($other->isPrimary() !== $this->isPrimary()) { + return false; + } + + return $other->isUnique() === $this->isUnique(); + } + + return false; + } + + /** + * Detects if the other index is a non-unique, non primary index that can be overwritten by this one. + * + * @return bool + */ + public function overrules(Index $other) + { + if ($other->isPrimary()) { + return false; + } + + if ($this->isSimpleIndex() && $other->isUnique()) { + return false; + } + + return $this->spansColumns($other->getColumns()) + && ($this->isPrimary() || $this->isUnique()) + && $this->samePartialIndex($other); + } + + /** + * Returns platform specific flags for indexes. + * + * @return string[] + */ + public function getFlags() + { + return array_keys($this->_flags); + } + + /** + * Adds Flag for an index that translates to platform specific handling. + * + * @param string $flag + * + * @return Index + * + * @example $index->addFlag('CLUSTERED') + */ + public function addFlag($flag) + { + $this->_flags[strtolower($flag)] = true; + + return $this; + } + + /** + * Does this index have a specific flag? + * + * @param string $flag + * + * @return bool + */ + public function hasFlag($flag) + { + return isset($this->_flags[strtolower($flag)]); + } + + /** + * Removes a flag. + * + * @param string $flag + * + * @return void + */ + public function removeFlag($flag) + { + unset($this->_flags[strtolower($flag)]); + } + + /** + * @param string $name + * + * @return bool + */ + public function hasOption($name) + { + return isset($this->options[strtolower($name)]); + } + + /** + * @param string $name + * + * @return mixed + */ + public function getOption($name) + { + return $this->options[strtolower($name)]; + } + + /** + * @return mixed[] + */ + public function getOptions() + { + return $this->options; + } + + /** + * Return whether the two indexes have the same partial index + * + * @return bool + */ + private function samePartialIndex(Index $other) + { + if ( + $this->hasOption('where') + && $other->hasOption('where') + && $this->getOption('where') === $other->getOption('where') + ) { + return true; + } + + return ! $this->hasOption('where') && ! $other->hasOption('where'); + } + + /** + * Returns whether the index has the same column lengths as the other + */ + private function hasSameColumnLengths(self $other): bool + { + $filter = static function (?int $length): bool { + return $length !== null; + }; + + return array_filter($this->options['lengths'] ?? [], $filter) + === array_filter($other->options['lengths'] ?? [], $filter); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php new file mode 100755 index 0000000..4a8e621 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php @@ -0,0 +1,375 @@ + "\0", + "\\'" => "'", + '\\"' => '"', + '\\b' => "\b", + '\\n' => "\n", + '\\r' => "\r", + '\\t' => "\t", + '\\Z' => "\x1a", + '\\\\' => '\\', + '\\%' => '%', + '\\_' => '_', + + // Internally, MariaDB escapes single quotes using the standard syntax + "''" => "'", + ]; + + /** + * {@inheritdoc} + */ + protected function _getPortableViewDefinition($view) + { + return new View($view['TABLE_NAME'], $view['VIEW_DEFINITION']); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableDefinition($table) + { + return array_shift($table); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableUserDefinition($user) + { + return [ + 'user' => $user['User'], + 'password' => $user['Password'], + ]; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + { + foreach ($tableIndexes as $k => $v) { + $v = array_change_key_case($v, CASE_LOWER); + if ($v['key_name'] === 'PRIMARY') { + $v['primary'] = true; + } else { + $v['primary'] = false; + } + + if (strpos($v['index_type'], 'FULLTEXT') !== false) { + $v['flags'] = ['FULLTEXT']; + } elseif (strpos($v['index_type'], 'SPATIAL') !== false) { + $v['flags'] = ['SPATIAL']; + } + + // Ignore prohibited prefix `length` for spatial index + if (strpos($v['index_type'], 'SPATIAL') === false) { + $v['length'] = isset($v['sub_part']) ? (int) $v['sub_part'] : null; + } + + $tableIndexes[$k] = $v; + } + + return parent::_getPortableTableIndexesList($tableIndexes, $tableName); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableDatabaseDefinition($database) + { + return $database['Database']; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableColumnDefinition($tableColumn) + { + $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); + + $dbType = strtolower($tableColumn['type']); + $dbType = strtok($dbType, '(), '); + assert(is_string($dbType)); + + $length = $tableColumn['length'] ?? strtok('(), '); + + $fixed = null; + + if (! isset($tableColumn['name'])) { + $tableColumn['name'] = ''; + } + + $scale = null; + $precision = null; + + $type = $this->_platform->getDoctrineTypeMapping($dbType); + + // In cases where not connected to a database DESCRIBE $table does not return 'Comment' + if (isset($tableColumn['comment'])) { + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); + $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); + } + + switch ($dbType) { + case 'char': + case 'binary': + $fixed = true; + break; + + case 'float': + case 'double': + case 'real': + case 'numeric': + case 'decimal': + if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['type'], $match)) { + $precision = $match[1]; + $scale = $match[2]; + $length = null; + } + + break; + + case 'tinytext': + $length = MySqlPlatform::LENGTH_LIMIT_TINYTEXT; + break; + + case 'text': + $length = MySqlPlatform::LENGTH_LIMIT_TEXT; + break; + + case 'mediumtext': + $length = MySqlPlatform::LENGTH_LIMIT_MEDIUMTEXT; + break; + + case 'tinyblob': + $length = MySqlPlatform::LENGTH_LIMIT_TINYBLOB; + break; + + case 'blob': + $length = MySqlPlatform::LENGTH_LIMIT_BLOB; + break; + + case 'mediumblob': + $length = MySqlPlatform::LENGTH_LIMIT_MEDIUMBLOB; + break; + + case 'tinyint': + case 'smallint': + case 'mediumint': + case 'int': + case 'integer': + case 'bigint': + case 'year': + $length = null; + break; + } + + if ($this->_platform instanceof MariaDb1027Platform) { + $columnDefault = $this->getMariaDb1027ColumnDefault($this->_platform, $tableColumn['default']); + } else { + $columnDefault = $tableColumn['default']; + } + + $options = [ + 'length' => $length !== null ? (int) $length : null, + 'unsigned' => strpos($tableColumn['type'], 'unsigned') !== false, + 'fixed' => (bool) $fixed, + 'default' => $columnDefault, + 'notnull' => $tableColumn['null'] !== 'YES', + 'scale' => null, + 'precision' => null, + 'autoincrement' => strpos($tableColumn['extra'], 'auto_increment') !== false, + 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' + ? $tableColumn['comment'] + : null, + ]; + + if ($scale !== null && $precision !== null) { + $options['scale'] = (int) $scale; + $options['precision'] = (int) $precision; + } + + $column = new Column($tableColumn['field'], Type::getType($type), $options); + + if (isset($tableColumn['characterset'])) { + $column->setPlatformOption('charset', $tableColumn['characterset']); + } + + if (isset($tableColumn['collation'])) { + $column->setPlatformOption('collation', $tableColumn['collation']); + } + + return $column; + } + + /** + * Return Doctrine/Mysql-compatible column default values for MariaDB 10.2.7+ servers. + * + * - Since MariaDb 10.2.7 column defaults stored in information_schema are now quoted + * to distinguish them from expressions (see MDEV-10134). + * - CURRENT_TIMESTAMP, CURRENT_TIME, CURRENT_DATE are stored in information_schema + * as current_timestamp(), currdate(), currtime() + * - Quoted 'NULL' is not enforced by Maria, it is technically possible to have + * null in some circumstances (see https://jira.mariadb.org/browse/MDEV-14053) + * - \' is always stored as '' in information_schema (normalized) + * + * @link https://mariadb.com/kb/en/library/information-schema-columns-table/ + * @link https://jira.mariadb.org/browse/MDEV-13132 + * + * @param string|null $columnDefault default value as stored in information_schema for MariaDB >= 10.2.7 + */ + private function getMariaDb1027ColumnDefault(MariaDb1027Platform $platform, ?string $columnDefault): ?string + { + if ($columnDefault === 'NULL' || $columnDefault === null) { + return null; + } + + if (preg_match('/^\'(.*)\'$/', $columnDefault, $matches)) { + return strtr($matches[1], self::MARIADB_ESCAPE_SEQUENCES); + } + + switch ($columnDefault) { + case 'current_timestamp()': + return $platform->getCurrentTimestampSQL(); + + case 'curdate()': + return $platform->getCurrentDateSQL(); + + case 'curtime()': + return $platform->getCurrentTimeSQL(); + } + + return $columnDefault; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableForeignKeysList($tableForeignKeys) + { + $list = []; + foreach ($tableForeignKeys as $value) { + $value = array_change_key_case($value, CASE_LOWER); + if (! isset($list[$value['constraint_name']])) { + if (! isset($value['delete_rule']) || $value['delete_rule'] === 'RESTRICT') { + $value['delete_rule'] = null; + } + + if (! isset($value['update_rule']) || $value['update_rule'] === 'RESTRICT') { + $value['update_rule'] = null; + } + + $list[$value['constraint_name']] = [ + 'name' => $value['constraint_name'], + 'local' => [], + 'foreign' => [], + 'foreignTable' => $value['referenced_table_name'], + 'onDelete' => $value['delete_rule'], + 'onUpdate' => $value['update_rule'], + ]; + } + + $list[$value['constraint_name']]['local'][] = $value['column_name']; + $list[$value['constraint_name']]['foreign'][] = $value['referenced_column_name']; + } + + $result = []; + foreach ($list as $constraint) { + $result[] = new ForeignKeyConstraint( + array_values($constraint['local']), + $constraint['foreignTable'], + array_values($constraint['foreign']), + $constraint['name'], + [ + 'onDelete' => $constraint['onDelete'], + 'onUpdate' => $constraint['onUpdate'], + ] + ); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function listTableDetails($name) + { + $table = parent::listTableDetails($name); + + $platform = $this->_platform; + assert($platform instanceof MySqlPlatform); + $sql = $platform->getListTableMetadataSQL($name); + + $tableOptions = $this->_conn->fetchAssociative($sql); + + if ($tableOptions === false) { + return $table; + } + + $table->addOption('engine', $tableOptions['ENGINE']); + + if ($tableOptions['TABLE_COLLATION'] !== null) { + $table->addOption('collation', $tableOptions['TABLE_COLLATION']); + } + + if ($tableOptions['AUTO_INCREMENT'] !== null) { + $table->addOption('autoincrement', $tableOptions['AUTO_INCREMENT']); + } + + $table->addOption('comment', $tableOptions['TABLE_COMMENT']); + $table->addOption('create_options', $this->parseCreateOptions($tableOptions['CREATE_OPTIONS'])); + + return $table; + } + + /** + * @return string[]|true[] + */ + private function parseCreateOptions(?string $string): array + { + $options = []; + + if ($string === null || $string === '') { + return $options; + } + + foreach (explode(' ', $string) as $pair) { + $parts = explode('=', $pair, 2); + + $options[$parts[0]] = $parts[1] ?? true; + } + + return $options; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php new file mode 100755 index 0000000..223ae4e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php @@ -0,0 +1,425 @@ +getPrevious(); + assert($exception instanceof Throwable); + + if (! $exception instanceof Exception) { + throw $exception; + } + + // If we have a error code 1940 (ORA-01940), the drop database operation failed + // because of active connections on the database. + // To force dropping the database, we first have to close all active connections + // on that database and issue the drop database operation again. + if ($exception->getErrorCode() !== 1940) { + throw $exception; + } + + $this->killUserSessions($database); + + parent::dropDatabase($database); + } + } + + /** + * {@inheritdoc} + */ + protected function _getPortableViewDefinition($view) + { + $view = array_change_key_case($view, CASE_LOWER); + + return new View($this->getQuotedIdentifierName($view['view_name']), $view['text']); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableUserDefinition($user) + { + $user = array_change_key_case($user, CASE_LOWER); + + return [ + 'user' => $user['username'], + ]; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableDefinition($table) + { + $table = array_change_key_case($table, CASE_LOWER); + + return $this->getQuotedIdentifierName($table['table_name']); + } + + /** + * {@inheritdoc} + * + * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + { + $indexBuffer = []; + foreach ($tableIndexes as $tableIndex) { + $tableIndex = array_change_key_case($tableIndex, CASE_LOWER); + + $keyName = strtolower($tableIndex['name']); + $buffer = []; + + if ($tableIndex['is_primary'] === 'P') { + $keyName = 'primary'; + $buffer['primary'] = true; + $buffer['non_unique'] = false; + } else { + $buffer['primary'] = false; + $buffer['non_unique'] = ! $tableIndex['is_unique']; + } + + $buffer['key_name'] = $keyName; + $buffer['column_name'] = $this->getQuotedIdentifierName($tableIndex['column_name']); + $indexBuffer[] = $buffer; + } + + return parent::_getPortableTableIndexesList($indexBuffer, $tableName); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableColumnDefinition($tableColumn) + { + $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); + + $dbType = strtolower($tableColumn['data_type']); + if (strpos($dbType, 'timestamp(') === 0) { + if (strpos($dbType, 'with time zone')) { + $dbType = 'timestamptz'; + } else { + $dbType = 'timestamp'; + } + } + + $unsigned = $fixed = $precision = $scale = $length = null; + + if (! isset($tableColumn['column_name'])) { + $tableColumn['column_name'] = ''; + } + + // Default values returned from database sometimes have trailing spaces. + if (is_string($tableColumn['data_default'])) { + $tableColumn['data_default'] = trim($tableColumn['data_default']); + } + + if ($tableColumn['data_default'] === '' || $tableColumn['data_default'] === 'NULL') { + $tableColumn['data_default'] = null; + } + + if ($tableColumn['data_default'] !== null) { + // Default values returned from database are represented as literal expressions + if (preg_match('/^\'(.*)\'$/s', $tableColumn['data_default'], $matches)) { + $tableColumn['data_default'] = str_replace("''", "'", $matches[1]); + } + } + + if ($tableColumn['data_precision'] !== null) { + $precision = (int) $tableColumn['data_precision']; + } + + if ($tableColumn['data_scale'] !== null) { + $scale = (int) $tableColumn['data_scale']; + } + + $type = $this->_platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comments'], $type); + $tableColumn['comments'] = $this->removeDoctrineTypeFromComment($tableColumn['comments'], $type); + + switch ($dbType) { + case 'number': + if ($precision === 20 && $scale === 0) { + $type = 'bigint'; + } elseif ($precision === 5 && $scale === 0) { + $type = 'smallint'; + } elseif ($precision === 1 && $scale === 0) { + $type = 'boolean'; + } elseif ($scale > 0) { + $type = 'decimal'; + } + + break; + + case 'varchar': + case 'varchar2': + case 'nvarchar2': + $length = $tableColumn['char_length']; + $fixed = false; + break; + + case 'char': + case 'nchar': + $length = $tableColumn['char_length']; + $fixed = true; + break; + } + + $options = [ + 'notnull' => $tableColumn['nullable'] === 'N', + 'fixed' => (bool) $fixed, + 'unsigned' => (bool) $unsigned, + 'default' => $tableColumn['data_default'], + 'length' => $length, + 'precision' => $precision, + 'scale' => $scale, + 'comment' => isset($tableColumn['comments']) && $tableColumn['comments'] !== '' + ? $tableColumn['comments'] + : null, + ]; + + return new Column($this->getQuotedIdentifierName($tableColumn['column_name']), Type::getType($type), $options); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableForeignKeysList($tableForeignKeys) + { + $list = []; + foreach ($tableForeignKeys as $value) { + $value = array_change_key_case($value, CASE_LOWER); + if (! isset($list[$value['constraint_name']])) { + if ($value['delete_rule'] === 'NO ACTION') { + $value['delete_rule'] = null; + } + + $list[$value['constraint_name']] = [ + 'name' => $this->getQuotedIdentifierName($value['constraint_name']), + 'local' => [], + 'foreign' => [], + 'foreignTable' => $value['references_table'], + 'onDelete' => $value['delete_rule'], + ]; + } + + $localColumn = $this->getQuotedIdentifierName($value['local_column']); + $foreignColumn = $this->getQuotedIdentifierName($value['foreign_column']); + + $list[$value['constraint_name']]['local'][$value['position']] = $localColumn; + $list[$value['constraint_name']]['foreign'][$value['position']] = $foreignColumn; + } + + $result = []; + foreach ($list as $constraint) { + $result[] = new ForeignKeyConstraint( + array_values($constraint['local']), + $this->getQuotedIdentifierName($constraint['foreignTable']), + array_values($constraint['foreign']), + $this->getQuotedIdentifierName($constraint['name']), + ['onDelete' => $constraint['onDelete']] + ); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableSequenceDefinition($sequence) + { + $sequence = array_change_key_case($sequence, CASE_LOWER); + + return new Sequence( + $this->getQuotedIdentifierName($sequence['sequence_name']), + (int) $sequence['increment_by'], + (int) $sequence['min_value'] + ); + } + + /** + * {@inheritdoc} + * + * @deprecated + */ + protected function _getPortableFunctionDefinition($function) + { + $function = array_change_key_case($function, CASE_LOWER); + + return $function['name']; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableDatabaseDefinition($database) + { + $database = array_change_key_case($database, CASE_LOWER); + + return $database['username']; + } + + /** + * {@inheritdoc} + * + * @param string|null $database + * + * Calling this method without an argument or by passing NULL is deprecated. + */ + public function createDatabase($database = null) + { + if ($database === null) { + $database = $this->_conn->getDatabase(); + } + + $statement = 'CREATE USER ' . $database; + + $params = $this->_conn->getParams(); + + if (isset($params['password'])) { + $statement .= ' IDENTIFIED BY ' . $params['password']; + } + + $this->_conn->executeStatement($statement); + + $statement = 'GRANT DBA TO ' . $database; + $this->_conn->executeStatement($statement); + } + + /** + * @param string $table + * + * @return bool + */ + public function dropAutoincrement($table) + { + assert($this->_platform instanceof OraclePlatform); + + $sql = $this->_platform->getDropAutoincrementSql($table); + foreach ($sql as $query) { + $this->_conn->executeStatement($query); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function dropTable($name) + { + $this->tryMethod('dropAutoincrement', $name); + + parent::dropTable($name); + } + + /** + * Returns the quoted representation of the given identifier name. + * + * Quotes non-uppercase identifiers explicitly to preserve case + * and thus make references to the particular identifier work. + * + * @param string $identifier The identifier to quote. + * + * @return string The quoted identifier. + */ + private function getQuotedIdentifierName($identifier) + { + if (preg_match('/[a-z]/', $identifier)) { + return $this->_platform->quoteIdentifier($identifier); + } + + return $identifier; + } + + /** + * Kills sessions connected with the given user. + * + * This is useful to force DROP USER operations which could fail because of active user sessions. + * + * @param string $user The name of the user to kill sessions for. + * + * @return void + */ + private function killUserSessions($user) + { + $sql = <<_conn->fetchAllAssociative($sql, [strtoupper($user)]); + + foreach ($activeUserSessions as $activeUserSession) { + $activeUserSession = array_change_key_case($activeUserSession, CASE_LOWER); + + $this->_execSql( + sprintf( + "ALTER SYSTEM KILL SESSION '%s, %s' IMMEDIATE", + $activeUserSession['sid'], + $activeUserSession['serial#'] + ) + ); + } + } + + /** + * {@inheritdoc} + */ + public function listTableDetails($name): Table + { + $table = parent::listTableDetails($name); + + $platform = $this->_platform; + assert($platform instanceof OraclePlatform); + $sql = $platform->getListTableCommentsSQL($name); + + $tableOptions = $this->_conn->fetchAssociative($sql); + + if ($tableOptions !== false) { + $table->addOption('comment', $tableOptions['COMMENTS']); + } + + return $table; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php new file mode 100755 index 0000000..3678b42 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php @@ -0,0 +1,544 @@ +_conn->executeQuery( + "SELECT nspname FROM pg_namespace WHERE nspname !~ '^pg_.*' AND nspname != 'information_schema'" + ); + + return $statement->fetchAll(FetchMode::COLUMN); + } + + /** + * Returns an array of schema search paths. + * + * This is a PostgreSQL only function. + * + * @return string[] + */ + public function getSchemaSearchPaths() + { + $params = $this->_conn->getParams(); + + $searchPaths = $this->_conn->fetchColumn('SHOW search_path'); + assert($searchPaths !== false); + + $schema = explode(',', $searchPaths); + + if (isset($params['user'])) { + $schema = str_replace('"$user"', $params['user'], $schema); + } + + return array_map('trim', $schema); + } + + /** + * Gets names of all existing schemas in the current users search path. + * + * This is a PostgreSQL only function. + * + * @return string[] + */ + public function getExistingSchemaSearchPaths() + { + if ($this->existingSchemaPaths === null) { + $this->determineExistingSchemaSearchPaths(); + } + + assert($this->existingSchemaPaths !== null); + + return $this->existingSchemaPaths; + } + + /** + * Sets or resets the order of the existing schemas in the current search path of the user. + * + * This is a PostgreSQL only function. + * + * @return void + */ + public function determineExistingSchemaSearchPaths() + { + $names = $this->getSchemaNames(); + $paths = $this->getSchemaSearchPaths(); + + $this->existingSchemaPaths = array_filter($paths, static function ($v) use ($names) { + return in_array($v, $names); + }); + } + + /** + * {@inheritdoc} + */ + public function dropDatabase($database) + { + try { + parent::dropDatabase($database); + } catch (DriverException $exception) { + // If we have a SQLSTATE 55006, the drop database operation failed + // because of active connections on the database. + // To force dropping the database, we first have to close all active connections + // on that database and issue the drop database operation again. + if ($exception->getSQLState() !== '55006') { + throw $exception; + } + + assert($this->_platform instanceof PostgreSqlPlatform); + + $this->_execSql( + [ + $this->_platform->getDisallowDatabaseConnectionsSQL($database), + $this->_platform->getCloseActiveDatabaseConnectionsSQL($database), + ] + ); + + parent::dropDatabase($database); + } + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + { + $onUpdate = null; + $onDelete = null; + $localColumns = []; + $foreignColumns = []; + $foreignTable = null; + + if (preg_match('(ON UPDATE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', $tableForeignKey['condef'], $match)) { + $onUpdate = $match[1]; + } + + if (preg_match('(ON DELETE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', $tableForeignKey['condef'], $match)) { + $onDelete = $match[1]; + } + + $result = preg_match('/FOREIGN KEY \((.+)\) REFERENCES (.+)\((.+)\)/', $tableForeignKey['condef'], $values); + assert($result === 1); + + // PostgreSQL returns identifiers that are keywords with quotes, we need them later, don't get + // the idea to trim them here. + $localColumns = array_map('trim', explode(',', $values[1])); + $foreignColumns = array_map('trim', explode(',', $values[3])); + $foreignTable = $values[2]; + + return new ForeignKeyConstraint( + $localColumns, + $foreignTable, + $foreignColumns, + $tableForeignKey['conname'], + ['onUpdate' => $onUpdate, 'onDelete' => $onDelete] + ); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTriggerDefinition($trigger) + { + return $trigger['trigger_name']; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableViewDefinition($view) + { + return new View($view['schemaname'] . '.' . $view['viewname'], $view['definition']); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableUserDefinition($user) + { + return [ + 'user' => $user['usename'], + 'password' => $user['passwd'], + ]; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableDefinition($table) + { + $schemas = $this->getExistingSchemaSearchPaths(); + $firstSchema = array_shift($schemas); + + if ($table['schema_name'] === $firstSchema) { + return $table['table_name']; + } + + return $table['schema_name'] . '.' . $table['table_name']; + } + + /** + * {@inheritdoc} + * + * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + { + $buffer = []; + foreach ($tableIndexes as $row) { + $colNumbers = array_map('intval', explode(' ', $row['indkey'])); + $columnNameSql = sprintf( + 'SELECT attnum, attname FROM pg_attribute WHERE attrelid=%d AND attnum IN (%s) ORDER BY attnum ASC', + $row['indrelid'], + implode(' ,', $colNumbers) + ); + + $indexColumns = $this->_conn->fetchAllAssociative($columnNameSql); + + // required for getting the order of the columns right. + foreach ($colNumbers as $colNum) { + foreach ($indexColumns as $colRow) { + if ($colNum !== $colRow['attnum']) { + continue; + } + + $buffer[] = [ + 'key_name' => $row['relname'], + 'column_name' => trim($colRow['attname']), + 'non_unique' => ! $row['indisunique'], + 'primary' => $row['indisprimary'], + 'where' => $row['where'], + ]; + } + } + } + + return parent::_getPortableTableIndexesList($buffer, $tableName); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableDatabaseDefinition($database) + { + return $database['datname']; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableSequencesList($sequences) + { + $sequenceDefinitions = []; + + foreach ($sequences as $sequence) { + if ($sequence['schemaname'] !== 'public') { + $sequenceName = $sequence['schemaname'] . '.' . $sequence['relname']; + } else { + $sequenceName = $sequence['relname']; + } + + $sequenceDefinitions[$sequenceName] = $sequence; + } + + $list = []; + + foreach ($this->filterAssetNames(array_keys($sequenceDefinitions)) as $sequenceName) { + $list[] = $this->_getPortableSequenceDefinition($sequenceDefinitions[$sequenceName]); + } + + return $list; + } + + /** + * {@inheritdoc} + */ + protected function getPortableNamespaceDefinition(array $namespace) + { + return $namespace['nspname']; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableSequenceDefinition($sequence) + { + if ($sequence['schemaname'] !== 'public') { + $sequenceName = $sequence['schemaname'] . '.' . $sequence['relname']; + } else { + $sequenceName = $sequence['relname']; + } + + if (! isset($sequence['increment_by'], $sequence['min_value'])) { + /** @var string[] $data */ + $data = $this->_conn->fetchAssoc( + 'SELECT min_value, increment_by FROM ' . $this->_platform->quoteIdentifier($sequenceName) + ); + + $sequence += $data; + } + + return new Sequence($sequenceName, (int) $sequence['increment_by'], (int) $sequence['min_value']); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableColumnDefinition($tableColumn) + { + $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); + + if (strtolower($tableColumn['type']) === 'varchar' || strtolower($tableColumn['type']) === 'bpchar') { + // get length from varchar definition + $length = preg_replace('~.*\(([0-9]*)\).*~', '$1', $tableColumn['complete_type']); + $tableColumn['length'] = $length; + } + + $matches = []; + + $autoincrement = false; + + if ( + $tableColumn['default'] !== null + && preg_match("/^nextval\('(.*)'(::.*)?\)$/", $tableColumn['default'], $matches) === 1 + ) { + $tableColumn['sequence'] = $matches[1]; + $tableColumn['default'] = null; + $autoincrement = true; + } + + if ($tableColumn['default'] !== null) { + if (preg_match("/^['(](.*)[')]::/", $tableColumn['default'], $matches) === 1) { + $tableColumn['default'] = $matches[1]; + } elseif (preg_match('/^NULL::/', $tableColumn['default']) === 1) { + $tableColumn['default'] = null; + } + } + + $length = $tableColumn['length'] ?? null; + if ($length === '-1' && isset($tableColumn['atttypmod'])) { + $length = $tableColumn['atttypmod'] - 4; + } + + if ((int) $length <= 0) { + $length = null; + } + + $fixed = null; + + if (! isset($tableColumn['name'])) { + $tableColumn['name'] = ''; + } + + $precision = null; + $scale = null; + $jsonb = null; + + $dbType = strtolower($tableColumn['type']); + if ( + $tableColumn['domain_type'] !== null + && $tableColumn['domain_type'] !== '' + && ! $this->_platform->hasDoctrineTypeMappingFor($tableColumn['type']) + ) { + $dbType = strtolower($tableColumn['domain_type']); + $tableColumn['complete_type'] = $tableColumn['domain_complete_type']; + } + + $type = $this->_platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); + $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); + + switch ($dbType) { + case 'smallint': + case 'int2': + $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); + $length = null; + break; + + case 'int': + case 'int4': + case 'integer': + $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); + $length = null; + break; + + case 'bigint': + case 'int8': + $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); + $length = null; + break; + + case 'bool': + case 'boolean': + if ($tableColumn['default'] === 'true') { + $tableColumn['default'] = true; + } + + if ($tableColumn['default'] === 'false') { + $tableColumn['default'] = false; + } + + $length = null; + break; + + case 'text': + case '_varchar': + case 'varchar': + $tableColumn['default'] = $this->parseDefaultExpression($tableColumn['default']); + $fixed = false; + break; + case 'interval': + $fixed = false; + break; + + case 'char': + case 'bpchar': + $fixed = true; + break; + + case 'float': + case 'float4': + case 'float8': + case 'double': + case 'double precision': + case 'real': + case 'decimal': + case 'money': + case 'numeric': + $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); + + if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['complete_type'], $match)) { + $precision = $match[1]; + $scale = $match[2]; + $length = null; + } + + break; + + case 'year': + $length = null; + break; + + // PostgreSQL 9.4+ only + case 'jsonb': + $jsonb = true; + break; + } + + if ($tableColumn['default'] && preg_match("('([^']+)'::)", $tableColumn['default'], $match)) { + $tableColumn['default'] = $match[1]; + } + + $options = [ + 'length' => $length, + 'notnull' => (bool) $tableColumn['isnotnull'], + 'default' => $tableColumn['default'], + 'precision' => $precision, + 'scale' => $scale, + 'fixed' => $fixed, + 'unsigned' => false, + 'autoincrement' => $autoincrement, + 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' + ? $tableColumn['comment'] + : null, + ]; + + $column = new Column($tableColumn['field'], Type::getType($type), $options); + + if (isset($tableColumn['collation']) && ! empty($tableColumn['collation'])) { + $column->setPlatformOption('collation', $tableColumn['collation']); + } + + if (in_array($column->getType()->getName(), [Types::JSON_ARRAY, Types::JSON], true)) { + $column->setPlatformOption('jsonb', $jsonb); + } + + return $column; + } + + /** + * PostgreSQL 9.4 puts parentheses around negative numeric default values that need to be stripped eventually. + * + * @param mixed $defaultValue + * + * @return mixed + */ + private function fixVersion94NegativeNumericDefaultValue($defaultValue) + { + if ($defaultValue !== null && strpos($defaultValue, '(') === 0) { + return trim($defaultValue, '()'); + } + + return $defaultValue; + } + + /** + * Parses a default value expression as given by PostgreSQL + */ + private function parseDefaultExpression(?string $default): ?string + { + if ($default === null) { + return $default; + } + + return str_replace("''", "'", $default); + } + + /** + * {@inheritdoc} + */ + public function listTableDetails($name): Table + { + $table = parent::listTableDetails($name); + + $platform = $this->_platform; + assert($platform instanceof PostgreSqlPlatform); + $sql = $platform->getListTableMetadataSQL($name); + + $tableOptions = $this->_conn->fetchAssoc($sql); + + if ($tableOptions !== false) { + $table->addOption('comment', $tableOptions['table_comment']); + } + + return $table; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php new file mode 100755 index 0000000..4cd0f32 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php @@ -0,0 +1,236 @@ +startDatabase($database); + } + + /** + * {@inheritdoc} + * + * Tries stopping a database before dropping + * as SQL Anywhere needs a database to be stopped + * before it can be dropped. + * + * @see stopDatabase + */ + public function dropDatabase($database) + { + $this->tryMethod('stopDatabase', $database); + parent::dropDatabase($database); + } + + /** + * Starts a database. + * + * @param string $database The name of the database to start. + * + * @return void + */ + public function startDatabase($database) + { + assert($this->_platform instanceof SQLAnywherePlatform); + $this->_execSql($this->_platform->getStartDatabaseSQL($database)); + } + + /** + * Stops a database. + * + * @param string $database The name of the database to stop. + * + * @return void + */ + public function stopDatabase($database) + { + assert($this->_platform instanceof SQLAnywherePlatform); + $this->_execSql($this->_platform->getStopDatabaseSQL($database)); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableDatabaseDefinition($database) + { + return $database['name']; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableSequenceDefinition($sequence) + { + return new Sequence($sequence['sequence_name'], $sequence['increment_by'], $sequence['start_with']); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableColumnDefinition($tableColumn) + { + $type = $this->_platform->getDoctrineTypeMapping($tableColumn['type']); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); + $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); + $precision = null; + $scale = null; + $fixed = false; + $default = null; + + if ($tableColumn['default'] !== null) { + // Strip quotes from default value. + $default = preg_replace(["/^'(.*)'$/", "/''/"], ['$1', "'"], $tableColumn['default']); + + if ($default === 'autoincrement') { + $default = null; + } + } + + switch ($tableColumn['type']) { + case 'binary': + case 'char': + case 'nchar': + $fixed = true; + break; + } + + switch ($type) { + case 'decimal': + case 'float': + $precision = $tableColumn['length']; + $scale = $tableColumn['scale']; + break; + } + + return new Column( + $tableColumn['column_name'], + Type::getType($type), + [ + 'length' => $type === 'string' ? $tableColumn['length'] : null, + 'precision' => $precision, + 'scale' => $scale, + 'unsigned' => (bool) $tableColumn['unsigned'], + 'fixed' => $fixed, + 'notnull' => (bool) $tableColumn['notnull'], + 'default' => $default, + 'autoincrement' => (bool) $tableColumn['autoincrement'], + 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' + ? $tableColumn['comment'] + : null, + ] + ); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableDefinition($table) + { + return $table['table_name']; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + { + return new ForeignKeyConstraint( + $tableForeignKey['local_columns'], + $tableForeignKey['foreign_table'], + $tableForeignKey['foreign_columns'], + $tableForeignKey['name'], + $tableForeignKey['options'] + ); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableForeignKeysList($tableForeignKeys) + { + $foreignKeys = []; + + foreach ($tableForeignKeys as $tableForeignKey) { + if (! isset($foreignKeys[$tableForeignKey['index_name']])) { + $foreignKeys[$tableForeignKey['index_name']] = [ + 'local_columns' => [$tableForeignKey['local_column']], + 'foreign_table' => $tableForeignKey['foreign_table'], + 'foreign_columns' => [$tableForeignKey['foreign_column']], + 'name' => $tableForeignKey['index_name'], + 'options' => [ + 'notnull' => $tableForeignKey['notnull'], + 'match' => $tableForeignKey['match'], + 'onUpdate' => $tableForeignKey['on_update'], + 'onDelete' => $tableForeignKey['on_delete'], + 'check_on_commit' => $tableForeignKey['check_on_commit'], + 'clustered' => $tableForeignKey['clustered'], + 'for_olap_workload' => $tableForeignKey['for_olap_workload'], + ], + ]; + } else { + $foreignKeys[$tableForeignKey['index_name']]['local_columns'][] = $tableForeignKey['local_column']; + $foreignKeys[$tableForeignKey['index_name']]['foreign_columns'][] = $tableForeignKey['foreign_column']; + } + } + + return parent::_getPortableTableForeignKeysList($foreignKeys); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + { + foreach ($tableIndexes as &$tableIndex) { + $tableIndex['primary'] = (bool) $tableIndex['primary']; + $tableIndex['flags'] = []; + + if ($tableIndex['clustered']) { + $tableIndex['flags'][] = 'clustered'; + } + + if ($tableIndex['with_nulls_not_distinct']) { + $tableIndex['flags'][] = 'with_nulls_not_distinct'; + } + + if (! $tableIndex['for_olap_workload']) { + continue; + } + + $tableIndex['flags'][] = 'for_olap_workload'; + } + + return parent::_getPortableTableIndexesList($tableIndexes, $tableName); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableViewDefinition($view) + { + $definition = preg_replace('/^.*\s+as\s+SELECT(.*)/i', 'SELECT$1', $view['view_def']); + + return new View($view['table_name'], $definition); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php new file mode 100755 index 0000000..1454fa2 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php @@ -0,0 +1,347 @@ +getPrevious(); + assert($exception instanceof Throwable); + + if (! $exception instanceof Exception) { + throw $exception; + } + + // If we have a error code 3702, the drop database operation failed + // because of active connections on the database. + // To force dropping the database, we first have to close all active connections + // on that database and issue the drop database operation again. + if ($exception->getErrorCode() !== 3702) { + throw $exception; + } + + $this->closeActiveDatabaseConnections($database); + + parent::dropDatabase($database); + } + } + + /** + * {@inheritdoc} + */ + protected function _getPortableSequenceDefinition($sequence) + { + return new Sequence($sequence['name'], (int) $sequence['increment'], (int) $sequence['start_value']); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableColumnDefinition($tableColumn) + { + $dbType = strtok($tableColumn['type'], '(), '); + assert(is_string($dbType)); + + $fixed = null; + $length = (int) $tableColumn['length']; + $default = $tableColumn['default']; + + if (! isset($tableColumn['name'])) { + $tableColumn['name'] = ''; + } + + if ($default !== null) { + $default = $this->parseDefaultExpression($default); + } + + switch ($dbType) { + case 'nchar': + case 'nvarchar': + case 'ntext': + // Unicode data requires 2 bytes per character + $length /= 2; + break; + + case 'varchar': + // TEXT type is returned as VARCHAR(MAX) with a length of -1 + if ($length === -1) { + $dbType = 'text'; + } + + break; + } + + if ($dbType === 'char' || $dbType === 'nchar' || $dbType === 'binary') { + $fixed = true; + } + + $type = $this->_platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); + $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); + + $options = [ + 'length' => $length === 0 || ! in_array($type, ['text', 'string']) ? null : $length, + 'unsigned' => false, + 'fixed' => (bool) $fixed, + 'default' => $default, + 'notnull' => (bool) $tableColumn['notnull'], + 'scale' => $tableColumn['scale'], + 'precision' => $tableColumn['precision'], + 'autoincrement' => (bool) $tableColumn['autoincrement'], + 'comment' => $tableColumn['comment'] !== '' ? $tableColumn['comment'] : null, + ]; + + $column = new Column($tableColumn['name'], Type::getType($type), $options); + + if (isset($tableColumn['collation']) && $tableColumn['collation'] !== 'NULL') { + $column->setPlatformOption('collation', $tableColumn['collation']); + } + + return $column; + } + + private function parseDefaultExpression(string $value): ?string + { + while (preg_match('/^\((.*)\)$/s', $value, $matches)) { + $value = $matches[1]; + } + + if ($value === 'NULL') { + return null; + } + + if (preg_match('/^\'(.*)\'$/s', $value, $matches)) { + $value = str_replace("''", "'", $matches[1]); + } + + if ($value === 'getdate()') { + return $this->_platform->getCurrentTimestampSQL(); + } + + return $value; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableForeignKeysList($tableForeignKeys) + { + $foreignKeys = []; + + foreach ($tableForeignKeys as $tableForeignKey) { + $name = $tableForeignKey['ForeignKey']; + + if (! isset($foreignKeys[$name])) { + $foreignKeys[$name] = [ + 'local_columns' => [$tableForeignKey['ColumnName']], + 'foreign_table' => $tableForeignKey['ReferenceTableName'], + 'foreign_columns' => [$tableForeignKey['ReferenceColumnName']], + 'name' => $name, + 'options' => [ + 'onUpdate' => str_replace('_', ' ', $tableForeignKey['update_referential_action_desc']), + 'onDelete' => str_replace('_', ' ', $tableForeignKey['delete_referential_action_desc']), + ], + ]; + } else { + $foreignKeys[$name]['local_columns'][] = $tableForeignKey['ColumnName']; + $foreignKeys[$name]['foreign_columns'][] = $tableForeignKey['ReferenceColumnName']; + } + } + + return parent::_getPortableTableForeignKeysList($foreignKeys); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + { + foreach ($tableIndexes as &$tableIndex) { + $tableIndex['non_unique'] = (bool) $tableIndex['non_unique']; + $tableIndex['primary'] = (bool) $tableIndex['primary']; + $tableIndex['flags'] = $tableIndex['flags'] ? [$tableIndex['flags']] : null; + } + + return parent::_getPortableTableIndexesList($tableIndexes, $tableName); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + { + return new ForeignKeyConstraint( + $tableForeignKey['local_columns'], + $tableForeignKey['foreign_table'], + $tableForeignKey['foreign_columns'], + $tableForeignKey['name'], + $tableForeignKey['options'] + ); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableDefinition($table) + { + if (isset($table['schema_name']) && $table['schema_name'] !== 'dbo') { + return $table['schema_name'] . '.' . $table['name']; + } + + return $table['name']; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableDatabaseDefinition($database) + { + return $database['name']; + } + + /** + * {@inheritdoc} + */ + protected function getPortableNamespaceDefinition(array $namespace) + { + return $namespace['name']; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableViewDefinition($view) + { + // @todo + return new View($view['name'], ''); + } + + /** + * {@inheritdoc} + */ + public function listTableIndexes($table) + { + $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase()); + + try { + $tableIndexes = $this->_conn->fetchAllAssociative($sql); + } catch (DBALException $e) { + if (strpos($e->getMessage(), 'SQLSTATE [01000, 15472]') === 0) { + return []; + } + + throw $e; + } + + return $this->_getPortableTableIndexesList($tableIndexes, $table); + } + + /** + * {@inheritdoc} + */ + public function alterTable(TableDiff $tableDiff) + { + if (count($tableDiff->removedColumns) > 0) { + foreach ($tableDiff->removedColumns as $col) { + $columnConstraintSql = $this->getColumnConstraintSQL($tableDiff->name, $col->getName()); + foreach ($this->_conn->fetchAllAssociative($columnConstraintSql) as $constraint) { + $this->_conn->exec( + sprintf( + 'ALTER TABLE %s DROP CONSTRAINT %s', + $tableDiff->name, + $constraint['Name'] + ) + ); + } + } + } + + parent::alterTable($tableDiff); + } + + /** + * Returns the SQL to retrieve the constraints for a given column. + * + * @param string $table + * @param string $column + * + * @return string + */ + private function getColumnConstraintSQL($table, $column) + { + return "SELECT sysobjects.[Name] + FROM sysobjects INNER JOIN (SELECT [Name],[ID] FROM sysobjects WHERE XType = 'U') AS Tab + ON Tab.[ID] = sysobjects.[Parent_Obj] + INNER JOIN sys.default_constraints DefCons ON DefCons.[object_id] = sysobjects.[ID] + INNER JOIN syscolumns Col ON Col.[ColID] = DefCons.[parent_column_id] AND Col.[ID] = Tab.[ID] + WHERE Col.[Name] = " . $this->_conn->quote($column) . ' AND Tab.[Name] = ' . $this->_conn->quote($table) . ' + ORDER BY Col.[Name]'; + } + + /** + * Closes currently active connections on the given database. + * + * This is useful to force DROP DATABASE operations which could fail because of active connections. + * + * @param string $database The name of the database to close currently active connections for. + * + * @return void + */ + private function closeActiveDatabaseConnections($database) + { + $database = new Identifier($database); + + $this->_execSql( + sprintf( + 'ALTER DATABASE %s SET SINGLE_USER WITH ROLLBACK IMMEDIATE', + $database->getQuotedName($this->_platform) + ) + ); + } + + /** + * @param string $name + */ + public function listTableDetails($name): Table + { + $table = parent::listTableDetails($name); + + $platform = $this->_platform; + assert($platform instanceof SQLServerPlatform); + $sql = $platform->getListTableMetadataSQL($name); + + $tableOptions = $this->_conn->fetchAssociative($sql); + + if ($tableOptions !== false) { + $table->addOption('comment', $tableOptions['table_comment']); + } + + return $table; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Schema.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Schema.php new file mode 100755 index 0000000..24fc47b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Schema.php @@ -0,0 +1,482 @@ +_schemaConfig = $schemaConfig; + $this->_setName($schemaConfig->getName() ?: 'public'); + + foreach ($namespaces as $namespace) { + $this->createNamespace($namespace); + } + + foreach ($tables as $table) { + $this->_addTable($table); + } + + foreach ($sequences as $sequence) { + $this->_addSequence($sequence); + } + } + + /** + * @return bool + */ + public function hasExplicitForeignKeyIndexes() + { + return $this->_schemaConfig->hasExplicitForeignKeyIndexes(); + } + + /** + * @return void + * + * @throws SchemaException + */ + protected function _addTable(Table $table) + { + $namespaceName = $table->getNamespaceName(); + $tableName = $table->getFullQualifiedName($this->getName()); + + if (isset($this->_tables[$tableName])) { + throw SchemaException::tableAlreadyExists($tableName); + } + + if ( + $namespaceName !== null + && ! $table->isInDefaultNamespace($this->getName()) + && ! $this->hasNamespace($namespaceName) + ) { + $this->createNamespace($namespaceName); + } + + $this->_tables[$tableName] = $table; + $table->setSchemaConfig($this->_schemaConfig); + } + + /** + * @return void + * + * @throws SchemaException + */ + protected function _addSequence(Sequence $sequence) + { + $namespaceName = $sequence->getNamespaceName(); + $seqName = $sequence->getFullQualifiedName($this->getName()); + + if (isset($this->_sequences[$seqName])) { + throw SchemaException::sequenceAlreadyExists($seqName); + } + + if ( + $namespaceName !== null + && ! $sequence->isInDefaultNamespace($this->getName()) + && ! $this->hasNamespace($namespaceName) + ) { + $this->createNamespace($namespaceName); + } + + $this->_sequences[$seqName] = $sequence; + } + + /** + * Returns the namespaces of this schema. + * + * @return string[] A list of namespace names. + */ + public function getNamespaces() + { + return $this->namespaces; + } + + /** + * Gets all tables of this schema. + * + * @return Table[] + */ + public function getTables() + { + return $this->_tables; + } + + /** + * @param string $name + * + * @return Table + * + * @throws SchemaException + */ + public function getTable($name) + { + $name = $this->getFullQualifiedAssetName($name); + if (! isset($this->_tables[$name])) { + throw SchemaException::tableDoesNotExist($name); + } + + return $this->_tables[$name]; + } + + /** + * @param string $name + * + * @return string + */ + private function getFullQualifiedAssetName($name) + { + $name = $this->getUnquotedAssetName($name); + + if (strpos($name, '.') === false) { + $name = $this->getName() . '.' . $name; + } + + return strtolower($name); + } + + /** + * Returns the unquoted representation of a given asset name. + * + * @param string $assetName Quoted or unquoted representation of an asset name. + * + * @return string + */ + private function getUnquotedAssetName($assetName) + { + if ($this->isIdentifierQuoted($assetName)) { + return $this->trimQuotes($assetName); + } + + return $assetName; + } + + /** + * Does this schema have a namespace with the given name? + * + * @param string $name + * + * @return bool + */ + public function hasNamespace($name) + { + $name = strtolower($this->getUnquotedAssetName($name)); + + return isset($this->namespaces[$name]); + } + + /** + * Does this schema have a table with the given name? + * + * @param string $name + * + * @return bool + */ + public function hasTable($name) + { + $name = $this->getFullQualifiedAssetName($name); + + return isset($this->_tables[$name]); + } + + /** + * Gets all table names, prefixed with a schema name, even the default one if present. + * + * @return string[] + */ + public function getTableNames() + { + return array_keys($this->_tables); + } + + /** + * @param string $name + * + * @return bool + */ + public function hasSequence($name) + { + $name = $this->getFullQualifiedAssetName($name); + + return isset($this->_sequences[$name]); + } + + /** + * @param string $name + * + * @return Sequence + * + * @throws SchemaException + */ + public function getSequence($name) + { + $name = $this->getFullQualifiedAssetName($name); + if (! $this->hasSequence($name)) { + throw SchemaException::sequenceDoesNotExist($name); + } + + return $this->_sequences[$name]; + } + + /** + * @return Sequence[] + */ + public function getSequences() + { + return $this->_sequences; + } + + /** + * Creates a new namespace. + * + * @param string $name The name of the namespace to create. + * + * @return Schema This schema instance. + * + * @throws SchemaException + */ + public function createNamespace($name) + { + $unquotedName = strtolower($this->getUnquotedAssetName($name)); + + if (isset($this->namespaces[$unquotedName])) { + throw SchemaException::namespaceAlreadyExists($unquotedName); + } + + $this->namespaces[$unquotedName] = $name; + + return $this; + } + + /** + * Creates a new table. + * + * @param string $name + * + * @return Table + */ + public function createTable($name) + { + $table = new Table($name); + $this->_addTable($table); + + foreach ($this->_schemaConfig->getDefaultTableOptions() as $option => $value) { + $table->addOption($option, $value); + } + + return $table; + } + + /** + * Renames a table. + * + * @param string $oldName + * @param string $newName + * + * @return Schema + */ + public function renameTable($oldName, $newName) + { + $table = $this->getTable($oldName); + $table->_setName($newName); + + $this->dropTable($oldName); + $this->_addTable($table); + + return $this; + } + + /** + * Drops a table from the schema. + * + * @param string $name + * + * @return Schema + */ + public function dropTable($name) + { + $name = $this->getFullQualifiedAssetName($name); + $this->getTable($name); + unset($this->_tables[$name]); + + return $this; + } + + /** + * Creates a new sequence. + * + * @param string $name + * @param int $allocationSize + * @param int $initialValue + * + * @return Sequence + */ + public function createSequence($name, $allocationSize = 1, $initialValue = 1) + { + $seq = new Sequence($name, $allocationSize, $initialValue); + $this->_addSequence($seq); + + return $seq; + } + + /** + * @param string $name + * + * @return Schema + */ + public function dropSequence($name) + { + $name = $this->getFullQualifiedAssetName($name); + unset($this->_sequences[$name]); + + return $this; + } + + /** + * Returns an array of necessary SQL queries to create the schema on the given platform. + * + * @return string[] + */ + public function toSql(AbstractPlatform $platform) + { + $sqlCollector = new CreateSchemaSqlCollector($platform); + $this->visit($sqlCollector); + + return $sqlCollector->getQueries(); + } + + /** + * Return an array of necessary SQL queries to drop the schema on the given platform. + * + * @return string[] + */ + public function toDropSql(AbstractPlatform $platform) + { + $dropSqlCollector = new DropSchemaSqlCollector($platform); + $this->visit($dropSqlCollector); + + return $dropSqlCollector->getQueries(); + } + + /** + * @return string[] + */ + public function getMigrateToSql(Schema $toSchema, AbstractPlatform $platform) + { + $comparator = new Comparator(); + $schemaDiff = $comparator->compare($this, $toSchema); + + return $schemaDiff->toSql($platform); + } + + /** + * @return string[] + */ + public function getMigrateFromSql(Schema $fromSchema, AbstractPlatform $platform) + { + $comparator = new Comparator(); + $schemaDiff = $comparator->compare($fromSchema, $this); + + return $schemaDiff->toSql($platform); + } + + /** + * @return void + */ + public function visit(Visitor $visitor) + { + $visitor->acceptSchema($this); + + if ($visitor instanceof NamespaceVisitor) { + foreach ($this->namespaces as $namespace) { + $visitor->acceptNamespace($namespace); + } + } + + foreach ($this->_tables as $table) { + $table->visit($visitor); + } + + foreach ($this->_sequences as $sequence) { + $sequence->visit($visitor); + } + } + + /** + * Cloning a Schema triggers a deep clone of all related assets. + * + * @return void + */ + public function __clone() + { + foreach ($this->_tables as $k => $table) { + $this->_tables[$k] = clone $table; + } + + foreach ($this->_sequences as $k => $sequence) { + $this->_sequences[$k] = clone $sequence; + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaConfig.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaConfig.php new file mode 100755 index 0000000..b8c3502 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaConfig.php @@ -0,0 +1,100 @@ +hasExplicitForeignKeyIndexes; + } + + /** + * @param bool $flag + * + * @return void + */ + public function setExplicitForeignKeyIndexes($flag) + { + $this->hasExplicitForeignKeyIndexes = (bool) $flag; + } + + /** + * @param int $length + * + * @return void + */ + public function setMaxIdentifierLength($length) + { + $this->maxIdentifierLength = (int) $length; + } + + /** + * @return int + */ + public function getMaxIdentifierLength() + { + return $this->maxIdentifierLength; + } + + /** + * Gets the default namespace of schema objects. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Sets the default namespace name of schema objects. + * + * @param string $name The value to set. + * + * @return void + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * Gets the default options that are passed to Table instances created with + * Schema#createTable(). + * + * @return mixed[] + */ + public function getDefaultTableOptions() + { + return $this->defaultTableOptions; + } + + /** + * @param mixed[] $defaultTableOptions + * + * @return void + */ + public function setDefaultTableOptions(array $defaultTableOptions) + { + $this->defaultTableOptions = $defaultTableOptions; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaDiff.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaDiff.php new file mode 100755 index 0000000..67fb9bb --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaDiff.php @@ -0,0 +1,170 @@ +newTables = $newTables; + $this->changedTables = $changedTables; + $this->removedTables = $removedTables; + $this->fromSchema = $fromSchema; + } + + /** + * The to save sql mode ensures that the following things don't happen: + * + * 1. Tables are deleted + * 2. Sequences are deleted + * 3. Foreign Keys which reference tables that would otherwise be deleted. + * + * This way it is ensured that assets are deleted which might not be relevant to the metadata schema at all. + * + * @return string[] + */ + public function toSaveSql(AbstractPlatform $platform) + { + return $this->_toSql($platform, true); + } + + /** + * @return string[] + */ + public function toSql(AbstractPlatform $platform) + { + return $this->_toSql($platform, false); + } + + /** + * @param bool $saveMode + * + * @return string[] + */ + protected function _toSql(AbstractPlatform $platform, $saveMode = false) + { + $sql = []; + + if ($platform->supportsSchemas()) { + foreach ($this->newNamespaces as $newNamespace) { + $sql[] = $platform->getCreateSchemaSQL($newNamespace); + } + } + + if ($platform->supportsForeignKeyConstraints() && $saveMode === false) { + foreach ($this->orphanedForeignKeys as $orphanedForeignKey) { + $sql[] = $platform->getDropForeignKeySQL($orphanedForeignKey, $orphanedForeignKey->getLocalTable()); + } + } + + if ($platform->supportsSequences() === true) { + foreach ($this->changedSequences as $sequence) { + $sql[] = $platform->getAlterSequenceSQL($sequence); + } + + if ($saveMode === false) { + foreach ($this->removedSequences as $sequence) { + $sql[] = $platform->getDropSequenceSQL($sequence); + } + } + + foreach ($this->newSequences as $sequence) { + $sql[] = $platform->getCreateSequenceSQL($sequence); + } + } + + $foreignKeySql = []; + foreach ($this->newTables as $table) { + $sql = array_merge( + $sql, + $platform->getCreateTableSQL($table, AbstractPlatform::CREATE_INDEXES) + ); + + if (! $platform->supportsForeignKeyConstraints()) { + continue; + } + + foreach ($table->getForeignKeys() as $foreignKey) { + $foreignKeySql[] = $platform->getCreateForeignKeySQL($foreignKey, $table); + } + } + + $sql = array_merge($sql, $foreignKeySql); + + if ($saveMode === false) { + foreach ($this->removedTables as $table) { + $sql[] = $platform->getDropTableSQL($table); + } + } + + foreach ($this->changedTables as $tableDiff) { + $sql = array_merge($sql, $platform->getAlterTableSQL($tableDiff)); + } + + return $sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaException.php new file mode 100755 index 0000000..64f4b25 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaException.php @@ -0,0 +1,187 @@ +getName() . ' requires a named foreign key, ' . + 'but the given foreign key from (' . implode(', ', $foreignKey->getColumns()) . ') onto foreign table ' . + "'" . $foreignKey->getForeignTableName() . "' (" . implode(', ', $foreignKey->getForeignColumns()) . ')' . + ' is currently unnamed.' + ); + } + + /** + * @param string $changeName + * + * @return SchemaException + */ + public static function alterTableChangeNotSupported($changeName) + { + return new self( + sprintf("Alter table change not supported, given '%s'", $changeName) + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Sequence.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Sequence.php new file mode 100755 index 0000000..1cba86c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Sequence.php @@ -0,0 +1,140 @@ +_setName($name); + $this->setAllocationSize($allocationSize); + $this->setInitialValue($initialValue); + $this->cache = $cache; + } + + /** + * @return int + */ + public function getAllocationSize() + { + return $this->allocationSize; + } + + /** + * @return int + */ + public function getInitialValue() + { + return $this->initialValue; + } + + /** + * @return int|null + */ + public function getCache() + { + return $this->cache; + } + + /** + * @param int $allocationSize + * + * @return Sequence + */ + public function setAllocationSize($allocationSize) + { + $this->allocationSize = (int) $allocationSize ?: 1; + + return $this; + } + + /** + * @param int $initialValue + * + * @return Sequence + */ + public function setInitialValue($initialValue) + { + $this->initialValue = (int) $initialValue ?: 1; + + return $this; + } + + /** + * @param int $cache + * + * @return Sequence + */ + public function setCache($cache) + { + $this->cache = $cache; + + return $this; + } + + /** + * Checks if this sequence is an autoincrement sequence for a given table. + * + * This is used inside the comparator to not report sequences as missing, + * when the "from" schema implicitly creates the sequences. + * + * @return bool + */ + public function isAutoIncrementsFor(Table $table) + { + $primaryKey = $table->getPrimaryKey(); + + if ($primaryKey === null) { + return false; + } + + $pkColumns = $primaryKey->getColumns(); + + if (count($pkColumns) !== 1) { + return false; + } + + $column = $table->getColumn($pkColumns[0]); + + if (! $column->getAutoincrement()) { + return false; + } + + $sequenceName = $this->getShortestName($table->getNamespaceName()); + $tableName = $table->getShortestName($table->getNamespaceName()); + $tableSequenceName = sprintf('%s_%s_seq', $tableName, $column->getShortestName($table->getNamespaceName())); + + return $tableSequenceName === $sequenceName; + } + + /** + * @return void + */ + public function visit(Visitor $visitor) + { + $visitor->acceptSequence($this); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php new file mode 100755 index 0000000..841568a --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php @@ -0,0 +1,575 @@ +_conn->getParams(); + + $params['path'] = $database; + unset($params['memory']); + + $conn = DriverManager::getConnection($params); + $conn->connect(); + $conn->close(); + } + + /** + * {@inheritdoc} + */ + public function renameTable($name, $newName) + { + $tableDiff = new TableDiff($name); + $tableDiff->fromTable = $this->listTableDetails($name); + $tableDiff->newName = $newName; + $this->alterTable($tableDiff); + } + + /** + * {@inheritdoc} + */ + public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) + { + $tableDiff = $this->getTableDiffForAlterForeignKey($table); + $tableDiff->addedForeignKeys[] = $foreignKey; + + $this->alterTable($tableDiff); + } + + /** + * {@inheritdoc} + */ + public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) + { + $tableDiff = $this->getTableDiffForAlterForeignKey($table); + $tableDiff->changedForeignKeys[] = $foreignKey; + + $this->alterTable($tableDiff); + } + + /** + * {@inheritdoc} + */ + public function dropForeignKey($foreignKey, $table) + { + $tableDiff = $this->getTableDiffForAlterForeignKey($table); + $tableDiff->removedForeignKeys[] = $foreignKey; + + $this->alterTable($tableDiff); + } + + /** + * {@inheritdoc} + */ + public function listTableForeignKeys($table, $database = null) + { + if ($database === null) { + $database = $this->_conn->getDatabase(); + } + + $sql = $this->_platform->getListTableForeignKeysSQL($table, $database); + $tableForeignKeys = $this->_conn->fetchAllAssociative($sql); + + if (! empty($tableForeignKeys)) { + $createSql = $this->getCreateTableSQL($table); + + if ( + $createSql !== null && preg_match_all( + '# + (?:CONSTRAINT\s+([^\s]+)\s+)? + (?:FOREIGN\s+KEY[^\)]+\)\s*)? + REFERENCES\s+[^\s]+\s+(?:\([^\)]+\))? + (?: + [^,]*? + (NOT\s+DEFERRABLE|DEFERRABLE) + (?:\s+INITIALLY\s+(DEFERRED|IMMEDIATE))? + )?#isx', + $createSql, + $match + ) + ) { + $names = array_reverse($match[1]); + $deferrable = array_reverse($match[2]); + $deferred = array_reverse($match[3]); + } else { + $names = $deferrable = $deferred = []; + } + + foreach ($tableForeignKeys as $key => $value) { + $id = $value['id']; + + $tableForeignKeys[$key] = array_merge($tableForeignKeys[$key], [ + 'constraint_name' => isset($names[$id]) && $names[$id] !== '' ? $names[$id] : $id, + 'deferrable' => isset($deferrable[$id]) && strtolower($deferrable[$id]) === 'deferrable', + 'deferred' => isset($deferred[$id]) && strtolower($deferred[$id]) === 'deferred', + ]); + } + } + + return $this->_getPortableTableForeignKeysList($tableForeignKeys); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableDefinition($table) + { + return $table['name']; + } + + /** + * {@inheritdoc} + * + * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + { + $indexBuffer = []; + + // fetch primary + $indexArray = $this->_conn->fetchAllAssociative(sprintf( + 'PRAGMA TABLE_INFO (%s)', + $this->_conn->quote($tableName) + )); + + usort( + $indexArray, + /** + * @param array $a + * @param array $b + */ + static function (array $a, array $b): int { + if ($a['pk'] === $b['pk']) { + return $a['cid'] - $b['cid']; + } + + return $a['pk'] - $b['pk']; + } + ); + + foreach ($indexArray as $indexColumnRow) { + if ($indexColumnRow['pk'] === 0 || $indexColumnRow['pk'] === '0') { + continue; + } + + $indexBuffer[] = [ + 'key_name' => 'primary', + 'primary' => true, + 'non_unique' => false, + 'column_name' => $indexColumnRow['name'], + ]; + } + + // fetch regular indexes + foreach ($tableIndexes as $tableIndex) { + // Ignore indexes with reserved names, e.g. autoindexes + if (strpos($tableIndex['name'], 'sqlite_') === 0) { + continue; + } + + $keyName = $tableIndex['name']; + $idx = []; + $idx['key_name'] = $keyName; + $idx['primary'] = false; + $idx['non_unique'] = ! $tableIndex['unique']; + + $indexArray = $this->_conn->fetchAllAssociative(sprintf( + 'PRAGMA INDEX_INFO (%s)', + $this->_conn->quote($keyName) + )); + + foreach ($indexArray as $indexColumnRow) { + $idx['column_name'] = $indexColumnRow['name']; + $indexBuffer[] = $idx; + } + } + + return parent::_getPortableTableIndexesList($indexBuffer, $tableName); + } + + /** + * @deprecated + * + * @param array $tableIndex + * + * @return array + */ + protected function _getPortableTableIndexDefinition($tableIndex) + { + return [ + 'name' => $tableIndex['name'], + 'unique' => (bool) $tableIndex['unique'], + ]; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableColumnList($table, $database, $tableColumns) + { + $list = parent::_getPortableTableColumnList($table, $database, $tableColumns); + + // find column with autoincrement + $autoincrementColumn = null; + $autoincrementCount = 0; + + foreach ($tableColumns as $tableColumn) { + if ($tableColumn['pk'] === 0 || $tableColumn['pk'] === '0') { + continue; + } + + $autoincrementCount++; + if ($autoincrementColumn !== null || strtolower($tableColumn['type']) !== 'integer') { + continue; + } + + $autoincrementColumn = $tableColumn['name']; + } + + if ($autoincrementCount === 1 && $autoincrementColumn !== null) { + foreach ($list as $column) { + if ($autoincrementColumn !== $column->getName()) { + continue; + } + + $column->setAutoincrement(true); + } + } + + // inspect column collation and comments + $createSql = $this->getCreateTableSQL($table) ?? ''; + + foreach ($list as $columnName => $column) { + $type = $column->getType(); + + if ($type instanceof StringType || $type instanceof TextType) { + $column->setPlatformOption( + 'collation', + $this->parseColumnCollationFromSQL($columnName, $createSql) ?: 'BINARY' + ); + } + + $comment = $this->parseColumnCommentFromSQL($columnName, $createSql); + + if ($comment === null) { + continue; + } + + $type = $this->extractDoctrineTypeFromComment($comment, ''); + + if ($type !== '') { + $column->setType(Type::getType($type)); + + $comment = $this->removeDoctrineTypeFromComment($comment, $type); + } + + $column->setComment($comment); + } + + return $list; + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableColumnDefinition($tableColumn) + { + $parts = explode('(', $tableColumn['type']); + $tableColumn['type'] = trim($parts[0]); + if (isset($parts[1])) { + $length = trim($parts[1], ')'); + $tableColumn['length'] = $length; + } + + $dbType = strtolower($tableColumn['type']); + $length = $tableColumn['length'] ?? null; + $unsigned = false; + + if (strpos($dbType, ' unsigned') !== false) { + $dbType = str_replace(' unsigned', '', $dbType); + $unsigned = true; + } + + $fixed = false; + $type = $this->_platform->getDoctrineTypeMapping($dbType); + $default = $tableColumn['dflt_value']; + if ($default === 'NULL') { + $default = null; + } + + if ($default !== null) { + // SQLite returns the default value as a literal expression, so we need to parse it + if (preg_match('/^\'(.*)\'$/s', $default, $matches)) { + $default = str_replace("''", "'", $matches[1]); + } + } + + $notnull = (bool) $tableColumn['notnull']; + + if (! isset($tableColumn['name'])) { + $tableColumn['name'] = ''; + } + + $precision = null; + $scale = null; + + switch ($dbType) { + case 'char': + $fixed = true; + break; + case 'float': + case 'double': + case 'real': + case 'decimal': + case 'numeric': + if (isset($tableColumn['length'])) { + if (strpos($tableColumn['length'], ',') === false) { + $tableColumn['length'] .= ',0'; + } + + [$precision, $scale] = array_map('trim', explode(',', $tableColumn['length'])); + } + + $length = null; + break; + } + + $options = [ + 'length' => $length, + 'unsigned' => $unsigned, + 'fixed' => $fixed, + 'notnull' => $notnull, + 'default' => $default, + 'precision' => $precision, + 'scale' => $scale, + 'autoincrement' => false, + ]; + + return new Column($tableColumn['name'], Type::getType($type), $options); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableViewDefinition($view) + { + return new View($view['name'], $view['sql']); + } + + /** + * {@inheritdoc} + */ + protected function _getPortableTableForeignKeysList($tableForeignKeys) + { + $list = []; + foreach ($tableForeignKeys as $value) { + $value = array_change_key_case($value, CASE_LOWER); + $name = $value['constraint_name']; + if (! isset($list[$name])) { + if (! isset($value['on_delete']) || $value['on_delete'] === 'RESTRICT') { + $value['on_delete'] = null; + } + + if (! isset($value['on_update']) || $value['on_update'] === 'RESTRICT') { + $value['on_update'] = null; + } + + $list[$name] = [ + 'name' => $name, + 'local' => [], + 'foreign' => [], + 'foreignTable' => $value['table'], + 'onDelete' => $value['on_delete'], + 'onUpdate' => $value['on_update'], + 'deferrable' => $value['deferrable'], + 'deferred' => $value['deferred'], + ]; + } + + $list[$name]['local'][] = $value['from']; + + if ($value['to'] === null) { + continue; + } + + $list[$name]['foreign'][] = $value['to']; + } + + $result = []; + foreach ($list as $constraint) { + $result[] = new ForeignKeyConstraint( + array_values($constraint['local']), + $constraint['foreignTable'], + array_values($constraint['foreign']), + $constraint['name'], + [ + 'onDelete' => $constraint['onDelete'], + 'onUpdate' => $constraint['onUpdate'], + 'deferrable' => $constraint['deferrable'], + 'deferred' => $constraint['deferred'], + ] + ); + } + + return $result; + } + + /** + * @param Table|string $table + * + * @return TableDiff + * + * @throws Exception + */ + private function getTableDiffForAlterForeignKey($table) + { + if (! $table instanceof Table) { + $tableDetails = $this->tryMethod('listTableDetails', $table); + + if ($tableDetails === false) { + throw new Exception( + sprintf('Sqlite schema manager requires to modify foreign keys table definition "%s".', $table) + ); + } + + $table = $tableDetails; + } + + $tableDiff = new TableDiff($table->getName()); + $tableDiff->fromTable = $table; + + return $tableDiff; + } + + private function parseColumnCollationFromSQL(string $column, string $sql): ?string + { + $pattern = '{(?:\W' . preg_quote($column) . '\W|\W' + . preg_quote($this->_platform->quoteSingleIdentifier($column)) + . '\W)[^,(]+(?:\([^()]+\)[^,]*)?(?:(?:DEFAULT|CHECK)\s*(?:\(.*?\))?[^,]*)*COLLATE\s+["\']?([^\s,"\')]+)}is'; + + if (preg_match($pattern, $sql, $match) !== 1) { + return null; + } + + return $match[1]; + } + + private function parseTableCommentFromSQL(string $table, string $sql): ?string + { + $pattern = '/\s* # Allow whitespace characters at start of line +CREATE\sTABLE # Match "CREATE TABLE" +(?:\W"' . preg_quote($this->_platform->quoteSingleIdentifier($table), '/') . '"\W|\W' . preg_quote($table, '/') + . '\W) # Match table name (quoted and unquoted) +( # Start capture + (?:\s*--[^\n]*\n?)+ # Capture anything that starts with whitespaces followed by -- until the end of the line(s) +)/ix'; + + if (preg_match($pattern, $sql, $match) !== 1) { + return null; + } + + $comment = preg_replace('{^\s*--}m', '', rtrim($match[1], "\n")); + + return $comment === '' ? null : $comment; + } + + private function parseColumnCommentFromSQL(string $column, string $sql): ?string + { + $pattern = '{[\s(,](?:\W' . preg_quote($this->_platform->quoteSingleIdentifier($column)) + . '\W|\W' . preg_quote($column) . '\W)(?:\([^)]*?\)|[^,(])*?,?((?:(?!\n))(?:\s*--[^\n]*\n?)+)}i'; + + if (preg_match($pattern, $sql, $match) !== 1) { + return null; + } + + $comment = preg_replace('{^\s*--}m', '', rtrim($match[1], "\n")); + + return $comment === '' ? null : $comment; + } + + private function getCreateTableSQL(string $table): ?string + { + return $this->_conn->fetchColumn( + <<<'SQL' +SELECT sql + FROM ( + SELECT * + FROM sqlite_master + UNION ALL + SELECT * + FROM sqlite_temp_master + ) +WHERE type = 'table' +AND name = ? +SQL + , + [$table] + ) ?: null; + } + + /** + * @param string $name + */ + public function listTableDetails($name): Table + { + $table = parent::listTableDetails($name); + + $tableCreateSql = $this->getCreateTableSQL($name) ?? ''; + + $comment = $this->parseTableCommentFromSQL($name, $tableCreateSql); + + if ($comment !== null) { + $table->addOption('comment', $comment); + } + + return $table; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php new file mode 100755 index 0000000..85f4ae6 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php @@ -0,0 +1,56 @@ +conn = $conn; + + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4213', + 'SchemaSynchronizer API is deprecated without a replacement and will be removed in DBAL 3.0' + ); + } + + /** + * @param string[] $sql + * + * @return void + */ + protected function processSqlSafely(array $sql) + { + foreach ($sql as $s) { + try { + $this->conn->exec($s); + } catch (Throwable $e) { + } + } + } + + /** + * @param string[] $sql + * + * @return void + */ + protected function processSql(array $sql) + { + foreach ($sql as $s) { + $this->conn->exec($s); + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php new file mode 100755 index 0000000..a10d3b7 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php @@ -0,0 +1,74 @@ +platform = $conn->getDatabasePlatform(); + } + + /** + * {@inheritdoc} + */ + public function getCreateSchema(Schema $createSchema) + { + return $createSchema->toSql($this->platform); + } + + /** + * {@inheritdoc} + */ + public function getUpdateSchema(Schema $toSchema, $noDrops = false) + { + $comparator = new Comparator(); + $sm = $this->conn->getSchemaManager(); + + $fromSchema = $sm->createSchema(); + $schemaDiff = $comparator->compare($fromSchema, $toSchema); + + if ($noDrops) { + return $schemaDiff->toSaveSql($this->platform); + } + + return $schemaDiff->toSql($this->platform); + } + + /** + * {@inheritdoc} + */ + public function getDropSchema(Schema $dropSchema) + { + $visitor = new DropSchemaSqlCollector($this->platform); + $sm = $this->conn->getSchemaManager(); + + $fullSchema = $sm->createSchema(); + + foreach ($fullSchema->getTables() as $table) { + if ($dropSchema->hasTable($table->getName())) { + $visitor->acceptTable($table); + } + + foreach ($table->getForeignKeys() as $foreignKey) { + if (! $dropSchema->hasTable($table->getName())) { + continue; + } + + if (! $dropSchema->hasTable($foreignKey->getForeignTableName())) { + continue; + } + + $visitor->acceptForeignKey($table, $foreignKey); + } + } + + if (! $this->platform->supportsSequences()) { + return $visitor->getQueries(); + } + + foreach ($dropSchema->getSequences() as $sequence) { + $visitor->acceptSequence($sequence); + } + + foreach ($dropSchema->getTables() as $table) { + $primaryKey = $table->getPrimaryKey(); + + if ($primaryKey === null) { + continue; + } + + $columns = $primaryKey->getColumns(); + + if (count($columns) > 1) { + continue; + } + + $checkSequence = $table->getName() . '_' . $columns[0] . '_seq'; + if (! $fullSchema->hasSequence($checkSequence)) { + continue; + } + + $visitor->acceptSequence($fullSchema->getSequence($checkSequence)); + } + + return $visitor->getQueries(); + } + + /** + * {@inheritdoc} + */ + public function getDropAllSchema() + { + $sm = $this->conn->getSchemaManager(); + $visitor = new DropSchemaSqlCollector($this->platform); + + $schema = $sm->createSchema(); + $schema->visit($visitor); + + return $visitor->getQueries(); + } + + /** + * {@inheritdoc} + */ + public function createSchema(Schema $createSchema) + { + $this->processSql($this->getCreateSchema($createSchema)); + } + + /** + * {@inheritdoc} + */ + public function updateSchema(Schema $toSchema, $noDrops = false) + { + $this->processSql($this->getUpdateSchema($toSchema, $noDrops)); + } + + /** + * {@inheritdoc} + */ + public function dropSchema(Schema $dropSchema) + { + $this->processSqlSafely($this->getDropSchema($dropSchema)); + } + + /** + * {@inheritdoc} + */ + public function dropAllSchema() + { + $this->processSql($this->getDropAllSchema()); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Table.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Table.php new file mode 100755 index 0000000..9fe6dbd --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Table.php @@ -0,0 +1,909 @@ + [], + ]; + + /** @var SchemaConfig|null */ + protected $_schemaConfig; + + /** + * @param string $name + * @param Column[] $columns + * @param Index[] $indexes + * @param ForeignKeyConstraint[] $fkConstraints + * @param int $idGeneratorType + * @param mixed[] $options + * + * @throws Exception + */ + public function __construct( + $name, + array $columns = [], + array $indexes = [], + array $fkConstraints = [], + $idGeneratorType = 0, + array $options = [] + ) { + if (strlen($name) === 0) { + throw Exception::invalidTableName($name); + } + + $this->_setName($name); + + foreach ($columns as $column) { + $this->_addColumn($column); + } + + foreach ($indexes as $idx) { + $this->_addIndex($idx); + } + + foreach ($fkConstraints as $constraint) { + $this->_addForeignKeyConstraint($constraint); + } + + $this->_options = array_merge($this->_options, $options); + } + + /** + * @return void + */ + public function setSchemaConfig(SchemaConfig $schemaConfig) + { + $this->_schemaConfig = $schemaConfig; + } + + /** + * @return int + */ + protected function _getMaxIdentifierLength() + { + if ($this->_schemaConfig instanceof SchemaConfig) { + return $this->_schemaConfig->getMaxIdentifierLength(); + } + + return 63; + } + + /** + * Sets the Primary Key. + * + * @param string[] $columnNames + * @param string|false $indexName + * + * @return self + */ + public function setPrimaryKey(array $columnNames, $indexName = false) + { + $this->_addIndex($this->_createIndex($columnNames, $indexName ?: 'primary', true, true)); + + foreach ($columnNames as $columnName) { + $column = $this->getColumn($columnName); + $column->setNotnull(true); + } + + return $this; + } + + /** + * @param string[] $columnNames + * @param string|null $indexName + * @param string[] $flags + * @param mixed[] $options + * + * @return self + */ + public function addIndex(array $columnNames, $indexName = null, array $flags = [], array $options = []) + { + if ($indexName === null) { + $indexName = $this->_generateIdentifierName( + array_merge([$this->getName()], $columnNames), + 'idx', + $this->_getMaxIdentifierLength() + ); + } + + return $this->_addIndex($this->_createIndex($columnNames, $indexName, false, false, $flags, $options)); + } + + /** + * Drops the primary key from this table. + * + * @return void + */ + public function dropPrimaryKey() + { + if ($this->_primaryKeyName === false) { + return; + } + + $this->dropIndex($this->_primaryKeyName); + $this->_primaryKeyName = false; + } + + /** + * Drops an index from this table. + * + * @param string $name The index name. + * + * @return void + * + * @throws SchemaException If the index does not exist. + */ + public function dropIndex($name) + { + $name = $this->normalizeIdentifier($name); + if (! $this->hasIndex($name)) { + throw SchemaException::indexDoesNotExist($name, $this->_name); + } + + unset($this->_indexes[$name]); + } + + /** + * @param string[] $columnNames + * @param string|null $indexName + * @param mixed[] $options + * + * @return self + */ + public function addUniqueIndex(array $columnNames, $indexName = null, array $options = []) + { + if ($indexName === null) { + $indexName = $this->_generateIdentifierName( + array_merge([$this->getName()], $columnNames), + 'uniq', + $this->_getMaxIdentifierLength() + ); + } + + return $this->_addIndex($this->_createIndex($columnNames, $indexName, true, false, [], $options)); + } + + /** + * Renames an index. + * + * @param string $oldName The name of the index to rename from. + * @param string|null $newName The name of the index to rename to. + * If null is given, the index name will be auto-generated. + * + * @return self This table instance. + * + * @throws SchemaException If no index exists for the given current name + * or if an index with the given new name already exists on this table. + */ + public function renameIndex($oldName, $newName = null) + { + $oldName = $this->normalizeIdentifier($oldName); + $normalizedNewName = $this->normalizeIdentifier($newName); + + if ($oldName === $normalizedNewName) { + return $this; + } + + if (! $this->hasIndex($oldName)) { + throw SchemaException::indexDoesNotExist($oldName, $this->_name); + } + + if ($this->hasIndex($normalizedNewName)) { + throw SchemaException::indexAlreadyExists($normalizedNewName, $this->_name); + } + + $oldIndex = $this->_indexes[$oldName]; + + if ($oldIndex->isPrimary()) { + $this->dropPrimaryKey(); + + return $this->setPrimaryKey($oldIndex->getColumns(), $newName ?? false); + } + + unset($this->_indexes[$oldName]); + + if ($oldIndex->isUnique()) { + return $this->addUniqueIndex($oldIndex->getColumns(), $newName, $oldIndex->getOptions()); + } + + return $this->addIndex($oldIndex->getColumns(), $newName, $oldIndex->getFlags(), $oldIndex->getOptions()); + } + + /** + * Checks if an index begins in the order of the given columns. + * + * @param string[] $columnNames + * + * @return bool + */ + public function columnsAreIndexed(array $columnNames) + { + foreach ($this->getIndexes() as $index) { + if ($index->spansColumns($columnNames)) { + return true; + } + } + + return false; + } + + /** + * @param string[] $columnNames + * @param string $indexName + * @param bool $isUnique + * @param bool $isPrimary + * @param string[] $flags + * @param mixed[] $options + * + * @return Index + * + * @throws SchemaException + */ + private function _createIndex( + array $columnNames, + $indexName, + $isUnique, + $isPrimary, + array $flags = [], + array $options = [] + ) { + if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) { + throw SchemaException::indexNameInvalid($indexName); + } + + foreach ($columnNames as $columnName) { + if (! $this->hasColumn($columnName)) { + throw SchemaException::columnDoesNotExist($columnName, $this->_name); + } + } + + return new Index($indexName, $columnNames, $isUnique, $isPrimary, $flags, $options); + } + + /** + * @param string $name + * @param string $typeName + * @param mixed[] $options + * + * @return Column + */ + public function addColumn($name, $typeName, array $options = []) + { + $column = new Column($name, Type::getType($typeName), $options); + + $this->_addColumn($column); + + return $column; + } + + /** + * Renames a Column. + * + * @deprecated + * + * @param string $oldName + * @param string $name + * + * @return void + * + * @throws Exception + */ + public function renameColumn($oldName, $name) + { + throw new Exception('Table#renameColumn() was removed, because it drops and recreates ' . + 'the column instead. There is no fix available, because a schema diff cannot reliably detect if a ' . + 'column was renamed or one column was created and another one dropped.'); + } + + /** + * Change Column Details. + * + * @param string $name + * @param mixed[] $options + * + * @return self + */ + public function changeColumn($name, array $options) + { + $column = $this->getColumn($name); + $column->setOptions($options); + + return $this; + } + + /** + * Drops a Column from the Table. + * + * @param string $name + * + * @return self + */ + public function dropColumn($name) + { + $name = $this->normalizeIdentifier($name); + unset($this->_columns[$name]); + + return $this; + } + + /** + * Adds a foreign key constraint. + * + * Name is inferred from the local columns. + * + * @param Table|string $foreignTable Table schema instance or table name + * @param string[] $localColumnNames + * @param string[] $foreignColumnNames + * @param mixed[] $options + * @param string|null $constraintName + * + * @return self + */ + public function addForeignKeyConstraint( + $foreignTable, + array $localColumnNames, + array $foreignColumnNames, + array $options = [], + $constraintName = null + ) { + $constraintName = $constraintName ?: $this->_generateIdentifierName( + array_merge((array) $this->getName(), $localColumnNames), + 'fk', + $this->_getMaxIdentifierLength() + ); + + return $this->addNamedForeignKeyConstraint( + $constraintName, + $foreignTable, + $localColumnNames, + $foreignColumnNames, + $options + ); + } + + /** + * Adds a foreign key constraint. + * + * Name is to be generated by the database itself. + * + * @deprecated Use {@link addForeignKeyConstraint} + * + * @param Table|string $foreignTable Table schema instance or table name + * @param string[] $localColumnNames + * @param string[] $foreignColumnNames + * @param mixed[] $options + * + * @return self + */ + public function addUnnamedForeignKeyConstraint( + $foreignTable, + array $localColumnNames, + array $foreignColumnNames, + array $options = [] + ) { + return $this->addForeignKeyConstraint($foreignTable, $localColumnNames, $foreignColumnNames, $options); + } + + /** + * Adds a foreign key constraint with a given name. + * + * @deprecated Use {@link addForeignKeyConstraint} + * + * @param string $name + * @param Table|string $foreignTable Table schema instance or table name + * @param string[] $localColumnNames + * @param string[] $foreignColumnNames + * @param mixed[] $options + * + * @return self + * + * @throws SchemaException + */ + public function addNamedForeignKeyConstraint( + $name, + $foreignTable, + array $localColumnNames, + array $foreignColumnNames, + array $options = [] + ) { + if ($foreignTable instanceof Table) { + foreach ($foreignColumnNames as $columnName) { + if (! $foreignTable->hasColumn($columnName)) { + throw SchemaException::columnDoesNotExist($columnName, $foreignTable->getName()); + } + } + } + + foreach ($localColumnNames as $columnName) { + if (! $this->hasColumn($columnName)) { + throw SchemaException::columnDoesNotExist($columnName, $this->_name); + } + } + + $constraint = new ForeignKeyConstraint( + $localColumnNames, + $foreignTable, + $foreignColumnNames, + $name, + $options + ); + $this->_addForeignKeyConstraint($constraint); + + return $this; + } + + /** + * @param string $name + * @param mixed $value + * + * @return self + */ + public function addOption($name, $value) + { + $this->_options[$name] = $value; + + return $this; + } + + /** + * @return void + * + * @throws SchemaException + */ + protected function _addColumn(Column $column) + { + $columnName = $column->getName(); + $columnName = $this->normalizeIdentifier($columnName); + + if (isset($this->_columns[$columnName])) { + throw SchemaException::columnAlreadyExists($this->getName(), $columnName); + } + + $this->_columns[$columnName] = $column; + } + + /** + * Adds an index to the table. + * + * @return self + * + * @throws SchemaException + */ + protected function _addIndex(Index $indexCandidate) + { + $indexName = $indexCandidate->getName(); + $indexName = $this->normalizeIdentifier($indexName); + $replacedImplicitIndexes = []; + + foreach ($this->implicitIndexes as $name => $implicitIndex) { + if (! $implicitIndex->isFullfilledBy($indexCandidate) || ! isset($this->_indexes[$name])) { + continue; + } + + $replacedImplicitIndexes[] = $name; + } + + if ( + (isset($this->_indexes[$indexName]) && ! in_array($indexName, $replacedImplicitIndexes, true)) || + ($this->_primaryKeyName !== false && $indexCandidate->isPrimary()) + ) { + throw SchemaException::indexAlreadyExists($indexName, $this->_name); + } + + foreach ($replacedImplicitIndexes as $name) { + unset($this->_indexes[$name], $this->implicitIndexes[$name]); + } + + if ($indexCandidate->isPrimary()) { + $this->_primaryKeyName = $indexName; + } + + $this->_indexes[$indexName] = $indexCandidate; + + return $this; + } + + /** + * @return void + */ + protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint) + { + $constraint->setLocalTable($this); + + if (strlen($constraint->getName())) { + $name = $constraint->getName(); + } else { + $name = $this->_generateIdentifierName( + array_merge((array) $this->getName(), $constraint->getLocalColumns()), + 'fk', + $this->_getMaxIdentifierLength() + ); + } + + $name = $this->normalizeIdentifier($name); + + $this->_fkConstraints[$name] = $constraint; + + /* Add an implicit index (defined by the DBAL) on the foreign key + columns. If there is already a user-defined index that fulfills these + requirements drop the request. In the case of __construct() calling + this method during hydration from schema-details, all the explicitly + added indexes lead to duplicates. This creates computation overhead in + this case, however no duplicate indexes are ever added (based on + columns). */ + $indexName = $this->_generateIdentifierName( + array_merge([$this->getName()], $constraint->getColumns()), + 'idx', + $this->_getMaxIdentifierLength() + ); + + $indexCandidate = $this->_createIndex($constraint->getColumns(), $indexName, false, false); + + foreach ($this->_indexes as $existingIndex) { + if ($indexCandidate->isFullfilledBy($existingIndex)) { + return; + } + } + + $this->_addIndex($indexCandidate); + $this->implicitIndexes[$this->normalizeIdentifier($indexName)] = $indexCandidate; + } + + /** + * Returns whether this table has a foreign key constraint with the given name. + * + * @param string $name + * + * @return bool + */ + public function hasForeignKey($name) + { + $name = $this->normalizeIdentifier($name); + + return isset($this->_fkConstraints[$name]); + } + + /** + * Returns the foreign key constraint with the given name. + * + * @param string $name The constraint name. + * + * @return ForeignKeyConstraint + * + * @throws SchemaException If the foreign key does not exist. + */ + public function getForeignKey($name) + { + $name = $this->normalizeIdentifier($name); + if (! $this->hasForeignKey($name)) { + throw SchemaException::foreignKeyDoesNotExist($name, $this->_name); + } + + return $this->_fkConstraints[$name]; + } + + /** + * Removes the foreign key constraint with the given name. + * + * @param string $name The constraint name. + * + * @return void + * + * @throws SchemaException + */ + public function removeForeignKey($name) + { + $name = $this->normalizeIdentifier($name); + if (! $this->hasForeignKey($name)) { + throw SchemaException::foreignKeyDoesNotExist($name, $this->_name); + } + + unset($this->_fkConstraints[$name]); + } + + /** + * Returns ordered list of columns (primary keys are first, then foreign keys, then the rest) + * + * @return Column[] + */ + public function getColumns() + { + $primaryKey = $this->getPrimaryKey(); + $primaryKeyColumns = []; + + if ($primaryKey !== null) { + $primaryKeyColumns = $this->filterColumns($primaryKey->getColumns()); + } + + return array_merge($primaryKeyColumns, $this->getForeignKeyColumns(), $this->_columns); + } + + /** + * Returns foreign key columns + * + * @return Column[] + */ + private function getForeignKeyColumns() + { + $foreignKeyColumns = []; + foreach ($this->getForeignKeys() as $foreignKey) { + $foreignKeyColumns = array_merge($foreignKeyColumns, $foreignKey->getColumns()); + } + + return $this->filterColumns($foreignKeyColumns); + } + + /** + * Returns only columns that have specified names + * + * @param string[] $columnNames + * + * @return Column[] + */ + private function filterColumns(array $columnNames) + { + return array_filter($this->_columns, static function (string $columnName) use ($columnNames) { + return in_array($columnName, $columnNames, true); + }, ARRAY_FILTER_USE_KEY); + } + + /** + * Returns whether this table has a Column with the given name. + * + * @param string $name The column name. + * + * @return bool + */ + public function hasColumn($name) + { + $name = $this->normalizeIdentifier($name); + + return isset($this->_columns[$name]); + } + + /** + * Returns the Column with the given name. + * + * @param string $name The column name. + * + * @return Column + * + * @throws SchemaException If the column does not exist. + */ + public function getColumn($name) + { + $name = $this->normalizeIdentifier($name); + if (! $this->hasColumn($name)) { + throw SchemaException::columnDoesNotExist($name, $this->_name); + } + + return $this->_columns[$name]; + } + + /** + * Returns the primary key. + * + * @return Index|null The primary key, or null if this Table has no primary key. + */ + public function getPrimaryKey() + { + if ($this->_primaryKeyName !== false) { + return $this->getIndex($this->_primaryKeyName); + } + + return null; + } + + /** + * Returns the primary key columns. + * + * @return string[] + * + * @throws Exception + */ + public function getPrimaryKeyColumns() + { + $primaryKey = $this->getPrimaryKey(); + + if ($primaryKey === null) { + throw new Exception('Table ' . $this->getName() . ' has no primary key.'); + } + + return $primaryKey->getColumns(); + } + + /** + * Returns whether this table has a primary key. + * + * @return bool + */ + public function hasPrimaryKey() + { + return $this->_primaryKeyName && $this->hasIndex($this->_primaryKeyName); + } + + /** + * Returns whether this table has an Index with the given name. + * + * @param string $name The index name. + * + * @return bool + */ + public function hasIndex($name) + { + $name = $this->normalizeIdentifier($name); + + return isset($this->_indexes[$name]); + } + + /** + * Returns the Index with the given name. + * + * @param string $name The index name. + * + * @return Index + * + * @throws SchemaException If the index does not exist. + */ + public function getIndex($name) + { + $name = $this->normalizeIdentifier($name); + if (! $this->hasIndex($name)) { + throw SchemaException::indexDoesNotExist($name, $this->_name); + } + + return $this->_indexes[$name]; + } + + /** + * @return Index[] + */ + public function getIndexes() + { + return $this->_indexes; + } + + /** + * Returns the foreign key constraints. + * + * @return ForeignKeyConstraint[] + */ + public function getForeignKeys() + { + return $this->_fkConstraints; + } + + /** + * @param string $name + * + * @return bool + */ + public function hasOption($name) + { + return isset($this->_options[$name]); + } + + /** + * @param string $name + * + * @return mixed + */ + public function getOption($name) + { + return $this->_options[$name]; + } + + /** + * @return mixed[] + */ + public function getOptions() + { + return $this->_options; + } + + /** + * @return void + */ + public function visit(Visitor $visitor) + { + $visitor->acceptTable($this); + + foreach ($this->getColumns() as $column) { + $visitor->acceptColumn($this, $column); + } + + foreach ($this->getIndexes() as $index) { + $visitor->acceptIndex($this, $index); + } + + foreach ($this->getForeignKeys() as $constraint) { + $visitor->acceptForeignKey($this, $constraint); + } + } + + /** + * Clone of a Table triggers a deep clone of all affected assets. + * + * @return void + */ + public function __clone() + { + foreach ($this->_columns as $k => $column) { + $this->_columns[$k] = clone $column; + } + + foreach ($this->_indexes as $k => $index) { + $this->_indexes[$k] = clone $index; + } + + foreach ($this->_fkConstraints as $k => $fk) { + $this->_fkConstraints[$k] = clone $fk; + $this->_fkConstraints[$k]->setLocalTable($this); + } + } + + /** + * Normalizes a given identifier. + * + * Trims quotes and lowercases the given identifier. + * + * @param string|null $identifier The identifier to normalize. + * + * @return string The normalized identifier. + */ + private function normalizeIdentifier($identifier) + { + if ($identifier === null) { + return ''; + } + + return $this->trimQuotes(strtolower($identifier)); + } + + public function setComment(?string $comment): self + { + // For keeping backward compatibility with MySQL in previous releases, table comments are stored as options. + $this->addOption('comment', $comment); + + return $this; + } + + public function getComment(): ?string + { + return $this->_options['comment'] ?? null; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/TableDiff.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/TableDiff.php new file mode 100755 index 0000000..82c912f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/TableDiff.php @@ -0,0 +1,152 @@ +name = $tableName; + $this->addedColumns = $addedColumns; + $this->changedColumns = $changedColumns; + $this->removedColumns = $removedColumns; + $this->addedIndexes = $addedIndexes; + $this->changedIndexes = $changedIndexes; + $this->removedIndexes = $removedIndexes; + $this->fromTable = $fromTable; + } + + /** + * @param AbstractPlatform $platform The platform to use for retrieving this table diff's name. + * + * @return Identifier + */ + public function getName(AbstractPlatform $platform) + { + return new Identifier( + $this->fromTable instanceof Table ? $this->fromTable->getQuotedName($platform) : $this->name + ); + } + + /** + * @return Identifier|false + */ + public function getNewName() + { + if ($this->newName === false) { + return false; + } + + return new Identifier($this->newName); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/View.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/View.php new file mode 100755 index 0000000..ac8d6cb --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/View.php @@ -0,0 +1,30 @@ +_setName($name); + $this->sql = $sql; + } + + /** + * @return string + */ + public function getSql() + { + return $this->sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/AbstractVisitor.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/AbstractVisitor.php new file mode 100755 index 0000000..4716904 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/AbstractVisitor.php @@ -0,0 +1,47 @@ +platform = $platform; + } + + /** + * {@inheritdoc} + */ + public function acceptNamespace($namespaceName) + { + if (! $this->platform->supportsSchemas()) { + return; + } + + $this->createNamespaceQueries[] = $this->platform->getCreateSchemaSQL($namespaceName); + } + + /** + * {@inheritdoc} + */ + public function acceptTable(Table $table) + { + $this->createTableQueries = array_merge($this->createTableQueries, $this->platform->getCreateTableSQL($table)); + } + + /** + * {@inheritdoc} + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + if (! $this->platform->supportsForeignKeyConstraints()) { + return; + } + + $this->createFkConstraintQueries[] = $this->platform->getCreateForeignKeySQL($fkConstraint, $localTable); + } + + /** + * {@inheritdoc} + */ + public function acceptSequence(Sequence $sequence) + { + $this->createSequenceQueries[] = $this->platform->getCreateSequenceSQL($sequence); + } + + /** + * @return void + */ + public function resetQueries() + { + $this->createNamespaceQueries = []; + $this->createTableQueries = []; + $this->createSequenceQueries = []; + $this->createFkConstraintQueries = []; + } + + /** + * Gets all queries collected so far. + * + * @return string[] + */ + public function getQueries() + { + return array_merge( + $this->createNamespaceQueries, + $this->createTableQueries, + $this->createSequenceQueries, + $this->createFkConstraintQueries + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php new file mode 100755 index 0000000..1b77268 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php @@ -0,0 +1,106 @@ +platform = $platform; + $this->initializeQueries(); + } + + /** + * {@inheritdoc} + */ + public function acceptTable(Table $table) + { + $this->tables->attach($table); + } + + /** + * {@inheritdoc} + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + if (strlen($fkConstraint->getName()) === 0) { + throw SchemaException::namedForeignKeyRequired($localTable, $fkConstraint); + } + + $this->constraints->attach($fkConstraint, $localTable); + } + + /** + * {@inheritdoc} + */ + public function acceptSequence(Sequence $sequence) + { + $this->sequences->attach($sequence); + } + + /** + * @return void + */ + public function clearQueries() + { + $this->initializeQueries(); + } + + /** + * @return string[] + */ + public function getQueries() + { + $sql = []; + + foreach ($this->constraints as $fkConstraint) { + assert($fkConstraint instanceof ForeignKeyConstraint); + $localTable = $this->constraints[$fkConstraint]; + $sql[] = $this->platform->getDropForeignKeySQL($fkConstraint, $localTable); + } + + foreach ($this->sequences as $sequence) { + assert($sequence instanceof Sequence); + $sql[] = $this->platform->getDropSequenceSQL($sequence); + } + + foreach ($this->tables as $table) { + assert($table instanceof Table); + $sql[] = $this->platform->getDropTableSQL($table); + } + + return $sql; + } + + private function initializeQueries(): void + { + $this->constraints = new SplObjectStorage(); + $this->sequences = new SplObjectStorage(); + $this->tables = new SplObjectStorage(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php new file mode 100755 index 0000000..841b7cb --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php @@ -0,0 +1,168 @@ +output .= $this->createNodeRelation( + $fkConstraint->getLocalTableName() . ':col' . current($fkConstraint->getLocalColumns()) . ':se', + $fkConstraint->getForeignTableName() . ':col' . current($fkConstraint->getForeignColumns()) . ':se', + [ + 'dir' => 'back', + 'arrowtail' => 'dot', + 'arrowhead' => 'normal', + ] + ); + } + + /** + * {@inheritdoc} + */ + public function acceptSchema(Schema $schema) + { + $this->output = 'digraph "' . $schema->getName() . '" {' . "\n"; + $this->output .= 'splines = true;' . "\n"; + $this->output .= 'overlap = false;' . "\n"; + $this->output .= 'outputorder=edgesfirst;' . "\n"; + $this->output .= 'mindist = 0.6;' . "\n"; + $this->output .= 'sep = .2;' . "\n"; + } + + /** + * {@inheritdoc} + */ + public function acceptTable(Table $table) + { + $this->output .= $this->createNode( + $table->getName(), + [ + 'label' => $this->createTableLabel($table), + 'shape' => 'plaintext', + ] + ); + } + + /** + * @return string + */ + private function createTableLabel(Table $table) + { + // Start the table + $label = '<'; + + // The title + $label .= ''; + + // The attributes block + foreach ($table->getColumns() as $column) { + $columnLabel = $column->getName(); + + $label .= '' + . '' + . '' + . ''; + } + + // End the table + $label .= '
' + . '' . $table->getName() . '
' + . '' . $columnLabel . '' + . '' + . '' . strtolower($column->getType()) . '' + . ''; + + $primaryKey = $table->getPrimaryKey(); + + if ($primaryKey !== null && in_array($column->getName(), $primaryKey->getColumns())) { + $label .= "\xe2\x9c\xb7"; + } + + $label .= '
>'; + + return $label; + } + + /** + * @param string $name + * @param string[] $options + * + * @return string + */ + private function createNode($name, $options) + { + $node = $name . ' ['; + foreach ($options as $key => $value) { + $node .= $key . '=' . $value . ' '; + } + + $node .= "]\n"; + + return $node; + } + + /** + * @param string $node1 + * @param string $node2 + * @param string[] $options + * + * @return string + */ + private function createNodeRelation($node1, $node2, $options) + { + $relation = $node1 . ' -> ' . $node2 . ' ['; + foreach ($options as $key => $value) { + $relation .= $key . '=' . $value . ' '; + } + + $relation .= "]\n"; + + return $relation; + } + + /** + * Get Graphviz Output + * + * @return string + */ + public function getOutput() + { + return $this->output . '}'; + } + + /** + * Writes dot language output to a file. This should usually be a *.dot file. + * + * You have to convert the output into a viewable format. For example use "neato" on linux systems + * and execute: + * + * neato -Tpng -o er.png er.dot + * + * @param string $filename + * + * @return void + */ + public function write($filename) + { + file_put_contents($filename, $this->getOutput()); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/NamespaceVisitor.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/NamespaceVisitor.php new file mode 100755 index 0000000..b0548d6 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/NamespaceVisitor.php @@ -0,0 +1,18 @@ +schema = $schema; + } + + /** + * {@inheritdoc} + */ + public function acceptTable(Table $table) + { + if ($this->schema === null) { + return; + } + + if ($table->isInDefaultNamespace($this->schema->getName())) { + return; + } + + $this->schema->dropTable($table->getName()); + } + + /** + * {@inheritdoc} + */ + public function acceptSequence(Sequence $sequence) + { + if ($this->schema === null) { + return; + } + + if ($sequence->isInDefaultNamespace($this->schema->getName())) { + return; + } + + $this->schema->dropSequence($sequence->getName()); + } + + /** + * {@inheritdoc} + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + if ($this->schema === null) { + return; + } + + // The table may already be deleted in a previous + // RemoveNamespacedAssets#acceptTable call. Removing Foreign keys that + // point to nowhere. + if (! $this->schema->hasTable($fkConstraint->getForeignTableName())) { + $localTable->removeForeignKey($fkConstraint->getName()); + + return; + } + + $foreignTable = $this->schema->getTable($fkConstraint->getForeignTableName()); + if ($foreignTable->isInDefaultNamespace($this->schema->getName())) { + return; + } + + $localTable->removeForeignKey($fkConstraint->getName()); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/SchemaDiffVisitor.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/SchemaDiffVisitor.php new file mode 100755 index 0000000..040b59f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/SchemaDiffVisitor.php @@ -0,0 +1,50 @@ + "client" to the ShardChoser interface. + * - An exception is thrown if trying to switch shards during an open + * transaction. + * + * Instantiation through the DriverManager looks like: + * + * @deprecated + * + * @example + * + * $conn = DriverManager::getConnection(array( + * 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', + * 'driver' => 'pdo_mysql', + * 'global' => array('user' => '', 'password' => '', 'host' => '', 'dbname' => ''), + * 'shards' => array( + * array('id' => 1, 'user' => 'slave1', 'password', 'host' => '', 'dbname' => ''), + * array('id' => 2, 'user' => 'slave2', 'password', 'host' => '', 'dbname' => ''), + * ), + * 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', + * )); + * $shardManager = $conn->getShardManager(); + * $shardManager->selectGlobal(); + * $shardManager->selectShard($value); + */ +class PoolingShardConnection extends Connection +{ + /** @var DriverConnection[] */ + private $activeConnections = []; + + /** @var string|int|null */ + private $activeShardId; + + /** @var mixed[] */ + private $connectionParameters = []; + + /** + * {@inheritDoc} + * + * @internal The connection can be only instantiated by the driver manager. + * + * @throws InvalidArgumentException + */ + public function __construct( + array $params, + Driver $driver, + ?Configuration $config = null, + ?EventManager $eventManager = null + ) { + if (! isset($params['global'], $params['shards'])) { + throw new InvalidArgumentException("Connection Parameters require 'global' and 'shards' configurations."); + } + + if (! isset($params['shardChoser'])) { + throw new InvalidArgumentException("Missing Shard Choser configuration 'shardChoser'"); + } + + if (is_string($params['shardChoser'])) { + $params['shardChoser'] = new $params['shardChoser'](); + } + + if (! ($params['shardChoser'] instanceof ShardChoser)) { + throw new InvalidArgumentException( + "The 'shardChoser' configuration is not a valid instance of " . ShardChoser::class + ); + } + + $this->connectionParameters[0] = array_merge($params, $params['global']); + + foreach ($params['shards'] as $shard) { + if (! isset($shard['id'])) { + throw new InvalidArgumentException( + "Missing 'id' for one configured shard. Please specify a unique shard-id." + ); + } + + if (! is_numeric($shard['id']) || $shard['id'] < 1) { + throw new InvalidArgumentException('Shard Id has to be a non-negative number.'); + } + + if (isset($this->connectionParameters[$shard['id']])) { + throw new InvalidArgumentException('Shard ' . $shard['id'] . ' is duplicated in the configuration.'); + } + + $this->connectionParameters[$shard['id']] = array_merge($params, $shard); + } + + parent::__construct($params, $driver, $config, $eventManager); + } + + /** + * Get active shard id. + * + * @return string|int|null + */ + public function getActiveShardId() + { + return $this->activeShardId; + } + + /** + * {@inheritdoc} + */ + public function getParams() + { + return $this->activeShardId + ? $this->connectionParameters[$this->activeShardId] + : $this->connectionParameters[0]; + } + + /** + * {@inheritdoc} + */ + public function getHost() + { + $params = $this->getParams(); + + return $params['host'] ?? parent::getHost(); + } + + /** + * {@inheritdoc} + */ + public function getPort() + { + $params = $this->getParams(); + + return $params['port'] ?? parent::getPort(); + } + + /** + * {@inheritdoc} + */ + public function getUsername() + { + $params = $this->getParams(); + + return $params['user'] ?? parent::getUsername(); + } + + /** + * {@inheritdoc} + */ + public function getPassword() + { + $params = $this->getParams(); + + return $params['password'] ?? parent::getPassword(); + } + + /** + * Connects to a given shard. + * + * @param string|int|null $shardId + * + * @return bool + * + * @throws ShardingException + */ + public function connect($shardId = null) + { + if ($shardId === null && $this->_conn) { + return false; + } + + if ($shardId !== null && $shardId === $this->activeShardId) { + return false; + } + + if ($this->getTransactionNestingLevel() > 0) { + throw new ShardingException('Cannot switch shard when transaction is active.'); + } + + $activeShardId = $this->activeShardId = (int) $shardId; + + if (isset($this->activeConnections[$activeShardId])) { + $this->_conn = $this->activeConnections[$activeShardId]; + + return false; + } + + $this->_conn = $this->activeConnections[$activeShardId] = $this->connectTo($activeShardId); + + if ($this->_eventManager->hasListeners(Events::postConnect)) { + $eventArgs = new ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + } + + return true; + } + + /** + * Connects to a specific connection. + * + * @param string|int $shardId + * + * @return \Doctrine\DBAL\Driver\Connection + */ + protected function connectTo($shardId) + { + $params = $this->getParams(); + + $driverOptions = $params['driverOptions'] ?? []; + + $connectionParams = $this->connectionParameters[$shardId]; + + $user = $connectionParams['user'] ?? null; + $password = $connectionParams['password'] ?? null; + + return $this->_driver->connect($connectionParams, $user, $password, $driverOptions); + } + + /** + * @param string|int|null $shardId + * + * @return bool + */ + public function isConnected($shardId = null) + { + if ($shardId === null) { + return $this->_conn !== null; + } + + return isset($this->activeConnections[$shardId]); + } + + /** + * @return void + */ + public function close() + { + $this->_conn = null; + $this->activeConnections = []; + $this->activeShardId = null; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php new file mode 100755 index 0000000..739cfab --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php @@ -0,0 +1,110 @@ +getParams(); + $this->conn = $conn; + $this->choser = $params['shardChoser']; + } + + /** + * {@inheritDoc} + */ + public function selectGlobal() + { + $this->conn->connect(0); + $this->currentDistributionValue = null; + } + + /** + * {@inheritDoc} + */ + public function selectShard($distributionValue) + { + $shardId = $this->choser->pickShard($distributionValue, $this->conn); + $this->conn->connect($shardId); + $this->currentDistributionValue = $distributionValue; + } + + /** + * {@inheritDoc} + */ + public function getCurrentDistributionValue() + { + return $this->currentDistributionValue; + } + + /** + * {@inheritDoc} + */ + public function getShards() + { + $params = $this->conn->getParams(); + $shards = []; + + foreach ($params['shards'] as $shard) { + $shards[] = ['id' => $shard['id']]; + } + + return $shards; + } + + /** + * {@inheritDoc} + * + * @throws RuntimeException + */ + public function queryAll($sql, array $params, array $types) + { + $shards = $this->getShards(); + if (! $shards) { + throw new RuntimeException('No shards found.'); + } + + $result = []; + $oldDistribution = $this->getCurrentDistributionValue(); + + foreach ($shards as $shard) { + $this->conn->connect($shard['id']); + foreach ($this->conn->fetchAllAssociative($sql, $params, $types) as $row) { + $result[] = $row; + } + } + + if ($oldDistribution === null) { + $this->selectGlobal(); + } else { + $this->selectShard($oldDistribution); + } + + return $result; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php new file mode 100755 index 0000000..5fa2aa7 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php @@ -0,0 +1,284 @@ +shardManager = $shardManager; + $this->synchronizer = $sync ?: new SingleDatabaseSynchronizer($conn); + } + + /** + * {@inheritdoc} + */ + public function getCreateSchema(Schema $createSchema) + { + $sql = []; + + [$global, $federation] = $this->partitionSchema($createSchema); + + $globalSql = $this->synchronizer->getCreateSchema($global); + if ($globalSql) { + $sql[] = "-- Create Root Federation\n" . + 'USE FEDERATION ROOT WITH RESET;'; + $sql = array_merge($sql, $globalSql); + } + + $federationSql = $this->synchronizer->getCreateSchema($federation); + + if ($federationSql) { + $defaultValue = $this->getFederationTypeDefaultValue(); + + $sql[] = $this->getCreateFederationStatement(); + $sql[] = 'USE FEDERATION ' . $this->shardManager->getFederationName() + . ' (' . $this->shardManager->getDistributionKey() . ' = ' . $defaultValue . ')' + . ' WITH RESET, FILTERING = OFF;'; + $sql = array_merge($sql, $federationSql); + } + + return $sql; + } + + /** + * {@inheritdoc} + */ + public function getUpdateSchema(Schema $toSchema, $noDrops = false) + { + return $this->work($toSchema, static function ($synchronizer, $schema) use ($noDrops) { + return $synchronizer->getUpdateSchema($schema, $noDrops); + }); + } + + /** + * {@inheritdoc} + */ + public function getDropSchema(Schema $dropSchema) + { + return $this->work($dropSchema, static function ($synchronizer, $schema) { + return $synchronizer->getDropSchema($schema); + }); + } + + /** + * {@inheritdoc} + */ + public function createSchema(Schema $createSchema) + { + $this->processSql($this->getCreateSchema($createSchema)); + } + + /** + * {@inheritdoc} + */ + public function updateSchema(Schema $toSchema, $noDrops = false) + { + $this->processSql($this->getUpdateSchema($toSchema, $noDrops)); + } + + /** + * {@inheritdoc} + */ + public function dropSchema(Schema $dropSchema) + { + $this->processSqlSafely($this->getDropSchema($dropSchema)); + } + + /** + * {@inheritdoc} + */ + public function getDropAllSchema() + { + $this->shardManager->selectGlobal(); + $globalSql = $this->synchronizer->getDropAllSchema(); + + $sql = []; + + if ($globalSql) { + $sql[] = "-- Work on Root Federation\nUSE FEDERATION ROOT WITH RESET;"; + $sql = array_merge($sql, $globalSql); + } + + $shards = $this->shardManager->getShards(); + foreach ($shards as $shard) { + $this->shardManager->selectShard($shard['rangeLow']); + + $federationSql = $this->synchronizer->getDropAllSchema(); + if (! $federationSql) { + continue; + } + + $sql[] = '-- Work on Federation ID ' . $shard['id'] . "\n" . + 'USE FEDERATION ' . $this->shardManager->getFederationName() + . ' (' . $this->shardManager->getDistributionKey() . ' = ' . $shard['rangeLow'] . ')' + . ' WITH RESET, FILTERING = OFF;'; + $sql = array_merge($sql, $federationSql); + } + + $sql[] = 'USE FEDERATION ROOT WITH RESET;'; + $sql[] = 'DROP FEDERATION ' . $this->shardManager->getFederationName(); + + return $sql; + } + + /** + * {@inheritdoc} + */ + public function dropAllSchema() + { + $this->processSqlSafely($this->getDropAllSchema()); + } + + /** + * @return Schema[] + */ + private function partitionSchema(Schema $schema) + { + return [ + $this->extractSchemaFederation($schema, false), + $this->extractSchemaFederation($schema, true), + ]; + } + + /** + * @param bool $isFederation + * + * @return Schema + * + * @throws RuntimeException + */ + private function extractSchemaFederation(Schema $schema, $isFederation) + { + $partitionedSchema = clone $schema; + + foreach ($partitionedSchema->getTables() as $table) { + if ($isFederation) { + $table->addOption(self::FEDERATION_DISTRIBUTION_NAME, $this->shardManager->getDistributionKey()); + } + + if ($table->hasOption(self::FEDERATION_TABLE_FEDERATED) !== $isFederation) { + $partitionedSchema->dropTable($table->getName()); + } else { + foreach ($table->getForeignKeys() as $fk) { + $foreignTable = $schema->getTable($fk->getForeignTableName()); + if ($foreignTable->hasOption(self::FEDERATION_TABLE_FEDERATED) !== $isFederation) { + throw new RuntimeException('Cannot have foreign key between global/federation.'); + } + } + } + } + + return $partitionedSchema; + } + + /** + * Work on the Global/Federation based on currently existing shards and + * perform the given operation on the underlying schema synchronizer given + * the different partitioned schema instances. + * + * @return string[] + */ + private function work(Schema $schema, Closure $operation) + { + [$global, $federation] = $this->partitionSchema($schema); + $sql = []; + + $this->shardManager->selectGlobal(); + $globalSql = $operation($this->synchronizer, $global); + + if ($globalSql) { + $sql[] = "-- Work on Root Federation\nUSE FEDERATION ROOT WITH RESET;"; + $sql = array_merge($sql, $globalSql); + } + + $shards = $this->shardManager->getShards(); + + foreach ($shards as $shard) { + $this->shardManager->selectShard($shard['rangeLow']); + + $federationSql = $operation($this->synchronizer, $federation); + if (! $federationSql) { + continue; + } + + $sql[] = '-- Work on Federation ID ' . $shard['id'] . "\n" + . 'USE FEDERATION ' . $this->shardManager->getFederationName() + . ' (' . $this->shardManager->getDistributionKey() . ' = ' . $shard['rangeLow'] . ')' + . ' WITH RESET, FILTERING = OFF;'; + $sql = array_merge($sql, $federationSql); + } + + return $sql; + } + + /** + * @return string + */ + private function getFederationTypeDefaultValue() + { + $federationType = Type::getType($this->shardManager->getDistributionType()); + + switch ($federationType->getName()) { + case Types::GUID: + $defaultValue = '00000000-0000-0000-0000-000000000000'; + break; + case Types::INTEGER: + case Types::SMALLINT: + case Types::BIGINT: + $defaultValue = '0'; + break; + default: + $defaultValue = ''; + break; + } + + return $defaultValue; + } + + /** + * @return string + */ + private function getCreateFederationStatement() + { + $federationType = Type::getType($this->shardManager->getDistributionType()); + $federationTypeSql = $federationType->getSQLDeclaration([], $this->conn->getDatabasePlatform()); + + return "--Create Federation\n" + . 'CREATE FEDERATION ' . $this->shardManager->getFederationName() + . ' (' . $this->shardManager->getDistributionKey() + . ' ' . $federationTypeSql . ' RANGE)'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php new file mode 100755 index 0000000..83ad879 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php @@ -0,0 +1,218 @@ +conn = $conn; + $params = $conn->getParams(); + + if (! isset($params['sharding']['federationName'])) { + throw ShardingException::missingDefaultFederationName(); + } + + if (! isset($params['sharding']['distributionKey'])) { + throw ShardingException::missingDefaultDistributionKey(); + } + + if (! isset($params['sharding']['distributionType'])) { + throw ShardingException::missingDistributionType(); + } + + $this->federationName = $params['sharding']['federationName']; + $this->distributionKey = $params['sharding']['distributionKey']; + $this->distributionType = $params['sharding']['distributionType']; + $this->filteringEnabled = (bool) ($params['sharding']['filteringEnabled'] ?? false); + } + + /** + * Gets the name of the federation. + * + * @return string + */ + public function getFederationName() + { + return $this->federationName; + } + + /** + * Gets the distribution key. + * + * @return string + */ + public function getDistributionKey() + { + return $this->distributionKey; + } + + /** + * Gets the Doctrine Type name used for the distribution. + * + * @return string + */ + public function getDistributionType() + { + return $this->distributionType; + } + + /** + * Sets Enabled/Disable filtering on the fly. + * + * @param bool $flag + * + * @return void + */ + public function setFilteringEnabled($flag) + { + $this->filteringEnabled = (bool) $flag; + } + + /** + * {@inheritDoc} + */ + public function selectGlobal() + { + if ($this->conn->isTransactionActive()) { + throw ShardingException::activeTransaction(); + } + + $sql = 'USE FEDERATION ROOT WITH RESET'; + $this->conn->exec($sql); + $this->currentDistributionValue = null; + } + + /** + * {@inheritDoc} + */ + public function selectShard($distributionValue) + { + if ($this->conn->isTransactionActive()) { + throw ShardingException::activeTransaction(); + } + + $platform = $this->conn->getDatabasePlatform(); + $sql = sprintf( + 'USE FEDERATION %s (%s = %s) WITH RESET, FILTERING = %s;', + $platform->quoteIdentifier($this->federationName), + $platform->quoteIdentifier($this->distributionKey), + $this->conn->quote($distributionValue), + ($this->filteringEnabled ? 'ON' : 'OFF') + ); + + $this->conn->exec($sql); + $this->currentDistributionValue = $distributionValue; + } + + /** + * {@inheritDoc} + */ + public function getCurrentDistributionValue() + { + return $this->currentDistributionValue; + } + + /** + * {@inheritDoc} + */ + public function getShards() + { + $sql = 'SELECT member_id as id, + distribution_name as distribution_key, + CAST(range_low AS CHAR) AS rangeLow, + CAST(range_high AS CHAR) AS rangeHigh + FROM sys.federation_member_distributions d + INNER JOIN sys.federations f ON f.federation_id = d.federation_id + WHERE f.name = ' . $this->conn->quote($this->federationName); + + return $this->conn->fetchAllAssociative($sql); + } + + /** + * {@inheritDoc} + */ + public function queryAll($sql, array $params = [], array $types = []) + { + $shards = $this->getShards(); + if (! $shards) { + throw new RuntimeException('No shards found for ' . $this->federationName); + } + + $result = []; + $oldDistribution = $this->getCurrentDistributionValue(); + + foreach ($shards as $shard) { + $this->selectShard($shard['rangeLow']); + foreach ($this->conn->fetchAllAssociative($sql, $params, $types) as $row) { + $result[] = $row; + } + } + + if ($oldDistribution === null) { + $this->selectGlobal(); + } else { + $this->selectShard($oldDistribution); + } + + return $result; + } + + /** + * Splits Federation at a given distribution value. + * + * @param mixed $splitDistributionValue + * + * @return void + */ + public function splitFederation($splitDistributionValue) + { + $type = Type::getType($this->distributionType); + + $sql = 'ALTER FEDERATION ' . $this->getFederationName() . ' ' . + 'SPLIT AT (' . $this->getDistributionKey() . ' = ' . + $this->conn->quote($splitDistributionValue, $type->getBindingType()) . ')'; + $this->conn->exec($sql); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php new file mode 100755 index 0000000..d9ef9e8 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php @@ -0,0 +1,152 @@ +excludedTables = $excludedTables; + $this->tenantColumnName = $tenantColumnName; + $this->distributionName = $distributionName ?: $tenantColumnName; + } + + /** + * {@inheritdoc} + */ + public function acceptTable(Table $table) + { + if (in_array($table->getName(), $this->excludedTables)) { + return; + } + + $table->addColumn($this->tenantColumnName, $this->tenantColumnType, [ + 'default' => "federation_filtering_value('" . $this->distributionName . "')", + ]); + + $clusteredIndex = $this->getClusteredIndex($table); + + $indexColumns = $clusteredIndex->getColumns(); + $indexColumns[] = $this->tenantColumnName; + + if ($clusteredIndex->isPrimary()) { + $table->dropPrimaryKey(); + $table->setPrimaryKey($indexColumns); + } else { + $table->dropIndex($clusteredIndex->getName()); + $table->addIndex($indexColumns, $clusteredIndex->getName()); + $table->getIndex($clusteredIndex->getName())->addFlag('clustered'); + } + } + + /** + * @param Table $table + * + * @return Index + * + * @throws RuntimeException + */ + private function getClusteredIndex($table) + { + foreach ($table->getIndexes() as $index) { + if ($index->isPrimary() && ! $index->hasFlag('nonclustered')) { + return $index; + } + + if ($index->hasFlag('clustered')) { + return $index; + } + } + + throw new RuntimeException('No clustered index found on table ' . $table->getName()); + } + + /** + * {@inheritdoc} + */ + public function acceptSchema(Schema $schema) + { + } + + /** + * {@inheritdoc} + */ + public function acceptColumn(Table $table, Column $column) + { + } + + /** + * {@inheritdoc} + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + } + + /** + * {@inheritdoc} + */ + public function acceptIndex(Table $table, Index $index) + { + } + + /** + * {@inheritdoc} + */ + public function acceptSequence(Sequence $sequence) + { + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php new file mode 100755 index 0000000..f44c3af --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php @@ -0,0 +1,22 @@ +Statement for the given SQL and Connection. + * + * @internal The statement can be only instantiated by {@link Connection}. + * + * @param string $sql The SQL of the statement. + * @param Connection $conn The connection on which the statement should be executed. + */ + public function __construct($sql, Connection $conn) + { + $this->sql = $sql; + $this->stmt = $conn->getWrappedConnection()->prepare($sql); + $this->conn = $conn; + $this->platform = $conn->getDatabasePlatform(); + } + + /** + * Binds a parameter value to the statement. + * + * The value can optionally be bound with a PDO binding type or a DBAL mapping type. + * If bound with a DBAL mapping type, the binding type is derived from the mapping + * type and the value undergoes the conversion routines of the mapping type before + * being bound. + * + * @param string|int $param The name or position of the parameter. + * @param mixed $value The value of the parameter. + * @param mixed $type Either a PDO binding type or a DBAL mapping type name or instance. + * + * @return bool TRUE on success, FALSE on failure. + */ + public function bindValue($param, $value, $type = ParameterType::STRING) + { + $this->params[$param] = $value; + $this->types[$param] = $type; + if ($type !== null) { + if (is_string($type)) { + $type = Type::getType($type); + } + + if ($type instanceof Type) { + $value = $type->convertToDatabaseValue($value, $this->platform); + $bindingType = $type->getBindingType(); + } else { + $bindingType = $type; + } + + return $this->stmt->bindValue($param, $value, $bindingType); + } + + return $this->stmt->bindValue($param, $value); + } + + /** + * Binds a parameter to a value by reference. + * + * Binding a parameter by reference does not support DBAL mapping types. + * + * @param string|int $param The name or position of the parameter. + * @param mixed $variable The reference to the variable to bind. + * @param int $type The PDO binding type. + * @param int|null $length Must be specified when using an OUT bind + * so that PHP allocates enough memory to hold the returned value. + * + * @return bool TRUE on success, FALSE on failure. + */ + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) + { + $this->params[$param] = $variable; + $this->types[$param] = $type; + + if ($this->stmt instanceof PDOStatement) { + $length = $length ?? 0; + } + + return $this->stmt->bindParam($param, $variable, $type, $length); + } + + /** + * Executes the statement with the currently bound parameters. + * + * @deprecated Statement::execute() is deprecated, use Statement::executeQuery() or executeStatement() instead + * + * @param mixed[]|null $params + * + * @return bool TRUE on success, FALSE on failure. + * + * @throws Exception + */ + public function execute($params = null) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4580', + 'Statement::execute() is deprecated, use Statement::executeQuery() or Statement::executeStatement() instead' + ); + + if (is_array($params)) { + $this->params = $params; + } + + $logger = $this->conn->getConfiguration()->getSQLLogger(); + if ($logger) { + $logger->startQuery($this->sql, $this->params, $this->types); + } + + try { + $stmt = $this->stmt->execute($params); + } catch (Throwable $ex) { + if ($logger) { + $logger->stopQuery(); + } + + $this->conn->handleExceptionDuringQuery($ex, $this->sql, $this->params, $this->types); + } + + if ($logger) { + $logger->stopQuery(); + } + + return $stmt; + } + + /** + * Executes the statement with the currently bound parameters and return result. + * + * @param mixed[] $params + * + * @throws Exception + */ + public function executeQuery(array $params = []): BaseResult + { + if ($params === []) { + $params = null; // Workaround as long execute() exists and used internally. + } + + $this->execute($params); + + return new ForwardCompatibility\Result($this); + } + + /** + * Executes the statement with the currently bound parameters and return affected rows. + * + * @param mixed[] $params + * + * @throws Exception + */ + public function executeStatement(array $params = []): int + { + if ($params === []) { + $params = null; // Workaround as long execute() exists and used internally. + } + + $this->execute($params); + + return $this->rowCount(); + } + + /** + * Closes the cursor, freeing the database resources used by this statement. + * + * @deprecated Use Result::free() instead. + * + * @return bool TRUE on success, FALSE on failure. + */ + public function closeCursor() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4049', + 'Statement::closeCursor() is deprecated, use Result::free() instead.' + ); + + return $this->stmt->closeCursor(); + } + + /** + * Returns the number of columns in the result set. + * + * @return int + */ + public function columnCount() + { + return $this->stmt->columnCount(); + } + + /** + * Fetches the SQLSTATE associated with the last operation on the statement. + * + * @deprecated The error information is available via exceptions. + * + * @return string|int|bool + */ + public function errorCode() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3507', + 'Connection::errorCode() is deprecated, use getCode() or getSQLState() on Exception instead.' + ); + + return $this->stmt->errorCode(); + } + + /** + * {@inheritDoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3507', + 'Connection::errorInfo() is deprecated, use getCode() or getSQLState() on Exception instead.' + ); + + return $this->stmt->errorInfo(); + } + + /** + * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Statement::setFetchMode() is deprecated, use explicit Result::fetch*() APIs instead.' + ); + + if ($arg2 === null) { + return $this->stmt->setFetchMode($fetchMode); + } + + if ($arg3 === null) { + return $this->stmt->setFetchMode($fetchMode, $arg2); + } + + return $this->stmt->setFetchMode($fetchMode, $arg2, $arg3); + } + + /** + * Required by interface IteratorAggregate. + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. + * + * {@inheritdoc} + */ + #[ReturnTypeWillChange] + public function getIterator() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Statement::getIterator() is deprecated, use Result::iterateNumeric(), iterateAssociative() ' . + 'or iterateColumn() instead.' + ); + + return $this->stmt; + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + */ + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Statement::fetch() is deprecated, use Result::fetchNumeric(), fetchAssociative() or fetchOne() instead.' + ); + + return $this->stmt->fetch(...func_get_args()); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Statement::fetchAll() is deprecated, use Result::fetchAllNumeric(), fetchAllAssociative() or ' . + 'fetchFirstColumn() instead.' + ); + + if ($ctorArgs !== null) { + return $this->stmt->fetchAll($fetchMode, $fetchArgument, $ctorArgs); + } + + if ($fetchArgument !== null) { + return $this->stmt->fetchAll($fetchMode, $fetchArgument); + } + + return $this->stmt->fetchAll($fetchMode); + } + + /** + * {@inheritDoc} + * + * @deprecated Use fetchOne() instead. + */ + public function fetchColumn($columnIndex = 0) + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/4019', + 'Statement::fetchColumn() is deprecated, use Result::fetchOne() instead.' + ); + + return $this->stmt->fetchColumn($columnIndex); + } + + /** + * {@inheritdoc} + * + * @deprecated Use Result::fetchNumeric() instead + * + * @throws Exception + */ + public function fetchNumeric() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + try { + if ($this->stmt instanceof Result) { + return $this->stmt->fetchNumeric(); + } + + return $this->stmt->fetch(FetchMode::NUMERIC); + } catch (Exception $e) { + $this->conn->handleDriverException($e); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use Result::fetchAssociative() instead + * + * @throws Exception + */ + public function fetchAssociative() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + try { + if ($this->stmt instanceof Result) { + return $this->stmt->fetchAssociative(); + } + + return $this->stmt->fetch(FetchMode::ASSOCIATIVE); + } catch (Exception $e) { + $this->conn->handleDriverException($e); + } + } + + /** + * {@inheritDoc} + * + * @deprecated Use Result::fetchOne() instead + * + * @throws Exception + */ + public function fetchOne() + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + try { + if ($this->stmt instanceof Result) { + return $this->stmt->fetchOne(); + } + + return $this->stmt->fetch(FetchMode::COLUMN); + } catch (Exception $e) { + $this->conn->handleDriverException($e); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use Result::fetchAllNumeric() instead + * + * @throws Exception + */ + public function fetchAllNumeric(): array + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + try { + if ($this->stmt instanceof Result) { + return $this->stmt->fetchAllNumeric(); + } + + return $this->stmt->fetchAll(FetchMode::NUMERIC); + } catch (Exception $e) { + $this->conn->handleDriverException($e); + } + } + + /** + * {@inheritdoc} + * + * @deprecated Use Result::fetchAllAssociative() instead + * + * @throws Exception + */ + public function fetchAllAssociative(): array + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + try { + if ($this->stmt instanceof Result) { + return $this->stmt->fetchAllAssociative(); + } + + return $this->stmt->fetchAll(FetchMode::ASSOCIATIVE); + } catch (Exception $e) { + $this->conn->handleDriverException($e); + } + } + + /** + * Returns an associative array with the keys mapped to the first column and the values mapped to the second column. + * + * The result must contain at least two columns. + * + * @deprecated Use Result::fetchAllKeyValue() instead + * + * @return array + * + * @throws Exception + */ + public function fetchAllKeyValue(): array + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + $this->ensureHasKeyValue(); + + $data = []; + + foreach ($this->fetchAllNumeric() as [$key, $value]) { + $data[$key] = $value; + } + + return $data; + } + + /** + * Returns an associative array with the keys mapped to the first column and the values being + * an associative array representing the rest of the columns and their values. + * + * @deprecated Use Result::fetchAllAssociativeIndexed() instead + * + * @return array> + * + * @throws Exception + */ + public function fetchAllAssociativeIndexed(): array + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + $data = []; + + foreach ($this->fetchAll(FetchMode::ASSOCIATIVE) as $row) { + $data[array_shift($row)] = $row; + } + + return $data; + } + + /** + * {@inheritdoc} + * + * @deprecated Use Result::fetchFirstColumn() instead + * + * @throws Exception + */ + public function fetchFirstColumn(): array + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + try { + if ($this->stmt instanceof Result) { + return $this->stmt->fetchFirstColumn(); + } + + return $this->stmt->fetchAll(FetchMode::COLUMN); + } catch (Exception $e) { + $this->conn->handleDriverException($e); + } + } + + /** + * {@inheritDoc} + * + * @deprecated Use Result::iterateNumeric() instead + * + * @return Traversable> + * + * @throws Exception + */ + public function iterateNumeric(): Traversable + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + try { + if ($this->stmt instanceof Result) { + while (($row = $this->stmt->fetchNumeric()) !== false) { + yield $row; + } + } else { + while (($row = $this->stmt->fetch(FetchMode::NUMERIC)) !== false) { + yield $row; + } + } + } catch (Exception $e) { + $this->conn->handleDriverException($e); + } + } + + /** + * {@inheritDoc} + * + * @deprecated Use Result::iterateAssociative() instead + * + * @return Traversable> + * + * @throws Exception + */ + public function iterateAssociative(): Traversable + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + try { + if ($this->stmt instanceof Result) { + while (($row = $this->stmt->fetchAssociative()) !== false) { + yield $row; + } + } else { + while (($row = $this->stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) { + yield $row; + } + } + } catch (Exception $e) { + $this->conn->handleDriverException($e); + } + } + + /** + * Returns an iterator over the result set with the keys mapped to the first column + * and the values mapped to the second column. + * + * The result must contain at least two columns. + * + * @deprecated Use Result::iterateKeyValue() instead + * + * @return Traversable + * + * @throws Exception + */ + public function iterateKeyValue(): Traversable + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + $this->ensureHasKeyValue(); + + foreach ($this->iterateNumeric() as [$key, $value]) { + yield $key => $value; + } + } + + /** + * Returns an iterator over the result set with the keys mapped to the first column and the values being + * an associative array representing the rest of the columns and their values. + * + * @deprecated Use Result::iterateAssociativeIndexed() instead + * + * @return Traversable> + * + * @throws Exception + */ + public function iterateAssociativeIndexed(): Traversable + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + while (($row = $this->stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) { + yield array_shift($row) => $row; + } + } + + /** + * {@inheritDoc} + * + * @deprecated Use Result::iterateColumn() instead + * + * @return Traversable + * + * @throws Exception + */ + public function iterateColumn(): Traversable + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/issues/4554', + 'Statement::%s() is deprecated, use Result::%s() instead.', + __FUNCTION__, + __FUNCTION__ + ); + + try { + if ($this->stmt instanceof Result) { + while (($value = $this->stmt->fetchOne()) !== false) { + yield $value; + } + } else { + while (($value = $this->stmt->fetch(FetchMode::COLUMN)) !== false) { + yield $value; + } + } + } catch (Exception $e) { + $this->conn->handleDriverException($e); + } + } + + /** + * Returns the number of rows affected by the last execution of this statement. + * + * @return int The number of affected rows. + */ + public function rowCount() + { + return $this->stmt->rowCount(); + } + + public function free(): void + { + if ($this->stmt instanceof Result) { + $this->stmt->free(); + + return; + } + + $this->stmt->closeCursor(); + } + + /** + * Gets the wrapped driver statement. + * + * @return \Doctrine\DBAL\Driver\Statement + */ + public function getWrappedStatement() + { + return $this->stmt; + } + + private function ensureHasKeyValue(): void + { + $columnCount = $this->columnCount(); + + if ($columnCount < 2) { + throw NoKeyValue::fromColumnCount($columnCount); + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php new file mode 100755 index 0000000..2f23757 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php @@ -0,0 +1,145 @@ +setName('dbal:import') + ->setDescription('Import SQL file(s) directly to Database.') + ->setDefinition([new InputArgument( + 'file', + InputArgument::REQUIRED | InputArgument::IS_ARRAY, + 'File path(s) of SQL to be executed.' + ), + ]) + ->setHelp(<<getHelper('db')->getConnection(); + + $fileNames = $input->getArgument('file'); + + if ($fileNames === null) { + return 0; + } + + foreach ((array) $fileNames as $fileName) { + $filePath = realpath($fileName); + + // Phar compatibility. + if ($filePath === false) { + $filePath = $fileName; + } + + if (! file_exists($filePath)) { + throw new InvalidArgumentException( + sprintf("SQL file '%s' does not exist.", $filePath) + ); + } + + if (! is_readable($filePath)) { + throw new InvalidArgumentException( + sprintf("SQL file '%s' does not have read permissions.", $filePath) + ); + } + + $output->write(sprintf("Processing file '%s'... ", $filePath)); + $sql = @file_get_contents($filePath); + + if ($sql === false) { + $message = sprintf("Unable to read SQL file '%s'", $filePath); + $error = error_get_last(); + + if ($error !== null) { + $message .= ': ' . $error['message']; + } + + throw new RuntimeException($message); + } + + if ($conn instanceof PDOConnection) { + // PDO Drivers + try { + $lines = 0; + + $stmt = $conn->prepare($sql); + assert($stmt instanceof PDOStatement); + + $stmt->execute(); + + do { + // Required due to "MySQL has gone away!" issue + $stmt->fetch(); + $stmt->closeCursor(); + + $lines++; + } while ($stmt->nextRowset()); + + $output->write(sprintf('%d statements executed!', $lines) . PHP_EOL); + } catch (PDOException $e) { + $output->write('error!' . PHP_EOL); + + throw new RuntimeException($e->getMessage(), $e->getCode(), $e); + } + } else { + // Non-PDO Drivers (ie. OCI8 driver) + $stmt = $conn->prepare($sql); + $rs = $stmt->execute(); + + if (! $rs) { + $error = $stmt->errorInfo(); + + $output->write('error!' . PHP_EOL); + + throw new RuntimeException($error[2], $error[0]); + } + + $output->writeln('OK!' . PHP_EOL); + + $stmt->closeCursor(); + } + } + + return 0; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php new file mode 100755 index 0000000..c2fe410 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php @@ -0,0 +1,244 @@ +> */ + private $keywordListClasses = [ + 'mysql' => MySQLKeywords::class, + 'mysql57' => MySQL57Keywords::class, + 'mysql80' => MySQL80Keywords::class, + 'sqlserver' => SQLServerKeywords::class, + 'sqlserver2005' => SQLServer2005Keywords::class, + 'sqlserver2008' => SQLServer2008Keywords::class, + 'sqlserver2012' => SQLServer2012Keywords::class, + 'sqlite' => SQLiteKeywords::class, + 'pgsql' => PostgreSQLKeywords::class, + 'pgsql91' => PostgreSQL91Keywords::class, + 'pgsql92' => PostgreSQL92Keywords::class, + 'oracle' => OracleKeywords::class, + 'db2' => DB2Keywords::class, + 'sqlanywhere' => SQLAnywhereKeywords::class, + 'sqlanywhere11' => SQLAnywhere11Keywords::class, + 'sqlanywhere12' => SQLAnywhere12Keywords::class, + 'sqlanywhere16' => SQLAnywhere16Keywords::class, + ]; + + /** @var ConnectionProvider|null */ + private $connectionProvider; + + public function __construct(?ConnectionProvider $connectionProvider = null) + { + parent::__construct(); + $this->connectionProvider = $connectionProvider; + if ($connectionProvider !== null) { + return; + } + + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3956', + 'Not passing a connection provider as the first constructor argument is deprecated' + ); + } + + /** + * If you want to add or replace a keywords list use this command. + * + * @param string $name + * @param class-string $class + * + * @return void + */ + public function setKeywordListClass($name, $class) + { + $this->keywordListClasses[$name] = $class; + } + + /** @return void */ + protected function configure() + { + $this + ->setName('dbal:reserved-words') + ->setDescription('Checks if the current database contains identifiers that are reserved.') + ->setDefinition([ + new InputOption('connection', null, InputOption::VALUE_REQUIRED, 'The named database connection'), + new InputOption( + 'list', + 'l', + InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, + 'Keyword-List name.' + ), + ]) + ->setHelp(<<%command.full_name% + +If you want to check against specific dialects you can +pass them to the command: + + %command.full_name% -l mysql -l pgsql + +The following keyword lists are currently shipped with Doctrine: + + * mysql + * mysql57 + * mysql80 + * pgsql + * pgsql92 + * sqlite + * oracle + * sqlserver + * sqlserver2005 + * sqlserver2008 + * sqlserver2012 + * sqlanywhere + * sqlanywhere11 + * sqlanywhere12 + * sqlanywhere16 + * db2 (Not checked by default) +EOT + ); + } + + /** + * {@inheritdoc} + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $conn = $this->getConnection($input); + + $keywordLists = $input->getOption('list'); + + if (is_string($keywordLists)) { + $keywordLists = [$keywordLists]; + } elseif (! is_array($keywordLists)) { + $keywordLists = []; + } + + if (! $keywordLists) { + $keywordLists = [ + 'mysql', + 'mysql57', + 'mysql80', + 'pgsql', + 'pgsql92', + 'sqlite', + 'oracle', + 'sqlserver', + 'sqlserver2005', + 'sqlserver2008', + 'sqlserver2012', + 'sqlanywhere', + 'sqlanywhere11', + 'sqlanywhere12', + 'sqlanywhere16', + ]; + } + + $keywords = []; + foreach ($keywordLists as $keywordList) { + if (! isset($this->keywordListClasses[$keywordList])) { + throw new InvalidArgumentException( + "There exists no keyword list with name '" . $keywordList . "'. " . + 'Known lists: ' . implode(', ', array_keys($this->keywordListClasses)) + ); + } + + $class = $this->keywordListClasses[$keywordList]; + $keywords[] = new $class(); + } + + $output->write( + 'Checking keyword violations for ' . implode(', ', $keywordLists) . '...', + true + ); + + $schema = $conn->getSchemaManager()->createSchema(); + $visitor = new ReservedKeywordsValidator($keywords); + $schema->visit($visitor); + + $violations = $visitor->getViolations(); + if (count($violations) !== 0) { + $output->write( + 'There are ' . count($violations) . ' reserved keyword violations' + . ' in your database schema:', + true + ); + + foreach ($violations as $violation) { + $output->write(' - ' . $violation, true); + } + + return 1; + } + + $output->write('No reserved keywords violations have been found!', true); + + return 0; + } + + private function getConnection(InputInterface $input): Connection + { + $connectionName = $input->getOption('connection'); + assert(is_string($connectionName) || $connectionName === null); + + if ($this->connectionProvider === null) { + if ($connectionName !== null) { + throw new Exception('Specifying a connection is only supported when a ConnectionProvider is used.'); + } + + return $this->getHelper('db')->getConnection(); + } + + if ($connectionName !== null) { + return $this->connectionProvider->getConnection($connectionName); + } + + return $this->connectionProvider->getDefaultConnection(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php new file mode 100755 index 0000000..55c13e4 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php @@ -0,0 +1,121 @@ +connectionProvider = $connectionProvider; + if ($connectionProvider !== null) { + return; + } + + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3956', + 'Not passing a connection provider as the first constructor argument is deprecated' + ); + } + + /** @return void */ + protected function configure() + { + $this + ->setName('dbal:run-sql') + ->setDescription('Executes arbitrary SQL directly from the command line.') + ->setDefinition([ + new InputOption('connection', null, InputOption::VALUE_REQUIRED, 'The named database connection'), + new InputArgument('sql', InputArgument::REQUIRED, 'The SQL statement to execute.'), + new InputOption('depth', null, InputOption::VALUE_REQUIRED, 'Dumping depth of result set.', '7'), + new InputOption('force-fetch', null, InputOption::VALUE_NONE, 'Forces fetching the result.'), + ]) + ->setHelp(<<%command.name% command executes the given SQL query and +outputs the results: + +php %command.full_name% "SELECT * FROM users" +EOT + ); + } + + /** + * {@inheritdoc} + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $conn = $this->getConnection($input); + + $sql = $input->getArgument('sql'); + + if ($sql === null) { + throw new RuntimeException("Argument 'SQL' is required in order to execute this command correctly."); + } + + assert(is_string($sql)); + + $depth = $input->getOption('depth'); + + if (! is_numeric($depth)) { + throw new LogicException("Option 'depth' must contains an integer value"); + } + + if (stripos($sql, 'select') === 0 || $input->getOption('force-fetch')) { + $resultSet = $conn->fetchAllAssociative($sql); + } else { + $resultSet = $conn->executeStatement($sql); + } + + $output->write(Dumper::dump($resultSet, (int) $depth)); + + return 0; + } + + private function getConnection(InputInterface $input): Connection + { + $connectionName = $input->getOption('connection'); + assert(is_string($connectionName) || $connectionName === null); + + if ($this->connectionProvider === null) { + if ($connectionName !== null) { + throw new Exception('Specifying a connection is only supported when a ConnectionProvider is used.'); + } + + return $this->getHelper('db')->getConnection(); + } + + if ($connectionName !== null) { + return $this->connectionProvider->getConnection($connectionName); + } + + return $this->connectionProvider->getDefaultConnection(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/ConnectionNotFound.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/ConnectionNotFound.php new file mode 100755 index 0000000..81ca418 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/ConnectionNotFound.php @@ -0,0 +1,9 @@ +connection = $connection; + $this->defaultConnectionName = $defaultConnectionName; + } + + public function getDefaultConnection(): Connection + { + return $this->connection; + } + + public function getConnection(string $name): Connection + { + if ($name !== $this->defaultConnectionName) { + throw new ConnectionNotFound(sprintf('Connection with name "%s" does not exist.', $name)); + } + + return $this->connection; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php new file mode 100755 index 0000000..7fc14c3 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php @@ -0,0 +1,118 @@ + new ConnectionHelper($connection), + ]); + } + + /** + * Runs console with the given connection provider or helperset (deprecated). + * + * @param ConnectionProvider|HelperSet $helperSetOrConnectionProvider + * @param Command[] $commands + * + * @return void + */ + public static function run($helperSetOrConnectionProvider, $commands = []) + { + $cli = new Application('Doctrine Command Line Interface', Version::VERSION); + + $cli->setCatchExceptions(true); + + $connectionProvider = null; + if ($helperSetOrConnectionProvider instanceof HelperSet) { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3956', + 'Passing an instance of "%s" as the first argument is deprecated. Pass an instance of "%s" instead.', + HelperSet::class, + ConnectionProvider::class + ); + $connectionProvider = null; + $cli->setHelperSet($helperSetOrConnectionProvider); + } elseif ($helperSetOrConnectionProvider instanceof ConnectionProvider) { + $connectionProvider = $helperSetOrConnectionProvider; + } else { + throw new TypeError(sprintf( + 'First argument must be an instance of "%s" or "%s"', + HelperSet::class, + ConnectionProvider::class + )); + } + + self::addCommands($cli, $connectionProvider); + + $cli->addCommands($commands); + $cli->run(); + } + + /** + * @return void + */ + public static function addCommands(Application $cli, ?ConnectionProvider $connectionProvider = null) + { + $cli->addCommands([ + new RunSqlCommand($connectionProvider), + new ImportCommand(), + new ReservedWordsCommand($connectionProvider), + ]); + } + + /** + * Prints the instructions to create a configuration file + * + * @return void + */ + public static function printCliConfigTemplate() + { + echo <<<'HELP' +You are missing a "cli-config.php" or "config/cli-config.php" file in your +project, which is required to get the Doctrine-DBAL Console working. You can use the +following sample as a template: + +_connection = $connection; + } + + /** + * Retrieves the Doctrine database Connection. + * + * @return Connection + */ + public function getConnection() + { + return $this->_connection; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'connection'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Dumper.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Dumper.php new file mode 100755 index 0000000..c1e72aa --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Dumper.php @@ -0,0 +1,182 @@ +toArray(); + } + + if ($maxDepth === 0) { + return is_object($var) ? get_class($var) + : (is_array($var) ? 'Array(' . count($var) . ')' : $var); + } + + if (is_array($var)) { + $return = []; + + foreach ($var as $k => $v) { + $return[$k] = self::export($v, $maxDepth - 1); + } + + return $return; + } + + if (! $isObj) { + return $var; + } + + $return = new stdClass(); + if ($var instanceof DateTimeInterface) { + $return->__CLASS__ = get_class($var); + $return->date = $var->format('c'); + $return->timezone = $var->getTimezone()->getName(); + + return $return; + } + + $return->__CLASS__ = self::getClass($var); + + if ($var instanceof Proxy) { + $return->__IS_PROXY__ = true; + $return->__PROXY_INITIALIZED__ = $var->__isInitialized(); + } + + if ($var instanceof ArrayObject || $var instanceof ArrayIterator) { + $return->__STORAGE__ = self::export($var->getArrayCopy(), $maxDepth - 1); + } + + return self::fillReturnWithClassAttributes($var, $return, $maxDepth); + } + + /** + * Fill the $return variable with class attributes + * Based on obj2array function from {@see https://secure.php.net/manual/en/function.get-object-vars.php#47075} + * + * @param object $var + * + * @return mixed + */ + private static function fillReturnWithClassAttributes($var, stdClass $return, int $maxDepth) + { + $clone = (array) $var; + + foreach (array_keys($clone) as $key) { + $aux = explode("\0", $key); + $name = end($aux); + if ($aux[0] === '') { + $name .= ':' . ($aux[1] === '*' ? 'protected' : $aux[1] . ':private'); + } + + $return->$name = self::export($clone[$key], $maxDepth - 1); + } + + return $return; + } + + /** + * @param object $object + */ + private static function getClass($object): string + { + $class = get_class($object); + + if (! class_exists(Proxy::class)) { + return $class; + } + + $pos = strrpos($class, '\\' . Proxy::MARKER . '\\'); + + if ($pos === false) { + return $class; + } + + return substr($class, $pos + strlen(Proxy::MARKER) + 2); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/TransactionIsolationLevel.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/TransactionIsolationLevel.php new file mode 100755 index 0000000..e8dc5d9 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/TransactionIsolationLevel.php @@ -0,0 +1,35 @@ +getClobTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + // @todo 3.0 - $value === null check to save real NULL in database + return serialize($value); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return null; + } + + $value = is_resource($value) ? stream_get_contents($value) : $value; + + set_error_handler(function (int $code, string $message): bool { + throw ConversionException::conversionFailedUnserialization($this->getName(), $message); + }); + + try { + return unserialize($value); + } finally { + restore_error_handler(); + } + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return Types::ARRAY; + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/AsciiStringType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/AsciiStringType.php new file mode 100755 index 0000000..e797574 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/AsciiStringType.php @@ -0,0 +1,32 @@ +getAsciiStringTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function getBindingType() + { + return ParameterType::ASCII; + } + + public function getName(): string + { + return Types::ASCII_STRING; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BigIntType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BigIntType.php new file mode 100755 index 0000000..e5d6dcb --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BigIntType.php @@ -0,0 +1,44 @@ +getBigIntTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function getBindingType() + { + return ParameterType::STRING; + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return $value === null ? null : (string) $value; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BinaryType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BinaryType.php new file mode 100755 index 0000000..e030f16 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BinaryType.php @@ -0,0 +1,67 @@ +getBinaryTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return null; + } + + if (is_string($value)) { + $fp = fopen('php://temp', 'rb+'); + assert(is_resource($fp)); + fwrite($fp, $value); + fseek($fp, 0); + $value = $fp; + } + + if (! is_resource($value)) { + throw ConversionException::conversionFailed($value, Types::BINARY); + } + + return $value; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return Types::BINARY; + } + + /** + * {@inheritdoc} + */ + public function getBindingType() + { + return ParameterType::BINARY; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BlobType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BlobType.php new file mode 100755 index 0000000..b71e725 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BlobType.php @@ -0,0 +1,67 @@ +getBlobTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return null; + } + + if (is_string($value)) { + $fp = fopen('php://temp', 'rb+'); + assert(is_resource($fp)); + fwrite($fp, $value); + fseek($fp, 0); + $value = $fp; + } + + if (! is_resource($value)) { + throw ConversionException::conversionFailed($value, Types::BLOB); + } + + return $value; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return Types::BLOB; + } + + /** + * {@inheritdoc} + */ + public function getBindingType() + { + return ParameterType::LARGE_OBJECT; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BooleanType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BooleanType.php new file mode 100755 index 0000000..f6e4df3 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BooleanType.php @@ -0,0 +1,52 @@ +getBooleanTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return $platform->convertBooleansToDatabaseValue($value); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return $platform->convertFromBoolean($value); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return Types::BOOLEAN; + } + + /** + * {@inheritdoc} + */ + public function getBindingType() + { + return ParameterType::BOOLEAN; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ConversionException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ConversionException.php new file mode 100755 index 0000000..5be4743 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ConversionException.php @@ -0,0 +1,123 @@ + 32 ? substr($value, 0, 20) . '...' : $value; + + return new self('Could not convert database value "' . $value . '" to Doctrine Type ' . $toType, 0, $previous); + } + + /** + * Thrown when a Database to Doctrine Type Conversion fails and we can make a statement + * about the expected format. + * + * @param string $value + * @param string $toType + * @param string $expectedFormat + * + * @return ConversionException + */ + public static function conversionFailedFormat($value, $toType, $expectedFormat, ?Throwable $previous = null) + { + $value = strlen($value) > 32 ? substr($value, 0, 20) . '...' : $value; + + return new self( + 'Could not convert database value "' . $value . '" to Doctrine Type ' . + $toType . '. Expected format: ' . $expectedFormat, + 0, + $previous + ); + } + + /** + * Thrown when the PHP value passed to the converter was not of the expected type. + * + * @param mixed $value + * @param string $toType + * @param string[] $possibleTypes + * + * @return ConversionException + */ + public static function conversionFailedInvalidType( + $value, + $toType, + array $possibleTypes, + ?Throwable $previous = null + ) { + $actualType = is_object($value) ? get_class($value) : gettype($value); + + if (is_scalar($value)) { + return new self(sprintf( + "Could not convert PHP value '%s' of type '%s' to type '%s'. Expected one of the following types: %s", + $value, + $actualType, + $toType, + implode(', ', $possibleTypes) + ), 0, $previous); + } + + return new self(sprintf( + "Could not convert PHP value of type '%s' to type '%s'. Expected one of the following types: %s", + $actualType, + $toType, + implode(', ', $possibleTypes) + ), 0, $previous); + } + + /** + * @param mixed $value + * @param string $format + * @param string $error + * + * @return ConversionException + */ + public static function conversionFailedSerialization($value, $format, $error) + { + $actualType = is_object($value) ? get_class($value) : gettype($value); + + return new self(sprintf( + "Could not convert PHP type '%s' to '%s', as an '%s' error was triggered by the serialization", + $actualType, + $format, + $error + )); + } + + public static function conversionFailedUnserialization(string $format, string $error): self + { + return new self(sprintf( + "Could not convert database value to '%s' as an error was triggered by the unserialization: '%s'", + $format, + $error + )); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateImmutableType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateImmutableType.php new file mode 100755 index 0000000..a4c5d26 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateImmutableType.php @@ -0,0 +1,70 @@ +format($platform->getDateFormatString()); + } + + throw ConversionException::conversionFailedInvalidType( + $value, + $this->getName(), + ['null', DateTimeImmutable::class] + ); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof DateTimeImmutable) { + return $value; + } + + $dateTime = DateTimeImmutable::createFromFormat('!' . $platform->getDateFormatString(), $value); + + if (! $dateTime) { + throw ConversionException::conversionFailedFormat( + $value, + $this->getName(), + $platform->getDateFormatString() + ); + } + + return $dateTime; + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateIntervalType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateIntervalType.php new file mode 100755 index 0000000..6ecd498 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateIntervalType.php @@ -0,0 +1,88 @@ +getVarcharTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return null; + } + + if ($value instanceof DateInterval) { + return $value->format(self::FORMAT); + } + + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateInterval']); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof DateInterval) { + return $value; + } + + $negative = false; + + if (isset($value[0]) && ($value[0] === '+' || $value[0] === '-')) { + $negative = $value[0] === '-'; + $value = substr($value, 1); + } + + try { + $interval = new DateInterval($value); + + if ($negative) { + $interval->invert = 1; + } + + return $interval; + } catch (Throwable $exception) { + throw ConversionException::conversionFailedFormat($value, $this->getName(), self::FORMAT, $exception); + } + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeImmutableType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeImmutableType.php new file mode 100755 index 0000000..9af4fc3 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeImmutableType.php @@ -0,0 +1,76 @@ +format($platform->getDateTimeFormatString()); + } + + throw ConversionException::conversionFailedInvalidType( + $value, + $this->getName(), + ['null', DateTimeImmutable::class] + ); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof DateTimeImmutable) { + return $value; + } + + $dateTime = DateTimeImmutable::createFromFormat($platform->getDateTimeFormatString(), $value); + + if (! $dateTime) { + $dateTime = date_create_immutable($value); + } + + if (! $dateTime) { + throw ConversionException::conversionFailedFormat( + $value, + $this->getName(), + $platform->getDateTimeFormatString() + ); + } + + return $dateTime; + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php new file mode 100755 index 0000000..f6f6da0 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php @@ -0,0 +1,73 @@ +getDateTimeTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return $value; + } + + if ($value instanceof DateTimeInterface) { + return $value->format($platform->getDateTimeFormatString()); + } + + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof DateTimeInterface) { + return $value; + } + + $val = DateTime::createFromFormat($platform->getDateTimeFormatString(), $value); + + if (! $val) { + $val = date_create($value); + } + + if (! $val) { + throw ConversionException::conversionFailedFormat( + $value, + $this->getName(), + $platform->getDateTimeFormatString() + ); + } + + return $val; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeTzImmutableType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeTzImmutableType.php new file mode 100755 index 0000000..b888624 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeTzImmutableType.php @@ -0,0 +1,70 @@ +format($platform->getDateTimeTzFormatString()); + } + + throw ConversionException::conversionFailedInvalidType( + $value, + $this->getName(), + ['null', DateTimeImmutable::class] + ); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof DateTimeImmutable) { + return $value; + } + + $dateTime = DateTimeImmutable::createFromFormat($platform->getDateTimeTzFormatString(), $value); + + if (! $dateTime) { + throw ConversionException::conversionFailedFormat( + $value, + $this->getName(), + $platform->getDateTimeTzFormatString() + ); + } + + return $dateTime; + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeTzType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeTzType.php new file mode 100755 index 0000000..bc25890 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeTzType.php @@ -0,0 +1,79 @@ +getDateTimeTzTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return $value; + } + + if ($value instanceof DateTimeInterface) { + return $value->format($platform->getDateTimeTzFormatString()); + } + + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof DateTimeInterface) { + return $value; + } + + $val = DateTime::createFromFormat($platform->getDateTimeTzFormatString(), $value); + if (! $val) { + throw ConversionException::conversionFailedFormat( + $value, + $this->getName(), + $platform->getDateTimeTzFormatString() + ); + } + + return $val; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateType.php new file mode 100755 index 0000000..81cc86c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateType.php @@ -0,0 +1,66 @@ +getDateTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return $value; + } + + if ($value instanceof DateTimeInterface) { + return $value->format($platform->getDateFormatString()); + } + + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof DateTimeInterface) { + return $value; + } + + $val = DateTime::createFromFormat('!' . $platform->getDateFormatString(), $value); + if (! $val) { + throw ConversionException::conversionFailedFormat( + $value, + $this->getName(), + $platform->getDateFormatString() + ); + } + + return $val; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DecimalType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DecimalType.php new file mode 100755 index 0000000..c70067f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DecimalType.php @@ -0,0 +1,46 @@ +getDecimalTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + // Some drivers starting from PHP 8.1 can represent decimals as float/int + // See also: https://github.com/doctrine/dbal/pull/4818 + if (PHP_VERSION_ID >= 80100 && (is_float($value) || is_int($value))) { + return (string) $value; + } + + return $value; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/FloatType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/FloatType.php new file mode 100755 index 0000000..98ead4a --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/FloatType.php @@ -0,0 +1,32 @@ +getFloatDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return $value === null ? null : (float) $value; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/GuidType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/GuidType.php new file mode 100755 index 0000000..a4974f9 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/GuidType.php @@ -0,0 +1,35 @@ +getGuidTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return Types::GUID; + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return ! $platform->hasNativeGuidType(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/IntegerType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/IntegerType.php new file mode 100755 index 0000000..0df606e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/IntegerType.php @@ -0,0 +1,44 @@ +getIntegerTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return $value === null ? null : (int) $value; + } + + /** + * {@inheritdoc} + */ + public function getBindingType() + { + return ParameterType::INTEGER; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/JsonArrayType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/JsonArrayType.php new file mode 100755 index 0000000..400e0ef --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/JsonArrayType.php @@ -0,0 +1,47 @@ +getJsonTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return null; + } + + $encoded = json_encode($value); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw ConversionException::conversionFailedSerialization($value, 'json', json_last_error_msg()); + } + + return $encoded; + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value === '') { + return null; + } + + if (is_resource($value)) { + $value = stream_get_contents($value); + } + + $val = json_decode($value, true); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw ConversionException::conversionFailed($value, $this->getName()); + } + + return $val; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return Types::JSON; + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return ! $platform->hasNativeJsonType(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ObjectType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ObjectType.php new file mode 100755 index 0000000..49042c1 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ObjectType.php @@ -0,0 +1,72 @@ +getClobTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return serialize($value); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return null; + } + + $value = is_resource($value) ? stream_get_contents($value) : $value; + + set_error_handler(function (int $code, string $message): bool { + throw ConversionException::conversionFailedUnserialization($this->getName(), $message); + }); + + try { + return unserialize($value); + } finally { + restore_error_handler(); + } + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return Types::OBJECT; + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/PhpDateTimeMappingType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/PhpDateTimeMappingType.php new file mode 100755 index 0000000..4565850 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/PhpDateTimeMappingType.php @@ -0,0 +1,12 @@ +getClobTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if (! $value) { + return null; + } + + return implode(',', $value); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return []; + } + + $value = is_resource($value) ? stream_get_contents($value) : $value; + + return explode(',', $value); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return Types::SIMPLE_ARRAY; + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SmallIntType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SmallIntType.php new file mode 100755 index 0000000..90e6349 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SmallIntType.php @@ -0,0 +1,44 @@ +getSmallIntTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return $value === null ? null : (int) $value; + } + + /** + * {@inheritdoc} + */ + public function getBindingType() + { + return ParameterType::INTEGER; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/StringType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/StringType.php new file mode 100755 index 0000000..9a510ef --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/StringType.php @@ -0,0 +1,35 @@ +getVarcharTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function getDefaultLength(AbstractPlatform $platform) + { + return $platform->getVarcharDefaultLength(); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return Types::STRING; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TextType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TextType.php new file mode 100755 index 0000000..b1e640b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TextType.php @@ -0,0 +1,38 @@ +getClobTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return is_resource($value) ? stream_get_contents($value) : $value; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return Types::TEXT; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TimeImmutableType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TimeImmutableType.php new file mode 100755 index 0000000..cc43769 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TimeImmutableType.php @@ -0,0 +1,70 @@ +format($platform->getTimeFormatString()); + } + + throw ConversionException::conversionFailedInvalidType( + $value, + $this->getName(), + ['null', DateTimeImmutable::class] + ); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof DateTimeImmutable) { + return $value; + } + + $dateTime = DateTimeImmutable::createFromFormat('!' . $platform->getTimeFormatString(), $value); + + if (! $dateTime) { + throw ConversionException::conversionFailedFormat( + $value, + $this->getName(), + $platform->getTimeFormatString() + ); + } + + return $dateTime; + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TimeType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TimeType.php new file mode 100755 index 0000000..59bd7f7 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TimeType.php @@ -0,0 +1,66 @@ +getTimeTypeDeclarationSQL($column); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return $value; + } + + if ($value instanceof DateTimeInterface) { + return $value->format($platform->getTimeFormatString()); + } + + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof DateTimeInterface) { + return $value; + } + + $val = DateTime::createFromFormat('!' . $platform->getTimeFormatString(), $value); + if (! $val) { + throw ConversionException::conversionFailedFormat( + $value, + $this->getName(), + $platform->getTimeFormatString() + ); + } + + return $val; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/Type.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/Type.php new file mode 100755 index 0000000..64e59fe --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/Type.php @@ -0,0 +1,396 @@ + ArrayType::class, + Types::ASCII_STRING => AsciiStringType::class, + Types::BIGINT => BigIntType::class, + Types::BINARY => BinaryType::class, + Types::BLOB => BlobType::class, + Types::BOOLEAN => BooleanType::class, + Types::DATE_MUTABLE => DateType::class, + Types::DATE_IMMUTABLE => DateImmutableType::class, + Types::DATEINTERVAL => DateIntervalType::class, + Types::DATETIME_MUTABLE => DateTimeType::class, + Types::DATETIME_IMMUTABLE => DateTimeImmutableType::class, + Types::DATETIMETZ_MUTABLE => DateTimeTzType::class, + Types::DATETIMETZ_IMMUTABLE => DateTimeTzImmutableType::class, + Types::DECIMAL => DecimalType::class, + Types::FLOAT => FloatType::class, + Types::GUID => GuidType::class, + Types::INTEGER => IntegerType::class, + Types::JSON => JsonType::class, + Types::JSON_ARRAY => JsonArrayType::class, + Types::OBJECT => ObjectType::class, + Types::SIMPLE_ARRAY => SimpleArrayType::class, + Types::SMALLINT => SmallIntType::class, + Types::STRING => StringType::class, + Types::TEXT => TextType::class, + Types::TIME_MUTABLE => TimeType::class, + Types::TIME_IMMUTABLE => TimeImmutableType::class, + ]; + + /** @var TypeRegistry|null */ + private static $typeRegistry; + + /** + * @internal Do not instantiate directly - use {@see Type::addType()} method instead. + */ + final public function __construct() + { + } + + /** + * Converts a value from its PHP representation to its database representation + * of this type. + * + * @param mixed $value The value to convert. + * @param AbstractPlatform $platform The currently used database platform. + * + * @return mixed The database representation of the value. + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return $value; + } + + /** + * Converts a value from its database representation to its PHP representation + * of this type. + * + * @param mixed $value The value to convert. + * @param AbstractPlatform $platform The currently used database platform. + * + * @return mixed The PHP representation of the value. + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return $value; + } + + /** + * Gets the default length of this type. + * + * @deprecated Rely on information provided by the platform instead. + * + * @return int|null + */ + public function getDefaultLength(AbstractPlatform $platform) + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3255', + 'Type::getDefaultLength() is deprecated, use AbstractPlatform directly.' + ); + + return null; + } + + /** + * Gets the SQL declaration snippet for a column of this type. + * + * @param mixed[] $column The column definition + * @param AbstractPlatform $platform The currently used database platform. + * + * @return string + */ + abstract public function getSQLDeclaration(array $column, AbstractPlatform $platform); + + /** + * Gets the name of this type. + * + * @return string + * + * @todo Needed? + */ + abstract public function getName(); + + final public static function getTypeRegistry(): TypeRegistry + { + if (self::$typeRegistry === null) { + self::$typeRegistry = self::createTypeRegistry(); + } + + return self::$typeRegistry; + } + + private static function createTypeRegistry(): TypeRegistry + { + $instances = []; + + foreach (self::BUILTIN_TYPES_MAP as $name => $class) { + $instances[$name] = new $class(); + } + + return new TypeRegistry($instances); + } + + /** + * Factory method to create type instances. + * Type instances are implemented as flyweights. + * + * @param string $name The name of the type (as returned by getName()). + * + * @return Type + * + * @throws Exception + */ + public static function getType($name) + { + return self::getTypeRegistry()->get($name); + } + + /** + * Adds a custom type to the type map. + * + * @param string $name The name of the type. This should correspond to what getName() returns. + * @param class-string $className The class name of the custom type. + * + * @return void + * + * @throws Exception + */ + public static function addType($name, $className) + { + self::getTypeRegistry()->register($name, new $className()); + } + + /** + * Checks if exists support for a type. + * + * @param string $name The name of the type. + * + * @return bool TRUE if type is supported; FALSE otherwise. + */ + public static function hasType($name) + { + return self::getTypeRegistry()->has($name); + } + + /** + * Overrides an already defined type to use a different implementation. + * + * @param string $name + * @param class-string $className + * + * @return void + * + * @throws Exception + */ + public static function overrideType($name, $className) + { + self::getTypeRegistry()->override($name, new $className()); + } + + /** + * Gets the (preferred) binding type for values of this type that + * can be used when binding parameters to prepared statements. + * + * This method should return one of the {@link ParameterType} constants. + * + * @return int + */ + public function getBindingType() + { + return ParameterType::STRING; + } + + /** + * Gets the types array map which holds all registered types and the corresponding + * type class + * + * @return string[] + */ + public static function getTypesMap() + { + return array_map( + static function (Type $type): string { + return get_class($type); + }, + self::getTypeRegistry()->getMap() + ); + } + + /** + * @deprecated Relying on string representation is discouraged and will be removed in DBAL 3.0. + * + * @return string + */ + public function __toString() + { + Deprecation::trigger( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/3258', + 'Type::__toString() is deprecated, use Type::getName() or get_class($type) instead.' + ); + + $type = static::class; + $position = strrpos($type, '\\'); + + if ($position !== false) { + $type = substr($type, $position); + } + + return str_replace('Type', '', $type); + } + + /** + * Does working with this column require SQL conversion functions? + * + * This is a metadata function that is required for example in the ORM. + * Usage of {@link convertToDatabaseValueSQL} and + * {@link convertToPHPValueSQL} works for any type and mostly + * does nothing. This method can additionally be used for optimization purposes. + * + * @return bool + */ + public function canRequireSQLConversion() + { + return false; + } + + /** + * Modifies the SQL expression (identifier, parameter) to convert to a database value. + * + * @param string $sqlExpr + * + * @return string + */ + public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) + { + return $sqlExpr; + } + + /** + * Modifies the SQL expression (identifier, parameter) to convert to a PHP value. + * + * @param string $sqlExpr + * @param AbstractPlatform $platform + * + * @return string + */ + public function convertToPHPValueSQL($sqlExpr, $platform) + { + return $sqlExpr; + } + + /** + * Gets an array of database types that map to this Doctrine type. + * + * @return string[] + */ + public function getMappedDatabaseTypes(AbstractPlatform $platform) + { + return []; + } + + /** + * If this Doctrine Type maps to an already mapped database type, + * reverse schema engineering can't tell them apart. You need to mark + * one of those types as commented, which will have Doctrine use an SQL + * comment to typehint the actual Doctrine Type. + * + * @return bool + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return false; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TypeRegistry.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TypeRegistry.php new file mode 100755 index 0000000..ce33b95 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TypeRegistry.php @@ -0,0 +1,125 @@ + Map of type names and their corresponding flyweight objects. */ + private $instances; + + /** + * @param array $instances + */ + public function __construct(array $instances = []) + { + $this->instances = $instances; + } + + /** + * Finds a type by the given name. + * + * @throws Exception + */ + public function get(string $name): Type + { + if (! isset($this->instances[$name])) { + throw Exception::unknownColumnType($name); + } + + return $this->instances[$name]; + } + + /** + * Finds a name for the given type. + * + * @throws Exception + */ + public function lookupName(Type $type): string + { + $name = $this->findTypeName($type); + + if ($name === null) { + throw Exception::typeNotRegistered($type); + } + + return $name; + } + + /** + * Checks if there is a type of the given name. + */ + public function has(string $name): bool + { + return isset($this->instances[$name]); + } + + /** + * Registers a custom type to the type map. + * + * @throws Exception + */ + public function register(string $name, Type $type): void + { + if (isset($this->instances[$name])) { + throw Exception::typeExists($name); + } + + if ($this->findTypeName($type) !== null) { + throw Exception::typeAlreadyRegistered($type); + } + + $this->instances[$name] = $type; + } + + /** + * Overrides an already defined type to use a different implementation. + * + * @throws Exception + */ + public function override(string $name, Type $type): void + { + if (! isset($this->instances[$name])) { + throw Exception::typeNotFound($name); + } + + if (! in_array($this->findTypeName($type), [$name, null], true)) { + throw Exception::typeAlreadyRegistered($type); + } + + $this->instances[$name] = $type; + } + + /** + * Gets the map of all registered types and their corresponding type instances. + * + * @internal + * + * @return array + */ + public function getMap(): array + { + return $this->instances; + } + + private function findTypeName(Type $type): ?string + { + $name = array_search($type, $this->instances, true); + + if ($name === false) { + return null; + } + + return $name; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/Types.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/Types.php new file mode 100755 index 0000000..3ca6779 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/Types.php @@ -0,0 +1,47 @@ +format($platform->getDateTimeFormatString()); + } + + throw ConversionException::conversionFailedInvalidType( + $value, + $this->getName(), + ['null', DateTimeImmutable::class] + ); + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof DateTimeImmutable) { + return $value; + } + + $dateTime = date_create_immutable($value); + + if (! $dateTime) { + throw ConversionException::conversionFailed($value, $this->getName()); + } + + return $dateTime; + } + + /** + * {@inheritdoc} + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeType.php new file mode 100755 index 0000000..2096057 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeType.php @@ -0,0 +1,35 @@ + 0 it is necessary to use this type. + */ +class VarDateTimeType extends DateTimeType +{ + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof DateTime) { + return $value; + } + + $val = date_create($value); + if (! $val) { + throw ConversionException::conversionFailed($value, $this->getName()); + } + + return $val; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Version.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Version.php new file mode 100755 index 0000000..592816c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Version.php @@ -0,0 +1,35 @@ + $count) { + echo $identifier . " was triggered " . $count . " times\n"; +} +``` + +### Suppressing Specific Deprecations + +Disable triggering about specific deprecations: + +```php +\Doctrine\Deprecations\Deprecation::ignoreDeprecations("https://link/to/deprecations-description-identifier"); +``` + +Disable all deprecations from a package + +```php +\Doctrine\Deprecations\Deprecation::ignorePackage("doctrine/orm"); +``` + +### Other Operations + +When used within PHPUnit or other tools that could collect multiple instances of the same deprecations +the deduplication can be disabled: + +```php +\Doctrine\Deprecations\Deprecation::withoutDeduplication(); +``` + +Disable deprecation tracking again: + +```php +\Doctrine\Deprecations\Deprecation::disable(); +``` + +## Usage from a library/producer perspective: + +When you want to unconditionally trigger a deprecation even when called +from the library itself then the `trigger` method is the way to go: + +```php +\Doctrine\Deprecations\Deprecation::trigger( + "doctrine/orm", + "https://link/to/deprecations-description", + "message" +); +``` + +If variable arguments are provided at the end, they are used with `sprintf` on +the message. + +```php +\Doctrine\Deprecations\Deprecation::trigger( + "doctrine/orm", + "https://github.com/doctrine/orm/issue/1234", + "message %s %d", + "foo", + 1234 +); +``` + +When you want to trigger a deprecation only when it is called by a function +outside of the current package, but not trigger when the package itself is the cause, +then use: + +```php +\Doctrine\Deprecations\Deprecation::triggerIfCalledFromOutside( + "doctrine/orm", + "https://link/to/deprecations-description", + "message" +); +``` + +Based on the issue link each deprecation message is only triggered once per +request. + +A limited stacktrace is included in the deprecation message to find the +offending location. + +Note: A producer/library should never call `Deprecation::enableWith` methods +and leave the decision how to handle deprecations to application and +frameworks. + +## Usage in PHPUnit tests + +There is a `VerifyDeprecations` trait that you can use to make assertions on +the occurrence of deprecations within a test. + +```php +use Doctrine\Deprecations\PHPUnit\VerifyDeprecations; + +class MyTest extends TestCase +{ + use VerifyDeprecations; + + public function testSomethingDeprecation() + { + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234'); + + triggerTheCodeWithDeprecation(); + } +} +``` + +## What is a deprecation identifier? + +An identifier for deprecations is just a link to any resource, most often a +Github Issue or Pull Request explaining the deprecation and potentially its +alternative. diff --git a/vendor/doctrine/deprecations/composer.json b/vendor/doctrine/deprecations/composer.json new file mode 100755 index 0000000..5cc7ac1 --- /dev/null +++ b/vendor/doctrine/deprecations/composer.json @@ -0,0 +1,27 @@ +{ + "name": "doctrine/deprecations", + "type": "library", + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "license": "MIT", + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "psr/log": "^1.0", + "doctrine/coding-standard": "^6.0|^7.0|^8.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "autoload": { + "psr-4": {"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"} + }, + "autoload-dev": { + "psr-4": { + "DeprecationTests\\": "test_fixtures/src", + "Doctrine\\Foo\\": "test_fixtures/vendor/doctrine/foo" + } + } +} diff --git a/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php new file mode 100755 index 0000000..1029372 --- /dev/null +++ b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php @@ -0,0 +1,266 @@ + */ + private static $ignoredPackages = []; + + /** @var array */ + private static $ignoredLinks = []; + + /** @var bool */ + private static $deduplication = true; + + /** + * Trigger a deprecation for the given package and identfier. + * + * The link should point to a Github issue or Wiki entry detailing the + * deprecation. It is additionally used to de-duplicate the trigger of the + * same deprecation during a request. + * + * @param mixed $args + */ + public static function trigger(string $package, string $link, string $message, ...$args): void + { + if (self::$type === self::TYPE_NONE) { + return; + } + + if (array_key_exists($link, self::$ignoredLinks)) { + self::$ignoredLinks[$link]++; + } else { + self::$ignoredLinks[$link] = 1; + } + + if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) { + return; + } + + if (isset(self::$ignoredPackages[$package])) { + return; + } + + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + + $message = sprintf($message, ...$args); + + self::delegateTriggerToBackend($message, $backtrace, $link, $package); + } + + /** + * Trigger a deprecation for the given package and identifier when called from outside. + * + * "Outside" means we assume that $package is currently installed as a + * dependency and the caller is not a file in that package. When $package + * is installed as a root package then deprecations triggered from the + * tests folder are also considered "outside". + * + * This deprecation method assumes that you are using Composer to install + * the dependency and are using the default /vendor/ folder and not a + * Composer plugin to change the install location. The assumption is also + * that $package is the exact composer packge name. + * + * Compared to {@link trigger()} this method causes some overhead when + * deprecation tracking is enabled even during deduplication, because it + * needs to call {@link debug_backtrace()} + * + * @param mixed $args + */ + public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void + { + if (self::$type === self::TYPE_NONE) { + return; + } + + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + + // first check that the caller is not from a tests folder, in which case we always let deprecations pass + if (strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) { + $path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package . DIRECTORY_SEPARATOR; + + if (strpos($backtrace[0]['file'], $path) === false) { + return; + } + + if (strpos($backtrace[1]['file'], $path) !== false) { + return; + } + } + + if (array_key_exists($link, self::$ignoredLinks)) { + self::$ignoredLinks[$link]++; + } else { + self::$ignoredLinks[$link] = 1; + } + + if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) { + return; + } + + if (isset(self::$ignoredPackages[$package])) { + return; + } + + $message = sprintf($message, ...$args); + + self::delegateTriggerToBackend($message, $backtrace, $link, $package); + } + + /** + * @param array $backtrace + */ + private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void + { + if ((self::$type & self::TYPE_PSR_LOGGER) > 0) { + $context = [ + 'file' => $backtrace[0]['file'], + 'line' => $backtrace[0]['line'], + 'package' => $package, + 'link' => $link, + ]; + + self::$logger->notice($message, $context); + } + + if (! ((self::$type & self::TYPE_TRIGGER_ERROR) > 0)) { + return; + } + + $message .= sprintf( + ' (%s:%d called by %s:%d, %s, package %s)', + self::basename($backtrace[0]['file']), + $backtrace[0]['line'], + self::basename($backtrace[1]['file']), + $backtrace[1]['line'], + $link, + $package + ); + + @trigger_error($message, E_USER_DEPRECATED); + } + + /** + * A non-local-aware version of PHPs basename function. + */ + private static function basename(string $filename): string + { + $pos = strrpos($filename, DIRECTORY_SEPARATOR); + + if ($pos === false) { + return $filename; + } + + return substr($filename, $pos + 1); + } + + public static function enableTrackingDeprecations(): void + { + self::$type |= self::TYPE_TRACK_DEPRECATIONS; + } + + public static function enableWithTriggerError(): void + { + self::$type |= self::TYPE_TRIGGER_ERROR; + } + + public static function enableWithPsrLogger(LoggerInterface $logger): void + { + self::$type |= self::TYPE_PSR_LOGGER; + self::$logger = $logger; + } + + public static function withoutDeduplication(): void + { + self::$deduplication = false; + } + + public static function disable(): void + { + self::$type = self::TYPE_NONE; + self::$logger = null; + self::$deduplication = true; + + foreach (self::$ignoredLinks as $link => $count) { + self::$ignoredLinks[$link] = 0; + } + } + + public static function ignorePackage(string $packageName): void + { + self::$ignoredPackages[$packageName] = true; + } + + public static function ignoreDeprecations(string ...$links): void + { + foreach ($links as $link) { + self::$ignoredLinks[$link] = 0; + } + } + + public static function getUniqueTriggeredDeprecationsCount(): int + { + return array_reduce(self::$ignoredLinks, static function (int $carry, int $count) { + return $carry + $count; + }, 0); + } + + /** + * Returns each triggered deprecation link identifier and the amount of occurrences. + * + * @return array + */ + public static function getTriggeredDeprecations(): array + { + return self::$ignoredLinks; + } +} diff --git a/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php new file mode 100755 index 0000000..4c3366a --- /dev/null +++ b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php @@ -0,0 +1,66 @@ + */ + private $doctrineDeprecationsExpectations = []; + + /** @var array */ + private $doctrineNoDeprecationsExpectations = []; + + public function expectDeprecationWithIdentifier(string $identifier): void + { + $this->doctrineDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + } + + public function expectNoDeprecationWithIdentifier(string $identifier): void + { + $this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + } + + /** + * @before + */ + public function enableDeprecationTracking(): void + { + Deprecation::enableTrackingDeprecations(); + } + + /** + * @after + */ + public function verifyDeprecationsAreTriggered(): void + { + foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) { + $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + + $this->assertTrue( + $actualCount > $expectation, + sprintf( + "Expected deprecation with identifier '%s' was not triggered by code executed in test.", + $identifier + ) + ); + } + + foreach ($this->doctrineNoDeprecationsExpectations as $identifier => $expectation) { + $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + + $this->assertTrue( + $actualCount === $expectation, + sprintf( + "Expected deprecation with identifier '%s' was triggered by code executed in test, but expected not to.", + $identifier + ) + ); + } + } +} diff --git a/vendor/doctrine/deprecations/phpcs.xml b/vendor/doctrine/deprecations/phpcs.xml new file mode 100755 index 0000000..4e0cc21 --- /dev/null +++ b/vendor/doctrine/deprecations/phpcs.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + lib + tests + + + + + + diff --git a/vendor/doctrine/deprecations/phpunit.xml.dist b/vendor/doctrine/deprecations/phpunit.xml.dist new file mode 100755 index 0000000..4740c06 --- /dev/null +++ b/vendor/doctrine/deprecations/phpunit.xml.dist @@ -0,0 +1,8 @@ + + + + + tests + + + diff --git a/vendor/doctrine/deprecations/test_fixtures/src/Foo.php b/vendor/doctrine/deprecations/test_fixtures/src/Foo.php new file mode 100755 index 0000000..c4b8ebe --- /dev/null +++ b/vendor/doctrine/deprecations/test_fixtures/src/Foo.php @@ -0,0 +1,22 @@ +oldFunc(); + } + + public static function triggerDependencyWithDeprecationFromInside(): void + { + $bar = new Bar(); + $bar->newFunc(); + } +} diff --git a/vendor/doctrine/deprecations/test_fixtures/src/RootDeprecation.php b/vendor/doctrine/deprecations/test_fixtures/src/RootDeprecation.php new file mode 100755 index 0000000..feccd48 --- /dev/null +++ b/vendor/doctrine/deprecations/test_fixtures/src/RootDeprecation.php @@ -0,0 +1,20 @@ +setAccessible(true); + $reflectionProperty->setValue([]); + + $reflectionProperty = new ReflectionProperty(Deprecation::class, 'ignoredLinks'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue([]); + + Deprecation::enableTrackingDeprecations(); + } + + public function expectDeprecation(): void + { + if (method_exists(TestCase::class, 'expectDeprecation')) { + parent::expectDeprecation(); + } else { + parent::expectException(Deprecated::class); + } + } + + public function expectDeprecationMessage(string $message): void + { + if (method_exists(TestCase::class, 'expectDeprecationMessage')) { + parent::expectDeprecationMessage($message); + } else { + parent::expectExceptionMessage($message); + } + } + + public function expectErrorHandler(string $expectedMessage, string $identifier, int $times = 1): void + { + set_error_handler(function ($type, $message) use ($expectedMessage, $identifier, $times): void { + $this->assertStringMatchesFormat( + $expectedMessage, + $message + ); + $this->assertEquals([$identifier => $times], Deprecation::getTriggeredDeprecations()); + }); + } + + public function testDeprecation(): void + { + Deprecation::enableWithTriggerError(); + + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/deprecations/1234'); + + $this->expectErrorHandler( + 'this is deprecated foo 1234 (DeprecationTest.php:%d called by TestCase.php:%d, https://github.com/doctrine/deprecations/1234, package doctrine/orm)', + 'https://github.com/doctrine/deprecations/1234' + ); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/1234', + 'this is deprecated %s %d', + 'foo', + 1234 + ); + + $this->assertEquals(1, Deprecation::getUniqueTriggeredDeprecationsCount()); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/1234', + 'this is deprecated %s %d', + 'foo', + 1234 + ); + + $this->assertEquals(2, Deprecation::getUniqueTriggeredDeprecationsCount()); + } + + public function testDeprecationWithoutDeduplication(): void + { + Deprecation::enableWithTriggerError(); + Deprecation::withoutDeduplication(); + + $this->expectErrorHandler( + 'this is deprecated foo 2222 (DeprecationTest.php:%d called by TestCase.php:%d, https://github.com/doctrine/deprecations/2222, package doctrine/orm)', + 'https://github.com/doctrine/deprecations/2222' + ); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/2222', + 'this is deprecated %s %d', + 'foo', + 2222 + ); + + $this->assertEquals(1, Deprecation::getUniqueTriggeredDeprecationsCount()); + + $this->expectErrorHandler( + 'this is deprecated foo 2222 (DeprecationTest.php:%d called by TestCase.php:%d, https://github.com/doctrine/deprecations/2222, package doctrine/orm)', + 'https://github.com/doctrine/deprecations/2222', + 2 + ); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/2222', + 'this is deprecated %s %d', + 'foo', + 2222 + ); + + $this->assertEquals(2, Deprecation::getUniqueTriggeredDeprecationsCount()); + } + + public function testDeprecationResetsCounts(): void + { + try { + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/1234', + 'this is deprecated %s %d', + 'foo', + 1234 + ); + } catch (Throwable $e) { + Deprecation::disable(); + + $this->assertEquals(0, Deprecation::getUniqueTriggeredDeprecationsCount()); + $this->assertEquals(['https://github.com/doctrine/deprecations/1234' => 0], Deprecation::getTriggeredDeprecations()); + } + } + + public function expectDeprecationMock(string $message, string $identifier, string $package): MockObject + { + $mock = $this->createMock(LoggerInterface::class); + $mock->method('notice')->with($message, $this->callback(function ($context) use ($identifier, $package) { + $this->assertEquals($package, $context['package']); + $this->assertEquals($identifier, $context['link']); + + return true; + })); + + return $mock; + } + + public function testDeprecationWithPsrLogger(): void + { + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/deprecations/2222'); + + $mock = $this->expectDeprecationMock( + 'this is deprecated foo 1234', + 'https://github.com/doctrine/deprecations/2222', + 'doctrine/orm' + ); + Deprecation::enableWithPsrLogger($mock); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/2222', + 'this is deprecated %s %d', + 'foo', + 1234 + ); + } + + public function testDeprecationWithIgnoredPackage(): void + { + Deprecation::enableWithTriggerError(); + Deprecation::ignorePackage('doctrine/orm'); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/orm/issue/1234', + 'this is deprecated %s %d', + 'foo', + 1234 + ); + + $this->assertEquals(1, Deprecation::getUniqueTriggeredDeprecationsCount()); + $this->assertEquals(['https://github.com/doctrine/orm/issue/1234' => 1], Deprecation::getTriggeredDeprecations()); + } + + public function testDeprecationIfCalledFromOutside(): void + { + Deprecation::enableWithTriggerError(); + + $this->expectErrorHandler( + 'Bar::oldFunc() is deprecated, use Bar::newFunc() instead. (Bar.php:16 called by Foo.php:14, https://github.com/doctrine/foo, package doctrine/foo)', + 'https://github.com/doctrine/foo' + ); + + Foo::triggerDependencyWithDeprecation(); + } + + public function testDeprecationIfCalledFromOutsideNotTriggeringFromInside(): void + { + Deprecation::enableWithTriggerError(); + + Foo::triggerDependencyWithDeprecationFromInside(); + + $this->assertEquals(0, Deprecation::getUniqueTriggeredDeprecationsCount()); + } + + public function testDeprecationIfCalledFromOutsideNotTriggeringFromInsideClass(): void + { + Deprecation::enableWithTriggerError(); + + $baz = new Baz(); + $baz->usingOldFunc(); + + $this->assertEquals(0, Deprecation::getUniqueTriggeredDeprecationsCount()); + } + + public function testDeprecationCalledFromOutsideInRoot(): void + { + Deprecation::enableWithTriggerError(); + + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/deprecations/4444'); + + $this->expectErrorHandler( + 'this is deprecated foo 1234 (RootDeprecation.php:%d called by DeprecationTest.php:%d, https://github.com/doctrine/deprecations/4444, package doctrine/orm)', + 'https://github.com/doctrine/deprecations/4444' + ); + + RootDeprecation::run(); + + $this->assertEquals(1, Deprecation::getUniqueTriggeredDeprecationsCount()); + } +} diff --git a/vendor/doctrine/deprecations/tests/Doctrine/Deprecations/VerifyDeprecationsTest.php b/vendor/doctrine/deprecations/tests/Doctrine/Deprecations/VerifyDeprecationsTest.php new file mode 100755 index 0000000..8681f7d --- /dev/null +++ b/vendor/doctrine/deprecations/tests/Doctrine/Deprecations/VerifyDeprecationsTest.php @@ -0,0 +1,35 @@ +expectDeprecationWithIdentifier('http://example.com'); + + Deprecation::trigger('doctrine/dbal', 'http://example.com', 'message'); + } + + public function testExpectNoDeprecationWithIdentifier(): void + { + $this->expectNoDeprecationWithIdentifier('http://example.com'); + + Deprecation::trigger('doctrine/dbal', 'http://otherexample.com', 'message'); + } +} diff --git a/vendor/doctrine/event-manager/.doctrine-project.json b/vendor/doctrine/event-manager/.doctrine-project.json new file mode 100755 index 0000000..f6feb43 --- /dev/null +++ b/vendor/doctrine/event-manager/.doctrine-project.json @@ -0,0 +1,18 @@ +{ + "active": true, + "name": "Event Manager", + "slug": "event-manager", + "docsSlug": "doctrine-event-manager", + "versions": [ + { + "name": "1.0", + "branchName": "master", + "slug": "latest", + "current": true, + "aliases": [ + "current", + "stable" + ] + } + ] +} diff --git a/vendor/doctrine/event-manager/LICENSE b/vendor/doctrine/event-manager/LICENSE new file mode 100755 index 0000000..8c38cc1 --- /dev/null +++ b/vendor/doctrine/event-manager/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2015 Doctrine Project + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/doctrine/event-manager/README.md b/vendor/doctrine/event-manager/README.md new file mode 100755 index 0000000..3aee6b6 --- /dev/null +++ b/vendor/doctrine/event-manager/README.md @@ -0,0 +1,13 @@ +# Doctrine Event Manager + +[![Build Status](https://travis-ci.org/doctrine/event-manager.svg)](https://travis-ci.org/doctrine/event-manager) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/doctrine/event-manager/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/doctrine/event-manager/?branch=master) +[![Code Coverage](https://scrutinizer-ci.com/g/doctrine/event-manager/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/doctrine/event-manager/?branch=master) + +The Doctrine Event Manager is a library that provides a simple event system. + +## More resources: + +* [Website](https://www.doctrine-project.org/) +* [Documentation](https://www.doctrine-project.org/projects/doctrine-event-manager/en/latest/) +* [Downloads](https://github.com/doctrine/event-manager/releases) diff --git a/vendor/doctrine/event-manager/composer.json b/vendor/doctrine/event-manager/composer.json new file mode 100755 index 0000000..3f026fe --- /dev/null +++ b/vendor/doctrine/event-manager/composer.json @@ -0,0 +1,50 @@ +{ + "name": "doctrine/event-manager", + "type": "library", + "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", + "keywords": [ + "events", + "event", + "event dispatcher", + "event manager", + "event system" + ], + "homepage": "https://www.doctrine-project.org/projects/event-manager.html", + "license": "MIT", + "authors": [ + {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, + {"name": "Roman Borschel", "email": "roman@code-factory.org"}, + {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, + {"name": "Jonathan Wage", "email": "jonwage@gmail.com"}, + {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}, + {"name": "Marco Pivetta", "email": "ocramius@gmail.com"} + ], + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpunit/phpunit": "^7.0" + }, + "conflict": { + "doctrine/common": "<2.9@dev" + }, + "config": { + "sort-packages": true + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "autoload-dev": { + "psr-4": { + "Doctrine\\Tests\\": "tests/Doctrine/Tests" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/vendor/doctrine/event-manager/lib/Doctrine/Common/EventArgs.php b/vendor/doctrine/event-manager/lib/Doctrine/Common/EventArgs.php new file mode 100755 index 0000000..9b9cc05 --- /dev/null +++ b/vendor/doctrine/event-manager/lib/Doctrine/Common/EventArgs.php @@ -0,0 +1,45 @@ + => + * + * @var object[][] + */ + private $_listeners = []; + + /** + * Dispatches an event to all registered listeners. + * + * @param string $eventName The name of the event to dispatch. The name of the event is + * the name of the method that is invoked on listeners. + * @param EventArgs|null $eventArgs The event arguments to pass to the event handlers/listeners. + * If not supplied, the single empty EventArgs instance is used. + * + * @return void + */ + public function dispatchEvent($eventName, ?EventArgs $eventArgs = null) + { + if (! isset($this->_listeners[$eventName])) { + return; + } + + $eventArgs = $eventArgs ?? EventArgs::getEmptyInstance(); + + foreach ($this->_listeners[$eventName] as $listener) { + $listener->$eventName($eventArgs); + } + } + + /** + * Gets the listeners of a specific event or all listeners. + * + * @param string|null $event The name of the event. + * + * @return object[]|object[][] The event listeners for the specified event, or all event listeners. + */ + public function getListeners($event = null) + { + return $event ? $this->_listeners[$event] : $this->_listeners; + } + + /** + * Checks whether an event has any registered listeners. + * + * @param string $event + * + * @return bool TRUE if the specified event has any listeners, FALSE otherwise. + */ + public function hasListeners($event) + { + return ! empty($this->_listeners[$event]); + } + + /** + * Adds an event listener that listens on the specified events. + * + * @param string|string[] $events The event(s) to listen on. + * @param object $listener The listener object. + * + * @return void + */ + public function addEventListener($events, $listener) + { + // Picks the hash code related to that listener + $hash = spl_object_hash($listener); + + foreach ((array) $events as $event) { + // Overrides listener if a previous one was associated already + // Prevents duplicate listeners on same event (same instance only) + $this->_listeners[$event][$hash] = $listener; + } + } + + /** + * Removes an event listener from the specified events. + * + * @param string|string[] $events + * @param object $listener + * + * @return void + */ + public function removeEventListener($events, $listener) + { + // Picks the hash code related to that listener + $hash = spl_object_hash($listener); + + foreach ((array) $events as $event) { + unset($this->_listeners[$event][$hash]); + } + } + + /** + * Adds an EventSubscriber. The subscriber is asked for all the events it is + * interested in and added as a listener for these events. + * + * @param EventSubscriber $subscriber The subscriber. + * + * @return void + */ + public function addEventSubscriber(EventSubscriber $subscriber) + { + $this->addEventListener($subscriber->getSubscribedEvents(), $subscriber); + } + + /** + * Removes an EventSubscriber. The subscriber is asked for all the events it is + * interested in and removed as a listener for these events. + * + * @param EventSubscriber $subscriber The subscriber. + * + * @return void + */ + public function removeEventSubscriber(EventSubscriber $subscriber) + { + $this->removeEventListener($subscriber->getSubscribedEvents(), $subscriber); + } +} diff --git a/vendor/doctrine/event-manager/lib/Doctrine/Common/EventSubscriber.php b/vendor/doctrine/event-manager/lib/Doctrine/Common/EventSubscriber.php new file mode 100755 index 0000000..7d5e2ea --- /dev/null +++ b/vendor/doctrine/event-manager/lib/Doctrine/Common/EventSubscriber.php @@ -0,0 +1,21 @@ +build(); + +By default it will create an English inflector. If you want to use another language, just pass the language +you want to create an inflector for to the ``createForLanguage()`` method: + +.. code-block:: php + + use Doctrine\Inflector\InflectorFactory; + use Doctrine\Inflector\Language; + + $inflector = InflectorFactory::createForLanguage(Language::SPANISH)->build(); + +The supported languages are as follows: + +- ``Language::ENGLISH`` +- ``Language::FRENCH`` +- ``Language::NORWEGIAN_BOKMAL`` +- ``Language::PORTUGUESE`` +- ``Language::SPANISH`` +- ``Language::TURKISH`` + +If you want to manually construct the inflector instead of using a factory, you can do so like this: + +.. code-block:: php + + use Doctrine\Inflector\CachedWordInflector; + use Doctrine\Inflector\RulesetInflector; + use Doctrine\Inflector\Rules\English; + + $inflector = new Inflector( + new CachedWordInflector(new RulesetInflector( + English\Rules::getSingularRuleset() + )), + new CachedWordInflector(new RulesetInflector( + English\Rules::getPluralRuleset() + )) + ); + +Adding Languages +---------------- + +If you are interested in adding support for your language, take a look at the other languages defined in the +``Doctrine\Inflector\Rules`` namespace and the tests located in ``Doctrine\Tests\Inflector\Rules``. You can copy +one of the languages and update the rules for your language. + +Once you have done this, send a pull request to the ``doctrine/inflector`` repository with the additions. + +Custom Setup +============ + +If you want to setup custom singular and plural rules, you can configure these in the factory: + +.. code-block:: php + + use Doctrine\Inflector\InflectorFactory; + use Doctrine\Inflector\Rules\Pattern; + use Doctrine\Inflector\Rules\Patterns; + use Doctrine\Inflector\Rules\Ruleset; + use Doctrine\Inflector\Rules\Substitution; + use Doctrine\Inflector\Rules\Substitutions; + use Doctrine\Inflector\Rules\Transformation; + use Doctrine\Inflector\Rules\Transformations; + use Doctrine\Inflector\Rules\Word; + + $inflector = InflectorFactory::create() + ->withSingularRules( + new Ruleset( + new Transformations( + new Transformation(new Pattern('/^(bil)er$/i'), '\1'), + new Transformation(new Pattern('/^(inflec|contribu)tors$/i'), '\1ta') + ), + new Patterns(new Pattern('singulars')), + new Substitutions(new Substitution(new Word('spins'), new Word('spinor'))) + ) + ) + ->withPluralRules( + new Ruleset( + new Transformations( + new Transformation(new Pattern('^(bil)er$'), '\1'), + new Transformation(new Pattern('^(inflec|contribu)tors$'), '\1ta') + ), + new Patterns(new Pattern('noflect'), new Pattern('abtuse')), + new Substitutions( + new Substitution(new Word('amaze'), new Word('amazable')), + new Substitution(new Word('phone'), new Word('phonezes')) + ) + ) + ) + ->build(); + +No operation inflector +---------------------- + +The ``Doctrine\Inflector\NoopWordInflector`` may be used to configure an inflector that doesn't perform any operation for +pluralization and/or singularization. If will simply return the input as output. + +This is an implementation of the `Null Object design pattern `_. + +.. code-block:: php + + use Doctrine\Inflector\Inflector; + use Doctrine\Inflector\NoopWordInflector; + + $inflector = new Inflector(new NoopWordInflector(), new NoopWordInflector()); + +Tableize +======== + +Converts ``ModelName`` to ``model_name``: + +.. code-block:: php + + echo $inflector->tableize('ModelName'); // model_name + +Classify +======== + +Converts ``model_name`` to ``ModelName``: + +.. code-block:: php + + echo $inflector->classify('model_name'); // ModelName + +Camelize +======== + +This method uses `Classify`_ and then converts the first character to lowercase: + +.. code-block:: php + + echo $inflector->camelize('model_name'); // modelName + +Capitalize +========== + +Takes a string and capitalizes all of the words, like PHP's built-in +``ucwords`` function. This extends that behavior, however, by allowing the +word delimiters to be configured, rather than only separating on +whitespace. + +Here is an example: + +.. code-block:: php + + $string = 'top-o-the-morning to all_of_you!'; + + echo $inflector->capitalize($string); // Top-O-The-Morning To All_of_you! + + echo $inflector->capitalize($string, '-_ '); // Top-O-The-Morning To All_Of_You! + +Pluralize +========= + +Returns a word in plural form. + +.. code-block:: php + + echo $inflector->pluralize('browser'); // browsers + +Singularize +=========== + +Returns a word in singular form. + +.. code-block:: php + + echo $inflector->singularize('browsers'); // browser + +Urlize +====== + +Generate a URL friendly string from a string of text: + +.. code-block:: php + + echo $inflector->urlize('My first blog post'); // my-first-blog-post + +Unaccent +======== + +You can unaccent a string of text using the ``unaccent()`` method: + +.. code-block:: php + + echo $inflector->unaccent('año'); // ano + +Legacy API +========== + +As of 1.4.0, the API present in Inflector 1.x has been marked as deprecated. In the 2.x release series, +the legacy API has been dropped completely. +Support for languages other than English is available in the 2.0 API only. + +Acknowledgements +================ + +The language rules in this library have been adapted from several different sources, including but not limited to: + +- `Ruby On Rails Inflector `_ +- `ICanBoogie Inflector `_ +- `CakePHP Inflector `_ diff --git a/vendor/doctrine/inflector/lib/Doctrine/Common/Inflector/Inflector.php b/vendor/doctrine/inflector/lib/Doctrine/Common/Inflector/Inflector.php new file mode 100755 index 0000000..763b116 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Common/Inflector/Inflector.php @@ -0,0 +1,284 @@ +. + */ + +namespace Doctrine\Common\Inflector; + +use Doctrine\Inflector\Inflector as InflectorObject; +use Doctrine\Inflector\InflectorFactory; +use Doctrine\Inflector\LanguageInflectorFactory; +use Doctrine\Inflector\Rules\Pattern; +use Doctrine\Inflector\Rules\Patterns; +use Doctrine\Inflector\Rules\Ruleset; +use Doctrine\Inflector\Rules\Substitution; +use Doctrine\Inflector\Rules\Substitutions; +use Doctrine\Inflector\Rules\Transformation; +use Doctrine\Inflector\Rules\Transformations; +use Doctrine\Inflector\Rules\Word; +use InvalidArgumentException; +use function array_keys; +use function array_map; +use function array_unshift; +use function array_values; +use function sprintf; +use function trigger_error; +use const E_USER_DEPRECATED; + +/** + * @deprecated + */ +class Inflector +{ + /** + * @var LanguageInflectorFactory|null + */ + private static $factory; + + /** @var InflectorObject|null */ + private static $instance; + + private static function getInstance() : InflectorObject + { + if (self::$factory === null) { + self::$factory = self::createFactory(); + } + + if (self::$instance === null) { + self::$instance = self::$factory->build(); + } + + return self::$instance; + } + + private static function createFactory() : LanguageInflectorFactory + { + return InflectorFactory::create(); + } + + /** + * Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'. + * + * @deprecated + */ + public static function tableize(string $word) : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + return self::getInstance()->tableize($word); + } + + /** + * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'. + */ + public static function classify(string $word) : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + return self::getInstance()->classify($word); + } + + /** + * Camelizes a word. This uses the classify() method and turns the first character to lowercase. + * + * @deprecated + */ + public static function camelize(string $word) : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + return self::getInstance()->camelize($word); + } + + /** + * Uppercases words with configurable delimiters between words. + * + * Takes a string and capitalizes all of the words, like PHP's built-in + * ucwords function. This extends that behavior, however, by allowing the + * word delimiters to be configured, rather than only separating on + * whitespace. + * + * Here is an example: + * + * + * + * + * @param string $string The string to operate on. + * @param string $delimiters A list of word separators. + * + * @return string The string with all delimiter-separated words capitalized. + * + * @deprecated + */ + public static function ucwords(string $string, string $delimiters = " \n\t\r\0\x0B-") : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please use the "ucwords" function instead.', __METHOD__), E_USER_DEPRECATED); + + return ucwords($string, $delimiters); + } + + /** + * Clears Inflectors inflected value caches, and resets the inflection + * rules to the initial values. + * + * @deprecated + */ + public static function reset() : void + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + self::$factory = null; + self::$instance = null; + } + + /** + * Adds custom inflection $rules, of either 'plural' or 'singular' $type. + * + * ### Usage: + * + * {{{ + * Inflector::rules('plural', array('/^(inflect)or$/i' => '\1ables')); + * Inflector::rules('plural', array( + * 'rules' => array('/^(inflect)ors$/i' => '\1ables'), + * 'uninflected' => array('dontinflectme'), + * 'irregular' => array('red' => 'redlings') + * )); + * }}} + * + * @param string $type The type of inflection, either 'plural' or 'singular' + * @param array|iterable $rules An array of rules to be added. + * @param boolean $reset If true, will unset default inflections for all + * new rules that are being defined in $rules. + * + * @return void + * + * @deprecated + */ + public static function rules(string $type, iterable $rules, bool $reset = false) : void + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + if (self::$factory === null) { + self::$factory = self::createFactory(); + } + + self::$instance = null; + + switch ($type) { + case 'singular': + self::$factory->withSingularRules(self::buildRuleset($rules), $reset); + break; + case 'plural': + self::$factory->withPluralRules(self::buildRuleset($rules), $reset); + break; + default: + throw new InvalidArgumentException(sprintf('Cannot define custom inflection rules for type "%s".', $type)); + } + } + + /** + * @param array|iterable $rules An array of rules to be added. + */ + private static function buildRuleset(iterable $rules) : Ruleset + { + $regular = []; + $irregular = []; + $uninflected = []; + + foreach ($rules as $rule => $pattern) { + if ( ! is_array($pattern)) { + $regular[$rule] = $pattern; + + continue; + } + + switch ($rule) { + case 'uninflected': + $uninflected = $pattern; + break; + case 'irregular': + $irregular = $pattern; + break; + case 'rules': + $regular = $pattern; + break; + } + } + + return new Ruleset( + new Transformations(...array_map( + static function (string $pattern, string $replacement) : Transformation { + return new Transformation(new Pattern($pattern), $replacement); + }, + array_keys($regular), + array_values($regular) + )), + new Patterns(...array_map( + static function (string $pattern) : Pattern { + return new Pattern($pattern); + }, + $uninflected + )), + new Substitutions(...array_map( + static function (string $word, string $to) : Substitution { + return new Substitution(new Word($word), new Word($to)); + }, + array_keys($irregular), + array_values($irregular) + )) + ); + } + + /** + * Returns a word in plural form. + * + * @param string $word The word in singular form. + * + * @return string The word in plural form. + * + * @deprecated + */ + public static function pluralize(string $word) : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + return self::getInstance()->pluralize($word); + } + + /** + * Returns a word in singular form. + * + * @param string $word The word in plural form. + * + * @return string The word in singular form. + * + * @deprecated + */ + public static function singularize(string $word) : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + return self::getInstance()->singularize($word); + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/CachedWordInflector.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/CachedWordInflector.php new file mode 100755 index 0000000..2d52908 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/CachedWordInflector.php @@ -0,0 +1,24 @@ +wordInflector = $wordInflector; + } + + public function inflect(string $word): string + { + return $this->cache[$word] ?? $this->cache[$word] = $this->wordInflector->inflect($word); + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/GenericLanguageInflectorFactory.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/GenericLanguageInflectorFactory.php new file mode 100755 index 0000000..166061d --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/GenericLanguageInflectorFactory.php @@ -0,0 +1,66 @@ +singularRulesets[] = $this->getSingularRuleset(); + $this->pluralRulesets[] = $this->getPluralRuleset(); + } + + final public function build(): Inflector + { + return new Inflector( + new CachedWordInflector(new RulesetInflector( + ...$this->singularRulesets + )), + new CachedWordInflector(new RulesetInflector( + ...$this->pluralRulesets + )) + ); + } + + final public function withSingularRules(?Ruleset $singularRules, bool $reset = false): LanguageInflectorFactory + { + if ($reset) { + $this->singularRulesets = []; + } + + if ($singularRules instanceof Ruleset) { + array_unshift($this->singularRulesets, $singularRules); + } + + return $this; + } + + final public function withPluralRules(?Ruleset $pluralRules, bool $reset = false): LanguageInflectorFactory + { + if ($reset) { + $this->pluralRulesets = []; + } + + if ($pluralRules instanceof Ruleset) { + array_unshift($this->pluralRulesets, $pluralRules); + } + + return $this; + } + + abstract protected function getSingularRuleset(): Ruleset; + + abstract protected function getPluralRuleset(): Ruleset; +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Inflector.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Inflector.php new file mode 100755 index 0000000..610a4cf --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Inflector.php @@ -0,0 +1,507 @@ + 'A', + 'Á' => 'A', + 'Â' => 'A', + 'Ã' => 'A', + 'Ä' => 'Ae', + 'Æ' => 'Ae', + 'Å' => 'Aa', + 'æ' => 'a', + 'Ç' => 'C', + 'È' => 'E', + 'É' => 'E', + 'Ê' => 'E', + 'Ë' => 'E', + 'Ì' => 'I', + 'Í' => 'I', + 'Î' => 'I', + 'Ï' => 'I', + 'Ñ' => 'N', + 'Ò' => 'O', + 'Ó' => 'O', + 'Ô' => 'O', + 'Õ' => 'O', + 'Ö' => 'Oe', + 'Ù' => 'U', + 'Ú' => 'U', + 'Û' => 'U', + 'Ü' => 'Ue', + 'Ý' => 'Y', + 'ß' => 'ss', + 'à' => 'a', + 'á' => 'a', + 'â' => 'a', + 'ã' => 'a', + 'ä' => 'ae', + 'å' => 'aa', + 'ç' => 'c', + 'è' => 'e', + 'é' => 'e', + 'ê' => 'e', + 'ë' => 'e', + 'ì' => 'i', + 'í' => 'i', + 'î' => 'i', + 'ï' => 'i', + 'ñ' => 'n', + 'ò' => 'o', + 'ó' => 'o', + 'ô' => 'o', + 'õ' => 'o', + 'ö' => 'oe', + 'ù' => 'u', + 'ú' => 'u', + 'û' => 'u', + 'ü' => 'ue', + 'ý' => 'y', + 'ÿ' => 'y', + 'Ā' => 'A', + 'ā' => 'a', + 'Ă' => 'A', + 'ă' => 'a', + 'Ą' => 'A', + 'ą' => 'a', + 'Ć' => 'C', + 'ć' => 'c', + 'Ĉ' => 'C', + 'ĉ' => 'c', + 'Ċ' => 'C', + 'ċ' => 'c', + 'Č' => 'C', + 'č' => 'c', + 'Ď' => 'D', + 'ď' => 'd', + 'Đ' => 'D', + 'đ' => 'd', + 'Ē' => 'E', + 'ē' => 'e', + 'Ĕ' => 'E', + 'ĕ' => 'e', + 'Ė' => 'E', + 'ė' => 'e', + 'Ę' => 'E', + 'ę' => 'e', + 'Ě' => 'E', + 'ě' => 'e', + 'Ĝ' => 'G', + 'ĝ' => 'g', + 'Ğ' => 'G', + 'ğ' => 'g', + 'Ġ' => 'G', + 'ġ' => 'g', + 'Ģ' => 'G', + 'ģ' => 'g', + 'Ĥ' => 'H', + 'ĥ' => 'h', + 'Ħ' => 'H', + 'ħ' => 'h', + 'Ĩ' => 'I', + 'ĩ' => 'i', + 'Ī' => 'I', + 'ī' => 'i', + 'Ĭ' => 'I', + 'ĭ' => 'i', + 'Į' => 'I', + 'į' => 'i', + 'İ' => 'I', + 'ı' => 'i', + 'IJ' => 'IJ', + 'ij' => 'ij', + 'Ĵ' => 'J', + 'ĵ' => 'j', + 'Ķ' => 'K', + 'ķ' => 'k', + 'ĸ' => 'k', + 'Ĺ' => 'L', + 'ĺ' => 'l', + 'Ļ' => 'L', + 'ļ' => 'l', + 'Ľ' => 'L', + 'ľ' => 'l', + 'Ŀ' => 'L', + 'ŀ' => 'l', + 'Ł' => 'L', + 'ł' => 'l', + 'Ń' => 'N', + 'ń' => 'n', + 'Ņ' => 'N', + 'ņ' => 'n', + 'Ň' => 'N', + 'ň' => 'n', + 'ʼn' => 'N', + 'Ŋ' => 'n', + 'ŋ' => 'N', + 'Ō' => 'O', + 'ō' => 'o', + 'Ŏ' => 'O', + 'ŏ' => 'o', + 'Ő' => 'O', + 'ő' => 'o', + 'Œ' => 'OE', + 'œ' => 'oe', + 'Ø' => 'O', + 'ø' => 'o', + 'Ŕ' => 'R', + 'ŕ' => 'r', + 'Ŗ' => 'R', + 'ŗ' => 'r', + 'Ř' => 'R', + 'ř' => 'r', + 'Ś' => 'S', + 'ś' => 's', + 'Ŝ' => 'S', + 'ŝ' => 's', + 'Ş' => 'S', + 'ş' => 's', + 'Š' => 'S', + 'š' => 's', + 'Ţ' => 'T', + 'ţ' => 't', + 'Ť' => 'T', + 'ť' => 't', + 'Ŧ' => 'T', + 'ŧ' => 't', + 'Ũ' => 'U', + 'ũ' => 'u', + 'Ū' => 'U', + 'ū' => 'u', + 'Ŭ' => 'U', + 'ŭ' => 'u', + 'Ů' => 'U', + 'ů' => 'u', + 'Ű' => 'U', + 'ű' => 'u', + 'Ų' => 'U', + 'ų' => 'u', + 'Ŵ' => 'W', + 'ŵ' => 'w', + 'Ŷ' => 'Y', + 'ŷ' => 'y', + 'Ÿ' => 'Y', + 'Ź' => 'Z', + 'ź' => 'z', + 'Ż' => 'Z', + 'ż' => 'z', + 'Ž' => 'Z', + 'ž' => 'z', + 'ſ' => 's', + '€' => 'E', + '£' => '', + ]; + + /** @var WordInflector */ + private $singularizer; + + /** @var WordInflector */ + private $pluralizer; + + public function __construct(WordInflector $singularizer, WordInflector $pluralizer) + { + $this->singularizer = $singularizer; + $this->pluralizer = $pluralizer; + } + + /** + * Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'. + */ + public function tableize(string $word): string + { + $tableized = preg_replace('~(?<=\\w)([A-Z])~u', '_$1', $word); + + if ($tableized === null) { + throw new RuntimeException(sprintf( + 'preg_replace returned null for value "%s"', + $word + )); + } + + return mb_strtolower($tableized); + } + + /** + * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'. + */ + public function classify(string $word): string + { + return str_replace([' ', '_', '-'], '', ucwords($word, ' _-')); + } + + /** + * Camelizes a word. This uses the classify() method and turns the first character to lowercase. + */ + public function camelize(string $word): string + { + return lcfirst($this->classify($word)); + } + + /** + * Uppercases words with configurable delimiters between words. + * + * Takes a string and capitalizes all of the words, like PHP's built-in + * ucwords function. This extends that behavior, however, by allowing the + * word delimiters to be configured, rather than only separating on + * whitespace. + * + * Here is an example: + * + * capitalize($string); + * // Top-O-The-Morning To All_of_you! + * + * echo $inflector->capitalize($string, '-_ '); + * // Top-O-The-Morning To All_Of_You! + * ?> + * + * + * @param string $string The string to operate on. + * @param string $delimiters A list of word separators. + * + * @return string The string with all delimiter-separated words capitalized. + */ + public function capitalize(string $string, string $delimiters = " \n\t\r\0\x0B-"): string + { + return ucwords($string, $delimiters); + } + + /** + * Checks if the given string seems like it has utf8 characters in it. + * + * @param string $string The string to check for utf8 characters in. + */ + public function seemsUtf8(string $string): bool + { + for ($i = 0; $i < strlen($string); $i++) { + if (ord($string[$i]) < 0x80) { + continue; // 0bbbbbbb + } + + if ((ord($string[$i]) & 0xE0) === 0xC0) { + $n = 1; // 110bbbbb + } elseif ((ord($string[$i]) & 0xF0) === 0xE0) { + $n = 2; // 1110bbbb + } elseif ((ord($string[$i]) & 0xF8) === 0xF0) { + $n = 3; // 11110bbb + } elseif ((ord($string[$i]) & 0xFC) === 0xF8) { + $n = 4; // 111110bb + } elseif ((ord($string[$i]) & 0xFE) === 0xFC) { + $n = 5; // 1111110b + } else { + return false; // Does not match any model + } + + for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ? + if (++$i === strlen($string) || ((ord($string[$i]) & 0xC0) !== 0x80)) { + return false; + } + } + } + + return true; + } + + /** + * Remove any illegal characters, accents, etc. + * + * @param string $string String to unaccent + * + * @return string Unaccented string + */ + public function unaccent(string $string): string + { + if (preg_match('/[\x80-\xff]/', $string) === false) { + return $string; + } + + if ($this->seemsUtf8($string)) { + $string = strtr($string, self::ACCENTED_CHARACTERS); + } else { + $characters = []; + + // Assume ISO-8859-1 if not UTF-8 + $characters['in'] = + chr(128) + . chr(131) + . chr(138) + . chr(142) + . chr(154) + . chr(158) + . chr(159) + . chr(162) + . chr(165) + . chr(181) + . chr(192) + . chr(193) + . chr(194) + . chr(195) + . chr(196) + . chr(197) + . chr(199) + . chr(200) + . chr(201) + . chr(202) + . chr(203) + . chr(204) + . chr(205) + . chr(206) + . chr(207) + . chr(209) + . chr(210) + . chr(211) + . chr(212) + . chr(213) + . chr(214) + . chr(216) + . chr(217) + . chr(218) + . chr(219) + . chr(220) + . chr(221) + . chr(224) + . chr(225) + . chr(226) + . chr(227) + . chr(228) + . chr(229) + . chr(231) + . chr(232) + . chr(233) + . chr(234) + . chr(235) + . chr(236) + . chr(237) + . chr(238) + . chr(239) + . chr(241) + . chr(242) + . chr(243) + . chr(244) + . chr(245) + . chr(246) + . chr(248) + . chr(249) + . chr(250) + . chr(251) + . chr(252) + . chr(253) + . chr(255); + + $characters['out'] = 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy'; + + $string = strtr($string, $characters['in'], $characters['out']); + + $doubleChars = []; + + $doubleChars['in'] = [ + chr(140), + chr(156), + chr(198), + chr(208), + chr(222), + chr(223), + chr(230), + chr(240), + chr(254), + ]; + + $doubleChars['out'] = ['OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th']; + + $string = str_replace($doubleChars['in'], $doubleChars['out'], $string); + } + + return $string; + } + + /** + * Convert any passed string to a url friendly string. + * Converts 'My first blog post' to 'my-first-blog-post' + * + * @param string $string String to urlize. + * + * @return string Urlized string. + */ + public function urlize(string $string): string + { + // Remove all non url friendly characters with the unaccent function + $unaccented = $this->unaccent($string); + + if (function_exists('mb_strtolower')) { + $lowered = mb_strtolower($unaccented); + } else { + $lowered = strtolower($unaccented); + } + + $replacements = [ + '/\W/' => ' ', + '/([A-Z]+)([A-Z][a-z])/' => '\1_\2', + '/([a-z\d])([A-Z])/' => '\1_\2', + '/[^A-Z^a-z^0-9^\/]+/' => '-', + ]; + + $urlized = $lowered; + + foreach ($replacements as $pattern => $replacement) { + $replaced = preg_replace($pattern, $replacement, $urlized); + + if ($replaced === null) { + throw new RuntimeException(sprintf( + 'preg_replace returned null for value "%s"', + $urlized + )); + } + + $urlized = $replaced; + } + + return trim($urlized, '-'); + } + + /** + * Returns a word in singular form. + * + * @param string $word The word in plural form. + * + * @return string The word in singular form. + */ + public function singularize(string $word): string + { + return $this->singularizer->inflect($word); + } + + /** + * Returns a word in plural form. + * + * @param string $word The word in singular form. + * + * @return string The word in plural form. + */ + public function pluralize(string $word): string + { + return $this->pluralizer->inflect($word); + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/InflectorFactory.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/InflectorFactory.php new file mode 100755 index 0000000..a0740a7 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/InflectorFactory.php @@ -0,0 +1,52 @@ +getFlippedSubstitutions() + ); + } + + public static function getPluralRuleset(): Ruleset + { + return new Ruleset( + new Transformations(...Inflectible::getPlural()), + new Patterns(...Uninflected::getPlural()), + new Substitutions(...Inflectible::getIrregular()) + ); + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php new file mode 100755 index 0000000..e2656cc --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php @@ -0,0 +1,193 @@ +getFlippedSubstitutions() + ); + } + + public static function getPluralRuleset(): Ruleset + { + return new Ruleset( + new Transformations(...Inflectible::getPlural()), + new Patterns(...Uninflected::getPlural()), + new Substitutions(...Inflectible::getIrregular()) + ); + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php new file mode 100755 index 0000000..3cf2444 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php @@ -0,0 +1,34 @@ +getFlippedSubstitutions() + ); + } + + public static function getPluralRuleset(): Ruleset + { + return new Ruleset( + new Transformations(...Inflectible::getPlural()), + new Patterns(...Uninflected::getPlural()), + new Substitutions(...Inflectible::getIrregular()) + ); + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php new file mode 100755 index 0000000..5d878c6 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php @@ -0,0 +1,36 @@ +pattern = $pattern; + + if (isset($this->pattern[0]) && $this->pattern[0] === '/') { + $this->regex = $this->pattern; + } else { + $this->regex = '/' . $this->pattern . '/i'; + } + } + + public function getPattern(): string + { + return $this->pattern; + } + + public function getRegex(): string + { + return $this->regex; + } + + public function matches(string $word): bool + { + return preg_match($this->getRegex(), $word) === 1; + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Patterns.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Patterns.php new file mode 100755 index 0000000..e8d45cb --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Patterns.php @@ -0,0 +1,34 @@ +patterns = $patterns; + + $patterns = array_map(static function (Pattern $pattern): string { + return $pattern->getPattern(); + }, $this->patterns); + + $this->regex = '/^(?:' . implode('|', $patterns) . ')$/i'; + } + + public function matches(string $word): bool + { + return preg_match($this->regex, $word, $regs) === 1; + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Inflectible.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Inflectible.php new file mode 100755 index 0000000..95564d4 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Inflectible.php @@ -0,0 +1,104 @@ +getFlippedSubstitutions() + ); + } + + public static function getPluralRuleset(): Ruleset + { + return new Ruleset( + new Transformations(...Inflectible::getPlural()), + new Patterns(...Uninflected::getPlural()), + new Substitutions(...Inflectible::getIrregular()) + ); + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Uninflected.php new file mode 100755 index 0000000..58c34f9 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Uninflected.php @@ -0,0 +1,38 @@ +regular = $regular; + $this->uninflected = $uninflected; + $this->irregular = $irregular; + } + + public function getRegular(): Transformations + { + return $this->regular; + } + + public function getUninflected(): Patterns + { + return $this->uninflected; + } + + public function getIrregular(): Substitutions + { + return $this->irregular; + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Inflectible.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Inflectible.php new file mode 100755 index 0000000..c6862fa --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Inflectible.php @@ -0,0 +1,53 @@ +getFlippedSubstitutions() + ); + } + + public static function getPluralRuleset(): Ruleset + { + return new Ruleset( + new Transformations(...Inflectible::getPlural()), + new Patterns(...Uninflected::getPlural()), + new Substitutions(...Inflectible::getIrregular()) + ); + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Uninflected.php new file mode 100755 index 0000000..c743b39 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Uninflected.php @@ -0,0 +1,36 @@ +from = $from; + $this->to = $to; + } + + public function getFrom(): Word + { + return $this->from; + } + + public function getTo(): Word + { + return $this->to; + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitutions.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitutions.php new file mode 100755 index 0000000..17ee296 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitutions.php @@ -0,0 +1,57 @@ +substitutions[$substitution->getFrom()->getWord()] = $substitution; + } + } + + public function getFlippedSubstitutions(): Substitutions + { + $substitutions = []; + + foreach ($this->substitutions as $substitution) { + $substitutions[] = new Substitution( + $substitution->getTo(), + $substitution->getFrom() + ); + } + + return new Substitutions(...$substitutions); + } + + public function inflect(string $word): string + { + $lowerWord = strtolower($word); + + if (isset($this->substitutions[$lowerWord])) { + $firstLetterUppercase = $lowerWord[0] !== $word[0]; + + $toWord = $this->substitutions[$lowerWord]->getTo()->getWord(); + + if ($firstLetterUppercase) { + return strtoupper($toWord[0]) . substr($toWord, 1); + } + + return $toWord; + } + + return $word; + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformation.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformation.php new file mode 100755 index 0000000..30dcd59 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformation.php @@ -0,0 +1,39 @@ +pattern = $pattern; + $this->replacement = $replacement; + } + + public function getPattern(): Pattern + { + return $this->pattern; + } + + public function getReplacement(): string + { + return $this->replacement; + } + + public function inflect(string $word): string + { + return (string) preg_replace($this->pattern->getRegex(), $this->replacement, $word); + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformations.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformations.php new file mode 100755 index 0000000..b6a48fa --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformations.php @@ -0,0 +1,29 @@ +transformations = $transformations; + } + + public function inflect(string $word): string + { + foreach ($this->transformations as $transformation) { + if ($transformation->getPattern()->matches($word)) { + return $transformation->inflect($word); + } + } + + return $word; + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Inflectible.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Inflectible.php new file mode 100755 index 0000000..d7b7064 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Inflectible.php @@ -0,0 +1,40 @@ +getFlippedSubstitutions() + ); + } + + public static function getPluralRuleset(): Ruleset + { + return new Ruleset( + new Transformations(...Inflectible::getPlural()), + new Patterns(...Uninflected::getPlural()), + new Substitutions(...Inflectible::getIrregular()) + ); + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Uninflected.php new file mode 100755 index 0000000..a75d248 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Uninflected.php @@ -0,0 +1,36 @@ +word = $word; + } + + public function getWord(): string + { + return $this->word; + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php new file mode 100755 index 0000000..12b2ed5 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php @@ -0,0 +1,56 @@ +rulesets = array_merge([$ruleset], $rulesets); + } + + public function inflect(string $word): string + { + if ($word === '') { + return ''; + } + + foreach ($this->rulesets as $ruleset) { + if ($ruleset->getUninflected()->matches($word)) { + return $word; + } + + $inflected = $ruleset->getIrregular()->inflect($word); + + if ($inflected !== $word) { + return $inflected; + } + + $inflected = $ruleset->getRegular()->inflect($word); + + if ($inflected !== $word) { + return $inflected; + } + } + + return $word; + } +} diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php new file mode 100755 index 0000000..b88b1d6 --- /dev/null +++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php @@ -0,0 +1,10 @@ +input = $input; + $this->tokens = []; + + $this->reset(); + $this->scan($input); + } + + /** + * Resets the lexer. + * + * @return void + */ + public function reset() + { + $this->lookahead = null; + $this->token = null; + $this->peek = 0; + $this->position = 0; + } + + /** + * Resets the peek pointer to 0. + * + * @return void + */ + public function resetPeek() + { + $this->peek = 0; + } + + /** + * Resets the lexer position on the input to the given position. + * + * @param int $position Position to place the lexical scanner. + * + * @return void + */ + public function resetPosition($position = 0) + { + $this->position = $position; + } + + /** + * Retrieve the original lexer's input until a given position. + * + * @param int $position + * + * @return string + */ + public function getInputUntilPosition($position) + { + return substr($this->input, 0, $position); + } + + /** + * Checks whether a given token matches the current lookahead. + * + * @param int|string $token + * + * @return bool + */ + public function isNextToken($token) + { + return $this->lookahead !== null && $this->lookahead['type'] === $token; + } + + /** + * Checks whether any of the given tokens matches the current lookahead. + * + * @param array $tokens + * + * @return bool + */ + public function isNextTokenAny(array $tokens) + { + return $this->lookahead !== null && in_array($this->lookahead['type'], $tokens, true); + } + + /** + * Moves to the next token in the input string. + * + * @return bool + */ + public function moveNext() + { + $this->peek = 0; + $this->token = $this->lookahead; + $this->lookahead = isset($this->tokens[$this->position]) + ? $this->tokens[$this->position++] : null; + + return $this->lookahead !== null; + } + + /** + * Tells the lexer to skip input tokens until it sees a token with the given value. + * + * @param string $type The token type to skip until. + * + * @return void + */ + public function skipUntil($type) + { + while ($this->lookahead !== null && $this->lookahead['type'] !== $type) { + $this->moveNext(); + } + } + + /** + * Checks if given value is identical to the given token. + * + * @param mixed $value + * @param int|string $token + * + * @return bool + */ + public function isA($value, $token) + { + return $this->getType($value) === $token; + } + + /** + * Moves the lookahead token forward. + * + * @return array|null The next token or NULL if there are no more tokens ahead. + */ + public function peek() + { + if (isset($this->tokens[$this->position + $this->peek])) { + return $this->tokens[$this->position + $this->peek++]; + } + + return null; + } + + /** + * Peeks at the next token, returns it and immediately resets the peek. + * + * @return array|null The next token or NULL if there are no more tokens ahead. + */ + public function glimpse() + { + $peek = $this->peek(); + $this->peek = 0; + + return $peek; + } + + /** + * Scans the input string for tokens. + * + * @param string $input A query string. + * + * @return void + */ + protected function scan($input) + { + if (! isset($this->regex)) { + $this->regex = sprintf( + '/(%s)|%s/%s', + implode(')|(', $this->getCatchablePatterns()), + implode('|', $this->getNonCatchablePatterns()), + $this->getModifiers() + ); + } + + $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE; + $matches = preg_split($this->regex, $input, -1, $flags); + + if ($matches === false) { + // Work around https://bugs.php.net/78122 + $matches = [[$input, 0]]; + } + + foreach ($matches as $match) { + // Must remain before 'value' assignment since it can change content + $type = $this->getType($match[0]); + + $this->tokens[] = [ + 'value' => $match[0], + 'type' => $type, + 'position' => $match[1], + ]; + } + } + + /** + * Gets the literal for a given token. + * + * @param int|string $token + * + * @return int|string + */ + public function getLiteral($token) + { + $className = static::class; + $reflClass = new ReflectionClass($className); + $constants = $reflClass->getConstants(); + + foreach ($constants as $name => $value) { + if ($value === $token) { + return $className . '::' . $name; + } + } + + return $token; + } + + /** + * Regex modifiers + * + * @return string + */ + protected function getModifiers() + { + return 'iu'; + } + + /** + * Lexical catchable patterns. + * + * @return array + */ + abstract protected function getCatchablePatterns(); + + /** + * Lexical non-catchable patterns. + * + * @return array + */ + abstract protected function getNonCatchablePatterns(); + + /** + * Retrieve token type. Also processes the token value if necessary. + * + * @param string $value + * + * @return int|string|null + */ + abstract protected function getType(&$value); +} diff --git a/vendor/dragonmantank/cron-expression/CHANGELOG.md b/vendor/dragonmantank/cron-expression/CHANGELOG.md new file mode 100755 index 0000000..fab2375 --- /dev/null +++ b/vendor/dragonmantank/cron-expression/CHANGELOG.md @@ -0,0 +1,134 @@ +# Change Log + +## [3.1.0] - 2020-11-24 + +### Added +- Added `CronExpression::getParts()` method to get parts of the expression as an array (#83) + +### Changed +- Changed to Interfaces for some type hints (#97, #86) +- Dropped minimum PHP version to 7.2 +- Few syntax changes for phpstan compatibility (#93) + +### Fixed +- N/A + +### Deprecated +- Deprecated `CronExpression::factory` in favor of the constructor (#56) +- Deprecated `CronExpression::YEAR` as a formality, the functionality is already removed (#87) + +## [3.0.1] - 2020-10-12 +### Added +- Added support for PHP 8 (#92) +### Changed +- N/A +### Fixed +- N/A + +## [3.0.0] - 2020-03-25 + +**MAJOR CHANGE** - In previous versions of this library, setting both a "Day of Month" and a "Day of Week" would be interpreted as an `AND` statement, not an `OR` statement. For example: + +`30 0 1 * 1` + +would evaluate to "Run 30 minutes after the 0 hour when the Day Of Month is 1 AND a Monday" instead of "Run 30 minutes after the 0 hour on Day Of Month 1 OR a Monday", where the latter is more inline with most cron systems. This means that if your cron expression has both of these fields set, you may see your expression fire more often starting with v3.0.0. + +### Added +- Additional docblocks for IDE and documentation +- Added phpstan as a development dependency +- Added a `Cron\FieldFactoryInterface` to make migrations easier (#38) +### Changed +- Changed some DI testing during TravisCI runs +- `\Cron\CronExpression::determineTimezone()` now checks for `\DateTimeInterface` instead of just `\DateTime` +- Errors with fields now report a more human-understandable error and are 1-based instead of 0-based +- Better support for `\DateTimeImmutable` across the library by typehinting for `\DateTimeInterface` now +- Literals should now be less case-sensative across the board +- Changed logic for when both a Day of Week and a Day of Month are supplied to now be an OR statement, not an AND +### Fixed +- Fixed infinite loop when determining last day of week from literals +- Fixed bug where single number ranges were allowed (ex: `1/10`) +- Fixed nullable FieldFactory in CronExpression where no factory could be supplied +- Fixed issue where logic for dropping seconds to 0 could lead to a timezone change + +## [2.3.1] - 2020-10-12 +### Added +- Added support for PHP 8 (#92) +### Changed +- N/A +### Fixed +- N/A + +## [2.3.0] - 2019-03-30 +### Added +- Added support for DateTimeImmutable via DateTimeInterface +- Added support for PHP 7.3 +- Started listing projects that use the library +### Changed +- Errors should now report a human readable position in the cron expression, instead of starting at 0 +### Fixed +- N/A + +## [2.2.0] - 2018-06-05 +### Added +- Added support for steps larger than field ranges (#6) +## Changed +- N/A +### Fixed +- Fixed validation for numbers with leading 0s (#12) + +## [2.1.0] - 2018-04-06 +### Added +- N/A +### Changed +- Upgraded to PHPUnit 6 (#2) +### Fixed +- Refactored timezones to deal with some inconsistent behavior (#3) +- Allow ranges and lists in same expression (#5) +- Fixed regression where literals were not converted to their numerical counterpart (#) + +## [2.0.0] - 2017-10-12 +### Added +- N/A + +### Changed +- Dropped support for PHP 5.x +- Dropped support for the YEAR field, as it was not part of the cron standard + +### Fixed +- Reworked validation for all the field types +- Stepping should now work for 1-indexed fields like Month (#153) + +## [1.2.0] - 2017-01-22 +### Added +- Added IDE, CodeSniffer, and StyleCI.IO support + +### Changed +- Switched to PSR-4 Autoloading + +### Fixed +- 0 step expressions are handled better +- Fixed `DayOfMonth` validation to be more strict +- Typos + +## [1.1.0] - 2016-01-26 +### Added +- Support for non-hourly offset timezones +- Checks for valid expressions + +### Changed +- Max Iterations no longer hardcoded for `getRunDate()` +- Supports DateTimeImmutable for newer PHP verions + +### Fixed +- Fixed looping bug for PHP 7 when determining the last specified weekday of a month + +## [1.0.3] - 2013-11-23 +### Added +- Now supports expressions with any number of extra spaces, tabs, or newlines + +### Changed +- Using static instead of self in `CronExpression::factory` + +### Fixed +- Fixes issue [#28](https://github.com/mtdowling/cron-expression/issues/28) where PHP increments of ranges were failing due to PHP casting hyphens to 0 +- Only set default timezone if the given $currentTime is not a DateTime instance ([#34](https://github.com/mtdowling/cron-expression/issues/34)) diff --git a/vendor/dragonmantank/cron-expression/LICENSE b/vendor/dragonmantank/cron-expression/LICENSE new file mode 100755 index 0000000..3e38bbc --- /dev/null +++ b/vendor/dragonmantank/cron-expression/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Michael Dowling , 2016 Chris Tankersley , and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/dragonmantank/cron-expression/README.md b/vendor/dragonmantank/cron-expression/README.md new file mode 100755 index 0000000..fbdbdea --- /dev/null +++ b/vendor/dragonmantank/cron-expression/README.md @@ -0,0 +1,87 @@ +PHP Cron Expression Parser +========================== + +[![Latest Stable Version](https://poser.pugx.org/dragonmantank/cron-expression/v/stable.png)](https://packagist.org/packages/dragonmantank/cron-expression) [![Total Downloads](https://poser.pugx.org/dragonmantank/cron-expression/downloads.png)](https://packagist.org/packages/dragonmantank/cron-expression) [![Build Status](https://secure.travis-ci.org/dragonmantank/cron-expression.png)](http://travis-ci.org/dragonmantank/cron-expression) [![StyleCI](https://github.styleci.io/repos/103715337/shield?branch=master)](https://github.styleci.io/repos/103715337) + +The PHP cron expression parser can parse a CRON expression, determine if it is +due to run, calculate the next run date of the expression, and calculate the previous +run date of the expression. You can calculate dates far into the future or past by +skipping **n** number of matching dates. + +The parser can handle increments of ranges (e.g. */12, 2-59/3), intervals (e.g. 0-9), +lists (e.g. 1,2,3), **W** to find the nearest weekday for a given day of the month, **L** to +find the last day of the month, **L** to find the last given weekday of a month, and hash +(#) to find the nth weekday of a given month. + +More information about this fork can be found in the blog post [here](http://ctankersley.com/2017/10/12/cron-expression-update/). tl;dr - v2.0.0 is a major breaking change, and @dragonmantank can better take care of the project in a separate fork. + +Installing +========== + +Add the dependency to your project: + +```bash +composer require dragonmantank/cron-expression +``` + +Usage +===== +```php +isDue(); +echo $cron->getNextRunDate()->format('Y-m-d H:i:s'); +echo $cron->getPreviousRunDate()->format('Y-m-d H:i:s'); + +// Works with complex expressions +$cron = new Cron\CronExpression('3-59/15 6-12 */15 1 2-5'); +echo $cron->getNextRunDate()->format('Y-m-d H:i:s'); + +// Calculate a run date two iterations into the future +$cron = new Cron\CronExpression('@daily'); +echo $cron->getNextRunDate(null, 2)->format('Y-m-d H:i:s'); + +// Calculate a run date relative to a specific time +$cron = new Cron\CronExpression('@monthly'); +echo $cron->getNextRunDate('2010-01-12 00:00:00')->format('Y-m-d H:i:s'); +``` + +CRON Expressions +================ + +A CRON expression is a string representing the schedule for a particular command to execute. The parts of a CRON schedule are as follows: + + * * * * * + - - - - - + | | | | | + | | | | | + | | | | +----- day of week (0 - 7) (Sunday=0 or 7) + | | | +---------- month (1 - 12) + | | +--------------- day of month (1 - 31) + | +-------------------- hour (0 - 23) + +------------------------- min (0 - 59) + +This library also supports a few macros: + +* `@yearly`, `@annually` - Run once a year, midnight, Jan. 1 - `0 0 1 1 *` +* `@monthly` - Run once a month, midnight, first of month - `0 0 1 * *` +* `@weekly` - Run once a week, midnight on Sun - `0 0 * * 0` +* `@daily` - Run once a day, midnight - `0 0 * * *` +* `@hourly` - Run once an hour, first minute - `0 * * * *` + +Requirements +============ + +- PHP 7.1+ +- PHPUnit is required to run the unit tests +- Composer is required to run the unit tests + +Projects that Use cron-expression +================================= +* Part of the [Laravel Framework](https://github.com/laravel/framework/) +* Available as a [Symfony Bundle - setono/cron-expression-bundle](https://github.com/Setono/CronExpressionBundle) +* Framework agnostic, PHP-based job scheduler - [Crunz](https://github.com/lavary/crunz) diff --git a/vendor/dragonmantank/cron-expression/composer.json b/vendor/dragonmantank/cron-expression/composer.json new file mode 100755 index 0000000..59439b0 --- /dev/null +++ b/vendor/dragonmantank/cron-expression/composer.json @@ -0,0 +1,41 @@ +{ + "name": "dragonmantank/cron-expression", + "type": "library", + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": ["cron", "schedule"], + "license": "MIT", + "authors": [ + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "require": { + "php": "^7.2|^8.0", + "webmozart/assert": "^1.7.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "phpstan/phpstan-webmozart-assert": "^0.12.7", + "phpstan/extension-installer": "^1.0" + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "autoload-dev": { + "psr-4": { + "Cron\\Tests\\": "tests/Cron/" + } + }, + "replace": { + "mtdowling/cron-expression": "^1.0" + }, + "scripts": { + "phpstan": "./vendor/bin/phpstan analyse -l max src", + "test": "phpunit" + } +} diff --git a/vendor/dragonmantank/cron-expression/phpstan.neon b/vendor/dragonmantank/cron-expression/phpstan.neon new file mode 100755 index 0000000..9d52fd9 --- /dev/null +++ b/vendor/dragonmantank/cron-expression/phpstan.neon @@ -0,0 +1,2 @@ +parameters: + checkMissingIterableValueType: false diff --git a/vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php b/vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php new file mode 100755 index 0000000..22d5d0c --- /dev/null +++ b/vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php @@ -0,0 +1,303 @@ +fullRange = range($this->rangeStart, $this->rangeEnd); + } + + /** + * Check to see if a field is satisfied by a value. + * + * @param int $dateValue Date value to check + * @param string $value Value to test + * + * @return bool + */ + public function isSatisfied(int $dateValue, string $value): bool + { + if ($this->isIncrementsOfRanges($value)) { + return $this->isInIncrementsOfRanges($dateValue, $value); + } + + if ($this->isRange($value)) { + return $this->isInRange($dateValue, $value); + } + + return '*' === $value || $dateValue === (int) $value; + } + + /** + * Check if a value is a range. + * + * @param string $value Value to test + * + * @return bool + */ + public function isRange(string $value): bool + { + return false !== strpos($value, '-'); + } + + /** + * Check if a value is an increments of ranges. + * + * @param string $value Value to test + * + * @return bool + */ + public function isIncrementsOfRanges(string $value): bool + { + return false !== strpos($value, '/'); + } + + /** + * Test if a value is within a range. + * + * @param int $dateValue Set date value + * @param string $value Value to test + * + * @return bool + */ + public function isInRange(int $dateValue, $value): bool + { + $parts = array_map( + function ($value) { + $value = trim($value); + + return $this->convertLiterals($value); + }, + explode('-', $value, 2) + ); + + return $dateValue >= $parts[0] && $dateValue <= $parts[1]; + } + + /** + * Test if a value is within an increments of ranges (offset[-to]/step size). + * + * @param int $dateValue Set date value + * @param string $value Value to test + * + * @return bool + */ + public function isInIncrementsOfRanges(int $dateValue, string $value): bool + { + $chunks = array_map('trim', explode('/', $value, 2)); + $range = $chunks[0]; + $step = $chunks[1] ?? 0; + + // No step or 0 steps aren't cool + /** @phpstan-ignore-next-line */ + if (null === $step || '0' === $step || 0 === $step) { + return false; + } + + // Expand the * to a full range + if ('*' === $range) { + $range = $this->rangeStart . '-' . $this->rangeEnd; + } + + // Generate the requested small range + $rangeChunks = explode('-', $range, 2); + $rangeStart = $rangeChunks[0]; + $rangeEnd = $rangeChunks[1] ?? $rangeStart; + + if ($rangeStart < $this->rangeStart || $rangeStart > $this->rangeEnd || $rangeStart > $rangeEnd) { + throw new \OutOfRangeException('Invalid range start requested'); + } + + if ($rangeEnd < $this->rangeStart || $rangeEnd > $this->rangeEnd || $rangeEnd < $rangeStart) { + throw new \OutOfRangeException('Invalid range end requested'); + } + + // Steps larger than the range need to wrap around and be handled slightly differently than smaller steps + if ($step >= $this->rangeEnd) { + $thisRange = [$this->fullRange[$step % \count($this->fullRange)]]; + } else { + $thisRange = range($rangeStart, $rangeEnd, (int) $step); + } + + return \in_array($dateValue, $thisRange, true); + } + + /** + * Returns a range of values for the given cron expression. + * + * @param string $expression The expression to evaluate + * @param int $max Maximum offset for range + * + * @return array + */ + public function getRangeForExpression(string $expression, int $max): array + { + $values = []; + $expression = $this->convertLiterals($expression); + + if (false !== strpos($expression, ',')) { + $ranges = explode(',', $expression); + $values = []; + foreach ($ranges as $range) { + $expanded = $this->getRangeForExpression($range, $this->rangeEnd); + $values = array_merge($values, $expanded); + } + + return $values; + } + + if ($this->isRange($expression) || $this->isIncrementsOfRanges($expression)) { + if (!$this->isIncrementsOfRanges($expression)) { + [$offset, $to] = explode('-', $expression); + $offset = $this->convertLiterals($offset); + $to = $this->convertLiterals($to); + $stepSize = 1; + } else { + $range = array_map('trim', explode('/', $expression, 2)); + $stepSize = $range[1] ?? 0; + $range = $range[0]; + $range = explode('-', $range, 2); + $offset = $range[0]; + $to = $range[1] ?? $max; + } + $offset = '*' === $offset ? $this->rangeStart : $offset; + if ($stepSize >= $this->rangeEnd) { + $values = [$this->fullRange[$stepSize % \count($this->fullRange)]]; + } else { + for ($i = $offset; $i <= $to; $i += $stepSize) { + $values[] = (int) $i; + } + } + sort($values); + } else { + $values = [$expression]; + } + + return $values; + } + + /** + * Convert literal. + * + * @param string $value + * + * @return string + */ + protected function convertLiterals(string $value): string + { + if (\count($this->literals)) { + $key = array_search(strtoupper($value), $this->literals, true); + if (false !== $key) { + return (string) $key; + } + } + + return $value; + } + + /** + * Checks to see if a value is valid for the field. + * + * @param string $value + * + * @return bool + */ + public function validate(string $value): bool + { + $value = $this->convertLiterals($value); + + // All fields allow * as a valid value + if ('*' === $value) { + return true; + } + + if (false !== strpos($value, '/')) { + [$range, $step] = explode('/', $value); + + // Don't allow numeric ranges + if (is_numeric($range)) { + return false; + } + + return $this->validate($range) && filter_var($step, FILTER_VALIDATE_INT); + } + + // Validate each chunk of a list individually + if (false !== strpos($value, ',')) { + foreach (explode(',', $value) as $listItem) { + if (!$this->validate($listItem)) { + return false; + } + } + + return true; + } + + if (false !== strpos($value, '-')) { + if (substr_count($value, '-') > 1) { + return false; + } + + $chunks = explode('-', $value); + $chunks[0] = $this->convertLiterals($chunks[0]); + $chunks[1] = $this->convertLiterals($chunks[1]); + + if ('*' === $chunks[0] || '*' === $chunks[1]) { + return false; + } + + return $this->validate($chunks[0]) && $this->validate($chunks[1]); + } + + if (!is_numeric($value)) { + return false; + } + + if (false !== strpos($value, '.')) { + return false; + } + + // We should have a numeric by now, so coerce this into an integer + $value = (int) $value; + + return \in_array($value, $this->fullRange, true); + } +} diff --git a/vendor/dragonmantank/cron-expression/src/Cron/CronExpression.php b/vendor/dragonmantank/cron-expression/src/Cron/CronExpression.php new file mode 100755 index 0000000..9b34276 --- /dev/null +++ b/vendor/dragonmantank/cron-expression/src/Cron/CronExpression.php @@ -0,0 +1,462 @@ + '0 0 1 1 *', + '@annually' => '0 0 1 1 *', + '@monthly' => '0 0 1 * *', + '@weekly' => '0 0 * * 0', + '@daily' => '0 0 * * *', + '@hourly' => '0 * * * *', + ]; + + /** + * @var array CRON expression parts + */ + private $cronParts; + + /** + * @var FieldFactoryInterface CRON field factory + */ + private $fieldFactory; + + /** + * @var int Max iteration count when searching for next run date + */ + private $maxIterationCount = 1000; + + /** + * @var array Order in which to test of cron parts + */ + private static $order = [ + self::YEAR, + self::MONTH, + self::DAY, + self::WEEKDAY, + self::HOUR, + self::MINUTE, + ]; + + /** + * @deprecated since version 3.0.2, use __construct instead. + */ + public static function factory(string $expression, FieldFactoryInterface $fieldFactory = null): CronExpression + { + /** @phpstan-ignore-next-line */ + return new static($expression, $fieldFactory); + } + + /** + * Validate a CronExpression. + * + * @param string $expression the CRON expression to validate + * + * @return bool True if a valid CRON expression was passed. False if not. + */ + public static function isValidExpression(string $expression): bool + { + try { + new CronExpression($expression); + } catch (InvalidArgumentException $e) { + return false; + } + + return true; + } + + /** + * Parse a CRON expression. + * + * @param string $expression CRON expression (e.g. '8 * * * *') + * @param null|FieldFactoryInterface $fieldFactory Factory to create cron fields + */ + public function __construct(string $expression, FieldFactoryInterface $fieldFactory = null) + { + $shortcut = strtolower($expression); + $expression = self::MAPPINGS[$shortcut] ?? $expression; + + $this->fieldFactory = $fieldFactory ?: new FieldFactory(); + $this->setExpression($expression); + } + + /** + * Set or change the CRON expression. + * + * @param string $value CRON expression (e.g. 8 * * * *) + * + * @throws \InvalidArgumentException if not a valid CRON expression + * + * @return CronExpression + */ + public function setExpression(string $value): CronExpression + { + $split = preg_split('/\s/', $value, -1, PREG_SPLIT_NO_EMPTY); + Assert::isArray($split); + + $this->cronParts = $split; + if (\count($this->cronParts) < 5) { + throw new InvalidArgumentException( + $value . ' is not a valid CRON expression' + ); + } + + foreach ($this->cronParts as $position => $part) { + $this->setPart($position, $part); + } + + return $this; + } + + /** + * Set part of the CRON expression. + * + * @param int $position The position of the CRON expression to set + * @param string $value The value to set + * + * @throws \InvalidArgumentException if the value is not valid for the part + * + * @return CronExpression + */ + public function setPart(int $position, string $value): CronExpression + { + if (!$this->fieldFactory->getField($position)->validate($value)) { + throw new InvalidArgumentException( + 'Invalid CRON field value ' . $value . ' at position ' . $position + ); + } + + $this->cronParts[$position] = $value; + + return $this; + } + + /** + * Set max iteration count for searching next run dates. + * + * @param int $maxIterationCount Max iteration count when searching for next run date + * + * @return CronExpression + */ + public function setMaxIterationCount(int $maxIterationCount): CronExpression + { + $this->maxIterationCount = $maxIterationCount; + + return $this; + } + + /** + * Get a next run date relative to the current date or a specific date + * + * @param string|\DateTimeInterface $currentTime Relative calculation date + * @param int $nth Number of matches to skip before returning a + * matching next run date. 0, the default, will return the + * current date and time if the next run date falls on the + * current date and time. Setting this value to 1 will + * skip the first match and go to the second match. + * Setting this value to 2 will skip the first 2 + * matches and so on. + * @param bool $allowCurrentDate Set to TRUE to return the current date if + * it matches the cron expression. + * @param null|string $timeZone TimeZone to use instead of the system default + * + * @throws \RuntimeException on too many iterations + * @throws \Exception + * + * @return \DateTime + */ + public function getNextRunDate($currentTime = 'now', int $nth = 0, bool $allowCurrentDate = false, $timeZone = null): DateTime + { + return $this->getRunDate($currentTime, $nth, false, $allowCurrentDate, $timeZone); + } + + /** + * Get a previous run date relative to the current date or a specific date. + * + * @param string|\DateTimeInterface $currentTime Relative calculation date + * @param int $nth Number of matches to skip before returning + * @param bool $allowCurrentDate Set to TRUE to return the + * current date if it matches the cron expression + * @param null|string $timeZone TimeZone to use instead of the system default + * + * @throws \RuntimeException on too many iterations + * @throws \Exception + * + * @return \DateTime + * + * @see \Cron\CronExpression::getNextRunDate + */ + public function getPreviousRunDate($currentTime = 'now', int $nth = 0, bool $allowCurrentDate = false, $timeZone = null): DateTime + { + return $this->getRunDate($currentTime, $nth, true, $allowCurrentDate, $timeZone); + } + + /** + * Get multiple run dates starting at the current date or a specific date. + * + * @param int $total Set the total number of dates to calculate + * @param string|\DateTimeInterface|null $currentTime Relative calculation date + * @param bool $invert Set to TRUE to retrieve previous dates + * @param bool $allowCurrentDate Set to TRUE to return the + * current date if it matches the cron expression + * @param null|string $timeZone TimeZone to use instead of the system default + * + * @return \DateTime[] Returns an array of run dates + */ + public function getMultipleRunDates(int $total, $currentTime = 'now', bool $invert = false, bool $allowCurrentDate = false, $timeZone = null): array + { + $matches = []; + $max = max(0, $total); + for ($i = 0; $i < $max; ++$i) { + try { + $matches[] = $this->getRunDate($currentTime, $i, $invert, $allowCurrentDate, $timeZone); + } catch (RuntimeException $e) { + break; + } + } + + return $matches; + } + + /** + * Get all or part of the CRON expression. + * + * @param int|string|null $part specify the part to retrieve or NULL to get the full + * cron schedule string + * + * @return null|string Returns the CRON expression, a part of the + * CRON expression, or NULL if the part was specified but not found + */ + public function getExpression($part = null): ?string + { + if (null === $part) { + return implode(' ', $this->cronParts); + } + + if (array_key_exists($part, $this->cronParts)) { + return $this->cronParts[$part]; + } + + return null; + } + + /** + * Gets the parts of the cron expression as an array. + * + * @return string[] + * The array of parts that make up this expression. + */ + public function getParts() + { + return $this->cronParts; + } + + /** + * Helper method to output the full expression. + * + * @return string Full CRON expression + */ + public function __toString(): string + { + return (string) $this->getExpression(); + } + + /** + * Determine if the cron is due to run based on the current date or a + * specific date. This method assumes that the current number of + * seconds are irrelevant, and should be called once per minute. + * + * @param string|\DateTimeInterface $currentTime Relative calculation date + * @param null|string $timeZone TimeZone to use instead of the system default + * + * @return bool Returns TRUE if the cron is due to run or FALSE if not + */ + public function isDue($currentTime = 'now', $timeZone = null): bool + { + $timeZone = $this->determineTimeZone($currentTime, $timeZone); + + if ('now' === $currentTime) { + $currentTime = new DateTime(); + } elseif ($currentTime instanceof DateTime) { + $currentTime = clone $currentTime; + } elseif ($currentTime instanceof DateTimeImmutable) { + $currentTime = DateTime::createFromFormat('U', $currentTime->format('U')); + } elseif (\is_string($currentTime)) { + $currentTime = new DateTime($currentTime); + } + + Assert::isInstanceOf($currentTime, DateTime::class); + $currentTime->setTimezone(new DateTimeZone($timeZone)); + + // drop the seconds to 0 + $currentTime->setTime((int) $currentTime->format('H'), (int) $currentTime->format('i'), 0); + + try { + return $this->getNextRunDate($currentTime, 0, true)->getTimestamp() === $currentTime->getTimestamp(); + } catch (Exception $e) { + return false; + } + } + + /** + * Get the next or previous run date of the expression relative to a date. + * + * @param string|\DateTimeInterface|null $currentTime Relative calculation date + * @param int $nth Number of matches to skip before returning + * @param bool $invert Set to TRUE to go backwards in time + * @param bool $allowCurrentDate Set to TRUE to return the + * current date if it matches the cron expression + * @param string|null $timeZone TimeZone to use instead of the system default + * + * @throws \RuntimeException on too many iterations + * @throws Exception + * + * @return \DateTime + */ + protected function getRunDate($currentTime = null, int $nth = 0, bool $invert = false, bool $allowCurrentDate = false, $timeZone = null): DateTime + { + $timeZone = $this->determineTimeZone($currentTime, $timeZone); + + if ($currentTime instanceof DateTime) { + $currentDate = clone $currentTime; + } elseif ($currentTime instanceof DateTimeImmutable) { + $currentDate = DateTime::createFromFormat('U', $currentTime->format('U')); + } elseif (\is_string($currentTime)) { + $currentDate = new DateTime($currentTime); + } else { + $currentDate = new DateTime('now'); + } + + Assert::isInstanceOf($currentDate, DateTime::class); + $currentDate->setTimezone(new DateTimeZone($timeZone)); + $currentDate->setTime((int) $currentDate->format('H'), (int) $currentDate->format('i'), 0); + + $nextRun = clone $currentDate; + + // We don't have to satisfy * or null fields + $parts = []; + $fields = []; + foreach (self::$order as $position) { + $part = $this->getExpression($position); + if (null === $part || '*' === $part) { + continue; + } + $parts[$position] = $part; + $fields[$position] = $this->fieldFactory->getField($position); + } + + if (isset($parts[2]) && isset($parts[4])) { + $domExpression = sprintf('%s %s %s %s *', $this->getExpression(0), $this->getExpression(1), $this->getExpression(2), $this->getExpression(3)); + $dowExpression = sprintf('%s %s * %s %s', $this->getExpression(0), $this->getExpression(1), $this->getExpression(3), $this->getExpression(4)); + + $domExpression = new self($domExpression); + $dowExpression = new self($dowExpression); + + $domRunDates = $domExpression->getMultipleRunDates($nth + 1, $currentTime, $invert, $allowCurrentDate, $timeZone); + $dowRunDates = $dowExpression->getMultipleRunDates($nth + 1, $currentTime, $invert, $allowCurrentDate, $timeZone); + + $combined = array_merge($domRunDates, $dowRunDates); + usort($combined, function ($a, $b) { + return $a->format('Y-m-d H:i:s') <=> $b->format('Y-m-d H:i:s'); + }); + + return $combined[$nth]; + } + + // Set a hard limit to bail on an impossible date + for ($i = 0; $i < $this->maxIterationCount; ++$i) { + foreach ($parts as $position => $part) { + $satisfied = false; + // Get the field object used to validate this part + $field = $fields[$position]; + // Check if this is singular or a list + if (false === strpos($part, ',')) { + $satisfied = $field->isSatisfiedBy($nextRun, $part); + } else { + foreach (array_map('trim', explode(',', $part)) as $listPart) { + if ($field->isSatisfiedBy($nextRun, $listPart)) { + $satisfied = true; + + break; + } + } + } + + // If the field is not satisfied, then start over + if (!$satisfied) { + $field->increment($nextRun, $invert, $part); + + continue 2; + } + } + + // Skip this match if needed + if ((!$allowCurrentDate && $nextRun == $currentDate) || --$nth > -1) { + $this->fieldFactory->getField(0)->increment($nextRun, $invert, $parts[0] ?? null); + + continue; + } + + return $nextRun; + } + + // @codeCoverageIgnoreStart + throw new RuntimeException('Impossible CRON expression'); + // @codeCoverageIgnoreEnd + } + + /** + * Workout what timeZone should be used. + * + * @param string|\DateTimeInterface|null $currentTime Relative calculation date + * @param string|null $timeZone TimeZone to use instead of the system default + * + * @return string + */ + protected function determineTimeZone($currentTime, ?string $timeZone): string + { + if (null !== $timeZone) { + return $timeZone; + } + + if ($currentTime instanceof DateTimeInterface) { + return $currentTime->getTimeZone()->getName(); + } + + return date_default_timezone_get(); + } +} diff --git a/vendor/dragonmantank/cron-expression/src/Cron/DayOfMonthField.php b/vendor/dragonmantank/cron-expression/src/Cron/DayOfMonthField.php new file mode 100755 index 0000000..21c2d97 --- /dev/null +++ b/vendor/dragonmantank/cron-expression/src/Cron/DayOfMonthField.php @@ -0,0 +1,159 @@ + + */ +class DayOfMonthField extends AbstractField +{ + /** + * {@inheritdoc} + */ + protected $rangeStart = 1; + + /** + * {@inheritdoc} + */ + protected $rangeEnd = 31; + + /** + * Get the nearest day of the week for a given day in a month. + * + * @param int $currentYear Current year + * @param int $currentMonth Current month + * @param int $targetDay Target day of the month + * + * @return \DateTime|null Returns the nearest date + */ + private static function getNearestWeekday(int $currentYear, int $currentMonth, int $targetDay): ?DateTime + { + $tday = str_pad((string) $targetDay, 2, '0', STR_PAD_LEFT); + $target = DateTime::createFromFormat('Y-m-d', "${currentYear}-${currentMonth}-${tday}"); + + if ($target === false) { + return null; + } + + $currentWeekday = (int) $target->format('N'); + + if ($currentWeekday < 6) { + return $target; + } + + $lastDayOfMonth = $target->format('t'); + foreach ([-1, 1, -2, 2] as $i) { + $adjusted = $targetDay + $i; + if ($adjusted > 0 && $adjusted <= $lastDayOfMonth) { + $target->setDate($currentYear, $currentMonth, $adjusted); + + if ((int) $target->format('N') < 6 && (int) $target->format('m') === $currentMonth) { + return $target; + } + } + } + + return null; + } + + /** + * {@inheritdoc} + */ + public function isSatisfiedBy(DateTimeInterface $date, $value): bool + { + // ? states that the field value is to be skipped + if ('?' === $value) { + return true; + } + + $fieldValue = $date->format('d'); + + // Check to see if this is the last day of the month + if ('L' === $value) { + return $fieldValue === $date->format('t'); + } + + // Check to see if this is the nearest weekday to a particular value + if (strpos($value, 'W')) { + // Parse the target day + /** @phpstan-ignore-next-line */ + $targetDay = (int) substr($value, 0, strpos($value, 'W')); + // Find out if the current day is the nearest day of the week + /** @phpstan-ignore-next-line */ + return $date->format('j') === self::getNearestWeekday( + (int) $date->format('Y'), + (int) $date->format('m'), + $targetDay + )->format('j'); + } + + return $this->isSatisfied((int) $date->format('d'), $value); + } + + /** + * @inheritDoc + * + * @param \DateTime|\DateTimeImmutable $date + */ + public function increment(DateTimeInterface &$date, $invert = false, $parts = null): FieldInterface + { + if ($invert) { + $date = $date->modify('previous day')->setTime(23, 59); + } else { + $date = $date->modify('next day')->setTime(0, 0); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function validate(string $value): bool + { + $basicChecks = parent::validate($value); + + // Validate that a list don't have W or L + if (false !== strpos($value, ',') && (false !== strpos($value, 'W') || false !== strpos($value, 'L'))) { + return false; + } + + if (!$basicChecks) { + if ('?' === $value) { + return true; + } + + if ('L' === $value) { + return true; + } + + if (preg_match('/^(.*)W$/', $value, $matches)) { + return $this->validate($matches[1]); + } + + return false; + } + + return $basicChecks; + } +} diff --git a/vendor/dragonmantank/cron-expression/src/Cron/DayOfWeekField.php b/vendor/dragonmantank/cron-expression/src/Cron/DayOfWeekField.php new file mode 100755 index 0000000..9805695 --- /dev/null +++ b/vendor/dragonmantank/cron-expression/src/Cron/DayOfWeekField.php @@ -0,0 +1,204 @@ + 'MON', 2 => 'TUE', 3 => 'WED', 4 => 'THU', 5 => 'FRI', 6 => 'SAT', 7 => 'SUN']; + + /** + * Constructor + */ + public function __construct() + { + $this->nthRange = range(1, 5); + parent::__construct(); + } + + /** + * @inheritDoc + * + * @param \DateTime|\DateTimeImmutable $date + */ + public function isSatisfiedBy(DateTimeInterface $date, $value): bool + { + if ('?' === $value) { + return true; + } + + // Convert text day of the week values to integers + $value = $this->convertLiterals($value); + + $currentYear = (int) $date->format('Y'); + $currentMonth = (int) $date->format('m'); + $lastDayOfMonth = (int) $date->format('t'); + + // Find out if this is the last specific weekday of the month + if (strpos($value, 'L')) { + /** @phpstan-ignore-next-line */ + $weekday = $this->convertLiterals(substr($value, 0, strpos($value, 'L'))); + $weekday %= 7; + + $tdate = clone $date; + $tdate = $tdate->setDate($currentYear, $currentMonth, $lastDayOfMonth); + while ($tdate->format('w') != $weekday) { + $tdateClone = new DateTime(); + $tdate = $tdateClone->setTimezone($tdate->getTimezone()) + ->setDate($currentYear, $currentMonth, --$lastDayOfMonth); + } + + return (int) $date->format('j') === $lastDayOfMonth; + } + + // Handle # hash tokens + if (strpos($value, '#')) { + [$weekday, $nth] = explode('#', $value); + + if (!is_numeric($nth)) { + throw new InvalidArgumentException("Hashed weekdays must be numeric, {$nth} given"); + } else { + $nth = (int) $nth; + } + + // 0 and 7 are both Sunday, however 7 matches date('N') format ISO-8601 + if ('0' === $weekday) { + $weekday = 7; + } + + $weekday = (int) $this->convertLiterals((string) $weekday); + + // Validate the hash fields + if ($weekday < 0 || $weekday > 7) { + throw new InvalidArgumentException("Weekday must be a value between 0 and 7. {$weekday} given"); + } + + if (!\in_array($nth, $this->nthRange, true)) { + throw new InvalidArgumentException("There are never more than 5 or less than 1 of a given weekday in a month, {$nth} given"); + } + + // The current weekday must match the targeted weekday to proceed + if ((int) $date->format('N') !== $weekday) { + return false; + } + + $tdate = clone $date; + $tdate = $tdate->setDate($currentYear, $currentMonth, 1); + $dayCount = 0; + $currentDay = 1; + while ($currentDay < $lastDayOfMonth + 1) { + if ((int) $tdate->format('N') === $weekday) { + if (++$dayCount >= $nth) { + break; + } + } + $tdate = $tdate->setDate($currentYear, $currentMonth, ++$currentDay); + } + + return (int) $date->format('j') === $currentDay; + } + + // Handle day of the week values + if (false !== strpos($value, '-')) { + $parts = explode('-', $value); + if ('7' === $parts[0]) { + $parts[0] = 0; + } elseif ('0' === $parts[1]) { + $parts[1] = 7; + } + $value = implode('-', $parts); + } + + // Test to see which Sunday to use -- 0 == 7 == Sunday + $format = \in_array(7, array_map(function ($value) { + return (int) $value; + }, str_split($value)), true) ? 'N' : 'w'; + $fieldValue = (int) $date->format($format); + + return $this->isSatisfied($fieldValue, $value); + } + + /** + * @inheritDoc + * + * @param \DateTime|\DateTimeImmutable $date + */ + public function increment(DateTimeInterface &$date, $invert = false, $parts = null): FieldInterface + { + if ($invert) { + $date = $date->modify('-1 day')->setTime(23, 59, 0); + } else { + $date = $date->modify('+1 day')->setTime(0, 0, 0); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function validate(string $value): bool + { + $basicChecks = parent::validate($value); + + if (!$basicChecks) { + if ('?' === $value) { + return true; + } + + // Handle the # value + if (false !== strpos($value, '#')) { + $chunks = explode('#', $value); + $chunks[0] = $this->convertLiterals($chunks[0]); + + if (parent::validate($chunks[0]) && is_numeric($chunks[1]) && \in_array((int) $chunks[1], $this->nthRange, true)) { + return true; + } + } + + if (preg_match('/^(.*)L$/', $value, $matches)) { + return $this->validate($matches[1]); + } + + return false; + } + + return $basicChecks; + } +} diff --git a/vendor/dragonmantank/cron-expression/src/Cron/FieldFactory.php b/vendor/dragonmantank/cron-expression/src/Cron/FieldFactory.php new file mode 100755 index 0000000..839b275 --- /dev/null +++ b/vendor/dragonmantank/cron-expression/src/Cron/FieldFactory.php @@ -0,0 +1,52 @@ +fields[$position] ?? $this->fields[$position] = $this->instantiateField($position); + } + + private function instantiateField(int $position): FieldInterface + { + switch ($position) { + case CronExpression::MINUTE: + return new MinutesField(); + case CronExpression::HOUR: + return new HoursField(); + case CronExpression::DAY: + return new DayOfMonthField(); + case CronExpression::MONTH: + return new MonthField(); + case CronExpression::WEEKDAY: + return new DayOfWeekField(); + } + + throw new InvalidArgumentException( + ($position + 1) . ' is not a valid position' + ); + } +} diff --git a/vendor/dragonmantank/cron-expression/src/Cron/FieldFactoryInterface.php b/vendor/dragonmantank/cron-expression/src/Cron/FieldFactoryInterface.php new file mode 100755 index 0000000..8bd3c65 --- /dev/null +++ b/vendor/dragonmantank/cron-expression/src/Cron/FieldFactoryInterface.php @@ -0,0 +1,8 @@ +isSatisfied((int) $date->format('H'), $value); + } + + /** + * {@inheritdoc} + * + * @param \DateTime|\DateTimeImmutable $date + * @param string|null $parts + */ + public function increment(DateTimeInterface &$date, $invert = false, $parts = null): FieldInterface + { + // Change timezone to UTC temporarily. This will + // allow us to go back or forwards and hour even + // if DST will be changed between the hours. + if (null === $parts || '*' === $parts) { + $timezone = $date->getTimezone(); + $date = $date->setTimezone(new DateTimeZone('UTC')); + $date = $date->modify(($invert ? '-' : '+') . '1 hour'); + $date = $date->setTimezone($timezone); + + $date = $date->setTime((int)$date->format('H'), $invert ? 59 : 0); + return $this; + } + + $parts = false !== strpos($parts, ',') ? explode(',', $parts) : [$parts]; + $hours = []; + foreach ($parts as $part) { + $hours = array_merge($hours, $this->getRangeForExpression($part, 23)); + } + + $current_hour = $date->format('H'); + $position = $invert ? \count($hours) - 1 : 0; + $countHours = \count($hours); + if ($countHours > 1) { + for ($i = 0; $i < $countHours - 1; ++$i) { + if ((!$invert && $current_hour >= $hours[$i] && $current_hour < $hours[$i + 1]) || + ($invert && $current_hour > $hours[$i] && $current_hour <= $hours[$i + 1])) { + $position = $invert ? $i : $i + 1; + + break; + } + } + } + + $hour = (int) $hours[$position]; + if ((!$invert && (int) $date->format('H') >= $hour) || ($invert && (int) $date->format('H') <= $hour)) { + $date = $date->modify(($invert ? '-' : '+') . '1 day'); + $date = $date->setTime($invert ? 23 : 0, $invert ? 59 : 0); + } else { + $date = $date->setTime($hour, $invert ? 59 : 0); + } + + return $this; + } +} diff --git a/vendor/dragonmantank/cron-expression/src/Cron/MinutesField.php b/vendor/dragonmantank/cron-expression/src/Cron/MinutesField.php new file mode 100755 index 0000000..d95ba74 --- /dev/null +++ b/vendor/dragonmantank/cron-expression/src/Cron/MinutesField.php @@ -0,0 +1,78 @@ +isSatisfied((int)$date->format('i'), $value); + } + + /** + * {@inheritdoc} + * {@inheritDoc} + * + * @param \DateTime|\DateTimeImmutable $date + * @param string|null $parts + */ + public function increment(DateTimeInterface &$date, $invert = false, $parts = null): FieldInterface + { + if (is_null($parts)) { + $date = $date->modify(($invert ? '-' : '+') . '1 minute'); + return $this; + } + + $parts = false !== strpos($parts, ',') ? explode(',', $parts) : [$parts]; + $minutes = []; + foreach ($parts as $part) { + $minutes = array_merge($minutes, $this->getRangeForExpression($part, 59)); + } + + $current_minute = $date->format('i'); + $position = $invert ? \count($minutes) - 1 : 0; + if (\count($minutes) > 1) { + for ($i = 0; $i < \count($minutes) - 1; ++$i) { + if ((!$invert && $current_minute >= $minutes[$i] && $current_minute < $minutes[$i + 1]) || + ($invert && $current_minute > $minutes[$i] && $current_minute <= $minutes[$i + 1])) { + $position = $invert ? $i : $i + 1; + + break; + } + } + } + + if ((!$invert && $current_minute >= $minutes[$position]) || ($invert && $current_minute <= $minutes[$position])) { + $date = $date->modify(($invert ? '-' : '+') . '1 hour'); + $date = $date->setTime((int) $date->format('H'), $invert ? 59 : 0); + } else { + $date = $date->setTime((int) $date->format('H'), (int) $minutes[$position]); + } + + return $this; + } +} diff --git a/vendor/dragonmantank/cron-expression/src/Cron/MonthField.php b/vendor/dragonmantank/cron-expression/src/Cron/MonthField.php new file mode 100755 index 0000000..06bdbf4 --- /dev/null +++ b/vendor/dragonmantank/cron-expression/src/Cron/MonthField.php @@ -0,0 +1,59 @@ + 'JAN', 2 => 'FEB', 3 => 'MAR', 4 => 'APR', 5 => 'MAY', 6 => 'JUN', 7 => 'JUL', + 8 => 'AUG', 9 => 'SEP', 10 => 'OCT', 11 => 'NOV', 12 => 'DEC', ]; + + /** + * {@inheritdoc} + */ + public function isSatisfiedBy(DateTimeInterface $date, $value): bool + { + if ($value == '?') { + return true; + } + + $value = $this->convertLiterals($value); + + return $this->isSatisfied((int) $date->format('m'), $value); + } + + /** + * @inheritDoc + * + * @param \DateTime|\DateTimeImmutable $date + */ + public function increment(DateTimeInterface &$date, $invert = false, $parts = null): FieldInterface + { + if ($invert) { + $date = $date->modify('last day of previous month')->setTime(23, 59); + } else { + $date = $date->modify('first day of next month')->setTime(0, 0); + } + + return $this; + } +} diff --git a/vendor/egulias/email-validator/LICENSE b/vendor/egulias/email-validator/LICENSE new file mode 100755 index 0000000..c34d2c1 --- /dev/null +++ b/vendor/egulias/email-validator/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2016 Eduardo Gulias Davis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/egulias/email-validator/composer.json b/vendor/egulias/email-validator/composer.json new file mode 100755 index 0000000..a275696 --- /dev/null +++ b/vendor/egulias/email-validator/composer.json @@ -0,0 +1,38 @@ +{ + "name": "egulias/email-validator", + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": ["email", "validation", "validator", "emailvalidation", "emailvalidator"], + "license": "MIT", + "authors": [ + {"name": "Eduardo Gulias Davis"} + ], + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "require": { + "php": ">=5.5", + "doctrine/lexer": "^1.0.1", + "symfony/polyfill-intl-idn": "^1.10" + }, + "require-dev": { + "dominicsayers/isemail": "^3.0.7", + "phpunit/phpunit": "^4.8.36|^7.5.15", + "satooshi/php-coveralls": "^1.0.1" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Egulias\\EmailValidator\\Tests\\": "tests" + } + } +} diff --git a/vendor/egulias/email-validator/src/EmailLexer.php b/vendor/egulias/email-validator/src/EmailLexer.php new file mode 100755 index 0000000..59dcd58 --- /dev/null +++ b/vendor/egulias/email-validator/src/EmailLexer.php @@ -0,0 +1,283 @@ + self::S_OPENPARENTHESIS, + ')' => self::S_CLOSEPARENTHESIS, + '<' => self::S_LOWERTHAN, + '>' => self::S_GREATERTHAN, + '[' => self::S_OPENBRACKET, + ']' => self::S_CLOSEBRACKET, + ':' => self::S_COLON, + ';' => self::S_SEMICOLON, + '@' => self::S_AT, + '\\' => self::S_BACKSLASH, + '/' => self::S_SLASH, + ',' => self::S_COMMA, + '.' => self::S_DOT, + "'" => self::S_SQUOTE, + "`" => self::S_BACKTICK, + '"' => self::S_DQUOTE, + '-' => self::S_HYPHEN, + '::' => self::S_DOUBLECOLON, + ' ' => self::S_SP, + "\t" => self::S_HTAB, + "\r" => self::S_CR, + "\n" => self::S_LF, + "\r\n" => self::CRLF, + 'IPv6' => self::S_IPV6TAG, + '{' => self::S_OPENQBRACKET, + '}' => self::S_CLOSEQBRACKET, + '' => self::S_EMPTY, + '\0' => self::C_NUL, + ); + + /** + * @var bool + */ + protected $hasInvalidTokens = false; + + /** + * @var array + * + * @psalm-var array{value:string, type:null|int, position:int}|array + */ + protected $previous = []; + + /** + * The last matched/seen token. + * + * @var array + * + * @psalm-var array{value:string, type:null|int, position:int} + */ + public $token; + + /** + * The next token in the input. + * + * @var array|null + */ + public $lookahead; + + /** + * @psalm-var array{value:'', type:null, position:0} + */ + private static $nullToken = [ + 'value' => '', + 'type' => null, + 'position' => 0, + ]; + + public function __construct() + { + $this->previous = $this->token = self::$nullToken; + $this->lookahead = null; + } + + /** + * @return void + */ + public function reset() + { + $this->hasInvalidTokens = false; + parent::reset(); + $this->previous = $this->token = self::$nullToken; + } + + /** + * @return bool + */ + public function hasInvalidTokens() + { + return $this->hasInvalidTokens; + } + + /** + * @param int $type + * @throws \UnexpectedValueException + * @return boolean + * + * @psalm-suppress InvalidScalarArgument + */ + public function find($type) + { + $search = clone $this; + $search->skipUntil($type); + + if (!$search->lookahead) { + throw new \UnexpectedValueException($type . ' not found'); + } + return true; + } + + /** + * getPrevious + * + * @return array + */ + public function getPrevious() + { + return $this->previous; + } + + /** + * moveNext + * + * @return boolean + */ + public function moveNext() + { + $this->previous = $this->token; + $hasNext = parent::moveNext(); + $this->token = $this->token ?: self::$nullToken; + + return $hasNext; + } + + /** + * Lexical catchable patterns. + * + * @return string[] + */ + protected function getCatchablePatterns() + { + return array( + '[a-zA-Z_]+[46]?', //ASCII and domain literal + '[^\x00-\x7F]', //UTF-8 + '[0-9]+', + '\r\n', + '::', + '\s+?', + '.', + ); + } + + /** + * Lexical non-catchable patterns. + * + * @return string[] + */ + protected function getNonCatchablePatterns() + { + return array('[\xA0-\xff]+'); + } + + /** + * Retrieve token type. Also processes the token value if necessary. + * + * @param string $value + * @throws \InvalidArgumentException + * @return integer + */ + protected function getType(&$value) + { + if ($this->isNullType($value)) { + return self::C_NUL; + } + + if ($this->isValid($value)) { + return $this->charValue[$value]; + } + + if ($this->isUTF8Invalid($value)) { + $this->hasInvalidTokens = true; + return self::INVALID; + } + + return self::GENERIC; + } + + /** + * @param string $value + * + * @return bool + */ + protected function isValid($value) + { + if (isset($this->charValue[$value])) { + return true; + } + + return false; + } + + /** + * @param string $value + * @return bool + */ + protected function isNullType($value) + { + if ($value === "\0") { + return true; + } + + return false; + } + + /** + * @param string $value + * @return bool + */ + protected function isUTF8Invalid($value) + { + if (preg_match('/\p{Cc}+/u', $value)) { + return true; + } + + return false; + } + + /** + * @return string + */ + protected function getModifiers() + { + return 'iu'; + } +} diff --git a/vendor/egulias/email-validator/src/EmailParser.php b/vendor/egulias/email-validator/src/EmailParser.php new file mode 100755 index 0000000..6b7bad6 --- /dev/null +++ b/vendor/egulias/email-validator/src/EmailParser.php @@ -0,0 +1,137 @@ + + */ +class EmailParser +{ + const EMAIL_MAX_LENGTH = 254; + + /** + * @var array + */ + protected $warnings = []; + + /** + * @var string + */ + protected $domainPart = ''; + + /** + * @var string + */ + protected $localPart = ''; + /** + * @var EmailLexer + */ + protected $lexer; + + /** + * @var LocalPart + */ + protected $localPartParser; + + /** + * @var DomainPart + */ + protected $domainPartParser; + + public function __construct(EmailLexer $lexer) + { + $this->lexer = $lexer; + $this->localPartParser = new LocalPart($this->lexer); + $this->domainPartParser = new DomainPart($this->lexer); + } + + /** + * @param string $str + * @return array + */ + public function parse($str) + { + $this->lexer->setInput($str); + + if (!$this->hasAtToken()) { + throw new NoLocalPart(); + } + + + $this->localPartParser->parse($str); + $this->domainPartParser->parse($str); + + $this->setParts($str); + + if ($this->lexer->hasInvalidTokens()) { + throw new ExpectingATEXT(); + } + + return array('local' => $this->localPart, 'domain' => $this->domainPart); + } + + /** + * @return Warning\Warning[] + */ + public function getWarnings() + { + $localPartWarnings = $this->localPartParser->getWarnings(); + $domainPartWarnings = $this->domainPartParser->getWarnings(); + $this->warnings = array_merge($localPartWarnings, $domainPartWarnings); + + $this->addLongEmailWarning($this->localPart, $this->domainPart); + + return $this->warnings; + } + + /** + * @return string + */ + public function getParsedDomainPart() + { + return $this->domainPart; + } + + /** + * @param string $email + */ + protected function setParts($email) + { + $parts = explode('@', $email); + $this->domainPart = $this->domainPartParser->getDomainPart(); + $this->localPart = $parts[0]; + } + + /** + * @return bool + */ + protected function hasAtToken() + { + $this->lexer->moveNext(); + $this->lexer->moveNext(); + if ($this->lexer->token['type'] === EmailLexer::S_AT) { + return false; + } + + return true; + } + + /** + * @param string $localPart + * @param string $parsedDomainPart + */ + protected function addLongEmailWarning($localPart, $parsedDomainPart) + { + if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAIL_MAX_LENGTH) { + $this->warnings[EmailTooLong::CODE] = new EmailTooLong(); + } + } +} diff --git a/vendor/egulias/email-validator/src/EmailValidator.php b/vendor/egulias/email-validator/src/EmailValidator.php new file mode 100755 index 0000000..a30f21d --- /dev/null +++ b/vendor/egulias/email-validator/src/EmailValidator.php @@ -0,0 +1,67 @@ +lexer = new EmailLexer(); + } + + /** + * @param string $email + * @param EmailValidation $emailValidation + * @return bool + */ + public function isValid($email, EmailValidation $emailValidation) + { + $isValid = $emailValidation->isValid($email, $this->lexer); + $this->warnings = $emailValidation->getWarnings(); + $this->error = $emailValidation->getError(); + + return $isValid; + } + + /** + * @return boolean + */ + public function hasWarnings() + { + return !empty($this->warnings); + } + + /** + * @return array + */ + public function getWarnings() + { + return $this->warnings; + } + + /** + * @return InvalidEmail|null + */ + public function getError() + { + return $this->error; + } +} diff --git a/vendor/egulias/email-validator/src/Exception/AtextAfterCFWS.php b/vendor/egulias/email-validator/src/Exception/AtextAfterCFWS.php new file mode 100755 index 0000000..97f41a2 --- /dev/null +++ b/vendor/egulias/email-validator/src/Exception/AtextAfterCFWS.php @@ -0,0 +1,9 @@ +lexer->moveNext(); + + $this->performDomainStartChecks(); + + $domain = $this->doParseDomainPart(); + + $prev = $this->lexer->getPrevious(); + $length = strlen($domain); + + if ($prev['type'] === EmailLexer::S_DOT) { + throw new DotAtEnd(); + } + if ($prev['type'] === EmailLexer::S_HYPHEN) { + throw new DomainHyphened(); + } + if ($length > self::DOMAIN_MAX_LENGTH) { + $this->warnings[DomainTooLong::CODE] = new DomainTooLong(); + } + if ($prev['type'] === EmailLexer::S_CR) { + throw new CRLFAtTheEnd(); + } + $this->domainPart = $domain; + } + + private function performDomainStartChecks() + { + $this->checkInvalidTokensAfterAT(); + $this->checkEmptyDomain(); + + if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { + $this->warnings[DeprecatedComment::CODE] = new DeprecatedComment(); + $this->parseDomainComments(); + } + } + + private function checkEmptyDomain() + { + $thereIsNoDomain = $this->lexer->token['type'] === EmailLexer::S_EMPTY || + ($this->lexer->token['type'] === EmailLexer::S_SP && + !$this->lexer->isNextToken(EmailLexer::GENERIC)); + + if ($thereIsNoDomain) { + throw new NoDomainPart(); + } + } + + private function checkInvalidTokensAfterAT() + { + if ($this->lexer->token['type'] === EmailLexer::S_DOT) { + throw new DotAtStart(); + } + if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) { + throw new DomainHyphened(); + } + } + + /** + * @return string + */ + public function getDomainPart() + { + return $this->domainPart; + } + + /** + * @param string $addressLiteral + * @param int $maxGroups + */ + public function checkIPV6Tag($addressLiteral, $maxGroups = 8) + { + $prev = $this->lexer->getPrevious(); + if ($prev['type'] === EmailLexer::S_COLON) { + $this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd(); + } + + $IPv6 = substr($addressLiteral, 5); + //Daniel Marschall's new IPv6 testing strategy + $matchesIP = explode(':', $IPv6); + $groupCount = count($matchesIP); + $colons = strpos($IPv6, '::'); + + if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) { + $this->warnings[IPV6BadChar::CODE] = new IPV6BadChar(); + } + + if ($colons === false) { + // We need exactly the right number of groups + if ($groupCount !== $maxGroups) { + $this->warnings[IPV6GroupCount::CODE] = new IPV6GroupCount(); + } + return; + } + + if ($colons !== strrpos($IPv6, '::')) { + $this->warnings[IPV6DoubleColon::CODE] = new IPV6DoubleColon(); + return; + } + + if ($colons === 0 || $colons === (strlen($IPv6) - 2)) { + // RFC 4291 allows :: at the start or end of an address + //with 7 other groups in addition + ++$maxGroups; + } + + if ($groupCount > $maxGroups) { + $this->warnings[IPV6MaxGroups::CODE] = new IPV6MaxGroups(); + } elseif ($groupCount === $maxGroups) { + $this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated(); + } + } + + /** + * @return string + */ + protected function doParseDomainPart() + { + $domain = ''; + $label = ''; + $openedParenthesis = 0; + do { + $prev = $this->lexer->getPrevious(); + + $this->checkNotAllowedChars($this->lexer->token); + + if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { + $this->parseComments(); + $openedParenthesis += $this->getOpenedParenthesis(); + $this->lexer->moveNext(); + $tmpPrev = $this->lexer->getPrevious(); + if ($tmpPrev['type'] === EmailLexer::S_CLOSEPARENTHESIS) { + $openedParenthesis--; + } + } + if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) { + if ($openedParenthesis === 0) { + throw new UnopenedComment(); + } else { + $openedParenthesis--; + } + } + + $this->checkConsecutiveDots(); + $this->checkDomainPartExceptions($prev); + + if ($this->hasBrackets()) { + $this->parseDomainLiteral(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_DOT) { + $this->checkLabelLength($label); + $label = ''; + } else { + $label .= $this->lexer->token['value']; + } + + if ($this->isFWS()) { + $this->parseFWS(); + } + + $domain .= $this->lexer->token['value']; + $this->lexer->moveNext(); + if ($this->lexer->token['type'] === EmailLexer::S_SP) { + throw new CharNotAllowed(); + } + } while (null !== $this->lexer->token['type']); + + $this->checkLabelLength($label); + + return $domain; + } + + private function checkNotAllowedChars(array $token) + { + $notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true]; + if (isset($notAllowed[$token['type']])) { + throw new CharNotAllowed(); + } + } + + /** + * @return string|false + */ + protected function parseDomainLiteral() + { + if ($this->lexer->isNextToken(EmailLexer::S_COLON)) { + $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart(); + } + if ($this->lexer->isNextToken(EmailLexer::S_IPV6TAG)) { + $lexer = clone $this->lexer; + $lexer->moveNext(); + if ($lexer->isNextToken(EmailLexer::S_DOUBLECOLON)) { + $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart(); + } + } + + return $this->doParseDomainLiteral(); + } + + /** + * @return string|false + */ + protected function doParseDomainLiteral() + { + $IPv6TAG = false; + $addressLiteral = ''; + do { + if ($this->lexer->token['type'] === EmailLexer::C_NUL) { + throw new ExpectingDTEXT(); + } + + if ($this->lexer->token['type'] === EmailLexer::INVALID || + $this->lexer->token['type'] === EmailLexer::C_DEL || + $this->lexer->token['type'] === EmailLexer::S_LF + ) { + $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT(); + } + + if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENQBRACKET, EmailLexer::S_OPENBRACKET))) { + throw new ExpectingDTEXT(); + } + + if ($this->lexer->isNextTokenAny( + array(EmailLexer::S_HTAB, EmailLexer::S_SP, $this->lexer->token['type'] === EmailLexer::CRLF) + )) { + $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); + $this->parseFWS(); + } + + if ($this->lexer->isNextToken(EmailLexer::S_CR)) { + throw new CRNoLF(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH) { + $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT(); + $addressLiteral .= $this->lexer->token['value']; + $this->lexer->moveNext(); + $this->validateQuotedPair(); + } + if ($this->lexer->token['type'] === EmailLexer::S_IPV6TAG) { + $IPv6TAG = true; + } + if ($this->lexer->token['type'] === EmailLexer::S_CLOSEQBRACKET) { + break; + } + + $addressLiteral .= $this->lexer->token['value']; + + } while ($this->lexer->moveNext()); + + $addressLiteral = str_replace('[', '', $addressLiteral); + $addressLiteral = $this->checkIPV4Tag($addressLiteral); + + if (false === $addressLiteral) { + return $addressLiteral; + } + + if (!$IPv6TAG) { + $this->warnings[DomainLiteral::CODE] = new DomainLiteral(); + return $addressLiteral; + } + + $this->warnings[AddressLiteral::CODE] = new AddressLiteral(); + + $this->checkIPV6Tag($addressLiteral); + + return $addressLiteral; + } + + /** + * @param string $addressLiteral + * + * @return string|false + */ + protected function checkIPV4Tag($addressLiteral) + { + $matchesIP = array(); + + // Extract IPv4 part from the end of the address-literal (if there is one) + if (preg_match( + '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/', + $addressLiteral, + $matchesIP + ) > 0 + ) { + $index = strrpos($addressLiteral, $matchesIP[0]); + if ($index === 0) { + $this->warnings[AddressLiteral::CODE] = new AddressLiteral(); + return false; + } + // Convert IPv4 part to IPv6 format for further testing + $addressLiteral = substr($addressLiteral, 0, (int) $index) . '0:0'; + } + + return $addressLiteral; + } + + protected function checkDomainPartExceptions(array $prev) + { + $invalidDomainTokens = array( + EmailLexer::S_DQUOTE => true, + EmailLexer::S_SQUOTE => true, + EmailLexer::S_BACKTICK => true, + EmailLexer::S_SEMICOLON => true, + EmailLexer::S_GREATERTHAN => true, + EmailLexer::S_LOWERTHAN => true, + ); + + if (isset($invalidDomainTokens[$this->lexer->token['type']])) { + throw new ExpectingATEXT(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_COMMA) { + throw new CommaInDomain(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_AT) { + throw new ConsecutiveAt(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_OPENQBRACKET && $prev['type'] !== EmailLexer::S_AT) { + throw new ExpectingATEXT(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN && $this->lexer->isNextToken(EmailLexer::S_DOT)) { + throw new DomainHyphened(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH + && $this->lexer->isNextToken(EmailLexer::GENERIC)) { + throw new ExpectingATEXT(); + } + } + + /** + * @return bool + */ + protected function hasBrackets() + { + if ($this->lexer->token['type'] !== EmailLexer::S_OPENBRACKET) { + return false; + } + + try { + $this->lexer->find(EmailLexer::S_CLOSEBRACKET); + } catch (\RuntimeException $e) { + throw new ExpectingDomainLiteralClose(); + } + + return true; + } + + /** + * @param string $label + */ + protected function checkLabelLength($label) + { + if ($this->isLabelTooLong($label)) { + $this->warnings[LabelTooLong::CODE] = new LabelTooLong(); + } + } + + /** + * @param string $label + * @return bool + */ + private function isLabelTooLong($label) + { + if (preg_match('/[^\x00-\x7F]/', $label)) { + idn_to_ascii($label, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46, $idnaInfo); + + return (bool) ($idnaInfo['errors'] & IDNA_ERROR_LABEL_TOO_LONG); + } + + return strlen($label) > self::LABEL_MAX_LENGTH; + } + + protected function parseDomainComments() + { + $this->isUnclosedComment(); + while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) { + $this->warnEscaping(); + $this->lexer->moveNext(); + } + + $this->lexer->moveNext(); + if ($this->lexer->isNextToken(EmailLexer::S_DOT)) { + throw new ExpectingATEXT(); + } + } + + protected function addTLDWarnings() + { + if ($this->warnings[DomainLiteral::CODE]) { + $this->warnings[TLD::CODE] = new TLD(); + } + } +} diff --git a/vendor/egulias/email-validator/src/Parser/LocalPart.php b/vendor/egulias/email-validator/src/Parser/LocalPart.php new file mode 100755 index 0000000..3c21f34 --- /dev/null +++ b/vendor/egulias/email-validator/src/Parser/LocalPart.php @@ -0,0 +1,145 @@ +lexer->token['type'] !== EmailLexer::S_AT && null !== $this->lexer->token['type']) { + if ($this->lexer->token['type'] === EmailLexer::S_DOT && null === $this->lexer->getPrevious()['type']) { + throw new DotAtStart(); + } + + $closingQuote = $this->checkDQUOTE($closingQuote); + if ($closingQuote && $parseDQuote) { + $parseDQuote = $this->parseDoubleQuote(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { + $this->parseComments(); + $openedParenthesis += $this->getOpenedParenthesis(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) { + if ($openedParenthesis === 0) { + throw new UnopenedComment(); + } + + $openedParenthesis--; + } + + $this->checkConsecutiveDots(); + + if ($this->lexer->token['type'] === EmailLexer::S_DOT && + $this->lexer->isNextToken(EmailLexer::S_AT) + ) { + throw new DotAtEnd(); + } + + $this->warnEscaping(); + $this->isInvalidToken($this->lexer->token, $closingQuote); + + if ($this->isFWS()) { + $this->parseFWS(); + } + + $totalLength += strlen($this->lexer->token['value']); + $this->lexer->moveNext(); + } + + if ($totalLength > LocalTooLong::LOCAL_PART_LENGTH) { + $this->warnings[LocalTooLong::CODE] = new LocalTooLong(); + } + } + + /** + * @return bool + */ + protected function parseDoubleQuote() + { + $parseAgain = true; + $special = array( + EmailLexer::S_CR => true, + EmailLexer::S_HTAB => true, + EmailLexer::S_LF => true + ); + + $invalid = array( + EmailLexer::C_NUL => true, + EmailLexer::S_HTAB => true, + EmailLexer::S_CR => true, + EmailLexer::S_LF => true + ); + $setSpecialsWarning = true; + + $this->lexer->moveNext(); + + while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && null !== $this->lexer->token['type']) { + $parseAgain = false; + if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) { + $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); + $setSpecialsWarning = false; + } + if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH && $this->lexer->isNextToken(EmailLexer::S_DQUOTE)) { + $this->lexer->moveNext(); + } + + $this->lexer->moveNext(); + + if (!$this->escaped() && isset($invalid[$this->lexer->token['type']])) { + throw new ExpectingATEXT(); + } + } + + $prev = $this->lexer->getPrevious(); + + if ($prev['type'] === EmailLexer::S_BACKSLASH) { + if (!$this->checkDQUOTE(false)) { + throw new UnclosedQuotedString(); + } + } + + if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) { + throw new ExpectingAT(); + } + + return $parseAgain; + } + + /** + * @param bool $closingQuote + */ + protected function isInvalidToken(array $token, $closingQuote) + { + $forbidden = array( + EmailLexer::S_COMMA, + EmailLexer::S_CLOSEBRACKET, + EmailLexer::S_OPENBRACKET, + EmailLexer::S_GREATERTHAN, + EmailLexer::S_LOWERTHAN, + EmailLexer::S_COLON, + EmailLexer::S_SEMICOLON, + EmailLexer::INVALID + ); + + if (in_array($token['type'], $forbidden) && !$closingQuote) { + throw new ExpectingATEXT(); + } + } +} diff --git a/vendor/egulias/email-validator/src/Parser/Parser.php b/vendor/egulias/email-validator/src/Parser/Parser.php new file mode 100755 index 0000000..ccdc938 --- /dev/null +++ b/vendor/egulias/email-validator/src/Parser/Parser.php @@ -0,0 +1,249 @@ +lexer = $lexer; + } + + /** + * @return \Egulias\EmailValidator\Warning\Warning[] + */ + public function getWarnings() + { + return $this->warnings; + } + + /** + * @param string $str + */ + abstract public function parse($str); + + /** @return int */ + public function getOpenedParenthesis() + { + return $this->openedParenthesis; + } + + /** + * validateQuotedPair + */ + protected function validateQuotedPair() + { + if (!($this->lexer->token['type'] === EmailLexer::INVALID + || $this->lexer->token['type'] === EmailLexer::C_DEL)) { + throw new ExpectingQPair(); + } + + $this->warnings[QuotedPart::CODE] = + new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']); + } + + protected function parseComments() + { + $this->openedParenthesis = 1; + $this->isUnclosedComment(); + $this->warnings[Comment::CODE] = new Comment(); + while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) { + if ($this->lexer->isNextToken(EmailLexer::S_OPENPARENTHESIS)) { + $this->openedParenthesis++; + } + $this->warnEscaping(); + $this->lexer->moveNext(); + } + + $this->lexer->moveNext(); + if ($this->lexer->isNextTokenAny(array(EmailLexer::GENERIC, EmailLexer::S_EMPTY))) { + throw new ExpectingATEXT(); + } + + if ($this->lexer->isNextToken(EmailLexer::S_AT)) { + $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); + } + } + + /** + * @return bool + */ + protected function isUnclosedComment() + { + try { + $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS); + return true; + } catch (\RuntimeException $e) { + throw new UnclosedComment(); + } + } + + protected function parseFWS() + { + $previous = $this->lexer->getPrevious(); + + $this->checkCRLFInFWS(); + + if ($this->lexer->token['type'] === EmailLexer::S_CR) { + throw new CRNoLF(); + } + + if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] !== EmailLexer::S_AT) { + throw new AtextAfterCFWS(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_LF || $this->lexer->token['type'] === EmailLexer::C_NUL) { + throw new ExpectingCTEXT(); + } + + if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous['type'] === EmailLexer::S_AT) { + $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); + } else { + $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); + } + } + + protected function checkConsecutiveDots() + { + if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) { + throw new ConsecutiveDot(); + } + } + + /** + * @return bool + */ + protected function isFWS() + { + if ($this->escaped()) { + return false; + } + + if ($this->lexer->token['type'] === EmailLexer::S_SP || + $this->lexer->token['type'] === EmailLexer::S_HTAB || + $this->lexer->token['type'] === EmailLexer::S_CR || + $this->lexer->token['type'] === EmailLexer::S_LF || + $this->lexer->token['type'] === EmailLexer::CRLF + ) { + return true; + } + + return false; + } + + /** + * @return bool + */ + protected function escaped() + { + $previous = $this->lexer->getPrevious(); + + if ($previous && $previous['type'] === EmailLexer::S_BACKSLASH + && + $this->lexer->token['type'] !== EmailLexer::GENERIC + ) { + return true; + } + + return false; + } + + /** + * @return bool + */ + protected function warnEscaping() + { + if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) { + return false; + } + + if ($this->lexer->isNextToken(EmailLexer::GENERIC)) { + throw new ExpectingATEXT(); + } + + if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { + return false; + } + + $this->warnings[QuotedPart::CODE] = + new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']); + return true; + + } + + /** + * @param bool $hasClosingQuote + * + * @return bool + */ + protected function checkDQUOTE($hasClosingQuote) + { + if ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE) { + return $hasClosingQuote; + } + if ($hasClosingQuote) { + return $hasClosingQuote; + } + $previous = $this->lexer->getPrevious(); + if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) { + throw new ExpectingATEXT(); + } + + try { + $this->lexer->find(EmailLexer::S_DQUOTE); + $hasClosingQuote = true; + } catch (\Exception $e) { + throw new UnclosedQuotedString(); + } + $this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']); + + return $hasClosingQuote; + } + + protected function checkCRLFInFWS() + { + if ($this->lexer->token['type'] !== EmailLexer::CRLF) { + return; + } + + if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { + throw new CRLFX2(); + } + + if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { + throw new CRLFAtTheEnd(); + } + } +} diff --git a/vendor/egulias/email-validator/src/Validation/DNSCheckValidation.php b/vendor/egulias/email-validator/src/Validation/DNSCheckValidation.php new file mode 100755 index 0000000..491082a --- /dev/null +++ b/vendor/egulias/email-validator/src/Validation/DNSCheckValidation.php @@ -0,0 +1,166 @@ +error = new LocalOrReservedDomain(); + return false; + } + + return $this->checkDns($host); + } + + public function getError() + { + return $this->error; + } + + public function getWarnings() + { + return $this->warnings; + } + + /** + * @param string $host + * + * @return bool + */ + protected function checkDns($host) + { + $variant = INTL_IDNA_VARIANT_UTS46; + + $host = rtrim(idn_to_ascii($host, IDNA_DEFAULT, $variant), '.') . '.'; + + return $this->validateDnsRecords($host); + } + + + /** + * Validate the DNS records for given host. + * + * @param string $host A set of DNS records in the format returned by dns_get_record. + * + * @return bool True on success. + */ + private function validateDnsRecords($host) + { + // Get all MX, A and AAAA DNS records for host + // Using @ as workaround to fix https://bugs.php.net/bug.php?id=73149 + $dnsRecords = @dns_get_record($host, DNS_MX + DNS_A + DNS_AAAA); + + + // No MX, A or AAAA DNS records + if (empty($dnsRecords)) { + $this->error = new NoDNSRecord(); + return false; + } + + // For each DNS record + foreach ($dnsRecords as $dnsRecord) { + if (!$this->validateMXRecord($dnsRecord)) { + return false; + } + } + + // No MX records (fallback to A or AAAA records) + if (empty($this->mxRecords)) { + $this->warnings[NoDNSMXRecord::CODE] = new NoDNSMXRecord(); + } + + return true; + } + + /** + * Validate an MX record + * + * @param array $dnsRecord Given DNS record. + * + * @return bool True if valid. + */ + private function validateMxRecord($dnsRecord) + { + if ($dnsRecord['type'] !== 'MX') { + return true; + } + + // "Null MX" record indicates the domain accepts no mail (https://tools.ietf.org/html/rfc7505) + if (empty($dnsRecord['target']) || $dnsRecord['target'] === '.') { + $this->error = new DomainAcceptsNoMail(); + return false; + } + + $this->mxRecords[] = $dnsRecord; + + return true; + } +} diff --git a/vendor/egulias/email-validator/src/Validation/EmailValidation.php b/vendor/egulias/email-validator/src/Validation/EmailValidation.php new file mode 100755 index 0000000..d5a015b --- /dev/null +++ b/vendor/egulias/email-validator/src/Validation/EmailValidation.php @@ -0,0 +1,34 @@ +errors = $errors; + parent::__construct(); + } + + /** + * @return InvalidEmail[] + */ + public function getErrors() + { + return $this->errors; + } +} diff --git a/vendor/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php b/vendor/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php new file mode 100755 index 0000000..feb2240 --- /dev/null +++ b/vendor/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php @@ -0,0 +1,124 @@ +validations = $validations; + $this->mode = $mode; + } + + /** + * {@inheritdoc} + */ + public function isValid($email, EmailLexer $emailLexer) + { + $result = true; + $errors = []; + foreach ($this->validations as $validation) { + $emailLexer->reset(); + $validationResult = $validation->isValid($email, $emailLexer); + $result = $result && $validationResult; + $this->warnings = array_merge($this->warnings, $validation->getWarnings()); + $errors = $this->addNewError($validation->getError(), $errors); + + if ($this->shouldStop($result)) { + break; + } + } + + if (!empty($errors)) { + $this->error = new MultipleErrors($errors); + } + + return $result; + } + + /** + * @param \Egulias\EmailValidator\Exception\InvalidEmail|null $possibleError + * @param \Egulias\EmailValidator\Exception\InvalidEmail[] $errors + * + * @return \Egulias\EmailValidator\Exception\InvalidEmail[] + */ + private function addNewError($possibleError, array $errors) + { + if (null !== $possibleError) { + $errors[] = $possibleError; + } + + return $errors; + } + + /** + * @param bool $result + * + * @return bool + */ + private function shouldStop($result) + { + return !$result && $this->mode === self::STOP_ON_ERROR; + } + + /** + * Returns the validation errors. + * + * @return MultipleErrors|null + */ + public function getError() + { + return $this->error; + } + + /** + * {@inheritdoc} + */ + public function getWarnings() + { + return $this->warnings; + } +} diff --git a/vendor/egulias/email-validator/src/Validation/NoRFCWarningsValidation.php b/vendor/egulias/email-validator/src/Validation/NoRFCWarningsValidation.php new file mode 100755 index 0000000..6b31e54 --- /dev/null +++ b/vendor/egulias/email-validator/src/Validation/NoRFCWarningsValidation.php @@ -0,0 +1,41 @@ +getWarnings())) { + return true; + } + + $this->error = new RFCWarnings(); + + return false; + } + + /** + * {@inheritdoc} + */ + public function getError() + { + return $this->error ?: parent::getError(); + } +} diff --git a/vendor/egulias/email-validator/src/Validation/RFCValidation.php b/vendor/egulias/email-validator/src/Validation/RFCValidation.php new file mode 100755 index 0000000..8781e0b --- /dev/null +++ b/vendor/egulias/email-validator/src/Validation/RFCValidation.php @@ -0,0 +1,49 @@ +parser = new EmailParser($emailLexer); + try { + $this->parser->parse((string)$email); + } catch (InvalidEmail $invalid) { + $this->error = $invalid; + return false; + } + + $this->warnings = $this->parser->getWarnings(); + return true; + } + + public function getError() + { + return $this->error; + } + + public function getWarnings() + { + return $this->warnings; + } +} diff --git a/vendor/egulias/email-validator/src/Validation/SpoofCheckValidation.php b/vendor/egulias/email-validator/src/Validation/SpoofCheckValidation.php new file mode 100755 index 0000000..e10bfab --- /dev/null +++ b/vendor/egulias/email-validator/src/Validation/SpoofCheckValidation.php @@ -0,0 +1,51 @@ +setChecks(Spoofchecker::SINGLE_SCRIPT); + + if ($checker->isSuspicious($email)) { + $this->error = new SpoofEmail(); + } + + return $this->error === null; + } + + /** + * @return InvalidEmail|null + */ + public function getError() + { + return $this->error; + } + + public function getWarnings() + { + return []; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/AddressLiteral.php b/vendor/egulias/email-validator/src/Warning/AddressLiteral.php new file mode 100755 index 0000000..77e70f7 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/AddressLiteral.php @@ -0,0 +1,14 @@ +message = 'Address literal in domain part'; + $this->rfcNumber = 5321; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/CFWSNearAt.php b/vendor/egulias/email-validator/src/Warning/CFWSNearAt.php new file mode 100755 index 0000000..be43bbe --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/CFWSNearAt.php @@ -0,0 +1,13 @@ +message = "Deprecated folding white space near @"; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/CFWSWithFWS.php b/vendor/egulias/email-validator/src/Warning/CFWSWithFWS.php new file mode 100755 index 0000000..dea3450 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/CFWSWithFWS.php @@ -0,0 +1,13 @@ +message = 'Folding whites space followed by folding white space'; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/Comment.php b/vendor/egulias/email-validator/src/Warning/Comment.php new file mode 100755 index 0000000..704c290 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/Comment.php @@ -0,0 +1,13 @@ +message = "Comments found in this email"; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/DeprecatedComment.php b/vendor/egulias/email-validator/src/Warning/DeprecatedComment.php new file mode 100755 index 0000000..ad43bd7 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/DeprecatedComment.php @@ -0,0 +1,13 @@ +message = 'Deprecated comments'; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/DomainLiteral.php b/vendor/egulias/email-validator/src/Warning/DomainLiteral.php new file mode 100755 index 0000000..6f36b5e --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/DomainLiteral.php @@ -0,0 +1,14 @@ +message = 'Domain Literal'; + $this->rfcNumber = 5322; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/DomainTooLong.php b/vendor/egulias/email-validator/src/Warning/DomainTooLong.php new file mode 100755 index 0000000..61ff17a --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/DomainTooLong.php @@ -0,0 +1,14 @@ +message = 'Domain is too long, exceeds 255 chars'; + $this->rfcNumber = 5322; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/EmailTooLong.php b/vendor/egulias/email-validator/src/Warning/EmailTooLong.php new file mode 100755 index 0000000..497309d --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/EmailTooLong.php @@ -0,0 +1,15 @@ +message = 'Email is too long, exceeds ' . EmailParser::EMAIL_MAX_LENGTH; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/IPV6BadChar.php b/vendor/egulias/email-validator/src/Warning/IPV6BadChar.php new file mode 100755 index 0000000..ba2fcc0 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/IPV6BadChar.php @@ -0,0 +1,14 @@ +message = 'Bad char in IPV6 domain literal'; + $this->rfcNumber = 5322; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/IPV6ColonEnd.php b/vendor/egulias/email-validator/src/Warning/IPV6ColonEnd.php new file mode 100755 index 0000000..41afa78 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/IPV6ColonEnd.php @@ -0,0 +1,14 @@ +message = ':: found at the end of the domain literal'; + $this->rfcNumber = 5322; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/IPV6ColonStart.php b/vendor/egulias/email-validator/src/Warning/IPV6ColonStart.php new file mode 100755 index 0000000..1bf754e --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/IPV6ColonStart.php @@ -0,0 +1,14 @@ +message = ':: found at the start of the domain literal'; + $this->rfcNumber = 5322; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/IPV6Deprecated.php b/vendor/egulias/email-validator/src/Warning/IPV6Deprecated.php new file mode 100755 index 0000000..d752caa --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/IPV6Deprecated.php @@ -0,0 +1,14 @@ +message = 'Deprecated form of IPV6'; + $this->rfcNumber = 5321; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/IPV6DoubleColon.php b/vendor/egulias/email-validator/src/Warning/IPV6DoubleColon.php new file mode 100755 index 0000000..4f82394 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/IPV6DoubleColon.php @@ -0,0 +1,14 @@ +message = 'Double colon found after IPV6 tag'; + $this->rfcNumber = 5322; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/IPV6GroupCount.php b/vendor/egulias/email-validator/src/Warning/IPV6GroupCount.php new file mode 100755 index 0000000..a59d317 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/IPV6GroupCount.php @@ -0,0 +1,14 @@ +message = 'Group count is not IPV6 valid'; + $this->rfcNumber = 5322; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/IPV6MaxGroups.php b/vendor/egulias/email-validator/src/Warning/IPV6MaxGroups.php new file mode 100755 index 0000000..936274c --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/IPV6MaxGroups.php @@ -0,0 +1,14 @@ +message = 'Reached the maximum number of IPV6 groups allowed'; + $this->rfcNumber = 5321; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/LabelTooLong.php b/vendor/egulias/email-validator/src/Warning/LabelTooLong.php new file mode 100755 index 0000000..daf07f4 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/LabelTooLong.php @@ -0,0 +1,14 @@ +message = 'Label too long'; + $this->rfcNumber = 5322; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/LocalTooLong.php b/vendor/egulias/email-validator/src/Warning/LocalTooLong.php new file mode 100755 index 0000000..0d08d8b --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/LocalTooLong.php @@ -0,0 +1,15 @@ +message = 'Local part is too long, exceeds 64 chars (octets)'; + $this->rfcNumber = 5322; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/NoDNSMXRecord.php b/vendor/egulias/email-validator/src/Warning/NoDNSMXRecord.php new file mode 100755 index 0000000..b3c21a1 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/NoDNSMXRecord.php @@ -0,0 +1,14 @@ +message = 'No MX DSN record was found for this email'; + $this->rfcNumber = 5321; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/ObsoleteDTEXT.php b/vendor/egulias/email-validator/src/Warning/ObsoleteDTEXT.php new file mode 100755 index 0000000..10f19e3 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/ObsoleteDTEXT.php @@ -0,0 +1,14 @@ +rfcNumber = 5322; + $this->message = 'Obsolete DTEXT in domain literal'; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/QuotedPart.php b/vendor/egulias/email-validator/src/Warning/QuotedPart.php new file mode 100755 index 0000000..36a4265 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/QuotedPart.php @@ -0,0 +1,17 @@ +message = "Deprecated Quoted String found between $prevToken and $postToken"; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/QuotedString.php b/vendor/egulias/email-validator/src/Warning/QuotedString.php new file mode 100755 index 0000000..817e4e8 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/QuotedString.php @@ -0,0 +1,17 @@ +message = "Quoted String found between $prevToken and $postToken"; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/TLD.php b/vendor/egulias/email-validator/src/Warning/TLD.php new file mode 100755 index 0000000..2338b9f --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/TLD.php @@ -0,0 +1,13 @@ +message = "RFC5321, TLD"; + } +} diff --git a/vendor/egulias/email-validator/src/Warning/Warning.php b/vendor/egulias/email-validator/src/Warning/Warning.php new file mode 100755 index 0000000..a2ee7b0 --- /dev/null +++ b/vendor/egulias/email-validator/src/Warning/Warning.php @@ -0,0 +1,47 @@ +message; + } + + /** + * @return int + */ + public function code() + { + return static::CODE; + } + + /** + * @return int + */ + public function RFCNumber() + { + return $this->rfcNumber; + } + + public function __toString() + { + return $this->message() . " rfc: " . $this->rfcNumber . "interal code: " . static::CODE; + } +} diff --git a/vendor/facade/flare-client-php/.php-cs-fixer.cache b/vendor/facade/flare-client-php/.php-cs-fixer.cache new file mode 100755 index 0000000..d771a1b --- /dev/null +++ b/vendor/facade/flare-client-php/.php-cs-fixer.cache @@ -0,0 +1 @@ +{"php":"8.0.10","version":"3.1.0","indent":" ","lineEnding":"\n","rules":{"blank_line_after_opening_tag":true,"braces":{"allow_single_line_anonymous_class_with_empty_body":true},"compact_nullable_typehint":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"new_with_braces":true,"no_blank_lines_after_class_opening":true,"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"sort_algorithm":"alpha"},"return_type_declaration":true,"short_scalar_cast":true,"single_blank_line_before_namespace":true,"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"visibility_required":true,"blank_line_after_namespace":true,"class_definition":true,"constant_case":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"on_multiline":"ensure_fully_multiline","keep_multiple_spaces_after_comma":true},"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true,"array_syntax":{"syntax":"short"},"no_unused_imports":true,"not_operator_with_successor_space":true,"trailing_comma_in_multiline":true,"phpdoc_scalar":true,"unary_operator_spaces":true,"binary_operator_spaces":true,"blank_line_before_statement":{"statements":["break","continue","declare","return","throw","try"]},"phpdoc_single_line_var_spacing":true,"phpdoc_var_without_name":true,"class_attributes_separation":{"elements":{"method":"one"}}},"hashes":{"src\/Middleware\/AddGlows.php":2757630618,"src\/Middleware\/AnonymizeIp.php":2582237091,"src\/Middleware\/CensorRequestBodyFields.php":3157018559,"src\/Time\/Time.php":3063453905,"src\/Time\/SystemTime.php":1875330795,"src\/Solutions\/ReportSolution.php":1414311092,"src\/View.php":1758466251,"src\/Enums\/GroupingTypes.php":794823242,"src\/Enums\/MessageLevels.php":2252993314,"src\/Glows\/Glow.php":2938926460,"src\/Glows\/Recorder.php":741799100,"src\/Stacktrace\/Codesnippet.php":1758681831,"src\/Stacktrace\/File.php":2191220409,"src\/Stacktrace\/Stacktrace.php":3487330919,"src\/Stacktrace\/Frame.php":2201806026,"src\/Truncation\/ReportTrimmer.php":1411772441,"src\/Truncation\/TrimStringsStrategy.php":1149918480,"src\/Truncation\/TrimContextItemsStrategy.php":2488083767,"src\/Truncation\/TruncationStrategy.php":2876512000,"src\/Truncation\/AbstractTruncationStrategy.php":3738899546,"src\/Flare.php":615945847,"src\/Http\/Response.php":3175166434,"src\/Http\/Exceptions\/BadResponse.php":2136825932,"src\/Http\/Exceptions\/MissingParameter.php":3963873571,"src\/Http\/Exceptions\/NotFound.php":605045793,"src\/Http\/Exceptions\/BadResponseCode.php":3629899270,"src\/Http\/Exceptions\/InvalidData.php":4224780353,"src\/Http\/Client.php":3513047095,"src\/Contracts\/ProvidesFlareContext.php":3654647562,"src\/Report.php":677962539,"src\/helpers.php":878229930,"src\/Api.php":4147640268,"src\/Concerns\/UsesTime.php":2203258051,"src\/Concerns\/HasContext.php":2283577173,"src\/Context\/ContextContextDetector.php":1433590813,"src\/Context\/ConsoleContext.php":2891436865,"src\/Context\/ContextInterface.php":3556428806,"src\/Context\/RequestContext.php":916577092,"src\/Context\/ContextDetectorInterface.php":3409530978,"src\/Frame.php":1560844999,"tests\/TestClasses\/ExceptionWithContext.php":3729019575,"tests\/TestClasses\/Assert.php":151773303,"tests\/TestClasses\/DumpDriver.php":3041182929,"tests\/TestClasses\/CodeSnippetDriver.php":615657858,"tests\/TestClasses\/FakeTime.php":2977551027,"tests\/TestClasses\/ReportDriver.php":3461657491,"tests\/FlareTest.php":2320308878,"tests\/Glows\/RecorderTest.php":946753721,"tests\/Stacktrace\/FileTest.php":420603250,"tests\/Stacktrace\/__snapshots__\/StrackTraceTest__it_can_detect_application_frames__1.php":167790125,"tests\/Stacktrace\/CodesnippetTest.php":765068665,"tests\/Stacktrace\/CodeSnippetDriver.php":4244799073,"tests\/Stacktrace\/ThrowAndReturnExceptionAction.php":4198281204,"tests\/Stacktrace\/StrackTraceTest.php":757065022,"tests\/Truncation\/TrimContextItemsStrategyTest.php":112441598,"tests\/Truncation\/TrimStringsStrategyTest.php":2187306892,"tests\/TestCase.php":996592721,"tests\/Concerns\/MatchesCodeSnippetSnapshots.php":685279681,"tests\/Concerns\/MatchesDumpSnapshots.php":3419801558,"tests\/Concerns\/MatchesReportSnapshots.php":2362276842,"tests\/Mocks\/FakeClient.php":1694586070,"tests\/ReportTest.php":1195087882,"tests\/Context\/ConsoleContextTest.php":3637467343,"tests\/Context\/RequestContextTest.php":1346110003}} \ No newline at end of file diff --git a/vendor/facade/flare-client-php/.php-cs-fixer.php b/vendor/facade/flare-client-php/.php-cs-fixer.php new file mode 100755 index 0000000..b410d78 --- /dev/null +++ b/vendor/facade/flare-client-php/.php-cs-fixer.php @@ -0,0 +1,44 @@ +notPath('bootstrap/*') + ->notPath('storage/*') + ->notPath('resources/view/mail/*') + ->in([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]) + ->name('*.php') + ->notName('*.blade.php') + ->notName('GitConflictController.php') + ->ignoreDotFiles(true) + ->ignoreVCS(true); + +return (new PhpCsFixer\Config()) + ->setRules([ + '@PSR12' => true, + 'array_syntax' => ['syntax' => 'short'], + 'ordered_imports' => ['sort_algorithm' => 'alpha'], + 'no_unused_imports' => true, + 'not_operator_with_successor_space' => true, + 'trailing_comma_in_multiline' => true, + 'phpdoc_scalar' => true, + 'unary_operator_spaces' => true, + 'binary_operator_spaces' => true, + 'blank_line_before_statement' => [ + 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], + ], + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_var_without_name' => true, + 'class_attributes_separation' => [ + 'elements' => [ + 'method' => 'one', + ], + ], + 'method_argument_space' => [ + 'on_multiline' => 'ensure_fully_multiline', + 'keep_multiple_spaces_after_comma' => true, + ], + 'single_trait_insert_per_statement' => true, + ]) + ->setFinder($finder); diff --git a/vendor/facade/flare-client-php/CHANGELOG.md b/vendor/facade/flare-client-php/CHANGELOG.md new file mode 100755 index 0000000..c30fd2e --- /dev/null +++ b/vendor/facade/flare-client-php/CHANGELOG.md @@ -0,0 +1,114 @@ +# Changelog + +All notable changes to `flare-client-php` will be documented in this file + +## 1.9.1 - 2021-09-13 + +- let `report` return the created report + +## 1.9.0 - 2021-09-13 + +- add report tracking uuid + +## 1.8.1 - 2021-05-31 + +- improve compatibility with Symfony 5.3 + +## 1.8.0 - 2021-04-30 + +- add ability to ignore errors and exceptions (#23) +- fix curl parameters + +## 1.7.0 - 2021-04-12 + +- use new Flare endpoint and allow 1 redirect to it + +## 1.6.1 - 2021-04-08 + +- make `censorRequestBodyFields` chainable + +## 1.6.0 - 2021-04-08 + +- add ability to censor request body fields (#18) + +## 1.5.0 - 2021-03-31 + +- add `determineVersionUsing` + +## 1.4.0 - 2021-02-16 + +- remove custom grouping + +## 1.3.7 - 2020-10-21 + +- allow PHP 8 + +## 1.3.6 - 2020-09-18 + +- remove `larapack/dd` (#15) + +## 1.3.5 - 2020-08-26 + +- allow Laravel 8 (#13) + +## 1.3.4 - 2020-07-14 + +- use directory separator constant + +## 1.3.3 - 2020-07-14 + +- fix tests by requiring symfony/mime +- display real exception class for view errors (see https://github.com/facade/ignition/discussions/237) + +## 1.3.2 - 2020-03-02 + +- allow L7 + +## 1.3.1 - 2019-12-15 + +- allow var-dumper v5.0 + +## 1.3.0 - 2019-11-27 + +- Allow custom grouping types + +## 1.2.1 - 2019-11-19 + +- Let `registerFlareHandlers` return $this + +## 1.2.0 - 2019-11-19 + +- Add `registerFlareHandlers` method to register error and exception handlers in non-Laravel applications +- Fix get requests with query parameters (#4) + +## 1.1.2 - 2019-11-08 + +- Ignore invalid mime type detection issues + +## 1.1.1 - 2019-10-07 + +- Wrap filesize detection in try-catch block + +## 1.1.0 - 2019-09-27 + +- Add ability to log messages + +## 1.0.4 - 2019-09-11 + +- Fixes an issue when sending exceptions inside a queue worker + +## 1.0.3 - 2019-09-05 + +- Ensure valid session data + +## 1.0.2 - 2019-09-05 + +- Fix error when uploading multiple files using an array name + +## 1.0.1 - 2019-09-02 + +- Fix issue with uploaded files in request context + +## 1.0.0 - 2019-08-30 + +- initial release diff --git a/vendor/facade/flare-client-php/LICENSE.md b/vendor/facade/flare-client-php/LICENSE.md new file mode 100755 index 0000000..48c30e4 --- /dev/null +++ b/vendor/facade/flare-client-php/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Facade + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/facade/flare-client-php/README.md b/vendor/facade/flare-client-php/README.md new file mode 100755 index 0000000..1a9c216 --- /dev/null +++ b/vendor/facade/flare-client-php/README.md @@ -0,0 +1,36 @@ +# Send PHP errors to Flare + +[![Latest Version on Packagist](https://img.shields.io/packagist/v/facade/flare-client-php.svg?style=flat-square)](https://packagist.org/packages/facade/flare-client-php) +![Tests](https://github.com/facade/flare-client-php/workflows/Run%20tests/badge.svg) +[![Total Downloads](https://img.shields.io/packagist/dt/facade/flare-client-php.svg?style=flat-square)](https://packagist.org/packages/facade/flare-client-php) + +This repository contains a PHP client to send PHP errors to [Flare](https://flareapp.io). + +![Screenshot of error in Flare](https://facade.github.io/flare-client-php/screenshot.png) + +## Documentation + +You can find the documentation of this package at [the docs of Flare](https://flareapp.io/docs/general/projects). + +## Changelog + +Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. + +## Testing + +``` bash +composer test +``` + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## Security + +If you discover any security related issues, please email support@flareapp.io instead of using the issue tracker. + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. + diff --git a/vendor/facade/flare-client-php/composer.json b/vendor/facade/flare-client-php/composer.json new file mode 100755 index 0000000..00729fb --- /dev/null +++ b/vendor/facade/flare-client-php/composer.json @@ -0,0 +1,52 @@ +{ + "name": "facade/flare-client-php", + "description": "Send PHP errors to Flare", + "keywords": [ + "facade", + "flare", + "exception", + "reporting" + ], + "homepage": "https://github.com/facade/flare-client-php", + "license": "MIT", + "require": { + "php": "^7.1|^8.0", + "facade/ignition-contracts": "~1.0", + "illuminate/pipeline": "^5.5|^6.0|^7.0|^8.0", + "symfony/http-foundation": "^3.3|^4.1|^5.0", + "symfony/mime": "^3.4|^4.0|^5.1", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "spatie/phpunit-snapshot-assertions": "^2.0", + "phpunit/phpunit": "^7.5.16" + }, + "autoload": { + "psr-4": { + "Facade\\FlareClient\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "autoload-dev": { + "psr-4": { + "Facade\\FlareClient\\Tests\\": "tests" + } + }, + "scripts": { + "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes", + "test": "vendor/bin/phpunit", + "test-coverage": "vendor/bin/phpunit --coverage-html coverage" + + }, + "config": { + "sort-packages": true + }, + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + } +} diff --git a/vendor/facade/flare-client-php/src/Api.php b/vendor/facade/flare-client-php/src/Api.php new file mode 100755 index 0000000..d5fc906 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Api.php @@ -0,0 +1,77 @@ +client = $client; + + register_shutdown_function([$this, 'sendQueuedReports']); + } + + public static function sendReportsInBatches(bool $batchSending = true) + { + static::$sendInBatches = $batchSending; + } + + public function report(Report $report) + { + try { + if (static::$sendInBatches) { + $this->addReportToQueue($report); + } else { + $this->sendReportToApi($report); + } + } catch (Exception $e) { + // + } + } + + public function sendTestReport(Report $report) + { + $this->sendReportToApi($report); + } + + protected function addReportToQueue(Report $report) + { + $this->queue[] = $report; + } + + public function sendQueuedReports() + { + try { + foreach ($this->queue as $report) { + $this->sendReportToApi($report); + } + } catch (Exception $e) { + // + } finally { + $this->queue = []; + } + } + + protected function sendReportToApi(Report $report) + { + $this->client->post('reports', $this->truncateReport($report->toArray())); + } + + protected function truncateReport(array $payload): array + { + return (new ReportTrimmer())->trim($payload); + } +} diff --git a/vendor/facade/flare-client-php/src/Concerns/HasContext.php b/vendor/facade/flare-client-php/src/Concerns/HasContext.php new file mode 100755 index 0000000..2fb6a6d --- /dev/null +++ b/vendor/facade/flare-client-php/src/Concerns/HasContext.php @@ -0,0 +1,51 @@ +stage = $stage; + + return $this; + } + + public function messageLevel(?string $messageLevel) + { + $this->messageLevel = $messageLevel; + + return $this; + } + + public function getGroup(string $groupName = 'context', $default = []): array + { + return $this->userProvidedContext[$groupName] ?? $default; + } + + public function context($key, $value) + { + return $this->group('context', [$key => $value]); + } + + public function group(string $groupName, array $properties) + { + $group = $this->userProvidedContext[$groupName] ?? []; + + $this->userProvidedContext[$groupName] = array_merge_recursive_distinct( + $group, + $properties + ); + + return $this; + } +} diff --git a/vendor/facade/flare-client-php/src/Concerns/UsesTime.php b/vendor/facade/flare-client-php/src/Concerns/UsesTime.php new file mode 100755 index 0000000..5414409 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Concerns/UsesTime.php @@ -0,0 +1,24 @@ +getCurrentTime(); + } +} diff --git a/vendor/facade/flare-client-php/src/Context/ConsoleContext.php b/vendor/facade/flare-client-php/src/Context/ConsoleContext.php new file mode 100755 index 0000000..da87122 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Context/ConsoleContext.php @@ -0,0 +1,21 @@ +arguments = $arguments; + } + + public function toArray(): array + { + return [ + 'arguments' => $this->arguments, + ]; + } +} diff --git a/vendor/facade/flare-client-php/src/Context/ContextContextDetector.php b/vendor/facade/flare-client-php/src/Context/ContextContextDetector.php new file mode 100755 index 0000000..e73a78e --- /dev/null +++ b/vendor/facade/flare-client-php/src/Context/ContextContextDetector.php @@ -0,0 +1,28 @@ +runningInConsole()) { + return new ConsoleContext($_SERVER['argv'] ?? []); + } + + return new RequestContext(); + } + + private function runningInConsole(): bool + { + if (isset($_ENV['APP_RUNNING_IN_CONSOLE'])) { + return $_ENV['APP_RUNNING_IN_CONSOLE'] === 'true'; + } + + if (isset($_ENV['FLARE_FAKE_WEB_REQUEST'])) { + return false; + } + + return in_array(php_sapi_name(), ['cli', 'phpdb']); + } +} diff --git a/vendor/facade/flare-client-php/src/Context/ContextDetectorInterface.php b/vendor/facade/flare-client-php/src/Context/ContextDetectorInterface.php new file mode 100755 index 0000000..b02ed8e --- /dev/null +++ b/vendor/facade/flare-client-php/src/Context/ContextDetectorInterface.php @@ -0,0 +1,8 @@ +request = $request ?? Request::createFromGlobals(); + } + + public function getRequest(): array + { + return [ + 'url' => $this->request->getUri(), + 'ip' => $this->request->getClientIp(), + 'method' => $this->request->getMethod(), + 'useragent' => $this->request->headers->get('User-Agent'), + ]; + } + + private function getFiles(): array + { + if (is_null($this->request->files)) { + return []; + } + + return $this->mapFiles($this->request->files->all()); + } + + protected function mapFiles(array $files) + { + return array_map(function ($file) { + if (is_array($file)) { + return $this->mapFiles($file); + } + + if (! $file instanceof UploadedFile) { + return; + } + + try { + $fileSize = $file->getSize(); + } catch (\RuntimeException $e) { + $fileSize = 0; + } + + try { + $mimeType = $file->getMimeType(); + } catch (InvalidArgumentException $e) { + $mimeType = 'undefined'; + } + + return [ + 'pathname' => $file->getPathname(), + 'size' => $fileSize, + 'mimeType' => $mimeType, + ]; + }, $files); + } + + public function getSession(): array + { + try { + $session = $this->request->getSession(); + } catch (\Exception $exception) { + $session = []; + } + + return $session ? $this->getValidSessionData($session) : []; + } + + /** + * @param SessionInterface $session + * @return array + */ + protected function getValidSessionData($session): array + { + try { + json_encode($session->all()); + } catch (Throwable $e) { + return []; + } + + return $session->all(); + } + + public function getCookies(): array + { + return $this->request->cookies->all(); + } + + public function getHeaders(): array + { + return $this->request->headers->all(); + } + + public function getRequestData(): array + { + return [ + 'queryString' => $this->request->query->all(), + 'body' => $this->request->request->all(), + 'files' => $this->getFiles(), + ]; + } + + public function toArray(): array + { + return [ + 'request' => $this->getRequest(), + 'request_data' => $this->getRequestData(), + 'headers' => $this->getHeaders(), + 'cookies' => $this->getCookies(), + 'session' => $this->getSession(), + ]; + } +} diff --git a/vendor/facade/flare-client-php/src/Contracts/ProvidesFlareContext.php b/vendor/facade/flare-client-php/src/Contracts/ProvidesFlareContext.php new file mode 100755 index 0000000..f3b7faa --- /dev/null +++ b/vendor/facade/flare-client-php/src/Contracts/ProvidesFlareContext.php @@ -0,0 +1,8 @@ +determineVersionCallable = $determineVersionCallable; + } + + public function reportErrorLevels(int $reportErrorLevels) + { + $this->reportErrorLevels = $reportErrorLevels; + } + + public function filterExceptionsUsing(callable $filterExceptionsCallable) + { + $this->filterExceptionsCallable = $filterExceptionsCallable; + } + + /** + * @return null|string + */ + public function version() + { + if (! $this->determineVersionCallable) { + return null; + } + + return ($this->determineVersionCallable)(); + } + + public function __construct(Client $client, ContextDetectorInterface $contextDetector = null, Container $container = null, array $middleware = []) + { + $this->client = $client; + $this->recorder = new Recorder(); + $this->contextDetector = $contextDetector ?? new ContextContextDetector(); + $this->container = $container; + $this->middleware = $middleware; + $this->api = new Api($this->client); + + $this->registerDefaultMiddleware(); + } + + public function getMiddleware(): array + { + return $this->middleware; + } + + public function registerFlareHandlers() + { + $this->registerExceptionHandler(); + $this->registerErrorHandler(); + + return $this; + } + + public function registerExceptionHandler() + { + $this->previousExceptionHandler = set_exception_handler([$this, 'handleException']); + + return $this; + } + + public function registerErrorHandler() + { + $this->previousErrorHandler = set_error_handler([$this, 'handleError']); + + return $this; + } + + private function registerDefaultMiddleware() + { + return $this->registerMiddleware(new AddGlows($this->recorder)); + } + + public function registerMiddleware($callable) + { + $this->middleware[] = $callable; + + return $this; + } + + public function getMiddlewares(): array + { + return $this->middleware; + } + + public function glow( + string $name, + string $messageLevel = MessageLevels::INFO, + array $metaData = [] + ) { + $this->recorder->record(new Glow($name, $messageLevel, $metaData)); + } + + public function handleException(Throwable $throwable) + { + $this->report($throwable); + + if ($this->previousExceptionHandler) { + call_user_func($this->previousExceptionHandler, $throwable); + } + } + + public function handleError($code, $message, $file = '', $line = 0) + { + $exception = new ErrorException($message, 0, $code, $file, $line); + + $this->report($exception); + + if ($this->previousErrorHandler) { + return call_user_func( + $this->previousErrorHandler, + $message, + $code, + $file, + $line + ); + } + } + + public function applicationPath(string $applicationPath) + { + $this->applicationPath = $applicationPath; + + return $this; + } + + public function report(Throwable $throwable, callable $callback = null): ?Report + { + if (! $this->shouldSendReport($throwable)) { + return null; + } + + $report = $this->createReport($throwable); + + if (! is_null($callback)) { + call_user_func($callback, $report); + } + + $this->sendReportToApi($report); + + return $report; + } + + protected function shouldSendReport(Throwable $throwable): bool + { + if ($this->reportErrorLevels && $throwable instanceof Error) { + return $this->reportErrorLevels & $throwable->getCode(); + } + + if ($this->reportErrorLevels && $throwable instanceof ErrorException) { + return $this->reportErrorLevels & $throwable->getSeverity(); + } + + if ($this->filterExceptionsCallable && $throwable instanceof Exception) { + return call_user_func($this->filterExceptionsCallable, $throwable); + } + + return true; + } + + public function reportMessage(string $message, string $logLevel, callable $callback = null) + { + $report = $this->createReportFromMessage($message, $logLevel); + + if (! is_null($callback)) { + call_user_func($callback, $report); + } + + $this->sendReportToApi($report); + } + + public function sendTestReport(Throwable $throwable) + { + $this->api->sendTestReport($this->createReport($throwable)); + } + + private function sendReportToApi(Report $report) + { + try { + $this->api->report($report); + } catch (Exception $exception) { + } + } + + public function reset() + { + $this->api->sendQueuedReports(); + + $this->userProvidedContext = []; + $this->recorder->reset(); + } + + private function applyAdditionalParameters(Report $report) + { + $report + ->stage($this->stage) + ->messageLevel($this->messageLevel) + ->setApplicationPath($this->applicationPath) + ->userProvidedContext($this->userProvidedContext); + } + + public function anonymizeIp() + { + $this->registerMiddleware(new AnonymizeIp()); + + return $this; + } + + public function censorRequestBodyFields(array $fieldNames) + { + $this->registerMiddleware(new CensorRequestBodyFields($fieldNames)); + + return $this; + } + + public function createReport(Throwable $throwable): Report + { + $report = Report::createForThrowable( + $throwable, + $this->contextDetector->detectCurrentContext(), + $this->applicationPath, + $this->version() + ); + + return $this->applyMiddlewareToReport($report); + } + + public function createReportFromMessage(string $message, string $logLevel): Report + { + $report = Report::createForMessage( + $message, + $logLevel, + $this->contextDetector->detectCurrentContext(), + $this->applicationPath + ); + + return $this->applyMiddlewareToReport($report); + } + + protected function applyMiddlewareToReport(Report $report): Report + { + $this->applyAdditionalParameters($report); + + $report = (new Pipeline($this->container)) + ->send($report) + ->through($this->middleware) + ->then(function ($report) { + return $report; + }); + + return $report; + } +} diff --git a/vendor/facade/flare-client-php/src/Frame.php b/vendor/facade/flare-client-php/src/Frame.php new file mode 100755 index 0000000..9e58dea --- /dev/null +++ b/vendor/facade/flare-client-php/src/Frame.php @@ -0,0 +1,66 @@ +file = $file; + + $this->lineNumber = $lineNumber; + + $this->method = $method; + + $this->class = $class; + } + + public function toArray(): array + { + $codeSnippet = (new Codesnippet()) + ->snippetLineCount(9) + ->surroundingLine($this->lineNumber) + ->get($this->file); + + return [ + 'line_number' => $this->lineNumber, + 'method' => $this->getFullMethod(), + 'code_snippet' => $codeSnippet, + 'file' => $this->file, + ]; + } + + private function getFullMethod(): string + { + $method = $this->method; + + if ($class = $this->class ?? false) { + $method = "{$class}::{$method}"; + } + + return $method; + } + + public function getFile(): string + { + return $this->file; + } +} diff --git a/vendor/facade/flare-client-php/src/Glows/Glow.php b/vendor/facade/flare-client-php/src/Glows/Glow.php new file mode 100755 index 0000000..5f649e9 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Glows/Glow.php @@ -0,0 +1,42 @@ +name = $name; + $this->messageLevel = $messageLevel; + $this->metaData = $metaData; + $this->microtime = $microtime ?? microtime(true); + } + + public function toArray() + { + return [ + 'time' => $this->getCurrentTime(), + 'name' => $this->name, + 'message_level' => $this->messageLevel, + 'meta_data' => $this->metaData, + 'microtime' => $this->microtime, + ]; + } +} diff --git a/vendor/facade/flare-client-php/src/Glows/Recorder.php b/vendor/facade/flare-client-php/src/Glows/Recorder.php new file mode 100755 index 0000000..4a01784 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Glows/Recorder.php @@ -0,0 +1,27 @@ +glows[] = $glow; + + $this->glows = array_slice($this->glows, static::GLOW_LIMIT * -1, static::GLOW_LIMIT); + } + + public function glows(): array + { + return $this->glows; + } + + public function reset() + { + $this->glows = []; + } +} diff --git a/vendor/facade/flare-client-php/src/Http/Client.php b/vendor/facade/flare-client-php/src/Http/Client.php new file mode 100755 index 0000000..91366ca --- /dev/null +++ b/vendor/facade/flare-client-php/src/Http/Client.php @@ -0,0 +1,217 @@ +apiToken = $apiToken; + + $this->apiSecret = $apiSecret; + + if (! $baseUrl) { + throw MissingParameter::create('baseUrl'); + } + + $this->baseUrl = $baseUrl; + + if (! $timeout) { + throw MissingParameter::create('timeout'); + } + + $this->timeout = $timeout; + } + + /** + * @param string $url + * @param array $arguments + * + * @return array|false + */ + public function get(string $url, array $arguments = []) + { + return $this->makeRequest('get', $url, $arguments); + } + + /** + * @param string $url + * @param array $arguments + * + * @return array|false + */ + public function post(string $url, array $arguments = []) + { + return $this->makeRequest('post', $url, $arguments); + } + + /** + * @param string $url + * @param array $arguments + * + * @return array|false + */ + public function patch(string $url, array $arguments = []) + { + return $this->makeRequest('patch', $url, $arguments); + } + + /** + * @param string $url + * @param array $arguments + * + * @return array|false + */ + public function put(string $url, array $arguments = []) + { + return $this->makeRequest('put', $url, $arguments); + } + + /** + * @param string $method + * @param array $arguments + * + * @return array|false + */ + public function delete(string $method, array $arguments = []) + { + return $this->makeRequest('delete', $method, $arguments); + } + + /** + * @param string $httpVerb + * @param string $url + * @param array $arguments + * + * @return array + */ + private function makeRequest(string $httpVerb, string $url, array $arguments = []) + { + $queryString = http_build_query([ + 'key' => $this->apiToken, + 'secret' => $this->apiSecret, + ]); + + $fullUrl = "{$this->baseUrl}/{$url}?{$queryString}"; + + $headers = [ + 'x-api-token: '.$this->apiToken, + ]; + + $response = $this->makeCurlRequest($httpVerb, $fullUrl, $headers, $arguments); + + if ($response->getHttpResponseCode() === 422) { + throw InvalidData::createForResponse($response); + } + + if ($response->getHttpResponseCode() === 404) { + throw NotFound::createForResponse($response); + } + + if ($response->getHttpResponseCode() !== 200 && $response->getHttpResponseCode() !== 204) { + throw BadResponseCode::createForResponse($response); + } + + return $response->getBody(); + } + + public function makeCurlRequest(string $httpVerb, string $fullUrl, array $headers = [], array $arguments = []): Response + { + $curlHandle = $this->getCurlHandle($fullUrl, $headers); + + switch ($httpVerb) { + case 'post': + curl_setopt($curlHandle, CURLOPT_POST, true); + $this->attachRequestPayload($curlHandle, $arguments); + + break; + + case 'get': + curl_setopt($curlHandle, CURLOPT_URL, $fullUrl.'&'.http_build_query($arguments)); + + break; + + case 'delete': + curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'DELETE'); + + break; + + case 'patch': + curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'PATCH'); + $this->attachRequestPayload($curlHandle, $arguments); + + break; + + case 'put': + curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'PUT'); + $this->attachRequestPayload($curlHandle, $arguments); + + break; + } + + $body = json_decode(curl_exec($curlHandle), true); + $headers = curl_getinfo($curlHandle); + $error = curl_error($curlHandle); + + return new Response($headers, $body, $error); + } + + private function attachRequestPayload(&$curlHandle, array $data) + { + $encoded = json_encode($data); + + $this->lastRequest['body'] = $encoded; + curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $encoded); + } + + /** + * @param string $fullUrl + * @param array $headers + * + * @return resource + */ + private function getCurlHandle(string $fullUrl, array $headers = []) + { + $curlHandle = curl_init(); + + curl_setopt($curlHandle, CURLOPT_URL, $fullUrl); + + curl_setopt($curlHandle, CURLOPT_HTTPHEADER, array_merge([ + 'Accept: application/json', + 'Content-Type: application/json', + ], $headers)); + + curl_setopt($curlHandle, CURLOPT_USERAGENT, 'Laravel/Flare API 1.0'); + curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curlHandle, CURLOPT_TIMEOUT, $this->timeout); + curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($curlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_setopt($curlHandle, CURLOPT_ENCODING, ''); + curl_setopt($curlHandle, CURLINFO_HEADER_OUT, true); + curl_setopt($curlHandle, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curlHandle, CURLOPT_MAXREDIRS, 1); + + return $curlHandle; + } +} diff --git a/vendor/facade/flare-client-php/src/Http/Exceptions/BadResponse.php b/vendor/facade/flare-client-php/src/Http/Exceptions/BadResponse.php new file mode 100755 index 0000000..4962bdd --- /dev/null +++ b/vendor/facade/flare-client-php/src/Http/Exceptions/BadResponse.php @@ -0,0 +1,21 @@ +getError()}"); + + $exception->response = $response; + + return $exception; + } +} diff --git a/vendor/facade/flare-client-php/src/Http/Exceptions/BadResponseCode.php b/vendor/facade/flare-client-php/src/Http/Exceptions/BadResponseCode.php new file mode 100755 index 0000000..6e1e4c5 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Http/Exceptions/BadResponseCode.php @@ -0,0 +1,33 @@ +response = $response; + + $bodyErrors = isset($response->getBody()['errors']) ? $response->getBody()['errors'] : []; + + $exception->errors = $bodyErrors; + + return $exception; + } + + public static function getMessageForResponse(Response $response) + { + return "Response code {$response->getHttpResponseCode()} returned"; + } +} diff --git a/vendor/facade/flare-client-php/src/Http/Exceptions/InvalidData.php b/vendor/facade/flare-client-php/src/Http/Exceptions/InvalidData.php new file mode 100755 index 0000000..73ae1ac --- /dev/null +++ b/vendor/facade/flare-client-php/src/Http/Exceptions/InvalidData.php @@ -0,0 +1,13 @@ +headers = $headers; + + $this->body = $body; + + $this->error = $error; + } + + /** + * @return mixed + */ + public function getHeaders() + { + return $this->headers; + } + + /** + * @return mixed + */ + public function getBody() + { + return $this->body; + } + + /** + * @return bool + */ + public function hasBody() + { + return $this->body != false; + } + + /** + * @return mixed + */ + public function getError() + { + return $this->error; + } + + /** + * @return null|int + */ + public function getHttpResponseCode() + { + if (! isset($this->headers['http_code'])) { + return; + } + + return (int) $this->headers['http_code']; + } +} diff --git a/vendor/facade/flare-client-php/src/Middleware/AddGlows.php b/vendor/facade/flare-client-php/src/Middleware/AddGlows.php new file mode 100755 index 0000000..ce47447 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Middleware/AddGlows.php @@ -0,0 +1,26 @@ +recorder = $recorder; + } + + public function handle(Report $report, $next) + { + foreach ($this->recorder->glows() as $glow) { + $report->addGlow($glow); + } + + return $next($report); + } +} diff --git a/vendor/facade/flare-client-php/src/Middleware/AnonymizeIp.php b/vendor/facade/flare-client-php/src/Middleware/AnonymizeIp.php new file mode 100755 index 0000000..2df3598 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Middleware/AnonymizeIp.php @@ -0,0 +1,19 @@ +allContext(); + + $context['request']['ip'] = null; + + $report->userProvidedContext($context); + + return $next($report); + } +} diff --git a/vendor/facade/flare-client-php/src/Middleware/CensorRequestBodyFields.php b/vendor/facade/flare-client-php/src/Middleware/CensorRequestBodyFields.php new file mode 100755 index 0000000..39aba40 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Middleware/CensorRequestBodyFields.php @@ -0,0 +1,30 @@ +fieldNames = $fieldNames; + } + + public function handle(Report $report, $next) + { + $context = $report->allContext(); + + foreach ($this->fieldNames as $fieldName) { + if (isset($context['request_data']['body'][$fieldName])) { + $context['request_data']['body'][$fieldName] = ''; + } + } + + $report->userProvidedContext($context); + + return $next($report); + } +} diff --git a/vendor/facade/flare-client-php/src/Report.php b/vendor/facade/flare-client-php/src/Report.php new file mode 100755 index 0000000..44c931a --- /dev/null +++ b/vendor/facade/flare-client-php/src/Report.php @@ -0,0 +1,335 @@ +setApplicationPath($applicationPath) + ->throwable($throwable) + ->useContext($context) + ->exceptionClass(self::getClassForThrowable($throwable)) + ->message($throwable->getMessage()) + ->stackTrace(Stacktrace::createForThrowable($throwable, $applicationPath)) + ->exceptionContext($throwable) + ->setApplicationVersion($version); + } + + protected static function getClassForThrowable(Throwable $throwable): string + { + if ($throwable instanceof \Facade\Ignition\Exceptions\ViewException) { + if ($previous = $throwable->getPrevious()) { + return get_class($previous); + } + } + + return get_class($throwable); + } + + public static function createForMessage(string $message, string $logLevel, ContextInterface $context, ?string $applicationPath = null): self + { + $stacktrace = Stacktrace::create($applicationPath); + + return (new static()) + ->setApplicationPath($applicationPath) + ->message($message) + ->useContext($context) + ->exceptionClass($logLevel) + ->stacktrace($stacktrace) + ->openFrameIndex($stacktrace->firstApplicationFrameIndex()); + } + + public function __construct() + { + $this->trackingUuid = self::$fakeTrackingUuid ?? $this->generateUuid(); + } + + public function trackingUuid(): string + { + return $this->trackingUuid; + } + + public function exceptionClass(string $exceptionClass) + { + $this->exceptionClass = $exceptionClass; + + return $this; + } + + public function getExceptionClass(): string + { + return $this->exceptionClass; + } + + public function throwable(Throwable $throwable) + { + $this->throwable = $throwable; + + return $this; + } + + public function getThrowable(): ?Throwable + { + return $this->throwable; + } + + public function message(string $message) + { + $this->message = $message; + + return $this; + } + + public function getMessage(): string + { + return $this->message; + } + + public function stacktrace(Stacktrace $stacktrace) + { + $this->stacktrace = $stacktrace; + + return $this; + } + + public function getStacktrace(): Stacktrace + { + return $this->stacktrace; + } + + public function notifierName(string $notifierName) + { + $this->notifierName = $notifierName; + + return $this; + } + + public function languageVersion(string $languageVersion) + { + $this->languageVersion = $languageVersion; + + return $this; + } + + public function frameworkVersion(string $frameworkVersion) + { + $this->frameworkVersion = $frameworkVersion; + + return $this; + } + + public function useContext(ContextInterface $request) + { + $this->context = $request; + + return $this; + } + + public function openFrameIndex(?int $index) + { + $this->openFrameIndex = $index; + + return $this; + } + + public function setApplicationPath(?string $applicationPath) + { + $this->applicationPath = $applicationPath; + + return $this; + } + + public function getApplicationPath(): ?string + { + return $this->applicationPath; + } + + public function setApplicationVersion(?string $applicationVersion) + { + $this->applicationVersion = $applicationVersion; + + return $this; + } + + public function getApplicationVersion(): ?string + { + return $this->applicationVersion; + } + + public function view(?View $view) + { + $this->view = $view; + + return $this; + } + + public function addGlow(Glow $glow) + { + $this->glows[] = $glow->toArray(); + + return $this; + } + + public function addSolution(Solution $solution) + { + $this->solutions[] = ReportSolution::fromSolution($solution)->toArray(); + + return $this; + } + + public function userProvidedContext(array $userProvidedContext) + { + $this->userProvidedContext = $userProvidedContext; + + return $this; + } + + /** @deprecated */ + public function groupByTopFrame() + { + $this->groupBy = GroupingTypes::TOP_FRAME; + + return $this; + } + + /** @deprecated */ + public function groupByException() + { + $this->groupBy = GroupingTypes::EXCEPTION; + + return $this; + } + + public function allContext(): array + { + $context = $this->context->toArray(); + + $context = array_merge_recursive_distinct($context, $this->exceptionContext); + + return array_merge_recursive_distinct($context, $this->userProvidedContext); + } + + private function exceptionContext(Throwable $throwable) + { + if ($throwable instanceof ProvidesFlareContext) { + $this->exceptionContext = $throwable->context(); + } + + return $this; + } + + public function toArray() + { + return [ + 'notifier' => $this->notifierName ?? 'Flare Client', + 'language' => 'PHP', + 'framework_version' => $this->frameworkVersion, + 'language_version' => $this->languageVersion ?? phpversion(), + 'exception_class' => $this->exceptionClass, + 'seen_at' => $this->getCurrentTime(), + 'message' => $this->message, + 'glows' => $this->glows, + 'solutions' => $this->solutions, + 'stacktrace' => $this->stacktrace->toArray(), + 'context' => $this->allContext(), + 'stage' => $this->stage, + 'message_level' => $this->messageLevel, + 'open_frame_index' => $this->openFrameIndex, + 'application_path' => $this->applicationPath, + 'application_version' => $this->applicationVersion, + 'tracking_uuid' => $this->trackingUuid, + ]; + } + + /* + * Found on https://stackoverflow.com/questions/2040240/php-function-to-generate-v4-uuid/15875555#15875555 + */ + private function generateUuid(): string + { + // Generate 16 bytes (128 bits) of random data or use the data passed into the function. + $data = $data ?? random_bytes(16); + assert(strlen($data) == 16); + + // Set version to 0100 + $data[6] = chr(ord($data[6]) & 0x0f | 0x40); + // Set bits 6-7 to 10 + $data[8] = chr(ord($data[8]) & 0x3f | 0x80); + + // Output the 36 character UUID. + return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); + } +} diff --git a/vendor/facade/flare-client-php/src/Solutions/ReportSolution.php b/vendor/facade/flare-client-php/src/Solutions/ReportSolution.php new file mode 100755 index 0000000..5437e2e --- /dev/null +++ b/vendor/facade/flare-client-php/src/Solutions/ReportSolution.php @@ -0,0 +1,36 @@ +solution = $solution; + } + + public static function fromSolution(SolutionContract $solution) + { + return new static($solution); + } + + public function toArray(): array + { + $isRunnable = ($this->solution instanceof RunnableSolution); + + return [ + 'class' => get_class($this->solution), + 'title' => $this->solution->getSolutionTitle(), + 'description' => $this->solution->getSolutionDescription(), + 'links' => $this->solution->getDocumentationLinks(), + 'action_description' => $isRunnable ? $this->solution->getSolutionActionDescription() : null, + 'is_runnable' => $isRunnable, + ]; + } +} diff --git a/vendor/facade/flare-client-php/src/Stacktrace/Codesnippet.php b/vendor/facade/flare-client-php/src/Stacktrace/Codesnippet.php new file mode 100755 index 0000000..81bfcba --- /dev/null +++ b/vendor/facade/flare-client-php/src/Stacktrace/Codesnippet.php @@ -0,0 +1,72 @@ +surroundingLine = $surroundingLine; + + return $this; + } + + public function snippetLineCount(int $snippetLineCount): self + { + $this->snippetLineCount = $snippetLineCount; + + return $this; + } + + public function get(string $fileName): array + { + if (! file_exists($fileName)) { + return []; + } + + try { + $file = new File($fileName); + + [$startLineNumber, $endLineNumber] = $this->getBounds($file->numberOfLines()); + + $code = []; + + $line = $file->getLine($startLineNumber); + + $currentLineNumber = $startLineNumber; + + while ($currentLineNumber <= $endLineNumber) { + $code[$currentLineNumber] = rtrim(substr($line, 0, 250)); + + $line = $file->getNextLine(); + $currentLineNumber++; + } + + return $code; + } catch (RuntimeException $exception) { + return []; + } + } + + private function getBounds($totalNumberOfLineInFile): array + { + $startLine = max($this->surroundingLine - floor($this->snippetLineCount / 2), 1); + + $endLine = $startLine + ($this->snippetLineCount - 1); + + if ($endLine > $totalNumberOfLineInFile) { + $endLine = $totalNumberOfLineInFile; + $startLine = max($endLine - ($this->snippetLineCount - 1), 1); + } + + return [$startLine, $endLine]; + } +} diff --git a/vendor/facade/flare-client-php/src/Stacktrace/File.php b/vendor/facade/flare-client-php/src/Stacktrace/File.php new file mode 100755 index 0000000..f8bc0ea --- /dev/null +++ b/vendor/facade/flare-client-php/src/Stacktrace/File.php @@ -0,0 +1,41 @@ +file = new SplFileObject($path); + } + + public function numberOfLines(): int + { + $this->file->seek(PHP_INT_MAX); + + return $this->file->key() + 1; + } + + public function getLine(int $lineNumber = null): string + { + if (is_null($lineNumber)) { + return $this->getNextLine(); + } + + $this->file->seek($lineNumber - 1); + + return $this->file->current(); + } + + public function getNextLine(): string + { + $this->file->next(); + + return $this->file->current(); + } +} diff --git a/vendor/facade/flare-client-php/src/Stacktrace/Frame.php b/vendor/facade/flare-client-php/src/Stacktrace/Frame.php new file mode 100755 index 0000000..04304b3 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Stacktrace/Frame.php @@ -0,0 +1,71 @@ +file = $file; + + $this->lineNumber = $lineNumber; + + $this->method = $method; + + $this->class = $class; + + $this->isApplicationFrame = $isApplicationFrame; + } + + public function toArray(): array + { + $codeSnippet = (new Codesnippet()) + ->snippetLineCount(31) + ->surroundingLine($this->lineNumber) + ->get($this->file); + + return [ + 'line_number' => $this->lineNumber, + 'method' => $this->method, + 'class' => $this->class, + 'code_snippet' => $codeSnippet, + 'file' => $this->file, + 'is_application_frame' => $this->isApplicationFrame, + ]; + } + + public function getFile(): string + { + return $this->file; + } + + public function getLinenumber(): int + { + return $this->lineNumber; + } + + public function isApplicationFrame() + { + return $this->isApplicationFrame; + } +} diff --git a/vendor/facade/flare-client-php/src/Stacktrace/Stacktrace.php b/vendor/facade/flare-client-php/src/Stacktrace/Stacktrace.php new file mode 100755 index 0000000..b029093 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Stacktrace/Stacktrace.php @@ -0,0 +1,126 @@ +getTrace(), $applicationPath, $throwable->getFile(), $throwable->getLine()); + } + + public static function create(?string $applicationPath = null): self + { + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS & ~DEBUG_BACKTRACE_PROVIDE_OBJECT); + + return new static($backtrace, $applicationPath); + } + + public function __construct(array $backtrace, ?string $applicationPath = null, string $topmostFile = null, string $topmostLine = null) + { + $this->applicationPath = $applicationPath; + + $currentFile = $topmostFile; + $currentLine = $topmostLine; + + foreach ($backtrace as $rawFrame) { + if (! $this->frameFromFlare($rawFrame) && ! $this->fileIgnored($currentFile)) { + $this->frames[] = new Frame( + $currentFile, + $currentLine, + $rawFrame['function'] ?? null, + $rawFrame['class'] ?? null, + $this->frameFileFromApplication($currentFile) + ); + } + + $currentFile = $rawFrame['file'] ?? 'unknown'; + $currentLine = $rawFrame['line'] ?? 0; + } + + $this->frames[] = new Frame( + $currentFile, + $currentLine, + '[top]' + ); + } + + protected function frameFromFlare(array $rawFrame): bool + { + return isset($rawFrame['class']) && strpos($rawFrame['class'], 'Facade\\FlareClient\\') === 0; + } + + protected function frameFileFromApplication(string $frameFilename): bool + { + $relativeFile = str_replace('\\', DIRECTORY_SEPARATOR, $frameFilename); + + if (! empty($this->applicationPath)) { + $relativeFile = array_reverse(explode($this->applicationPath ?? '', $frameFilename, 2))[0]; + } + + if (strpos($relativeFile, DIRECTORY_SEPARATOR . 'vendor') === 0) { + return false; + } + + return true; + } + + protected function fileIgnored(string $currentFile): bool + { + $currentFile = str_replace('\\', DIRECTORY_SEPARATOR, $currentFile); + + $ignoredFiles = [ + '/ignition/src/helpers.php', + ]; + + foreach ($ignoredFiles as $ignoredFile) { + if (strstr($currentFile, $ignoredFile) !== false) { + return true; + } + } + + return false; + } + + public function firstFrame(): Frame + { + return $this->frames[0]; + } + + public function toArray(): array + { + return array_map(function (Frame $frame) { + return $frame->toArray(); + }, $this->frames); + } + + public function firstApplicationFrame(): ?Frame + { + foreach ($this->frames as $index => $frame) { + if ($frame->isApplicationFrame()) { + return $frame; + } + } + + return null; + } + + public function firstApplicationFrameIndex(): ?int + { + foreach ($this->frames as $index => $frame) { + if ($frame->isApplicationFrame()) { + return $index; + } + } + + return null; + } +} diff --git a/vendor/facade/flare-client-php/src/Time/SystemTime.php b/vendor/facade/flare-client-php/src/Time/SystemTime.php new file mode 100755 index 0000000..8f24a7e --- /dev/null +++ b/vendor/facade/flare-client-php/src/Time/SystemTime.php @@ -0,0 +1,13 @@ +getTimestamp(); + } +} diff --git a/vendor/facade/flare-client-php/src/Time/Time.php b/vendor/facade/flare-client-php/src/Time/Time.php new file mode 100755 index 0000000..989212d --- /dev/null +++ b/vendor/facade/flare-client-php/src/Time/Time.php @@ -0,0 +1,8 @@ +reportTrimmer = $reportTrimmer; + } +} diff --git a/vendor/facade/flare-client-php/src/Truncation/ReportTrimmer.php b/vendor/facade/flare-client-php/src/Truncation/ReportTrimmer.php new file mode 100755 index 0000000..e8e18a3 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Truncation/ReportTrimmer.php @@ -0,0 +1,41 @@ +strategies as $strategy) { + if (! $this->needsToBeTrimmed($payload)) { + break; + } + + $payload = (new $strategy($this))->execute($payload); + } + + return $payload; + } + + public function needsToBeTrimmed(array $payload): bool + { + return strlen(json_encode($payload)) > self::getMaxPayloadSize(); + } + + public static function getMaxPayloadSize(): int + { + return self::$maxPayloadSize; + } + + public static function setMaxPayloadSize(int $maxPayloadSize): void + { + self::$maxPayloadSize = $maxPayloadSize; + } +} diff --git a/vendor/facade/flare-client-php/src/Truncation/TrimContextItemsStrategy.php b/vendor/facade/flare-client-php/src/Truncation/TrimContextItemsStrategy.php new file mode 100755 index 0000000..7e0ca9c --- /dev/null +++ b/vendor/facade/flare-client-php/src/Truncation/TrimContextItemsStrategy.php @@ -0,0 +1,44 @@ +reportTrimmer->needsToBeTrimmed($payload)) { + break; + } + + $payload['context'] = $this->iterateContextItems($payload['context'], $threshold); + } + + return $payload; + } + + protected function iterateContextItems(array $contextItems, int $threshold): array + { + array_walk($contextItems, [$this, 'trimContextItems'], $threshold); + + return $contextItems; + } + + protected function trimContextItems(&$value, $key, int $threshold) + { + if (is_array($value)) { + if (count($value) > $threshold) { + $value = array_slice($value, $threshold * -1, $threshold); + } + + array_walk($value, [$this, 'trimContextItems'], $threshold); + } + + return $value; + } +} diff --git a/vendor/facade/flare-client-php/src/Truncation/TrimStringsStrategy.php b/vendor/facade/flare-client-php/src/Truncation/TrimStringsStrategy.php new file mode 100755 index 0000000..6cb9ad4 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Truncation/TrimStringsStrategy.php @@ -0,0 +1,35 @@ +reportTrimmer->needsToBeTrimmed($payload)) { + break; + } + + $payload = $this->trimPayloadString($payload, $threshold); + } + + return $payload; + } + + protected function trimPayloadString(array $payload, int $threshold): array + { + array_walk_recursive($payload, function (&$value) use ($threshold) { + if (is_string($value) && strlen($value) > $threshold) { + $value = substr($value, 0, $threshold); + } + }); + + return $payload; + } +} diff --git a/vendor/facade/flare-client-php/src/Truncation/TruncationStrategy.php b/vendor/facade/flare-client-php/src/Truncation/TruncationStrategy.php new file mode 100755 index 0000000..ae29d45 --- /dev/null +++ b/vendor/facade/flare-client-php/src/Truncation/TruncationStrategy.php @@ -0,0 +1,8 @@ +file = $file; + $this->data = $data; + } + + public static function create(string $file, array $data = []): self + { + return new static($file, $data); + } + + private function dumpViewData($variable): string + { + $cloner = new VarCloner(); + + $dumper = new HtmlDumper(); + $dumper->setDumpHeader(''); + + $output = fopen('php://memory', 'r+b'); + + $dumper->dump($cloner->cloneVar($variable)->withMaxDepth(1), $output, [ + 'maxDepth' => 1, + 'maxStringLength' => 160, + ]); + + return stream_get_contents($output, -1, 0); + } + + public function toArray() + { + return [ + 'file' => $this->file, + 'data' => array_map([$this, 'dumpViewData'], $this->data), + ]; + } +} diff --git a/vendor/facade/flare-client-php/src/helpers.php b/vendor/facade/flare-client-php/src/helpers.php new file mode 100755 index 0000000..f54ed0a --- /dev/null +++ b/vendor/facade/flare-client-php/src/helpers.php @@ -0,0 +1,17 @@ + &$value) { + if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) { + $merged[$key] = array_merge_recursive_distinct($merged[$key], $value); + } else { + $merged[$key] = $value; + } + } + + return $merged; + } +} diff --git a/vendor/facade/ignition-contracts/.github/workflows/php-cs-fixer.yml b/vendor/facade/ignition-contracts/.github/workflows/php-cs-fixer.yml new file mode 100755 index 0000000..84ab01a --- /dev/null +++ b/vendor/facade/ignition-contracts/.github/workflows/php-cs-fixer.yml @@ -0,0 +1,29 @@ +name: Check & fix styling + +on: [push] + +jobs: + style: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Fix style + uses: docker://oskarstark/php-cs-fixer-ga + with: + args: --config=.php_cs --allow-risky=yes + + - name: Extract branch name + shell: bash + run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" + id: extract_branch + + - name: Commit changes + uses: stefanzweifel/git-auto-commit-action@v2.3.0 + with: + commit_message: Fix styling + branch: ${{ steps.extract_branch.outputs.branch }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/vendor/facade/ignition-contracts/.github/workflows/psalm.yml b/vendor/facade/ignition-contracts/.github/workflows/psalm.yml new file mode 100755 index 0000000..1f6b7aa --- /dev/null +++ b/vendor/facade/ignition-contracts/.github/workflows/psalm.yml @@ -0,0 +1,33 @@ +name: Psalm + +on: + push: + paths: + - '**.php' + - 'psalm.xml' + +jobs: + psalm: + name: psalm + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick + coverage: none + + - name: Cache composer dependencies + uses: actions/cache@v1 + with: + path: vendor + key: composer-${{ hashFiles('composer.lock') }} + + - name: Run composer require + run: composer require -n --prefer-dist + + - name: Run psalm + run: ./vendor/bin/psalm -c psalm.xml diff --git a/vendor/facade/ignition-contracts/.github/workflows/run-tests.yml b/vendor/facade/ignition-contracts/.github/workflows/run-tests.yml new file mode 100755 index 0000000..6b6d1a3 --- /dev/null +++ b/vendor/facade/ignition-contracts/.github/workflows/run-tests.yml @@ -0,0 +1,43 @@ +name: Run tests + +on: + push: + pull_request: + schedule: + - cron: '0 0 * * *' + +jobs: + php-tests: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + php: [ 8.0, 7.4, 7.3 ] + dependency-version: [ prefer-lowest, prefer-stable ] + os: [ ubuntu-latest, windows-latest ] + allow_failures: + - php: 8.0 + + name: P${{ matrix.php }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + tools: composer:v2 + + - name: Install PHP 7 dependencies + run: composer update --${{ matrix.dependency-version }} --no-interaction --no-progress + if: "matrix.php < 8" + + - name: Install PHP 8 dependencies + run: composer update --prefer-stable --ignore-platform-req=php --no-interaction --no-progress + if: "matrix.php >= 8" + + - name: Execute tests + run: vendor/bin/phpunit diff --git a/vendor/facade/ignition-contracts/.php_cs b/vendor/facade/ignition-contracts/.php_cs new file mode 100755 index 0000000..4ca9a7f --- /dev/null +++ b/vendor/facade/ignition-contracts/.php_cs @@ -0,0 +1,38 @@ +notPath('bootstrap/*') + ->notPath('storage/*') + ->notPath('resources/view/mail/*') + ->in([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]) + ->name('*.php') + ->notName('*.blade.php') + ->notName('GitConflictController.php') + ->ignoreDotFiles(true) + ->ignoreVCS(true); + +return PhpCsFixer\Config::create() + ->setRules([ + '@PSR2' => true, + 'array_syntax' => ['syntax' => 'short'], + 'ordered_imports' => ['sortAlgorithm' => 'alpha'], + 'no_unused_imports' => true, + 'not_operator_with_successor_space' => true, + 'trailing_comma_in_multiline_array' => true, + 'phpdoc_scalar' => true, + 'unary_operator_spaces' => true, + 'binary_operator_spaces' => true, + 'blank_line_before_statement' => [ + 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], + ], + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_var_without_name' => true, + 'method_argument_space' => [ + 'on_multiline' => 'ensure_fully_multiline', + 'keep_multiple_spaces_after_comma' => true, + ] + ]) + ->setFinder($finder); diff --git a/vendor/facade/ignition-contracts/LICENSE.md b/vendor/facade/ignition-contracts/LICENSE.md new file mode 100755 index 0000000..9a0c798 --- /dev/null +++ b/vendor/facade/ignition-contracts/LICENSE.md @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) Facade + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/facade/ignition-contracts/composer.json b/vendor/facade/ignition-contracts/composer.json new file mode 100755 index 0000000..69074f4 --- /dev/null +++ b/vendor/facade/ignition-contracts/composer.json @@ -0,0 +1,46 @@ +{ + "name": "facade/ignition-contracts", + "description": "Solution contracts for Ignition", + "keywords": [ + "flare", + "contracts", + "ignition" + ], + "homepage": "https://github.com/facade/ignition-contracts", + "license": "MIT", + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://flareapp.io", + "role": "Developer" + } + ], + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v2.15.8", + "phpunit/phpunit": "^9.3.11", + "vimeo/psalm": "^3.17.1" + }, + "autoload": { + "psr-4": { + "Facade\\IgnitionContracts\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Facade\\IgnitionContracts\\Tests\\": "tests" + } + }, + "scripts": { + "psalm": "vendor/bin/psalm", + "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes", + "test": "vendor/bin/phpunit", + "test-coverage": "vendor/bin/phpunit --coverage-html coverage" + }, + "config": { + "sort-packages": true + } +} diff --git a/vendor/facade/ignition-contracts/psalm.xml b/vendor/facade/ignition-contracts/psalm.xml new file mode 100755 index 0000000..bc341f0 --- /dev/null +++ b/vendor/facade/ignition-contracts/psalm.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/vendor/facade/ignition-contracts/src/BaseSolution.php b/vendor/facade/ignition-contracts/src/BaseSolution.php new file mode 100755 index 0000000..b4a4909 --- /dev/null +++ b/vendor/facade/ignition-contracts/src/BaseSolution.php @@ -0,0 +1,56 @@ +title = $title; + } + + public function getSolutionTitle(): string + { + return $this->title; + } + + public function setSolutionTitle(string $title): self + { + $this->title = $title; + + return $this; + } + + public function getSolutionDescription(): string + { + return $this->description; + } + + public function setSolutionDescription(string $description): self + { + $this->description = $description; + + return $this; + } + + public function getDocumentationLinks(): array + { + return $this->links; + } + + public function setDocumentationLinks(array $links): self + { + $this->links = $links; + + return $this; + } +} diff --git a/vendor/facade/ignition-contracts/src/HasSolutionsForThrowable.php b/vendor/facade/ignition-contracts/src/HasSolutionsForThrowable.php new file mode 100755 index 0000000..32ad3e9 --- /dev/null +++ b/vendor/facade/ignition-contracts/src/HasSolutionsForThrowable.php @@ -0,0 +1,13 @@ +in([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]) + ->name('*.php') + ->notName('*.blade.php') + ->ignoreDotFiles(true) + ->ignoreVCS(true); + +return (new PhpCsFixer\Config()) + ->setRules([ + '@PSR12' => true, + 'array_syntax' => ['syntax' => 'short'], + 'ordered_imports' => ['sort_algorithm' => 'alpha'], + 'no_unused_imports' => true, + 'not_operator_with_successor_space' => true, + 'trailing_comma_in_multiline' => true, + 'phpdoc_scalar' => true, + 'unary_operator_spaces' => true, + 'binary_operator_spaces' => true, + 'blank_line_before_statement' => [ + 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], + ], + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_var_without_name' => true, + 'class_attributes_separation' => [ + 'elements' => [ + 'method' => 'one', + ], + ], + 'method_argument_space' => [ + 'on_multiline' => 'ensure_fully_multiline', + 'keep_multiple_spaces_after_comma' => true, + ], + 'single_trait_insert_per_statement' => true, + ]) + ->setFinder($finder); diff --git a/vendor/facade/ignition/CHANGELOG.md b/vendor/facade/ignition/CHANGELOG.md new file mode 100755 index 0000000..f7890f3 --- /dev/null +++ b/vendor/facade/ignition/CHANGELOG.md @@ -0,0 +1,542 @@ +# Changelog + +All notable changes to `ignition` will be documented in this file + +## 2.17.2 - 2021-11-29 + +- scroll overflow on solutions + +## 2.17.1 - 2021-11-25 + +- streamline Livewire solutions + +## 2.17.0 - 2021-11-24 + +- improve recording of Livewire data + +## 2.16.1 - 2021-11-16 + +- allow sending of unbinded sql queries to Flare + +## 2.16.0 - 2021-10-28 + +- improve recording data from jobs (#416) + +## 2.15.0 - 2021-10-11 + +- improve output of flare:test + +## 2.14.1 - 2021-10-08 + +- update base URL for Flare + +## 2.14.0 - 2021-10-01 + +- add support for VScode WSL + SSH remote (#420) + +## 2.13.1 - 2021-09-13 + +- fix namespace of `SentReports` in facade + +## 2.13.0 - 2021-09-13 + +- add tracking uuid (#418) + +## 2.12.1 - 2021-09-08 + +- add support for VS Codium editor (#417) + +## 2.12.0 - 2021-08-24 + +- add support for collecting information about jobs (#412) + +## 2.11.4 - 2021-08-16 + +- use npm ci instead of install (#411) + +## 2.11.3 - 2021-08-16 + +- fix issues with circular dependencies in model route parameters (#408) +- remove notice about dirty git state in context +- wrap `AddGitInformation` middleware in try-catch + +## 2.11.2 - 2021-07-20 + +- fix issues introduced in 2.11.1 (#403) + +## 2.11.1 - 2021-07-20 + +- fix sending queued reports on Laravel Vapor queues (#398) + +## 2.11.0 - 2021-07-12 + +- prepare Laravel 9 support +- remove filp/whoops dependency +- update front-end dependencies + +## 2.10.2 - 2021-06-11 + +- fix typo in config/flare.php (#395) + +## 2.10.1 - 2021-06-03 + +- fix memory leaks in Octane (#393) + +## 2.10.0 - 2021-06-03 + +- add a solution for lazy loading violations (#392) + +## 2.9.0 - 2021-05-05 + +- add Xdebug format links for editor (#383) + +## 2.8.4 - 2021-04-29 + +- avoid making call to Flare when no API key is specified + +## 2.8.3 - 2021-04-09 + +- support Octane (#379) + +## 2.8.2 - 2021-04-08 + +- censor passwords by default (#377) + +## 2.8.1 - 2021-04-08 + +- add `censor_request_body_fields` default config option + +## 2.8.0 - 2021-04-08 + +- add `censor_request_body_fields` config option + +## 2.7.0 - 2021-03-30 + +- adds a debug warning when having debug enabled on a non-local environment (#366) + +## 2.6.1 - 2021-03-30 + +- Disable executing solutions on non-local environments or from non-local IP addresses (#364) + +## 2.6.0 - 2021-03-24 + +- add extra output to test command when executing verbosely + +## 2.5.14 - 2021-03-03 + +- fix ignition not working when there is no argv + +## 2.5.13 - 2021-02-16 + +- remove custom grouping + +## 2.5.12 - 2021-02-15 + +- fix wrong config usage (#354) + +## 2.5.11 - 2021-02-05 + +- fix memory leaks caused by log and query recorder (#344) + +## 2.5.10 - 2021-02-02 + +- fix tinker logs not being sent to Flare + +## 2.5.9 - 2021-01-26 + +- fix logged context not being sent to Flare + +## 2.5.8 - 2020-12-29 + +- fix double `$` on PHP 8 (#338) + +## 2.5.7 - 2020-12-29 + +- fix for breaking change in highlight.js (fixes 2.5.5) + +## 2.5.6 - 2020-12-29 + +- revert to compiled js of 2.5.3 + +## 2.5.5 - 2020-12-29 + +- added compiled js of previous release + +## 2.5.4 - 2020-12-29 + +- added support for Nova text editor (#343) + +## 2.5.3 - 2020-12-08 + +- Use Livewire compatible compiler engine when using Livewire (#340) + +## 2.5.2 - 2020-11-14 + +- fix `MakeViewVariableOptionalSolution` to disallow stream wrappers and files that do not end in ".blade.php" (#334) + +## 2.5.1 - 2020-11-13 + +- add support for LiveWire component urls + +## 2.5.0 - 2020-10-27 + +- add PHP 8.0-dev support +- remove unnecessary `scrivo/highlight.php` dependency + +## 2.4.2 - 2021-03-08 + +- fix `MakeViewVariableOptionalSolution` to disallow stream wrappers and files that do not end in .blade.php (#356) + +## 2.4.1 - 2020-10-14 + +- fix copy casing + +## 2.4.0 - 2020-10-14 + +- add livewire component discovery solution + +## 2.3.8 - 2020-10-02 + +- Address Missing Mix Manifest Error (#317) + +## 2.3.7 - 2020-09-06 + +- add loading state on share button (#309) +- compatibility fix for L8 + +## 2.3.6 - 2020-08-10 + +- possible security vulnerability: bump elliptic version (#300) +- possible XSS vulnerability: escape characters in stacktrace and exception title + +## 2.3.5 - 2020-08-01 + +- catch exception in detectLineNumber for not existing blade files (#299) + +## 2.3.4 - 2020-07-27 + +- fix an error that would throw a blank page when using third party extensions + +## 2.3.3 -2020-07-14 + +- fix all psalm related issues + +## 2.3.2 - 2020-07-14 + +- properly bind singleton (#291) + +## 2.3.1 - 2020-07-13 + +- improve db name solution (#289) + +## 2.3.0 - 2020-07-13 + +- allow override of Dumper via `$_SERVER variable` (#271) +- make DumpHandler instance manually in DumpRecorder (#286) +- only setup queues when queue is available (#287) + +## 2.2.0 - 2020-07-13 + +- add `ignition:make:solution-provider` command + +## 2.1.0 - 2020-07-13 + +- add "Undefined Property" solution (#264) + +## 2.0.10 - 2020-07-13 + +- correctly detect dump location from ddd (#216) + +## 2.0.9 - 2020-07-13 + +- use application contract instead of concrete class (#243) + +## 2.0.8 - 2020-07-12 + +- do not render solution title tag for empty titles + +## 2.0.7 - 2020-06-07 + +- Fix `DefaultDbNameSolutionProvider` (#277) + +## 2.0.6 - 2020-06-01 + +- remove ability to fix variable names + +## 2.0.5 - 2020-05-29 + +- blacklist certain variable names when fixing variable names + +## 2.0.4 - 2020-05-18 + +- handle exceptions in case the request doesn't have a user (#274) + +## 2.0.3 - 2020-04-07 + +- support Laravel 8 + +## 2.0.2 - 2020-03-18 + +- fix execute solution route not defined (#265) + +## 2.0.0 - 2020-02-02 + +- adds support for Laravel 7 +- drop support for Laravel 6 and below +- git information won't be collected by default anymore (if you need this set `collect_git_information` to `true` in the `flare` config file) +- `MissingPackageSolutionProvider` was added to the `ignored_solution_providers` because it potentially could be slow. + +## 1.16.0 - 2020-01-21 + +- add named routes (#197) + +## 1.15.0 - 2020-01-21 + +- add exception to the bottom of the html (#230) + +## 1.14.0 - 2020-01-06 + +- add indicator that solution is running (#212) + +## 1.13.1 - 2020-01-02 + +- Remove external reference for icons (#134) + +## 1.13.0 - 2019-11-27 + +- Allow custom grouping types + +## 1.12.1 - 2019-11-25 + +- Detect multibyte position offsets when adding linenumbers to the blade view - Fixes #193 + +## 1.12.0 - 2019-11-14 + +- Add exception to html (#206) +- Add a clear exception when passing no parameters to ddd (#205) +- Ignore JS tests (#215) +- Fix share report route bug + +## 1.11.2 - 2019-10-13 + +- simplify default Laravel installation (#198) + +## 1.11.1 - 2019-10-08 + +- add conditional line number (#182) + +## 1.11.0 - 2019-10-08 + +- add better error messages for missing validation rules (#125) + +## 1.10.0 - 2019-10-07 + +- Add `ignition:make-solution` command +- Add default for query binding option (Fixes #183) + +## 1.9.2 - 2019-10-04 + +- Fix service provider registration (Fixes #177) + +## 1.9.1 - 2019-10-01 + +- collapse vendor frames on windows fix (#176) + +## 1.9.0 - 2019-09-27 + +- add ability to send logs to flare +- add `ddd` function + +## 1.8.4 - 2019-09-27 + +- Resolve configuration from the injected app instead of the helper ([#168](https://github.com/facade/ignition/pull/168)) + +## 1.8.3 - 2019-09-25 + +- Remove `select-none` from error message +- Change line clamp behaviour for longer error messages + +## 1.8.2 - 2019-09-20 + +- fix for `TypeError: Cannot set property 'highlightState' of undefined` + +## 1.8.1 - 2019-09-20 + +- Revert javascript assets via URL - Fixes #161 + +## 1.8.0 - 2019-09-18 + +- added solution for running Laravel Dusk in production ([#121](https://github.com/facade/ignition/pull/121)) +- Automatically fix blade variable typos and optional variables ([#38](https://github.com/facade/ignition/pull/38)) + +## 1.7.1 - 2019-09-18 + +- Use url helper to generate housekeeping endpoints + +## 1.7.0 - 2019-09-18 + +- Add the ability to define a query collector max value ([#153](https://github.com/facade/ignition/pull/153)) + +## 1.6.10 - 2019-09-18 + +- fix `__invoke` method name in solution ([#151](https://github.com/facade/ignition/pull/151)) + +## 1.6.9 - 2019-09-18 + +- Add noscript trace information - fixes [#146](https://github.com/facade/ignition/issues/146) + +## 1.6.8 - 2019-09-18 + +- Use javascript content type for asset response - fixes [#149](https://github.com/facade/ignition/issues/149) + +## 1.6.7 - 2019-09-18 + +- Load javascript assets via URL. Fixes [#16](https://github.com/facade/ignition/issues/16) + +## 1.6.6 - 2019-09-16 + +- Prevent undefined index exception in `TestCommand` + +## 1.6.5 - 2019-09-13 + +- Ignore invalid characters in JSON encoding. Fixes [#138](https://github.com/facade/ignition/issues/138) + +## 1.6.4 - 2019-09-13 + +- add no-index on error page + +## 1.6.3 - 2019-09-12 + +- Fix `RouteNotDefinedSolutionProvider` in Laravel 5 + +## 1.6.2 - 2019-09-12 + +- updated publishing tag from default config + +## 1.6.1 - 2019-09-12 + +- Resolve configuration from the injected application instead of the helper - Fixes [#131](https://github.com/facade/ignition/issues/131) + +## 1.6.0 - 2019-09-09 + +- add `RouteNotDefined` solution provider ([#113](https://github.com/facade/ignition/pull/113)) + +## 1.5.0 - 2019-09-09 + +- suggest running migrations when a column is missing ([#83](https://github.com/facade/ignition/pull/83)) + +## 1.4.19 - 2019-09-09 + +- Remove quotation from git commit url ([#89](https://github.com/facade/ignition/pull/89)) + +## 1.4.18 - 2019-09-09 + +- Fix open_basedir restriction when looking up config file. Fixes ([#120](https://github.com/facade/ignition/pull/120)) + +## 1.4.17 - 2019-09-06 + +- Remove Inter, Operator from font stack. Fixes [#74](https://github.com/facade/ignition/issues/74) + +## 1.4.15 - 2019-09-05 + +- Use previous exception trace for view exceptions. Fixes [#107](https://github.com/facade/ignition/issues/107) + +## 1.4.14 - 2019-09-05 + +- Use DIRECTORY_SEPARATOR to fix an issue with blade view lookups in Windows + +## 1.4.13 - 2019-09-05 + +- Use Laravel style comments + +## 1.4.12 - 2019-09-04 + +- Use a middleware to protect ignition routes ([#93](https://github.com/facade/ignition/pull/93)) + +## 1.4.11 - 2019-09-04 + +- Use exception line number as fallbacks for view errors + +## 1.4.10 - 2019-09-04 + +- Wrap solution provider lookup in a try-catch block + +## 1.4.9 - 2019-09-04 + +- Lookup the first exception when linking to Telescope + +## 1.4.8 - 2019-09-04 + +- pass an empty string to query if no connection name is available - fixes [#86](https://github.com/facade/ignition/issues/86) + +## 1.4.7 - 2019-09-04 + +- Match whoops minimum version constraint with Laravel 6 + +## 1.4.6 - 2019-09-04 + +- Use empty array for default ignored solution providers + +## 1.4.5 - 2019-09-03 + +- fix for new Laravel 6 installs + +## 1.4.4 - 2019-09-03 + +- Suggest default database name in Laravel 6 +- Add void return type to FlareHandler::write() + +## 1.4.3 - 2019-09-03 + +- allow monolog v2 + +## 1.4.2 - 2019-09-03 + +- style fixes + +## 1.4.1 - 2019-09-03 + +- Change `remote-sites-path` and `local-sites-path` config keys to us snake case + +## 1.4.0 - 2019-09-03 + +- add `enable_runnable_solutions` key to config file + +## 1.3.0 - 2019-09-02 + +- add `MergeConflictSolutionProvider` + +## 1.2.0 - 2019-09-02 + +- add `ignored_solution_providers` key to config file + +## 1.1.1 - 2019-09-02 + +- Fixed context tab crash when not using git ([#24](https://github.com/facade/ignition/issues/24)) + +## 1.1.0 - 2019-09-02 + +- Fixed an error that removed the ability to register custom blade directives. +- Fixed an error that prevented solution execution in Laravel 5.5 and 5.6 +- The "Share" button can now be disabled in the configuration file +- Fixes an error when trying to log `null` values + +## 1.0.4 - 2019-09-02 + +- Check if the authenticated user has a `toArray` method available, before collecting user data + +## 1.0.3 - 2019-09-02 + +- Corrected invalid link in config file + +## 1.0.2 - 2019-09-02 + +- Fixed an error in the `DefaultDbNameSolutionProvider` that could cause an infinite loop in Laravel < 5.6.28 + +## 1.0.1 - 2019-08-31 + +- add support for L5.5 & 5.6 ([#21](https://github.com/facade/ignition/pull/21)) + +## 1.0.0 - 2019-08-30 + +- initial release diff --git a/vendor/facade/ignition/LICENSE.md b/vendor/facade/ignition/LICENSE.md new file mode 100755 index 0000000..48c30e4 --- /dev/null +++ b/vendor/facade/ignition/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Facade + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/facade/ignition/README.md b/vendor/facade/ignition/README.md new file mode 100755 index 0000000..ac1c0e0 --- /dev/null +++ b/vendor/facade/ignition/README.md @@ -0,0 +1,25 @@ +# Ignition: a beautiful error page for Laravel apps + +[![Latest Version on Packagist](https://img.shields.io/packagist/v/facade/ignition.svg?style=flat-square)](https://packagist.org/packages/facade/ignition) +![Tests](https://github.com/facade/ignition/workflows/Run%20tests/badge.svg) +[![Total Downloads](https://img.shields.io/packagist/dt/facade/ignition.svg?style=flat-square)](https://packagist.org/packages/facade/ignition) + +[Ignition](https://flareapp.io/docs/ignition-for-laravel/introduction) is a beautiful and customizable error page for Laravel applications running on Laravel 5.5 and newer. It is the default error page for all Laravel 6 applications. It also allows to publicly share your errors on [Flare](https://flareapp.io). If configured with a valid Flare API key, your errors in production applications will be tracked, and you'll get notified when they happen. + +![Screenshot of ignition](https://facade.github.io/ignition/screenshot.png) + +## Official Documentation + +The official documentation for Ignition can be found on the [Flare website](https://flareapp.io/docs/ignition-for-laravel/installation). + +### Changelog + +Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. diff --git a/vendor/facade/ignition/SECURITY.md b/vendor/facade/ignition/SECURITY.md new file mode 100755 index 0000000..754cc4a --- /dev/null +++ b/vendor/facade/ignition/SECURITY.md @@ -0,0 +1,3 @@ +# Security Policy + +For security related problems, please don't use the public issue tracker, but mail info@spatie.be. diff --git a/vendor/facade/ignition/composer.json b/vendor/facade/ignition/composer.json new file mode 100755 index 0000000..b745434 --- /dev/null +++ b/vendor/facade/ignition/composer.json @@ -0,0 +1,77 @@ +{ + "name": "facade/ignition", + "description": "A beautiful error page for Laravel applications.", + "keywords": [ + "error", + "page", + "laravel", + "flare" + ], + "homepage": "https://github.com/facade/ignition", + "license": "MIT", + "require": { + "php": "^7.2.5|^8.0", + "ext-json": "*", + "ext-mbstring": "*", + "facade/flare-client-php": "^1.9.1", + "facade/ignition-contracts": "^1.0.2", + "illuminate/support": "^7.0|^8.0", + "monolog/monolog": "^2.0", + "symfony/console": "^5.0", + "symfony/var-dumper": "^5.0", + "ext-curl": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "livewire/livewire": "^2.4", + "mockery/mockery": "^1.3", + "orchestra/testbench": "^5.0|^6.0", + "psalm/plugin-laravel": "^1.2" + }, + "suggest": { + "laravel/telescope": "^3.1" + }, + "config": { + "sort-packages": true + }, + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + }, + "laravel": { + "providers": [ + "Facade\\Ignition\\IgnitionServiceProvider" + ], + "aliases": { + "Flare": "Facade\\Ignition\\Facades\\Flare" + } + } + }, + "autoload": { + "psr-4": { + "Facade\\Ignition\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "autoload-dev": { + "psr-4": { + "Facade\\Ignition\\Tests\\": "tests" + } + }, + "minimum-stability": "dev", + "prefer-stable": true, + "scripts": { + "psalm": "vendor/bin/psalm", + "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes", + "test": "vendor/bin/phpunit", + "test-coverage": "vendor/bin/phpunit --coverage-html coverage" + }, + "support": { + "issues": "https://github.com/facade/ignition/issues", + "forum": "https://twitter.com/flareappio", + "source": "https://github.com/facade/ignition", + "docs": "https://flareapp.io/docs/ignition-for-laravel/introduction" + } +} diff --git a/vendor/facade/ignition/config/flare.php b/vendor/facade/ignition/config/flare.php new file mode 100755 index 0000000..48fc07d --- /dev/null +++ b/vendor/facade/ignition/config/flare.php @@ -0,0 +1,62 @@ + env('FLARE_KEY'), + + /* + |-------------------------------------------------------------------------- + | Reporting Options + |-------------------------------------------------------------------------- + | + | These options determine which information will be transmitted to Flare. + | + */ + + 'reporting' => [ + 'anonymize_ips' => true, + 'collect_git_information' => false, + 'report_queries' => true, + 'maximum_number_of_collected_queries' => 200, + 'report_query_bindings' => true, + 'report_view_data' => true, + 'grouping_type' => null, + 'report_logs' => true, + 'maximum_number_of_collected_logs' => 200, + 'censor_request_body_fields' => ['password'], + ], + + /* + |-------------------------------------------------------------------------- + | Reporting Log statements + |-------------------------------------------------------------------------- + | + | If this setting is `false` log statements won't be sent as events to Flare, + | no matter which error level you specified in the Flare log channel. + | + */ + + 'send_logs_as_events' => true, + + /* + |-------------------------------------------------------------------------- + | Censor request body fields + |-------------------------------------------------------------------------- + | + | These fields will be censored from your request when sent to Flare. + | + */ + + 'censor_request_body_fields' => ['password'], +]; diff --git a/vendor/facade/ignition/config/ignition.php b/vendor/facade/ignition/config/ignition.php new file mode 100755 index 0000000..268d2f2 --- /dev/null +++ b/vendor/facade/ignition/config/ignition.php @@ -0,0 +1,126 @@ + env('IGNITION_EDITOR', 'phpstorm'), + + /* + |-------------------------------------------------------------------------- + | Theme + |-------------------------------------------------------------------------- + | + | Here you may specify which theme Ignition should use. + | + | Supported: "light", "dark", "auto" + | + */ + + 'theme' => env('IGNITION_THEME', 'light'), + + /* + |-------------------------------------------------------------------------- + | Sharing + |-------------------------------------------------------------------------- + | + | You can share local errors with colleagues or others around the world. + | Sharing is completely free and doesn't require an account on Flare. + | + | If necessary, you can completely disable sharing below. + | + */ + + 'enable_share_button' => env('IGNITION_SHARING_ENABLED', true), + + /* + |-------------------------------------------------------------------------- + | Register Ignition commands + |-------------------------------------------------------------------------- + | + | Ignition comes with an additional make command that lets you create + | new solution classes more easily. To keep your default Laravel + | installation clean, this command is not registered by default. + | + | You can enable the command registration below. + | + */ + 'register_commands' => env('REGISTER_IGNITION_COMMANDS', false), + + /* + |-------------------------------------------------------------------------- + | Ignored Solution Providers + |-------------------------------------------------------------------------- + | + | You may specify a list of solution providers (as fully qualified class + | names) that shouldn't be loaded. Ignition will ignore these classes + | and possible solutions provided by them will never be displayed. + | + */ + + 'ignored_solution_providers' => [ + \Facade\Ignition\SolutionProviders\MissingPackageSolutionProvider::class, + ], + + /* + |-------------------------------------------------------------------------- + | Runnable Solutions + |-------------------------------------------------------------------------- + | + | Some solutions that Ignition displays are runnable and can perform + | various tasks. Runnable solutions are enabled when your app has + | debug mode enabled. You may also fully disable this feature. + | + */ + + 'enable_runnable_solutions' => env('IGNITION_ENABLE_RUNNABLE_SOLUTIONS', null), + + /* + |-------------------------------------------------------------------------- + | Remote Path Mapping + |-------------------------------------------------------------------------- + | + | If you are using a remote dev server, like Laravel Homestead, Docker, or + | even a remote VPS, it will be necessary to specify your path mapping. + | + | Leaving one, or both of these, empty or null will not trigger the remote + | URL changes and Ignition will treat your editor links as local files. + | + | "remote_sites_path" is an absolute base path for your sites or projects + | in Homestead, Vagrant, Docker, or another remote development server. + | + | Example value: "/home/vagrant/Code" + | + | "local_sites_path" is an absolute base path for your sites or projects + | on your local computer where your IDE or code editor is running on. + | + | Example values: "/Users//Code", "C:\Users\\Documents\Code" + | + */ + + 'remote_sites_path' => env('IGNITION_REMOTE_SITES_PATH', ''), + 'local_sites_path' => env('IGNITION_LOCAL_SITES_PATH', ''), + + /* + |-------------------------------------------------------------------------- + | Housekeeping Endpoint Prefix + |-------------------------------------------------------------------------- + | + | Ignition registers a couple of routes when it is enabled. Below you may + | specify a route prefix that will be used to host all internal links. + | + */ + 'housekeeping_endpoint_prefix' => '_ignition', + +]; diff --git a/vendor/facade/ignition/package.json b/vendor/facade/ignition/package.json new file mode 100755 index 0000000..11c0b1c --- /dev/null +++ b/vendor/facade/ignition/package.json @@ -0,0 +1,65 @@ +{ + "private": true, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "NODE_ENV=production webpack --mode production", + "format": "prettier --write 'resources/**/*.{css,js,ts,vue}'" + }, + "dependencies": { + "git-url-parse": "^11.1.2", + "highlight.js": "^10.4.1", + "lodash": "^4.17.21", + "markdown-it": "^9.0.1", + "md5": "^2.2.1", + "sql-formatter": "^2.3.3" + }, + "devDependencies": { + "@babel/core": "^7.4.5", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-transform-runtime": "^7.4.4", + "@babel/preset-env": "^7.4.5", + "@babel/preset-typescript": "^7.3.3", + "@fullhuman/postcss-purgecss": "^1.1.0", + "@types/jest": "^24.0.15", + "@types/lodash": "^4.14.133", + "babel-loader": "^8.0.6", + "css-loader": "^3.0.0", + "husky": "^1.3.1", + "jest": "^24.8.0", + "lint-staged": "^8.1.5", + "postcss-import": "^12.0.1", + "postcss-loader": "^3.0.0", + "postcss-preset-env": "^6.6.0", + "prettier": "^1.16.4", + "style-loader": "^0.23.1", + "tailwindcss": "^1.0.4", + "typescript": "^3.5.2", + "vue": "^2.6.10", + "vue-loader": "^15.7.0", + "vue-template-compiler": "^2.6.10", + "webpack": "^4.35.0", + "webpack-cli": "^3.3.5" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged && yarn build && git add resources/compiled/ignition.js" + } + }, + "lint-staged": { + "linters": { + "*.{css,js,ts,vue}": [ + "yarn format", + "git add" + ] + }, + "ignore": [ + "resources/compiled/**/*" + ] + }, + "jest": { + "testPathIgnorePatterns": [ + "/node_modules/", + "/__helpers__/" + ] + } +} diff --git a/vendor/facade/ignition/psalm-baseline.xml b/vendor/facade/ignition/psalm-baseline.xml new file mode 100755 index 0000000..0133da9 --- /dev/null +++ b/vendor/facade/ignition/psalm-baseline.xml @@ -0,0 +1,51 @@ + + + + + $this->app + $this->app + $this->app + $this->app + $this->app + $this->app + $this->app + + + + + $this->app + + + + + $this->app + $this->app + $this->app + + + + + ComponentNotFoundException + + + + + app('validator') + + + + + LivewireComponentsFinder + + + + + $baseException + + + + + $baseException + + + diff --git a/vendor/facade/ignition/psalm.xml b/vendor/facade/ignition/psalm.xml new file mode 100755 index 0000000..25eb793 --- /dev/null +++ b/vendor/facade/ignition/psalm.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/facade/ignition/resources/.gitignore b/vendor/facade/ignition/resources/.gitignore new file mode 100755 index 0000000..4dcdd85 --- /dev/null +++ b/vendor/facade/ignition/resources/.gitignore @@ -0,0 +1,3 @@ +compiled/* +!compiled/index.html +!compiled/ignition.js diff --git a/vendor/facade/ignition/resources/compiled/ignition.js b/vendor/facade/ignition/resources/compiled/ignition.js new file mode 100755 index 0000000..80a0ebf --- /dev/null +++ b/vendor/facade/ignition/resources/compiled/ignition.js @@ -0,0 +1,32 @@ +!function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/",n(n.s=282)}([function(t,e,n){"use strict";function r(t,e,n,r,o,i,a,s){var c,u="function"==typeof t?t.options:t;if(e&&(u.render=e,u.staticRenderFns=n,u._compiled=!0),r&&(u.functional=!0),i&&(u._scopeId="data-v-"+i),a?(c=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),o&&o.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(a)},u._ssrRegister=c):o&&(c=s?function(){o.call(this,this.$root.$options.shadowRoot)}:o),c)if(u.functional){u._injectStyles=c;var l=u.render;u.render=function(t,e){return c.call(e),l(t,e)}}else{var f=u.beforeCreate;u.beforeCreate=f?[].concat(f,c):[c]}return{exports:t,options:u}}n.d(e,"a",(function(){return r}))},function(t,e,n){"use strict";var r=Object.prototype.hasOwnProperty;function o(t,e){return r.call(t,e)}function i(t){return!(t>=55296&&t<=57343)&&(!(t>=64976&&t<=65007)&&(65535!=(65535&t)&&65534!=(65535&t)&&(!(t>=0&&t<=8)&&(11!==t&&(!(t>=14&&t<=31)&&(!(t>=127&&t<=159)&&!(t>1114111)))))))}function a(t){if(t>65535){var e=55296+((t-=65536)>>10),n=56320+(1023&t);return String.fromCharCode(e,n)}return String.fromCharCode(t)}var s=/\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g,c=new RegExp(s.source+"|"+/&([a-z#][a-z0-9]{1,31});/gi.source,"gi"),u=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,l=n(55);var f=/[&<>"]/,p=/[&<>"]/g,d={"&":"&","<":"<",">":">",'"':"""};function h(t){return d[t]}var g=/[.?*+^$[\]\\(){}|-]/g;var m=n(36);e.lib={},e.lib.mdurl=n(56),e.lib.ucmicro=n(108),e.assign=function(t){return Array.prototype.slice.call(arguments,1).forEach((function(e){if(e){if("object"!=typeof e)throw new TypeError(e+"must be object");Object.keys(e).forEach((function(n){t[n]=e[n]}))}})),t},e.isString=function(t){return"[object String]"===function(t){return Object.prototype.toString.call(t)}(t)},e.has=o,e.unescapeMd=function(t){return t.indexOf("\\")<0?t:t.replace(s,"$1")},e.unescapeAll=function(t){return t.indexOf("\\")<0&&t.indexOf("&")<0?t:t.replace(c,(function(t,e,n){return e||function(t,e){var n=0;return o(l,e)?l[e]:35===e.charCodeAt(0)&&u.test(e)&&i(n="x"===e[1].toLowerCase()?parseInt(e.slice(2),16):parseInt(e.slice(1),10))?a(n):t}(t,n)}))},e.isValidEntityCode=i,e.fromCodePoint=a,e.escapeHtml=function(t){return f.test(t)?t.replace(p,h):t},e.arrayReplaceAt=function(t,e,n){return[].concat(t.slice(0,e),n,t.slice(e+1))},e.isSpace=function(t){switch(t){case 9:case 32:return!0}return!1},e.isWhiteSpace=function(t){if(t>=8192&&t<=8202)return!0;switch(t){case 9:case 10:case 11:case 12:case 13:case 32:case 160:case 5760:case 8239:case 8287:case 12288:return!0}return!1},e.isMdAsciiPunct=function(t){switch(t){case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 58:case 59:case 60:case 61:case 62:case 63:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 124:case 125:case 126:return!0;default:return!1}},e.isPunctChar=function(t){return m.test(t)},e.escapeRE=function(t){return t.replace(g,"\\$&")},e.normalizeReference=function(t){return t=t.trim().replace(/\s+/g," "),"Ṿ"==="ẞ".toLowerCase()&&(t=t.replace(/ẞ/g,"ß")),t.toLowerCase().toUpperCase()}},function(t,e,n){"use strict";e.a={functional:!0,props:{label:{default:""}},render:function(t,e){return[t("dt",{attrs:{class:"definition-label"}},e.props.label),t("dd",{attrs:{class:"definition-value"}},e.children)]}}},function(t,e,n){"use strict";var r={props:{title:{default:""},className:{default:""}}},o=n(0),i=Object(o.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{class:t.className},[t.title?n("h3",{staticClass:"definition-list-title"},[t._v(t._s(t.title))]):t._e(),t._v(" "),this.$slots.default?n("dl",{staticClass:"definition-list"},[t._t("default")],2):t._e(),t._v(" "),this.$slots.default?t._e():n("div",{staticClass:"definition-list"},[n("div",{staticClass:"definition-list-empty"},[t._v("—")])])])}),[],!1,null,null,null);e.a=i.exports},function(t,e,n){var r=n(155),o=n(156),i=n(157);t.exports=function(t){return r(t)||o(t)||i()}},function(t,e,n){"use strict";var r=n(34),o={props:{file:{required:!0},editable:{default:!1},relative:{default:!0},lineNumber:{required:!1},pathClass:{default:""}},data:function(){return{segments:[],filename:"",fileSegments:[]}},inject:["config","report"],watch:{file:{immediate:!0,handler:function(){this.segments=this.path.replace(/^\/Users/,"~").split("/"),this.filename=this.segments.pop()||"",this.fileSegments=this.filename.split(".")}}},computed:{path:function(){return this.relative?this.file.replace(this.report.application_path+"/",""):this.file},editorUrl:function(){return Object(r.a)(this.config,this.file,this.lineNumber)}}},i=n(0),a=Object(i.a)(o,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("span",{staticClass:"inline-flex justify-start items-baseline"},[n("span",t._g({staticClass:"ui-path",class:t.pathClass},t.$listeners),[t._l(t.segments,(function(e,r){return n("span",{key:"segment-"+r},[t._v(t._s(e)+"/"),n("wbr")])})),t._l(t.fileSegments,(function(e,r){return n("span",{key:"file-"+r,class:0===r?"font-semibold":""},[t._v(t._s(r>0?".":"")+t._s(e))])})),t.lineNumber?n("span",[t._v(":"+t._s(t.lineNumber))]):t._e()],2),t._v(" "),t._t("default"),t._v(" "),t.editable&&t.editorUrl?n("a",{staticClass:"ml-2 inline-block text-sm text-purple-400 hover:text-purple-500",attrs:{href:t.editorUrl}},[n("Icon",{attrs:{name:"pencil"}})],1):t._e()],2)}),[],!1,null,null,null);e.a=a.exports},function(t,e){t.exports=function(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}},function(t,e,n){"use strict";(function(t,n){ +/*! + * Vue.js v2.6.10 + * (c) 2014-2019 Evan You + * Released under the MIT License. + */ +var r=Object.freeze({});function o(t){return null==t}function i(t){return null!=t}function a(t){return!0===t}function s(t){return"string"==typeof t||"number"==typeof t||"symbol"==typeof t||"boolean"==typeof t}function c(t){return null!==t&&"object"==typeof t}var u=Object.prototype.toString;function l(t){return"[object Object]"===u.call(t)}function f(t){return"[object RegExp]"===u.call(t)}function p(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function d(t){return i(t)&&"function"==typeof t.then&&"function"==typeof t.catch}function h(t){return null==t?"":Array.isArray(t)||l(t)&&t.toString===u?JSON.stringify(t,null,2):String(t)}function g(t){var e=parseFloat(t);return isNaN(e)?t:e}function m(t,e){for(var n=Object.create(null),r=t.split(","),o=0;o-1)return t.splice(n,1)}}var y=Object.prototype.hasOwnProperty;function E(t,e){return y.call(t,e)}function x(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}var k=/-(\w)/g,w=x((function(t){return t.replace(k,(function(t,e){return e?e.toUpperCase():""}))})),C=x((function(t){return t.charAt(0).toUpperCase()+t.slice(1)})),A=/\B([A-Z])/g,T=x((function(t){return t.replace(A,"-$1").toLowerCase()}));var S=Function.prototype.bind?function(t,e){return t.bind(e)}:function(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n};function R(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function O(t,e){for(var n in e)t[n]=e[n];return t}function N(t){for(var e={},n=0;n0,tt=Z&&Z.indexOf("edge/")>0,et=(Z&&Z.indexOf("android"),Z&&/iphone|ipad|ipod|ios/.test(Z)||"ios"===X),nt=(Z&&/chrome\/\d+/.test(Z),Z&&/phantomjs/.test(Z),Z&&Z.match(/firefox\/(\d+)/)),rt={}.watch,ot=!1;if(Y)try{var it={};Object.defineProperty(it,"passive",{get:function(){ot=!0}}),window.addEventListener("test-passive",null,it)}catch(t){}var at=function(){return void 0===V&&(V=!Y&&!K&&void 0!==t&&(t.process&&"server"===t.process.env.VUE_ENV)),V},st=Y&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function ct(t){return"function"==typeof t&&/native code/.test(t.toString())}var ut,lt="undefined"!=typeof Symbol&&ct(Symbol)&&"undefined"!=typeof Reflect&&ct(Reflect.ownKeys);ut="undefined"!=typeof Set&&ct(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var ft=L,pt=0,dt=function(){this.id=pt++,this.subs=[]};dt.prototype.addSub=function(t){this.subs.push(t)},dt.prototype.removeSub=function(t){_(this.subs,t)},dt.prototype.depend=function(){dt.target&&dt.target.addDep(this)},dt.prototype.notify=function(){var t=this.subs.slice();for(var e=0,n=t.length;e-1)if(i&&!E(o,"default"))a=!1;else if(""===a||a===T(t)){var c=qt(String,o.type);(c<0||s0&&(pe((u=t(u,(n||"")+"_"+c))[0])&&pe(f)&&(r[l]=yt(f.text+u[0].text),u.shift()),r.push.apply(r,u)):s(u)?pe(f)?r[l]=yt(f.text+u):""!==u&&r.push(yt(u)):pe(u)&&pe(f)?r[l]=yt(f.text+u.text):(a(e._isVList)&&i(u.tag)&&o(u.key)&&i(n)&&(u.key="__vlist"+n+"_"+c+"__"),r.push(u)));return r}(t):void 0}function pe(t){return i(t)&&i(t.text)&&!1===t.isComment}function de(t,e){if(t){for(var n=Object.create(null),r=lt?Reflect.ownKeys(t):Object.keys(t),o=0;o0,a=t?!!t.$stable:!i,s=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(a&&n&&n!==r&&s===n.$key&&!i&&!n.$hasNormal)return n;for(var c in o={},t)t[c]&&"$"!==c[0]&&(o[c]=ve(e,c,t[c]))}else o={};for(var u in e)u in o||(o[u]=be(e,u));return t&&Object.isExtensible(t)&&(t._normalized=o),H(o,"$stable",a),H(o,"$key",s),H(o,"$hasNormal",i),o}function ve(t,e,n){var r=function(){var t=arguments.length?n.apply(null,arguments):n({});return(t=t&&"object"==typeof t&&!Array.isArray(t)?[t]:fe(t))&&(0===t.length||1===t.length&&t[0].isComment)?void 0:t};return n.proxy&&Object.defineProperty(t,e,{get:r,enumerable:!0,configurable:!0}),r}function be(t,e){return function(){return t[e]}}function _e(t,e){var n,r,o,a,s;if(Array.isArray(t)||"string"==typeof t)for(n=new Array(t.length),r=0,o=t.length;rdocument.createEvent("Event").timeStamp&&(pn=function(){return dn.now()})}function hn(){var t,e;for(fn=pn(),un=!0,on.sort((function(t,e){return t.id-e.id})),ln=0;lnln&&on[n].id>t.id;)n--;on.splice(n+1,0,t)}else on.push(t);cn||(cn=!0,re(hn))}}(this)},mn.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||c(t)||this.deep){var e=this.value;if(this.value=t,this.user)try{this.cb.call(this.vm,t,e)}catch(t){Ht(t,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,t,e)}}},mn.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},mn.prototype.depend=function(){for(var t=this.deps.length;t--;)this.deps[t].depend()},mn.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||_(this.vm._watchers,this);for(var t=this.deps.length;t--;)this.deps[t].removeSub(this);this.active=!1}};var vn={enumerable:!0,configurable:!0,get:L,set:L};function bn(t,e,n){vn.get=function(){return this[e][n]},vn.set=function(t){this[e][n]=t},Object.defineProperty(t,n,vn)}function _n(t){t._watchers=[];var e=t.$options;e.props&&function(t,e){var n=t.$options.propsData||{},r=t._props={},o=t.$options._propKeys=[];t.$parent&&At(!1);var i=function(i){o.push(i);var a=$t(i,e,n,t);Rt(r,i,a),i in t||bn(t,"_props",i)};for(var a in e)i(a);At(!0)}(t,e.props),e.methods&&function(t,e){t.$options.props;for(var n in e)t[n]="function"!=typeof e[n]?L:S(e[n],t)}(t,e.methods),e.data?function(t){var e=t.$options.data;l(e=t._data="function"==typeof e?function(t,e){gt();try{return t.call(e,e)}catch(t){return Ht(t,e,"data()"),{}}finally{mt()}}(e,t):e||{})||(e={});var n=Object.keys(e),r=t.$options.props,o=(t.$options.methods,n.length);for(;o--;){var i=n[o];0,r&&E(r,i)||q(i)||bn(t,"_data",i)}St(e,!0)}(t):St(t._data={},!0),e.computed&&function(t,e){var n=t._computedWatchers=Object.create(null),r=at();for(var o in e){var i=e[o],a="function"==typeof i?i:i.get;0,r||(n[o]=new mn(t,a||L,L,yn)),o in t||En(t,o,i)}}(t,e.computed),e.watch&&e.watch!==rt&&function(t,e){for(var n in e){var r=e[n];if(Array.isArray(r))for(var o=0;o-1:"string"==typeof t?t.split(",").indexOf(e)>-1:!!f(t)&&t.test(e)}function Nn(t,e){var n=t.cache,r=t.keys,o=t._vnode;for(var i in n){var a=n[i];if(a){var s=Rn(a.componentOptions);s&&!e(s)&&Ln(n,i,r,o)}}}function Ln(t,e,n,r){var o=t[e];!o||r&&o.tag===r.tag||o.componentInstance.$destroy(),t[e]=null,_(n,e)}!function(t){t.prototype._init=function(t){var e=this;e._uid=Cn++,e._isVue=!0,t&&t._isComponent?function(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r;var o=r.componentOptions;n.propsData=o.propsData,n._parentListeners=o.listeners,n._renderChildren=o.children,n._componentTag=o.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}(e,t):e.$options=Ft(An(e.constructor),t||{},e),e._renderProxy=e,e._self=e,function(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}(e),function(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&Je(t,e)}(e),function(t){t._vnode=null,t._staticTrees=null;var e=t.$options,n=t.$vnode=e._parentVnode,o=n&&n.context;t.$slots=he(e._renderChildren,o),t.$scopedSlots=r,t._c=function(e,n,r,o){return qe(t,e,n,r,o,!1)},t.$createElement=function(e,n,r,o){return qe(t,e,n,r,o,!0)};var i=n&&n.data;Rt(t,"$attrs",i&&i.attrs||r,null,!0),Rt(t,"$listeners",e._parentListeners||r,null,!0)}(e),rn(e,"beforeCreate"),function(t){var e=de(t.$options.inject,t);e&&(At(!1),Object.keys(e).forEach((function(n){Rt(t,n,e[n])})),At(!0))}(e),_n(e),function(t){var e=t.$options.provide;e&&(t._provided="function"==typeof e?e.call(t):e)}(e),rn(e,"created"),e.$options.el&&e.$mount(e.$options.el)}}(Tn),function(t){var e={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(t.prototype,"$data",e),Object.defineProperty(t.prototype,"$props",n),t.prototype.$set=Ot,t.prototype.$delete=Nt,t.prototype.$watch=function(t,e,n){if(l(e))return wn(this,t,e,n);(n=n||{}).user=!0;var r=new mn(this,t,e,n);if(n.immediate)try{e.call(this,r.value)}catch(t){Ht(t,this,'callback for immediate watcher "'+r.expression+'"')}return function(){r.teardown()}}}(Tn),function(t){var e=/^hook:/;t.prototype.$on=function(t,n){var r=this;if(Array.isArray(t))for(var o=0,i=t.length;o1?R(n):n;for(var r=R(arguments,1),o='event handler for "'+t+'"',i=0,a=n.length;iparseInt(this.max)&&Ln(a,s[0],s,this._vnode)),e.data.keepAlive=!0}return e||t&&t[0]}}};!function(t){var e={get:function(){return B}};Object.defineProperty(t,"config",e),t.util={warn:ft,extend:O,mergeOptions:Ft,defineReactive:Rt},t.set=Ot,t.delete=Nt,t.nextTick=re,t.observable=function(t){return St(t),t},t.options=Object.create(null),U.forEach((function(e){t.options[e+"s"]=Object.create(null)})),t.options._base=t,O(t.options.components,Dn),function(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=R(arguments,1);return n.unshift(this),"function"==typeof t.install?t.install.apply(t,n):"function"==typeof t&&t.apply(null,n),e.push(t),this}}(t),function(t){t.mixin=function(t){return this.options=Ft(this.options,t),this}}(t),Sn(t),function(t){U.forEach((function(e){t[e]=function(t,n){return n?("component"===e&&l(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&"function"==typeof n&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}}))}(t)}(Tn),Object.defineProperty(Tn.prototype,"$isServer",{get:at}),Object.defineProperty(Tn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(Tn,"FunctionalRenderContext",{value:De}),Tn.version="2.6.10";var Mn=m("style,class"),Pn=m("input,textarea,option,select,progress"),jn=function(t,e,n){return"value"===n&&Pn(t)&&"button"!==e||"selected"===n&&"option"===t||"checked"===n&&"input"===t||"muted"===n&&"video"===t},Fn=m("contenteditable,draggable,spellcheck"),Un=m("events,caret,typing,plaintext-only"),$n=function(t,e){return Gn(e)||"false"===e?"false":"contenteditable"===t&&Un(e)?e:"true"},Bn=m("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible"),zn="http://www.w3.org/1999/xlink",qn=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},Hn=function(t){return qn(t)?t.slice(6,t.length):""},Gn=function(t){return null==t||!1===t};function Vn(t){for(var e=t.data,n=t,r=t;i(r.componentInstance);)(r=r.componentInstance._vnode)&&r.data&&(e=Wn(r.data,e));for(;i(n=n.parent);)n&&n.data&&(e=Wn(e,n.data));return function(t,e){if(i(t)||i(e))return Yn(t,Kn(e));return""}(e.staticClass,e.class)}function Wn(t,e){return{staticClass:Yn(t.staticClass,e.staticClass),class:i(t.class)?[t.class,e.class]:e.class}}function Yn(t,e){return t?e?t+" "+e:t:e||""}function Kn(t){return Array.isArray(t)?function(t){for(var e,n="",r=0,o=t.length;r-1?yr(t,e,n):Bn(e)?Gn(n)?t.removeAttribute(e):(n="allowfullscreen"===e&&"EMBED"===t.tagName?"true":e,t.setAttribute(e,n)):Fn(e)?t.setAttribute(e,$n(e,n)):qn(e)?Gn(n)?t.removeAttributeNS(zn,Hn(e)):t.setAttributeNS(zn,e,n):yr(t,e,n)}function yr(t,e,n){if(Gn(n))t.removeAttribute(e);else{if(J&&!Q&&"TEXTAREA"===t.tagName&&"placeholder"===e&&""!==n&&!t.__ieph){var r=function(e){e.stopImmediatePropagation(),t.removeEventListener("input",r)};t.addEventListener("input",r),t.__ieph=!0}t.setAttribute(e,n)}}var Er={create:br,update:br};function xr(t,e){var n=e.elm,r=e.data,a=t.data;if(!(o(r.staticClass)&&o(r.class)&&(o(a)||o(a.staticClass)&&o(a.class)))){var s=Vn(e),c=n._transitionClasses;i(c)&&(s=Yn(s,Kn(c))),s!==n._prevClass&&(n.setAttribute("class",s),n._prevClass=s)}}var kr,wr,Cr,Ar,Tr,Sr,Rr={create:xr,update:xr},Or=/[\w).+\-_$\]]/;function Nr(t){var e,n,r,o,i,a=!1,s=!1,c=!1,u=!1,l=0,f=0,p=0,d=0;for(r=0;r=0&&" "===(g=t.charAt(h));h--);g&&Or.test(g)||(u=!0)}}else void 0===o?(d=r+1,o=t.slice(0,r).trim()):m();function m(){(i||(i=[])).push(t.slice(d,r).trim()),d=r+1}if(void 0===o?o=t.slice(0,r).trim():0!==d&&m(),i)for(r=0;r-1?{exp:t.slice(0,Ar),key:'"'+t.slice(Ar+1)+'"'}:{exp:t,key:null};wr=t,Ar=Tr=Sr=0;for(;!Yr();)Kr(Cr=Wr())?Zr(Cr):91===Cr&&Xr(Cr);return{exp:t.slice(0,Tr),key:t.slice(Tr+1,Sr)}}(t);return null===n.key?t+"="+e:"$set("+n.exp+", "+n.key+", "+e+")"}function Wr(){return wr.charCodeAt(++Ar)}function Yr(){return Ar>=kr}function Kr(t){return 34===t||39===t}function Xr(t){var e=1;for(Tr=Ar;!Yr();)if(Kr(t=Wr()))Zr(t);else if(91===t&&e++,93===t&&e--,0===e){Sr=Ar;break}}function Zr(t){for(var e=t;!Yr()&&(t=Wr())!==e;);}var Jr,Qr="__r",to="__c";function eo(t,e,n){var r=Jr;return function o(){var i=e.apply(null,arguments);null!==i&&oo(t,o,n,r)}}var no=Kt&&!(nt&&Number(nt[1])<=53);function ro(t,e,n,r){if(no){var o=fn,i=e;e=i._wrapper=function(t){if(t.target===t.currentTarget||t.timeStamp>=o||t.timeStamp<=0||t.target.ownerDocument!==document)return i.apply(this,arguments)}}Jr.addEventListener(t,e,ot?{capture:n,passive:r}:n)}function oo(t,e,n,r){(r||Jr).removeEventListener(t,e._wrapper||e,n)}function io(t,e){if(!o(t.data.on)||!o(e.data.on)){var n=e.data.on||{},r=t.data.on||{};Jr=e.elm,function(t){if(i(t[Qr])){var e=J?"change":"input";t[e]=[].concat(t[Qr],t[e]||[]),delete t[Qr]}i(t[to])&&(t.change=[].concat(t[to],t.change||[]),delete t[to])}(n),ce(n,r,ro,oo,eo,e.context),Jr=void 0}}var ao,so={create:io,update:io};function co(t,e){if(!o(t.data.domProps)||!o(e.data.domProps)){var n,r,a=e.elm,s=t.data.domProps||{},c=e.data.domProps||{};for(n in i(c.__ob__)&&(c=e.data.domProps=O({},c)),s)n in c||(a[n]="");for(n in c){if(r=c[n],"textContent"===n||"innerHTML"===n){if(e.children&&(e.children.length=0),r===s[n])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===n&&"PROGRESS"!==a.tagName){a._value=r;var u=o(r)?"":String(r);uo(a,u)&&(a.value=u)}else if("innerHTML"===n&&Jn(a.tagName)&&o(a.innerHTML)){(ao=ao||document.createElement("div")).innerHTML=""+r+"";for(var l=ao.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;l.firstChild;)a.appendChild(l.firstChild)}else if(r!==s[n])try{a[n]=r}catch(t){}}}}function uo(t,e){return!t.composing&&("OPTION"===t.tagName||function(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}(t,e)||function(t,e){var n=t.value,r=t._vModifiers;if(i(r)){if(r.number)return g(n)!==g(e);if(r.trim)return n.trim()!==e.trim()}return n!==e}(t,e))}var lo={create:co,update:co},fo=x((function(t){var e={},n=/:(.+)/;return t.split(/;(?![^(]*\))/g).forEach((function(t){if(t){var r=t.split(n);r.length>1&&(e[r[0].trim()]=r[1].trim())}})),e}));function po(t){var e=ho(t.style);return t.staticStyle?O(t.staticStyle,e):e}function ho(t){return Array.isArray(t)?N(t):"string"==typeof t?fo(t):t}var go,mo=/^--/,vo=/\s*!important$/,bo=function(t,e,n){if(mo.test(e))t.style.setProperty(e,n);else if(vo.test(n))t.style.setProperty(T(e),n.replace(vo,""),"important");else{var r=yo(e);if(Array.isArray(n))for(var o=0,i=n.length;o-1?e.split(ko).forEach((function(e){return t.classList.add(e)})):t.classList.add(e);else{var n=" "+(t.getAttribute("class")||"")+" ";n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function Co(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(ko).forEach((function(e){return t.classList.remove(e)})):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" "+(t.getAttribute("class")||"")+" ",r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?t.setAttribute("class",n):t.removeAttribute("class")}}function Ao(t){if(t){if("object"==typeof t){var e={};return!1!==t.css&&O(e,To(t.name||"v")),O(e,t),e}return"string"==typeof t?To(t):void 0}}var To=x((function(t){return{enterClass:t+"-enter",enterToClass:t+"-enter-to",enterActiveClass:t+"-enter-active",leaveClass:t+"-leave",leaveToClass:t+"-leave-to",leaveActiveClass:t+"-leave-active"}})),So=Y&&!Q,Ro="transition",Oo="animation",No="transition",Lo="transitionend",Io="animation",Do="animationend";So&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(No="WebkitTransition",Lo="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(Io="WebkitAnimation",Do="webkitAnimationEnd"));var Mo=Y?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function Po(t){Mo((function(){Mo(t)}))}function jo(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),wo(t,e))}function Fo(t,e){t._transitionClasses&&_(t._transitionClasses,e),Co(t,e)}function Uo(t,e,n){var r=Bo(t,e),o=r.type,i=r.timeout,a=r.propCount;if(!o)return n();var s=o===Ro?Lo:Do,c=0,u=function(){t.removeEventListener(s,l),n()},l=function(e){e.target===t&&++c>=a&&u()};setTimeout((function(){c0&&(n=Ro,l=a,f=i.length):e===Oo?u>0&&(n=Oo,l=u,f=c.length):f=(n=(l=Math.max(a,u))>0?a>u?Ro:Oo:null)?n===Ro?i.length:c.length:0,{type:n,timeout:l,propCount:f,hasTransform:n===Ro&&$o.test(r[No+"Property"])}}function zo(t,e){for(;t.length1}function Yo(t,e){!0!==e.data.show&&Ho(e)}var Ko=function(t){var e,n,r={},c=t.modules,u=t.nodeOps;for(e=0;eh?_(t,o(n[v+1])?null:n[v+1].elm,n,d,v,r):d>v&&E(0,e,p,h)}(p,m,v,n,l):i(v)?(i(t.text)&&u.setTextContent(p,""),_(p,null,v,0,v.length-1,n)):i(m)?E(0,m,0,m.length-1):i(t.text)&&u.setTextContent(p,""):t.text!==e.text&&u.setTextContent(p,e.text),i(h)&&i(d=h.hook)&&i(d=d.postpatch)&&d(t,e)}}}function C(t,e,n){if(a(n)&&i(t.parent))t.parent.data.pendingInsert=e;else for(var r=0;r-1,a.selected!==i&&(a.selected=i);else if(M(ti(a),r))return void(t.selectedIndex!==s&&(t.selectedIndex=s));o||(t.selectedIndex=-1)}}function Qo(t,e){return e.every((function(e){return!M(e,t)}))}function ti(t){return"_value"in t?t._value:t.value}function ei(t){t.target.composing=!0}function ni(t){t.target.composing&&(t.target.composing=!1,ri(t.target,"input"))}function ri(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function oi(t){return!t.componentInstance||t.data&&t.data.transition?t:oi(t.componentInstance._vnode)}var ii={model:Xo,show:{bind:function(t,e,n){var r=e.value,o=(n=oi(n)).data&&n.data.transition,i=t.__vOriginalDisplay="none"===t.style.display?"":t.style.display;r&&o?(n.data.show=!0,Ho(n,(function(){t.style.display=i}))):t.style.display=r?i:"none"},update:function(t,e,n){var r=e.value;!r!=!e.oldValue&&((n=oi(n)).data&&n.data.transition?(n.data.show=!0,r?Ho(n,(function(){t.style.display=t.__vOriginalDisplay})):Go(n,(function(){t.style.display="none"}))):t.style.display=r?t.__vOriginalDisplay:"none")},unbind:function(t,e,n,r,o){o||(t.style.display=t.__vOriginalDisplay)}}},ai={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function si(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?si(Ye(e.children)):t}function ci(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var o=n._parentListeners;for(var i in o)e[w(i)]=o[i];return e}function ui(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}var li=function(t){return t.tag||We(t)},fi=function(t){return"show"===t.name},pi={name:"transition",props:ai,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(li)).length){0;var r=this.mode;0;var o=n[0];if(function(t){for(;t=t.parent;)if(t.data.transition)return!0}(this.$vnode))return o;var i=si(o);if(!i)return o;if(this._leaving)return ui(t,o);var a="__transition-"+this._uid+"-";i.key=null==i.key?i.isComment?a+"comment":a+i.tag:s(i.key)?0===String(i.key).indexOf(a)?i.key:a+i.key:i.key;var c=(i.data||(i.data={})).transition=ci(this),u=this._vnode,l=si(u);if(i.data.directives&&i.data.directives.some(fi)&&(i.data.show=!0),l&&l.data&&!function(t,e){return e.key===t.key&&e.tag===t.tag}(i,l)&&!We(l)&&(!l.componentInstance||!l.componentInstance._vnode.isComment)){var f=l.data.transition=O({},c);if("out-in"===r)return this._leaving=!0,ue(f,"afterLeave",(function(){e._leaving=!1,e.$forceUpdate()})),ui(t,o);if("in-out"===r){if(We(i))return u;var p,d=function(){p()};ue(c,"afterEnter",d),ue(c,"enterCancelled",d),ue(f,"delayLeave",(function(t){p=t}))}}return o}}},di=O({tag:String,moveClass:String},ai);function hi(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function gi(t){t.data.newPos=t.elm.getBoundingClientRect()}function mi(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,o=e.top-n.top;if(r||o){t.data.moved=!0;var i=t.elm.style;i.transform=i.WebkitTransform="translate("+r+"px,"+o+"px)",i.transitionDuration="0s"}}delete di.mode;var vi={Transition:pi,TransitionGroup:{props:di,beforeMount:function(){var t=this,e=this._update;this._update=function(n,r){var o=tn(t);t.__patch__(t._vnode,t.kept,!1,!0),t._vnode=t.kept,o(),e.call(t,n,r)}},render:function(t){for(var e=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,o=this.$slots.default||[],i=this.children=[],a=ci(this),s=0;s-1?er[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:er[t]=/HTMLUnknownElement/.test(e.toString())},O(Tn.options.directives,ii),O(Tn.options.components,vi),Tn.prototype.__patch__=Y?Ko:L,Tn.prototype.$mount=function(t,e){return function(t,e,n){var r;return t.$el=e,t.$options.render||(t.$options.render=_t),rn(t,"beforeMount"),r=function(){t._update(t._render(),n)},new mn(t,r,L,{before:function(){t._isMounted&&!t._isDestroyed&&rn(t,"beforeUpdate")}},!0),n=!1,null==t.$vnode&&(t._isMounted=!0,rn(t,"mounted")),t}(this,t=t&&Y?rr(t):void 0,e)},Y&&setTimeout((function(){B.devtools&&st&&st.emit("init",Tn)}),0);var bi=/\{\{((?:.|\r?\n)+?)\}\}/g,_i=/[-.*+?^${}()|[\]\/\\]/g,yi=x((function(t){var e=t[0].replace(_i,"\\$&"),n=t[1].replace(_i,"\\$&");return new RegExp(e+"((?:.|\\n)+?)"+n,"g")}));var Ei={staticKeys:["staticClass"],transformNode:function(t,e){e.warn;var n=zr(t,"class");n&&(t.staticClass=JSON.stringify(n));var r=Br(t,"class",!1);r&&(t.classBinding=r)},genData:function(t){var e="";return t.staticClass&&(e+="staticClass:"+t.staticClass+","),t.classBinding&&(e+="class:"+t.classBinding+","),e}};var xi,ki={staticKeys:["staticStyle"],transformNode:function(t,e){e.warn;var n=zr(t,"style");n&&(t.staticStyle=JSON.stringify(fo(n)));var r=Br(t,"style",!1);r&&(t.styleBinding=r)},genData:function(t){var e="";return t.staticStyle&&(e+="staticStyle:"+t.staticStyle+","),t.styleBinding&&(e+="style:("+t.styleBinding+"),"),e}},wi=function(t){return(xi=xi||document.createElement("div")).innerHTML=t,xi.textContent},Ci=m("area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),Ai=m("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),Ti=m("address,article,aside,base,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track"),Si=/^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Ri=/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Oi="[a-zA-Z_][\\-\\.0-9_a-zA-Z"+z.source+"]*",Ni="((?:"+Oi+"\\:)?"+Oi+")",Li=new RegExp("^<"+Ni),Ii=/^\s*(\/?)>/,Di=new RegExp("^<\\/"+Ni+"[^>]*>"),Mi=/^]+>/i,Pi=/^",""":'"',"&":"&"," ":"\n"," ":"\t","'":"'"},Bi=/&(?:lt|gt|quot|amp|#39);/g,zi=/&(?:lt|gt|quot|amp|#39|#10|#9);/g,qi=m("pre,textarea",!0),Hi=function(t,e){return t&&qi(t)&&"\n"===e[0]};function Gi(t,e){var n=e?zi:Bi;return t.replace(n,(function(t){return $i[t]}))}var Vi,Wi,Yi,Ki,Xi,Zi,Ji,Qi,ta=/^@|^v-on:/,ea=/^v-|^@|^:/,na=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,ra=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,oa=/^\(|\)$/g,ia=/^\[.*\]$/,aa=/:(.*)$/,sa=/^:|^\.|^v-bind:/,ca=/\.[^.\]]+(?=[^\]]*$)/g,ua=/^v-slot(:|$)|^#/,la=/[\r\n]/,fa=/\s+/g,pa=x(wi),da="_empty_";function ha(t,e,n){return{type:1,tag:t,attrsList:e,attrsMap:Ea(e),rawAttrsMap:{},parent:n,children:[]}}function ga(t,e){Vi=e.warn||Ir,Zi=e.isPreTag||I,Ji=e.mustUseProp||I,Qi=e.getTagNamespace||I;var n=e.isReservedTag||I;(function(t){return!!t.component||!n(t.tag)}),Yi=Dr(e.modules,"transformNode"),Ki=Dr(e.modules,"preTransformNode"),Xi=Dr(e.modules,"postTransformNode"),Wi=e.delimiters;var r,o,i=[],a=!1!==e.preserveWhitespace,s=e.whitespace,c=!1,u=!1;function l(t){if(f(t),c||t.processed||(t=ma(t,e)),i.length||t===r||r.if&&(t.elseif||t.else)&&ba(r,{exp:t.elseif,block:t}),o&&!t.forbidden)if(t.elseif||t.else)a=t,(s=function(t){for(var e=t.length;e--;){if(1===t[e].type)return t[e];t.pop()}}(o.children))&&s.if&&ba(s,{exp:a.elseif,block:a});else{if(t.slotScope){var n=t.slotTarget||'"default"';(o.scopedSlots||(o.scopedSlots={}))[n]=t}o.children.push(t),t.parent=o}var a,s;t.children=t.children.filter((function(t){return!t.slotScope})),f(t),t.pre&&(c=!1),Zi(t.tag)&&(u=!1);for(var l=0;l]*>)","i")),p=t.replace(f,(function(t,n,r){return u=r.length,Fi(l)||"noscript"===l||(n=n.replace(//g,"$1").replace(//g,"$1")),Hi(l,n)&&(n=n.slice(1)),e.chars&&e.chars(n),""}));c+=t.length-p.length,t=p,A(l,c-u,c)}else{var d=t.indexOf("<");if(0===d){if(Pi.test(t)){var h=t.indexOf("--\x3e");if(h>=0){e.shouldKeepComment&&e.comment(t.substring(4,h),c,c+h+3),k(h+3);continue}}if(ji.test(t)){var g=t.indexOf("]>");if(g>=0){k(g+2);continue}}var m=t.match(Mi);if(m){k(m[0].length);continue}var v=t.match(Di);if(v){var b=c;k(v[0].length),A(v[1],b,c);continue}var _=w();if(_){C(_),Hi(_.tagName,t)&&k(1);continue}}var y=void 0,E=void 0,x=void 0;if(d>=0){for(E=t.slice(d);!(Di.test(E)||Li.test(E)||Pi.test(E)||ji.test(E)||(x=E.indexOf("<",1))<0);)d+=x,E=t.slice(d);y=t.substring(0,d)}d<0&&(y=t),y&&k(y.length),e.chars&&y&&e.chars(y,c-y.length,c)}if(t===n){e.chars&&e.chars(t);break}}function k(e){c+=e,t=t.substring(e)}function w(){var e=t.match(Li);if(e){var n,r,o={tagName:e[1],attrs:[],start:c};for(k(e[0].length);!(n=t.match(Ii))&&(r=t.match(Ri)||t.match(Si));)r.start=c,k(r[0].length),r.end=c,o.attrs.push(r);if(n)return o.unarySlash=n[1],k(n[0].length),o.end=c,o}}function C(t){var n=t.tagName,c=t.unarySlash;i&&("p"===r&&Ti(n)&&A(r),s(n)&&r===n&&A(n));for(var u=a(n)||!!c,l=t.attrs.length,f=new Array(l),p=0;p=0&&o[a].lowerCasedTag!==s;a--);else a=0;if(a>=0){for(var u=o.length-1;u>=a;u--)e.end&&e.end(o[u].tag,n,i);o.length=a,r=a&&o[a-1].tag}else"br"===s?e.start&&e.start(t,[],!0,n,i):"p"===s&&(e.start&&e.start(t,[],!1,n,i),e.end&&e.end(t,n,i))}A()}(t,{warn:Vi,expectHTML:e.expectHTML,isUnaryTag:e.isUnaryTag,canBeLeftOpenTag:e.canBeLeftOpenTag,shouldDecodeNewlines:e.shouldDecodeNewlines,shouldDecodeNewlinesForHref:e.shouldDecodeNewlinesForHref,shouldKeepComment:e.comments,outputSourceRange:e.outputSourceRange,start:function(t,n,a,s,f){var p=o&&o.ns||Qi(t);J&&"svg"===p&&(n=function(t){for(var e=[],n=0;nc&&(s.push(i=t.slice(c,o)),a.push(JSON.stringify(i)));var u=Nr(r[1].trim());a.push("_s("+u+")"),s.push({"@binding":u}),c=o+r[0].length}return c-1"+("true"===i?":("+e+")":":_q("+e+","+i+")")),$r(t,"change","var $$a="+e+",$$el=$event.target,$$c=$$el.checked?("+i+"):("+a+");if(Array.isArray($$a)){var $$v="+(r?"_n("+o+")":o)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Vr(e,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Vr(e,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Vr(e,"$$c")+"}",null,!0)}(t,r,o);else if("input"===i&&"radio"===a)!function(t,e,n){var r=n&&n.number,o=Br(t,"value")||"null";Mr(t,"checked","_q("+e+","+(o=r?"_n("+o+")":o)+")"),$r(t,"change",Vr(e,o),null,!0)}(t,r,o);else if("input"===i||"textarea"===i)!function(t,e,n){var r=t.attrsMap.type;0;var o=n||{},i=o.lazy,a=o.number,s=o.trim,c=!i&&"range"!==r,u=i?"change":"range"===r?Qr:"input",l="$event.target.value";s&&(l="$event.target.value.trim()");a&&(l="_n("+l+")");var f=Vr(e,l);c&&(f="if($event.target.composing)return;"+f);Mr(t,"value","("+e+")"),$r(t,u,f,null,!0),(s||a)&&$r(t,"blur","$forceUpdate()")}(t,r,o);else{if(!B.isReservedTag(i))return Gr(t,r,o),!1}return!0},text:function(t,e){e.value&&Mr(t,"textContent","_s("+e.value+")",e)},html:function(t,e){e.value&&Mr(t,"innerHTML","_s("+e.value+")",e)}},isPreTag:function(t){return"pre"===t},isUnaryTag:Ci,mustUseProp:jn,canBeLeftOpenTag:Ai,isReservedTag:Qn,getTagNamespace:tr,staticKeys:function(t){return t.reduce((function(t,e){return t.concat(e.staticKeys||[])}),[]).join(",")}(Ca)},Ra=x((function(t){return m("type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap"+(t?","+t:""))}));function Oa(t,e){t&&(Aa=Ra(e.staticKeys||""),Ta=e.isReservedTag||I,function t(e){e.static=function(t){if(2===t.type)return!1;if(3===t.type)return!0;return!(!t.pre&&(t.hasBindings||t.if||t.for||v(t.tag)||!Ta(t.tag)||function(t){for(;t.parent;){if("template"!==(t=t.parent).tag)return!1;if(t.for)return!0}return!1}(t)||!Object.keys(t).every(Aa)))}(e);if(1===e.type){if(!Ta(e.tag)&&"slot"!==e.tag&&null==e.attrsMap["inline-template"])return;for(var n=0,r=e.children.length;n|^function\s*(?:[\w$]+)?\s*\(/,La=/\([^)]*?\);*$/,Ia=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,Da={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},Ma={esc:["Esc","Escape"],tab:"Tab",enter:"Enter",space:[" ","Spacebar"],up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete","Del"]},Pa=function(t){return"if("+t+")return null;"},ja={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:Pa("$event.target !== $event.currentTarget"),ctrl:Pa("!$event.ctrlKey"),shift:Pa("!$event.shiftKey"),alt:Pa("!$event.altKey"),meta:Pa("!$event.metaKey"),left:Pa("'button' in $event && $event.button !== 0"),middle:Pa("'button' in $event && $event.button !== 1"),right:Pa("'button' in $event && $event.button !== 2")};function Fa(t,e){var n=e?"nativeOn:":"on:",r="",o="";for(var i in t){var a=Ua(t[i]);t[i]&&t[i].dynamic?o+=i+","+a+",":r+='"'+i+'":'+a+","}return r="{"+r.slice(0,-1)+"}",o?n+"_d("+r+",["+o.slice(0,-1)+"])":n+r}function Ua(t){if(!t)return"function(){}";if(Array.isArray(t))return"["+t.map((function(t){return Ua(t)})).join(",")+"]";var e=Ia.test(t.value),n=Na.test(t.value),r=Ia.test(t.value.replace(La,""));if(t.modifiers){var o="",i="",a=[];for(var s in t.modifiers)if(ja[s])i+=ja[s],Da[s]&&a.push(s);else if("exact"===s){var c=t.modifiers;i+=Pa(["ctrl","shift","alt","meta"].filter((function(t){return!c[t]})).map((function(t){return"$event."+t+"Key"})).join("||"))}else a.push(s);return a.length&&(o+=function(t){return"if(!$event.type.indexOf('key')&&"+t.map($a).join("&&")+")return null;"}(a)),i&&(o+=i),"function($event){"+o+(e?"return "+t.value+"($event)":n?"return ("+t.value+")($event)":r?"return "+t.value:t.value)+"}"}return e||n?t.value:"function($event){"+(r?"return "+t.value:t.value)+"}"}function $a(t){var e=parseInt(t,10);if(e)return"$event.keyCode!=="+e;var n=Da[t],r=Ma[t];return"_k($event.keyCode,"+JSON.stringify(t)+","+JSON.stringify(n)+",$event.key,"+JSON.stringify(r)+")"}var Ba={on:function(t,e){t.wrapListeners=function(t){return"_g("+t+","+e.value+")"}},bind:function(t,e){t.wrapData=function(n){return"_b("+n+",'"+t.tag+"',"+e.value+","+(e.modifiers&&e.modifiers.prop?"true":"false")+(e.modifiers&&e.modifiers.sync?",true":"")+")"}},cloak:L},za=function(t){this.options=t,this.warn=t.warn||Ir,this.transforms=Dr(t.modules,"transformCode"),this.dataGenFns=Dr(t.modules,"genData"),this.directives=O(O({},Ba),t.directives);var e=t.isReservedTag||I;this.maybeComponent=function(t){return!!t.component||!e(t.tag)},this.onceId=0,this.staticRenderFns=[],this.pre=!1};function qa(t,e){var n=new za(e);return{render:"with(this){return "+(t?Ha(t,n):'_c("div")')+"}",staticRenderFns:n.staticRenderFns}}function Ha(t,e){if(t.parent&&(t.pre=t.pre||t.parent.pre),t.staticRoot&&!t.staticProcessed)return Ga(t,e);if(t.once&&!t.onceProcessed)return Va(t,e);if(t.for&&!t.forProcessed)return Ya(t,e);if(t.if&&!t.ifProcessed)return Wa(t,e);if("template"!==t.tag||t.slotTarget||e.pre){if("slot"===t.tag)return function(t,e){var n=t.slotName||'"default"',r=Ja(t,e),o="_t("+n+(r?","+r:""),i=t.attrs||t.dynamicAttrs?es((t.attrs||[]).concat(t.dynamicAttrs||[]).map((function(t){return{name:w(t.name),value:t.value,dynamic:t.dynamic}}))):null,a=t.attrsMap["v-bind"];!i&&!a||r||(o+=",null");i&&(o+=","+i);a&&(o+=(i?"":",null")+","+a);return o+")"}(t,e);var n;if(t.component)n=function(t,e,n){var r=e.inlineTemplate?null:Ja(e,n,!0);return"_c("+t+","+Ka(e,n)+(r?","+r:"")+")"}(t.component,t,e);else{var r;(!t.plain||t.pre&&e.maybeComponent(t))&&(r=Ka(t,e));var o=t.inlineTemplate?null:Ja(t,e,!0);n="_c('"+t.tag+"'"+(r?","+r:"")+(o?","+o:"")+")"}for(var i=0;i>>0}(a):"")+")"}(t,t.scopedSlots,e)+","),t.model&&(n+="model:{value:"+t.model.value+",callback:"+t.model.callback+",expression:"+t.model.expression+"},"),t.inlineTemplate){var i=function(t,e){var n=t.children[0];0;if(n&&1===n.type){var r=qa(n,e.options);return"inlineTemplate:{render:function(){"+r.render+"},staticRenderFns:["+r.staticRenderFns.map((function(t){return"function(){"+t+"}"})).join(",")+"]}"}}(t,e);i&&(n+=i+",")}return n=n.replace(/,$/,"")+"}",t.dynamicAttrs&&(n="_b("+n+',"'+t.tag+'",'+es(t.dynamicAttrs)+")"),t.wrapData&&(n=t.wrapData(n)),t.wrapListeners&&(n=t.wrapListeners(n)),n}function Xa(t){return 1===t.type&&("slot"===t.tag||t.children.some(Xa))}function Za(t,e){var n=t.attrsMap["slot-scope"];if(t.if&&!t.ifProcessed&&!n)return Wa(t,e,Za,"null");if(t.for&&!t.forProcessed)return Ya(t,e,Za);var r=t.slotScope===da?"":String(t.slotScope),o="function("+r+"){return "+("template"===t.tag?t.if&&n?"("+t.if+")?"+(Ja(t,e)||"undefined")+":undefined":Ja(t,e)||"undefined":Ha(t,e))+"}",i=r?"":",proxy:true";return"{key:"+(t.slotTarget||'"default"')+",fn:"+o+i+"}"}function Ja(t,e,n,r,o){var i=t.children;if(i.length){var a=i[0];if(1===i.length&&a.for&&"template"!==a.tag&&"slot"!==a.tag){var s=n?e.maybeComponent(a)?",1":",0":"";return""+(r||Ha)(a,e)+s}var c=n?function(t,e){for(var n=0,r=0;r':'
',as.innerHTML.indexOf(" ")>0}var ls=!!Y&&us(!1),fs=!!Y&&us(!0),ps=x((function(t){var e=rr(t);return e&&e.innerHTML})),ds=Tn.prototype.$mount;Tn.prototype.$mount=function(t,e){if((t=t&&rr(t))===document.body||t===document.documentElement)return this;var n=this.$options;if(!n.render){var r=n.template;if(r)if("string"==typeof r)"#"===r.charAt(0)&&(r=ps(r));else{if(!r.nodeType)return this;r=r.innerHTML}else t&&(r=function(t){if(t.outerHTML)return t.outerHTML;var e=document.createElement("div");return e.appendChild(t.cloneNode(!0)),e.innerHTML}(t));if(r){0;var o=cs(r,{outputSourceRange:!1,shouldDecodeNewlines:ls,shouldDecodeNewlinesForHref:fs,delimiters:n.delimiters,comments:n.comments},this),i=o.render,a=o.staticRenderFns;n.render=i,n.staticRenderFns=a}}return ds.call(this,t,e)},Tn.compile=cs,e.a=Tn}).call(this,n(11),n(158).setImmediate)},function(t,e,n){var r=n(71),o="object"==typeof self&&self&&self.Object===Object&&self,i=r||o||Function("return this")();t.exports=i},function(t,e){var n=Array.isArray;t.exports=n},function(t,e,n){t.exports=n(100)},function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e,n){var r=n(201),o=n(204);t.exports=function(t,e){var n=o(t,e);return r(n)?n:void 0}},function(t,e,n){var r=n(172)("toUpperCase");t.exports=r},function(t,e,n){"use strict";var r={props:{lineNumber:{required:!0}}},o=n(0),i=Object(o.a)(r,(function(){var t=this.$createElement,e=this._self._c||t;return e("span",{staticClass:"ui-line-number"},[this._v("\n :"),e("span",{staticClass:"font-mono"},[this._v(this._s(this.lineNumber))])])}),[],!1,null,null,null);e.a=i.exports},function(t,e,n){"use strict";var r={props:{name:{required:!0},method:{default:null}},data:function(){return{segments:[],segmentsClass:""}},watch:{name:{immediate:!0,handler:function(){this.segments=this.name.split("\\"),this.segmentsClass=this.segments.pop()}}}},o=n(0),i=Object(o.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("span",{staticClass:"ui-exception-class"},[t._l(t.segments,(function(e,r){return n("span",{key:r,staticClass:"opacity-75"},[t._v(t._s(e)+"\\"),n("wbr")])})),n("span",[t._v(t._s(t.segmentsClass)),n("wbr")]),t.method?n("span",{staticClass:"opacity-75"},[t._v("::"+t._s(t.method))]):t._e()],2)}),[],!1,null,null,null);e.a=i.exports},function(t,e,n){var r=n(217);t.exports=function(t){return t&&t.length?r(t):[]}},function(t,e,n){var r=n(70);t.exports=function(t){return null==t?"":r(t)}},function(t,e,n){var r=n(23),o=n(177),i=n(178),a="[object Null]",s="[object Undefined]",c=r?r.toStringTag:void 0;t.exports=function(t){return null==t?void 0===t?s:a:c&&c in Object(t)?o(t):i(t)}},function(t,e){t.exports=function(t){return null!=t&&"object"==typeof t}},function(t,e){t.exports=function(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}},function(t,e){function n(t,e,n,r,o,i,a){try{var s=t[i](a),c=s.value}catch(t){return void n(t)}s.done?e(c):Promise.resolve(c).then(r,o)}t.exports=function(t){return function(){var e=this,r=arguments;return new Promise((function(o,i){var a=t.apply(e,r);function s(t){n(a,o,i,s,c,"next",t)}function c(t){n(a,o,i,s,c,"throw",t)}s(void 0)}))}}},function(t,e){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,e,n){var r=n(8).Symbol;t.exports=r},function(t,e,n){var r=n(18),o=n(19),i="[object Symbol]";t.exports=function(t){return"symbol"==typeof t||o(t)&&r(t)==i}},function(t,e,n){"use strict";e.__esModule=!0;var r=c(n(181)),o=c(n(39)),i=c(n(186)),a=c(n(195)),s=c(n(196));function c(t){return t&&t.__esModule?t:{default:t}}var u=function(){function t(e,n){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.cfg=e||{},this.indentation=new i.default(this.cfg.indent),this.inlineBlock=new a.default,this.params=new s.default(this.cfg.params),this.tokenizer=n,this.previousReservedWord={},this.tokens=[],this.index=0}return t.prototype.format=function(t){return this.tokens=this.tokenizer.tokenize(t),this.getFormattedQueryFromTokens().trim()},t.prototype.getFormattedQueryFromTokens=function(){var t=this,e="";return this.tokens.forEach((function(n,r){t.index=r,n.type===o.default.WHITESPACE||(n.type===o.default.LINE_COMMENT?e=t.formatLineComment(n,e):n.type===o.default.BLOCK_COMMENT?e=t.formatBlockComment(n,e):n.type===o.default.RESERVED_TOPLEVEL?(e=t.formatToplevelReservedWord(n,e),t.previousReservedWord=n):n.type===o.default.RESERVED_NEWLINE?(e=t.formatNewlineReservedWord(n,e),t.previousReservedWord=n):n.type===o.default.RESERVED?(e=t.formatWithSpaces(n,e),t.previousReservedWord=n):e=n.type===o.default.OPEN_PAREN?t.formatOpeningParentheses(n,e):n.type===o.default.CLOSE_PAREN?t.formatClosingParentheses(n,e):n.type===o.default.PLACEHOLDER?t.formatPlaceholder(n,e):","===n.value?t.formatComma(n,e):":"===n.value?t.formatWithSpaceAfter(n,e):"."===n.value?t.formatWithoutSpaces(n,e):";"===n.value?t.formatQuerySeparator(n,e):t.formatWithSpaces(n,e))})),e},t.prototype.formatLineComment=function(t,e){return this.addNewline(e+t.value)},t.prototype.formatBlockComment=function(t,e){return this.addNewline(this.addNewline(e)+this.indentComment(t.value))},t.prototype.indentComment=function(t){return t.replace(/\n/g,"\n"+this.indentation.getIndent())},t.prototype.formatToplevelReservedWord=function(t,e){return this.indentation.decreaseTopLevel(),e=this.addNewline(e),this.indentation.increaseToplevel(),e+=this.equalizeWhitespace(t.value),this.addNewline(e)},t.prototype.formatNewlineReservedWord=function(t,e){return this.addNewline(e)+this.equalizeWhitespace(t.value)+" "},t.prototype.equalizeWhitespace=function(t){return t.replace(/\s+/g," ")},t.prototype.formatOpeningParentheses=function(t,e){return[o.default.WHITESPACE,o.default.OPEN_PAREN,o.default.LINE_COMMENT].includes(this.previousToken().type)||(e=(0,r.default)(e)),e+=t.value,this.inlineBlock.beginIfPossible(this.tokens,this.index),this.inlineBlock.isActive()||(this.indentation.increaseBlockLevel(),e=this.addNewline(e)),e},t.prototype.formatClosingParentheses=function(t,e){return this.inlineBlock.isActive()?(this.inlineBlock.end(),this.formatWithSpaceAfter(t,e)):(this.indentation.decreaseBlockLevel(),this.formatWithSpaces(t,this.addNewline(e)))},t.prototype.formatPlaceholder=function(t,e){return e+this.params.get(t)+" "},t.prototype.formatComma=function(t,e){return e=this.trimTrailingWhitespace(e)+t.value+" ",this.inlineBlock.isActive()?e:/^LIMIT$/i.test(this.previousReservedWord.value)?e:this.addNewline(e)},t.prototype.formatWithSpaceAfter=function(t,e){return this.trimTrailingWhitespace(e)+t.value+" "},t.prototype.formatWithoutSpaces=function(t,e){return this.trimTrailingWhitespace(e)+t.value},t.prototype.formatWithSpaces=function(t,e){return e+t.value+" "},t.prototype.formatQuerySeparator=function(t,e){return this.trimTrailingWhitespace(e)+t.value+"\n"},t.prototype.addNewline=function(t){return(0,r.default)(t)+"\n"+this.indentation.getIndent()},t.prototype.trimTrailingWhitespace=function(t){return this.previousNonWhitespaceToken().type===o.default.LINE_COMMENT?(0,r.default)(t)+"\n":(0,r.default)(t)},t.prototype.previousNonWhitespaceToken=function(){for(var t=1;this.previousToken(t).type===o.default.WHITESPACE;)t++;return this.previousToken(t)},t.prototype.previousToken=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1;return this.tokens[this.index-t]||{}},t}();e.default=u,t.exports=e.default},function(t,e,n){"use strict";e.__esModule=!0;var r=a(n(197)),o=a(n(212)),i=a(n(39));function a(t){return t&&t.__esModule?t:{default:t}}var s=function(){function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.WHITESPACE_REGEX=/^(\s+)/,this.NUMBER_REGEX=/^((-\s*)?[0-9]+(\.[0-9]+)?|0x[0-9a-fA-F]+|0b[01]+)\b/,this.OPERATOR_REGEX=/^(!=|<>|==|<=|>=|!<|!>|\|\||::|->>|->|~~\*|~~|!~~\*|!~~|~\*|!~\*|!~|.)/,this.BLOCK_COMMENT_REGEX=/^(\/\*[^]*?(?:\*\/|$))/,this.LINE_COMMENT_REGEX=this.createLineCommentRegex(e.lineCommentTypes),this.RESERVED_TOPLEVEL_REGEX=this.createReservedWordRegex(e.reservedToplevelWords),this.RESERVED_NEWLINE_REGEX=this.createReservedWordRegex(e.reservedNewlineWords),this.RESERVED_PLAIN_REGEX=this.createReservedWordRegex(e.reservedWords),this.WORD_REGEX=this.createWordRegex(e.specialWordChars),this.STRING_REGEX=this.createStringRegex(e.stringTypes),this.OPEN_PAREN_REGEX=this.createParenRegex(e.openParens),this.CLOSE_PAREN_REGEX=this.createParenRegex(e.closeParens),this.INDEXED_PLACEHOLDER_REGEX=this.createPlaceholderRegex(e.indexedPlaceholderTypes,"[0-9]*"),this.IDENT_NAMED_PLACEHOLDER_REGEX=this.createPlaceholderRegex(e.namedPlaceholderTypes,"[a-zA-Z0-9._$]+"),this.STRING_NAMED_PLACEHOLDER_REGEX=this.createPlaceholderRegex(e.namedPlaceholderTypes,this.createStringPattern(e.stringTypes))}return t.prototype.createLineCommentRegex=function(t){return new RegExp("^((?:"+t.map((function(t){return(0,o.default)(t)})).join("|")+").*?(?:\n|$))")},t.prototype.createReservedWordRegex=function(t){var e=t.join("|").replace(/ /g,"\\s+");return new RegExp("^("+e+")\\b","i")},t.prototype.createWordRegex=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return new RegExp("^([\\w"+t.join("")+"]+)")},t.prototype.createStringRegex=function(t){return new RegExp("^("+this.createStringPattern(t)+")")},t.prototype.createStringPattern=function(t){var e={"``":"((`[^`]*($|`))+)","[]":"((\\[[^\\]]*($|\\]))(\\][^\\]]*($|\\]))*)",'""':'(("[^"\\\\]*(?:\\\\.[^"\\\\]*)*("|$))+)',"''":"(('[^'\\\\]*(?:\\\\.[^'\\\\]*)*('|$))+)","N''":"((N'[^N'\\\\]*(?:\\\\.[^N'\\\\]*)*('|$))+)"};return t.map((function(t){return e[t]})).join("|")},t.prototype.createParenRegex=function(t){var e=this;return new RegExp("^("+t.map((function(t){return e.escapeParen(t)})).join("|")+")","i")},t.prototype.escapeParen=function(t){return 1===t.length?(0,o.default)(t):"\\b"+t+"\\b"},t.prototype.createPlaceholderRegex=function(t,e){if((0,r.default)(t))return!1;var n=t.map(o.default).join("|");return new RegExp("^((?:"+n+")(?:"+e+"))")},t.prototype.tokenize=function(t){for(var e=[],n=void 0;t.length;)n=this.getNextToken(t,n),t=t.substring(n.value.length),e.push(n);return e},t.prototype.getNextToken=function(t,e){return this.getWhitespaceToken(t)||this.getCommentToken(t)||this.getStringToken(t)||this.getOpenParenToken(t)||this.getCloseParenToken(t)||this.getPlaceholderToken(t)||this.getNumberToken(t)||this.getReservedWordToken(t,e)||this.getWordToken(t)||this.getOperatorToken(t)},t.prototype.getWhitespaceToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.WHITESPACE,regex:this.WHITESPACE_REGEX})},t.prototype.getCommentToken=function(t){return this.getLineCommentToken(t)||this.getBlockCommentToken(t)},t.prototype.getLineCommentToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.LINE_COMMENT,regex:this.LINE_COMMENT_REGEX})},t.prototype.getBlockCommentToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.BLOCK_COMMENT,regex:this.BLOCK_COMMENT_REGEX})},t.prototype.getStringToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.STRING,regex:this.STRING_REGEX})},t.prototype.getOpenParenToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.OPEN_PAREN,regex:this.OPEN_PAREN_REGEX})},t.prototype.getCloseParenToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.CLOSE_PAREN,regex:this.CLOSE_PAREN_REGEX})},t.prototype.getPlaceholderToken=function(t){return this.getIdentNamedPlaceholderToken(t)||this.getStringNamedPlaceholderToken(t)||this.getIndexedPlaceholderToken(t)},t.prototype.getIdentNamedPlaceholderToken=function(t){return this.getPlaceholderTokenWithKey({input:t,regex:this.IDENT_NAMED_PLACEHOLDER_REGEX,parseKey:function(t){return t.slice(1)}})},t.prototype.getStringNamedPlaceholderToken=function(t){var e=this;return this.getPlaceholderTokenWithKey({input:t,regex:this.STRING_NAMED_PLACEHOLDER_REGEX,parseKey:function(t){return e.getEscapedPlaceholderKey({key:t.slice(2,-1),quoteChar:t.slice(-1)})}})},t.prototype.getIndexedPlaceholderToken=function(t){return this.getPlaceholderTokenWithKey({input:t,regex:this.INDEXED_PLACEHOLDER_REGEX,parseKey:function(t){return t.slice(1)}})},t.prototype.getPlaceholderTokenWithKey=function(t){var e=t.input,n=t.regex,r=t.parseKey,o=this.getTokenOnFirstMatch({input:e,regex:n,type:i.default.PLACEHOLDER});return o&&(o.key=r(o.value)),o},t.prototype.getEscapedPlaceholderKey=function(t){var e=t.key,n=t.quoteChar;return e.replace(new RegExp((0,o.default)("\\")+n,"g"),n)},t.prototype.getNumberToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.NUMBER,regex:this.NUMBER_REGEX})},t.prototype.getOperatorToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.OPERATOR,regex:this.OPERATOR_REGEX})},t.prototype.getReservedWordToken=function(t,e){if(!e||!e.value||"."!==e.value)return this.getToplevelReservedToken(t)||this.getNewlineReservedToken(t)||this.getPlainReservedToken(t)},t.prototype.getToplevelReservedToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.RESERVED_TOPLEVEL,regex:this.RESERVED_TOPLEVEL_REGEX})},t.prototype.getNewlineReservedToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.RESERVED_NEWLINE,regex:this.RESERVED_NEWLINE_REGEX})},t.prototype.getPlainReservedToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.RESERVED,regex:this.RESERVED_PLAIN_REGEX})},t.prototype.getWordToken=function(t){return this.getTokenOnFirstMatch({input:t,type:i.default.WORD,regex:this.WORD_REGEX})},t.prototype.getTokenOnFirstMatch=function(t){var e=t.input,n=t.type,r=t.regex,o=e.match(r);if(o)return{type:n,value:o[1]}},t}();e.default=s,t.exports=e.default},function(t,e,n){var r=n(12)(Object,"create");t.exports=r},function(t,e,n){var r=n(225),o=n(226),i=n(227),a=n(228),s=n(229);function c(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e0&&(t.localSitesPath||!1).length>0?e.replace(t.remoteSitesPath,t.localSitesPath):e,Object.keys(o).includes(r)?o[r].replace("%path",encodeURIComponent(e)).replace("%line",encodeURIComponent(n)):(console.error("'".concat(r,"' is not supported. Support editors are: ").concat(Object.keys(o).join(", "))),null)}n.d(e,"a",(function(){return r}))},function(t,e,n){"use strict";var r={props:{label:{required:!0},name:{required:!0},disabled:{required:!1},value:{required:!1,default:!1}},methods:{checkboxChanged:function(t){this.$emit("input",t.target.checked)}}},o=n(0),i=Object(o.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("label",{staticClass:"checkbox-label",class:t.disabled?"text-gray-400 pointer-events-none":"",attrs:{for:t.name}},[n("input",{staticClass:"checkbox",attrs:{id:t.name,type:"checkbox",disabled:t.disabled},domProps:{checked:t.value},on:{change:t.checkboxChanged}}),t._v("\n "+t._s(t.label)+"\n")])}),[],!1,null,null,null);e.a=i.exports},function(t,e){t.exports=/[!-#%-\*,-\/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4E\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD803[\uDF55-\uDF59]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC8\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD806[\uDC3B\uDE3F-\uDE46\uDE9A-\uDE9C\uDE9E-\uDEA2]|\uD807[\uDC41-\uDC45\uDC70\uDC71\uDEF7\uDEF8]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD81B[\uDE97-\uDE9A]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/},function(t,e,n){"use strict";function r(){this.__rules__=[],this.__cache__=null}r.prototype.__find__=function(t){for(var e=0;e=0&&(n=this.attrs[e][1]),n},r.prototype.attrJoin=function(t,e){var n=this.attrIndex(t);n<0?this.attrPush([t,e]):this.attrs[n][1]=this.attrs[n][1]+" "+e},t.exports=r},function(t,e,n){"use strict";e.__esModule=!0,e.default={WHITESPACE:"whitespace",WORD:"word",STRING:"string",RESERVED:"reserved",RESERVED_TOPLEVEL:"reserved-toplevel",RESERVED_NEWLINE:"reserved-newline",OPERATOR:"operator",OPEN_PAREN:"open-paren",CLOSE_PAREN:"close-paren",LINE_COMMENT:"line-comment",BLOCK_COMMENT:"block-comment",NUMBER:"number",PLACEHOLDER:"placeholder"},t.exports=e.default},function(t,e){t.exports=function(t,e){return t===e||t!=t&&e!=e}},function(t,e,n){var r=n(74),o=n(42);t.exports=function(t){return null!=t&&o(t.length)&&!r(t)}},function(t,e){var n=9007199254740991;t.exports=function(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}},function(t,e){var n=9007199254740991,r=/^(?:0|[1-9]\d*)$/;t.exports=function(t,e){var o=typeof t;return!!(e=null==e?n:e)&&("number"==o||"symbol"!=o&&r.test(t))&&t>-1&&t%1==0&&t2?n.slice(1-n.length).join("."):e.source=e.resource,e.git_suffix=/\.git$/.test(e.pathname),e.name=decodeURIComponent(e.pathname.replace(/^\//,"").replace(/\.git$/,"")),e.owner=decodeURIComponent(e.user),e.source){case"git.cloudforge.com":e.owner=e.user,e.organization=n[0],e.source="cloudforge.com";break;case"visualstudio.com":if("vs-ssh.visualstudio.com"===e.resource){4===(i=e.name.split("/")).length&&(e.organization=i[1],e.owner=i[2],e.name=i[3],e.full_name=i[2]+"/"+i[3]);break}2===(i=e.name.split("/")).length?(e.owner=i[1],e.name=i[1],e.full_name="_git/"+e.name):3===i.length?(e.name=i[2],"DefaultCollection"===i[0]?(e.owner=i[2],e.organization=i[0],e.full_name=e.organization+"/_git/"+e.name):(e.owner=i[0],e.full_name=e.owner+"/_git/"+e.name)):4===i.length&&(e.organization=i[0],e.owner=i[1],e.name=i[3],e.full_name=e.organization+"/"+e.owner+"/_git/"+e.name);break;case"dev.azure.com":case"azure.com":if("ssh.dev.azure.com"===e.resource){4===(i=e.name.split("/")).length&&(e.organization=i[1],e.owner=i[2],e.name=i[3]);break}5===(i=e.name.split("/")).length?(e.organization=i[0],e.owner=i[1],e.name=i[4],e.full_name="_git/"+e.name):3===i.length?(e.name=i[2],"DefaultCollection"===i[0]?(e.owner=i[2],e.organization=i[0],e.full_name=e.organization+"/_git/"+e.name):(e.owner=i[0],e.full_name=e.owner+"/_git/"+e.name)):4===i.length&&(e.organization=i[0],e.owner=i[1],e.name=i[3],e.full_name=e.organization+"/"+e.owner+"/_git/"+e.name);break;default:var a=(i=e.name.split("/")).length-1;if(i.length>=2){var s=i.indexOf("blob",2),c=i.indexOf("tree",2),u=i.indexOf("commit",2);a=s>0?s-1:c>0?c-1:u>0?u-1:a,e.owner=i.slice(0,a).join("/"),e.name=i[a],u&&(e.commit=i[a+2])}e.ref="",e.filepathtype="",e.filepath="",i.length>a+2&&["blob","tree"].indexOf(i[a+1])>=0&&(e.filepathtype=i[a+1],e.ref=i[a+2],i.length>a+3&&(e.filepath=i.slice(a+3).join("/"))),e.organization=e.owner}return e.full_name||(e.full_name=e.owner,e.name&&(e.full_name&&(e.full_name+="/"),e.full_name+=e.name)),e}o.stringify=function(t,e){e=e||(t.protocols&&t.protocols.length?t.protocols.join("+"):t.protocol);var n=t.port?":"+t.port:"",r=t.user||"git",o=t.git_suffix?".git":"";switch(e){case"ssh":return n?"ssh://"+r+"@"+t.resource+n+"/"+t.full_name+o:r+"@"+t.resource+":"+t.full_name+o;case"git+ssh":case"ssh+git":case"ftp":case"ftps":return e+"://"+r+"@"+t.resource+n+"/"+t.full_name+o;case"http":case"https":return e+"://"+(t.token? +/*! + * buildToken + * Builds OAuth token prefix (helper function) + * + * @name buildToken + * @function + * @param {GitUrl} obj The parsed Git url object. + * @return {String} token prefix + */ +function(t){switch(t.source){case"bitbucket.org":return"x-token-auth:"+t.token+"@";default:return t.token+"@"}}(t):t.user&&(t.protocols.includes("http")||t.protocols.includes("https"))?t.user+"@":"")+t.resource+n+"/"+t.full_name+o;default:return t.href}},t.exports=o},function(t,e,n){(function(t,r){var o; +/** + * @license + * Lodash + * Copyright OpenJS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */(function(){var i,a=200,s="Unsupported core-js use. Try https://npms.io/search?q=ponyfill.",c="Expected a function",u="Invalid `variable` option passed into `_.template`",l="__lodash_hash_undefined__",f=500,p="__lodash_placeholder__",d=1,h=2,g=4,m=1,v=2,b=1,_=2,y=4,E=8,x=16,k=32,w=64,C=128,A=256,T=512,S=30,R="...",O=800,N=16,L=1,I=2,D=1/0,M=9007199254740991,P=17976931348623157e292,j=NaN,F=4294967295,U=F-1,$=F>>>1,B=[["ary",C],["bind",b],["bindKey",_],["curry",E],["curryRight",x],["flip",T],["partial",k],["partialRight",w],["rearg",A]],z="[object Arguments]",q="[object Array]",H="[object AsyncFunction]",G="[object Boolean]",V="[object Date]",W="[object DOMException]",Y="[object Error]",K="[object Function]",X="[object GeneratorFunction]",Z="[object Map]",J="[object Number]",Q="[object Null]",tt="[object Object]",et="[object Proxy]",nt="[object RegExp]",rt="[object Set]",ot="[object String]",it="[object Symbol]",at="[object Undefined]",st="[object WeakMap]",ct="[object WeakSet]",ut="[object ArrayBuffer]",lt="[object DataView]",ft="[object Float32Array]",pt="[object Float64Array]",dt="[object Int8Array]",ht="[object Int16Array]",gt="[object Int32Array]",mt="[object Uint8Array]",vt="[object Uint8ClampedArray]",bt="[object Uint16Array]",_t="[object Uint32Array]",yt=/\b__p \+= '';/g,Et=/\b(__p \+=) '' \+/g,xt=/(__e\(.*?\)|\b__t\)) \+\n'';/g,kt=/&(?:amp|lt|gt|quot|#39);/g,wt=/[&<>"']/g,Ct=RegExp(kt.source),At=RegExp(wt.source),Tt=/<%-([\s\S]+?)%>/g,St=/<%([\s\S]+?)%>/g,Rt=/<%=([\s\S]+?)%>/g,Ot=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Nt=/^\w*$/,Lt=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,It=/[\\^$.*+?()[\]{}|]/g,Dt=RegExp(It.source),Mt=/^\s+/,Pt=/\s/,jt=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Ft=/\{\n\/\* \[wrapped with (.+)\] \*/,Ut=/,? & /,$t=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,Bt=/[()=,{}\[\]\/\s]/,zt=/\\(\\)?/g,qt=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,Ht=/\w*$/,Gt=/^[-+]0x[0-9a-f]+$/i,Vt=/^0b[01]+$/i,Wt=/^\[object .+?Constructor\]$/,Yt=/^0o[0-7]+$/i,Kt=/^(?:0|[1-9]\d*)$/,Xt=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,Zt=/($^)/,Jt=/['\n\r\u2028\u2029\\]/g,Qt="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",te="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",ee="[\\ud800-\\udfff]",ne="["+te+"]",re="["+Qt+"]",oe="\\d+",ie="[\\u2700-\\u27bf]",ae="[a-z\\xdf-\\xf6\\xf8-\\xff]",se="[^\\ud800-\\udfff"+te+oe+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",ce="\\ud83c[\\udffb-\\udfff]",ue="[^\\ud800-\\udfff]",le="(?:\\ud83c[\\udde6-\\uddff]){2}",fe="[\\ud800-\\udbff][\\udc00-\\udfff]",pe="[A-Z\\xc0-\\xd6\\xd8-\\xde]",de="(?:"+ae+"|"+se+")",he="(?:"+pe+"|"+se+")",ge="(?:"+re+"|"+ce+")"+"?",me="[\\ufe0e\\ufe0f]?"+ge+("(?:\\u200d(?:"+[ue,le,fe].join("|")+")[\\ufe0e\\ufe0f]?"+ge+")*"),ve="(?:"+[ie,le,fe].join("|")+")"+me,be="(?:"+[ue+re+"?",re,le,fe,ee].join("|")+")",_e=RegExp("['’]","g"),ye=RegExp(re,"g"),Ee=RegExp(ce+"(?="+ce+")|"+be+me,"g"),xe=RegExp([pe+"?"+ae+"+(?:['’](?:d|ll|m|re|s|t|ve))?(?="+[ne,pe,"$"].join("|")+")",he+"+(?:['’](?:D|LL|M|RE|S|T|VE))?(?="+[ne,pe+de,"$"].join("|")+")",pe+"?"+de+"+(?:['’](?:d|ll|m|re|s|t|ve))?",pe+"+(?:['’](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",oe,ve].join("|"),"g"),ke=RegExp("[\\u200d\\ud800-\\udfff"+Qt+"\\ufe0e\\ufe0f]"),we=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Ce=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Ae=-1,Te={};Te[ft]=Te[pt]=Te[dt]=Te[ht]=Te[gt]=Te[mt]=Te[vt]=Te[bt]=Te[_t]=!0,Te[z]=Te[q]=Te[ut]=Te[G]=Te[lt]=Te[V]=Te[Y]=Te[K]=Te[Z]=Te[J]=Te[tt]=Te[nt]=Te[rt]=Te[ot]=Te[st]=!1;var Se={};Se[z]=Se[q]=Se[ut]=Se[lt]=Se[G]=Se[V]=Se[ft]=Se[pt]=Se[dt]=Se[ht]=Se[gt]=Se[Z]=Se[J]=Se[tt]=Se[nt]=Se[rt]=Se[ot]=Se[it]=Se[mt]=Se[vt]=Se[bt]=Se[_t]=!0,Se[Y]=Se[K]=Se[st]=!1;var Re={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Oe=parseFloat,Ne=parseInt,Le="object"==typeof t&&t&&t.Object===Object&&t,Ie="object"==typeof self&&self&&self.Object===Object&&self,De=Le||Ie||Function("return this")(),Me=e&&!e.nodeType&&e,Pe=Me&&"object"==typeof r&&r&&!r.nodeType&&r,je=Pe&&Pe.exports===Me,Fe=je&&Le.process,Ue=function(){try{var t=Pe&&Pe.require&&Pe.require("util").types;return t||Fe&&Fe.binding&&Fe.binding("util")}catch(t){}}(),$e=Ue&&Ue.isArrayBuffer,Be=Ue&&Ue.isDate,ze=Ue&&Ue.isMap,qe=Ue&&Ue.isRegExp,He=Ue&&Ue.isSet,Ge=Ue&&Ue.isTypedArray;function Ve(t,e,n){switch(n.length){case 0:return t.call(e);case 1:return t.call(e,n[0]);case 2:return t.call(e,n[0],n[1]);case 3:return t.call(e,n[0],n[1],n[2])}return t.apply(e,n)}function We(t,e,n,r){for(var o=-1,i=null==t?0:t.length;++o-1}function Qe(t,e,n){for(var r=-1,o=null==t?0:t.length;++r-1;);return n}function kn(t,e){for(var n=t.length;n--&&un(e,t[n],0)>-1;);return n}var wn=hn({"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss","Ā":"A","Ă":"A","Ą":"A","ā":"a","ă":"a","ą":"a","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","ć":"c","ĉ":"c","ċ":"c","č":"c","Ď":"D","Đ":"D","ď":"d","đ":"d","Ē":"E","Ĕ":"E","Ė":"E","Ę":"E","Ě":"E","ē":"e","ĕ":"e","ė":"e","ę":"e","ě":"e","Ĝ":"G","Ğ":"G","Ġ":"G","Ģ":"G","ĝ":"g","ğ":"g","ġ":"g","ģ":"g","Ĥ":"H","Ħ":"H","ĥ":"h","ħ":"h","Ĩ":"I","Ī":"I","Ĭ":"I","Į":"I","İ":"I","ĩ":"i","ī":"i","ĭ":"i","į":"i","ı":"i","Ĵ":"J","ĵ":"j","Ķ":"K","ķ":"k","ĸ":"k","Ĺ":"L","Ļ":"L","Ľ":"L","Ŀ":"L","Ł":"L","ĺ":"l","ļ":"l","ľ":"l","ŀ":"l","ł":"l","Ń":"N","Ņ":"N","Ň":"N","Ŋ":"N","ń":"n","ņ":"n","ň":"n","ŋ":"n","Ō":"O","Ŏ":"O","Ő":"O","ō":"o","ŏ":"o","ő":"o","Ŕ":"R","Ŗ":"R","Ř":"R","ŕ":"r","ŗ":"r","ř":"r","Ś":"S","Ŝ":"S","Ş":"S","Š":"S","ś":"s","ŝ":"s","ş":"s","š":"s","Ţ":"T","Ť":"T","Ŧ":"T","ţ":"t","ť":"t","ŧ":"t","Ũ":"U","Ū":"U","Ŭ":"U","Ů":"U","Ű":"U","Ų":"U","ũ":"u","ū":"u","ŭ":"u","ů":"u","ű":"u","ų":"u","Ŵ":"W","ŵ":"w","Ŷ":"Y","ŷ":"y","Ÿ":"Y","Ź":"Z","Ż":"Z","Ž":"Z","ź":"z","ż":"z","ž":"z","IJ":"IJ","ij":"ij","Œ":"Oe","œ":"oe","ʼn":"'n","ſ":"s"}),Cn=hn({"&":"&","<":"<",">":">",'"':""","'":"'"});function An(t){return"\\"+Re[t]}function Tn(t){return ke.test(t)}function Sn(t){var e=-1,n=Array(t.size);return t.forEach((function(t,r){n[++e]=[r,t]})),n}function Rn(t,e){return function(n){return t(e(n))}}function On(t,e){for(var n=-1,r=t.length,o=0,i=[];++n",""":'"',"'":"'"});var jn=function t(e){var n,r=(e=null==e?De:jn.defaults(De.Object(),e,jn.pick(De,Ce))).Array,o=e.Date,Pt=e.Error,Qt=e.Function,te=e.Math,ee=e.Object,ne=e.RegExp,re=e.String,oe=e.TypeError,ie=r.prototype,ae=Qt.prototype,se=ee.prototype,ce=e["__core-js_shared__"],ue=ae.toString,le=se.hasOwnProperty,fe=0,pe=(n=/[^.]+$/.exec(ce&&ce.keys&&ce.keys.IE_PROTO||""))?"Symbol(src)_1."+n:"",de=se.toString,he=ue.call(ee),ge=De._,me=ne("^"+ue.call(le).replace(It,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),ve=je?e.Buffer:i,be=e.Symbol,Ee=e.Uint8Array,ke=ve?ve.allocUnsafe:i,Re=Rn(ee.getPrototypeOf,ee),Le=ee.create,Ie=se.propertyIsEnumerable,Me=ie.splice,Pe=be?be.isConcatSpreadable:i,Fe=be?be.iterator:i,Ue=be?be.toStringTag:i,an=function(){try{var t=Bi(ee,"defineProperty");return t({},"",{}),t}catch(t){}}(),hn=e.clearTimeout!==De.clearTimeout&&e.clearTimeout,Fn=o&&o.now!==De.Date.now&&o.now,Un=e.setTimeout!==De.setTimeout&&e.setTimeout,$n=te.ceil,Bn=te.floor,zn=ee.getOwnPropertySymbols,qn=ve?ve.isBuffer:i,Hn=e.isFinite,Gn=ie.join,Vn=Rn(ee.keys,ee),Wn=te.max,Yn=te.min,Kn=o.now,Xn=e.parseInt,Zn=te.random,Jn=ie.reverse,Qn=Bi(e,"DataView"),tr=Bi(e,"Map"),er=Bi(e,"Promise"),nr=Bi(e,"Set"),rr=Bi(e,"WeakMap"),or=Bi(ee,"create"),ir=rr&&new rr,ar={},sr=da(Qn),cr=da(tr),ur=da(er),lr=da(nr),fr=da(rr),pr=be?be.prototype:i,dr=pr?pr.valueOf:i,hr=pr?pr.toString:i;function gr(t){if(Os(t)&&!_s(t)&&!(t instanceof _r)){if(t instanceof br)return t;if(le.call(t,"__wrapped__"))return ha(t)}return new br(t)}var mr=function(){function t(){}return function(e){if(!Rs(e))return{};if(Le)return Le(e);t.prototype=e;var n=new t;return t.prototype=i,n}}();function vr(){}function br(t,e){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!e,this.__index__=0,this.__values__=i}function _r(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=F,this.__views__=[]}function yr(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e=e?t:e)),t}function jr(t,e,n,r,o,a){var s,c=e&d,u=e&h,l=e&g;if(n&&(s=o?n(t,r,o,a):n(t)),s!==i)return s;if(!Rs(t))return t;var f=_s(t);if(f){if(s=function(t){var e=t.length,n=new t.constructor(e);e&&"string"==typeof t[0]&&le.call(t,"index")&&(n.index=t.index,n.input=t.input);return n}(t),!c)return ii(t,s)}else{var p=Hi(t),m=p==K||p==X;if(ks(t))return Qo(t,c);if(p==tt||p==z||m&&!o){if(s=u||m?{}:Vi(t),!c)return u?function(t,e){return ai(t,qi(t),e)}(t,function(t,e){return t&&ai(e,sc(e),t)}(s,t)):function(t,e){return ai(t,zi(t),e)}(t,Ir(s,t))}else{if(!Se[p])return o?t:{};s=function(t,e,n){var r=t.constructor;switch(e){case ut:return ti(t);case G:case V:return new r(+t);case lt:return function(t,e){var n=e?ti(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.byteLength)}(t,n);case ft:case pt:case dt:case ht:case gt:case mt:case vt:case bt:case _t:return ei(t,n);case Z:return new r;case J:case ot:return new r(t);case nt:return function(t){var e=new t.constructor(t.source,Ht.exec(t));return e.lastIndex=t.lastIndex,e}(t);case rt:return new r;case it:return o=t,dr?ee(dr.call(o)):{}}var o}(t,p,c)}}a||(a=new wr);var v=a.get(t);if(v)return v;a.set(t,s),Ms(t)?t.forEach((function(r){s.add(jr(r,e,n,r,t,a))})):Ns(t)&&t.forEach((function(r,o){s.set(o,jr(r,e,n,o,t,a))}));var b=f?i:(l?u?Di:Ii:u?sc:ac)(t);return Ye(b||t,(function(r,o){b&&(r=t[o=r]),Or(s,o,jr(r,e,n,o,t,a))})),s}function Fr(t,e,n){var r=n.length;if(null==t)return!r;for(t=ee(t);r--;){var o=n[r],a=e[o],s=t[o];if(s===i&&!(o in t)||!a(s))return!1}return!0}function Ur(t,e,n){if("function"!=typeof t)throw new oe(c);return aa((function(){t.apply(i,n)}),e)}function $r(t,e,n,r){var o=-1,i=Je,s=!0,c=t.length,u=[],l=e.length;if(!c)return u;n&&(e=tn(e,_n(n))),r?(i=Qe,s=!1):e.length>=a&&(i=En,s=!1,e=new kr(e));t:for(;++o-1},Er.prototype.set=function(t,e){var n=this.__data__,r=Nr(n,t);return r<0?(++this.size,n.push([t,e])):n[r][1]=e,this},xr.prototype.clear=function(){this.size=0,this.__data__={hash:new yr,map:new(tr||Er),string:new yr}},xr.prototype.delete=function(t){var e=Ui(this,t).delete(t);return this.size-=e?1:0,e},xr.prototype.get=function(t){return Ui(this,t).get(t)},xr.prototype.has=function(t){return Ui(this,t).has(t)},xr.prototype.set=function(t,e){var n=Ui(this,t),r=n.size;return n.set(t,e),this.size+=n.size==r?0:1,this},kr.prototype.add=kr.prototype.push=function(t){return this.__data__.set(t,l),this},kr.prototype.has=function(t){return this.__data__.has(t)},wr.prototype.clear=function(){this.__data__=new Er,this.size=0},wr.prototype.delete=function(t){var e=this.__data__,n=e.delete(t);return this.size=e.size,n},wr.prototype.get=function(t){return this.__data__.get(t)},wr.prototype.has=function(t){return this.__data__.has(t)},wr.prototype.set=function(t,e){var n=this.__data__;if(n instanceof Er){var r=n.__data__;if(!tr||r.length0&&n(s)?e>1?Vr(s,e-1,n,r,o):en(o,s):r||(o[o.length]=s)}return o}var Wr=li(),Yr=li(!0);function Kr(t,e){return t&&Wr(t,e,ac)}function Xr(t,e){return t&&Yr(t,e,ac)}function Zr(t,e){return Ze(e,(function(e){return As(t[e])}))}function Jr(t,e){for(var n=0,r=(e=Ko(e,t)).length;null!=t&&ne}function no(t,e){return null!=t&&le.call(t,e)}function ro(t,e){return null!=t&&e in ee(t)}function oo(t,e,n){for(var o=n?Qe:Je,a=t[0].length,s=t.length,c=s,u=r(s),l=1/0,f=[];c--;){var p=t[c];c&&e&&(p=tn(p,_n(e))),l=Yn(p.length,l),u[c]=!n&&(e||a>=120&&p.length>=120)?new kr(c&&p):i}p=t[0];var d=-1,h=u[0];t:for(;++d=s)return c;var u=n[r];return c*("desc"==u?-1:1)}}return t.index-e.index}(t,e,n)}))}function Eo(t,e,n){for(var r=-1,o=e.length,i={};++r-1;)s!==t&&Me.call(s,c,1),Me.call(t,c,1);return t}function ko(t,e){for(var n=t?e.length:0,r=n-1;n--;){var o=e[n];if(n==r||o!==i){var i=o;Yi(o)?Me.call(t,o,1):Bo(t,o)}}return t}function wo(t,e){return t+Bn(Zn()*(e-t+1))}function Co(t,e){var n="";if(!t||e<1||e>M)return n;do{e%2&&(n+=t),(e=Bn(e/2))&&(t+=t)}while(e);return n}function Ao(t,e){return sa(na(t,e,Lc),t+"")}function To(t){return Ar(gc(t))}function So(t,e){var n=gc(t);return la(n,Pr(e,0,n.length))}function Ro(t,e,n,r){if(!Rs(t))return t;for(var o=-1,a=(e=Ko(e,t)).length,s=a-1,c=t;null!=c&&++oi?0:i+e),(n=n>i?i:n)<0&&(n+=i),i=e>n?0:n-e>>>0,e>>>=0;for(var a=r(i);++o>>1,a=t[i];null!==a&&!js(a)&&(n?a<=e:a=a){var l=e?null:Ci(t);if(l)return Nn(l);s=!1,o=En,u=new kr}else u=e?[]:c;t:for(;++r=r?t:Io(t,e,n)}var Jo=hn||function(t){return De.clearTimeout(t)};function Qo(t,e){if(e)return t.slice();var n=t.length,r=ke?ke(n):new t.constructor(n);return t.copy(r),r}function ti(t){var e=new t.constructor(t.byteLength);return new Ee(e).set(new Ee(t)),e}function ei(t,e){var n=e?ti(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.length)}function ni(t,e){if(t!==e){var n=t!==i,r=null===t,o=t==t,a=js(t),s=e!==i,c=null===e,u=e==e,l=js(e);if(!c&&!l&&!a&&t>e||a&&s&&u&&!c&&!l||r&&s&&u||!n&&u||!o)return 1;if(!r&&!a&&!l&&t1?n[o-1]:i,s=o>2?n[2]:i;for(a=t.length>3&&"function"==typeof a?(o--,a):i,s&&Ki(n[0],n[1],s)&&(a=o<3?i:a,o=1),e=ee(e);++r-1?o[a?e[s]:s]:i}}function gi(t){return Li((function(e){var n=e.length,r=n,o=br.prototype.thru;for(t&&e.reverse();r--;){var a=e[r];if("function"!=typeof a)throw new oe(c);if(o&&!s&&"wrapper"==Pi(a))var s=new br([],!0)}for(r=s?r:n;++r1&&y.reverse(),p&&l<_&&(y.length=l),this&&this!==De&&this instanceof b&&(A=v||di(A)),A.apply(C,y)}}function vi(t,e){return function(n,r){return function(t,e,n,r){return Kr(t,(function(t,o,i){e(r,n(t),o,i)})),r}(n,t,e(r),{})}}function bi(t,e){return function(n,r){var o;if(n===i&&r===i)return e;if(n!==i&&(o=n),r!==i){if(o===i)return r;"string"==typeof n||"string"==typeof r?(n=Uo(n),r=Uo(r)):(n=Fo(n),r=Fo(r)),o=t(n,r)}return o}}function _i(t){return Li((function(e){return e=tn(e,_n(Fi())),Ao((function(n){var r=this;return t(e,(function(t){return Ve(t,r,n)}))}))}))}function yi(t,e){var n=(e=e===i?" ":Uo(e)).length;if(n<2)return n?Co(e,t):e;var r=Co(e,$n(t/In(e)));return Tn(e)?Zo(Dn(r),0,t).join(""):r.slice(0,t)}function Ei(t){return function(e,n,o){return o&&"number"!=typeof o&&Ki(e,n,o)&&(n=o=i),e=zs(e),n===i?(n=e,e=0):n=zs(n),function(t,e,n,o){for(var i=-1,a=Wn($n((e-t)/(n||1)),0),s=r(a);a--;)s[o?a:++i]=t,t+=n;return s}(e,n,o=o===i?ec))return!1;var l=a.get(t),f=a.get(e);if(l&&f)return l==e&&f==t;var p=-1,d=!0,h=n&v?new kr:i;for(a.set(t,e),a.set(e,t);++p-1&&t%1==0&&t1?"& ":"")+e[r],e=e.join(n>2?", ":" "),t.replace(jt,"{\n/* [wrapped with "+e+"] */\n")}(r,function(t,e){return Ye(B,(function(n){var r="_."+n[0];e&n[1]&&!Je(t,r)&&t.push(r)})),t.sort()}(function(t){var e=t.match(Ft);return e?e[1].split(Ut):[]}(r),n)))}function ua(t){var e=0,n=0;return function(){var r=Kn(),o=N-(r-n);if(n=r,o>0){if(++e>=O)return arguments[0]}else e=0;return t.apply(i,arguments)}}function la(t,e){var n=-1,r=t.length,o=r-1;for(e=e===i?r:e;++n1?t[e-1]:i;return n="function"==typeof n?(t.pop(),n):i,Da(t,n)}));function Ba(t){var e=gr(t);return e.__chain__=!0,e}function za(t,e){return e(t)}var qa=Li((function(t){var e=t.length,n=e?t[0]:0,r=this.__wrapped__,o=function(e){return Mr(e,t)};return!(e>1||this.__actions__.length)&&r instanceof _r&&Yi(n)?((r=r.slice(n,+n+(e?1:0))).__actions__.push({func:za,args:[o],thisArg:i}),new br(r,this.__chain__).thru((function(t){return e&&!t.length&&t.push(i),t}))):this.thru(o)}));var Ha=si((function(t,e,n){le.call(t,n)?++t[n]:Dr(t,n,1)}));var Ga=hi(ba),Va=hi(_a);function Wa(t,e){return(_s(t)?Ye:Br)(t,Fi(e,3))}function Ya(t,e){return(_s(t)?Ke:zr)(t,Fi(e,3))}var Ka=si((function(t,e,n){le.call(t,n)?t[n].push(e):Dr(t,n,[e])}));var Xa=Ao((function(t,e,n){var o=-1,i="function"==typeof e,a=Es(t)?r(t.length):[];return Br(t,(function(t){a[++o]=i?Ve(e,t,n):io(t,e,n)})),a})),Za=si((function(t,e,n){Dr(t,n,e)}));function Ja(t,e){return(_s(t)?tn:go)(t,Fi(e,3))}var Qa=si((function(t,e,n){t[n?0:1].push(e)}),(function(){return[[],[]]}));var ts=Ao((function(t,e){if(null==t)return[];var n=e.length;return n>1&&Ki(t,e[0],e[1])?e=[]:n>2&&Ki(e[0],e[1],e[2])&&(e=[e[0]]),yo(t,Vr(e,1),[])})),es=Fn||function(){return De.Date.now()};function ns(t,e,n){return e=n?i:e,e=t&&null==e?t.length:e,Ti(t,C,i,i,i,i,e)}function rs(t,e){var n;if("function"!=typeof e)throw new oe(c);return t=qs(t),function(){return--t>0&&(n=e.apply(this,arguments)),t<=1&&(e=i),n}}var os=Ao((function(t,e,n){var r=b;if(n.length){var o=On(n,ji(os));r|=k}return Ti(t,r,e,n,o)})),is=Ao((function(t,e,n){var r=b|_;if(n.length){var o=On(n,ji(is));r|=k}return Ti(e,r,t,n,o)}));function as(t,e,n){var r,o,a,s,u,l,f=0,p=!1,d=!1,h=!0;if("function"!=typeof t)throw new oe(c);function g(e){var n=r,a=o;return r=o=i,f=e,s=t.apply(a,n)}function m(t){var n=t-l;return l===i||n>=e||n<0||d&&t-f>=a}function v(){var t=es();if(m(t))return b(t);u=aa(v,function(t){var n=e-(t-l);return d?Yn(n,a-(t-f)):n}(t))}function b(t){return u=i,h&&r?g(t):(r=o=i,s)}function _(){var t=es(),n=m(t);if(r=arguments,o=this,l=t,n){if(u===i)return function(t){return f=t,u=aa(v,e),p?g(t):s}(l);if(d)return Jo(u),u=aa(v,e),g(l)}return u===i&&(u=aa(v,e)),s}return e=Gs(e)||0,Rs(n)&&(p=!!n.leading,a=(d="maxWait"in n)?Wn(Gs(n.maxWait)||0,e):a,h="trailing"in n?!!n.trailing:h),_.cancel=function(){u!==i&&Jo(u),f=0,r=l=o=u=i},_.flush=function(){return u===i?s:b(es())},_}var ss=Ao((function(t,e){return Ur(t,1,e)})),cs=Ao((function(t,e,n){return Ur(t,Gs(e)||0,n)}));function us(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)throw new oe(c);var n=function(){var r=arguments,o=e?e.apply(this,r):r[0],i=n.cache;if(i.has(o))return i.get(o);var a=t.apply(this,r);return n.cache=i.set(o,a)||i,a};return n.cache=new(us.Cache||xr),n}function ls(t){if("function"!=typeof t)throw new oe(c);return function(){var e=arguments;switch(e.length){case 0:return!t.call(this);case 1:return!t.call(this,e[0]);case 2:return!t.call(this,e[0],e[1]);case 3:return!t.call(this,e[0],e[1],e[2])}return!t.apply(this,e)}}us.Cache=xr;var fs=Xo((function(t,e){var n=(e=1==e.length&&_s(e[0])?tn(e[0],_n(Fi())):tn(Vr(e,1),_n(Fi()))).length;return Ao((function(r){for(var o=-1,i=Yn(r.length,n);++o=e})),bs=ao(function(){return arguments}())?ao:function(t){return Os(t)&&le.call(t,"callee")&&!Ie.call(t,"callee")},_s=r.isArray,ys=$e?_n($e):function(t){return Os(t)&&to(t)==ut};function Es(t){return null!=t&&Ss(t.length)&&!As(t)}function xs(t){return Os(t)&&Es(t)}var ks=qn||Gc,ws=Be?_n(Be):function(t){return Os(t)&&to(t)==V};function Cs(t){if(!Os(t))return!1;var e=to(t);return e==Y||e==W||"string"==typeof t.message&&"string"==typeof t.name&&!Is(t)}function As(t){if(!Rs(t))return!1;var e=to(t);return e==K||e==X||e==H||e==et}function Ts(t){return"number"==typeof t&&t==qs(t)}function Ss(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=M}function Rs(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}function Os(t){return null!=t&&"object"==typeof t}var Ns=ze?_n(ze):function(t){return Os(t)&&Hi(t)==Z};function Ls(t){return"number"==typeof t||Os(t)&&to(t)==J}function Is(t){if(!Os(t)||to(t)!=tt)return!1;var e=Re(t);if(null===e)return!0;var n=le.call(e,"constructor")&&e.constructor;return"function"==typeof n&&n instanceof n&&ue.call(n)==he}var Ds=qe?_n(qe):function(t){return Os(t)&&to(t)==nt};var Ms=He?_n(He):function(t){return Os(t)&&Hi(t)==rt};function Ps(t){return"string"==typeof t||!_s(t)&&Os(t)&&to(t)==ot}function js(t){return"symbol"==typeof t||Os(t)&&to(t)==it}var Fs=Ge?_n(Ge):function(t){return Os(t)&&Ss(t.length)&&!!Te[to(t)]};var Us=xi(ho),$s=xi((function(t,e){return t<=e}));function Bs(t){if(!t)return[];if(Es(t))return Ps(t)?Dn(t):ii(t);if(Fe&&t[Fe])return function(t){for(var e,n=[];!(e=t.next()).done;)n.push(e.value);return n}(t[Fe]());var e=Hi(t);return(e==Z?Sn:e==rt?Nn:gc)(t)}function zs(t){return t?(t=Gs(t))===D||t===-D?(t<0?-1:1)*P:t==t?t:0:0===t?t:0}function qs(t){var e=zs(t),n=e%1;return e==e?n?e-n:e:0}function Hs(t){return t?Pr(qs(t),0,F):0}function Gs(t){if("number"==typeof t)return t;if(js(t))return j;if(Rs(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=Rs(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=bn(t);var n=Vt.test(t);return n||Yt.test(t)?Ne(t.slice(2),n?2:8):Gt.test(t)?j:+t}function Vs(t){return ai(t,sc(t))}function Ws(t){return null==t?"":Uo(t)}var Ys=ci((function(t,e){if(Qi(e)||Es(e))ai(e,ac(e),t);else for(var n in e)le.call(e,n)&&Or(t,n,e[n])})),Ks=ci((function(t,e){ai(e,sc(e),t)})),Xs=ci((function(t,e,n,r){ai(e,sc(e),t,r)})),Zs=ci((function(t,e,n,r){ai(e,ac(e),t,r)})),Js=Li(Mr);var Qs=Ao((function(t,e){t=ee(t);var n=-1,r=e.length,o=r>2?e[2]:i;for(o&&Ki(e[0],e[1],o)&&(r=1);++n1),e})),ai(t,Di(t),n),r&&(n=jr(n,d|h|g,Oi));for(var o=e.length;o--;)Bo(n,e[o]);return n}));var fc=Li((function(t,e){return null==t?{}:function(t,e){return Eo(t,e,(function(e,n){return nc(t,n)}))}(t,e)}));function pc(t,e){if(null==t)return{};var n=tn(Di(t),(function(t){return[t]}));return e=Fi(e),Eo(t,n,(function(t,n){return e(t,n[0])}))}var dc=Ai(ac),hc=Ai(sc);function gc(t){return null==t?[]:yn(t,ac(t))}var mc=pi((function(t,e,n){return e=e.toLowerCase(),t+(n?vc(e):e)}));function vc(t){return Cc(Ws(t).toLowerCase())}function bc(t){return(t=Ws(t))&&t.replace(Xt,wn).replace(ye,"")}var _c=pi((function(t,e,n){return t+(n?"-":"")+e.toLowerCase()})),yc=pi((function(t,e,n){return t+(n?" ":"")+e.toLowerCase()})),Ec=fi("toLowerCase");var xc=pi((function(t,e,n){return t+(n?"_":"")+e.toLowerCase()}));var kc=pi((function(t,e,n){return t+(n?" ":"")+Cc(e)}));var wc=pi((function(t,e,n){return t+(n?" ":"")+e.toUpperCase()})),Cc=fi("toUpperCase");function Ac(t,e,n){return t=Ws(t),(e=n?i:e)===i?function(t){return we.test(t)}(t)?function(t){return t.match(xe)||[]}(t):function(t){return t.match($t)||[]}(t):t.match(e)||[]}var Tc=Ao((function(t,e){try{return Ve(t,i,e)}catch(t){return Cs(t)?t:new Pt(t)}})),Sc=Li((function(t,e){return Ye(e,(function(e){e=pa(e),Dr(t,e,os(t[e],t))})),t}));function Rc(t){return function(){return t}}var Oc=gi(),Nc=gi(!0);function Lc(t){return t}function Ic(t){return lo("function"==typeof t?t:jr(t,d))}var Dc=Ao((function(t,e){return function(n){return io(n,t,e)}})),Mc=Ao((function(t,e){return function(n){return io(t,n,e)}}));function Pc(t,e,n){var r=ac(e),o=Zr(e,r);null!=n||Rs(e)&&(o.length||!r.length)||(n=e,e=t,t=this,o=Zr(e,ac(e)));var i=!(Rs(n)&&"chain"in n&&!n.chain),a=As(t);return Ye(o,(function(n){var r=e[n];t[n]=r,a&&(t.prototype[n]=function(){var e=this.__chain__;if(i||e){var n=t(this.__wrapped__),o=n.__actions__=ii(this.__actions__);return o.push({func:r,args:arguments,thisArg:t}),n.__chain__=e,n}return r.apply(t,en([this.value()],arguments))})})),t}function jc(){}var Fc=_i(tn),Uc=_i(Xe),$c=_i(on);function Bc(t){return Xi(t)?dn(pa(t)):function(t){return function(e){return Jr(e,t)}}(t)}var zc=Ei(),qc=Ei(!0);function Hc(){return[]}function Gc(){return!1}var Vc=bi((function(t,e){return t+e}),0),Wc=wi("ceil"),Yc=bi((function(t,e){return t/e}),1),Kc=wi("floor");var Xc,Zc=bi((function(t,e){return t*e}),1),Jc=wi("round"),Qc=bi((function(t,e){return t-e}),0);return gr.after=function(t,e){if("function"!=typeof e)throw new oe(c);return t=qs(t),function(){if(--t<1)return e.apply(this,arguments)}},gr.ary=ns,gr.assign=Ys,gr.assignIn=Ks,gr.assignInWith=Xs,gr.assignWith=Zs,gr.at=Js,gr.before=rs,gr.bind=os,gr.bindAll=Sc,gr.bindKey=is,gr.castArray=function(){if(!arguments.length)return[];var t=arguments[0];return _s(t)?t:[t]},gr.chain=Ba,gr.chunk=function(t,e,n){e=(n?Ki(t,e,n):e===i)?1:Wn(qs(e),0);var o=null==t?0:t.length;if(!o||e<1)return[];for(var a=0,s=0,c=r($n(o/e));ao?0:o+n),(r=r===i||r>o?o:qs(r))<0&&(r+=o),r=n>r?0:Hs(r);n>>0)?(t=Ws(t))&&("string"==typeof e||null!=e&&!Ds(e))&&!(e=Uo(e))&&Tn(t)?Zo(Dn(t),0,n):t.split(e,n):[]},gr.spread=function(t,e){if("function"!=typeof t)throw new oe(c);return e=null==e?0:Wn(qs(e),0),Ao((function(n){var r=n[e],o=Zo(n,0,e);return r&&en(o,r),Ve(t,this,o)}))},gr.tail=function(t){var e=null==t?0:t.length;return e?Io(t,1,e):[]},gr.take=function(t,e,n){return t&&t.length?Io(t,0,(e=n||e===i?1:qs(e))<0?0:e):[]},gr.takeRight=function(t,e,n){var r=null==t?0:t.length;return r?Io(t,(e=r-(e=n||e===i?1:qs(e)))<0?0:e,r):[]},gr.takeRightWhile=function(t,e){return t&&t.length?qo(t,Fi(e,3),!1,!0):[]},gr.takeWhile=function(t,e){return t&&t.length?qo(t,Fi(e,3)):[]},gr.tap=function(t,e){return e(t),t},gr.throttle=function(t,e,n){var r=!0,o=!0;if("function"!=typeof t)throw new oe(c);return Rs(n)&&(r="leading"in n?!!n.leading:r,o="trailing"in n?!!n.trailing:o),as(t,e,{leading:r,maxWait:e,trailing:o})},gr.thru=za,gr.toArray=Bs,gr.toPairs=dc,gr.toPairsIn=hc,gr.toPath=function(t){return _s(t)?tn(t,pa):js(t)?[t]:ii(fa(Ws(t)))},gr.toPlainObject=Vs,gr.transform=function(t,e,n){var r=_s(t),o=r||ks(t)||Fs(t);if(e=Fi(e,4),null==n){var i=t&&t.constructor;n=o?r?new i:[]:Rs(t)&&As(i)?mr(Re(t)):{}}return(o?Ye:Kr)(t,(function(t,r,o){return e(n,t,r,o)})),n},gr.unary=function(t){return ns(t,1)},gr.union=Oa,gr.unionBy=Na,gr.unionWith=La,gr.uniq=function(t){return t&&t.length?$o(t):[]},gr.uniqBy=function(t,e){return t&&t.length?$o(t,Fi(e,2)):[]},gr.uniqWith=function(t,e){return e="function"==typeof e?e:i,t&&t.length?$o(t,i,e):[]},gr.unset=function(t,e){return null==t||Bo(t,e)},gr.unzip=Ia,gr.unzipWith=Da,gr.update=function(t,e,n){return null==t?t:zo(t,e,Yo(n))},gr.updateWith=function(t,e,n,r){return r="function"==typeof r?r:i,null==t?t:zo(t,e,Yo(n),r)},gr.values=gc,gr.valuesIn=function(t){return null==t?[]:yn(t,sc(t))},gr.without=Ma,gr.words=Ac,gr.wrap=function(t,e){return ps(Yo(e),t)},gr.xor=Pa,gr.xorBy=ja,gr.xorWith=Fa,gr.zip=Ua,gr.zipObject=function(t,e){return Vo(t||[],e||[],Or)},gr.zipObjectDeep=function(t,e){return Vo(t||[],e||[],Ro)},gr.zipWith=$a,gr.entries=dc,gr.entriesIn=hc,gr.extend=Ks,gr.extendWith=Xs,Pc(gr,gr),gr.add=Vc,gr.attempt=Tc,gr.camelCase=mc,gr.capitalize=vc,gr.ceil=Wc,gr.clamp=function(t,e,n){return n===i&&(n=e,e=i),n!==i&&(n=(n=Gs(n))==n?n:0),e!==i&&(e=(e=Gs(e))==e?e:0),Pr(Gs(t),e,n)},gr.clone=function(t){return jr(t,g)},gr.cloneDeep=function(t){return jr(t,d|g)},gr.cloneDeepWith=function(t,e){return jr(t,d|g,e="function"==typeof e?e:i)},gr.cloneWith=function(t,e){return jr(t,g,e="function"==typeof e?e:i)},gr.conformsTo=function(t,e){return null==e||Fr(t,e,ac(e))},gr.deburr=bc,gr.defaultTo=function(t,e){return null==t||t!=t?e:t},gr.divide=Yc,gr.endsWith=function(t,e,n){t=Ws(t),e=Uo(e);var r=t.length,o=n=n===i?r:Pr(qs(n),0,r);return(n-=e.length)>=0&&t.slice(n,o)==e},gr.eq=gs,gr.escape=function(t){return(t=Ws(t))&&At.test(t)?t.replace(wt,Cn):t},gr.escapeRegExp=function(t){return(t=Ws(t))&&Dt.test(t)?t.replace(It,"\\$&"):t},gr.every=function(t,e,n){var r=_s(t)?Xe:qr;return n&&Ki(t,e,n)&&(e=i),r(t,Fi(e,3))},gr.find=Ga,gr.findIndex=ba,gr.findKey=function(t,e){return sn(t,Fi(e,3),Kr)},gr.findLast=Va,gr.findLastIndex=_a,gr.findLastKey=function(t,e){return sn(t,Fi(e,3),Xr)},gr.floor=Kc,gr.forEach=Wa,gr.forEachRight=Ya,gr.forIn=function(t,e){return null==t?t:Wr(t,Fi(e,3),sc)},gr.forInRight=function(t,e){return null==t?t:Yr(t,Fi(e,3),sc)},gr.forOwn=function(t,e){return t&&Kr(t,Fi(e,3))},gr.forOwnRight=function(t,e){return t&&Xr(t,Fi(e,3))},gr.get=ec,gr.gt=ms,gr.gte=vs,gr.has=function(t,e){return null!=t&&Gi(t,e,no)},gr.hasIn=nc,gr.head=Ea,gr.identity=Lc,gr.includes=function(t,e,n,r){t=Es(t)?t:gc(t),n=n&&!r?qs(n):0;var o=t.length;return n<0&&(n=Wn(o+n,0)),Ps(t)?n<=o&&t.indexOf(e,n)>-1:!!o&&un(t,e,n)>-1},gr.indexOf=function(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var o=null==n?0:qs(n);return o<0&&(o=Wn(r+o,0)),un(t,e,o)},gr.inRange=function(t,e,n){return e=zs(e),n===i?(n=e,e=0):n=zs(n),function(t,e,n){return t>=Yn(e,n)&&t=-M&&t<=M},gr.isSet=Ms,gr.isString=Ps,gr.isSymbol=js,gr.isTypedArray=Fs,gr.isUndefined=function(t){return t===i},gr.isWeakMap=function(t){return Os(t)&&Hi(t)==st},gr.isWeakSet=function(t){return Os(t)&&to(t)==ct},gr.join=function(t,e){return null==t?"":Gn.call(t,e)},gr.kebabCase=_c,gr.last=Ca,gr.lastIndexOf=function(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var o=r;return n!==i&&(o=(o=qs(n))<0?Wn(r+o,0):Yn(o,r-1)),e==e?function(t,e,n){for(var r=n+1;r--;)if(t[r]===e)return r;return r}(t,e,o):cn(t,fn,o,!0)},gr.lowerCase=yc,gr.lowerFirst=Ec,gr.lt=Us,gr.lte=$s,gr.max=function(t){return t&&t.length?Hr(t,Lc,eo):i},gr.maxBy=function(t,e){return t&&t.length?Hr(t,Fi(e,2),eo):i},gr.mean=function(t){return pn(t,Lc)},gr.meanBy=function(t,e){return pn(t,Fi(e,2))},gr.min=function(t){return t&&t.length?Hr(t,Lc,ho):i},gr.minBy=function(t,e){return t&&t.length?Hr(t,Fi(e,2),ho):i},gr.stubArray=Hc,gr.stubFalse=Gc,gr.stubObject=function(){return{}},gr.stubString=function(){return""},gr.stubTrue=function(){return!0},gr.multiply=Zc,gr.nth=function(t,e){return t&&t.length?_o(t,qs(e)):i},gr.noConflict=function(){return De._===this&&(De._=ge),this},gr.noop=jc,gr.now=es,gr.pad=function(t,e,n){t=Ws(t);var r=(e=qs(e))?In(t):0;if(!e||r>=e)return t;var o=(e-r)/2;return yi(Bn(o),n)+t+yi($n(o),n)},gr.padEnd=function(t,e,n){t=Ws(t);var r=(e=qs(e))?In(t):0;return e&&re){var r=t;t=e,e=r}if(n||t%1||e%1){var o=Zn();return Yn(t+o*(e-t+Oe("1e-"+((o+"").length-1))),e)}return wo(t,e)},gr.reduce=function(t,e,n){var r=_s(t)?nn:gn,o=arguments.length<3;return r(t,Fi(e,4),n,o,Br)},gr.reduceRight=function(t,e,n){var r=_s(t)?rn:gn,o=arguments.length<3;return r(t,Fi(e,4),n,o,zr)},gr.repeat=function(t,e,n){return e=(n?Ki(t,e,n):e===i)?1:qs(e),Co(Ws(t),e)},gr.replace=function(){var t=arguments,e=Ws(t[0]);return t.length<3?e:e.replace(t[1],t[2])},gr.result=function(t,e,n){var r=-1,o=(e=Ko(e,t)).length;for(o||(o=1,t=i);++rM)return[];var n=F,r=Yn(t,F);e=Fi(e),t-=F;for(var o=vn(r,e);++n=a)return t;var c=n-In(r);if(c<1)return r;var u=s?Zo(s,0,c).join(""):t.slice(0,c);if(o===i)return u+r;if(s&&(c+=u.length-c),Ds(o)){if(t.slice(c).search(o)){var l,f=u;for(o.global||(o=ne(o.source,Ws(Ht.exec(o))+"g")),o.lastIndex=0;l=o.exec(f);)var p=l.index;u=u.slice(0,p===i?c:p)}}else if(t.indexOf(Uo(o),c)!=c){var d=u.lastIndexOf(o);d>-1&&(u=u.slice(0,d))}return u+r},gr.unescape=function(t){return(t=Ws(t))&&Ct.test(t)?t.replace(kt,Pn):t},gr.uniqueId=function(t){var e=++fe;return Ws(t)+e},gr.upperCase=wc,gr.upperFirst=Cc,gr.each=Wa,gr.eachRight=Ya,gr.first=Ea,Pc(gr,(Xc={},Kr(gr,(function(t,e){le.call(gr.prototype,e)||(Xc[e]=t)})),Xc),{chain:!1}),gr.VERSION="4.17.21",Ye(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(t){gr[t].placeholder=gr})),Ye(["drop","take"],(function(t,e){_r.prototype[t]=function(n){n=n===i?1:Wn(qs(n),0);var r=this.__filtered__&&!e?new _r(this):this.clone();return r.__filtered__?r.__takeCount__=Yn(n,r.__takeCount__):r.__views__.push({size:Yn(n,F),type:t+(r.__dir__<0?"Right":"")}),r},_r.prototype[t+"Right"]=function(e){return this.reverse()[t](e).reverse()}})),Ye(["filter","map","takeWhile"],(function(t,e){var n=e+1,r=n==L||3==n;_r.prototype[t]=function(t){var e=this.clone();return e.__iteratees__.push({iteratee:Fi(t,3),type:n}),e.__filtered__=e.__filtered__||r,e}})),Ye(["head","last"],(function(t,e){var n="take"+(e?"Right":"");_r.prototype[t]=function(){return this[n](1).value()[0]}})),Ye(["initial","tail"],(function(t,e){var n="drop"+(e?"":"Right");_r.prototype[t]=function(){return this.__filtered__?new _r(this):this[n](1)}})),_r.prototype.compact=function(){return this.filter(Lc)},_r.prototype.find=function(t){return this.filter(t).head()},_r.prototype.findLast=function(t){return this.reverse().find(t)},_r.prototype.invokeMap=Ao((function(t,e){return"function"==typeof t?new _r(this):this.map((function(n){return io(n,t,e)}))})),_r.prototype.reject=function(t){return this.filter(ls(Fi(t)))},_r.prototype.slice=function(t,e){t=qs(t);var n=this;return n.__filtered__&&(t>0||e<0)?new _r(n):(t<0?n=n.takeRight(-t):t&&(n=n.drop(t)),e!==i&&(n=(e=qs(e))<0?n.dropRight(-e):n.take(e-t)),n)},_r.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},_r.prototype.toArray=function(){return this.take(F)},Kr(_r.prototype,(function(t,e){var n=/^(?:filter|find|map|reject)|While$/.test(e),r=/^(?:head|last)$/.test(e),o=gr[r?"take"+("last"==e?"Right":""):e],a=r||/^find/.test(e);o&&(gr.prototype[e]=function(){var e=this.__wrapped__,s=r?[1]:arguments,c=e instanceof _r,u=s[0],l=c||_s(e),f=function(t){var e=o.apply(gr,en([t],s));return r&&p?e[0]:e};l&&n&&"function"==typeof u&&1!=u.length&&(c=l=!1);var p=this.__chain__,d=!!this.__actions__.length,h=a&&!p,g=c&&!d;if(!a&&l){e=g?e:new _r(this);var m=t.apply(e,s);return m.__actions__.push({func:za,args:[f],thisArg:i}),new br(m,p)}return h&&g?t.apply(this,s):(m=this.thru(f),h?r?m.value()[0]:m.value():m)})})),Ye(["pop","push","shift","sort","splice","unshift"],(function(t){var e=ie[t],n=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",r=/^(?:pop|shift)$/.test(t);gr.prototype[t]=function(){var t=arguments;if(r&&!this.__chain__){var o=this.value();return e.apply(_s(o)?o:[],t)}return this[n]((function(n){return e.apply(_s(n)?n:[],t)}))}})),Kr(_r.prototype,(function(t,e){var n=gr[e];if(n){var r=n.name+"";le.call(ar,r)||(ar[r]=[]),ar[r].push({name:e,func:n})}})),ar[mi(i,_).name]=[{name:"wrapper",func:i}],_r.prototype.clone=function(){var t=new _r(this.__wrapped__);return t.__actions__=ii(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=ii(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=ii(this.__views__),t},_r.prototype.reverse=function(){if(this.__filtered__){var t=new _r(this);t.__dir__=-1,t.__filtered__=!0}else(t=this.clone()).__dir__*=-1;return t},_r.prototype.value=function(){var t=this.__wrapped__.value(),e=this.__dir__,n=_s(t),r=e<0,o=n?t.length:0,i=function(t,e,n){var r=-1,o=n.length;for(;++r=this.__values__.length;return{done:t,value:t?i:this.__values__[this.__index__++]}},gr.prototype.plant=function(t){for(var e,n=this;n instanceof vr;){var r=ha(n);r.__index__=0,r.__values__=i,e?o.__wrapped__=r:e=r;var o=r;n=n.__wrapped__}return o.__wrapped__=t,e},gr.prototype.reverse=function(){var t=this.__wrapped__;if(t instanceof _r){var e=t;return this.__actions__.length&&(e=new _r(this)),(e=e.reverse()).__actions__.push({func:za,args:[Ra],thisArg:i}),new br(e,this.__chain__)}return this.thru(Ra)},gr.prototype.toJSON=gr.prototype.valueOf=gr.prototype.value=function(){return Ho(this.__wrapped__,this.__actions__)},gr.prototype.first=gr.prototype.head,Fe&&(gr.prototype[Fe]=function(){return this}),gr}();De._=jn,(o=function(){return jn}.call(e,n,e,r))===i||(r.exports=o)}).call(this)}).call(this,n(11),n(22)(t))},function(t,e){function n(t){return t instanceof Map?t.clear=t.delete=t.set=function(){throw new Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=function(){throw new Error("set is read-only")}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((function(e){var r=t[e];"object"!=typeof r||Object.isFrozen(r)||n(r)})),t}var r=n,o=n;r.default=o;class i{constructor(t){void 0===t.data&&(t.data={}),this.data=t.data}ignoreMatch(){this.ignore=!0}}function a(t){return t.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function s(t,...e){const n=Object.create(null);for(const e in t)n[e]=t[e];return e.forEach((function(t){for(const e in t)n[e]=t[e]})),n}function c(t){return t.nodeName.toLowerCase()}var u=Object.freeze({__proto__:null,escapeHTML:a,inherit:s,nodeStream:function(t){const e=[];return function t(n,r){for(let o=n.firstChild;o;o=o.nextSibling)3===o.nodeType?r+=o.nodeValue.length:1===o.nodeType&&(e.push({event:"start",offset:r,node:o}),r=t(o,r),c(o).match(/br|hr|img|input/)||e.push({event:"stop",offset:r,node:o}));return r}(t,0),e},mergeStreams:function(t,e,n){let r=0,o="";const i=[];function s(){return t.length&&e.length?t[0].offset!==e[0].offset?t[0].offset"}function l(t){o+=""}function f(t){("start"===t.event?u:l)(t.node)}for(;t.length||e.length;){let e=s();if(o+=a(n.substring(r,e[0].offset)),r=e[0].offset,e===t){i.reverse().forEach(l);do{f(e.splice(0,1)[0]),e=s()}while(e===t&&e.length&&e[0].offset===r);i.reverse().forEach(u)}else"start"===e[0].event?i.push(e[0].node):i.pop(),f(e.splice(0,1)[0])}return o+a(n.substr(r))}});const l="",f=t=>!!t.kind;class p{constructor(t,e){this.buffer="",this.classPrefix=e.classPrefix,t.walk(this)}addText(t){this.buffer+=a(t)}openNode(t){if(!f(t))return;let e=t.kind;t.sublanguage||(e=`${this.classPrefix}${e}`),this.span(e)}closeNode(t){f(t)&&(this.buffer+=l)}value(){return this.buffer}span(t){this.buffer+=``}}class d{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(t){this.top.children.push(t)}openNode(t){const e={kind:t,children:[]};this.add(e),this.stack.push(e)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(t){return this.constructor._walk(t,this.rootNode)}static _walk(t,e){return"string"==typeof e?t.addText(e):e.children&&(t.openNode(e),e.children.forEach(e=>this._walk(t,e)),t.closeNode(e)),t}static _collapse(t){"string"!=typeof t&&t.children&&(t.children.every(t=>"string"==typeof t)?t.children=[t.children.join("")]:t.children.forEach(t=>{d._collapse(t)}))}}class h extends d{constructor(t){super(),this.options=t}addKeyword(t,e){""!==t&&(this.openNode(e),this.addText(t),this.closeNode())}addText(t){""!==t&&this.add(t)}addSublanguage(t,e){const n=t.root;n.kind=e,n.sublanguage=!0,this.add(n)}toHTML(){return new p(this,this.options).value()}finalize(){return!0}}function g(t){return t?"string"==typeof t?t:t.source:null}const m="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",v={begin:"\\\\[\\s\\S]",relevance:0},b={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[v]},_={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[v]},y={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},E=function(t,e,n={}){const r=s({className:"comment",begin:t,end:e,contains:[]},n);return r.contains.push(y),r.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),r},x=E("//","$"),k=E("/\\*","\\*/"),w=E("#","$"),C={className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},A={className:"number",begin:m,relevance:0},T={className:"number",begin:"\\b(0b[01]+)",relevance:0},S={className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},R={begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[v,{begin:/\[/,end:/\]/,relevance:0,contains:[v]}]}]},O={className:"title",begin:"[a-zA-Z]\\w*",relevance:0},N={className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},L={begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0};var I=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:m,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(t={})=>{const e=/^#![ ]*\//;return t.binary&&(t.begin=function(...t){return t.map(t=>g(t)).join("")}(e,/.*\b/,t.binary,/\b.*/)),s({className:"meta",begin:e,end:/$/,relevance:0,"on:begin":(t,e)=>{0!==t.index&&e.ignoreMatch()}},t)},BACKSLASH_ESCAPE:v,APOS_STRING_MODE:b,QUOTE_STRING_MODE:_,PHRASAL_WORDS_MODE:y,COMMENT:E,C_LINE_COMMENT_MODE:x,C_BLOCK_COMMENT_MODE:k,HASH_COMMENT_MODE:w,NUMBER_MODE:C,C_NUMBER_MODE:A,BINARY_NUMBER_MODE:T,CSS_NUMBER_MODE:S,REGEXP_MODE:R,TITLE_MODE:O,UNDERSCORE_TITLE_MODE:N,METHOD_GUARD:L,END_SAME_AS_BEGIN:function(t){return Object.assign(t,{"on:begin":(t,e)=>{e.data._beginMatch=t[1]},"on:end":(t,e)=>{e.data._beginMatch!==t[1]&&e.ignoreMatch()}})}});const D=["of","and","for","in","not","or","if","then","parent","list","value"];function M(t){function e(e,n){return new RegExp(g(e),"m"+(t.case_insensitive?"i":"")+(n?"g":""))}class n{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(t,e){e.position=this.position++,this.matchIndexes[this.matchAt]=e,this.regexes.push([e,t]),this.matchAt+=function(t){return new RegExp(t.toString()+"|").exec("").length-1}(t)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const t=this.regexes.map(t=>t[1]);this.matcherRe=e(function(t,e="|"){const n=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;let r=0,o="";for(let i=0;i0&&(o+=e),o+="(";s.length>0;){const t=n.exec(s);if(null==t){o+=s;break}o+=s.substring(0,t.index),s=s.substring(t.index+t[0].length),"\\"===t[0][0]&&t[1]?o+="\\"+String(Number(t[1])+a):(o+=t[0],"("===t[0]&&r++)}o+=")"}return o}(t),!0),this.lastIndex=0}exec(t){this.matcherRe.lastIndex=this.lastIndex;const e=this.matcherRe.exec(t);if(!e)return null;const n=e.findIndex((t,e)=>e>0&&void 0!==t),r=this.matchIndexes[n];return e.splice(0,n),Object.assign(e,r)}}class r{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(t){if(this.multiRegexes[t])return this.multiRegexes[t];const e=new n;return this.rules.slice(t).forEach(([t,n])=>e.addRule(t,n)),e.compile(),this.multiRegexes[t]=e,e}resumingScanAtSamePosition(){return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(t,e){this.rules.push([t,e]),"begin"===e.type&&this.count++}exec(t){const e=this.getMatcher(this.regexIndex);e.lastIndex=this.lastIndex;let n=e.exec(t);if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{const e=this.getMatcher(0);e.lastIndex=this.lastIndex+1,n=e.exec(t)}return n&&(this.regexIndex+=n.position+1,this.regexIndex===this.count&&this.considerAll()),n}}function o(t,e){"."===t.input[t.index-1]&&e.ignoreMatch()}if(t.contains&&t.contains.includes("self"))throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return t.classNameAliases=s(t.classNameAliases||{}),function n(i,a){const c=i;if(i.compiled)return c;i.compiled=!0,i.__beforeBegin=null,i.keywords=i.keywords||i.beginKeywords;let u=null;if("object"==typeof i.keywords&&(u=i.keywords.$pattern,delete i.keywords.$pattern),i.keywords&&(i.keywords=function(t,e){const n={};"string"==typeof t?r("keyword",t):Object.keys(t).forEach((function(e){r(e,t[e])}));return n;function r(t,r){e&&(r=r.toLowerCase()),r.split(" ").forEach((function(e){const r=e.split("|");n[r[0]]=[t,P(r[0],r[1])]}))}}(i.keywords,t.case_insensitive)),i.lexemes&&u)throw new Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return c.keywordPatternRe=e(i.lexemes||u||/\w+/,!0),a&&(i.beginKeywords&&(i.begin="\\b("+i.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",i.__beforeBegin=o),i.begin||(i.begin=/\B|\b/),c.beginRe=e(i.begin),i.endSameAsBegin&&(i.end=i.begin),i.end||i.endsWithParent||(i.end=/\B|\b/),i.end&&(c.endRe=e(i.end)),c.terminator_end=g(i.end)||"",i.endsWithParent&&a.terminator_end&&(c.terminator_end+=(i.end?"|":"")+a.terminator_end)),i.illegal&&(c.illegalRe=e(i.illegal)),void 0===i.relevance&&(i.relevance=1),i.contains||(i.contains=[]),i.contains=[].concat(...i.contains.map((function(t){return function(t){t.variants&&!t.cached_variants&&(t.cached_variants=t.variants.map((function(e){return s(t,{variants:null},e)})));if(t.cached_variants)return t.cached_variants;if(function t(e){if(!e)return!1;return e.endsWithParent||t(e.starts)}(t))return s(t,{starts:t.starts?s(t.starts):null});if(Object.isFrozen(t))return s(t);return t}("self"===t?i:t)}))),i.contains.forEach((function(t){n(t,c)})),i.starts&&n(i.starts,a),c.matcher=function(t){const e=new r;return t.contains.forEach(t=>e.addRule(t.begin,{rule:t,type:"begin"})),t.terminator_end&&e.addRule(t.terminator_end,{type:"end"}),t.illegal&&e.addRule(t.illegal,{type:"illegal"}),e}(c),c}(t)}function P(t,e){return e?Number(e):function(t){return D.includes(t.toLowerCase())}(t)?0:1}function j(t){const e={props:["language","code","autodetect"],data:function(){return{detectedLanguage:"",unknownLanguage:!1}},computed:{className(){return this.unknownLanguage?"":"hljs "+this.detectedLanguage},highlighted(){if(!this.autoDetect&&!t.getLanguage(this.language))return console.warn(`The language "${this.language}" you specified could not be found.`),this.unknownLanguage=!0,a(this.code);let e;return this.autoDetect?(e=t.highlightAuto(this.code),this.detectedLanguage=e.language):(e=t.highlight(this.language,this.code,this.ignoreIllegals),this.detectedLanguage=this.language),e.value},autoDetect(){return!this.language||(t=this.autodetect,Boolean(t||""===t));var t},ignoreIllegals:()=>!0},render(t){return t("pre",{},[t("code",{class:this.className,domProps:{innerHTML:this.highlighted}})])}};return{Component:e,VuePlugin:{install(t){t.component("highlightjs",e)}}}}const F=a,U=s,{nodeStream:$,mergeStreams:B}=u,z=Symbol("nomatch");var q=function(t){const e=[],n=Object.create(null),o=Object.create(null),a=[];let s=!0;const c=/(^(<[^>]+>|\t|)+|\n)/gm,u="Could not find the language '{}', did you forget to load/include a language module?",l={disableAutodetect:!0,name:"Plain text",contains:[]};let f={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:h};function p(t){return f.noHighlightRe.test(t)}function d(t,e,n,r){const o={code:e,language:t};k("before:highlight",o);const i=o.result?o.result:g(o.language,o.code,n,r);return i.code=o.code,k("after:highlight",i),i}function g(t,e,r,o){const a=e;function c(t,e){const n=E.case_insensitive?e[0].toLowerCase():e[0];return Object.prototype.hasOwnProperty.call(t.keywords,n)&&t.keywords[n]}function l(){null!=w.subLanguage?function(){if(""===T)return;let t=null;if("string"==typeof w.subLanguage){if(!n[w.subLanguage])return void A.addText(T);t=g(w.subLanguage,T,!0,C[w.subLanguage]),C[w.subLanguage]=t.top}else t=m(T,w.subLanguage.length?w.subLanguage:null);w.relevance>0&&(S+=t.relevance),A.addSublanguage(t.emitter,t.language)}():function(){if(!w.keywords)return void A.addText(T);let t=0;w.keywordPatternRe.lastIndex=0;let e=w.keywordPatternRe.exec(T),n="";for(;e;){n+=T.substring(t,e.index);const r=c(w,e);if(r){const[t,o]=r;A.addText(n),n="",S+=o;const i=E.classNameAliases[t]||t;A.addKeyword(e[0],i)}else n+=e[0];t=w.keywordPatternRe.lastIndex,e=w.keywordPatternRe.exec(T)}n+=T.substr(t),A.addText(n)}(),T=""}function p(t){return t.className&&A.openNode(E.classNameAliases[t.className]||t.className),w=Object.create(t,{parent:{value:w}})}function d(t){return 0===w.matcher.regexIndex?(T+=t[0],1):(N=!0,0)}function h(t){const e=t[0],n=t.rule,r=new i(n),o=[n.__beforeBegin,n["on:begin"]];for(const n of o)if(n&&(n(t,r),r.ignore))return d(e);return n&&n.endSameAsBegin&&(n.endRe=new RegExp(e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),n.skip?T+=e:(n.excludeBegin&&(T+=e),l(),n.returnBegin||n.excludeBegin||(T=e)),p(n),n.returnBegin?0:e.length}function v(t){const e=t[0],n=a.substr(t.index),r=function t(e,n,r){let o=function(t,e){const n=t&&t.exec(e);return n&&0===n.index}(e.endRe,r);if(o){if(e["on:end"]){const t=new i(e);e["on:end"](n,t),t.ignore&&(o=!1)}if(o){for(;e.endsParent&&e.parent;)e=e.parent;return e}}if(e.endsWithParent)return t(e.parent,n,r)}(w,t,n);if(!r)return z;const o=w;o.skip?T+=e:(o.returnEnd||o.excludeEnd||(T+=e),l(),o.excludeEnd&&(T=e));do{w.className&&A.closeNode(),w.skip||w.subLanguage||(S+=w.relevance),w=w.parent}while(w!==r.parent);return r.starts&&(r.endSameAsBegin&&(r.starts.endRe=r.endRe),p(r.starts)),o.returnEnd?0:e.length}let b={};function _(e,n){const o=n&&n[0];if(T+=e,null==o)return l(),0;if("begin"===b.type&&"end"===n.type&&b.index===n.index&&""===o){if(T+=a.slice(n.index,n.index+1),!s){const e=new Error("0 width match regex");throw e.languageName=t,e.badRule=b.rule,e}return 1}if(b=n,"begin"===n.type)return h(n);if("illegal"===n.type&&!r){const t=new Error('Illegal lexeme "'+o+'" for mode "'+(w.className||"")+'"');throw t.mode=w,t}if("end"===n.type){const t=v(n);if(t!==z)return t}if("illegal"===n.type&&""===o)return 1;if(O>1e5&&O>3*n.index){throw new Error("potential infinite loop, way more iterations than matches")}return T+=o,o.length}const E=y(t);if(!E)throw console.error(u.replace("{}",t)),new Error('Unknown language: "'+t+'"');const x=M(E);let k="",w=o||x;const C={},A=new f.__emitter(f);!function(){const t=[];for(let e=w;e!==E;e=e.parent)e.className&&t.unshift(e.className);t.forEach(t=>A.openNode(t))}();let T="",S=0,R=0,O=0,N=!1;try{for(w.matcher.considerAll();;){O++,N?N=!1:w.matcher.considerAll(),w.matcher.lastIndex=R;const t=w.matcher.exec(a);if(!t)break;const e=_(a.substring(R,t.index),t);R=t.index+e}return _(a.substr(R)),A.closeAllNodes(),A.finalize(),k=A.toHTML(),{relevance:S,value:k,language:t,illegal:!1,emitter:A,top:w}}catch(e){if(e.message&&e.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:e.message,context:a.slice(R-100,R+100),mode:e.mode},sofar:k,relevance:0,value:F(a),emitter:A};if(s)return{illegal:!1,relevance:0,value:F(a),emitter:A,language:t,top:w,errorRaised:e};throw e}}function m(t,e){e=e||f.languages||Object.keys(n);const r=function(t){const e={relevance:0,emitter:new f.__emitter(f),value:F(t),illegal:!1,top:l};return e.emitter.addText(t),e}(t),o=e.filter(y).filter(x).map(e=>g(e,t,!1));o.unshift(r);const i=o.sort((t,e)=>{if(t.relevance!==e.relevance)return e.relevance-t.relevance;if(t.language&&e.language){if(y(t.language).supersetOf===e.language)return 1;if(y(e.language).supersetOf===t.language)return-1}return 0}),[a,s]=i,c=a;return c.second_best=s,c}function v(t){return f.tabReplace||f.useBR?t.replace(c,t=>"\n"===t?f.useBR?"
":t:f.tabReplace?t.replace(/\t/g,f.tabReplace):t):t}function b(t){let e=null;const n=function(t){let e=t.className+" ";e+=t.parentNode?t.parentNode.className:"";const n=f.languageDetectRe.exec(e);if(n){const e=y(n[1]);return e||(console.warn(u.replace("{}",n[1])),console.warn("Falling back to no-highlight mode for this block.",t)),e?n[1]:"no-highlight"}return e.split(/\s+/).find(t=>p(t)||y(t))}(t);if(p(n))return;k("before:highlightBlock",{block:t,language:n}),f.useBR?(e=document.createElement("div")).innerHTML=t.innerHTML.replace(/\n/g,"").replace(//g,"\n"):e=t;const r=e.textContent,i=n?d(n,r,!0):m(r),a=$(e);if(a.length){const t=document.createElement("div");t.innerHTML=i.value,i.value=B(a,$(t),r)}i.value=v(i.value),k("after:highlightBlock",{block:t,result:i}),t.innerHTML=i.value,t.className=function(t,e,n){const r=e?o[e]:n,i=[t.trim()];return t.match(/\bhljs\b/)||i.push("hljs"),t.includes(r)||i.push(r),i.join(" ").trim()}(t.className,n,i.language),t.result={language:i.language,re:i.relevance,relavance:i.relevance},i.second_best&&(t.second_best={language:i.second_best.language,re:i.second_best.relevance,relavance:i.second_best.relevance})}const _=()=>{if(_.called)return;_.called=!0;const t=document.querySelectorAll("pre code");e.forEach.call(t,b)};function y(t){return t=(t||"").toLowerCase(),n[t]||n[o[t]]}function E(t,{languageName:e}){"string"==typeof t&&(t=[t]),t.forEach(t=>{o[t]=e})}function x(t){const e=y(t);return e&&!e.disableAutodetect}function k(t,e){const n=t;a.forEach((function(t){t[n]&&t[n](e)}))}Object.assign(t,{highlight:d,highlightAuto:m,fixMarkup:function(t){return console.warn("fixMarkup is deprecated and will be removed entirely in v11.0"),console.warn("Please see https://github.com/highlightjs/highlight.js/issues/2534"),v(t)},highlightBlock:b,configure:function(t){t.useBR&&(console.warn("'useBR' option is deprecated and will be removed entirely in v11.0"),console.warn("Please see https://github.com/highlightjs/highlight.js/issues/2559")),f=U(f,t)},initHighlighting:_,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",_,!1)},registerLanguage:function(e,r){let o=null;try{o=r(t)}catch(t){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!s)throw t;console.error(t),o=l}o.name||(o.name=e),n[e]=o,o.rawDefinition=r.bind(null,t),o.aliases&&E(o.aliases,{languageName:e})},listLanguages:function(){return Object.keys(n)},getLanguage:y,registerAliases:E,requireLanguage:function(t){console.warn("requireLanguage is deprecated and will be removed entirely in the future."),console.warn("Please see https://github.com/highlightjs/highlight.js/pull/2844");const e=y(t);if(e)return e;throw new Error("The '{}' language is required, but not loaded.".replace("{}",t))},autoDetection:x,inherit:U,addPlugin:function(t){a.push(t)},vuePlugin:j(t).VuePlugin}),t.debugMode=function(){s=!1},t.safeMode=function(){s=!0},t.versionString="10.4.1";for(const t in I)"object"==typeof I[t]&&r(I[t]);return Object.assign(t,I),t}({});t.exports=q},function(t,e,n){"use strict";t.exports=n(103)},function(t,e,n){"use strict";t.exports.encode=n(104),t.exports.decode=n(105),t.exports.format=n(106),t.exports.parse=n(107)},function(t,e){t.exports=/[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/},function(t,e){t.exports=/[\0-\x1F\x7F-\x9F]/},function(t,e){t.exports=/[ \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]/},function(t,e,n){"use strict";var r="<[A-Za-z][A-Za-z0-9\\-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:\\s*=\\s*(?:[^\"'=<>`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*\\/?>",o="<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>",i=new RegExp("^(?:"+r+"|"+o+"|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|<[?].*?[?]>|]*>|)"),a=new RegExp("^(?:"+r+"|"+o+")");t.exports.HTML_TAG_RE=i,t.exports.HTML_OPEN_CLOSE_TAG_RE=a},function(t,e,n){"use strict";t.exports.tokenize=function(t,e){var n,r,o,i,a=t.pos,s=t.src.charCodeAt(a);if(e)return!1;if(126!==s)return!1;if(o=(r=t.scanDelims(t.pos,!0)).length,i=String.fromCharCode(s),o<2)return!1;for(o%2&&(t.push("text","",0).content=i,o--),n=0;n=0;e--)95!==(n=s[e]).marker&&42!==n.marker||-1!==n.end&&(r=s[n.end],a=e>0&&s[e-1].end===n.end+1&&s[e-1].token===n.token-1&&s[n.end+1].token===r.token+1&&s[e-1].marker===n.marker,i=String.fromCharCode(n.marker),(o=t.tokens[n.token]).type=a?"strong_open":"em_open",o.tag=a?"strong":"em",o.nesting=1,o.markup=a?i+i:i,o.content="",(o=t.tokens[r.token]).type=a?"strong_close":"em_close",o.tag=a?"strong":"em",o.nesting=-1,o.markup=a?i+i:i,o.content="",a&&(t.tokens[s[e-1].token].content="",t.tokens[s[n.end+1].token].content="",e--))}},function(t,e,n){(function(t,r){var o;/*! https://mths.be/punycode v1.4.1 by @mathias */!function(i){e&&e.nodeType,t&&t.nodeType;var a="object"==typeof r&&r;a.global!==a&&a.window!==a&&a.self;var s,c=2147483647,u=36,l=1,f=26,p=38,d=700,h=72,g=128,m="-",v=/^xn--/,b=/[^\x20-\x7E]/,_=/[\x2E\u3002\uFF0E\uFF61]/g,y={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},E=u-l,x=Math.floor,k=String.fromCharCode;function w(t){throw new RangeError(y[t])}function C(t,e){for(var n=t.length,r=[];n--;)r[n]=e(t[n]);return r}function A(t,e){var n=t.split("@"),r="";return n.length>1&&(r=n[0]+"@",t=n[1]),r+C((t=t.replace(_,".")).split("."),e).join(".")}function T(t){for(var e,n,r=[],o=0,i=t.length;o=55296&&e<=56319&&o65535&&(e+=k((t-=65536)>>>10&1023|55296),t=56320|1023&t),e+=k(t)})).join("")}function R(t,e){return t+22+75*(t<26)-((0!=e)<<5)}function O(t,e,n){var r=0;for(t=n?x(t/d):t>>1,t+=x(t/e);t>E*f>>1;r+=u)t=x(t/E);return x(r+(E+1)*t/(t+p))}function N(t){var e,n,r,o,i,a,s,p,d,v,b,_=[],y=t.length,E=0,k=g,C=h;for((n=t.lastIndexOf(m))<0&&(n=0),r=0;r=128&&w("not-basic"),_.push(t.charCodeAt(r));for(o=n>0?n+1:0;o=y&&w("invalid-input"),((p=(b=t.charCodeAt(o++))-48<10?b-22:b-65<26?b-65:b-97<26?b-97:u)>=u||p>x((c-E)/a))&&w("overflow"),E+=p*a,!(p<(d=s<=C?l:s>=C+f?f:s-C));s+=u)a>x(c/(v=u-d))&&w("overflow"),a*=v;C=O(E-i,e=_.length+1,0==i),x(E/e)>c-k&&w("overflow"),k+=x(E/e),E%=e,_.splice(E++,0,k)}return S(_)}function L(t){var e,n,r,o,i,a,s,p,d,v,b,_,y,E,C,A=[];for(_=(t=T(t)).length,e=g,n=0,i=h,a=0;a<_;++a)(b=t[a])<128&&A.push(k(b));for(r=o=A.length,o&&A.push(m);r<_;){for(s=c,a=0;a<_;++a)(b=t[a])>=e&&bx((c-n)/(y=r+1))&&w("overflow"),n+=(s-e)*y,e=s,a=0;a<_;++a)if((b=t[a])c&&w("overflow"),b==e){for(p=n,d=u;!(p<(v=d<=i?l:d>=i+f?f:d-i));d+=u)C=p-v,E=u-v,A.push(k(R(v+C%E,0))),p=x(C/E);A.push(k(R(p,0))),i=O(n,y,r==o),n=0,++r}++n,++e}return A.join("")}s={version:"1.4.1",ucs2:{decode:T,encode:S},decode:N,encode:L,toASCII:function(t){return A(t,(function(t){return b.test(t)?"xn--"+L(t):t}))},toUnicode:function(t){return A(t,(function(t){return v.test(t)?N(t.slice(4).toLowerCase()):t}))}},void 0===(o=function(){return s}.call(e,n,e,t))||(t.exports=o)}()}).call(this,n(22)(t),n(11))},function(t,e,n){"use strict";t.exports=function(t,e){!0===e&&(e=0);var n=t.indexOf("://"),r=t.substring(0,n).split("+").filter(Boolean);return"number"==typeof e?r[e]:r}},function(t,e,n){"use strict";var r=n(64);t.exports=function t(e){if(Array.isArray(e))return-1!==e.indexOf("ssh")||-1!==e.indexOf("rsync");if("string"!=typeof e)return!1;var n=r(e);return e=e.substring(e.indexOf("://")+3),!!t(n)||e.indexOf("@")=o?t:r(t,e,n)}},function(t,e){var n=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]");t.exports=function(t){return n.test(t)}},function(t,e,n){var r=n(174),o=n(68),i=n(175);t.exports=function(t){return o(t)?i(t):r(t)}},function(t,e,n){var r=n(23),o=n(176),i=n(9),a=n(24),s=1/0,c=r?r.prototype:void 0,u=c?c.toString:void 0;t.exports=function t(e){if("string"==typeof e)return e;if(i(e))return o(e,t)+"";if(a(e))return u?u.call(e):"";var n=e+"";return"0"==n&&1/e==-s?"-0":n}},function(t,e,n){(function(e){var n="object"==typeof e&&e&&e.Object===Object&&e;t.exports=n}).call(this,n(11))},function(t,e,n){var r=n(183),o=n(184),i=n(185);t.exports=function(t,e,n){return e==e?i(t,e,n):r(t,o,n)}},function(t,e){var n=/\s/;t.exports=function(t){for(var e=t.length;e--&&n.test(t.charAt(e)););return e}},function(t,e,n){var r=n(18),o=n(20),i="[object AsyncFunction]",a="[object Function]",s="[object GeneratorFunction]",c="[object Proxy]";t.exports=function(t){if(!o(t))return!1;var e=r(t);return e==a||e==s||e==i||e==c}},function(t,e,n){var r=n(76),o=n(198),i=Object.prototype.hasOwnProperty;t.exports=function(t){if(!r(t))return o(t);var e=[];for(var n in Object(t))i.call(t,n)&&"constructor"!=n&&e.push(n);return e}},function(t,e){var n=Object.prototype;t.exports=function(t){var e=t&&t.constructor;return t===("function"==typeof e&&e.prototype||n)}},function(t,e,n){var r=n(200),o=n(44),i=n(205),a=n(79),s=n(206),c=n(18),u=n(78),l=u(r),f=u(o),p=u(i),d=u(a),h=u(s),g=c;(r&&"[object DataView]"!=g(new r(new ArrayBuffer(1)))||o&&"[object Map]"!=g(new o)||i&&"[object Promise]"!=g(i.resolve())||a&&"[object Set]"!=g(new a)||s&&"[object WeakMap]"!=g(new s))&&(g=function(t){var e=c(t),n="[object Object]"==e?t.constructor:void 0,r=n?u(n):"";if(r)switch(r){case l:return"[object DataView]";case f:return"[object Map]";case p:return"[object Promise]";case d:return"[object Set]";case h:return"[object WeakMap]"}return e}),t.exports=g},function(t,e){var n=Function.prototype.toString;t.exports=function(t){if(null!=t){try{return n.call(t)}catch(t){}try{return t+""}catch(t){}}return""}},function(t,e,n){var r=n(12)(n(8),"Set");t.exports=r},function(t,e,n){var r=n(48),o=n(235),i=n(236);function a(t){var e=-1,n=null==t?0:t.length;for(this.__data__=new r;++ep))return!1;var h=l.get(t),g=l.get(e);if(h&&g)return h==e&&g==t;var m=-1,v=!0,b=n&s?new r:void 0;for(l.set(t,e),l.set(e,t);++m>>24)|4278255360&(n[d]<<24|n[d]>>>8);n[c>>>5]|=128<>>9<<4)]=c;var h=s._ff,g=s._gg,m=s._hh,v=s._ii;for(d=0;d>>0,l=l+_>>>0,f=f+y>>>0,p=p+E>>>0}return r.endian([u,l,f,p])})._ff=function(t,e,n,r,o,i,a){var s=t+(e&n|~e&r)+(o>>>0)+a;return(s<>>32-i)+e},s._gg=function(t,e,n,r,o,i,a){var s=t+(e&r|n&~r)+(o>>>0)+a;return(s<>>32-i)+e},s._hh=function(t,e,n,r,o,i,a){var s=t+(e^n^r)+(o>>>0)+a;return(s<>>32-i)+e},s._ii=function(t,e,n,r,o,i,a){var s=t+(n^(e|~r))+(o>>>0)+a;return(s<>>32-i)+e},s._blocksize=16,s._digestsize=16,t.exports=function(t,e){if(null==t)throw new Error("Illegal argument "+t);var n=r.wordsToBytes(s(t,e));return e&&e.asBytes?n:e&&e.asString?a.bytesToString(n):r.bytesToHex(n)}},function(t,e,n){var r=n(95);"string"==typeof r&&(r=[[t.i,r,""]]);var o={hmr:!0,transform:void 0,insertInto:void 0};n(97)(r,o);r.locals&&(t.exports=r.locals)},function(t,e,n){(t.exports=n(96)(!1)).push([t.i,'@charset \'UTF-8\';\n\n/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */\n\n/* Document\n ========================================================================== */\n\n/**\n * 1. Correct the line height in all browsers.\n * 2. Prevent adjustments of font size after orientation changes in iOS.\n */\n\nhtml {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/* Sections\n ========================================================================== */\n\n/**\n * Remove the margin in all browsers.\n */\n\nbody {\n margin: 0;\n}\n\n/**\n * Render the `main` element consistently in IE.\n */\n\nmain {\n display: block;\n}\n\n/**\n * Correct the font size and margin on `h1` elements within `section` and\n * `article` contexts in Chrome, Firefox, and Safari.\n */\n\n/* Grouping content\n ========================================================================== */\n\n/**\n * 1. Add the correct box sizing in Firefox.\n * 2. Show the overflow in Edge and IE.\n */\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\npre {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/* Text-level semantics\n ========================================================================== */\n\n/**\n * Remove the gray background on active links in IE 10.\n */\n\na {\n background-color: transparent;\n}\n\n/**\n * 1. Remove the bottom border in Chrome 57-\n * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n */\n\n/**\n * Add the correct font weight in Chrome, Edge, and Safari.\n */\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\ncode {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/**\n * Add the correct font size in all browsers.\n */\n\n/**\n * Prevent `sub` and `sup` elements from affecting the line height in\n * all browsers.\n */\n\n/* Embedded content\n ========================================================================== */\n\n/**\n * Remove the border on images inside links in IE 10.\n */\n\n/* Forms\n ========================================================================== */\n\n/**\n * 1. Change the font styles in all browsers.\n * 2. Remove the margin in Firefox and Safari.\n */\n\nbutton,\ninput,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n}\n\n/**\n * Show the overflow in IE.\n * 1. Show the overflow in Edge.\n */\n\nbutton,\ninput { /* 1 */\n overflow: visible;\n}\n\n/**\n * Remove the inheritance of text transform in Edge, Firefox, and IE.\n * 1. Remove the inheritance of text transform in Firefox.\n */\n\nbutton,\nselect { /* 1 */\n text-transform: none;\n}\n\n/**\n * Correct the inability to style clickable types in iOS and Safari.\n */\n\nbutton,\n[type="button"],\n[type="reset"],\n[type="submit"] {\n -webkit-appearance: button;\n}\n\n/**\n * Remove the inner border and padding in Firefox.\n */\n\nbutton::-moz-focus-inner,\n[type="button"]::-moz-focus-inner,\n[type="reset"]::-moz-focus-inner,\n[type="submit"]::-moz-focus-inner {\n border-style: none;\n padding: 0;\n}\n\n/**\n * Restore the focus styles unset by the previous rule.\n */\n\nbutton:-moz-focusring,\n[type="button"]:-moz-focusring,\n[type="reset"]:-moz-focusring,\n[type="submit"]:-moz-focusring {\n outline: 1px dotted ButtonText;\n}\n\n/**\n * Correct the padding in Firefox.\n */\n\n/**\n * 1. Correct the text wrapping in Edge and IE.\n * 2. Correct the color inheritance from `fieldset` elements in IE.\n * 3. Remove the padding so developers are not caught out when they zero out\n * `fieldset` elements in all browsers.\n */\n\nlegend {\n box-sizing: border-box; /* 1 */\n color: inherit; /* 2 */\n display: table; /* 1 */\n max-width: 100%; /* 1 */\n padding: 0; /* 3 */\n white-space: normal; /* 1 */\n}\n\n/**\n * Add the correct vertical alignment in Chrome, Firefox, and Opera.\n */\n\n/**\n * Remove the default vertical scrollbar in IE 10+.\n */\n\ntextarea {\n overflow: auto;\n}\n\n/**\n * 1. Add the correct box sizing in IE 10.\n * 2. Remove the padding in IE 10.\n */\n\n[type="checkbox"],\n[type="radio"] {\n box-sizing: border-box; /* 1 */\n padding: 0; /* 2 */\n}\n\n/**\n * Correct the cursor style of increment and decrement buttons in Chrome.\n */\n\n[type="number"]::-webkit-inner-spin-button,\n[type="number"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n/**\n * 1. Correct the odd appearance in Chrome and Safari.\n * 2. Correct the outline style in Safari.\n */\n\n[type="search"] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/**\n * Remove the inner padding in Chrome and Safari on macOS.\n */\n\n[type="search"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/**\n * 1. Correct the inability to style clickable types in iOS and Safari.\n * 2. Change font properties to `inherit` in Safari.\n */\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/* Interactive\n ========================================================================== */\n\n/*\n * Add the correct display in Edge, IE 10+, and Firefox.\n */\n\n/*\n * Add the correct display in all browsers.\n */\n\n/* Misc\n ========================================================================== */\n\n/**\n * Add the correct display in IE 10+.\n */\n\ntemplate {\n display: none;\n}\n\n/**\n * Add the correct display in IE 10.\n */\n\n[hidden] {\n display: none;\n}\n\n/**\n * Manually forked from SUIT CSS Base: https://github.com/suitcss/base\n * A thin layer on top of normalize.css that provides a starting point more\n * suitable for web applications.\n */\n\n/**\n * 1. Prevent padding and border from affecting element width\n * https://goo.gl/pYtbK7\n * 2. Change the default font family in all browsers (opinionated)\n */\n\nhtml {\n box-sizing: border-box; /* 1 */\n font-family: sans-serif; /* 2 */\n}\n\n*,\n*::before,\n*::after {\n box-sizing: inherit;\n}\n\n/**\n * Removes the default spacing and border for appropriate elements.\n */\n\n\ndl,\ndd,\nh2,\nh3,\nh5,\np,\npre {\n margin: 0;\n}\n\nbutton {\n background: transparent;\n padding: 0;\n}\n\n/**\n * Work around a Firefox/IE bug where the transparent `button` background\n * results in a loss of the default `button` focus styles.\n */\n\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\nol,\nul {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n/**\n * Tailwind custom reset styles\n */\n\n/**\n * 1. Use the system font stack as a sane default.\n * 2. Use Tailwind\'s default "normal" line-height so the user isn\'t forced\n * to override it to ensure consistency even when using the default theme.\n */\n\nhtml {\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 1 */\n line-height: 1.5; /* 2 */\n}\n\n/**\n * Allow adding a border to an element by just adding a border-width.\n *\n * By default, the way the browser specifies that an element should have no\n * border is by setting it\'s border-style to `none` in the user-agent\n * stylesheet.\n *\n * In order to easily add borders to elements by just setting the `border-width`\n * property, we change the default border-style for all elements to `solid`, and\n * use border-width to hide them instead. This way our `border` utilities only\n * need to set the `border-width` property instead of the entire `border`\n * shorthand, making our border utilities much more straightforward to compose.\n *\n * https://github.com/tailwindcss/tailwindcss/pull/116\n */\n\n*,\n*::before,\n*::after {\n border-width: 0;\n border-style: solid;\n border-color: rgb(232, 229, 239);\n border-color: var(--gray-300);\n}\n\n/*\n * Ensure horizontal rules are visible by default\n */\n\n/**\n * Undo the `border-style: none` reset that Normalize applies to images so that\n * our `border-{width}` utilities have the expected effect.\n *\n * The Normalize reset is unnecessary for us since we default the border-width\n * to 0 on all elements.\n *\n * https://github.com/tailwindcss/tailwindcss/issues/362\n */\n\ntextarea {\n resize: vertical;\n}\n\ninput::-moz-placeholder,\ntextarea::-moz-placeholder {\n color: #a0aec0;\n}\n\ninput:-ms-input-placeholder,\ntextarea:-ms-input-placeholder {\n color: #a0aec0;\n}\n\ninput::placeholder,\ntextarea::placeholder {\n color: #a0aec0;\n}\n\nbutton,\n[role="button"] {\n cursor: pointer;\n}\n\n\nh2,\nh3,\nh5 {\n font-size: inherit;\n font-weight: inherit;\n}\n\n/**\n * Reset links to optimize for opt-in styling instead of\n * opt-out.\n */\n\na {\n color: inherit;\n text-decoration: inherit;\n}\n\n/**\n * Reset form element properties that are easy to forget to\n * style explicitly so you don\'t inadvertently introduce\n * styles that deviate from your design system. These styles\n * supplement a partial reset that is already applied by\n * normalize.css.\n */\n\nbutton,\ninput,\nselect,\ntextarea {\n padding: 0;\n line-height: inherit;\n color: inherit;\n}\n\n/**\n * Use the configured \'mono\' font family for elements that\n * are expected to be rendered with a monospace font, falling\n * back to the system monospace stack if there is no configured\n * \'mono\' font family.\n */\n\npre,\ncode {\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;\n}\n\n/**\n * Make replaced elements `display: block` by default as that\'s\n * the behavior you want almost all of the time. Inspired by\n * CSS Remedy, with `svg` added as well.\n *\n * https://github.com/mozdevs/cssremedy/issues/14\n */\n\n\nsvg,\ncanvas {\n display: block;\n vertical-align: middle;\n}\n\n/**\n * Constrain images and videos to the parent width and preserve\n * their instrinsic aspect ratio.\n *\n * https://github.com/mozdevs/cssremedy/issues/14\n */\n\n:root {\n --white: rgb(255, 255, 255);\n --blue-400: rgb(122, 122, 255);\n --green-100: rgb(227, 255, 242);\n --green-300: rgb(148, 242, 200);\n --green-400: rgb(114, 224, 175);\n --green-500: rgb(34, 212, 146);\n --purple-100: rgb(251, 245, 255);\n --purple-200: rgb(236, 211, 253);\n --purple-300: rgb(214, 188, 250);\n --purple-400: rgb(183, 148, 244);\n --purple-500: rgb(121, 0, 245);\n --purple-600: rgb(113, 7, 220);\n --purple-800: rgb(79, 15, 143);\n --red-100: rgb(255, 235, 243);\n --red-300: rgb(250, 133, 162);\n --red-400: rgb(250, 78, 121);\n --yellow-100: rgb(255, 253, 235);\n --yellow-200: rgb(255, 248, 196);\n --yellow-300: rgb(255, 243, 148);\n --yellow-400: rgb(255, 234, 79);\n --tint-50: rgba(0, 0, 150, 0.015);\n --tint-100: rgba(0, 0, 150, 0.025);\n --tint-200: rgba(0, 0, 100, 0.07);\n --tint-300: rgba(25, 0, 100, 0.1);\n --tint-400: rgba(20, 0, 100, 0.2);\n --tint-500: rgba(30, 20, 90, 0.35);\n --tint-600: rgba(30, 20, 70, 0.5);\n --tint-700: rgba(15, 10, 60, 0.75);\n --gray-50: rgb(252, 252, 253);\n --gray-100: rgb(247, 247, 252);\n --gray-200: rgb(238, 238, 245);\n --gray-300: rgb(232, 229, 239);\n --gray-400: rgb(209, 204, 224);\n --gray-500: rgb(176, 173, 197);\n --gray-600: rgb(142, 137, 162);\n --gray-700: rgb(75, 71, 109);\n --gray-800: rgb(51, 47, 81);\n /* dark theme */\n --dark-white: rgb(38, 38, 50);\n --dark-blue-400: rgb(85, 0, 255);\n --dark-green-100: rgb(32, 97, 90);\n --dark-green-300: rgb(55, 111, 123);\n --dark-green-500: rgb(63, 152, 142);\n --dark-purple-100: rgb(60, 46, 96);\n --dark-purple-200: rgb(81, 50, 128);\n --dark-purple-300: rgb(104, 85, 147);\n --dark-purple-400: rgb(106, 87, 148);\n --dark-purple-500: rgb(126, 107, 167);\n --dark-purple-600: rgb(145, 127, 183);\n --dark-purple-800: rgb(158, 140, 194);\n --dark-red-100: rgb(255, 235, 243);\n --dark-red-300: rgb(250, 133, 162);\n --dark-red-400: rgb(250, 78, 121);\n --dark-yellow-100: rgb(61, 57, 49);\n --dark-yellow-200: rgb(90, 78, 53);\n --dark-yellow-300: rgb(119, 103, 70);\n --dark-yellow-400: rgb(145, 121, 90);\n --dark-tint-50: rgba(240, 240, 245, 0.05);\n --dark-tint-100: rgba(240, 240, 245, 0.075);\n --dark-tint-200: rgba(240, 240, 245, 0.1);\n --dark-tint-300: rgba(240, 240, 245, 0.125);\n --dark-tint-400: rgba(240, 240, 245, 0.25);\n --dark-tint-500: rgba(240, 240, 245, 0.45);\n --dark-tint-600: rgba(240, 240, 245, 0.55);\n --dark-tint-700: rgba(240, 240, 245, 0.65);\n --dark-gray-0: rgb(30, 30, 40);\n --dark-gray-50: rgb(38, 38, 50);\n --dark-gray-100: rgb(48, 48, 58);\n --dark-gray-200: rgb(51, 51, 65);\n --dark-gray-300: rgb(75, 75, 85);\n --dark-gray-400: rgb(142, 142, 160);\n --dark-gray-500: rgb(152, 152, 170);\n --dark-gray-600: rgb(165, 165, 175);\n --dark-gray-700: rgb(216, 216, 223);\n --dark-gray-800: rgb(230, 230, 235);\n --dark-shadow-sm: \'0 2px 0 var(--gray-0)\';\n --dark-shadow-default: \'0 2px 0 var(--gray-50), 2px 4px 0 var(--gray-0)\';\n --dark-shadow-lg: \'0 2px 0 var(--gray-100), 2px 4px 0 var(--gray-50), 4px 6px 0 var(--gray-0)\';\n --dark-shadow-input: \'inset 0 2px 0 var(--gray-100)\';\n}\n\nhtml {\n box-sizing: border-box;\n font-size: 14px;\n background-color: rgb(238, 238, 245);\n background-color: var(--gray-200);\n overflow-x: hidden;\n overflow-y: scroll;\n}\n\n@media (min-width: 1024px) {\n html {\n font-size: 16px;\n }\n}\n\n/* Exclude iframes like 1Password save modals */\n\n*:not(iframe),\n*:after,\n*:before {\n position: relative;\n}\n\n*:focus {\n outline: 0 !important;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";\n color: rgb(51, 47, 81);\n color: var(--gray-800);\n line-height: 1.5;\n width: 100%;\n}\n\n/* Dark theme */\n\n@media (prefers-color-scheme: dark) {\n html.theme-auto {\n --white: var(--dark-white);\n --blue-400: var(--dark-blue-400);\n --green-100: var(--dark-green-100);\n --green-300: var(--dark-green-300);\n --green-400: var(--dark-green-400);\n --green-500: var(--dark-green-500);\n --purple-100: var(--dark-purple-100);\n --purple-200: var(--dark-purple-200);\n --purple-300: var(--dark-purple-300);\n --purple-400: var(--dark-purple-400);\n --purple-500: var(--dark-purple-500);\n --purple-600: var(--dark-purple-600);\n --purple-800: var(--dark-purple-800);\n --red-100: var(--dark-red-100);\n --red-300: var(--dark-red-300);\n --red-400: var(--dark-red-400);\n --yellow-100: var(--dark-yellow-100);\n --yellow-200: var(--dark-yellow-200);\n --yellow-300: var(--dark-yellow-300);\n --yellow-400: var(--dark-yellow-400);\n --tint-50: var(--dark-tint-50);\n --tint-100: var(--dark-tint-100);\n --tint-200: var(--dark-tint-200);\n --tint-300: var(--dark-tint-300);\n --tint-400: var(--dark-tint-400);\n --tint-500: var(--dark-tint-500);\n --tint-600: var(--dark-tint-600);\n --tint-700: var(--dark-tint-700);\n --gray-0: var(--dark-gray-0);\n --gray-50: var(--dark-gray-50);\n --gray-100: var(--dark-gray-100);\n --gray-200: var(--dark-gray-200);\n --gray-300: var(--dark-gray-300);\n --gray-400: var(--dark-gray-400);\n --gray-500: var(--dark-gray-500);\n --gray-600: var(--dark-gray-600);\n --gray-700: var(--dark-gray-700);\n --gray-800: var(--dark-gray-800);\n --shadow-sm: \'0 2px 0 var(--gray-50)\';\n --shadow-default: \'0 2px 0 var(--gray-100), 2px 4px 0 var(--gray-50)\';\n --shadow-lg: \'0 2px 0 var(--gray-200), 2px 4px 0 var(--gray-100), 4px 6px 0 var(--gray-50)\';\n --shadow-input: \'inset 0 2px 0 var(--gray-100)\';\n }\n\n html.theme-auto {\n background-color: rgb(30, 30, 40);\n background-color: var(--dark-gray-0);\n }\n\n html.theme-auto .checkbox:before {\n background-color: rgb(51, 47, 81);\n background-color: var(--gray-800);\n }\n\n html.theme-auto .tab-nav,\n html.theme-auto .dropdown {\n background-color: rgb(209, 204, 224);\n background-color: var(--gray-400);\n }\n}\n\nhtml.theme-dark {\n --white: var(--dark-white);\n --blue-400: var(--dark-blue-400);\n --green-100: var(--dark-green-100);\n --green-300: var(--dark-green-300);\n --green-400: var(--dark-green-400);\n --green-500: var(--dark-green-500);\n --purple-100: var(--dark-purple-100);\n --purple-200: var(--dark-purple-200);\n --purple-300: var(--dark-purple-300);\n --purple-400: var(--dark-purple-400);\n --purple-500: var(--dark-purple-500);\n --purple-600: var(--dark-purple-600);\n --purple-800: var(--dark-purple-800);\n --red-100: var(--dark-red-100);\n --red-300: var(--dark-red-300);\n --red-400: var(--dark-red-400);\n --yellow-100: var(--dark-yellow-100);\n --yellow-200: var(--dark-yellow-200);\n --yellow-300: var(--dark-yellow-300);\n --yellow-400: var(--dark-yellow-400);\n --tint-50: var(--dark-tint-50);\n --tint-100: var(--dark-tint-100);\n --tint-200: var(--dark-tint-200);\n --tint-300: var(--dark-tint-300);\n --tint-400: var(--dark-tint-400);\n --tint-500: var(--dark-tint-500);\n --tint-600: var(--dark-tint-600);\n --tint-700: var(--dark-tint-700);\n --gray-0: var(--dark-gray-0);\n --gray-50: var(--dark-gray-50);\n --gray-100: var(--dark-gray-100);\n --gray-200: var(--dark-gray-200);\n --gray-300: var(--dark-gray-300);\n --gray-400: var(--dark-gray-400);\n --gray-500: var(--dark-gray-500);\n --gray-600: var(--dark-gray-600);\n --gray-700: var(--dark-gray-700);\n --gray-800: var(--dark-gray-800);\n --shadow-sm: \'0 2px 0 var(--gray-50)\';\n --shadow-default: \'0 2px 0 var(--gray-100), 2px 4px 0 var(--gray-50)\';\n --shadow-lg: \'0 2px 0 var(--gray-200), 2px 4px 0 var(--gray-100), 4px 6px 0 var(--gray-50)\';\n --shadow-input: \'inset 0 2px 0 var(--gray-100)\';\n}\n\nhtml.theme-dark {\n background-color: rgb(30, 30, 40);\n background-color: var(--dark-gray-0);\n}\n\nhtml.theme-dark .checkbox:before {\n background-color: rgb(51, 47, 81);\n background-color: var(--gray-800);\n}\n\nhtml.theme-dark .tab-nav,\nhtml.theme-dark .dropdown {\n background-color: rgb(209, 204, 224);\n background-color: var(--gray-400);\n}\n\n.alert-empty {\n color: rgba(30, 20, 90, 0.35);\n color: var(--tint-500);\n padding-top: 2rem;\n padding-bottom: 2rem;\n text-align: center;\n}\n\n.button {\n display: inline-flex;\n align-items: center;\n justify-items: center;\n align-content: center;\n justify-content: center;\n padding-left: 1rem;\n padding-right: 1rem;\n min-height: 2.5rem;\n border-width: 0;\n background-color: rgb(121, 0, 245);\n background-color: var(--purple-500);\n overflow: hidden;\n border-radius: 0.125rem;\n color: rgb(255, 255, 255);\n color: var(--white);\n line-height: 1;\n text-decoration: none;\n}\n\n.button:after {\n content: \'\';\n display: block;\n position: absolute;\n left: 100%;\n bottom: 0;\n width: 200%;\n height: 100vh;\n background-color: rgba(30, 20, 90, 0.35);\n background-color: var(--tint-500);\n transform: translateX(-1rem) skewX(-65deg);\n transform-origin: 0% 100%;\n transition: transform 0.75s ease-out;\n}\n\n.button:hover:after {\n transform: translateX(-1.5rem) skewX(-65deg);\n transition-duration: 0.3s;\n}\n\n.button:not(:disabled):active:after {\n transition-delay: 0.2s;\n transition-duration: 0.3s;\n transform: translateX(-100%) skewX(-65deg);\n}\n\n.button-secondary {\n display: inline-flex;\n align-items: center;\n justify-items: center;\n align-content: center;\n justify-content: center;\n padding-left: 1rem;\n padding-right: 1rem;\n min-height: 2.5rem;\n border-width: 0;\n background-color: rgb(121, 0, 245);\n background-color: var(--purple-500);\n overflow: hidden;\n border-radius: 0.125rem;\n color: rgb(255, 255, 255);\n color: var(--white);\n line-height: 1;\n text-decoration: none;\n background-color: rgba(0, 0, 100, 0.07);\n background-color: var(--tint-200);\n color: rgba(15, 10, 60, 0.75);\n color: var(--tint-700);\n}\n\n.button-secondary:hover {\n background-color: rgba(25, 0, 100, 0.1);\n background-color: var(--tint-300);\n}\n\n.button-secondary:not(:disabled):active {\n background-color: rgba(30, 20, 90, 0.35);\n background-color: var(--tint-500);\n opacity: 0.5;\n}\n\n.button:focus,\n.button-secondary:focus {\n outline: 0;\n}\n\n.button:disabled,\n.button-secondary:disabled {\n cursor: not-allowed;\n opacity: 0.25;\n}\n\n.button-sm {\n font-size: 0.875rem;\n}\n\n.button.button-sm,\n.button-secondary.button-sm {\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n min-height: 1.5rem;\n border-radius: 0.125rem;\n}\n\n.button-lg {\n font-size: 1.125rem;\n}\n\n.button.button-lg,\n.button-secondary.button-lg {\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n min-height: 3rem;\n}\n\n.button-lg.button:after {\n transform: translateX(-2rem) skewX(-65deg);\n}\n\n.button-lg.button:hover:after {\n transform: translateX(-3rem) skewX(-65deg);\n}\n\n.card {\n position: relative;\n display: grid;\n align-items: stretch;\n border-width: 1px;\n border-color: rgba(25, 0, 100, 0.1);\n border-color: var(--tint-300);\n background-color: rgb(255, 255, 255);\n background-color: var(--white);\n box-shadow: var(--shadow-sm);\n border-radius: 0.125rem;\n}\n\n.card-details {\n overflow: hidden;\n}\n\n.card-details-overflow {\n display: grid;\n grid-gap: 1rem;\n padding: 1.5rem;\n overflow-x: auto;\n}\n\n.card-danger {\n background-color: rgb(250, 78, 121);\n background-color: var(--red-400);\n color: rgb(255, 255, 255);\n color: var(--white);\n}\n\n@media (min-width: 768px) {\n .card {\n grid-template-columns: 16rem 1fr;\n }\n\n .card-has-header {\n grid-template-rows: auto 1fr;\n }\n\n .card.card-no-props {\n display: block;\n }\n\n .card-header {\n grid-column-end: span 2;\n }\n\n .card-details-overflow {\n padding: 2rem;\n }\n}\n\n.checkbox-label {\n display: grid;\n justify-content: flex-start;\n grid-template-columns: auto;\n grid-auto-flow: column;\n grid-gap: 0.5rem;\n min-height: 0;\n cursor: pointer;\n color: rgb(51, 47, 81);\n color: var(--gray-800);\n}\n\n.checkbox {\n width: 1.5em;\n height: 1.5em;\n border-style: none;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.checkbox:before {\n position: absolute;\n width: 1.5em;\n height: 1.5em;\n border-width: 1px;\n border-color: rgba(0, 0, 100, 0.07);\n border-color: var(--tint-200);\n background-color: rgb(252, 252, 253);\n background-color: var(--gray-50);\n box-shadow: var(--shadow-default);\n border-radius: 0.125rem;\n overflow: hidden;\n content: \'\';\n}\n\n.checkbox:after {\n position: absolute;\n top: 50%;\n left: 50%;\n color: rgb(121, 0, 245);\n color: var(--purple-500);\n font-size: 1.2em;\n font-weight: 900;\n line-height: 1;\n content: \'✓\';\n transition: transform 0.1s;\n transform: translate(-50%, -50%) scale(0);\n}\n\n.checkbox:focus,\n.checkbox:hover {\n outline: 0;\n}\n\n.checkbox:focus:before {\n border-color: rgba(25, 0, 100, 0.1);\n border-color: var(--tint-300);\n background-color: rgb(255, 255, 255);\n background-color: var(--white);\n}\n\n.checkbox:hover:before {\n border-color: rgba(25, 0, 100, 0.1);\n border-color: var(--tint-300);\n}\n\n.checkbox:checked:after {\n transform: translate(-50%, -50%) scale(1);\n}\n\n.checkbox:disabled {\n opacity: 0.5;\n}\n\n.code {\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;\n color: rgb(75, 71, 109);\n color: var(--gray-700);\n}\n\n.code-inline {\n display: inline-block;\n margin-top: -0.25rem;\n margin-bottom: -0.25rem;\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n border-radius: 0.125rem;\n background-color: rgb(247, 247, 252);\n background-color: var(--gray-100);\n border-width: 1px;\n border-color: rgba(0, 0, 150, 0.025);\n border-color: var(--tint-100);\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;\n color: rgb(75, 71, 109);\n color: var(--gray-700);\n word-break: break-all;\n}\n\n.code-block {\n display: block;\n padding-left: 1rem;\n padding-right: 1rem;\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n border-radius: 0.125rem;\n background-color: rgb(247, 247, 252);\n background-color: var(--gray-100);\n border-width: 1px;\n border-color: rgba(0, 0, 150, 0.025);\n border-color: var(--tint-100);\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;\n color: rgb(75, 71, 109);\n color: var(--gray-700);\n}\n\n.code-inline pre,\n.code-block pre {\n white-space: pre-wrap;\n}\n\n.definition-list {\n display: grid;\n grid-column-gap: 1.5rem;\n grid-row-gap: 0.5rem;\n}\n\n.definition-list .definition-list {\n border-left-width: 2px;\n border-color: rgb(232, 229, 239);\n border-color: var(--gray-300);\n padding-left: 1rem;\n}\n\n@media (min-width: 640px) {\n .definition-list {\n grid-template-columns: 8rem 1fr;\n }\n\n .definition-list .definition-list {\n grid-template-columns: auto 1fr;\n }\n}\n\n@media (min-width: 1024px) {\n .definition-list {\n grid-template-columns: 14rem 1fr;\n }\n}\n\n.definition-list-title {\n font-weight: 600;\n margin-bottom: 0.75rem;\n}\n\n@media (min-width: 640px) {\n .definition-list-title {\n margin-left: 9.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .definition-list-title {\n margin-left: 15.5rem;\n }\n}\n\n.definition-label {\n color: rgba(30, 20, 70, 0.5);\n color: var(--tint-600);\n word-wrap: break-word;\n line-height: 1.25;\n}\n\n@media (min-width: 640px) {\n .definition-label {\n text-align: right;\n }\n}\n\n.definition-value {\n word-break: break-all;\n margin-bottom: 1rem;\n line-height: 1.25;\n}\n\n@media (min-width: 640px) {\n .definition-value {\n margin-bottom: 0;\n }\n}\n\n.definition-label:empty:after,\n.definition-value:empty:after {\n content: \'—\';\n color: rgb(232, 229, 239);\n color: var(--gray-300);\n}\n\n.definition-list-empty {\n color: rgb(232, 229, 239);\n color: var(--gray-300);\n}\n\n@media (min-width: 640px) {\n .definition-list-empty {\n grid-column-start: 2;\n }\n\n .definition-list .definition-list .definition-list-empty {\n grid-column-start: 1;\n }\n}\n\n.dropdown {\n position: absolute;\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n overflow-y: auto;\n max-height: \'66vh\';\n border-width: 1px;\n border-top-width: 0;\n border-color: rgba(0, 0, 100, 0.07);\n border-color: var(--tint-200);\n color: rgb(255, 255, 255);\n color: var(--white);\n background-color: rgb(75, 71, 109);\n background-color: var(--gray-700);\n}\n\n.layout-col {\n max-width: 80rem;\n padding-left: 1rem;\n padding-right: 1rem;\n margin-left: auto;\n margin-right: auto;\n}\n\n@media (min-width: 640px) {\n .layout-col {\n padding-left: 2.5rem;\n padding-right: 2.5rem;\n }\n}\n\n.link {\n text-decoration: underline;\n -webkit-text-decoration-color: rgb(209, 204, 224);\n text-decoration-color: rgb(209, 204, 224);\n -webkit-text-decoration-color: var(--gray-400);\n text-decoration-color: var(--gray-400);\n}\n\n.link:hover {\n color: rgb(121, 0, 245);\n color: var(--purple-500);\n -webkit-text-decoration-color: rgb(214, 188, 250);\n text-decoration-color: rgb(214, 188, 250);\n -webkit-text-decoration-color: var(--purple-300);\n text-decoration-color: var(--purple-300);\n}\n\n.links a {\n text-decoration: underline;\n -webkit-text-decoration-color: rgb(209, 204, 224);\n text-decoration-color: rgb(209, 204, 224);\n -webkit-text-decoration-color: var(--gray-400);\n text-decoration-color: var(--gray-400);\n}\n\n.links a:hover {\n color: rgb(121, 0, 245);\n color: var(--purple-500);\n -webkit-text-decoration-color: rgb(214, 188, 250);\n text-decoration-color: rgb(214, 188, 250);\n -webkit-text-decoration-color: var(--purple-300);\n text-decoration-color: var(--purple-300);\n}\n\n.link-dimmed {\n font-weight: 400;\n text-decoration: underline;\n color: rgba(30, 20, 70, 0.5);\n color: var(--tint-600);\n -webkit-text-decoration-color: rgba(20, 0, 100, 0.2);\n text-decoration-color: rgba(20, 0, 100, 0.2);\n -webkit-text-decoration-color: var(--tint-400);\n text-decoration-color: var(--tint-400);\n}\n\n.link-dimmed:hover {\n color: rgba(15, 10, 60, 0.75);\n color: var(--tint-700);\n -webkit-text-decoration-color: rgba(30, 20, 90, 0.35);\n text-decoration-color: rgba(30, 20, 90, 0.35);\n -webkit-text-decoration-color: var(--tint-500);\n text-decoration-color: var(--tint-500);\n}\n\n.link-solution {\n text-decoration: underline;\n color: rgb(75, 71, 109);\n color: var(--gray-700);\n -webkit-text-decoration-color: rgba(20, 0, 100, 0.2);\n text-decoration-color: rgba(20, 0, 100, 0.2);\n -webkit-text-decoration-color: var(--tint-400);\n text-decoration-color: var(--tint-400);\n}\n\n.link-solution:hover {\n color: rgb(51, 47, 81);\n color: var(--gray-800);\n -webkit-text-decoration-color: rgba(30, 20, 90, 0.35);\n text-decoration-color: rgba(30, 20, 90, 0.35);\n -webkit-text-decoration-color: var(--tint-500);\n text-decoration-color: var(--tint-500);\n}\n\n.grid {\n display: grid;\n}\n\n.cols-2 {\n grid-template-columns: repeat(2, 1fr);\n}\n\n.cols-auto {\n grid-template-columns: auto;\n grid-auto-flow: column;\n}\n\n.cols-auto-1fr {\n grid-template-columns: auto 1fr;\n}\n\n.gap-1 {\n grid-gap: 0.25rem;\n}\n\n.gap-2 {\n grid-gap: 0.5rem;\n}\n\n.gapy-2 {\n grid-row-gap: 0.5rem;\n}\n\n.gap-4 {\n grid-gap: 1rem;\n}\n\n.gapx-4 {\n grid-column-gap: 1rem;\n}\n\n.gapx-6 {\n grid-column-gap: 1.5rem;\n}\n\n.span-2 {\n grid-column-end: span 2;\n}\n\n.place-center {\n align-items: center;\n justify-items: center;\n align-content: center;\n justify-content: center;\n}\n\n.icon {\n fill: currentColor;\n height: 1em;\n line-height: 1;\n width: 1em;\n display: inline-block;\n vertical-align: baseline;\n vertical-align: initial;\n}\n\n.scrollbar::-webkit-scrollbar,\n.scrollbar::-webkit-scrollbar-corner {\n width: 4px;\n height: 4px;\n}\n\n.scrollbar::-webkit-scrollbar-track {\n background-color: rgb(255, 255, 255);\n background-color: var(--white);\n}\n\n.scrollbar::-webkit-scrollbar-track:horizontal,\n.scrollbar-lg::-webkit-scrollbar-track:horizontal {\n border-top: solid 1px rgba(0, 0, 0, 0.1);\n}\n\n.scrollbar::-webkit-scrollbar-track:vertical,\n.scrollbar-lg::-webkit-scrollbar-track:vertical {\n border-left: solid 1px rgba(0, 0, 0, 0.1);\n}\n\n.scrollbar::-webkit-scrollbar-thumb {\n background-color: rgb(209, 204, 224);\n background-color: var(--gray-400);\n border-radius: 2px;\n}\n\n.scrollbar-lg::-webkit-scrollbar,\n.scrollbar-lg::-webkit-scrollbar-corner {\n width: 8px;\n height: 8px;\n}\n\n.scrollbar-lg::-webkit-scrollbar-track {\n background-color: rgb(252, 252, 253);\n background-color: var(--gray-50);\n}\n\n.scrollbar-lg::-webkit-scrollbar-thumb {\n background-color: rgb(142, 137, 162);\n background-color: var(--gray-600);\n border-radius: 4px;\n}\n\n:root {\n --stack-height: var(--tab-main-height);\n}\n\n.stack {\n display: grid;\n grid-template: calc(0.4 * calc(100vh - 3rem)) calc(0.6 * calc(100vh - 3rem)) / 1fr;\n grid-template: calc(0.4 * var(--stack-height)) calc(0.6 * var(--stack-height)) / 1fr;\n}\n\n@media (min-width: 640px) {\n .stack {\n align-items: stretch;\n grid-template: calc(100vh - 3rem) / 22rem 1fr;\n grid-template: var(--stack-height) / 22rem 1fr;\n }\n}\n\n.stack-nav {\n height: 100%;\n background-color: rgb(255, 255, 255);\n background-color: var(--white);\n border-bottom-width: 1px;\n border-color: rgb(232, 229, 239);\n border-color: var(--gray-300);\n font-size: 0.75rem;\n overflow: hidden;\n display: grid;\n grid-template: 1fr / 100%;\n}\n\n@media (min-width: 640px) {\n .stack-nav {\n display: grid;\n grid-template: auto 1fr / 100%;\n border-bottom-width: 0;\n border-right-width: 1px;\n }\n}\n\n.stack-nav-actions {\n display: none;\n}\n\n@media (min-width: 640px) {\n .stack-nav-actions {\n display: grid;\n align-items: center;\n justify-content: space-between;\n grid-template-columns: auto;\n grid-auto-flow: column;\n padding-top: 1rem;\n padding-bottom: 1rem;\n background-color: rgb(247, 247, 252);\n background-color: var(--gray-100);\n }\n}\n\n.stack-nav-arrows {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n justify-content: center;\n align-items: center;\n grid-gap: 0.25rem;\n width: 2.5rem;\n padding-left: 0.75rem;\n padding-right: 0.75rem;\n}\n\n.stack-nav-arrow {\n color: rgb(176, 173, 197);\n color: var(--gray-500);\n font-size: 0.75rem;\n}\n\n.stack-nav-arrow:hover {\n color: rgb(75, 71, 109);\n color: var(--gray-700);\n}\n\n.stack-frames {\n overflow: hidden;\n border-top-width: 1px;\n border-color: rgb(238, 238, 245);\n border-color: var(--gray-200);\n}\n\n.stack-frames-scroll {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n.stack-frame-group {\n border-bottom-width: 1px;\n border-color: rgb(232, 229, 239);\n border-color: var(--gray-300);\n background-color: rgb(255, 255, 255);\n background-color: var(--white);\n}\n\n.stack-frame {\n display: grid;\n align-items: flex-end;\n grid-template-columns: 2rem auto auto;\n}\n\n@media (min-width: 640px) {\n .stack-frame {\n grid-template-columns: 3rem 1fr auto;\n }\n}\n\n.stack-frame:not(:first-child) {\n margin-top: -0.5rem;\n}\n\n.stack-frame-selected,\n.stack-frame-selected .stack-frame-header {\n background-color: rgb(251, 245, 255);\n background-color: var(--purple-100);\n z-index: 10;\n}\n\n.stack-frame-group-vendor .stack-frame-selected,\n.stack-frame-group-vendor .stack-frame-selected .stack-frame-header {\n /* @apply bg-gray-100; */\n}\n\n.stack-frame-number {\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n padding-top: 1rem;\n padding-bottom: 1rem;\n color: rgb(121, 0, 245);\n color: var(--purple-500);\n font-feature-settings: "tnum";\n font-variant-numeric: tabular-nums;\n text-align: center;\n}\n\n.stack-frame-group-vendor .stack-frame-number {\n color: rgba(30, 20, 90, 0.35);\n color: var(--tint-500);\n}\n\n.stack-frame-header {\n margin-right: -2.5rem;\n width: 100%;\n}\n\n.stack-frame-text {\n display: grid;\n align-items: center;\n grid-gap: 0.5rem;\n border-left-width: 2px;\n padding-left: 0.75rem;\n padding-top: 1rem;\n padding-bottom: 1rem;\n border-color: rgb(214, 188, 250);\n border-color: var(--purple-300);\n color: rgb(75, 71, 109);\n color: var(--gray-700);\n}\n\n.stack-frame-group-vendor .stack-frame-text {\n border-color: rgb(232, 229, 239);\n border-color: var(--gray-300);\n}\n\n.stack-frame-selected .stack-frame-text {\n border-color: rgb(121, 0, 245);\n border-color: var(--purple-500);\n}\n\n.stack-frame-group-vendor .stack-frame-selected .stack-frame-text {\n border-color: rgb(176, 173, 197);\n border-color: var(--gray-500);\n}\n\n.stack-frame-line {\n padding-left: 0.5rem;\n padding-right: 0.25rem;\n padding-top: 1rem;\n padding-bottom: 1rem;\n text-align: right;\n line-height: 1.25;\n}\n\n.stack-main {\n display: grid;\n height: 100%;\n overflow: hidden;\n background-color: rgb(247, 247, 252);\n background-color: var(--gray-100);\n grid-template: auto 1fr / 100%;\n}\n\n.stack-main-header {\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n border-bottom-width: 1px;\n border-color: rgb(238, 238, 245);\n border-color: var(--gray-200);\n font-size: 0.75rem;\n}\n\n@media (min-width: 640px) {\n .stack-main-header {\n padding-top: 1rem;\n padding-bottom: 1rem;\n font-size: 1rem;\n }\n}\n\n.stack-main-content {\n overflow: hidden;\n}\n\n.stack-viewer {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n display: flex;\n overflow: auto;\n background-color: rgb(255, 255, 255);\n background-color: var(--white);\n font-size: 0.75rem;\n}\n\n.stack-ruler {\n position: sticky;\n flex: none;\n left: 0;\n z-index: 20;\n}\n\n.stack-lines {\n min-height: 100%;\n border-right-width: 1px;\n border-color: rgb(238, 238, 245);\n border-color: var(--gray-200);\n background-color: rgb(247, 247, 252);\n background-color: var(--gray-100);\n padding-top: 1rem;\n padding-bottom: 1rem;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n.stack-line {\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;\n color: rgba(30, 20, 70, 0.5);\n color: var(--tint-600);\n line-height: 2;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n.stack-line-highlight {\n background-color: rgb(236, 211, 253);\n background-color: var(--purple-200);\n}\n\n.stack-line-selected {\n background-color: rgb(255, 248, 196);\n background-color: var(--yellow-200);\n}\n\n.stack-line-highlight.stack-line-selected {\n background-color: rgb(255, 243, 148);\n background-color: var(--yellow-300);\n}\n\n.stack-code {\n flex-grow: 1;\n padding-top: 1rem;\n padding-bottom: 1rem;\n}\n\n.stack-code-line {\n padding-left: 1.5rem;\n color: rgb(75, 71, 109);\n color: var(--gray-700);\n line-height: 2;\n}\n\n.stack-code-line:hover {\n background-color: rgb(251, 245, 255);\n background-color: var(--purple-100);\n}\n\n.stack-code-line .editor-link {\n display: inline-block;\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n opacity: 0;\n color: rgb(183, 148, 244);\n color: var(--purple-400);\n}\n\n.stack-code-line .editor-link:hover {\n color: rgb(121, 0, 245);\n color: var(--purple-500);\n}\n\n.stack-code-line:hover .editor-link {\n opacity: 1;\n}\n\n.stack-code-line-highlight {\n background-color: rgb(251, 245, 255);\n background-color: var(--purple-100);\n}\n\n.stack-code-line-selected {\n background-color: rgb(255, 253, 235);\n background-color: var(--yellow-100);\n}\n\n.stack-code-line-highlight.stack-code-line-selected {\n background-color: rgb(255, 248, 196);\n background-color: var(--yellow-200);\n}\n\n.solution-hiding {\n pointer-events: none;\n}\n\n.solution-hidden {\n height: 0;\n overflow: hidden;\n}\n\n.solution-hidden .solution-main,\n.solution-hiding .solution-main {\n transform: translateY(-25px) scaleY(0.95);\n opacity: 0;\n}\n\n.solution-main {\n z-index: 1;\n color: rgb(51, 47, 81);\n color: var(--gray-800);\n opacity: 1;\n transition: all 0.1s;\n}\n\n.solution-toggle {\n position: absolute;\n z-index: 10;\n top: 0.5rem;\n right: 10px;\n padding-left: 0.75rem;\n padding-right: 0.75rem;\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n font-size: 0.75rem;\n line-height: 1;\n cursor: pointer;\n}\n\n.solution-toggle-show {\n top: 0;\n background-color: rgb(148, 242, 200);\n background-color: var(--green-300);\n box-shadow: var(--shadow-sm);\n border-bottom-right-radius: 0.125rem;\n border-bottom-left-radius: 0.125rem;\n z-index: 0;\n clip-path: polygon(0 0, 100% 0, 100% 100%, 9px 100%, 0 calc(100% - 5px));\n -webkit-clip-path: polygon(0 0, 100% 0, 100% 100%, 9px 100%, 0 calc(100% - 5px));\n}\n\n.solution-toggle-show a {\n text-decoration: none;\n}\n\n.solution-background {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n top: -6px;\n margin: 0 10px;\n background-color: rgb(148, 242, 200);\n background-color: var(--green-300);\n box-shadow: var(--shadow-default);\n border-width: 1px;\n border-color: rgba(25, 0, 100, 0.1);\n border-color: var(--tint-300);\n overflow: hidden;\n border-bottom-right-radius: 0.125rem;\n border-bottom-left-radius: 0.125rem;\n}\n\n.solution-title {\n font-weight: 600;\n font-size: 1.5rem;\n line-height: 1.25;\n margin-bottom: 1rem;\n}\n\n.solution-content-wrapper {\n padding: 3rem;\n overflow-x: auto;\n}\n\n.solution-content {\n max-width: 56rem;\n}\n\n@media (min-width: 768px) {\n .solution-content {\n margin-left: 15rem;\n }\n}\n\n.solution code {\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;\n color: rgb(75, 71, 109);\n color: var(--gray-700);\n display: inline-block;\n margin-top: -0.25rem;\n margin-bottom: -0.25rem;\n padding-left: 0.25rem;\n padding-right: 0.25rem;\n border-radius: 0.125rem;\n background-color: rgba(0, 0, 150, 0.025);\n background-color: var(--tint-100);\n border-width: 1px;\n border-color: rgba(0, 0, 150, 0.025);\n border-color: var(--tint-100);\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;\n color: rgb(75, 71, 109);\n color: var(--gray-700);\n word-break: break-all;\n line-height: 1.25;\n}\n\n:root {\n --tab-main-height: calc(100vh - 3rem);\n}\n\n.tabs {\n z-index: 10;\n}\n\n.tab-main {\n z-index: 1;\n border-left-width: 1px;\n border-right-width: 1px;\n border-bottom-width: 1px;\n border-color: rgba(25, 0, 100, 0.1);\n border-color: var(--tint-300);\n min-height: calc(100vh - 3rem);\n min-height: var(--tab-main-height);\n}\n\n.tab-content {\n background-color: rgb(255, 255, 255);\n background-color: var(--white);\n font-size: 0.875rem;\n min-height: calc(100vh - 3rem);\n min-height: var(--tab-main-height);\n}\n\n.tab-content-section {\n padding-top: 2rem;\n padding-bottom: 2rem;\n border-top-width: 2px;\n border-color: rgba(0, 0, 100, 0.07);\n border-color: var(--tint-200);\n}\n\n.tab-content-section:first-child {\n border-top-width: 0;\n}\n\n.tab-nav {\n position: sticky;\n position: -webkit-sticky;\n display: grid;\n justify-content: center;\n grid-template-columns: auto;\n grid-auto-flow: column;\n grid-gap: 0.5rem;\n top: 0;\n width: 100%;\n z-index: 10;\n background-color: rgb(75, 71, 109);\n background-color: var(--gray-700);\n padding: 0.25rem;\n box-shadow: var(--shadow-default);\n border-top-left-radius: 0.125rem;\n border-top-right-radius: 0.125rem;\n font-size: 0.75rem;\n}\n\n.tab-bar {\n display: grid;\n grid-template-columns: auto;\n grid-auto-flow: column;\n justify-content: flex-start;\n grid-gap: 0.25rem;\n overflow-x: auto;\n overflow-y: hidden;\n}\n\n.tab-bar::-webkit-scrollbar {\n height: 2px;\n}\n\n@media (min-width: 640px) {\n .tab-bar {\n justify-content: center;\n }\n}\n\n.tab {\n padding-left: 1rem;\n padding-right: 1rem;\n color: rgb(232, 229, 239);\n color: var(--gray-300);\n white-space: nowrap;\n border-radius: 0.125rem;\n height: 2.5rem;\n font-size: 0.875rem;\n}\n\n.tab-delimiter {\n border-left-width: 1px;\n border-color: rgb(142, 137, 162);\n border-color: var(--gray-600);\n}\n\n.tab:hover {\n background-color: rgba(20, 0, 100, 0.2);\n background-color: var(--tint-400);\n color: rgb(255, 255, 255);\n color: var(--white);\n}\n\n.tab-active,\n.tab-active:hover {\n background-color: rgba(30, 20, 70, 0.5);\n background-color: var(--tint-600);\n color: rgb(255, 255, 255);\n color: var(--white);\n}\n\n.ui-url {\n display: inline-block;\n line-height: 1.25;\n font-size: 0.875rem;\n font-weight: 400;\n text-decoration: underline;\n color: rgba(30, 20, 70, 0.5);\n color: var(--tint-600);\n -webkit-text-decoration-color: rgba(20, 0, 100, 0.2);\n text-decoration-color: rgba(20, 0, 100, 0.2);\n -webkit-text-decoration-color: var(--tint-400);\n text-decoration-color: var(--tint-400);\n}\n\n.ui-url:hover {\n color: rgba(15, 10, 60, 0.75);\n color: var(--tint-700);\n -webkit-text-decoration-color: rgba(30, 20, 90, 0.35);\n text-decoration-color: rgba(30, 20, 90, 0.35);\n -webkit-text-decoration-color: var(--tint-500);\n text-decoration-color: var(--tint-500);\n}\n\n.ui-path {\n display: inline-block;\n line-height: 1.25;\n}\n\n.ui-exception-message {\n font-weight: 600;\n line-height: 1.25;\n word-wrap: break-word;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 5;\n overflow: hidden;\n}\n\n.ui-exception-message-full {\n -webkit-line-clamp: unset;\n}\n\n.ui-exception-class {\n display: inline-block;\n line-height: 1.25;\n color: rgba(30, 20, 70, 0.5);\n color: var(--tint-600);\n}\n\n.ui-line-number {\n display: inline-block;\n padding-left: 0.25rem;\n padding-right: 0.25rem;\n border-radius: 0.125rem;\n background-color: rgba(0, 0, 150, 0.015);\n background-color: var(--tint-50);\n color: rgba(30, 20, 70, 0.5);\n color: var(--tint-600);\n font-size: 0.75rem;\n line-height: 1.25;\n}\n\n.dark .hljs {\n display: block;\n overflow-x: auto;\n padding: 0.5em;\n color: #abb2bf;\n background: #282c34;\n}\n\n.dark .hljs-comment,\n.dark .hljs-quote {\n color: #5c6370;\n font-style: italic;\n}\n\n.dark .hljs-doctag,\n.dark .hljs-keyword,\n.dark .hljs-formula {\n color: #c678dd;\n}\n\n.dark .hljs-section,\n.dark .hljs-name,\n.dark .hljs-selector-tag,\n.dark .hljs-deletion,\n.dark .hljs-subst {\n color: #e06c75;\n}\n\n.dark .hljs-literal {\n color: #56b6c2;\n}\n\n.dark .hljs-string,\n.dark .hljs-regexp,\n.dark .hljs-addition,\n.dark .hljs-attribute,\n.dark .hljs-meta-string {\n color: #98c379;\n}\n\n.dark .hljs-built_in,\n.dark .hljs-class .dark .hljs-title {\n color: #e6c07b;\n}\n\n.dark .hljs-attr,\n.dark .hljs-variable,\n.dark .hljs-template-variable,\n.dark .hljs-type,\n.dark .hljs-selector-class,\n.dark .hljs-selector-attr,\n.dark .hljs-selector-pseudo,\n.dark .hljs-number {\n color: #d19a66;\n}\n\n.dark .hljs-symbol,\n.dark .hljs-bullet,\n.dark .hljs-link,\n.dark .hljs-meta,\n.dark .hljs-selector-id,\n.dark .hljs-title {\n color: #61aeee;\n}\n\n.dark .hljs-emphasis {\n font-style: italic;\n}\n\n.dark .hljs-strong {\n font-weight: bold;\n}\n\n.dark .hljs-link {\n text-decoration: underline;\n}\n\n.light .hljs {\n display: block;\n overflow-x: auto;\n padding: 0.5em;\n color: #383a42;\n background: #fafafa;\n}\n\n.light .hljs-comment,\n.light .hljs-quote {\n color: #a0a1a7;\n font-style: italic;\n}\n\n.light .hljs-doctag,\n.light .hljs-keyword,\n.light .hljs-formula {\n color: #a626a4;\n}\n\n.light .hljs-section,\n.light .hljs-name,\n.light .hljs-selector-tag,\n.light .hljs-deletion,\n.light .hljs-subst {\n color: #e45649;\n}\n\n.light .hljs-literal {\n color: #0184bb;\n}\n\n.light .hljs-string,\n.light .hljs-regexp,\n.light .hljs-addition,\n.light .hljs-attribute,\n.light .hljs-meta-string {\n color: #50a14f;\n}\n\n.light .hljs-built_in,\n.light .hljs-class .light .hljs-title {\n color: #c18401;\n}\n\n.light .hljs-attr,\n.light .hljs-variable,\n.light .hljs-template-variable,\n.light .hljs-type,\n.light .hljs-selector-class,\n.light .hljs-selector-attr,\n.light .hljs-selector-pseudo,\n.light .hljs-number {\n color: #986801;\n}\n\n.light .hljs-symbol,\n.light .hljs-bullet,\n.light .hljs-link,\n.light .hljs-meta,\n.light .hljs-selector-id,\n.light .hljs-title {\n color: #4078f2;\n}\n\n.light .hljs-emphasis {\n font-style: italic;\n}\n\n.light .hljs-strong {\n font-weight: bold;\n}\n\n.light .hljs-link {\n text-decoration: underline;\n}\n\n/* \n Dumps are hidden asap in errorPage.blade \n What follows is !important\n*/\n\n.tabs pre.sf-dump {\n display: block !important;\n}\n\n.sf-dump-public.sf-dump-highlight,\n.sf-dump-protected.sf-dump-highlight,\n.sf-dump-private.sf-dump-highlight,\n.sf-dump-str.sf-dump-highlight,\n.sf-dump-key.sf-dump-highlight {\n background-color: rgb(251, 245, 255) !important;\n background-color: var(--purple-100) !important;\n border-color: rgb(236, 211, 253) !important;\n border-color: var(--purple-200) !important;\n}\n\n.sf-dump-public.sf-dump-highlight-active,\n.sf-dump-protected.sf-dump-highlight-active,\n.sf-dump-private.sf-dump-highlight-active,\n.sf-dump-str.sf-dump-highlight-active,\n.sf-dump-key.sf-dump-highlight-active {\n background-color: rgb(255, 253, 235) !important;\n background-color: var(--yellow-100) !important;\n border-color: rgb(255, 248, 196) !important;\n border-color: var(--yellow-200) !important;\n}\n\npre.sf-dump .sf-dump-search-wrapper > * {\n border-color: rgb(232, 229, 239) !important;\n border-color: var(--gray-300) !important;\n}\n\npre.sf-dump .sf-dump-search-wrapper > input.sf-dump-search-input {\n font-size: 0.75rem !important;\n background-color: rgb(51, 47, 81) !important;\n background-color: var(--gray-800) !important;\n}\n\npre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next,\npre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-previous {\n background-color: rgba(0, 0, 150, 0.025) !important;\n background-color: var(--tint-100) !important;\n}\n\npre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-count {\n font-size: 0.875rem !important;\n}\n\npre.sf-dump,\npre.sf-dump .sf-dump-default {\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !important;\n background-color: rgb(247, 247, 252) !important;\n background-color: var(--gray-100) !important;\n color: rgb(51, 47, 81) !important;\n color: var(--gray-800) !important;\n}\n\npre.sf-dump .sf-dump-num {\n color: rgb(250, 133, 162) !important;\n color: var(--red-300) !important;\n}\n\npre.sf-dump .sf-dump-const {\n font-weight: 400 !important;\n}\n\npre.sf-dump .sf-dump-str {\n font-weight: 400 !important;\n color: rgb(142, 137, 162) !important;\n color: var(--gray-600) !important;\n}\n\npre.sf-dump .sf-dump-note {\n color: rgb(122, 122, 255) !important;\n color: var(--blue-400) !important;\n}\n\npre.sf-dump .sf-dump-ref {\n color: rgb(142, 137, 162) !important;\n color: var(--gray-600) !important;\n}\n\npre.sf-dump .sf-dump-public,\npre.sf-dump .sf-dump-protected,\npre.sf-dump .sf-dump-private {\n color: rgb(121, 0, 245) !important;\n color: var(--purple-500) !important;\n}\n\npre.sf-dump .sf-dump-meta {\n color: rgb(121, 0, 245) !important;\n color: var(--purple-500) !important;\n}\n\npre.sf-dump .sf-dump-key {\n color: rgb(113, 7, 220) !important;\n color: var(--purple-600) !important;\n}\n\npre.sf-dump .sf-dump-index {\n color: rgb(122, 122, 255) !important;\n color: var(--blue-400) !important;\n}\n\npre.sf-dump .sf-dump-ellipsis {\n color: rgb(113, 7, 220) !important;\n color: var(--purple-600) !important;\n}\n\n.bg-gray-100{\n background-color: rgb(247, 247, 252) !important;\n background-color: var(--gray-100) !important;\n}\n\n.bg-tint-200{\n background-color: rgba(0, 0, 100, 0.07) !important;\n background-color: var(--tint-200) !important;\n}\n\n.bg-tint-300{\n background-color: rgba(25, 0, 100, 0.1) !important;\n background-color: var(--tint-300) !important;\n}\n\n.bg-tint-600{\n background-color: rgba(30, 20, 70, 0.5) !important;\n background-color: var(--tint-600) !important;\n}\n\n.hover\\:bg-tint-100:hover{\n background-color: rgba(0, 0, 150, 0.025) !important;\n background-color: var(--tint-100) !important;\n}\n\n.hover\\:bg-tint-400:hover{\n background-color: rgba(20, 0, 100, 0.2) !important;\n background-color: var(--tint-400) !important;\n}\n\n.hover\\:bg-tint-700:hover{\n background-color: rgba(15, 10, 60, 0.75) !important;\n background-color: var(--tint-700) !important;\n}\n\n.border-gray-700{\n border-color: rgb(75, 71, 109) !important;\n border-color: var(--gray-700) !important;\n}\n\n.border-tint-200{\n border-color: rgba(0, 0, 100, 0.07) !important;\n border-color: var(--tint-200) !important;\n}\n\n.border-tint-300{\n border-color: rgba(25, 0, 100, 0.1) !important;\n border-color: var(--tint-300) !important;\n}\n\n.rounded-full{\n border-radius: 9999px !important;\n}\n\n.rounded-t{\n border-top-left-radius: 0.25rem !important;\n border-top-right-radius: 0.25rem !important;\n}\n\n.border-none{\n border-style: none !important;\n}\n\n.border-t-2{\n border-top-width: 2px !important;\n}\n\n.border-b{\n border-bottom-width: 1px !important;\n}\n\n.cursor-pointer{\n cursor: pointer !important;\n}\n\n.inline-block{\n display: inline-block !important;\n}\n\n.flex{\n display: flex !important;\n}\n\n.inline-flex{\n display: inline-flex !important;\n}\n\n.hidden{\n display: none !important;\n}\n\n.items-center{\n align-items: center !important;\n}\n\n.items-baseline{\n align-items: baseline !important;\n}\n\n.justify-start{\n justify-content: flex-start !important;\n}\n\n.justify-end{\n justify-content: flex-end !important;\n}\n\n.justify-center{\n justify-content: center !important;\n}\n\n.font-mono{\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !important;\n}\n\n.font-normal{\n font-weight: 400 !important;\n}\n\n.font-medium{\n font-weight: 500 !important;\n}\n\n.font-semibold{\n font-weight: 600 !important;\n}\n\n.h-5{\n height: 1.25rem !important;\n}\n\n.h-8{\n height: 2rem !important;\n}\n\n.h-full{\n height: 100% !important;\n}\n\n.mx-0{\n margin-left: 0 !important;\n margin-right: 0 !important;\n}\n\n.ml-0{\n margin-left: 0 !important;\n}\n\n.mt-1{\n margin-top: 0.25rem !important;\n}\n\n.mr-1{\n margin-right: 0.25rem !important;\n}\n\n.mb-1{\n margin-bottom: 0.25rem !important;\n}\n\n.mt-2{\n margin-top: 0.5rem !important;\n}\n\n.mr-2{\n margin-right: 0.5rem !important;\n}\n\n.mb-2{\n margin-bottom: 0.5rem !important;\n}\n\n.ml-2{\n margin-left: 0.5rem !important;\n}\n\n.mb-3{\n margin-bottom: 0.75rem !important;\n}\n\n.mt-4{\n margin-top: 1rem !important;\n}\n\n.mr-4{\n margin-right: 1rem !important;\n}\n\n.mb-4{\n margin-bottom: 1rem !important;\n}\n\n.ml-6{\n margin-left: 1.5rem !important;\n}\n\n.mt-8{\n margin-top: 2rem !important;\n}\n\n.mt-12{\n margin-top: 3rem !important;\n}\n\n.ml-auto{\n margin-left: auto !important;\n}\n\n.min-w-8{\n min-width: 2rem !important;\n}\n\n.opacity-25{\n opacity: 0.25 !important;\n}\n\n.opacity-50{\n opacity: 0.5 !important;\n}\n\n.opacity-75{\n opacity: 0.75 !important;\n}\n\n.overflow-visible{\n overflow: visible !important;\n}\n\n.p-4{\n padding: 1rem !important;\n}\n\n.p-12{\n padding: 3rem !important;\n}\n\n.py-2{\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n}\n\n.px-2{\n padding-left: 0.5rem !important;\n padding-right: 0.5rem !important;\n}\n\n.py-4{\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n}\n\n.px-4{\n padding-left: 1rem !important;\n padding-right: 1rem !important;\n}\n\n.px-6{\n padding-left: 1.5rem !important;\n padding-right: 1.5rem !important;\n}\n\n.pt-2{\n padding-top: 0.5rem !important;\n}\n\n.pt-10{\n padding-top: 2.5rem !important;\n}\n\n.pointer-events-none{\n pointer-events: none !important;\n}\n\n.static{\n position: static !important;\n}\n\n.absolute{\n position: absolute !important;\n}\n\n.relative{\n position: relative !important;\n}\n\n.sticky{\n position: sticky !important;\n}\n\n.inset-0{\n top: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n left: 0 !important;\n}\n\n.top-0{\n top: 0 !important;\n}\n\n.right-0{\n right: 0 !important;\n}\n\n.bottom-0{\n bottom: 0 !important;\n}\n\n.left-0{\n left: 0 !important;\n}\n\n.top-full{\n top: 100% !important;\n}\n\n.left-full{\n left: 100% !important;\n}\n\n.text-left{\n text-align: left !important;\n}\n\n.text-white{\n color: rgb(255, 255, 255) !important;\n color: var(--white) !important;\n}\n\n.text-green-300{\n color: rgb(148, 242, 200) !important;\n color: var(--green-300) !important;\n}\n\n.text-purple-400{\n color: rgb(183, 148, 244) !important;\n color: var(--purple-400) !important;\n}\n\n.text-purple-800{\n color: rgb(79, 15, 143) !important;\n color: var(--purple-800) !important;\n}\n\n.text-gray-200{\n color: rgb(238, 238, 245) !important;\n color: var(--gray-200) !important;\n}\n\n.text-gray-300{\n color: rgb(232, 229, 239) !important;\n color: var(--gray-300) !important;\n}\n\n.text-gray-400{\n color: rgb(209, 204, 224) !important;\n color: var(--gray-400) !important;\n}\n\n.text-gray-500{\n color: rgb(176, 173, 197) !important;\n color: var(--gray-500) !important;\n}\n\n.text-gray-800{\n color: rgb(51, 47, 81) !important;\n color: var(--gray-800) !important;\n}\n\n.text-tint-600{\n color: rgba(30, 20, 70, 0.5) !important;\n color: var(--tint-600) !important;\n}\n\n.hover\\:text-white:hover{\n color: rgb(255, 255, 255) !important;\n color: var(--white) !important;\n}\n\n.hover\\:text-purple-500:hover{\n color: rgb(121, 0, 245) !important;\n color: var(--purple-500) !important;\n}\n\n.text-xs{\n font-size: 0.75rem !important;\n}\n\n.text-sm{\n font-size: 0.875rem !important;\n}\n\n.text-base{\n font-size: 1rem !important;\n}\n\n.text-xl{\n font-size: 1.25rem !important;\n}\n\n.text-2xl{\n font-size: 1.5rem !important;\n}\n\n.italic{\n font-style: italic !important;\n}\n\n.uppercase{\n text-transform: uppercase !important;\n}\n\n.underline{\n text-decoration: underline !important;\n}\n\n.no-underline{\n text-decoration: none !important;\n}\n\n.tracking-wider{\n letter-spacing: 0.05em !important;\n}\n\n.align-middle{\n vertical-align: middle !important;\n}\n\n.whitespace-no-wrap{\n white-space: nowrap !important;\n}\n\n.w-4{\n width: 1rem !important;\n}\n\n.w-full{\n width: 100% !important;\n}\n\n.z-1{\n z-index: 1 !important;\n}\n\n.z-10{\n z-index: 10 !important;\n}\n\n@media (min-width: 640px){\n\n .sm\\:block{\n display: block !important;\n }\n\n .sm\\:ml-6{\n margin-left: 1.5rem !important;\n }\n}\n\n@media (min-width: 768px){\n\n .md\\:block{\n display: block !important;\n }\n}\n',""])},function(t,e,n){"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var n=function(t,e){var n=t[1]||"",r=t[3];if(!r)return n;if(e&&"function"==typeof btoa){var o=(a=r,s=btoa(unescape(encodeURIComponent(JSON.stringify(a)))),c="sourceMappingURL=data:application/json;charset=utf-8;base64,".concat(s),"/*# ".concat(c," */")),i=r.sources.map((function(t){return"/*# sourceURL=".concat(r.sourceRoot).concat(t," */")}));return[n].concat(i).concat([o]).join("\n")}var a,s,c;return[n].join("\n")}(e,t);return e[2]?"@media ".concat(e[2],"{").concat(n,"}"):n})).join("")},e.i=function(t,n){"string"==typeof t&&(t=[[null,t,""]]);for(var r={},o=0;o=0&&f.splice(e,1)}function v(t){var e=document.createElement("style");if(void 0===t.attrs.type&&(t.attrs.type="text/css"),void 0===t.attrs.nonce){var r=function(){0;return n.nc}();r&&(t.attrs.nonce=r)}return b(e,t.attrs),g(t,e),e}function b(t,e){Object.keys(e).forEach((function(n){t.setAttribute(n,e[n])}))}function _(t,e){var n,r,o,i;if(e.transform&&t.css){if(!(i="function"==typeof e.transform?e.transform(t.css):e.transform.default(t.css)))return function(){};t.css=i}if(e.singleton){var a=l++;n=u||(u=v(e)),r=x.bind(null,n,a,!1),o=x.bind(null,n,a,!0)}else t.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(t){var e=document.createElement("link");return void 0===t.attrs.type&&(t.attrs.type="text/css"),t.attrs.rel="stylesheet",b(e,t.attrs),g(t,e),e}(e),r=w.bind(null,n,e),o=function(){m(n),n.href&&URL.revokeObjectURL(n.href)}):(n=v(e),r=k.bind(null,n),o=function(){m(n)});return r(t),function(e){if(e){if(e.css===t.css&&e.media===t.media&&e.sourceMap===t.sourceMap)return;r(t=e)}else o()}}t.exports=function(t,e){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(e=e||{}).attrs="object"==typeof e.attrs?e.attrs:{},e.singleton||"boolean"==typeof e.singleton||(e.singleton=a()),e.insertInto||(e.insertInto="head"),e.insertAt||(e.insertAt="bottom");var n=h(t,e);return d(n,e),function(t){for(var r=[],o=0;og.maxDepth)&&a(y)}else if(/\bsf-dump-ref\b/.test(m.className)&&(y=m.getAttribute("href"))&&(y=y.substr(1),m.className+=" "+y,/[\[{]$/.test(m.previousSibling.nodeValue))){y=y!=m.nextSibling.id&&t.getElementById(y);try{p=y.nextSibling,m.appendChild(y),p.parentNode.insertBefore(y,p),/^[@#]/.test(m.innerHTML)?m.innerHTML+=" ":(m.innerHTML="",m.className="sf-dump-ref"),m.className+=" sf-dump-toggle"}catch(t){"&"==m.innerHTML.charAt(0)&&(m.innerHTML="…",m.className="sf-dump-ref")}}if(t.evaluate&&Array.from&&l.children.length>1){var C=function(t){var e,n,r=t.current();r&&(!function(t){for(var e,n=[];(t=t.parentNode||{})&&(e=t.previousSibling)&&"A"===e.tagName;)n.push(e);0!==n.length&&n.forEach((function(t){s(t)}))}(r),function(t,e,n){u(t),Array.from(n||[]).forEach((function(t){/\bsf-dump-highlight\b/.test(t.className)||(t.className=t.className+" sf-dump-highlight")})),/\bsf-dump-highlight-active\b/.test(e.className)||(e.className=e.className+" sf-dump-highlight-active")}(l,r,t.nodes),"scrollIntoView"in r&&(r.scrollIntoView(!0),e=r.getBoundingClientRect(),n=A.getBoundingClientRect(),e.top0?this.idx-1:this.nodes.length-1,this.current())},isEmpty:function(){return 0===this.count()},current:function(){return this.isEmpty()?null:this.nodes[this.idx]},reset:function(){this.nodes=[],this.idx=0},count:function(){return this.nodes.length}};var A=t.createElement("div");A.className="sf-dump-search-wrapper sf-dump-search-hidden",A.innerHTML='\n \n 0 of 0\n \n \n ',l.insertBefore(A,l.firstChild);var T=new SearchState,S=A.querySelector(".sf-dump-search-input"),R=A.querySelector(".sf-dump-search-count"),O=0,N="";i(S,"keyup",(function(e){var n=e.target.value;n!==N&&(N=n,clearTimeout(O),O=setTimeout((function(){if(T.reset(),c(l),u(l),""!==n){for(var e=["sf-dump-str","sf-dump-key","sf-dump-public","sf-dump-protected","sf-dump-private"].map(k).join(" or "),r=t.evaluate(".//span["+e+"][contains(translate(child::text(), "+x(n.toUpperCase())+", "+x(n.toLowerCase())+"), "+x(n.toLowerCase())+")]",l,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);node=r.iterateNext();)T.nodes.push(node);C(T)}else R.textContent="0 of 0"}),400))})),Array.from(A.querySelectorAll(".sf-dump-search-input-next, .sf-dump-search-input-previous")).forEach((function(t){i(t,"click",(function(t){t.preventDefault(),-1!==t.target.className.indexOf("next")?T.next():T.previous(),S.focus(),c(l),C(T)}))})),i(l,"keydown",(function(t){var e=!/\bsf-dump-search-hidden\b/.test(A.className);if(114===t.keyCode&&!e||E(t)&&70===t.keyCode){if(70===t.keyCode&&document.activeElement===S)return;t.preventDefault(),A.className=A.className.replace(/\bsf-dump-search-hidden\b/,""),S.focus()}else e&&(27===t.keyCode?(A.className+=" sf-dump-search-hidden",t.preventDefault(),u(l),S.value=""):(E(t)&&71===t.keyCode||13===t.keyCode||114===t.keyCode)&&(t.preventDefault(),t.shiftKey?T.previous():T.next(),c(l),C(T)))}))}if(!(0>=g.maxStringLength))try{for(v=(m=l.querySelectorAll(".sf-dump-str")).length,b=0,_=[];b
'+m.innerHTML+'')}catch(t){}}}(document)},function(t,e,n){var r=function(t){"use strict";var e,n=Object.prototype,r=n.hasOwnProperty,o="function"==typeof Symbol?Symbol:{},i=o.iterator||"@@iterator",a=o.asyncIterator||"@@asyncIterator",s=o.toStringTag||"@@toStringTag";function c(t,e,n,r){var o=e&&e.prototype instanceof g?e:g,i=Object.create(o.prototype),a=new T(r||[]);return i._invoke=function(t,e,n){var r=l;return function(o,i){if(r===p)throw new Error("Generator is already running");if(r===d){if("throw"===o)throw i;return R()}for(n.method=o,n.arg=i;;){var a=n.delegate;if(a){var s=w(a,n);if(s){if(s===h)continue;return s}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(r===l)throw r=d,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);r=p;var c=u(t,e,n);if("normal"===c.type){if(r=n.done?d:f,c.arg===h)continue;return{value:c.arg,done:n.done}}"throw"===c.type&&(r=d,n.method="throw",n.arg=c.arg)}}}(t,n,a),i}function u(t,e,n){try{return{type:"normal",arg:t.call(e,n)}}catch(t){return{type:"throw",arg:t}}}t.wrap=c;var l="suspendedStart",f="suspendedYield",p="executing",d="completed",h={};function g(){}function m(){}function v(){}var b={};b[i]=function(){return this};var _=Object.getPrototypeOf,y=_&&_(_(S([])));y&&y!==n&&r.call(y,i)&&(b=y);var E=v.prototype=g.prototype=Object.create(b);function x(t){["next","throw","return"].forEach((function(e){t[e]=function(t){return this._invoke(e,t)}}))}function k(t){var e;this._invoke=function(n,o){function i(){return new Promise((function(e,i){!function e(n,o,i,a){var s=u(t[n],t,o);if("throw"!==s.type){var c=s.arg,l=c.value;return l&&"object"==typeof l&&r.call(l,"__await")?Promise.resolve(l.__await).then((function(t){e("next",t,i,a)}),(function(t){e("throw",t,i,a)})):Promise.resolve(l).then((function(t){c.value=t,i(c)}),(function(t){return e("throw",t,i,a)}))}a(s.arg)}(n,o,e,i)}))}return e=e?e.then(i,i):i()}}function w(t,n){var r=t.iterator[n.method];if(r===e){if(n.delegate=null,"throw"===n.method){if(t.iterator.return&&(n.method="return",n.arg=e,w(t,n),"throw"===n.method))return h;n.method="throw",n.arg=new TypeError("The iterator does not provide a 'throw' method")}return h}var o=u(r,t.iterator,n.arg);if("throw"===o.type)return n.method="throw",n.arg=o.arg,n.delegate=null,h;var i=o.arg;return i?i.done?(n[t.resultName]=i.value,n.next=t.nextLoc,"return"!==n.method&&(n.method="next",n.arg=e),n.delegate=null,h):i:(n.method="throw",n.arg=new TypeError("iterator result is not an object"),n.delegate=null,h)}function C(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function A(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function T(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(C,this),this.reset(!0)}function S(t){if(t){var n=t[i];if(n)return n.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var o=-1,a=function n(){for(;++o=0;--i){var a=this.tryEntries[i],s=a.completion;if("root"===a.tryLoc)return o("end");if(a.tryLoc<=this.prev){var c=r.call(a,"catchLoc"),u=r.call(a,"finallyLoc");if(c&&u){if(this.prev=0;--n){var o=this.tryEntries[n];if(o.tryLoc<=this.prev&&r.call(o,"finallyLoc")&&this.prev=0;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),A(n),h}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc===t){var r=n.completion;if("throw"===r.type){var o=r.arg;A(n)}return o}}throw new Error("illegal catch attempt")},delegateYield:function(t,n,r){return this.delegate={iterator:S(t),resultName:n,nextLoc:r},"next"===this.method&&(this.arg=e),h}},t}(t.exports);try{regeneratorRuntime=r}catch(t){Function("r","regeneratorRuntime = r")(r)}},function(t,e,n){"use strict";t.exports=n(102)},function(t,e,n){"use strict";var r=n(1),o=n(110),i=n(114),a=n(115),s=n(123),c=n(137),u=n(150),l=n(56),f=n(63),p={default:n(152),zero:n(153),commonmark:n(154)},d=/^(vbscript|javascript|file|data):/,h=/^data:image\/(gif|png|jpeg|webp);/;function g(t){var e=t.trim().toLowerCase();return!d.test(e)||!!h.test(e)}var m=["http:","https:","mailto:"];function v(t){var e=l.parse(t,!0);if(e.hostname&&(!e.protocol||m.indexOf(e.protocol)>=0))try{e.hostname=f.toASCII(e.hostname)}catch(t){}return l.encode(l.format(e))}function b(t){var e=l.parse(t,!0);if(e.hostname&&(!e.protocol||m.indexOf(e.protocol)>=0))try{e.hostname=f.toUnicode(e.hostname)}catch(t){}return l.decode(l.format(e))}function _(t,e){if(!(this instanceof _))return new _(t,e);e||r.isString(t)||(e=t||{},t="default"),this.inline=new c,this.block=new s,this.core=new a,this.renderer=new i,this.linkify=new u,this.validateLink=g,this.normalizeLink=v,this.normalizeLinkText=b,this.utils=r,this.helpers=r.assign({},o),this.options={},this.configure(t),e&&this.set(e)}_.prototype.set=function(t){return r.assign(this.options,t),this},_.prototype.configure=function(t){var e,n=this;if(r.isString(t)&&!(t=p[e=t]))throw new Error('Wrong `markdown-it` preset "'+e+'", check name');if(!t)throw new Error("Wrong `markdown-it` preset, can't be empty");return t.options&&n.set(t.options),t.components&&Object.keys(t.components).forEach((function(e){t.components[e].rules&&n[e].ruler.enableOnly(t.components[e].rules),t.components[e].rules2&&n[e].ruler2.enableOnly(t.components[e].rules2)})),this},_.prototype.enable=function(t,e){var n=[];Array.isArray(t)||(t=[t]),["core","block","inline"].forEach((function(e){n=n.concat(this[e].ruler.enable(t,!0))}),this),n=n.concat(this.inline.ruler2.enable(t,!0));var r=t.filter((function(t){return n.indexOf(t)<0}));if(r.length&&!e)throw new Error("MarkdownIt. Failed to enable unknown rule(s): "+r);return this},_.prototype.disable=function(t,e){var n=[];Array.isArray(t)||(t=[t]),["core","block","inline"].forEach((function(e){n=n.concat(this[e].ruler.disable(t,!0))}),this),n=n.concat(this.inline.ruler2.disable(t,!0));var r=t.filter((function(t){return n.indexOf(t)<0}));if(r.length&&!e)throw new Error("MarkdownIt. Failed to disable unknown rule(s): "+r);return this},_.prototype.use=function(t){var e=[this].concat(Array.prototype.slice.call(arguments,1));return t.apply(t,e),this},_.prototype.parse=function(t,e){if("string"!=typeof t)throw new Error("Input data should be a String");var n=new this.core.State(t,this,e);return this.core.process(n),n.tokens},_.prototype.render=function(t,e){return e=e||{},this.renderer.render(this.parse(t,e),this.options,e)},_.prototype.parseInline=function(t,e){var n=new this.core.State(t,this,e);return n.inlineMode=!0,this.core.process(n),n.tokens},_.prototype.renderInline=function(t,e){return e=e||{},this.renderer.render(this.parseInline(t,e),this.options,e)},t.exports=_},function(t){t.exports=JSON.parse('{"Aacute":"Á","aacute":"á","Abreve":"Ă","abreve":"ă","ac":"∾","acd":"∿","acE":"∾̳","Acirc":"Â","acirc":"â","acute":"´","Acy":"А","acy":"а","AElig":"Æ","aelig":"æ","af":"⁡","Afr":"𝔄","afr":"𝔞","Agrave":"À","agrave":"à","alefsym":"ℵ","aleph":"ℵ","Alpha":"Α","alpha":"α","Amacr":"Ā","amacr":"ā","amalg":"⨿","amp":"&","AMP":"&","andand":"⩕","And":"⩓","and":"∧","andd":"⩜","andslope":"⩘","andv":"⩚","ang":"∠","ange":"⦤","angle":"∠","angmsdaa":"⦨","angmsdab":"⦩","angmsdac":"⦪","angmsdad":"⦫","angmsdae":"⦬","angmsdaf":"⦭","angmsdag":"⦮","angmsdah":"⦯","angmsd":"∡","angrt":"∟","angrtvb":"⊾","angrtvbd":"⦝","angsph":"∢","angst":"Å","angzarr":"⍼","Aogon":"Ą","aogon":"ą","Aopf":"𝔸","aopf":"𝕒","apacir":"⩯","ap":"≈","apE":"⩰","ape":"≊","apid":"≋","apos":"\'","ApplyFunction":"⁡","approx":"≈","approxeq":"≊","Aring":"Å","aring":"å","Ascr":"𝒜","ascr":"𝒶","Assign":"≔","ast":"*","asymp":"≈","asympeq":"≍","Atilde":"Ã","atilde":"ã","Auml":"Ä","auml":"ä","awconint":"∳","awint":"⨑","backcong":"≌","backepsilon":"϶","backprime":"‵","backsim":"∽","backsimeq":"⋍","Backslash":"∖","Barv":"⫧","barvee":"⊽","barwed":"⌅","Barwed":"⌆","barwedge":"⌅","bbrk":"⎵","bbrktbrk":"⎶","bcong":"≌","Bcy":"Б","bcy":"б","bdquo":"„","becaus":"∵","because":"∵","Because":"∵","bemptyv":"⦰","bepsi":"϶","bernou":"ℬ","Bernoullis":"ℬ","Beta":"Β","beta":"β","beth":"ℶ","between":"≬","Bfr":"𝔅","bfr":"𝔟","bigcap":"⋂","bigcirc":"◯","bigcup":"⋃","bigodot":"⨀","bigoplus":"⨁","bigotimes":"⨂","bigsqcup":"⨆","bigstar":"★","bigtriangledown":"▽","bigtriangleup":"△","biguplus":"⨄","bigvee":"⋁","bigwedge":"⋀","bkarow":"⤍","blacklozenge":"⧫","blacksquare":"▪","blacktriangle":"▴","blacktriangledown":"▾","blacktriangleleft":"◂","blacktriangleright":"▸","blank":"␣","blk12":"▒","blk14":"░","blk34":"▓","block":"█","bne":"=⃥","bnequiv":"≡⃥","bNot":"⫭","bnot":"⌐","Bopf":"𝔹","bopf":"𝕓","bot":"⊥","bottom":"⊥","bowtie":"⋈","boxbox":"⧉","boxdl":"┐","boxdL":"╕","boxDl":"╖","boxDL":"╗","boxdr":"┌","boxdR":"╒","boxDr":"╓","boxDR":"╔","boxh":"─","boxH":"═","boxhd":"┬","boxHd":"╤","boxhD":"╥","boxHD":"╦","boxhu":"┴","boxHu":"╧","boxhU":"╨","boxHU":"╩","boxminus":"⊟","boxplus":"⊞","boxtimes":"⊠","boxul":"┘","boxuL":"╛","boxUl":"╜","boxUL":"╝","boxur":"└","boxuR":"╘","boxUr":"╙","boxUR":"╚","boxv":"│","boxV":"║","boxvh":"┼","boxvH":"╪","boxVh":"╫","boxVH":"╬","boxvl":"┤","boxvL":"╡","boxVl":"╢","boxVL":"╣","boxvr":"├","boxvR":"╞","boxVr":"╟","boxVR":"╠","bprime":"‵","breve":"˘","Breve":"˘","brvbar":"¦","bscr":"𝒷","Bscr":"ℬ","bsemi":"⁏","bsim":"∽","bsime":"⋍","bsolb":"⧅","bsol":"\\\\","bsolhsub":"⟈","bull":"•","bullet":"•","bump":"≎","bumpE":"⪮","bumpe":"≏","Bumpeq":"≎","bumpeq":"≏","Cacute":"Ć","cacute":"ć","capand":"⩄","capbrcup":"⩉","capcap":"⩋","cap":"∩","Cap":"⋒","capcup":"⩇","capdot":"⩀","CapitalDifferentialD":"ⅅ","caps":"∩︀","caret":"⁁","caron":"ˇ","Cayleys":"ℭ","ccaps":"⩍","Ccaron":"Č","ccaron":"č","Ccedil":"Ç","ccedil":"ç","Ccirc":"Ĉ","ccirc":"ĉ","Cconint":"∰","ccups":"⩌","ccupssm":"⩐","Cdot":"Ċ","cdot":"ċ","cedil":"¸","Cedilla":"¸","cemptyv":"⦲","cent":"¢","centerdot":"·","CenterDot":"·","cfr":"𝔠","Cfr":"ℭ","CHcy":"Ч","chcy":"ч","check":"✓","checkmark":"✓","Chi":"Χ","chi":"χ","circ":"ˆ","circeq":"≗","circlearrowleft":"↺","circlearrowright":"↻","circledast":"⊛","circledcirc":"⊚","circleddash":"⊝","CircleDot":"⊙","circledR":"®","circledS":"Ⓢ","CircleMinus":"⊖","CirclePlus":"⊕","CircleTimes":"⊗","cir":"○","cirE":"⧃","cire":"≗","cirfnint":"⨐","cirmid":"⫯","cirscir":"⧂","ClockwiseContourIntegral":"∲","CloseCurlyDoubleQuote":"”","CloseCurlyQuote":"’","clubs":"♣","clubsuit":"♣","colon":":","Colon":"∷","Colone":"⩴","colone":"≔","coloneq":"≔","comma":",","commat":"@","comp":"∁","compfn":"∘","complement":"∁","complexes":"ℂ","cong":"≅","congdot":"⩭","Congruent":"≡","conint":"∮","Conint":"∯","ContourIntegral":"∮","copf":"𝕔","Copf":"ℂ","coprod":"∐","Coproduct":"∐","copy":"©","COPY":"©","copysr":"℗","CounterClockwiseContourIntegral":"∳","crarr":"↵","cross":"✗","Cross":"⨯","Cscr":"𝒞","cscr":"𝒸","csub":"⫏","csube":"⫑","csup":"⫐","csupe":"⫒","ctdot":"⋯","cudarrl":"⤸","cudarrr":"⤵","cuepr":"⋞","cuesc":"⋟","cularr":"↶","cularrp":"⤽","cupbrcap":"⩈","cupcap":"⩆","CupCap":"≍","cup":"∪","Cup":"⋓","cupcup":"⩊","cupdot":"⊍","cupor":"⩅","cups":"∪︀","curarr":"↷","curarrm":"⤼","curlyeqprec":"⋞","curlyeqsucc":"⋟","curlyvee":"⋎","curlywedge":"⋏","curren":"¤","curvearrowleft":"↶","curvearrowright":"↷","cuvee":"⋎","cuwed":"⋏","cwconint":"∲","cwint":"∱","cylcty":"⌭","dagger":"†","Dagger":"‡","daleth":"ℸ","darr":"↓","Darr":"↡","dArr":"⇓","dash":"‐","Dashv":"⫤","dashv":"⊣","dbkarow":"⤏","dblac":"˝","Dcaron":"Ď","dcaron":"ď","Dcy":"Д","dcy":"д","ddagger":"‡","ddarr":"⇊","DD":"ⅅ","dd":"ⅆ","DDotrahd":"⤑","ddotseq":"⩷","deg":"°","Del":"∇","Delta":"Δ","delta":"δ","demptyv":"⦱","dfisht":"⥿","Dfr":"𝔇","dfr":"𝔡","dHar":"⥥","dharl":"⇃","dharr":"⇂","DiacriticalAcute":"´","DiacriticalDot":"˙","DiacriticalDoubleAcute":"˝","DiacriticalGrave":"`","DiacriticalTilde":"˜","diam":"⋄","diamond":"⋄","Diamond":"⋄","diamondsuit":"♦","diams":"♦","die":"¨","DifferentialD":"ⅆ","digamma":"ϝ","disin":"⋲","div":"÷","divide":"÷","divideontimes":"⋇","divonx":"⋇","DJcy":"Ђ","djcy":"ђ","dlcorn":"⌞","dlcrop":"⌍","dollar":"$","Dopf":"𝔻","dopf":"𝕕","Dot":"¨","dot":"˙","DotDot":"⃜","doteq":"≐","doteqdot":"≑","DotEqual":"≐","dotminus":"∸","dotplus":"∔","dotsquare":"⊡","doublebarwedge":"⌆","DoubleContourIntegral":"∯","DoubleDot":"¨","DoubleDownArrow":"⇓","DoubleLeftArrow":"⇐","DoubleLeftRightArrow":"⇔","DoubleLeftTee":"⫤","DoubleLongLeftArrow":"⟸","DoubleLongLeftRightArrow":"⟺","DoubleLongRightArrow":"⟹","DoubleRightArrow":"⇒","DoubleRightTee":"⊨","DoubleUpArrow":"⇑","DoubleUpDownArrow":"⇕","DoubleVerticalBar":"∥","DownArrowBar":"⤓","downarrow":"↓","DownArrow":"↓","Downarrow":"⇓","DownArrowUpArrow":"⇵","DownBreve":"̑","downdownarrows":"⇊","downharpoonleft":"⇃","downharpoonright":"⇂","DownLeftRightVector":"⥐","DownLeftTeeVector":"⥞","DownLeftVectorBar":"⥖","DownLeftVector":"↽","DownRightTeeVector":"⥟","DownRightVectorBar":"⥗","DownRightVector":"⇁","DownTeeArrow":"↧","DownTee":"⊤","drbkarow":"⤐","drcorn":"⌟","drcrop":"⌌","Dscr":"𝒟","dscr":"𝒹","DScy":"Ѕ","dscy":"ѕ","dsol":"⧶","Dstrok":"Đ","dstrok":"đ","dtdot":"⋱","dtri":"▿","dtrif":"▾","duarr":"⇵","duhar":"⥯","dwangle":"⦦","DZcy":"Џ","dzcy":"џ","dzigrarr":"⟿","Eacute":"É","eacute":"é","easter":"⩮","Ecaron":"Ě","ecaron":"ě","Ecirc":"Ê","ecirc":"ê","ecir":"≖","ecolon":"≕","Ecy":"Э","ecy":"э","eDDot":"⩷","Edot":"Ė","edot":"ė","eDot":"≑","ee":"ⅇ","efDot":"≒","Efr":"𝔈","efr":"𝔢","eg":"⪚","Egrave":"È","egrave":"è","egs":"⪖","egsdot":"⪘","el":"⪙","Element":"∈","elinters":"⏧","ell":"ℓ","els":"⪕","elsdot":"⪗","Emacr":"Ē","emacr":"ē","empty":"∅","emptyset":"∅","EmptySmallSquare":"◻","emptyv":"∅","EmptyVerySmallSquare":"▫","emsp13":" ","emsp14":" ","emsp":" ","ENG":"Ŋ","eng":"ŋ","ensp":" ","Eogon":"Ę","eogon":"ę","Eopf":"𝔼","eopf":"𝕖","epar":"⋕","eparsl":"⧣","eplus":"⩱","epsi":"ε","Epsilon":"Ε","epsilon":"ε","epsiv":"ϵ","eqcirc":"≖","eqcolon":"≕","eqsim":"≂","eqslantgtr":"⪖","eqslantless":"⪕","Equal":"⩵","equals":"=","EqualTilde":"≂","equest":"≟","Equilibrium":"⇌","equiv":"≡","equivDD":"⩸","eqvparsl":"⧥","erarr":"⥱","erDot":"≓","escr":"ℯ","Escr":"ℰ","esdot":"≐","Esim":"⩳","esim":"≂","Eta":"Η","eta":"η","ETH":"Ð","eth":"ð","Euml":"Ë","euml":"ë","euro":"€","excl":"!","exist":"∃","Exists":"∃","expectation":"ℰ","exponentiale":"ⅇ","ExponentialE":"ⅇ","fallingdotseq":"≒","Fcy":"Ф","fcy":"ф","female":"♀","ffilig":"ffi","fflig":"ff","ffllig":"ffl","Ffr":"𝔉","ffr":"𝔣","filig":"fi","FilledSmallSquare":"◼","FilledVerySmallSquare":"▪","fjlig":"fj","flat":"♭","fllig":"fl","fltns":"▱","fnof":"ƒ","Fopf":"𝔽","fopf":"𝕗","forall":"∀","ForAll":"∀","fork":"⋔","forkv":"⫙","Fouriertrf":"ℱ","fpartint":"⨍","frac12":"½","frac13":"⅓","frac14":"¼","frac15":"⅕","frac16":"⅙","frac18":"⅛","frac23":"⅔","frac25":"⅖","frac34":"¾","frac35":"⅗","frac38":"⅜","frac45":"⅘","frac56":"⅚","frac58":"⅝","frac78":"⅞","frasl":"⁄","frown":"⌢","fscr":"𝒻","Fscr":"ℱ","gacute":"ǵ","Gamma":"Γ","gamma":"γ","Gammad":"Ϝ","gammad":"ϝ","gap":"⪆","Gbreve":"Ğ","gbreve":"ğ","Gcedil":"Ģ","Gcirc":"Ĝ","gcirc":"ĝ","Gcy":"Г","gcy":"г","Gdot":"Ġ","gdot":"ġ","ge":"≥","gE":"≧","gEl":"⪌","gel":"⋛","geq":"≥","geqq":"≧","geqslant":"⩾","gescc":"⪩","ges":"⩾","gesdot":"⪀","gesdoto":"⪂","gesdotol":"⪄","gesl":"⋛︀","gesles":"⪔","Gfr":"𝔊","gfr":"𝔤","gg":"≫","Gg":"⋙","ggg":"⋙","gimel":"ℷ","GJcy":"Ѓ","gjcy":"ѓ","gla":"⪥","gl":"≷","glE":"⪒","glj":"⪤","gnap":"⪊","gnapprox":"⪊","gne":"⪈","gnE":"≩","gneq":"⪈","gneqq":"≩","gnsim":"⋧","Gopf":"𝔾","gopf":"𝕘","grave":"`","GreaterEqual":"≥","GreaterEqualLess":"⋛","GreaterFullEqual":"≧","GreaterGreater":"⪢","GreaterLess":"≷","GreaterSlantEqual":"⩾","GreaterTilde":"≳","Gscr":"𝒢","gscr":"ℊ","gsim":"≳","gsime":"⪎","gsiml":"⪐","gtcc":"⪧","gtcir":"⩺","gt":">","GT":">","Gt":"≫","gtdot":"⋗","gtlPar":"⦕","gtquest":"⩼","gtrapprox":"⪆","gtrarr":"⥸","gtrdot":"⋗","gtreqless":"⋛","gtreqqless":"⪌","gtrless":"≷","gtrsim":"≳","gvertneqq":"≩︀","gvnE":"≩︀","Hacek":"ˇ","hairsp":" ","half":"½","hamilt":"ℋ","HARDcy":"Ъ","hardcy":"ъ","harrcir":"⥈","harr":"↔","hArr":"⇔","harrw":"↭","Hat":"^","hbar":"ℏ","Hcirc":"Ĥ","hcirc":"ĥ","hearts":"♥","heartsuit":"♥","hellip":"…","hercon":"⊹","hfr":"𝔥","Hfr":"ℌ","HilbertSpace":"ℋ","hksearow":"⤥","hkswarow":"⤦","hoarr":"⇿","homtht":"∻","hookleftarrow":"↩","hookrightarrow":"↪","hopf":"𝕙","Hopf":"ℍ","horbar":"―","HorizontalLine":"─","hscr":"𝒽","Hscr":"ℋ","hslash":"ℏ","Hstrok":"Ħ","hstrok":"ħ","HumpDownHump":"≎","HumpEqual":"≏","hybull":"⁃","hyphen":"‐","Iacute":"Í","iacute":"í","ic":"⁣","Icirc":"Î","icirc":"î","Icy":"И","icy":"и","Idot":"İ","IEcy":"Е","iecy":"е","iexcl":"¡","iff":"⇔","ifr":"𝔦","Ifr":"ℑ","Igrave":"Ì","igrave":"ì","ii":"ⅈ","iiiint":"⨌","iiint":"∭","iinfin":"⧜","iiota":"℩","IJlig":"IJ","ijlig":"ij","Imacr":"Ī","imacr":"ī","image":"ℑ","ImaginaryI":"ⅈ","imagline":"ℐ","imagpart":"ℑ","imath":"ı","Im":"ℑ","imof":"⊷","imped":"Ƶ","Implies":"⇒","incare":"℅","in":"∈","infin":"∞","infintie":"⧝","inodot":"ı","intcal":"⊺","int":"∫","Int":"∬","integers":"ℤ","Integral":"∫","intercal":"⊺","Intersection":"⋂","intlarhk":"⨗","intprod":"⨼","InvisibleComma":"⁣","InvisibleTimes":"⁢","IOcy":"Ё","iocy":"ё","Iogon":"Į","iogon":"į","Iopf":"𝕀","iopf":"𝕚","Iota":"Ι","iota":"ι","iprod":"⨼","iquest":"¿","iscr":"𝒾","Iscr":"ℐ","isin":"∈","isindot":"⋵","isinE":"⋹","isins":"⋴","isinsv":"⋳","isinv":"∈","it":"⁢","Itilde":"Ĩ","itilde":"ĩ","Iukcy":"І","iukcy":"і","Iuml":"Ï","iuml":"ï","Jcirc":"Ĵ","jcirc":"ĵ","Jcy":"Й","jcy":"й","Jfr":"𝔍","jfr":"𝔧","jmath":"ȷ","Jopf":"𝕁","jopf":"𝕛","Jscr":"𝒥","jscr":"𝒿","Jsercy":"Ј","jsercy":"ј","Jukcy":"Є","jukcy":"є","Kappa":"Κ","kappa":"κ","kappav":"ϰ","Kcedil":"Ķ","kcedil":"ķ","Kcy":"К","kcy":"к","Kfr":"𝔎","kfr":"𝔨","kgreen":"ĸ","KHcy":"Х","khcy":"х","KJcy":"Ќ","kjcy":"ќ","Kopf":"𝕂","kopf":"𝕜","Kscr":"𝒦","kscr":"𝓀","lAarr":"⇚","Lacute":"Ĺ","lacute":"ĺ","laemptyv":"⦴","lagran":"ℒ","Lambda":"Λ","lambda":"λ","lang":"⟨","Lang":"⟪","langd":"⦑","langle":"⟨","lap":"⪅","Laplacetrf":"ℒ","laquo":"«","larrb":"⇤","larrbfs":"⤟","larr":"←","Larr":"↞","lArr":"⇐","larrfs":"⤝","larrhk":"↩","larrlp":"↫","larrpl":"⤹","larrsim":"⥳","larrtl":"↢","latail":"⤙","lAtail":"⤛","lat":"⪫","late":"⪭","lates":"⪭︀","lbarr":"⤌","lBarr":"⤎","lbbrk":"❲","lbrace":"{","lbrack":"[","lbrke":"⦋","lbrksld":"⦏","lbrkslu":"⦍","Lcaron":"Ľ","lcaron":"ľ","Lcedil":"Ļ","lcedil":"ļ","lceil":"⌈","lcub":"{","Lcy":"Л","lcy":"л","ldca":"⤶","ldquo":"“","ldquor":"„","ldrdhar":"⥧","ldrushar":"⥋","ldsh":"↲","le":"≤","lE":"≦","LeftAngleBracket":"⟨","LeftArrowBar":"⇤","leftarrow":"←","LeftArrow":"←","Leftarrow":"⇐","LeftArrowRightArrow":"⇆","leftarrowtail":"↢","LeftCeiling":"⌈","LeftDoubleBracket":"⟦","LeftDownTeeVector":"⥡","LeftDownVectorBar":"⥙","LeftDownVector":"⇃","LeftFloor":"⌊","leftharpoondown":"↽","leftharpoonup":"↼","leftleftarrows":"⇇","leftrightarrow":"↔","LeftRightArrow":"↔","Leftrightarrow":"⇔","leftrightarrows":"⇆","leftrightharpoons":"⇋","leftrightsquigarrow":"↭","LeftRightVector":"⥎","LeftTeeArrow":"↤","LeftTee":"⊣","LeftTeeVector":"⥚","leftthreetimes":"⋋","LeftTriangleBar":"⧏","LeftTriangle":"⊲","LeftTriangleEqual":"⊴","LeftUpDownVector":"⥑","LeftUpTeeVector":"⥠","LeftUpVectorBar":"⥘","LeftUpVector":"↿","LeftVectorBar":"⥒","LeftVector":"↼","lEg":"⪋","leg":"⋚","leq":"≤","leqq":"≦","leqslant":"⩽","lescc":"⪨","les":"⩽","lesdot":"⩿","lesdoto":"⪁","lesdotor":"⪃","lesg":"⋚︀","lesges":"⪓","lessapprox":"⪅","lessdot":"⋖","lesseqgtr":"⋚","lesseqqgtr":"⪋","LessEqualGreater":"⋚","LessFullEqual":"≦","LessGreater":"≶","lessgtr":"≶","LessLess":"⪡","lesssim":"≲","LessSlantEqual":"⩽","LessTilde":"≲","lfisht":"⥼","lfloor":"⌊","Lfr":"𝔏","lfr":"𝔩","lg":"≶","lgE":"⪑","lHar":"⥢","lhard":"↽","lharu":"↼","lharul":"⥪","lhblk":"▄","LJcy":"Љ","ljcy":"љ","llarr":"⇇","ll":"≪","Ll":"⋘","llcorner":"⌞","Lleftarrow":"⇚","llhard":"⥫","lltri":"◺","Lmidot":"Ŀ","lmidot":"ŀ","lmoustache":"⎰","lmoust":"⎰","lnap":"⪉","lnapprox":"⪉","lne":"⪇","lnE":"≨","lneq":"⪇","lneqq":"≨","lnsim":"⋦","loang":"⟬","loarr":"⇽","lobrk":"⟦","longleftarrow":"⟵","LongLeftArrow":"⟵","Longleftarrow":"⟸","longleftrightarrow":"⟷","LongLeftRightArrow":"⟷","Longleftrightarrow":"⟺","longmapsto":"⟼","longrightarrow":"⟶","LongRightArrow":"⟶","Longrightarrow":"⟹","looparrowleft":"↫","looparrowright":"↬","lopar":"⦅","Lopf":"𝕃","lopf":"𝕝","loplus":"⨭","lotimes":"⨴","lowast":"∗","lowbar":"_","LowerLeftArrow":"↙","LowerRightArrow":"↘","loz":"◊","lozenge":"◊","lozf":"⧫","lpar":"(","lparlt":"⦓","lrarr":"⇆","lrcorner":"⌟","lrhar":"⇋","lrhard":"⥭","lrm":"‎","lrtri":"⊿","lsaquo":"‹","lscr":"𝓁","Lscr":"ℒ","lsh":"↰","Lsh":"↰","lsim":"≲","lsime":"⪍","lsimg":"⪏","lsqb":"[","lsquo":"‘","lsquor":"‚","Lstrok":"Ł","lstrok":"ł","ltcc":"⪦","ltcir":"⩹","lt":"<","LT":"<","Lt":"≪","ltdot":"⋖","lthree":"⋋","ltimes":"⋉","ltlarr":"⥶","ltquest":"⩻","ltri":"◃","ltrie":"⊴","ltrif":"◂","ltrPar":"⦖","lurdshar":"⥊","luruhar":"⥦","lvertneqq":"≨︀","lvnE":"≨︀","macr":"¯","male":"♂","malt":"✠","maltese":"✠","Map":"⤅","map":"↦","mapsto":"↦","mapstodown":"↧","mapstoleft":"↤","mapstoup":"↥","marker":"▮","mcomma":"⨩","Mcy":"М","mcy":"м","mdash":"—","mDDot":"∺","measuredangle":"∡","MediumSpace":" ","Mellintrf":"ℳ","Mfr":"𝔐","mfr":"𝔪","mho":"℧","micro":"µ","midast":"*","midcir":"⫰","mid":"∣","middot":"·","minusb":"⊟","minus":"−","minusd":"∸","minusdu":"⨪","MinusPlus":"∓","mlcp":"⫛","mldr":"…","mnplus":"∓","models":"⊧","Mopf":"𝕄","mopf":"𝕞","mp":"∓","mscr":"𝓂","Mscr":"ℳ","mstpos":"∾","Mu":"Μ","mu":"μ","multimap":"⊸","mumap":"⊸","nabla":"∇","Nacute":"Ń","nacute":"ń","nang":"∠⃒","nap":"≉","napE":"⩰̸","napid":"≋̸","napos":"ʼn","napprox":"≉","natural":"♮","naturals":"ℕ","natur":"♮","nbsp":" ","nbump":"≎̸","nbumpe":"≏̸","ncap":"⩃","Ncaron":"Ň","ncaron":"ň","Ncedil":"Ņ","ncedil":"ņ","ncong":"≇","ncongdot":"⩭̸","ncup":"⩂","Ncy":"Н","ncy":"н","ndash":"–","nearhk":"⤤","nearr":"↗","neArr":"⇗","nearrow":"↗","ne":"≠","nedot":"≐̸","NegativeMediumSpace":"​","NegativeThickSpace":"​","NegativeThinSpace":"​","NegativeVeryThinSpace":"​","nequiv":"≢","nesear":"⤨","nesim":"≂̸","NestedGreaterGreater":"≫","NestedLessLess":"≪","NewLine":"\\n","nexist":"∄","nexists":"∄","Nfr":"𝔑","nfr":"𝔫","ngE":"≧̸","nge":"≱","ngeq":"≱","ngeqq":"≧̸","ngeqslant":"⩾̸","nges":"⩾̸","nGg":"⋙̸","ngsim":"≵","nGt":"≫⃒","ngt":"≯","ngtr":"≯","nGtv":"≫̸","nharr":"↮","nhArr":"⇎","nhpar":"⫲","ni":"∋","nis":"⋼","nisd":"⋺","niv":"∋","NJcy":"Њ","njcy":"њ","nlarr":"↚","nlArr":"⇍","nldr":"‥","nlE":"≦̸","nle":"≰","nleftarrow":"↚","nLeftarrow":"⇍","nleftrightarrow":"↮","nLeftrightarrow":"⇎","nleq":"≰","nleqq":"≦̸","nleqslant":"⩽̸","nles":"⩽̸","nless":"≮","nLl":"⋘̸","nlsim":"≴","nLt":"≪⃒","nlt":"≮","nltri":"⋪","nltrie":"⋬","nLtv":"≪̸","nmid":"∤","NoBreak":"⁠","NonBreakingSpace":" ","nopf":"𝕟","Nopf":"ℕ","Not":"⫬","not":"¬","NotCongruent":"≢","NotCupCap":"≭","NotDoubleVerticalBar":"∦","NotElement":"∉","NotEqual":"≠","NotEqualTilde":"≂̸","NotExists":"∄","NotGreater":"≯","NotGreaterEqual":"≱","NotGreaterFullEqual":"≧̸","NotGreaterGreater":"≫̸","NotGreaterLess":"≹","NotGreaterSlantEqual":"⩾̸","NotGreaterTilde":"≵","NotHumpDownHump":"≎̸","NotHumpEqual":"≏̸","notin":"∉","notindot":"⋵̸","notinE":"⋹̸","notinva":"∉","notinvb":"⋷","notinvc":"⋶","NotLeftTriangleBar":"⧏̸","NotLeftTriangle":"⋪","NotLeftTriangleEqual":"⋬","NotLess":"≮","NotLessEqual":"≰","NotLessGreater":"≸","NotLessLess":"≪̸","NotLessSlantEqual":"⩽̸","NotLessTilde":"≴","NotNestedGreaterGreater":"⪢̸","NotNestedLessLess":"⪡̸","notni":"∌","notniva":"∌","notnivb":"⋾","notnivc":"⋽","NotPrecedes":"⊀","NotPrecedesEqual":"⪯̸","NotPrecedesSlantEqual":"⋠","NotReverseElement":"∌","NotRightTriangleBar":"⧐̸","NotRightTriangle":"⋫","NotRightTriangleEqual":"⋭","NotSquareSubset":"⊏̸","NotSquareSubsetEqual":"⋢","NotSquareSuperset":"⊐̸","NotSquareSupersetEqual":"⋣","NotSubset":"⊂⃒","NotSubsetEqual":"⊈","NotSucceeds":"⊁","NotSucceedsEqual":"⪰̸","NotSucceedsSlantEqual":"⋡","NotSucceedsTilde":"≿̸","NotSuperset":"⊃⃒","NotSupersetEqual":"⊉","NotTilde":"≁","NotTildeEqual":"≄","NotTildeFullEqual":"≇","NotTildeTilde":"≉","NotVerticalBar":"∤","nparallel":"∦","npar":"∦","nparsl":"⫽⃥","npart":"∂̸","npolint":"⨔","npr":"⊀","nprcue":"⋠","nprec":"⊀","npreceq":"⪯̸","npre":"⪯̸","nrarrc":"⤳̸","nrarr":"↛","nrArr":"⇏","nrarrw":"↝̸","nrightarrow":"↛","nRightarrow":"⇏","nrtri":"⋫","nrtrie":"⋭","nsc":"⊁","nsccue":"⋡","nsce":"⪰̸","Nscr":"𝒩","nscr":"𝓃","nshortmid":"∤","nshortparallel":"∦","nsim":"≁","nsime":"≄","nsimeq":"≄","nsmid":"∤","nspar":"∦","nsqsube":"⋢","nsqsupe":"⋣","nsub":"⊄","nsubE":"⫅̸","nsube":"⊈","nsubset":"⊂⃒","nsubseteq":"⊈","nsubseteqq":"⫅̸","nsucc":"⊁","nsucceq":"⪰̸","nsup":"⊅","nsupE":"⫆̸","nsupe":"⊉","nsupset":"⊃⃒","nsupseteq":"⊉","nsupseteqq":"⫆̸","ntgl":"≹","Ntilde":"Ñ","ntilde":"ñ","ntlg":"≸","ntriangleleft":"⋪","ntrianglelefteq":"⋬","ntriangleright":"⋫","ntrianglerighteq":"⋭","Nu":"Ν","nu":"ν","num":"#","numero":"№","numsp":" ","nvap":"≍⃒","nvdash":"⊬","nvDash":"⊭","nVdash":"⊮","nVDash":"⊯","nvge":"≥⃒","nvgt":">⃒","nvHarr":"⤄","nvinfin":"⧞","nvlArr":"⤂","nvle":"≤⃒","nvlt":"<⃒","nvltrie":"⊴⃒","nvrArr":"⤃","nvrtrie":"⊵⃒","nvsim":"∼⃒","nwarhk":"⤣","nwarr":"↖","nwArr":"⇖","nwarrow":"↖","nwnear":"⤧","Oacute":"Ó","oacute":"ó","oast":"⊛","Ocirc":"Ô","ocirc":"ô","ocir":"⊚","Ocy":"О","ocy":"о","odash":"⊝","Odblac":"Ő","odblac":"ő","odiv":"⨸","odot":"⊙","odsold":"⦼","OElig":"Œ","oelig":"œ","ofcir":"⦿","Ofr":"𝔒","ofr":"𝔬","ogon":"˛","Ograve":"Ò","ograve":"ò","ogt":"⧁","ohbar":"⦵","ohm":"Ω","oint":"∮","olarr":"↺","olcir":"⦾","olcross":"⦻","oline":"‾","olt":"⧀","Omacr":"Ō","omacr":"ō","Omega":"Ω","omega":"ω","Omicron":"Ο","omicron":"ο","omid":"⦶","ominus":"⊖","Oopf":"𝕆","oopf":"𝕠","opar":"⦷","OpenCurlyDoubleQuote":"“","OpenCurlyQuote":"‘","operp":"⦹","oplus":"⊕","orarr":"↻","Or":"⩔","or":"∨","ord":"⩝","order":"ℴ","orderof":"ℴ","ordf":"ª","ordm":"º","origof":"⊶","oror":"⩖","orslope":"⩗","orv":"⩛","oS":"Ⓢ","Oscr":"𝒪","oscr":"ℴ","Oslash":"Ø","oslash":"ø","osol":"⊘","Otilde":"Õ","otilde":"õ","otimesas":"⨶","Otimes":"⨷","otimes":"⊗","Ouml":"Ö","ouml":"ö","ovbar":"⌽","OverBar":"‾","OverBrace":"⏞","OverBracket":"⎴","OverParenthesis":"⏜","para":"¶","parallel":"∥","par":"∥","parsim":"⫳","parsl":"⫽","part":"∂","PartialD":"∂","Pcy":"П","pcy":"п","percnt":"%","period":".","permil":"‰","perp":"⊥","pertenk":"‱","Pfr":"𝔓","pfr":"𝔭","Phi":"Φ","phi":"φ","phiv":"ϕ","phmmat":"ℳ","phone":"☎","Pi":"Π","pi":"π","pitchfork":"⋔","piv":"ϖ","planck":"ℏ","planckh":"ℎ","plankv":"ℏ","plusacir":"⨣","plusb":"⊞","pluscir":"⨢","plus":"+","plusdo":"∔","plusdu":"⨥","pluse":"⩲","PlusMinus":"±","plusmn":"±","plussim":"⨦","plustwo":"⨧","pm":"±","Poincareplane":"ℌ","pointint":"⨕","popf":"𝕡","Popf":"ℙ","pound":"£","prap":"⪷","Pr":"⪻","pr":"≺","prcue":"≼","precapprox":"⪷","prec":"≺","preccurlyeq":"≼","Precedes":"≺","PrecedesEqual":"⪯","PrecedesSlantEqual":"≼","PrecedesTilde":"≾","preceq":"⪯","precnapprox":"⪹","precneqq":"⪵","precnsim":"⋨","pre":"⪯","prE":"⪳","precsim":"≾","prime":"′","Prime":"″","primes":"ℙ","prnap":"⪹","prnE":"⪵","prnsim":"⋨","prod":"∏","Product":"∏","profalar":"⌮","profline":"⌒","profsurf":"⌓","prop":"∝","Proportional":"∝","Proportion":"∷","propto":"∝","prsim":"≾","prurel":"⊰","Pscr":"𝒫","pscr":"𝓅","Psi":"Ψ","psi":"ψ","puncsp":" ","Qfr":"𝔔","qfr":"𝔮","qint":"⨌","qopf":"𝕢","Qopf":"ℚ","qprime":"⁗","Qscr":"𝒬","qscr":"𝓆","quaternions":"ℍ","quatint":"⨖","quest":"?","questeq":"≟","quot":"\\"","QUOT":"\\"","rAarr":"⇛","race":"∽̱","Racute":"Ŕ","racute":"ŕ","radic":"√","raemptyv":"⦳","rang":"⟩","Rang":"⟫","rangd":"⦒","range":"⦥","rangle":"⟩","raquo":"»","rarrap":"⥵","rarrb":"⇥","rarrbfs":"⤠","rarrc":"⤳","rarr":"→","Rarr":"↠","rArr":"⇒","rarrfs":"⤞","rarrhk":"↪","rarrlp":"↬","rarrpl":"⥅","rarrsim":"⥴","Rarrtl":"⤖","rarrtl":"↣","rarrw":"↝","ratail":"⤚","rAtail":"⤜","ratio":"∶","rationals":"ℚ","rbarr":"⤍","rBarr":"⤏","RBarr":"⤐","rbbrk":"❳","rbrace":"}","rbrack":"]","rbrke":"⦌","rbrksld":"⦎","rbrkslu":"⦐","Rcaron":"Ř","rcaron":"ř","Rcedil":"Ŗ","rcedil":"ŗ","rceil":"⌉","rcub":"}","Rcy":"Р","rcy":"р","rdca":"⤷","rdldhar":"⥩","rdquo":"”","rdquor":"”","rdsh":"↳","real":"ℜ","realine":"ℛ","realpart":"ℜ","reals":"ℝ","Re":"ℜ","rect":"▭","reg":"®","REG":"®","ReverseElement":"∋","ReverseEquilibrium":"⇋","ReverseUpEquilibrium":"⥯","rfisht":"⥽","rfloor":"⌋","rfr":"𝔯","Rfr":"ℜ","rHar":"⥤","rhard":"⇁","rharu":"⇀","rharul":"⥬","Rho":"Ρ","rho":"ρ","rhov":"ϱ","RightAngleBracket":"⟩","RightArrowBar":"⇥","rightarrow":"→","RightArrow":"→","Rightarrow":"⇒","RightArrowLeftArrow":"⇄","rightarrowtail":"↣","RightCeiling":"⌉","RightDoubleBracket":"⟧","RightDownTeeVector":"⥝","RightDownVectorBar":"⥕","RightDownVector":"⇂","RightFloor":"⌋","rightharpoondown":"⇁","rightharpoonup":"⇀","rightleftarrows":"⇄","rightleftharpoons":"⇌","rightrightarrows":"⇉","rightsquigarrow":"↝","RightTeeArrow":"↦","RightTee":"⊢","RightTeeVector":"⥛","rightthreetimes":"⋌","RightTriangleBar":"⧐","RightTriangle":"⊳","RightTriangleEqual":"⊵","RightUpDownVector":"⥏","RightUpTeeVector":"⥜","RightUpVectorBar":"⥔","RightUpVector":"↾","RightVectorBar":"⥓","RightVector":"⇀","ring":"˚","risingdotseq":"≓","rlarr":"⇄","rlhar":"⇌","rlm":"‏","rmoustache":"⎱","rmoust":"⎱","rnmid":"⫮","roang":"⟭","roarr":"⇾","robrk":"⟧","ropar":"⦆","ropf":"𝕣","Ropf":"ℝ","roplus":"⨮","rotimes":"⨵","RoundImplies":"⥰","rpar":")","rpargt":"⦔","rppolint":"⨒","rrarr":"⇉","Rrightarrow":"⇛","rsaquo":"›","rscr":"𝓇","Rscr":"ℛ","rsh":"↱","Rsh":"↱","rsqb":"]","rsquo":"’","rsquor":"’","rthree":"⋌","rtimes":"⋊","rtri":"▹","rtrie":"⊵","rtrif":"▸","rtriltri":"⧎","RuleDelayed":"⧴","ruluhar":"⥨","rx":"℞","Sacute":"Ś","sacute":"ś","sbquo":"‚","scap":"⪸","Scaron":"Š","scaron":"š","Sc":"⪼","sc":"≻","sccue":"≽","sce":"⪰","scE":"⪴","Scedil":"Ş","scedil":"ş","Scirc":"Ŝ","scirc":"ŝ","scnap":"⪺","scnE":"⪶","scnsim":"⋩","scpolint":"⨓","scsim":"≿","Scy":"С","scy":"с","sdotb":"⊡","sdot":"⋅","sdote":"⩦","searhk":"⤥","searr":"↘","seArr":"⇘","searrow":"↘","sect":"§","semi":";","seswar":"⤩","setminus":"∖","setmn":"∖","sext":"✶","Sfr":"𝔖","sfr":"𝔰","sfrown":"⌢","sharp":"♯","SHCHcy":"Щ","shchcy":"щ","SHcy":"Ш","shcy":"ш","ShortDownArrow":"↓","ShortLeftArrow":"←","shortmid":"∣","shortparallel":"∥","ShortRightArrow":"→","ShortUpArrow":"↑","shy":"­","Sigma":"Σ","sigma":"σ","sigmaf":"ς","sigmav":"ς","sim":"∼","simdot":"⩪","sime":"≃","simeq":"≃","simg":"⪞","simgE":"⪠","siml":"⪝","simlE":"⪟","simne":"≆","simplus":"⨤","simrarr":"⥲","slarr":"←","SmallCircle":"∘","smallsetminus":"∖","smashp":"⨳","smeparsl":"⧤","smid":"∣","smile":"⌣","smt":"⪪","smte":"⪬","smtes":"⪬︀","SOFTcy":"Ь","softcy":"ь","solbar":"⌿","solb":"⧄","sol":"/","Sopf":"𝕊","sopf":"𝕤","spades":"♠","spadesuit":"♠","spar":"∥","sqcap":"⊓","sqcaps":"⊓︀","sqcup":"⊔","sqcups":"⊔︀","Sqrt":"√","sqsub":"⊏","sqsube":"⊑","sqsubset":"⊏","sqsubseteq":"⊑","sqsup":"⊐","sqsupe":"⊒","sqsupset":"⊐","sqsupseteq":"⊒","square":"□","Square":"□","SquareIntersection":"⊓","SquareSubset":"⊏","SquareSubsetEqual":"⊑","SquareSuperset":"⊐","SquareSupersetEqual":"⊒","SquareUnion":"⊔","squarf":"▪","squ":"□","squf":"▪","srarr":"→","Sscr":"𝒮","sscr":"𝓈","ssetmn":"∖","ssmile":"⌣","sstarf":"⋆","Star":"⋆","star":"☆","starf":"★","straightepsilon":"ϵ","straightphi":"ϕ","strns":"¯","sub":"⊂","Sub":"⋐","subdot":"⪽","subE":"⫅","sube":"⊆","subedot":"⫃","submult":"⫁","subnE":"⫋","subne":"⊊","subplus":"⪿","subrarr":"⥹","subset":"⊂","Subset":"⋐","subseteq":"⊆","subseteqq":"⫅","SubsetEqual":"⊆","subsetneq":"⊊","subsetneqq":"⫋","subsim":"⫇","subsub":"⫕","subsup":"⫓","succapprox":"⪸","succ":"≻","succcurlyeq":"≽","Succeeds":"≻","SucceedsEqual":"⪰","SucceedsSlantEqual":"≽","SucceedsTilde":"≿","succeq":"⪰","succnapprox":"⪺","succneqq":"⪶","succnsim":"⋩","succsim":"≿","SuchThat":"∋","sum":"∑","Sum":"∑","sung":"♪","sup1":"¹","sup2":"²","sup3":"³","sup":"⊃","Sup":"⋑","supdot":"⪾","supdsub":"⫘","supE":"⫆","supe":"⊇","supedot":"⫄","Superset":"⊃","SupersetEqual":"⊇","suphsol":"⟉","suphsub":"⫗","suplarr":"⥻","supmult":"⫂","supnE":"⫌","supne":"⊋","supplus":"⫀","supset":"⊃","Supset":"⋑","supseteq":"⊇","supseteqq":"⫆","supsetneq":"⊋","supsetneqq":"⫌","supsim":"⫈","supsub":"⫔","supsup":"⫖","swarhk":"⤦","swarr":"↙","swArr":"⇙","swarrow":"↙","swnwar":"⤪","szlig":"ß","Tab":"\\t","target":"⌖","Tau":"Τ","tau":"τ","tbrk":"⎴","Tcaron":"Ť","tcaron":"ť","Tcedil":"Ţ","tcedil":"ţ","Tcy":"Т","tcy":"т","tdot":"⃛","telrec":"⌕","Tfr":"𝔗","tfr":"𝔱","there4":"∴","therefore":"∴","Therefore":"∴","Theta":"Θ","theta":"θ","thetasym":"ϑ","thetav":"ϑ","thickapprox":"≈","thicksim":"∼","ThickSpace":"  ","ThinSpace":" ","thinsp":" ","thkap":"≈","thksim":"∼","THORN":"Þ","thorn":"þ","tilde":"˜","Tilde":"∼","TildeEqual":"≃","TildeFullEqual":"≅","TildeTilde":"≈","timesbar":"⨱","timesb":"⊠","times":"×","timesd":"⨰","tint":"∭","toea":"⤨","topbot":"⌶","topcir":"⫱","top":"⊤","Topf":"𝕋","topf":"𝕥","topfork":"⫚","tosa":"⤩","tprime":"‴","trade":"™","TRADE":"™","triangle":"▵","triangledown":"▿","triangleleft":"◃","trianglelefteq":"⊴","triangleq":"≜","triangleright":"▹","trianglerighteq":"⊵","tridot":"◬","trie":"≜","triminus":"⨺","TripleDot":"⃛","triplus":"⨹","trisb":"⧍","tritime":"⨻","trpezium":"⏢","Tscr":"𝒯","tscr":"𝓉","TScy":"Ц","tscy":"ц","TSHcy":"Ћ","tshcy":"ћ","Tstrok":"Ŧ","tstrok":"ŧ","twixt":"≬","twoheadleftarrow":"↞","twoheadrightarrow":"↠","Uacute":"Ú","uacute":"ú","uarr":"↑","Uarr":"↟","uArr":"⇑","Uarrocir":"⥉","Ubrcy":"Ў","ubrcy":"ў","Ubreve":"Ŭ","ubreve":"ŭ","Ucirc":"Û","ucirc":"û","Ucy":"У","ucy":"у","udarr":"⇅","Udblac":"Ű","udblac":"ű","udhar":"⥮","ufisht":"⥾","Ufr":"𝔘","ufr":"𝔲","Ugrave":"Ù","ugrave":"ù","uHar":"⥣","uharl":"↿","uharr":"↾","uhblk":"▀","ulcorn":"⌜","ulcorner":"⌜","ulcrop":"⌏","ultri":"◸","Umacr":"Ū","umacr":"ū","uml":"¨","UnderBar":"_","UnderBrace":"⏟","UnderBracket":"⎵","UnderParenthesis":"⏝","Union":"⋃","UnionPlus":"⊎","Uogon":"Ų","uogon":"ų","Uopf":"𝕌","uopf":"𝕦","UpArrowBar":"⤒","uparrow":"↑","UpArrow":"↑","Uparrow":"⇑","UpArrowDownArrow":"⇅","updownarrow":"↕","UpDownArrow":"↕","Updownarrow":"⇕","UpEquilibrium":"⥮","upharpoonleft":"↿","upharpoonright":"↾","uplus":"⊎","UpperLeftArrow":"↖","UpperRightArrow":"↗","upsi":"υ","Upsi":"ϒ","upsih":"ϒ","Upsilon":"Υ","upsilon":"υ","UpTeeArrow":"↥","UpTee":"⊥","upuparrows":"⇈","urcorn":"⌝","urcorner":"⌝","urcrop":"⌎","Uring":"Ů","uring":"ů","urtri":"◹","Uscr":"𝒰","uscr":"𝓊","utdot":"⋰","Utilde":"Ũ","utilde":"ũ","utri":"▵","utrif":"▴","uuarr":"⇈","Uuml":"Ü","uuml":"ü","uwangle":"⦧","vangrt":"⦜","varepsilon":"ϵ","varkappa":"ϰ","varnothing":"∅","varphi":"ϕ","varpi":"ϖ","varpropto":"∝","varr":"↕","vArr":"⇕","varrho":"ϱ","varsigma":"ς","varsubsetneq":"⊊︀","varsubsetneqq":"⫋︀","varsupsetneq":"⊋︀","varsupsetneqq":"⫌︀","vartheta":"ϑ","vartriangleleft":"⊲","vartriangleright":"⊳","vBar":"⫨","Vbar":"⫫","vBarv":"⫩","Vcy":"В","vcy":"в","vdash":"⊢","vDash":"⊨","Vdash":"⊩","VDash":"⊫","Vdashl":"⫦","veebar":"⊻","vee":"∨","Vee":"⋁","veeeq":"≚","vellip":"⋮","verbar":"|","Verbar":"‖","vert":"|","Vert":"‖","VerticalBar":"∣","VerticalLine":"|","VerticalSeparator":"❘","VerticalTilde":"≀","VeryThinSpace":" ","Vfr":"𝔙","vfr":"𝔳","vltri":"⊲","vnsub":"⊂⃒","vnsup":"⊃⃒","Vopf":"𝕍","vopf":"𝕧","vprop":"∝","vrtri":"⊳","Vscr":"𝒱","vscr":"𝓋","vsubnE":"⫋︀","vsubne":"⊊︀","vsupnE":"⫌︀","vsupne":"⊋︀","Vvdash":"⊪","vzigzag":"⦚","Wcirc":"Ŵ","wcirc":"ŵ","wedbar":"⩟","wedge":"∧","Wedge":"⋀","wedgeq":"≙","weierp":"℘","Wfr":"𝔚","wfr":"𝔴","Wopf":"𝕎","wopf":"𝕨","wp":"℘","wr":"≀","wreath":"≀","Wscr":"𝒲","wscr":"𝓌","xcap":"⋂","xcirc":"◯","xcup":"⋃","xdtri":"▽","Xfr":"𝔛","xfr":"𝔵","xharr":"⟷","xhArr":"⟺","Xi":"Ξ","xi":"ξ","xlarr":"⟵","xlArr":"⟸","xmap":"⟼","xnis":"⋻","xodot":"⨀","Xopf":"𝕏","xopf":"𝕩","xoplus":"⨁","xotime":"⨂","xrarr":"⟶","xrArr":"⟹","Xscr":"𝒳","xscr":"𝓍","xsqcup":"⨆","xuplus":"⨄","xutri":"△","xvee":"⋁","xwedge":"⋀","Yacute":"Ý","yacute":"ý","YAcy":"Я","yacy":"я","Ycirc":"Ŷ","ycirc":"ŷ","Ycy":"Ы","ycy":"ы","yen":"¥","Yfr":"𝔜","yfr":"𝔶","YIcy":"Ї","yicy":"ї","Yopf":"𝕐","yopf":"𝕪","Yscr":"𝒴","yscr":"𝓎","YUcy":"Ю","yucy":"ю","yuml":"ÿ","Yuml":"Ÿ","Zacute":"Ź","zacute":"ź","Zcaron":"Ž","zcaron":"ž","Zcy":"З","zcy":"з","Zdot":"Ż","zdot":"ż","zeetrf":"ℨ","ZeroWidthSpace":"​","Zeta":"Ζ","zeta":"ζ","zfr":"𝔷","Zfr":"ℨ","ZHcy":"Ж","zhcy":"ж","zigrarr":"⇝","zopf":"𝕫","Zopf":"ℤ","Zscr":"𝒵","zscr":"𝓏","zwj":"‍","zwnj":"‌"}')},function(t,e,n){"use strict";var r={};function o(t,e,n){var i,a,s,c,u,l="";for("string"!=typeof e&&(n=e,e=o.defaultChars),void 0===n&&(n=!0),u=function(t){var e,n,o=r[t];if(o)return o;for(o=r[t]=[],e=0;e<128;e++)n=String.fromCharCode(e),/^[0-9a-z]$/i.test(n)?o.push(n):o.push("%"+("0"+e.toString(16).toUpperCase()).slice(-2));for(e=0;e=55296&&s<=57343){if(s>=55296&&s<=56319&&i+1=56320&&c<=57343){l+=encodeURIComponent(t[i]+t[i+1]),i++;continue}l+="%EF%BF%BD"}else l+=encodeURIComponent(t[i]);return l}o.defaultChars=";/?:@&=+$,-_.!~*'()#",o.componentChars="-_.!~*'()",t.exports=o},function(t,e,n){"use strict";var r={};function o(t,e){var n;return"string"!=typeof e&&(e=o.defaultChars),n=function(t){var e,n,o=r[t];if(o)return o;for(o=r[t]=[],e=0;e<128;e++)n=String.fromCharCode(e),o.push(n);for(e=0;e=55296&&c<=57343?"���":String.fromCharCode(c),e+=6):240==(248&o)&&e+91114111?u+="����":(c-=65536,u+=String.fromCharCode(55296+(c>>10),56320+(1023&c))),e+=9):u+="�";return u}))}o.defaultChars=";/?:@&=+$,#",o.componentChars="",t.exports=o},function(t,e,n){"use strict";t.exports=function(t){var e="";return e+=t.protocol||"",e+=t.slashes?"//":"",e+=t.auth?t.auth+"@":"",t.hostname&&-1!==t.hostname.indexOf(":")?e+="["+t.hostname+"]":e+=t.hostname||"",e+=t.port?":"+t.port:"",e+=t.pathname||"",e+=t.search||"",e+=t.hash||""}},function(t,e,n){"use strict";function r(){this.protocol=null,this.slashes=null,this.auth=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.pathname=null}var o=/^([a-z0-9.+-]+:)/i,i=/:[0-9]*$/,a=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,s=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),c=["'"].concat(s),u=["%","/","?",";","#"].concat(c),l=["/","?","#"],f=/^[+a-z0-9A-Z_-]{0,63}$/,p=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,d={javascript:!0,"javascript:":!0},h={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0};r.prototype.parse=function(t,e){var n,r,i,s,c,g=t;if(g=g.trim(),!e&&1===t.split("#").length){var m=a.exec(g);if(m)return this.pathname=m[1],m[2]&&(this.search=m[2]),this}var v=o.exec(g);if(v&&(i=(v=v[0]).toLowerCase(),this.protocol=v,g=g.substr(v.length)),(e||v||g.match(/^\/\/[^@\/]+@[^@\/]+/))&&(!(c="//"===g.substr(0,2))||v&&d[v]||(g=g.substr(2),this.slashes=!0)),!d[v]&&(c||v&&!h[v])){var b,_,y=-1;for(n=0;n127?C+="x":C+=w[A];if(!C.match(f)){var S=k.slice(0,n),R=k.slice(n+1),O=w.match(p);O&&(S.push(O[1]),R.unshift(O[2])),R.length&&(g=R.join(".")+g),this.hostname=S.join(".");break}}}}this.hostname.length>255&&(this.hostname=""),x&&(this.hostname=this.hostname.substr(1,this.hostname.length-2))}var N=g.indexOf("#");-1!==N&&(this.hash=g.substr(N),g=g.slice(0,N));var L=g.indexOf("?");return-1!==L&&(this.search=g.substr(L),g=g.slice(0,L)),g&&(this.pathname=g),h[i]&&this.hostname&&!this.pathname&&(this.pathname=""),this},r.prototype.parseHost=function(t){var e=i.exec(t);e&&(":"!==(e=e[0])&&(this.port=e.substr(1)),t=t.substr(0,t.length-e.length)),t&&(this.hostname=t)},t.exports=function(t,e){if(t&&t instanceof r)return t;var n=new r;return n.parse(t,e),n}},function(t,e,n){"use strict";e.Any=n(57),e.Cc=n(58),e.Cf=n(109),e.P=n(36),e.Z=n(59)},function(t,e){t.exports=/[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804[\uDCBD\uDCCD]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/},function(t,e,n){"use strict";e.parseLinkLabel=n(111),e.parseLinkDestination=n(112),e.parseLinkTitle=n(113)},function(t,e,n){"use strict";t.exports=function(t,e,n){var r,o,i,a,s=-1,c=t.posMax,u=t.pos;for(t.pos=e+1,r=1;t.pos=n)return c;if(34!==(i=t.charCodeAt(e))&&39!==i&&40!==i)return c;for(e++,40===i&&(i=41);e"+i(t[e].content)+""},a.code_block=function(t,e,n,r,o){var a=t[e];return""+i(t[e].content)+"\n"},a.fence=function(t,e,n,r,a){var s,c,u,l,f=t[e],p=f.info?o(f.info).trim():"",d="";return p&&(d=p.split(/\s+/g)[0]),0===(s=n.highlight&&n.highlight(f.content,d)||i(f.content)).indexOf(""+s+"\n"):"
"+s+"
\n"},a.image=function(t,e,n,r,o){var i=t[e];return i.attrs[i.attrIndex("alt")][1]=o.renderInlineAsText(i.children,n,r),o.renderToken(t,e,n)},a.hardbreak=function(t,e,n){return n.xhtmlOut?"
\n":"
\n"},a.softbreak=function(t,e,n){return n.breaks?n.xhtmlOut?"
\n":"
\n":"\n"},a.text=function(t,e){return i(t[e].content)},a.html_block=function(t,e){return t[e].content},a.html_inline=function(t,e){return t[e].content},s.prototype.renderAttrs=function(t){var e,n,r;if(!t.attrs)return"";for(r="",e=0,n=t.attrs.length;e\n":">")},s.prototype.renderInline=function(t,e,n){for(var r,o="",i=this.rules,a=0,s=t.length;a/i.test(t)}t.exports=function(t){var e,n,i,a,s,c,u,l,f,p,d,h,g,m,v,b,_,y,E=t.tokens;if(t.md.options.linkify)for(n=0,i=E.length;n=0;e--)if("link_close"!==(c=a[e]).type){if("html_inline"===c.type&&(y=c.content,/^\s]/i.test(y)&&g>0&&g--,o(c.content)&&g++),!(g>0)&&"text"===c.type&&t.md.linkify.test(c.content)){for(f=c.content,_=t.md.linkify.match(f),u=[],h=c.level,d=0,l=0;l<_.length;l++)m=_[l].url,v=t.md.normalizeLink(m),t.md.validateLink(v)&&(b=_[l].text,b=_[l].schema?"mailto:"!==_[l].schema||/^mailto:/i.test(b)?t.md.normalizeLinkText(b):t.md.normalizeLinkText("mailto:"+b).replace(/^mailto:/,""):t.md.normalizeLinkText("http://"+b).replace(/^http:\/\//,""),(p=_[l].index)>d&&((s=new t.Token("text","",0)).content=f.slice(d,p),s.level=h,u.push(s)),(s=new t.Token("link_open","a",1)).attrs=[["href",v]],s.level=h++,s.markup="linkify",s.info="auto",u.push(s),(s=new t.Token("text","",0)).content=b,s.level=h,u.push(s),(s=new t.Token("link_close","a",-1)).level=--h,s.markup="linkify",s.info="auto",u.push(s),d=_[l].lastIndex);d=0;e--)"text"!==(n=t[e]).type||r||(n.content=n.content.replace(i,s)),"link_open"===n.type&&"auto"===n.info&&r--,"link_close"===n.type&&"auto"===n.info&&r++}function u(t){var e,n,o=0;for(e=t.length-1;e>=0;e--)"text"!==(n=t[e]).type||o||r.test(n.content)&&(n.content=n.content.replace(/\+-/g,"±").replace(/\.{2,}/g,"…").replace(/([?!])…/g,"$1..").replace(/([?!]){4,}/g,"$1$1$1").replace(/,{2,}/g,",").replace(/(^|[^-])---([^-]|$)/gm,"$1—$2").replace(/(^|\s)--(\s|$)/gm,"$1–$2").replace(/(^|[^-\s])--([^-\s]|$)/gm,"$1–$2")),"link_open"===n.type&&"auto"===n.info&&o--,"link_close"===n.type&&"auto"===n.info&&o++}t.exports=function(t){var e;if(t.md.options.typographer)for(e=t.tokens.length-1;e>=0;e--)"inline"===t.tokens[e].type&&(o.test(t.tokens[e].content)&&c(t.tokens[e].children),r.test(t.tokens[e].content)&&u(t.tokens[e].children))}},function(t,e,n){"use strict";var r=n(1).isWhiteSpace,o=n(1).isPunctChar,i=n(1).isMdAsciiPunct,a=/['"]/,s=/['"]/g,c="’";function u(t,e,n){return t.substr(0,e)+n+t.substr(e+1)}function l(t,e){var n,a,l,f,p,d,h,g,m,v,b,_,y,E,x,k,w,C,A,T,S;for(A=[],n=0;n=0&&!(A[w].level<=h);w--);if(A.length=w+1,"text"===a.type){p=0,d=(l=a.content).length;t:for(;p=0)m=l.charCodeAt(f.index-1);else for(w=n-1;w>=0&&("softbreak"!==t[w].type&&"hardbreak"!==t[w].type);w--)if("text"===t[w].type){m=t[w].content.charCodeAt(t[w].content.length-1);break}if(v=32,p=48&&m<=57&&(k=x=!1),x&&k&&(x=!1,k=_),x||k){if(k)for(w=A.length-1;w>=0&&(g=A[w],!(A[w].level=0;e--)"inline"===t.tokens[e].type&&a.test(t.tokens[e].content)&&l(t.tokens[e].children,t)}},function(t,e,n){"use strict";var r=n(38);function o(t,e,n){this.src=t,this.env=n,this.tokens=[],this.inlineMode=!1,this.md=e}o.prototype.Token=r,t.exports=o},function(t,e,n){"use strict";var r=n(37),o=[["table",n(124),["paragraph","reference"]],["code",n(125)],["fence",n(126),["paragraph","reference","blockquote","list"]],["blockquote",n(127),["paragraph","reference","blockquote","list"]],["hr",n(128),["paragraph","reference","blockquote","list"]],["list",n(129),["paragraph","reference","blockquote"]],["reference",n(130)],["heading",n(131),["paragraph","reference","blockquote"]],["lheading",n(132)],["html_block",n(133),["paragraph","reference","blockquote"]],["paragraph",n(135)]];function i(){this.ruler=new r;for(var t=0;t=n))&&!(t.sCount[a]=c){t.line=n;break}for(r=0;rn)return!1;if(f=e+1,t.sCount[f]=4)return!1;if((u=t.bMarks[f]+t.tShift[f])>=t.eMarks[f])return!1;if(124!==(s=t.src.charCodeAt(u++))&&45!==s&&58!==s)return!1;for(;u=4)return!1;if((d=(p=i(c.replace(/^\||\|$/g,""))).length)>g.length)return!1;if(a)return!0;for((h=t.push("table_open","table",1)).map=v=[e,0],(h=t.push("thead_open","thead",1)).map=[e,e+1],(h=t.push("tr_open","tr",1)).map=[e,e+1],l=0;l=4);f++){for(p=i(c.replace(/^\||\|$/g,"")),h=t.push("tr_open","tr",1),l=0;l=4))break;o=++r}return t.line=o,(i=t.push("code_block","code",0)).content=t.getLines(e,o,4+t.blkIndent,!0),i.map=[e,t.line],!0}},function(t,e,n){"use strict";t.exports=function(t,e,n,r){var o,i,a,s,c,u,l,f=!1,p=t.bMarks[e]+t.tShift[e],d=t.eMarks[e];if(t.sCount[e]-t.blkIndent>=4)return!1;if(p+3>d)return!1;if(126!==(o=t.src.charCodeAt(p))&&96!==o)return!1;if(c=p,(i=(p=t.skipChars(p,o))-c)<3)return!1;if(l=t.src.slice(c,p),a=t.src.slice(p,d),96===o&&a.indexOf(String.fromCharCode(o))>=0)return!1;if(r)return!0;for(s=e;!(++s>=n)&&!((p=c=t.bMarks[s]+t.tShift[s])<(d=t.eMarks[s])&&t.sCount[s]=4||(p=t.skipChars(p,o))-c=4)return!1;if(62!==t.src.charCodeAt(A++))return!1;if(o)return!0;for(c=d=t.sCount[e]+A-(t.bMarks[e]+t.tShift[e]),32===t.src.charCodeAt(A)?(A++,c++,d++,i=!1,y=!0):9===t.src.charCodeAt(A)?(y=!0,(t.bsCount[e]+d)%4==3?(A++,c++,d++,i=!1):i=!0):y=!1,h=[t.bMarks[e]],t.bMarks[e]=A;A=T,b=[t.sCount[e]],t.sCount[e]=d-c,_=[t.tShift[e]],t.tShift[e]=A-t.bMarks[e],x=t.md.block.ruler.getRules("blockquote"),v=t.parentType,t.parentType="blockquote",w=!1,p=e+1;p=(T=t.eMarks[p])));p++)if(62!==t.src.charCodeAt(A++)||w){if(l)break;for(E=!1,s=0,u=x.length;s=T,g.push(t.bsCount[p]),t.bsCount[p]=t.sCount[p]+1+(y?1:0),b.push(t.sCount[p]),t.sCount[p]=d-c,_.push(t.tShift[p]),t.tShift[p]=A-t.bMarks[p]}for(m=t.blkIndent,t.blkIndent=0,(k=t.push("blockquote_open","blockquote",1)).markup=">",k.map=f=[e,0],t.md.block.tokenize(t,e,p),(k=t.push("blockquote_close","blockquote",-1)).markup=">",t.lineMax=C,t.parentType=v,f[1]=t.line,s=0;s<_.length;s++)t.bMarks[s+e]=h[s],t.tShift[s+e]=_[s],t.sCount[s+e]=b[s],t.bsCount[s+e]=g[s];return t.blkIndent=m,!0}},function(t,e,n){"use strict";var r=n(1).isSpace;t.exports=function(t,e,n,o){var i,a,s,c,u=t.bMarks[e]+t.tShift[e],l=t.eMarks[e];if(t.sCount[e]-t.blkIndent>=4)return!1;if(42!==(i=t.src.charCodeAt(u++))&&45!==i&&95!==i)return!1;for(a=1;u=a)return-1;if((n=t.src.charCodeAt(i++))<48||n>57)return-1;for(;;){if(i>=a)return-1;if(!((n=t.src.charCodeAt(i++))>=48&&n<=57)){if(41===n||46===n)break;return-1}if(i-o>=10)return-1}return i=4)return!1;if(t.listIndent>=0&&t.sCount[e]-t.listIndent>=4&&t.sCount[e]=t.blkIndent&&(D=!0),(S=i(t,e))>=0){if(p=!0,O=t.bMarks[e]+t.tShift[e],b=Number(t.src.substr(O,S-O-1)),D&&1!==b)return!1}else{if(!((S=o(t,e))>=0))return!1;p=!1}if(D&&t.skipSpaces(S)>=t.eMarks[e])return!1;if(v=t.src.charCodeAt(S-1),r)return!0;for(m=t.tokens.length,p?(I=t.push("ordered_list_open","ol",1),1!==b&&(I.attrs=[["start",b]])):I=t.push("bullet_list_open","ul",1),I.map=g=[e,0],I.markup=String.fromCharCode(v),y=e,R=!1,L=t.md.block.ruler.getRules("list"),k=t.parentType,t.parentType="list";y=_?1:E-f)>4&&(l=1),u=f+l,(I=t.push("list_item_open","li",1)).markup=String.fromCharCode(v),I.map=d=[e,0],A=t.tight,C=t.tShift[e],w=t.sCount[e],x=t.listIndent,t.listIndent=t.blkIndent,t.blkIndent=u,t.tight=!0,t.tShift[e]=s-t.bMarks[e],t.sCount[e]=E,s>=_&&t.isEmpty(e+1)?t.line=Math.min(t.line+2,n):t.md.block.tokenize(t,e,n,!0),t.tight&&!R||(M=!1),R=t.line-e>1&&t.isEmpty(t.line-1),t.blkIndent=t.listIndent,t.listIndent=x,t.tShift[e]=C,t.sCount[e]=w,t.tight=A,(I=t.push("list_item_close","li",-1)).markup=String.fromCharCode(v),y=e=t.line,d[1]=y,s=t.bMarks[e],y>=n)break;if(t.sCount[y]=4)break;for(N=!1,c=0,h=L.length;c=4)return!1;if(91!==t.src.charCodeAt(k))return!1;for(;++k3||t.sCount[C]<0)){for(_=!1,f=0,p=y.length;f=4)return!1;if(35!==(i=t.src.charCodeAt(u))||u>=l)return!1;for(a=1,i=t.src.charCodeAt(++u);35===i&&u6||uu&&r(t.src.charCodeAt(s-1))&&(l=s),t.line=e+1,(c=t.push("heading_open","h"+String(a),1)).markup="########".slice(0,a),c.map=[e,t.line],(c=t.push("inline","",0)).content=t.src.slice(u,l).trim(),c.map=[e,t.line],c.children=[],(c=t.push("heading_close","h"+String(a),-1)).markup="########".slice(0,a),!0))}},function(t,e,n){"use strict";t.exports=function(t,e,n){var r,o,i,a,s,c,u,l,f,p,d=e+1,h=t.md.block.ruler.getRules("paragraph");if(t.sCount[e]-t.blkIndent>=4)return!1;for(p=t.parentType,t.parentType="paragraph";d3)){if(t.sCount[d]>=t.blkIndent&&(c=t.bMarks[d]+t.tShift[d])<(u=t.eMarks[d])&&(45===(f=t.src.charCodeAt(c))||61===f)&&(c=t.skipChars(c,f),(c=t.skipSpaces(c))>=u)){l=61===f?1:2;break}if(!(t.sCount[d]<0)){for(o=!1,i=0,a=h.length;i|$))/i,/<\/(script|pre|style)>/i,!0],[/^/,!0],[/^<\?/,/\?>/,!0],[/^/,!0],[/^/,!0],[new RegExp("^|$))","i"),/^$/,!0],[new RegExp(o.source+"\\s*$"),/^$/,!1]];t.exports=function(t,e,n,r){var o,a,s,c,u=t.bMarks[e]+t.tShift[e],l=t.eMarks[e];if(t.sCount[e]-t.blkIndent>=4)return!1;if(!t.md.options.html)return!1;if(60!==t.src.charCodeAt(u))return!1;for(c=t.src.slice(u,l),o=0;o3||t.sCount[c]<0)){for(r=!1,o=0,i=u.length;o0&&this.level++,this.tokens.push(o),o},i.prototype.isEmpty=function(t){return this.bMarks[t]+this.tShift[t]>=this.eMarks[t]},i.prototype.skipEmptyLines=function(t){for(var e=this.lineMax;te;)if(!o(this.src.charCodeAt(--t)))return t+1;return t},i.prototype.skipChars=function(t,e){for(var n=this.src.length;tn;)if(e!==this.src.charCodeAt(--t))return t+1;return t},i.prototype.getLines=function(t,e,n,r){var i,a,s,c,u,l,f,p=t;if(t>=e)return"";for(l=new Array(e-t),i=0;pn?new Array(a-n+1).join(" ")+this.src.slice(c,u):this.src.slice(c,u)}return l.join("")},i.prototype.Token=r,t.exports=i},function(t,e,n){"use strict";var r=n(37),o=[["text",n(138)],["newline",n(139)],["escape",n(140)],["backticks",n(141)],["strikethrough",n(61).tokenize],["emphasis",n(62).tokenize],["link",n(142)],["image",n(143)],["autolink",n(144)],["html_inline",n(145)],["entity",n(146)]],i=[["balance_pairs",n(147)],["strikethrough",n(61).postProcess],["emphasis",n(62).postProcess],["text_collapse",n(148)]];function a(){var t;for(this.ruler=new r,t=0;t=i)break}else t.pending+=t.src[t.pos++]}t.pending&&t.pushPending()},a.prototype.parse=function(t,e,n,r){var o,i,a,s=new this.State(t,e,n,r);for(this.tokenize(s),a=(i=this.ruler2.getRules("")).length,o=0;o=0&&32===t.pending.charCodeAt(n)?n>=1&&32===t.pending.charCodeAt(n-1)?(t.pending=t.pending.replace(/ +$/,""),t.push("hardbreak","br",0)):(t.pending=t.pending.slice(0,-1),t.push("softbreak","br",0)):t.push("softbreak","br",0)),i++;i?@[]^_`{|}~-".split("").forEach((function(t){o[t.charCodeAt(0)]=1})),t.exports=function(t,e){var n,i=t.pos,a=t.posMax;if(92!==t.src.charCodeAt(i))return!1;if(++i=g)return!1;for(m=u,(l=t.md.helpers.parseLinkDestination(t.src,u,t.posMax)).ok&&(d=t.md.normalizeLink(l.str),t.md.validateLink(d)?u=l.pos:d=""),m=u;u=g||41!==t.src.charCodeAt(u))&&(v=!0),u++}if(v){if(void 0===t.env.references)return!1;if(u=0?a=t.src.slice(m,u++):u=s+1):u=s+1,a||(a=t.src.slice(c,s)),!(f=t.env.references[r(a)]))return t.pos=h,!1;d=f.href,p=f.title}return e||(t.pos=c,t.posMax=s,t.push("link_open","a",1).attrs=n=[["href",d]],p&&n.push(["title",p]),t.md.inline.tokenize(t),t.push("link_close","a",-1)),t.pos=u,t.posMax=g,!0}},function(t,e,n){"use strict";var r=n(1).normalizeReference,o=n(1).isSpace;t.exports=function(t,e){var n,i,a,s,c,u,l,f,p,d,h,g,m,v="",b=t.pos,_=t.posMax;if(33!==t.src.charCodeAt(t.pos))return!1;if(91!==t.src.charCodeAt(t.pos+1))return!1;if(u=t.pos+2,(c=t.md.helpers.parseLinkLabel(t,t.pos+1,!1))<0)return!1;if((l=c+1)<_&&40===t.src.charCodeAt(l)){for(l++;l<_&&(i=t.src.charCodeAt(l),o(i)||10===i);l++);if(l>=_)return!1;for(m=l,(p=t.md.helpers.parseLinkDestination(t.src,l,t.posMax)).ok&&(v=t.md.normalizeLink(p.str),t.md.validateLink(v)?l=p.pos:v=""),m=l;l<_&&(i=t.src.charCodeAt(l),o(i)||10===i);l++);if(p=t.md.helpers.parseLinkTitle(t.src,l,t.posMax),l<_&&m!==l&&p.ok)for(d=p.str,l=p.pos;l<_&&(i=t.src.charCodeAt(l),o(i)||10===i);l++);else d="";if(l>=_||41!==t.src.charCodeAt(l))return t.pos=b,!1;l++}else{if(void 0===t.env.references)return!1;if(l<_&&91===t.src.charCodeAt(l)?(m=l+1,(l=t.md.helpers.parseLinkLabel(t,l))>=0?s=t.src.slice(m,l++):l=c+1):l=c+1,s||(s=t.src.slice(u,c)),!(f=t.env.references[r(s)]))return t.pos=b,!1;v=f.href,d=f.title}return e||(a=t.src.slice(u,c),t.md.inline.parse(a,t.md,t.env,g=[]),(h=t.push("image","img",0)).attrs=n=[["src",v],["alt",""]],h.children=g,h.content=a,d&&n.push(["title",d])),t.pos=l,t.posMax=_,!0}},function(t,e,n){"use strict";var r=/^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/,o=/^<([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)>/;t.exports=function(t,e){var n,i,a,s,c,u,l=t.pos;return 60===t.src.charCodeAt(l)&&(!((n=t.src.slice(l)).indexOf(">")<0)&&(o.test(n)?(s=(i=n.match(o))[0].slice(1,-1),c=t.md.normalizeLink(s),!!t.md.validateLink(c)&&(e||((u=t.push("link_open","a",1)).attrs=[["href",c]],u.markup="autolink",u.info="auto",(u=t.push("text","",0)).content=t.md.normalizeLinkText(s),(u=t.push("link_close","a",-1)).markup="autolink",u.info="auto"),t.pos+=i[0].length,!0)):!!r.test(n)&&(s=(a=n.match(r))[0].slice(1,-1),c=t.md.normalizeLink("mailto:"+s),!!t.md.validateLink(c)&&(e||((u=t.push("link_open","a",1)).attrs=[["href",c]],u.markup="autolink",u.info="auto",(u=t.push("text","",0)).content=t.md.normalizeLinkText(s),(u=t.push("link_close","a",-1)).markup="autolink",u.info="auto"),t.pos+=a[0].length,!0))))}},function(t,e,n){"use strict";var r=n(60).HTML_TAG_RE;t.exports=function(t,e){var n,o,i,a=t.pos;return!!t.md.options.html&&(i=t.posMax,!(60!==t.src.charCodeAt(a)||a+2>=i)&&(!(33!==(n=t.src.charCodeAt(a+1))&&63!==n&&47!==n&&!function(t){var e=32|t;return e>=97&&e<=122}(n))&&(!!(o=t.src.slice(a).match(r))&&(e||(t.push("html_inline","",0).content=t.src.slice(a,a+o[0].length)),t.pos+=o[0].length,!0))))}},function(t,e,n){"use strict";var r=n(55),o=n(1).has,i=n(1).isValidEntityCode,a=n(1).fromCodePoint,s=/^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i,c=/^&([a-z][a-z0-9]{1,31});/i;t.exports=function(t,e){var n,u,l=t.pos,f=t.posMax;if(38!==t.src.charCodeAt(l))return!1;if(l+1=0;){if((o=i[n]).open&&o.marker===r.marker&&o.end<0&&o.level===r.level){var s=!1;if((o.close||r.open)&&void 0!==o.length&&void 0!==r.length&&(o.length+r.length)%3==0&&(o.length%3==0&&r.length%3==0||(s=!0)),!s){r.jump=e-n,r.open=!1,o.end=e,o.jump=0;break}}n-=o.jump+1}}},function(t,e,n){"use strict";t.exports=function(t){var e,n,r=0,o=t.tokens,i=t.tokens.length;for(e=n=0;e0&&r++,"text"===o[e].type&&e+10&&this.level++,this.pendingLevel=this.level,this.tokens.push(o),o},s.prototype.scanDelims=function(t,e){var n,r,s,c,u,l,f,p,d,h=t,g=!0,m=!0,v=this.posMax,b=this.src.charCodeAt(t);for(n=t>0?this.src.charCodeAt(t-1):32;h=3&&":"===t[e-3]?0:e>=3&&"/"===t[e-3]?0:r.match(n.re.no_http)[0].length:0}},"mailto:":{validate:function(t,e,n){var r=t.slice(e);return n.re.mailto||(n.re.mailto=new RegExp("^"+n.re.src_email_name+"@"+n.re.src_host_strict,"i")),n.re.mailto.test(r)?r.match(n.re.mailto)[0].length:0}}},u="a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]",l="biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф".split("|");function f(t){var e=t.re=n(151)(t.__opts__),r=t.__tlds__.slice();function s(t){return t.replace("%TLDS%",e.src_tlds)}t.onCompile(),t.__tlds_replaced__||r.push(u),r.push(e.src_xn),e.src_tlds=r.join("|"),e.email_fuzzy=RegExp(s(e.tpl_email_fuzzy),"i"),e.link_fuzzy=RegExp(s(e.tpl_link_fuzzy),"i"),e.link_no_ip_fuzzy=RegExp(s(e.tpl_link_no_ip_fuzzy),"i"),e.host_fuzzy_test=RegExp(s(e.tpl_host_fuzzy_test),"i");var c=[];function l(t,e){throw new Error('(LinkifyIt) Invalid schema "'+t+'": '+e)}t.__compiled__={},Object.keys(t.__schemas__).forEach((function(e){var n=t.__schemas__[e];if(null!==n){var r={validate:null,link:null};if(t.__compiled__[e]=r,"[object Object]"===o(n))return!function(t){return"[object RegExp]"===o(t)}(n.validate)?i(n.validate)?r.validate=n.validate:l(e,n):r.validate=function(t){return function(e,n){var r=e.slice(n);return t.test(r)?r.match(t)[0].length:0}}(n.validate),void(i(n.normalize)?r.normalize=n.normalize:n.normalize?l(e,n):r.normalize=function(t,e){e.normalize(t)});!function(t){return"[object String]"===o(t)}(n)?l(e,n):c.push(e)}})),c.forEach((function(e){t.__compiled__[t.__schemas__[e]]&&(t.__compiled__[e].validate=t.__compiled__[t.__schemas__[e]].validate,t.__compiled__[e].normalize=t.__compiled__[t.__schemas__[e]].normalize)})),t.__compiled__[""]={validate:null,normalize:function(t,e){e.normalize(t)}};var f=Object.keys(t.__compiled__).filter((function(e){return e.length>0&&t.__compiled__[e]})).map(a).join("|");t.re.schema_test=RegExp("(^|(?!_)(?:[><|]|"+e.src_ZPCc+"))("+f+")","i"),t.re.schema_search=RegExp("(^|(?!_)(?:[><|]|"+e.src_ZPCc+"))("+f+")","ig"),t.re.pretest=RegExp("("+t.re.schema_test.source+")|("+t.re.host_fuzzy_test.source+")|@","i"),function(t){t.__index__=-1,t.__text_cache__=""}(t)}function p(t,e){var n=t.__index__,r=t.__last_index__,o=t.__text_cache__.slice(n,r);this.schema=t.__schema__.toLowerCase(),this.index=n+e,this.lastIndex=r+e,this.raw=o,this.text=o,this.url=o}function d(t,e){var n=new p(t,e);return t.__compiled__[n.schema].normalize(n,t),n}function h(t,e){if(!(this instanceof h))return new h(t,e);var n;e||(n=t,Object.keys(n||{}).reduce((function(t,e){return t||s.hasOwnProperty(e)}),!1)&&(e=t,t={})),this.__opts__=r({},s,e),this.__index__=-1,this.__last_index__=-1,this.__schema__="",this.__text_cache__="",this.__schemas__=r({},c,t),this.__compiled__={},this.__tlds__=l,this.__tlds_replaced__=!1,this.re={},f(this)}h.prototype.add=function(t,e){return this.__schemas__[t]=e,f(this),this},h.prototype.set=function(t){return this.__opts__=r(this.__opts__,t),this},h.prototype.test=function(t){if(this.__text_cache__=t,this.__index__=-1,!t.length)return!1;var e,n,r,o,i,a,s,c;if(this.re.schema_test.test(t))for((s=this.re.schema_search).lastIndex=0;null!==(e=s.exec(t));)if(o=this.testSchemaAt(t,e[2],s.lastIndex)){this.__schema__=e[2],this.__index__=e.index+e[1].length,this.__last_index__=e.index+e[0].length+o;break}return this.__opts__.fuzzyLink&&this.__compiled__["http:"]&&(c=t.search(this.re.host_fuzzy_test))>=0&&(this.__index__<0||c=0&&null!==(r=t.match(this.re.email_fuzzy))&&(i=r.index+r[1].length,a=r.index+r[0].length,(this.__index__<0||ithis.__last_index__)&&(this.__schema__="mailto:",this.__index__=i,this.__last_index__=a)),this.__index__>=0},h.prototype.pretest=function(t){return this.re.pretest.test(t)},h.prototype.testSchemaAt=function(t,e,n){return this.__compiled__[e.toLowerCase()]?this.__compiled__[e.toLowerCase()].validate(t,n,this):0},h.prototype.match=function(t){var e=0,n=[];this.__index__>=0&&this.__text_cache__===t&&(n.push(d(this,e)),e=this.__last_index__);for(var r=e?t.slice(e):t;this.test(r);)n.push(d(this,e)),r=r.slice(this.__last_index__),e+=this.__last_index__;return n.length?n:null},h.prototype.tlds=function(t,e){return t=Array.isArray(t)?t:[t],e?(this.__tlds__=this.__tlds__.concat(t).sort().filter((function(t,e,n){return t!==n[e-1]})).reverse(),f(this),this):(this.__tlds__=t.slice(),this.__tlds_replaced__=!0,f(this),this)},h.prototype.normalize=function(t){t.schema||(t.url="http://"+t.url),"mailto:"!==t.schema||/^mailto:/i.test(t.url)||(t.url="mailto:"+t.url)},h.prototype.onCompile=function(){},t.exports=h},function(t,e,n){"use strict";t.exports=function(t){var e={};e.src_Any=n(57).source,e.src_Cc=n(58).source,e.src_Z=n(59).source,e.src_P=n(36).source,e.src_ZPCc=[e.src_Z,e.src_P,e.src_Cc].join("|"),e.src_ZCc=[e.src_Z,e.src_Cc].join("|");return e.src_pseudo_letter="(?:(?![><|]|"+e.src_ZPCc+")"+e.src_Any+")",e.src_ip4="(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)",e.src_auth="(?:(?:(?!"+e.src_ZCc+"|[@/\\[\\]()]).)+@)?",e.src_port="(?::(?:6(?:[0-4]\\d{3}|5(?:[0-4]\\d{2}|5(?:[0-2]\\d|3[0-5])))|[1-5]?\\d{1,4}))?",e.src_host_terminator="(?=$|[><|]|"+e.src_ZPCc+")(?!-|_|:\\d|\\.-|\\.(?!$|"+e.src_ZPCc+"))",e.src_path="(?:[/?#](?:(?!"+e.src_ZCc+"|[><|]|[()[\\]{}.,\"'?!\\-]).|\\[(?:(?!"+e.src_ZCc+"|\\]).)*\\]|\\((?:(?!"+e.src_ZCc+"|[)]).)*\\)|\\{(?:(?!"+e.src_ZCc+'|[}]).)*\\}|\\"(?:(?!'+e.src_ZCc+'|["]).)+\\"|\\\'(?:(?!'+e.src_ZCc+"|[']).)+\\'|\\'(?="+e.src_pseudo_letter+"|[-]).|\\.{2,4}[a-zA-Z0-9%/]|\\.(?!"+e.src_ZCc+"|[.]).|"+(t&&t["---"]?"\\-(?!--(?:[^-]|$))(?:-*)|":"\\-+|")+"\\,(?!"+e.src_ZCc+").|\\!(?!"+e.src_ZCc+"|[!]).|\\?(?!"+e.src_ZCc+"|[?]).)+|\\/)?",e.src_email_name='[\\-;:&=\\+\\$,\\.a-zA-Z0-9_][\\-;:&=\\+\\$,\\"\\.a-zA-Z0-9_]*',e.src_xn="xn--[a-z0-9\\-]{1,59}",e.src_domain_root="(?:"+e.src_xn+"|"+e.src_pseudo_letter+"{1,63})",e.src_domain="(?:"+e.src_xn+"|(?:"+e.src_pseudo_letter+")|(?:"+e.src_pseudo_letter+"(?:-|"+e.src_pseudo_letter+"){0,61}"+e.src_pseudo_letter+"))",e.src_host="(?:(?:(?:(?:"+e.src_domain+")\\.)*"+e.src_domain+"))",e.tpl_host_fuzzy="(?:"+e.src_ip4+"|(?:(?:(?:"+e.src_domain+")\\.)+(?:%TLDS%)))",e.tpl_host_no_ip_fuzzy="(?:(?:(?:"+e.src_domain+")\\.)+(?:%TLDS%))",e.src_host_strict=e.src_host+e.src_host_terminator,e.tpl_host_fuzzy_strict=e.tpl_host_fuzzy+e.src_host_terminator,e.src_host_port_strict=e.src_host+e.src_port+e.src_host_terminator,e.tpl_host_port_fuzzy_strict=e.tpl_host_fuzzy+e.src_port+e.src_host_terminator,e.tpl_host_port_no_ip_fuzzy_strict=e.tpl_host_no_ip_fuzzy+e.src_port+e.src_host_terminator,e.tpl_host_fuzzy_test="localhost|www\\.|\\.\\d{1,3}\\.|(?:\\.(?:%TLDS%)(?:"+e.src_ZPCc+"|>|$))",e.tpl_email_fuzzy='(^|[><|]|"|\\(|'+e.src_ZCc+")("+e.src_email_name+"@"+e.tpl_host_fuzzy_strict+")",e.tpl_link_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`||]|"+e.src_ZPCc+"))((?![$+<=>^`||])"+e.tpl_host_port_fuzzy_strict+e.src_path+")",e.tpl_link_no_ip_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`||]|"+e.src_ZPCc+"))((?![$+<=>^`||])"+e.tpl_host_port_no_ip_fuzzy_strict+e.src_path+")",e}},function(t,e,n){"use strict";t.exports={options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"“”‘’",highlight:null,maxNesting:100},components:{core:{},block:{},inline:{}}}},function(t,e,n){"use strict";t.exports={options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"“”‘’",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline"]},block:{rules:["paragraph"]},inline:{rules:["text"],rules2:["balance_pairs","text_collapse"]}}}},function(t,e,n){"use strict";t.exports={options:{html:!0,xhtmlOut:!0,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"“”‘’",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline"]},block:{rules:["blockquote","code","fence","heading","hr","html_block","lheading","list","reference","paragraph"]},inline:{rules:["autolink","backticks","emphasis","entity","escape","html_inline","image","link","newline","text"],rules2:["balance_pairs","emphasis","text_collapse"]}}}},function(t,e){t.exports=function(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e=0&&(t._idleTimeoutId=setTimeout((function(){t._onTimeout&&t._onTimeout()}),e))},n(159),e.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==t&&t.setImmediate||this&&this.setImmediate,e.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==t&&t.clearImmediate||this&&this.clearImmediate}).call(this,n(11))},function(t,e,n){(function(t,e){!function(t,n){"use strict";if(!t.setImmediate){var r,o,i,a,s,c=1,u={},l=!1,f=t.document,p=Object.getPrototypeOf&&Object.getPrototypeOf(t);p=p&&p.setTimeout?p:t,"[object process]"==={}.toString.call(t.process)?r=function(t){e.nextTick((function(){h(t)}))}:!function(){if(t.postMessage&&!t.importScripts){var e=!0,n=t.onmessage;return t.onmessage=function(){e=!1},t.postMessage("","*"),t.onmessage=n,e}}()?t.MessageChannel?((i=new MessageChannel).port1.onmessage=function(t){h(t.data)},r=function(t){i.port2.postMessage(t)}):f&&"onreadystatechange"in f.createElement("script")?(o=f.documentElement,r=function(t){var e=f.createElement("script");e.onreadystatechange=function(){h(t),e.onreadystatechange=null,o.removeChild(e),e=null},o.appendChild(e)}):r=function(t){setTimeout(h,0,t)}:(a="setImmediate$"+Math.random()+"$",s=function(e){e.source===t&&"string"==typeof e.data&&0===e.data.indexOf(a)&&h(+e.data.slice(a.length))},t.addEventListener?t.addEventListener("message",s,!1):t.attachEvent("onmessage",s),r=function(e){t.postMessage(a+e,"*")}),p.setImmediate=function(t){"function"!=typeof t&&(t=new Function(""+t));for(var e=new Array(arguments.length-1),n=0;n1)for(var n=1;n1&&void 0!==arguments[1]&&arguments[1];if("string"!=typeof t||!t.trim())throw new Error("Invalid url.");return e&&("object"!==(void 0===e?"undefined":r(e))&&(e={stripFragment:!1}),t=i(t,e)),o(t)}},function(t,e,n){"use strict";var r=n(64),o=n(65),i=n(66);t.exports=function(t){t=(t||"").trim();var e={protocols:r(t),protocol:null,port:null,resource:"",user:"",pathname:"",hash:"",search:"",href:t,query:Object.create(null)},n=t.indexOf("://"),a=null,s=null;t.startsWith(".")&&(t.startsWith("./")&&(t=t.substring(2)),e.pathname=t,e.protocol="file");var c=t.charAt(1);return e.protocol||(e.protocol=e.protocols[0],e.protocol||(o(t)?e.protocol="ssh":"/"===c||"~"===c?(t=t.substring(2),e.protocol="file"):e.protocol="file")),-1!==n&&(t=t.substring(n+3)),s=t.split("/"),"file"!==e.protocol?e.resource=s.shift():e.resource="",2===(a=e.resource.split("@")).length&&(e.user=a[0],e.resource=a[1]),2===(a=e.resource.split(":")).length&&(e.resource=a[0],a[1]?(e.port=Number(a[1]),isNaN(e.port)&&(e.port=null,s.unshift(a[1]))):e.port=null),s=s.filter(Boolean),"file"===e.protocol?e.pathname=e.href:e.pathname=e.pathname||("file"!==e.protocol||"/"===e.href[0]?"/":"")+s.join("/"),2===(a=e.pathname.split("#")).length&&(e.pathname=a[0],e.hash=a[1]),2===(a=e.pathname.split("?")).length&&(e.pathname=a[0],e.search=a[1]),e.query=i.parse(e.search),e.href=e.href.replace(/\/$/,""),e.pathname=e.pathname.replace(/\/$/,""),e}},function(t,e,n){"use strict";function r(t,e){return Object.prototype.hasOwnProperty.call(t,e)}t.exports=function(t,e,n,i){e=e||"&",n=n||"=";var a={};if("string"!=typeof t||0===t.length)return a;var s=/\+/g;t=t.split(e);var c=1e3;i&&"number"==typeof i.maxKeys&&(c=i.maxKeys);var u=t.length;c>0&&u>c&&(u=c);for(var l=0;l=0?(f=g.substr(0,m),p=g.substr(m+1)):(f=g,p=""),d=decodeURIComponent(f),h=decodeURIComponent(p),r(a,d)?o(a[d])?a[d].push(h):a[d]=[a[d],h]:a[d]=h}return a};var o=Array.isArray||function(t){return"[object Array]"===Object.prototype.toString.call(t)}},function(t,e,n){"use strict";var r=function(t){switch(typeof t){case"string":return t;case"boolean":return t?"true":"false";case"number":return isFinite(t)?t:"";default:return""}};t.exports=function(t,e,n,s){return e=e||"&",n=n||"=",null===t&&(t=void 0),"object"==typeof t?i(a(t),(function(a){var s=encodeURIComponent(r(a))+n;return o(t[a])?i(t[a],(function(t){return s+encodeURIComponent(r(t))})).join(e):s+encodeURIComponent(r(t[a]))})).join(e):s?encodeURIComponent(r(s))+n+encodeURIComponent(r(t)):""};var o=Array.isArray||function(t){return"[object Array]"===Object.prototype.toString.call(t)};function i(t,e){if(t.map)return t.map(e);for(var n=[],r=0;re.some(e=>e instanceof RegExp?e.test(t):e===t);t.exports=(t,e)=>{e=Object.assign({defaultProtocol:"http:",normalizeProtocol:!0,forceHttp:!1,forceHttps:!1,stripHash:!0,stripWWW:!0,removeQueryParameters:[/^utm_\w+/i],removeTrailingSlash:!0,removeDirectoryIndex:!1,sortQueryParameters:!0},e),Reflect.has(e,"normalizeHttps")&&(e.forceHttp=e.normalizeHttps),Reflect.has(e,"normalizeHttp")&&(e.forceHttps=e.normalizeHttp),Reflect.has(e,"stripFragment")&&(e.stripHash=e.stripFragment);const n=(t=t.trim()).startsWith("//");!n&&/^\.*\//.test(t)||(t=t.replace(/^(?!(?:\w+:)?\/\/)|^\/\//,e.defaultProtocol));const i=new r(t);if(e.forceHttp&&e.forceHttps)throw new Error("The `forceHttp` and `forceHttps` options cannot be used together");if(e.forceHttp&&"https:"===i.protocol&&(i.protocol="http:"),e.forceHttps&&"http:"===i.protocol&&(i.protocol="https:"),e.stripHash&&(i.hash=""),i.pathname&&(i.pathname=i.pathname.replace(/((?![https?:]).)\/{2,}/g,(t,e)=>/^(?!\/)/g.test(e)?`${e}/`:"/")),i.pathname&&(i.pathname=decodeURI(i.pathname)),!0===e.removeDirectoryIndex&&(e.removeDirectoryIndex=[/^index\.[a-z]+$/]),Array.isArray(e.removeDirectoryIndex)&&e.removeDirectoryIndex.length>0){let t=i.pathname.split("/");const n=t[t.length-1];o(n,e.removeDirectoryIndex)&&(t=t.slice(0,t.length-1),i.pathname=t.slice(1).join("/")+"/")}if(i.hostname&&(i.hostname=i.hostname.replace(/\.$/,""),e.stripWWW&&/^www\.([a-z\-\d]{2,63})\.([a-z\.]{2,5})$/.test(i.hostname)&&(i.hostname=i.hostname.replace(/^www\./,""))),Array.isArray(e.removeQueryParameters))for(const t of[...i.searchParams.keys()])o(t,e.removeQueryParameters)&&i.searchParams.delete(t);return e.sortQueryParameters&&i.searchParams.sort(),t=i.toString(),(e.removeTrailingSlash||"/"===i.pathname)&&(t=t.replace(/\/$/,"")),n&&!e.normalizeProtocol&&(t=t.replace(/^http:\/\//,"//")),t}},function(t,e,n){"use strict";var r=n(63),o=n(171);function i(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}e.parse=_,e.resolve=function(t,e){return _(t,!1,!0).resolve(e)},e.resolveObject=function(t,e){return t?_(t,!1,!0).resolveObject(e):e},e.format=function(t){o.isString(t)&&(t=_(t));return t instanceof i?t.format():i.prototype.format.call(t)},e.Url=i;var a=/^([a-z0-9.+-]+:)/i,s=/:[0-9]*$/,c=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,u=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),l=["'"].concat(u),f=["%","/","?",";","#"].concat(l),p=["/","?","#"],d=/^[+a-z0-9A-Z_-]{0,63}$/,h=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,g={javascript:!0,"javascript:":!0},m={javascript:!0,"javascript:":!0},v={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},b=n(66);function _(t,e,n){if(t&&o.isObject(t)&&t instanceof i)return t;var r=new i;return r.parse(t,e,n),r}i.prototype.parse=function(t,e,n){if(!o.isString(t))throw new TypeError("Parameter 'url' must be a string, not "+typeof t);var i=t.indexOf("?"),s=-1!==i&&i127?I+="x":I+=L[D];if(!I.match(d)){var P=O.slice(0,T),j=O.slice(T+1),F=L.match(h);F&&(P.push(F[1]),j.unshift(F[2])),j.length&&(_="/"+j.join(".")+_),this.hostname=P.join(".");break}}}this.hostname.length>255?this.hostname="":this.hostname=this.hostname.toLowerCase(),R||(this.hostname=r.toASCII(this.hostname));var U=this.port?":"+this.port:"",$=this.hostname||"";this.host=$+U,this.href+=this.host,R&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==_[0]&&(_="/"+_))}if(!g[x])for(T=0,N=l.length;T0)&&n.host.split("@"))&&(n.auth=R.shift(),n.host=n.hostname=R.shift());return n.search=t.search,n.query=t.query,o.isNull(n.pathname)&&o.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.href=n.format(),n}if(!k.length)return n.pathname=null,n.search?n.path="/"+n.search:n.path=null,n.href=n.format(),n;for(var C=k.slice(-1)[0],A=(n.host||t.host||k.length>1)&&("."===C||".."===C)||""===C,T=0,S=k.length;S>=0;S--)"."===(C=k[S])?k.splice(S,1):".."===C?(k.splice(S,1),T++):T&&(k.splice(S,1),T--);if(!E&&!x)for(;T--;T)k.unshift("..");!E||""===k[0]||k[0]&&"/"===k[0].charAt(0)||k.unshift(""),A&&"/"!==k.join("/").substr(-1)&&k.push("");var R,O=""===k[0]||k[0]&&"/"===k[0].charAt(0);w&&(n.hostname=n.host=O?"":k.length?k.shift():"",(R=!!(n.host&&n.host.indexOf("@")>0)&&n.host.split("@"))&&(n.auth=R.shift(),n.host=n.hostname=R.shift()));return(E=E||n.host&&k.length)&&!O&&k.unshift(""),k.length?n.pathname=k.join("/"):(n.pathname=null,n.path=null),o.isNull(n.pathname)&&o.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.auth=t.auth||n.auth,n.slashes=n.slashes||t.slashes,n.href=n.format(),n},i.prototype.parseHost=function(){var t=this.host,e=s.exec(t);e&&(":"!==(e=e[0])&&(this.port=e.substr(1)),t=t.substr(0,t.length-e.length)),t&&(this.hostname=t)}},function(t,e,n){"use strict";t.exports={isString:function(t){return"string"==typeof t},isObject:function(t){return"object"==typeof t&&null!==t},isNull:function(t){return null===t},isNullOrUndefined:function(t){return null==t}}},function(t,e,n){var r=n(67),o=n(68),i=n(69),a=n(17);t.exports=function(t){return function(e){e=a(e);var n=o(e)?i(e):void 0,s=n?n[0]:e.charAt(0),c=n?r(n,1).join(""):e.slice(1);return s[t]()+c}}},function(t,e){t.exports=function(t,e,n){var r=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(n=n>o?o:n)<0&&(n+=o),o=e>n?0:n-e>>>0,e>>>=0;for(var i=Array(o);++r-1;);return n}},function(t,e){t.exports=function(t,e,n,r){for(var o=t.length,i=n+(r?1:-1);r?i--:++i0;){if("top-level"!==this.indentTypes.pop())break}},t}();e.default=a,t.exports=e.default},function(t,e,n){var r=n(188),o=n(189),i=n(190),a=n(17);t.exports=function(t,e,n){return e=(n?o(t,e,n):void 0===e)?1:i(e),r(a(t),e)}},function(t,e){var n=9007199254740991,r=Math.floor;t.exports=function(t,e){var o="";if(!t||e<1||e>n)return o;do{e%2&&(o+=t),(e=r(e/2))&&(t+=t)}while(e);return o}},function(t,e,n){var r=n(40),o=n(41),i=n(43),a=n(20);t.exports=function(t,e,n){if(!a(n))return!1;var s=typeof e;return!!("number"==s?o(n)&&i(e,n.length):"string"==s&&e in n)&&r(n[e],t)}},function(t,e,n){var r=n(191);t.exports=function(t){var e=r(t),n=e%1;return e==e?n?e-n:e:0}},function(t,e,n){var r=n(192),o=1/0,i=17976931348623157e292;t.exports=function(t){return t?(t=r(t))===o||t===-o?(t<0?-1:1)*i:t==t?t:0:0===t?t:0}},function(t,e,n){var r=n(193),o=n(20),i=n(24),a=NaN,s=/^[-+]0x[0-9a-f]+$/i,c=/^0b[01]+$/i,u=/^0o[0-7]+$/i,l=parseInt;t.exports=function(t){if("number"==typeof t)return t;if(i(t))return a;if(o(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=o(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=r(t);var n=c.test(t);return n||u.test(t)?l(t.slice(2),n?2:8):s.test(t)?a:+t}},function(t,e,n){var r=n(73),o=/^\s+/;t.exports=function(t){return t?t.slice(0,r(t)+1).replace(o,""):t}},function(t,e){t.exports=function(t){var e=null==t?0:t.length;return e?t[e-1]:void 0}},function(t,e,n){"use strict";e.__esModule=!0;var r,o=n(39),i=(r=o)&&r.__esModule?r:{default:r};var a=function(){function t(){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.level=0}return t.prototype.beginIfPossible=function(t,e){0===this.level&&this.isInlineBlock(t,e)?this.level=1:this.level>0?this.level++:this.level=0},t.prototype.end=function(){this.level--},t.prototype.isActive=function(){return this.level>0},t.prototype.isInlineBlock=function(t,e){for(var n=0,r=0,o=e;o50)return!1;if(a.type===i.default.OPEN_PAREN)r++;else if(a.type===i.default.CLOSE_PAREN&&0===--r)return!0;if(this.isForbiddenToken(a))return!1}return!1},t.prototype.isForbiddenToken=function(t){var e=t.type,n=t.value;return e===i.default.RESERVED_TOPLEVEL||e===i.default.RESERVED_NEWLINE||e===i.default.COMMENT||e===i.default.BLOCK_COMMENT||";"===n},t}();e.default=a,t.exports=e.default},function(t,e,n){"use strict";e.__esModule=!0;var r=function(){function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.params=e,this.index=0}return t.prototype.get=function(t){var e=t.key,n=t.value;return this.params?e?this.params[e]:this.params[this.index++]:n},t}();e.default=r,t.exports=e.default},function(t,e,n){var r=n(75),o=n(77),i=n(45),a=n(9),s=n(41),c=n(46),u=n(76),l=n(47),f="[object Map]",p="[object Set]",d=Object.prototype.hasOwnProperty;t.exports=function(t){if(null==t)return!0;if(s(t)&&(a(t)||"string"==typeof t||"function"==typeof t.splice||c(t)||l(t)||i(t)))return!t.length;var e=o(t);if(e==f||e==p)return!t.size;if(u(t))return!r(t).length;for(var n in t)if(d.call(t,n))return!1;return!0}},function(t,e,n){var r=n(199)(Object.keys,Object);t.exports=r},function(t,e){t.exports=function(t,e){return function(n){return t(e(n))}}},function(t,e,n){var r=n(12)(n(8),"DataView");t.exports=r},function(t,e,n){var r=n(74),o=n(202),i=n(20),a=n(78),s=/^\[object .+?Constructor\]$/,c=Function.prototype,u=Object.prototype,l=c.toString,f=u.hasOwnProperty,p=RegExp("^"+l.call(f).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");t.exports=function(t){return!(!i(t)||o(t))&&(r(t)?p:s).test(a(t))}},function(t,e,n){var r,o=n(203),i=(r=/[^.]+$/.exec(o&&o.keys&&o.keys.IE_PROTO||""))?"Symbol(src)_1."+r:"";t.exports=function(t){return!!i&&i in t}},function(t,e,n){var r=n(8)["__core-js_shared__"];t.exports=r},function(t,e){t.exports=function(t,e){return null==t?void 0:t[e]}},function(t,e,n){var r=n(12)(n(8),"Promise");t.exports=r},function(t,e,n){var r=n(12)(n(8),"WeakMap");t.exports=r},function(t,e,n){var r=n(18),o=n(19),i="[object Arguments]";t.exports=function(t){return o(t)&&r(t)==i}},function(t,e){t.exports=function(){return!1}},function(t,e,n){var r=n(18),o=n(42),i=n(19),a={};a["[object Float32Array]"]=a["[object Float64Array]"]=a["[object Int8Array]"]=a["[object Int16Array]"]=a["[object Int32Array]"]=a["[object Uint8Array]"]=a["[object Uint8ClampedArray]"]=a["[object Uint16Array]"]=a["[object Uint32Array]"]=!0,a["[object Arguments]"]=a["[object Array]"]=a["[object ArrayBuffer]"]=a["[object Boolean]"]=a["[object DataView]"]=a["[object Date]"]=a["[object Error]"]=a["[object Function]"]=a["[object Map]"]=a["[object Number]"]=a["[object Object]"]=a["[object RegExp]"]=a["[object Set]"]=a["[object String]"]=a["[object WeakMap]"]=!1,t.exports=function(t){return i(t)&&o(t.length)&&!!a[r(t)]}},function(t,e){t.exports=function(t){return function(e){return t(e)}}},function(t,e,n){(function(t){var r=n(71),o=e&&!e.nodeType&&e,i=o&&"object"==typeof t&&t&&!t.nodeType&&t,a=i&&i.exports===o&&r.process,s=function(){try{var t=i&&i.require&&i.require("util").types;return t||a&&a.binding&&a.binding("util")}catch(t){}}();t.exports=s}).call(this,n(22)(t))},function(t,e,n){var r=n(17),o=/[\\^$.*+?()[\]{}|]/g,i=RegExp(o.source);t.exports=function(t){return(t=r(t))&&i.test(t)?t.replace(o,"\\$&"):t}},function(t,e,n){"use strict";e.__esModule=!0;var r=i(n(25)),o=i(n(26));function i(t){return t&&t.__esModule?t:{default:t}}var a=["ALL","ALTER","ANALYZE","AND","ANY","ARRAY","AS","ASC","BEGIN","BETWEEN","BINARY","BOOLEAN","BREAK","BUCKET","BUILD","BY","CALL","CASE","CAST","CLUSTER","COLLATE","COLLECTION","COMMIT","CONNECT","CONTINUE","CORRELATE","COVER","CREATE","DATABASE","DATASET","DATASTORE","DECLARE","DECREMENT","DELETE","DERIVED","DESC","DESCRIBE","DISTINCT","DO","DROP","EACH","ELEMENT","ELSE","END","EVERY","EXCEPT","EXCLUDE","EXECUTE","EXISTS","EXPLAIN","FALSE","FETCH","FIRST","FLATTEN","FOR","FORCE","FROM","FUNCTION","GRANT","GROUP","GSI","HAVING","IF","IGNORE","ILIKE","IN","INCLUDE","INCREMENT","INDEX","INFER","INLINE","INNER","INSERT","INTERSECT","INTO","IS","JOIN","KEY","KEYS","KEYSPACE","KNOWN","LAST","LEFT","LET","LETTING","LIKE","LIMIT","LSM","MAP","MAPPING","MATCHED","MATERIALIZED","MERGE","MINUS","MISSING","NAMESPACE","NEST","NOT","NULL","NUMBER","OBJECT","OFFSET","ON","OPTION","OR","ORDER","OUTER","OVER","PARSE","PARTITION","PASSWORD","PATH","POOL","PREPARE","PRIMARY","PRIVATE","PRIVILEGE","PROCEDURE","PUBLIC","RAW","REALM","REDUCE","RENAME","RETURN","RETURNING","REVOKE","RIGHT","ROLE","ROLLBACK","SATISFIES","SCHEMA","SELECT","SELF","SEMI","SET","SHOW","SOME","START","STATISTICS","STRING","SYSTEM","THEN","TO","TRANSACTION","TRIGGER","TRUE","TRUNCATE","UNDER","UNION","UNIQUE","UNKNOWN","UNNEST","UNSET","UPDATE","UPSERT","USE","USER","USING","VALIDATE","VALUE","VALUED","VALUES","VIA","VIEW","WHEN","WHERE","WHILE","WITH","WITHIN","WORK","XOR"],s=["DELETE FROM","EXCEPT ALL","EXCEPT","EXPLAIN DELETE FROM","EXPLAIN UPDATE","EXPLAIN UPSERT","FROM","GROUP BY","HAVING","INFER","INSERT INTO","INTERSECT ALL","INTERSECT","LET","LIMIT","MERGE","NEST","ORDER BY","PREPARE","SELECT","SET CURRENT SCHEMA","SET SCHEMA","SET","UNION ALL","UNION","UNNEST","UPDATE","UPSERT","USE KEYS","VALUES","WHERE"],c=["AND","INNER JOIN","JOIN","LEFT JOIN","LEFT OUTER JOIN","OR","OUTER JOIN","RIGHT JOIN","RIGHT OUTER JOIN","XOR"],u=void 0,l=function(){function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.cfg=e}return t.prototype.format=function(t){return u||(u=new o.default({reservedWords:a,reservedToplevelWords:s,reservedNewlineWords:c,stringTypes:['""',"''","``"],openParens:["(","[","{"],closeParens:[")","]","}"],namedPlaceholderTypes:["$"],lineCommentTypes:["#","--"]})),new r.default(this.cfg,u).format(t)},t}();e.default=l,t.exports=e.default},function(t,e,n){"use strict";e.__esModule=!0;var r=i(n(25)),o=i(n(26));function i(t){return t&&t.__esModule?t:{default:t}}var a=["A","ACCESSIBLE","AGENT","AGGREGATE","ALL","ALTER","ANY","ARRAY","AS","ASC","AT","ATTRIBUTE","AUTHID","AVG","BETWEEN","BFILE_BASE","BINARY_INTEGER","BINARY","BLOB_BASE","BLOCK","BODY","BOOLEAN","BOTH","BOUND","BULK","BY","BYTE","C","CALL","CALLING","CASCADE","CASE","CHAR_BASE","CHAR","CHARACTER","CHARSET","CHARSETFORM","CHARSETID","CHECK","CLOB_BASE","CLONE","CLOSE","CLUSTER","CLUSTERS","COALESCE","COLAUTH","COLLECT","COLUMNS","COMMENT","COMMIT","COMMITTED","COMPILED","COMPRESS","CONNECT","CONSTANT","CONSTRUCTOR","CONTEXT","CONTINUE","CONVERT","COUNT","CRASH","CREATE","CREDENTIAL","CURRENT","CURRVAL","CURSOR","CUSTOMDATUM","DANGLING","DATA","DATE_BASE","DATE","DAY","DECIMAL","DEFAULT","DEFINE","DELETE","DESC","DETERMINISTIC","DIRECTORY","DISTINCT","DO","DOUBLE","DROP","DURATION","ELEMENT","ELSIF","EMPTY","ESCAPE","EXCEPTIONS","EXCLUSIVE","EXECUTE","EXISTS","EXIT","EXTENDS","EXTERNAL","EXTRACT","FALSE","FETCH","FINAL","FIRST","FIXED","FLOAT","FOR","FORALL","FORCE","FROM","FUNCTION","GENERAL","GOTO","GRANT","GROUP","HASH","HEAP","HIDDEN","HOUR","IDENTIFIED","IF","IMMEDIATE","IN","INCLUDING","INDEX","INDEXES","INDICATOR","INDICES","INFINITE","INSTANTIABLE","INT","INTEGER","INTERFACE","INTERVAL","INTO","INVALIDATE","IS","ISOLATION","JAVA","LANGUAGE","LARGE","LEADING","LENGTH","LEVEL","LIBRARY","LIKE","LIKE2","LIKE4","LIKEC","LIMITED","LOCAL","LOCK","LONG","MAP","MAX","MAXLEN","MEMBER","MERGE","MIN","MINUS","MINUTE","MLSLABEL","MOD","MODE","MONTH","MULTISET","NAME","NAN","NATIONAL","NATIVE","NATURAL","NATURALN","NCHAR","NEW","NEXTVAL","NOCOMPRESS","NOCOPY","NOT","NOWAIT","NULL","NULLIF","NUMBER_BASE","NUMBER","OBJECT","OCICOLL","OCIDATE","OCIDATETIME","OCIDURATION","OCIINTERVAL","OCILOBLOCATOR","OCINUMBER","OCIRAW","OCIREF","OCIREFCURSOR","OCIROWID","OCISTRING","OCITYPE","OF","OLD","ON","ONLY","OPAQUE","OPEN","OPERATOR","OPTION","ORACLE","ORADATA","ORDER","ORGANIZATION","ORLANY","ORLVARY","OTHERS","OUT","OVERLAPS","OVERRIDING","PACKAGE","PARALLEL_ENABLE","PARAMETER","PARAMETERS","PARENT","PARTITION","PASCAL","PCTFREE","PIPE","PIPELINED","PLS_INTEGER","PLUGGABLE","POSITIVE","POSITIVEN","PRAGMA","PRECISION","PRIOR","PRIVATE","PROCEDURE","PUBLIC","RAISE","RANGE","RAW","READ","REAL","RECORD","REF","REFERENCE","RELEASE","RELIES_ON","REM","REMAINDER","RENAME","RESOURCE","RESULT_CACHE","RESULT","RETURN","RETURNING","REVERSE","REVOKE","ROLLBACK","ROW","ROWID","ROWNUM","ROWTYPE","SAMPLE","SAVE","SAVEPOINT","SB1","SB2","SB4","SECOND","SEGMENT","SELF","SEPARATE","SEQUENCE","SERIALIZABLE","SHARE","SHORT","SIZE_T","SIZE","SMALLINT","SOME","SPACE","SPARSE","SQL","SQLCODE","SQLDATA","SQLERRM","SQLNAME","SQLSTATE","STANDARD","START","STATIC","STDDEV","STORED","STRING","STRUCT","STYLE","SUBMULTISET","SUBPARTITION","SUBSTITUTABLE","SUBTYPE","SUCCESSFUL","SUM","SYNONYM","SYSDATE","TABAUTH","TABLE","TDO","THE","THEN","TIME","TIMESTAMP","TIMEZONE_ABBR","TIMEZONE_HOUR","TIMEZONE_MINUTE","TIMEZONE_REGION","TO","TRAILING","TRANSACTION","TRANSACTIONAL","TRIGGER","TRUE","TRUSTED","TYPE","UB1","UB2","UB4","UID","UNDER","UNIQUE","UNPLUG","UNSIGNED","UNTRUSTED","USE","USER","USING","VALIDATE","VALIST","VALUE","VARCHAR","VARCHAR2","VARIABLE","VARIANCE","VARRAY","VARYING","VIEW","VIEWS","VOID","WHENEVER","WHILE","WITH","WORK","WRAPPED","WRITE","YEAR","ZONE"],s=["ADD","ALTER COLUMN","ALTER TABLE","BEGIN","CONNECT BY","DECLARE","DELETE FROM","DELETE","END","EXCEPT","EXCEPTION","FETCH FIRST","FROM","GROUP BY","HAVING","INSERT INTO","INSERT","INTERSECT","LIMIT","LOOP","MODIFY","ORDER BY","SELECT","SET CURRENT SCHEMA","SET SCHEMA","SET","START WITH","UNION ALL","UNION","UPDATE","VALUES","WHERE"],c=["AND","CROSS APPLY","CROSS JOIN","ELSE","END","INNER JOIN","JOIN","LEFT JOIN","LEFT OUTER JOIN","OR","OUTER APPLY","OUTER JOIN","RIGHT JOIN","RIGHT OUTER JOIN","WHEN","XOR"],u=void 0,l=function(){function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.cfg=e}return t.prototype.format=function(t){return u||(u=new o.default({reservedWords:a,reservedToplevelWords:s,reservedNewlineWords:c,stringTypes:['""',"N''","''","``"],openParens:["(","CASE"],closeParens:[")","END"],indexedPlaceholderTypes:["?"],namedPlaceholderTypes:[":"],lineCommentTypes:["--"],specialWordChars:["_","$","#",".","@"]})),new r.default(this.cfg,u).format(t)},t}();e.default=l,t.exports=e.default},function(t,e,n){"use strict";e.__esModule=!0;var r=i(n(25)),o=i(n(26));function i(t){return t&&t.__esModule?t:{default:t}}var a=["ACCESSIBLE","ACTION","AGAINST","AGGREGATE","ALGORITHM","ALL","ALTER","ANALYSE","ANALYZE","AS","ASC","AUTOCOMMIT","AUTO_INCREMENT","BACKUP","BEGIN","BETWEEN","BINLOG","BOTH","CASCADE","CASE","CHANGE","CHANGED","CHARACTER SET","CHARSET","CHECK","CHECKSUM","COLLATE","COLLATION","COLUMN","COLUMNS","COMMENT","COMMIT","COMMITTED","COMPRESSED","CONCURRENT","CONSTRAINT","CONTAINS","CONVERT","CREATE","CROSS","CURRENT_TIMESTAMP","DATABASE","DATABASES","DAY","DAY_HOUR","DAY_MINUTE","DAY_SECOND","DEFAULT","DEFINER","DELAYED","DELETE","DESC","DESCRIBE","DETERMINISTIC","DISTINCT","DISTINCTROW","DIV","DO","DROP","DUMPFILE","DUPLICATE","DYNAMIC","ELSE","ENCLOSED","END","ENGINE","ENGINES","ENGINE_TYPE","ESCAPE","ESCAPED","EVENTS","EXEC","EXECUTE","EXISTS","EXPLAIN","EXTENDED","FAST","FETCH","FIELDS","FILE","FIRST","FIXED","FLUSH","FOR","FORCE","FOREIGN","FULL","FULLTEXT","FUNCTION","GLOBAL","GRANT","GRANTS","GROUP_CONCAT","HEAP","HIGH_PRIORITY","HOSTS","HOUR","HOUR_MINUTE","HOUR_SECOND","IDENTIFIED","IF","IFNULL","IGNORE","IN","INDEX","INDEXES","INFILE","INSERT","INSERT_ID","INSERT_METHOD","INTERVAL","INTO","INVOKER","IS","ISOLATION","KEY","KEYS","KILL","LAST_INSERT_ID","LEADING","LEVEL","LIKE","LINEAR","LINES","LOAD","LOCAL","LOCK","LOCKS","LOGS","LOW_PRIORITY","MARIA","MASTER","MASTER_CONNECT_RETRY","MASTER_HOST","MASTER_LOG_FILE","MATCH","MAX_CONNECTIONS_PER_HOUR","MAX_QUERIES_PER_HOUR","MAX_ROWS","MAX_UPDATES_PER_HOUR","MAX_USER_CONNECTIONS","MEDIUM","MERGE","MINUTE","MINUTE_SECOND","MIN_ROWS","MODE","MODIFY","MONTH","MRG_MYISAM","MYISAM","NAMES","NATURAL","NOT","NOW()","NULL","OFFSET","ON DELETE","ON UPDATE","ON","ONLY","OPEN","OPTIMIZE","OPTION","OPTIONALLY","OUTFILE","PACK_KEYS","PAGE","PARTIAL","PARTITION","PARTITIONS","PASSWORD","PRIMARY","PRIVILEGES","PROCEDURE","PROCESS","PROCESSLIST","PURGE","QUICK","RAID0","RAID_CHUNKS","RAID_CHUNKSIZE","RAID_TYPE","RANGE","READ","READ_ONLY","READ_WRITE","REFERENCES","REGEXP","RELOAD","RENAME","REPAIR","REPEATABLE","REPLACE","REPLICATION","RESET","RESTORE","RESTRICT","RETURN","RETURNS","REVOKE","RLIKE","ROLLBACK","ROW","ROWS","ROW_FORMAT","SECOND","SECURITY","SEPARATOR","SERIALIZABLE","SESSION","SHARE","SHOW","SHUTDOWN","SLAVE","SONAME","SOUNDS","SQL","SQL_AUTO_IS_NULL","SQL_BIG_RESULT","SQL_BIG_SELECTS","SQL_BIG_TABLES","SQL_BUFFER_RESULT","SQL_CACHE","SQL_CALC_FOUND_ROWS","SQL_LOG_BIN","SQL_LOG_OFF","SQL_LOG_UPDATE","SQL_LOW_PRIORITY_UPDATES","SQL_MAX_JOIN_SIZE","SQL_NO_CACHE","SQL_QUOTE_SHOW_CREATE","SQL_SAFE_UPDATES","SQL_SELECT_LIMIT","SQL_SLAVE_SKIP_COUNTER","SQL_SMALL_RESULT","SQL_WARNINGS","START","STARTING","STATUS","STOP","STORAGE","STRAIGHT_JOIN","STRING","STRIPED","SUPER","TABLE","TABLES","TEMPORARY","TERMINATED","THEN","TO","TRAILING","TRANSACTIONAL","TRUE","TRUNCATE","TYPE","TYPES","UNCOMMITTED","UNIQUE","UNLOCK","UNSIGNED","USAGE","USE","USING","VARIABLES","VIEW","WHEN","WITH","WORK","WRITE","YEAR_MONTH"],s=["ADD","AFTER","ALTER COLUMN","ALTER TABLE","DELETE FROM","EXCEPT","FETCH FIRST","FROM","GROUP BY","GO","HAVING","INSERT INTO","INSERT","INTERSECT","LIMIT","MODIFY","ORDER BY","SELECT","SET CURRENT SCHEMA","SET SCHEMA","SET","UNION ALL","UNION","UPDATE","VALUES","WHERE"],c=["AND","CROSS APPLY","CROSS JOIN","ELSE","INNER JOIN","JOIN","LEFT JOIN","LEFT OUTER JOIN","OR","OUTER APPLY","OUTER JOIN","RIGHT JOIN","RIGHT OUTER JOIN","WHEN","XOR"],u=void 0,l=function(){function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.cfg=e}return t.prototype.format=function(t){return u||(u=new o.default({reservedWords:a,reservedToplevelWords:s,reservedNewlineWords:c,stringTypes:['""',"N''","''","``","[]"],openParens:["(","CASE"],closeParens:[")","END"],indexedPlaceholderTypes:["?"],namedPlaceholderTypes:["@",":"],lineCommentTypes:["#","--"]})),new r.default(this.cfg,u).format(t)},t}();e.default=l,t.exports=e.default},function(t,e){t.exports=function(t){const e={className:"variable",begin:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*(?![A-Za-z0-9])(?![$])"},n={className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},r={className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]},o=t.inherit(t.APOS_STRING_MODE,{illegal:null}),i=t.inherit(t.QUOTE_STRING_MODE,{illegal:null,contains:t.QUOTE_STRING_MODE.contains.concat(r)}),a=t.END_SAME_AS_BEGIN({begin:/<<<[ \t]*(\w+)\n/,end:/[ \t]*(\w+)\b/,contains:t.QUOTE_STRING_MODE.contains.concat(r)}),s={className:"string",contains:[t.BACKSLASH_ESCAPE,n],variants:[t.inherit(o,{begin:"b'",end:"'"}),t.inherit(i,{begin:'b"',end:'"'}),i,o,a]},c={variants:[t.BINARY_NUMBER_MODE,t.C_NUMBER_MODE]},u={keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list match|0 new object or private protected public real return string switch throw trait try unset use var void while xor yield",literal:"false null true",built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Throwable Traversable WeakReference Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"};return{aliases:["php","php3","php4","php5","php6","php7","php8"],case_insensitive:!0,keywords:u,contains:[t.HASH_COMMENT_MODE,t.COMMENT("//","$",{contains:[n]}),t.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),t.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,keywords:"__halt_compiler"}),n,{className:"keyword",begin:/\$this\b/},e,{begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[t.UNDERSCORE_TITLE_MODE,{begin:"=>"},{className:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:u,contains:["self",e,t.C_BLOCK_COMMENT_MODE,s,c]}]},{className:"class",beginKeywords:"class interface",relevance:0,end:/\{/,excludeEnd:!0,illegal:/[:($"]/,contains:[{beginKeywords:"extends implements"},t.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/,contains:[t.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",relevance:0,end:";",contains:[t.UNDERSCORE_TITLE_MODE]},s,c]}}},function(t,e,n){var r=n(80),o=n(237),i=n(238),a=n(81),s=n(239),c=n(49),u=200;t.exports=function(t,e,n){var l=-1,f=o,p=t.length,d=!0,h=[],g=h;if(n)d=!1,f=i;else if(p>=u){var m=e?null:s(t);if(m)return c(m);d=!1,f=a,g=new r}else g=e?[]:h;t:for(;++l-1}},function(t,e,n){var r=n(29);t.exports=function(t,e){var n=this.__data__,o=r(n,t);return o<0?(++this.size,n.push([t,e])):n[o][1]=e,this}},function(t,e,n){var r=n(30);t.exports=function(t){var e=r(this,t).delete(t);return this.size-=e?1:0,e}},function(t,e){t.exports=function(t){var e=typeof t;return"string"==e||"number"==e||"symbol"==e||"boolean"==e?"__proto__"!==t:null===t}},function(t,e,n){var r=n(30);t.exports=function(t){return r(this,t).get(t)}},function(t,e,n){var r=n(30);t.exports=function(t){return r(this,t).has(t)}},function(t,e,n){var r=n(30);t.exports=function(t,e){var n=r(this,t),o=n.size;return n.set(t,e),this.size+=n.size==o?0:1,this}},function(t,e){var n="__lodash_hash_undefined__";t.exports=function(t){return this.__data__.set(t,n),this}},function(t,e){t.exports=function(t){return this.__data__.has(t)}},function(t,e,n){var r=n(72);t.exports=function(t,e){return!!(null==t?0:t.length)&&r(t,e,0)>-1}},function(t,e){t.exports=function(t,e,n){for(var r=-1,o=null==t?0:t.length;++r>>32-e},rotr:function(t,e){return t<<32-e|t>>>e},endian:function(t){if(t.constructor==Number)return 16711935&r.rotl(t,8)|4278255360&r.rotl(t,24);for(var e=0;e0;t--)e.push(Math.floor(256*Math.random()));return e},bytesToWords:function(t){for(var e=[],n=0,r=0;n>>5]|=t[n]<<24-r%32;return e},wordsToBytes:function(t){for(var e=[],n=0;n<32*t.length;n+=8)e.push(t[n>>>5]>>>24-n%32&255);return e},bytesToHex:function(t){for(var e=[],n=0;n>>4).toString(16)),e.push((15&t[n]).toString(16));return e.join("")},hexToBytes:function(t){for(var e=[],n=0;n>>6*(3-i)&63)):e.push("=");return e.join("")},base64ToBytes:function(t){t=t.replace(/[^A-Z0-9+\/]/gi,"");for(var e=[],r=0,o=0;r>>6-2*o);return e}},t.exports=r},function(t,e){function n(t){return!!t.constructor&&"function"==typeof t.constructor.isBuffer&&t.constructor.isBuffer(t)} +/*! + * Determine if an object is a Buffer + * + * @author Feross Aboukhadijeh + * @license MIT + */ +t.exports=function(t){return null!=t&&(n(t)||function(t){return"function"==typeof t.readFloatLE&&"function"==typeof t.slice&&n(t.slice(0,0))}(t)||!!t._isBuffer)}},function(t,e,n){"use strict";n.r(e);n(94);var r,o,i,a=n(6),s=n.n(a),c=n(32),u=n.n(c),l=n(33),f=n.n(l),p=n(7),d=n(0),h=Object(d.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("svg",{staticStyle:{display:"none"},attrs:{xmlns:"http://www.w3.org/2000/svg"}},[e("symbol",{attrs:{id:"arrow-down-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 448 512"}},[e("path",{attrs:{d:"M413.1 222.5l22.2 22.2c9.4 9.4 9.4 24.6 0 33.9L241 473c-9.4 9.4-24.6 9.4-33.9 0L12.7 278.6c-9.4-9.4-9.4-24.6 0-33.9l22.2-22.2c9.5-9.5 25-9.3 34.3.4L184 343.4V56c0-13.3 10.7-24 24-24h32c13.3 0 24 10.7 24 24v287.4l114.8-120.5c9.3-9.8 24.8-10 34.3-.4z"}})]),this._v(" "),e("symbol",{attrs:{id:"arrow-up-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 448 512"}},[e("path",{attrs:{d:"M34.9 289.5l-22.2-22.2c-9.4-9.4-9.4-24.6 0-33.9L207 39c9.4-9.4 24.6-9.4 33.9 0l194.3 194.3c9.4 9.4 9.4 24.6 0 33.9L413 289.4c-9.5 9.5-25 9.3-34.3-.4L264 168.6V456c0 13.3-10.7 24-24 24h-32c-13.3 0-24-10.7-24-24V168.6L69.2 289.1c-9.3 9.8-24.8 10-34.3.4z"}})]),this._v(" "),e("symbol",{attrs:{id:"clipboard-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 384 512"}},[e("path",{attrs:{d:"M336 64h-80c0-35.3-28.7-64-64-64s-64 28.7-64 64H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM192 40c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm144 418c0 3.3-2.7 6-6 6H54c-3.3 0-6-2.7-6-6V118c0-3.3 2.7-6 6-6h42v36c0 6.6 5.4 12 12 12h168c6.6 0 12-5.4 12-12v-36h42c3.3 0 6 2.7 6 6z"}})]),this._v(" "),e("symbol",{attrs:{id:"lightbulb-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 352 512"}},[e("path",{attrs:{d:"M176 80c-52.94 0-96 43.06-96 96 0 8.84 7.16 16 16 16s16-7.16 16-16c0-35.3 28.72-64 64-64 8.84 0 16-7.16 16-16s-7.16-16-16-16zM96.06 459.17c0 3.15.93 6.22 2.68 8.84l24.51 36.84c2.97 4.46 7.97 7.14 13.32 7.14h78.85c5.36 0 10.36-2.68 13.32-7.14l24.51-36.84c1.74-2.62 2.67-5.7 2.68-8.84l.05-43.18H96.02l.04 43.18zM176 0C73.72 0 0 82.97 0 176c0 44.37 16.45 84.85 43.56 115.78 16.64 18.99 42.74 58.8 52.42 92.16v.06h48v-.12c-.01-4.77-.72-9.51-2.15-14.07-5.59-17.81-22.82-64.77-62.17-109.67-20.54-23.43-31.52-53.15-31.61-84.14-.2-73.64 59.67-128 127.95-128 70.58 0 128 57.42 128 128 0 30.97-11.24 60.85-31.65 84.14-39.11 44.61-56.42 91.47-62.1 109.46a47.507 47.507 0 0 0-2.22 14.3v.1h48v-.05c9.68-33.37 35.78-73.18 52.42-92.16C335.55 260.85 352 220.37 352 176 352 78.8 273.2 0 176 0z"}})]),this._v(" "),e("symbol",{attrs:{id:"pencil-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 512 512"}},[e("path",{attrs:{d:"M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"}})]),this._v(" "),e("symbol",{attrs:{id:"plus-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 512 512"}},[e("path",{attrs:{d:"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm144 276c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92h-92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z"}})]),this._v(" "),e("symbol",{attrs:{id:"share-icon",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 512 512"}},[e("path",{attrs:{d:"M503.691 189.836L327.687 37.851C312.281 24.546 288 35.347 288 56.015v80.053C127.371 137.907 0 170.1 0 322.326c0 61.441 39.581 122.309 83.333 154.132 13.653 9.931 33.111-2.533 28.077-18.631C66.066 312.814 132.917 274.316 288 272.085V360c0 20.7 24.3 31.453 39.687 18.164l176.004-152c11.071-9.562 11.086-26.753 0-36.328z"}})])])}),[],!1,null,null,null).exports,g=n(5),m={inject:["config"],props:["text"]},v=Object(d.a)(m,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"mt-12 card card-has-header card-no-props"},[e("div",{staticClass:"card-details card-danger"},[e("div",{staticClass:"card-details-overflow scrollbar p-4"},[e("div",{staticClass:"text-xl"},[this._t("default")],2)])])])}),[],!1,null,null,null).exports,b=n(14),_={props:{name:{required:!0}},data:function(){return{fullException:!1}},methods:{removeClamp:function(){this.fullException||(this.fullException=!0)}}},y=Object(d.a)(_,(function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"ui-exception-message",class:this.fullException?"ui-exception-message-full":"",on:{mousedown:this.removeClamp}},[this._v("\n "+this._s(this.name)+"\n")])}),[],!1,null,null,null).exports,E={components:{ExceptionClass:n(15).a,ExceptionMessage:y,LineNumber:b.a,FilePath:g.a},inject:["report"],computed:{firstFrame:function(){return this.report.stacktrace[0]}}},x={inject:["report","telescopeUrl","config"],components:{OccurrenceDetails:Object(d.a)(E,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"card-details-overflow scrollbar p-12 pt-10"},[n("div",{staticClass:"text-2xl"},[n("ExceptionClass",{attrs:{name:t.report.exception_class}}),t._v(" "),n("ExceptionMessage",{attrs:{name:t.report.message}})],1),t._v(" "),n("div",[n("a",{staticClass:"ui-url",attrs:{href:t.report.context.request.url,target:"_blank"}},[t._v("\n "+t._s(t.report.context.request.url)+"\n ")])])])}),[],!1,null,null,null).exports,FilePath:g.a}},k=Object(d.a)(x,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"mt-12 card card-has-header card-no-props"},[n("div",{staticClass:"card-header"},[n("div",{staticClass:"grid items-center rounded-t border-b border-tint-300 text-xs text-tint-600 ",staticStyle:{"grid-template-columns":"1fr 1fr"}},[n("div",{staticClass:"grid cols-auto justify-start gap-2 px-4 py-2"},[n("div",{staticClass:"flex items-center"},[n("a",{attrs:{href:"http://flareapp.io/docs/ignition-for-laravel/introduction",target:"_blank",title:"Ignition docs"}},[n("svg",{staticClass:"w-4 h-5 mr-4",attrs:{viewBox:"0 0 428 988"}},[n("polygon",{staticStyle:{fill:"#FA4E79"},attrs:{points:"428,247.1 428,494.1 214,617.5 214,369.3 \t\t"}}),t._v(" "),n("polygon",{staticStyle:{fill:"#FFF082"},attrs:{points:"0,988 0,741 214,617.5 214,864.1 \t\t"}}),t._v(" "),n("polygon",{staticStyle:{fill:"#E6003A"},attrs:{points:"214,123.9 214,617.5 0,494.1 0,0 \t\t"}}),t._v(" "),n("polygon",{staticStyle:{fill:"#FFE100"},attrs:{points:"214,864.1 214,617.5 428,741 428,988 \t\t"}})])]),t._v(" "),n("FilePath",{attrs:{pathClass:"font-normal",file:t.report.application_path+t.config.directorySeparator,relative:!1}})],1)]),t._v(" "),n("div",{staticClass:"grid cols-auto items-center justify-end gap-4 px-4 py-2"},[t.telescopeUrl?n("div",[n("a",{staticClass:"link-dimmed sm:ml-6",attrs:{href:t.telescopeUrl,target:"_blank"}},[t._v("Telescope")])]):t._e()])])]),t._v(" "),n("div"),t._v(" "),n("div",{staticClass:"card-details"},[n("OccurrenceDetails")],1)])}),[],!1,null,null,null).exports,w=n(10),C=n.n(w),A=n(21),T=n.n(A),S=n(101)(),R=null,O={inject:["config"],props:{solution:{required:!0}},data:function(){return{isHidingSolutions:this.hasHideSolutionsCookie(),canExecuteSolutions:null,runningSolution:!1,executionSuccessful:null}},computed:{healthCheckEndpoint:function(){return this.solution.execute_endpoint.replace("execute-solution","health-check")}},created:function(){this.configureRunnableSolutions()},mounted:function(){this.isHidingSolutions&&this.$refs.solutionCard.classList.add("solution-hidden")},methods:{configureRunnableSolutions:function(){this.config.enableRunnableSolutions?this.checkExecutionEndpoint():this.canExecuteSolutions=!1},markdown:function(t){return S.render(t)},checkExecutionEndpoint:(o=T()(C.a.mark((function t(){var e;return C.a.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.prev=0,t.next=3,fetch(this.healthCheckEndpoint);case 3:return t.next=5,t.sent.json();case 5:e=t.sent,this.canExecuteSolutions=e.can_execute_commands,t.next=12;break;case 9:t.prev=9,t.t0=t.catch(0),this.canExecuteSolutions=!1;case 12:case"end":return t.stop()}}),t,this,[[0,9]])}))),function(){return o.apply(this,arguments)}),execute:(r=T()(C.a.mark((function t(){var e;return C.a.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(!this.runningSolution){t.next=2;break}return t.abrupt("return");case 2:return t.prev=2,this.runningSolution=!0,t.next=6,fetch(this.solution.execute_endpoint,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({solution:this.solution.class,parameters:this.solution.run_parameters})});case 6:e=t.sent,this.executionSuccessful=200===e.status,t.next=14;break;case 10:t.prev=10,t.t0=t.catch(2),console.error(t.t0),this.executionSuccessful=!1;case 14:return t.prev=14,this.runningSolution=!1,t.finish(14);case 17:case"end":return t.stop()}}),t,this,[[2,10,14,17]])}))),function(){return r.apply(this,arguments)}),refresh:function(){location.reload()},getUrlLabel:function(t){var e=document.createElement("a");return e.href=t,e.hostname},toggleSolutions:function(){var t=this;this.isHidingSolutions?(window.clearTimeout(R),this.toggleHidingSolutions()):(this.$refs.solutionCard.classList.add("solution-hiding"),R=window.setTimeout((function(){t.$refs.solutionCard.classList.remove("solution-hiding"),t.toggleHidingSolutions()}),100))},toggleHidingSolutions:function(){if(this.isHidingSolutions)return document.cookie="".concat("hide_solutions","=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;"),void(this.isHidingSolutions=!1);var t=new Date;t.setTime(t.getTime()+31536e6),document.cookie="".concat("hide_solutions","=true;expires=").concat(t.toUTCString(),";path=/;"),this.isHidingSolutions=!0},hasHideSolutionsCookie:function(){return document.cookie.includes("hide_solutions")}}},N={components:{DangerCard:v,SolutionCard:Object(d.a)(O,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",[n("div",{staticClass:"solution-toggle",class:{"solution-toggle-show":t.isHidingSolutions},on:{click:t.toggleSolutions}},[t.isHidingSolutions?n("a",{staticClass:"link-solution",attrs:{target:"_blank"}},[n("Icon",{staticClass:"text-xs mr-1",attrs:{name:"lightbulb"}}),t._v(" Show solutions")],1):n("a",{staticClass:"link-solution",attrs:{target:"_blank"}},[t._v("Hide solutions")])]),t._v(" "),n("div",{ref:"solutionCard",staticClass:"solution",class:{"solution-hidden":t.isHidingSolutions}},[n("div",{staticClass:"solution-main"},[n("div",{staticClass:"solution-background mx-0"},[n("svg",{staticClass:"hidden absolute right-0 h-full | md:block",attrs:{x:"0px",y:"0px",viewBox:"0 0 299 452"}},[n("g",{staticStyle:{opacity:"0.075"}},[n("polygon",{staticStyle:{fill:"rgb(63,63,63)"},attrs:{points:"298.1,451.9 150.9,451.9 21,226.9 298.1,227.1"}}),t._v(" "),n("polygon",{staticStyle:{fill:"rgb(151,151,151)"},attrs:{points:"298.1,227.1 21,226.9 150.9,1.9 298.1,1.9"}})])])]),t._v(" "),n("div",{staticClass:"solution-content-wrapper scrollbar"},[n("div",{staticClass:"solution-content ml-0"},[""!==t.solution.title?n("h2",{staticClass:"solution-title"},[t._v("\n "+t._s(t.solution.title)+"\n ")]):t._e(),t._v(" "),t.solution.description?n("div",{domProps:{innerHTML:t._s(t.markdown(t.solution.description))}}):t._e(),t._v(" "),t.solution.is_runnable?n("div",[n("p",{domProps:{innerHTML:t._s(t.markdown(t.solution.action_description))}}),t._v(" "),null===t.canExecuteSolutions?n("p",{staticClass:"py-4 text-sm italic"},[t._v("\n Loading...\n ")]):t._e(),t._v(" "),n("div",{staticClass:"mt-4"},[t.solution.is_runnable&&!0===t.canExecuteSolutions&&null===t.executionSuccessful?n("button",{staticClass:"button-secondary button-lg bg-tint-300 hover:bg-tint-400",attrs:{disabled:t.runningSolution},on:{click:t.execute}},[t.runningSolution?n("span",[t._v("Running...")]):t._e(),t._v(" "),t.runningSolution?t._e():n("span",[t._v(t._s(t.solution.run_button_text))])]):t._e(),t._v(" "),t.executionSuccessful?n("p",[n("strong",{staticClass:"font-semibold"},[t._v("The solution was executed successfully.")]),t._v(" "),n("a",{staticClass:"link-solution",attrs:{href:"#"},on:{click:function(e){return e.preventDefault(),t.refresh(e)}}},[t._v("Refresh now.")])]):t._e(),t._v(" "),!1===t.executionSuccessful?n("p",[t._v("\n Something went wrong when executing the solution. Please try\n refreshing the page and try again.\n ")]):t._e()])]):t._e(),t._v(" "),Object.entries(t.solution.links).length>0?n("div",{staticClass:"mt-8 grid justify-start"},[n("div",{staticClass:"border-t-2 border-gray-700 opacity-25 "}),t._v(" "),n("div",{staticClass:"pt-2 grid cols-auto-1fr gapx-4 gapy-2 text-sm"},[n("label",{staticClass:"font-semibold uppercase tracking-wider"},[t._v("Read more")]),t._v(" "),n("ul",t._l(t.solution.links,(function(e,r){return n("li",{key:r},[n("a",{staticClass:"link-solution",attrs:{href:e,target:"_blank"}},[t._v(t._s(r))])])})),0)])]):t._e()])])])])])}),[],!1,null,null,null).exports,ErrorCard:k,FilePath:g.a},inject:["report","solutions","appEnv","appDebug"],data:function(){return{activeSolutionKey:0}},computed:{firstFrame:function(){return this.report.stacktrace[0]},solution:function(){return this.solutions[this.activeSolutionKey]}}},L=Object(d.a)(N,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",[n("div",{staticClass:"layout-col z-10"},["local"!==this.appEnv&&!0===this.appDebug?n("DangerCard",[n("p",[n("code",[t._v("APP_DEBUG")]),t._v(" is set to "),n("code",[t._v("true")]),t._v(" while "),n("code",[t._v("APP_ENV")]),t._v(" is\n not "),n("code",[t._v("local")])]),t._v(" "),n("p",{staticClass:"text-base"},[t._v("\n This could make your application vulnerable to remote execution.\n "),n("a",{staticClass:"underline",attrs:{target:"_blank",rel:"noopener",href:"https://flareapp.io/docs/ignition-for-laravel/security"}},[t._v("Read more about Ignition security.")])])]):t._e(),t._v(" "),n("ErrorCard")],1),t._v(" "),t.solutions.length>0?n("div",{staticClass:"layout-col z-1"},[n("SolutionCard",t._b({},"SolutionCard",{solution:t.solution},!1)),t._v(" "),t.solutions.length>1?n("div",{staticClass:"absolute left-0 bottom-0 w-full h-8 mb-2 px-4 text-sm z-10"},[n("ul",{staticClass:"grid cols-auto place-center gap-1"},t._l(t.solutions,(function(e,r){return n("li",{key:e.class,on:{click:function(e){t.activeSolutionKey=r}}},[n("a",{staticClass:"grid place-center h-8 min-w-8 px-2 rounded-full",class:{"bg-tint-200 font-semibold":t.activeSolutionKey===r,"hover:bg-tint-100 cursor-pointer":t.activeSolutionKey!==r}},[t._v("\n "+t._s(r+1)+"\n ")])])})),0)]):t._e()],1):t._e()])}),[],!1,null,null,null).exports,I=n(4),D=n.n(I),M={components:{CheckboxField:n(35).a},props:["error","isLoading"],computed:{selectedTabs:function(){return this.tabs.filter((function(t){return t.checked})).map((function(t){return t.name}))}},data:function(){return{tabs:[{label:"Stack trace",name:"stackTraceTab",checked:!0},{label:"Request",name:"requestTab",checked:!0},{label:"App",name:"appTab",checked:!0},{label:"User",name:"userTab",checked:!0},{label:"Context",name:"contextTab",checked:!0},{label:"Debug",name:"debugTab",checked:!0}]}},methods:{shareError:function(){this.isLoading||this.$emit("share",this.selectedTabs)}}},P=Object(d.a)(M,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",[n("div",{staticClass:"grid cols-2 justify-start gapx-6 gapy-2"},t._l(t.tabs,(function(e){return n("CheckboxField",{key:e.name,staticClass:"text-gray-200 hover:text-white",attrs:{label:e.label,name:e.name},on:{change:function(t){e.checked=!e.checked}},model:{value:e.checked,callback:function(n){t.$set(e,"checked",n)},expression:"tab.checked"}})})),1),t._v(" "),n("div",{staticClass:"mt-4"},[t.error?n("div",{staticClass:"mb-3"},[t._v("\n We were unable to share your error."),n("br"),t._v("\n Please try again later.\n ")]):t._e(),t._v(" "),n("button",{staticClass:"button-secondary button-sm text-white bg-tint-600",attrs:{disabled:t.isLoading},on:{click:t.shareError}},[t._v("\n "+t._s(t.isLoading?"Sharing…":"Share")+"\n ")])])])}),[],!1,null,null,null).exports,j={props:{text:{required:!0}},data:function(){return{copied:!1,timeout:!1}},methods:{copy:function(t){var e=this;this.timeout&&window.clearTimeout(this.timeout);var n=document.createElement("textarea");n.value=t,document.body.appendChild(n),n.select(),document.execCommand("copy"),document.body.removeChild(n),this.copied=!0,this.timeout=window.setTimeout((function(){return e.copied=!1}),3e3)}}},F={components:{CopyButton:Object(d.a)(j,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("button",{attrs:{title:"Copy to clipboard"},on:{click:function(e){return t.copy(t.text)}}},[n("Icon",{class:t.copied?"fill-green-300":"fill-gray-200 hover:fill-white",attrs:{name:"clipboard"}}),t._v(" "),t.copied?n("div",{staticClass:"ml-2 absolute top-0 left-full text-green-300"},[t._v("\n Copied!\n ")]):t._e()],1)}),[],!1,null,null,null).exports},props:{publicUrl:{required:!0},ownerUrl:{required:!0}}},U={components:{ShareLinks:Object(d.a)(F,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"text-left"},[n("p",{staticClass:"mt-2 text-gray-300"},[t._v("Share your error with others:")]),t._v(" "),n("div",{staticClass:"grid cols-auto items-center justify-start gap-2 mt-2"},[n("a",{staticClass:"button-secondary button-sm bg-tint-600 hover:bg-tint-700 text-white",attrs:{href:t.publicUrl,target:"_blank"}},[t._v("Open public share")]),t._v(" "),n("CopyButton",{attrs:{text:t.publicUrl}})],1),t._v(" "),n("p",{staticClass:"mt-4 text-gray-300"},[t._v("Administer your shared error here:")]),t._v(" "),n("div",{staticClass:"grid cols-auto items-center justify-start gap-2 mt-2"},[n("a",{staticClass:"button-secondary button-sm bg-tint-600 hover:bg-tint-700 text-white",attrs:{href:t.ownerUrl,target:"_blank"}},[t._v("Open share admin")]),t._v(" "),n("CopyButton",{attrs:{text:t.ownerUrl}})],1)])}),[],!1,null,null,null).exports,ShareForm:P},inject:["report","shareEndpoint"],data:function(){return{shareHadError:!1,sharedErrorUrls:null,menuVisible:!1,isShareLoading:!1}},watch:{menuVisible:function(t){t?window.addEventListener("click",this.toggleMenu):window.removeEventListener("click",this.toggleMenu)}},methods:{toggleMenu:function(){this.menuVisible=!this.menuVisible},shareError:(i=T()(C.a.mark((function t(e){var n,r;return C.a.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return this.isShareLoading=!0,t.prev=1,t.next=4,fetch(this.shareEndpoint,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({report:JSON.stringify(this.report),tabs:e,lineSelection:window.location.hash})});case 4:return n=t.sent,t.next=7,n.json();case 7:r=t.sent,n.ok?this.sharedErrorUrls=r:this.shareHadError=!0,t.next=14;break;case 11:t.prev=11,t.t0=t.catch(1),this.shareHadError=!0;case 14:this.isShareLoading=!1;case 15:case"end":return t.stop()}}),t,this,[[1,11]])}))),function(t){return i.apply(this,arguments)})}},$={inject:["config","report"],components:{ShareButton:Object(d.a)(U,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{on:{click:function(t){t.stopPropagation()}}},[n("button",{staticClass:"tab",class:t.menuVisible?"tab-active":"",on:{click:t.toggleMenu}},[t._v("\n Share\n "),n("Icon",{staticClass:"ml-2",attrs:{name:"share"}})],1),t._v(" "),n("div",{staticClass:"dropdown z-10 right-0 top-full p-4 overflow-visible",class:{hidden:!t.menuVisible},staticStyle:{"min-width":"18rem","margin-right":"-1px"},on:{click:function(t){t.stopPropagation()}}},[n("div",{staticClass:"flex items-center mb-4"},[n("svg",{staticClass:"w-4 h-5 mr-2",attrs:{viewBox:"0 0 682 1024"}},[n("polygon",{staticStyle:{fill:"#51DB9E"},attrs:{points:"235.3,510.5 21.5,387 21.5,140.2 236.5,264.1 "}}),t._v(" "),n("polygon",{staticStyle:{fill:"#7900F5"},attrs:{points:"235.3,1004.8 21.5,881.4 21.5,634.5 234.8,757.9 "}}),t._v(" "),n("polygon",{staticStyle:{fill:"#94F2C8"},attrs:{points:"448.9,386.9 21.5,140.2 235.3,16.7 663.2,263.4 "}}),t._v(" "),n("polygon",{staticStyle:{fill:"#A475F4"},attrs:{points:"234.8,757.9 21.5,634.5 235.3,511 449.1,634.5 "}})]),t._v(" "),n("h5",{staticClass:"text-left font-semibold uppercase tracking-wider whitespace-no-wrap"},[t._v("\n "+t._s(t.sharedErrorUrls?"Shared":"Share")+" on Flare\n ")]),t._v(" "),n("a",{staticClass:"ml-auto underline",attrs:{target:"_blank",href:"https://flareapp.io/docs/ignition-for-laravel/sharing-errors",title:"Flare documentation"}},[t._v("Docs\n ")])]),t._v(" "),t.sharedErrorUrls?n("div",[n("ShareLinks",{attrs:{publicUrl:t.sharedErrorUrls.public_url,ownerUrl:t.sharedErrorUrls.owner_url}})],1):n("ShareForm",{attrs:{error:t.shareHadError,"is-loading":t.isShareLoading},on:{share:t.shareError}})],1)])}),[],!1,null,null,null).exports},props:{value:{required:!0},customTabs:{required:!0}},data:function(){return{defaultTabs:[{component:"StackTab",title:"Stack trace"},{component:"RequestTab",title:"Request"}].concat(D()(this.report.context.livewire?[{component:"LivewireTab",title:"Livewire"}]:[]),[{component:"AppTab",title:"App"},{component:"UserTab",title:"User"},{component:"ContextTab",title:"Context"},{component:"DebugTab",title:"Debug"}]),shareButtonEnabled:this.config.enableShareButton}},mounted:function(){this.applyDefaultTabProps(),this.$emit("input",this.tabs[this.currentTabIndex])},computed:{currentTabIndex:function(){var t=this;return this.tabs.findIndex((function(e){return e.component===t.value.component}))},nextTab:function(){return this.tabs[this.currentTabIndex+1]||this.tabs[0]},previousTab:function(){return this.tabs[this.currentTabIndex-1]||this.tabs[this.tabs.length-1]},tabs:function(){var t={};return this.defaultTabs.forEach((function(e){t[e.component]=e})),this.customTabs.forEach((function(e){t[e.component]=e})),Object.values(t)}},methods:{applyDefaultTabProps:function(){var t=this;this.defaultTabs.map((function(e){return e.component===t.value.component&&(e.props=t.value.props||{}),e}))}}},B={props:{tab:{required:!0}},render:function(t){return t(this.tab.component,{props:this.tab.props||{}})}},z={props:{report:{required:!0},config:{required:!0},solutions:{required:!0},telescopeUrl:{required:!0},shareEndpoint:{required:!0},defaultTab:{required:!0},defaultTabProps:{required:!1},appEnv:{required:!0},appDebug:{required:!0}},data:function(){return{customTabs:window.tabs,tab:{component:this.defaultTab,props:this.defaultTabProps||{}}}},provide:function(){return{config:this.config,report:this.report,solutions:this.solutions,telescopeUrl:this.telescopeUrl,shareEndpoint:this.shareEndpoint,setTab:this.setTab,appEnv:this.appEnv,appDebug:this.appDebug}},components:{Summary:L,Tabs:Object(d.a)($,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("nav",{staticClass:"tab-nav"},[n("ul",{staticClass:"tab-bar"},t._l(t.tabs,(function(e){return n("li",{key:e.component},[n("button",{staticClass:"tab",class:t.value.component===e.component?"tab-active":"",on:{click:function(n){return n.preventDefault(),t.$emit("input",e)}}},[t._v("\n "+t._s(e.title)+"\n ")])])})),0),t._v(" "),t.shareButtonEnabled?[n("div",{staticClass:"tab-delimiter"}),t._v(" "),n("ShareButton")]:t._e()],2)}),[],!1,null,null,null).exports,Details:Object(d.a)(B,void 0,void 0,!1,null,null,null).exports,IconSymbols:h},methods:{setTab:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};this.tab={component:t,props:e}}},created:function(){}},q=Object(d.a)(z,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",[n("IconSymbols"),t._v(" "),n("Summary"),t._v(" "),n("div",{staticClass:"layout-col mt-12"},[n("div",{staticClass:"tabs"},[n("Tabs",t._b({model:{value:t.tab,callback:function(e){t.tab=e},expression:"tab"}},"Tabs",{customTabs:t.customTabs},!1)),t._v(" "),n("div",{staticClass:"tab-main"},[n("Details",t._b({},"Details",{tab:t.tab},!1))],1)],1)])],1)}),[],!1,null,null,null).exports;function H(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function G(t){for(var e=1;e=this.selectedRange[0]&&t<=this.selectedRange[1])},editorUrl:function(t){return Object(c.a)(this.config,this.selectedFrame.file,t)},highlightedCode:function(t){var e=o.a.highlight("php",t||"",!0,this.highlightState);return this.highlightState=e.top,e.value||" "}}},l=n(0),f=Object(l.a)(u,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"stack-main"},[n("div",{staticClass:"stack-main-header"},[n("div",{staticClass:"grid cols-auto gap-2 justify-start items-center"},[n("ExceptionClass",{attrs:{name:t.selectedFrame.class||"",method:t.selectedFrame.method||""}})],1),t._v(" "),t.selectedFrame.file?n("FilePath",{staticClass:"mt-1",attrs:{"line-number":t.selectedFrame.line_number,file:t.selectedFrame.file,editable:!0}}):t._e()],1),t._v(" "),n("div",{staticClass:"stack-main-content"},[n("div",{staticClass:"stack-viewer scrollbar"},[n("div",{staticClass:"stack-ruler"},[n("div",{staticClass:"stack-lines"},t._l(t.selectedFrame.code_snippet,(function(e,r){return n("p",{key:r,staticClass:"stack-line cursor-pointer",class:{"stack-line-selected":t.withinSelectedRange(parseInt(r)),"stack-line-highlight":parseInt(r)===t.selectedFrame.line_number},on:{click:function(e){t.handleLineNumberClick(e,parseInt(r))}}},[t._v("\n "+t._s(r)+"\n ")])})),0)]),t._v(" "),n("pre",{ref:"codeContainer",staticClass:"stack-code",class:t.highlightTheme},[t._l(t.selectedFrame.code_snippet,(function(e,r){return n("p",{key:r,staticClass:"stack-code-line",class:{"stack-code-line-highlight":parseInt(r)===t.selectedFrame.line_number,"stack-code-line-selected":t.withinSelectedRange(parseInt(r))}},[n("span",{domProps:{innerHTML:t._s(t.highlightedCode(e))}}),n("a",{staticClass:"editor-link",attrs:{href:t.editorUrl(r)}},[n("Icon",{attrs:{name:"pencil"}})],1)])})),t._v("\n ")],2)])])])}),[],!1,null,null,null).exports,p={props:{frameGroup:{required:!0}},components:{ExceptionClass:i.a,FilePath:a.a,LineNumber:s.a}},d=Object(l.a)(p,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.frameGroup.expanded||"vendor"!==t.frameGroup.type?"unknown"===t.frameGroup.type?n("li",{staticClass:"stack-frame-group stack-frame-group-unknown"},[n("div",{staticClass:"stack-frame"},[n("button",{staticClass:"stack-frame-number"}),t._v(" "),n("div",{staticClass:"span-2 stack-frame-text"},[n("span",{staticClass:"text-left text-gray-500"},[t._v("\n "+t._s(t.frameGroup.frames.length>1?t.frameGroup.frames.length+" unknown frames":"1 unknown frame")+"\n ")])])])]):n("li",[n("ul",{staticClass:"stack-frame-group",class:"vendor"===t.frameGroup.type?"stack-frame-group-vendor":""},t._l(t.frameGroup.frames,(function(e,r){return n("li",{key:r,staticClass:"stack-frame | cursor-pointer",class:e.selected?"stack-frame-selected":"",on:{click:function(n){return t.$emit("select",e.frame_number)}}},[n("div",{staticClass:"stack-frame-number"},[t._v(t._s(e.frame_number))]),t._v(" "),n("div",{staticClass:"stack-frame-text"},[0===r?n("header",{staticClass:"stack-frame-header",class:e.class?"mb-1":""},[n("FilePath",{staticClass:"stack-frame-path",attrs:{pathClass:"vendor"===t.frameGroup.type?"text-gray-800":"text-purple-800",file:e.relative_file}})],1):t._e(),t._v(" "),e.class?n("span",{staticClass:"stack-frame-exception-class"},[n("ExceptionClass",{staticClass:"stack-frame-exception-class",attrs:{name:e.class}})],1):t._e()]),t._v(" "),n("div",{staticClass:"stack-frame-line"},[n("LineNumber",{attrs:{lineNumber:e.line_number}})],1)])})),0)]):n("li",{staticClass:"stack-frame-group stack-frame-group-vendor",on:{click:function(e){return t.$emit("expand")}}},[n("div",{staticClass:"stack-frame | cursor-pointer"},[n("button",{staticClass:"stack-frame-number"},[n("Icon",{staticClass:"align-middle text-gray-500",attrs:{name:"plus"}})],1),t._v(" "),n("div",{staticClass:"span-2 stack-frame-text"},[n("button",{staticClass:"text-left text-gray-500"},[t._v("\n "+t._s(t.frameGroup.frames.length>1?t.frameGroup.frames.length+" vendor frames…":"1 vendor frame…")+"\n ")])])])])}),[],!1,null,null,null).exports,h=n(6),g=n.n(h),m=n(4),v=n.n(m),b=n(16),_=n.n(b);function y(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function E(t){return t.map((function(e,n){return function(t){for(var e=1;e