Repository: irabbi360/laravel-vue3-spa-starter Branch: main Commit: 48f5ba23aff6 Files: 227 Total size: 861.0 KB Directory structure: gitextract_q3enx6td/ ├── .editorconfig ├── .gitattributes ├── .github/ │ └── ISSUE_TEMPLATE/ │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── app/ │ ├── Console/ │ │ └── Kernel.php │ ├── Exceptions/ │ │ └── Handler.php │ ├── Helpers/ │ │ └── Misc.php │ ├── Http/ │ │ ├── Controllers/ │ │ │ ├── Api/ │ │ │ │ ├── ActivityLogController.php │ │ │ │ ├── BrowserSessionController.php │ │ │ │ ├── CategoryController.php │ │ │ │ ├── PermissionController.php │ │ │ │ ├── PostController.php │ │ │ │ ├── ProfileController.php │ │ │ │ ├── RoleController.php │ │ │ │ └── UserController.php │ │ │ ├── Auth/ │ │ │ │ ├── AuthenticatedSessionController.php │ │ │ │ ├── ConfirmPasswordController.php │ │ │ │ ├── ForgotPasswordController.php │ │ │ │ ├── LoginController.php │ │ │ │ ├── RegisterController.php │ │ │ │ ├── ResetPasswordController.php │ │ │ │ └── VerificationController.php │ │ │ ├── Controller.php │ │ │ └── HomeController.php │ │ ├── Kernel.php │ │ ├── Middleware/ │ │ │ ├── Authenticate.php │ │ │ ├── EncryptCookies.php │ │ │ ├── EnsureEmailIsVerified.php │ │ │ ├── HandleInvalidSignature.php │ │ │ ├── PreventRequestsDuringMaintenance.php │ │ │ ├── RedirectIfAuthenticated.php │ │ │ ├── TrimStrings.php │ │ │ ├── TrustHosts.php │ │ │ ├── TrustProxies.php │ │ │ ├── ValidateSignature.php │ │ │ └── VerifyCsrfToken.php │ │ ├── Requests/ │ │ │ ├── Auth/ │ │ │ │ ├── LoginRequest.php │ │ │ │ └── RegisterRequest.php │ │ │ ├── StoreCategoryRequest.php │ │ │ ├── StorePermissionRequest.php │ │ │ ├── StorePostRequest.php │ │ │ ├── StoreRoleRequest.php │ │ │ ├── StoreUserRequest.php │ │ │ ├── UpdateProfileRequest.php │ │ │ └── UpdateUserRequest.php │ │ └── Resources/ │ │ ├── ActivityLogResource.php │ │ ├── CategoryResource.php │ │ ├── PermissionResource.php │ │ ├── PostResource.php │ │ ├── RoleResource.php │ │ └── UserResource.php │ ├── Models/ │ │ ├── Category.php │ │ ├── CategoryPost.php │ │ ├── Post.php │ │ └── User.php │ ├── Notifications/ │ │ ├── UserResetPasswordNotification.php │ │ └── VerifyEmailNotification.php │ └── Providers/ │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ ├── BroadcastServiceProvider.php │ ├── EventServiceProvider.php │ └── RouteServiceProvider.php ├── artisan ├── bootstrap/ │ ├── app.php │ └── cache/ │ └── .gitignore ├── composer.json ├── config/ │ ├── activitylog.php │ ├── api-inspector.php │ ├── app.php │ ├── auth.php │ ├── broadcasting.php │ ├── browser-sessions.php │ ├── cache.php │ ├── cors.php │ ├── database.php │ ├── filesystems.php │ ├── hashing.php │ ├── logging.php │ ├── mail.php │ ├── media-library.php │ ├── permission.php │ ├── queue.php │ ├── sanctum.php │ ├── services.php │ ├── session.php │ └── view.php ├── database/ │ ├── .gitignore │ ├── factories/ │ │ └── UserFactory.php │ ├── migrations/ │ │ ├── 2014_10_12_000000_create_users_table.php │ │ ├── 2014_10_12_100000_create_password_resets_table.php │ │ ├── 2019_08_19_000000_create_failed_jobs_table.php │ │ ├── 2019_12_14_000001_create_personal_access_tokens_table.php │ │ ├── 2022_09_30_181156_create_posts_table.php │ │ ├── 2022_09_30_181227_create_categories_table.php │ │ ├── 2023_09_25_045349_create_jobs_table.php │ │ ├── 2023_10_02_010617_create_category_post_table.php │ │ ├── 2023_10_02_175025_create_media_table.php │ │ ├── 2024_11_25_022836_create_permission_tables.php │ │ ├── 2025_01_22_091913_create_sessions_table.php │ │ ├── 2025_01_23_093055_create_activity_log_table.php │ │ ├── 2025_01_23_093056_add_event_column_to_activity_log_table.php │ │ ├── 2025_01_23_093057_add_batch_uuid_column_to_activity_log_table.php │ │ └── 2026_01_05_114017_create_api_inspector_analytics_table.php │ └── seeders/ │ ├── CreateAdminUserSeeder.php │ ├── DatabaseSeeder.php │ └── PermissionTableSeeder.php ├── lang/ │ └── en/ │ ├── auth.php │ ├── pagination.php │ ├── passwords.php │ └── validation.php ├── package.json ├── phpunit.xml ├── public/ │ ├── .htaccess │ ├── index.php │ ├── robots.txt │ └── vendor/ │ └── api-inspector/ │ ├── .vite/ │ │ └── manifest.json │ ├── css/ │ │ └── app.css │ └── js/ │ └── app.js ├── resources/ │ ├── css/ │ │ └── app.css │ ├── js/ │ │ ├── app.js │ │ ├── bootstrap.js │ │ ├── components/ │ │ │ ├── Admin/ │ │ │ │ ├── Create.vue │ │ │ │ ├── Edit.vue │ │ │ │ └── Index.vue │ │ │ ├── DropZone.vue │ │ │ ├── DualListBox.vue │ │ │ ├── ExampleComponent.vue │ │ │ ├── Footer.vue │ │ │ ├── LocaleSwitcher.vue │ │ │ ├── Nav.vue │ │ │ ├── TextEditorComponent.vue │ │ │ └── includes/ │ │ │ ├── AdminNavbar.vue │ │ │ ├── AdminSidebar.vue │ │ │ └── Breadcrumb.vue │ │ ├── composables/ │ │ │ ├── activityLogs.js │ │ │ ├── auth.js │ │ │ ├── categories.js │ │ │ ├── permissions.js │ │ │ ├── posts.js │ │ │ ├── profile.js │ │ │ ├── roles.js │ │ │ └── users.js │ │ ├── lang/ │ │ │ ├── bn.json │ │ │ ├── en.json │ │ │ ├── es.json │ │ │ ├── fr.json │ │ │ ├── pt-BR.json │ │ │ └── zh-CN.json │ │ ├── layouts/ │ │ │ ├── Admin.vue │ │ │ ├── Authenticated.vue │ │ │ ├── Error.vue │ │ │ └── Guest.vue │ │ ├── plugins/ │ │ │ └── i18n.js │ │ ├── routes/ │ │ │ ├── index.js │ │ │ └── routes.js │ │ ├── services/ │ │ │ └── ability.js │ │ ├── store/ │ │ │ ├── auth.js │ │ │ └── lang.js │ │ ├── validation/ │ │ │ └── rules.js │ │ └── views/ │ │ ├── admin/ │ │ │ ├── activity-log/ │ │ │ │ └── Index.vue │ │ │ ├── browser-sessions/ │ │ │ │ └── Index.vue │ │ │ ├── categories/ │ │ │ │ ├── Create.vue │ │ │ │ ├── Edit.vue │ │ │ │ └── Index.vue │ │ │ ├── index.vue │ │ │ ├── permissions/ │ │ │ │ ├── Create.vue │ │ │ │ ├── Edit.vue │ │ │ │ └── Index.vue │ │ │ ├── posts/ │ │ │ │ ├── Create.vue │ │ │ │ ├── Edit.vue │ │ │ │ └── Index.vue │ │ │ ├── profile/ │ │ │ │ └── index.vue │ │ │ ├── roles/ │ │ │ │ ├── Create.vue │ │ │ │ ├── Edit.vue │ │ │ │ └── Index.vue │ │ │ └── users/ │ │ │ ├── Create.vue │ │ │ ├── Edit.vue │ │ │ └── Index.vue │ │ ├── auth/ │ │ │ ├── Verify.vue │ │ │ └── passwords/ │ │ │ ├── Confirm.vue │ │ │ ├── Email.vue │ │ │ └── Reset.vue │ │ ├── category/ │ │ │ └── posts.vue │ │ ├── errors/ │ │ │ └── 404.vue │ │ ├── home/ │ │ │ └── index.vue │ │ ├── login/ │ │ │ └── Login.vue │ │ ├── posts/ │ │ │ ├── details.vue │ │ │ └── index.vue │ │ └── register/ │ │ └── index.vue │ ├── sass/ │ │ ├── _custom.scss │ │ ├── _variables.scss │ │ └── app.scss │ └── views/ │ ├── auth/ │ │ ├── login.blade.php │ │ ├── passwords/ │ │ │ ├── confirm.blade.php │ │ │ ├── email.blade.php │ │ │ └── reset.blade.php │ │ ├── register.blade.php │ │ └── verify.blade.php │ ├── home.blade.php │ ├── layouts/ │ │ ├── app.blade.php │ │ └── master.blade.php │ ├── main-view.blade.php │ └── welcome.blade.php ├── routes/ │ ├── api.php │ ├── channels.php │ ├── console.php │ └── web.php ├── storage/ │ ├── app/ │ │ └── .gitignore │ ├── framework/ │ │ ├── .gitignore │ │ ├── cache/ │ │ │ └── .gitignore │ │ ├── sessions/ │ │ │ └── .gitignore │ │ ├── testing/ │ │ │ └── .gitignore │ │ └── views/ │ │ └── .gitignore │ └── logs/ │ └── .gitignore ├── tests/ │ ├── CreatesApplication.php │ ├── Feature/ │ │ └── ExampleTest.php │ ├── TestCase.php │ └── Unit/ │ └── ExampleTest.php ├── vite.config.js └── vue.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 end_of_line = lf insert_final_newline = true indent_style = space indent_size = 4 trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false [*.{yml,yaml}] indent_size = 2 [docker-compose.yml] indent_size = 4 ================================================ FILE: .gitattributes ================================================ * text=auto *.blade.php diff=html *.css diff=css *.html diff=html *.md diff=markdown *.php diff=php /.github export-ignore CHANGELOG.md export-ignore .styleci.yml export-ignore ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. iOS] - Browser [e.g. chrome, safari] - Version [e.g. 22] **Smartphone (please complete the following information):** - Device: [e.g. iPhone6] - OS: [e.g. iOS8.1] - Browser [e.g. stock browser, safari] - Version [e.g. 22] **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/custom.md ================================================ --- name: Custom issue template about: Describe this issue template's purpose here. title: '' labels: '' assignees: '' --- ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .gitignore ================================================ /node_modules /public/build /public/hot /public/storage /storage/*.key /vendor .env .env.backup .phpunit.result.cache Homestead.json Homestead.yaml auth.json npm-debug.log yarn-error.log /.idea /.vscode package-lock.json composer.lock yarn.lock /storage/media-library/temp .DS_Store ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at fazrabbi010@gmail.com. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. ================================================ FILE: CONTRIBUTING.md ================================================ ## Contributing Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2023 Fazle Rabbi 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. ================================================ FILE: README.md ================================================ ## Laravel 11 Vue.js 3 SPA Starter Boilerplate A simple and clean boilerplate to start a new SPA project with authentication, user, roles, permissions management and more features. This boilerplate uses the following tools: [![](https://img.shields.io/badge/vue.js-v3.5-04C690.svg)](https://vuejs.org) [![](https://img.shields.io/badge/Laravel-v11.x-ff2e21.svg)](https://laravel.com) [![](https://img.shields.io/badge/bootstrap-v5.3-712cf9.svg)](https://getbootstrap.com) [![](https://img.shields.io/badge/axios-v1.7-5A29E4.svg)](https://axios-http.com) [![](https://img.shields.io/badge/vite-v5.0-646cff.svg)](https://vitejs.dev) - [Laravel 11.x](https://github.com/laravel/laravel) - [Laravel Sanctum](https://laravel.com/docs/11.x/sanctum) - [Vue 3](https://github.com/vuejs/vue) - [Vue Router](https://router.vuejs.org/) - [Pinia](https://pinia.vuejs.org/) - [Bootstrap](https://getbootstrap.com/) - [Vue I18n](https://vue-i18n.intlify.dev) - [Laravel API Inspector - API Docs](https://github.com/irabbi360/laravel-api-inspector) Laravel is accessible, and powerful, and provides tools required for large, robust applications. ## Features The following Sanctum features are implemented in this Vue SPA: - ✅ Laravel 11 - ✅ Vue 3 - ✅ VueRouter - ✅ Pinia - ✅ Vue I18n Multi-Language - ✅ Login - ✅ Password Reset - ✅ Registration - ✅ Admin Panel - ✅ Profile Management - ✅ User Management - ✅ Roles Management - ✅ Permissions Management - ✅ Password Change - ✅ E-Mail Verification - ✅ Posts Management - ✅ Frontend Blog - ✅ Bootstrap 5 - ✅ Automatic Api Documentation -- route /api-docs - ✅ Browser Sessions - Other Device Logout - ✅ User Activity Logs ## How To Use #### Clone the repository ```bash git clone https://github.com/irabbi360/laravel-vue3-spa-starter.git ``` #### Copy .env.example file to .env and edit credentials also set the app URL #### Install Via Composer ```bash composer install ``` #### Generate Application Key ```bash php artisan key:generate ``` #### Migrate Database ```bash php artisan migrate ``` #### Run Seeder ```bash php artisan db:seed ``` #### Install Node Dependencies ```bash npm install or yarn install npm run dev or yarn dev ``` #### Production ```bash npm run build or yarn build ``` ## Email Verification To enable email verification, ensure your `App\User` model implements the `Illuminate\Contracts\Auth\MustVerifyEmail` contract. ## N.B If you want to use Laravel 10 or 9 version, please use laravel_10 or laravel_9 branch. ## Contributing Thank you for considering contributing to the project! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). ## Code of Conduct To ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). ## Security Vulnerabilities If you discover a security vulnerability within Laravel, please e-mail via [fazrabbi010@gmail.com](mailto:fazrabbi010@gmail.com). All security vulnerabilities will be promptly addressed. ## License The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). The Vue framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). This repository is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). ================================================ FILE: SECURITY.md ================================================ # Reporting Security Issues The Laravel Vue3 SPA Starter highly values the contributions from the security research community. We eagerly anticipate collaborating with you to mitigate and reduce potential risks. ## Where should I report security issues? If you think that you have found a security issue in Laravel Vue3 SPA Starter, please do not use the issue tracker and do not post it publicly. Instead, all security issues must be sent to mailto:fazrabbi010@gmail.com.com. ================================================ FILE: app/Console/Kernel.php ================================================ command('inspire')->hourly(); } /** * Register the commands for the application. * * @return void */ protected function commands() { $this->load(__DIR__.'/Commands'); require base_path('routes/console.php'); } } ================================================ FILE: app/Exceptions/Handler.php ================================================ , \Psr\Log\LogLevel::*> */ protected $levels = [ // ]; /** * A list of the exception types that are not reported. * * @var array> */ protected $dontReport = [ // ]; /** * A list of the inputs that are never flashed to the session on validation exceptions. * * @var array */ protected $dontFlash = [ 'current_password', 'password', 'password_confirmation', ]; /** * Register the exception handling callbacks for the application. * * @return void */ public function register() { $this->reportable(function (Throwable $e) { // }); } } ================================================ FILE: app/Helpers/Misc.php ================================================ 'John', * 'user_data' => [ * 'last_name' => 'Doe', * 'contact_info' => [ * 'phone_number' => '1234567890' * ] * ] * ] * * Output: * [ * 'First Name' => 'John', * 'User Data' => [ * 'Last Name' => 'Doe', * 'Contact Info' => [ * 'Phone Number' => '1234567890' * ] * ] * ] * * @param array $data The data to be processed. If the data is an array, its keys * will be transformed. Non-array data types will be returned * as-is without modification. * @return array The processed data, with all array keys in "headline" format. * If the input was not an array, it will return the original value. */ public static function convertKeysToHeadline(array $data) { $formatted = []; // Loop through each key and value foreach ($data as $key => $value) { // Apply Str::headline to the key and recursively process the value if it's an array $formatted[Str::headline($key)] = is_array($value) ? self::convertKeysToHeadline($value) : $value; } return $formatted; } public static function apiPagination(array $data) { return [ 'current_page' => $data['current_page'], 'from' => $data['from'], 'last_page' => $data['last_page'], // 'links' => $data['links'], // 'path' => $data['path'], 'per_page' => $data['per_page'], 'to' => $data['to'], 'total' => $data['total'], ]; } } ================================================ FILE: app/Http/Controllers/Api/ActivityLogController.php ================================================ get('per_page', 15); // Default pagination size $search = $request->get('search'); $activity = Activity::query() ->latest() ->where('causer_id', auth()->id()) ->when($request->filled('filter'), function ($query) use ($request) { $query->where('event', $request->filter); }) ->when($search, function ($query) use ($search) { $query->where(function ($q) use ($search) { $q->where('description', 'like', '%' . $search . '%') ->orWhere('event', 'like', '%' . $search . '%'); }); }) ->paginate($perPage); return ActivityLogResource::collection($activity); } } ================================================ FILE: app/Http/Controllers/Api/BrowserSessionController.php ================================================ json($sessions); } public function logoutOtherDevices() { return BrowserSessions::logoutOtherBrowserSessions(); } } ================================================ FILE: app/Http/Controllers/Api/CategoryController.php ================================================ where('id', request('search_id')); }) ->when(request('search_title'), function ($query) { $query->where('name', 'like', '%'.request('search_title').'%'); }) ->when(request('search_global'), function ($query) { $query->where(function($q) { $q->where('id', request('search_global')) ->orWhere('name', 'like', '%'.request('search_global').'%'); }); }) ->orderBy($orderColumn, $orderDirection) ->paginate(50); return CategoryResource::collection($categories); } public function store(StoreCategoryRequest $request) { $this->authorize('category-create'); $category = Category::create($request->validated()); return new CategoryResource($category); } public function show(Category $category) { $this->authorize('category-edit'); return new CategoryResource($category); } public function update(Category $category, StoreCategoryRequest $request) { $this->authorize('category-edit'); $category->update($request->validated()); return new CategoryResource($category); } public function destroy(Category $category) { $this->authorize('category-delete'); $category->delete(); return response()->noContent(); } public function getList() { return CategoryResource::collection(Category::all()); } } ================================================ FILE: app/Http/Controllers/Api/PermissionController.php ================================================ where('id', request('search_id')); }) ->when(request('search_title'), function ($query) { $query->where('name', 'like', '%' . request('search_title') . '%'); }) ->when(request('search_global'), function ($query) { $query->where(function ($q) { $q->where('id', request('search_global')) ->orWhere('name', 'like', '%' . request('search_global') . '%'); }); }) ->orderBy($orderColumn, $orderDirection) ->paginate(50); return PermissionResource::collection($permissions); } /** * Store a newly created resource in storage. * * @param StorePermissionRequest $request * @return PermissionResource * @throws AuthorizationException */ public function store(StorePermissionRequest $request) { $this->authorize('permission-create'); $permission = new Permission(); $permission->name = $request->name; $permission->guard_name = 'web'; if ($permission->save()) { return new PermissionResource($permission); } return response()->json(['status' => 405, 'success' => false]); } /** * Display the specified resource. * * @param int $id * @return PermissionResource */ public function show(Permission $permission) { $this->authorize('permission-edit'); return new PermissionResource($permission); } /** * Update the specified resource in storage. * * @param Permission $permission * @param StorePermissionRequest $request * @return JsonResponse|PermissionResource * @throws AuthorizationException */ public function update(Permission $permission, StorePermissionRequest $request) { $this->authorize('permission-edit'); $permission->name = $request->name; if ($permission->save()) { return new PermissionResource($permission); } return response()->json(['status' => 405, 'success' => false]); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy(Permission $permission) { $this->authorize('permission-delete'); $permission->delete(); return response()->noContent(); } public function getRolePermissions($id) { $permissions = Role::findById($id, 'web')->permissions; return PermissionResource::collection($permissions); } public function updateRolePermissions(Request $request) { $this->authorize('role-edit'); $permissions = json_decode($request->permissions, true); $permissions_where = Permission::whereIn('id', $permissions)->get(); $role = Role::findById($request->role_id, 'web'); $role->syncPermissions($permissions_where); return PermissionResource::collection($permissions_where); } } ================================================ FILE: app/Http/Controllers/Api/PostController.php ================================================ whereHas('categories', function ($query) { if (request('search_category')) { $categories = explode(",", request('search_category')); $query->whereIn('id', $categories); } }) ->when(request('search_id'), function ($query) { $query->where('id', request('search_id')); }) ->when(request('search_title'), function ($query) { $query->where('title', 'like', '%' . request('search_title') . '%'); }) ->when(request('search_content'), function ($query) { $query->where('content', 'like', '%' . request('search_content') . '%'); }) ->when(request('search_global'), function ($query) { $query->where(function ($q) { $q->where('id', request('search_global')) ->orWhere('title', 'like', '%' . request('search_global') . '%') ->orWhere('content', 'like', '%' . request('search_global') . '%'); }); }) ->when(!auth()->user()->hasPermissionTo('post-all'), function ($query) { $query->where('user_id', auth()->id()); }) ->orderBy($orderColumn, $orderDirection) ->paginate(50); return PostResource::collection($posts); } public function store(StorePostRequest $request) { $this->authorize('post-create'); $validatedData = $request->validated(); $validatedData['user_id'] = auth()->id(); $post = Post::create($validatedData); $categories = explode(",", $request->categories); $category = Category::findMany($categories); $post->categories()->attach($category); if ($request->hasFile('thumbnail')) { $post->addMediaFromRequest('thumbnail')->preservingOriginal()->toMediaCollection('images'); } return new PostResource($post); } public function show(Post $post): PostResource { $this->authorize('post-edit'); if ($post->user_id !== auth()->user()->id && !auth()->user()->hasPermissionTo('post-all')) { return response()->json(['status' => 405, 'success' => false, 'message' => 'You can only edit your own posts']); } else { return new PostResource($post); } } public function update(Post $post, StorePostRequest $request) { $this->authorize('post-edit'); if ($post->user_id !== auth()->id() && !auth()->user()->hasPermissionTo('post-all')) { return response()->json(['status' => 405, 'success' => false, 'message' => 'You can only edit your own posts']); } else { $post->update($request->validated()); $category = Category::findMany($request->categories); $post->categories()->sync($category); return new PostResource($post); } } public function destroy(Post $post) { $this->authorize('post-delete'); if ($post->user_id !== auth()->id() && !auth()->user()->hasPermissionTo('post-all')) { return response()->json(['status' => 405, 'success' => false, 'message' => 'You can only delete your own posts']); } else { $post->delete(); return response()->noContent(); } } /* * Display a listing of the resource. */ public function getPosts() { $posts = Post::with('categories')->with('media')->latest()->paginate(1); return PostResource::collection($posts); } public function getCategoryByPosts($id) { $posts = Post::whereRelation('categories', 'category_id', '=', $id)->paginate(); return PostResource::collection($posts); } public function getPost($id) { return Post::with('categories', 'user', 'media')->findOrFail($id); } } ================================================ FILE: app/Http/Controllers/Api/ProfileController.php ================================================ name = $request->name; $profile->email = $request->email; if ($profile->save()) { return $this->successResponse($profile, 'User updated');; } return response()->json(['status' => 403, 'success' => false]); } public function user(Request $request) { $user = $request->user(); return $this->successResponse($user, 'User Logged In Successfully'); } } ================================================ FILE: app/Http/Controllers/Api/RoleController.php ================================================ where('id', request('search_id')); }) ->when(request('search_title'), function ($query) { $query->where('name', 'like', '%'.request('search_title').'%'); }) ->when(request('search_global'), function ($query) { $query->where(function($q) { $q->where('id', request('search_global')) ->orWhere('name', 'like', '%'.request('search_global').'%'); }); }) ->orderBy($orderColumn, $orderDirection) ->paginate(50); return RoleResource::collection($roles); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return RoleResource */ public function store(StoreRoleRequest $request) { $this->authorize('role-create'); $role = new Role(); $role->name = $request->name; $role->guard_name = 'web'; if ($role->save()) { return new RoleResource($role); } return response()->json(['status' => 405, 'success' => false]); } /** * Display the specified resource. * * @param int $id * @return RoleResource */ public function show(Role $role) { $this->authorize('role-edit'); return new RoleResource($role); } /** * Update the specified resource in storage. * * @param Role $role * @param StoreRoleRequest $request * @return RoleResource * @throws AuthorizationException */ public function update(Role $role, StoreRoleRequest $request) { $this->authorize('role-edit'); $role->name = $request->name; if ($role->save()) { return new RoleResource($role); } return response()->json(['status' => 405, 'success' => false]); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy(Role $role) { $this->authorize('role-delete'); $role->delete(); return response()->noContent(); } public function getList() { return RoleResource::collection(Role::all()); } } ================================================ FILE: app/Http/Controllers/Api/UserController.php ================================================ where('id', request('search_id')); }) ->when(request('search_title'), function ($query) { $query->where('name', 'like', '%'.request('search_title').'%'); }) ->when(request('search_global'), function ($query) { $query->where(function($q) { $q->where('id', request('search_global')) ->orWhere('name', 'like', '%'.request('search_global').'%'); }); }) ->orderBy($orderColumn, $orderDirection) ->paginate(50); return UserResource::collection($users); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return UserResource */ public function store(StoreUserRequest $request) { $role = Role::find($request->role_id); $user = new User(); $user->name = $request->name; $user->email = $request->email; $user->password = Hash::make($request->password); if ($user->save()) { if ($role) { $user->assignRole($role); } return new UserResource($user); } } /** * Display the specified resource. * * @param int $id * @return UserResource */ public function show(User $user) { $user->load('roles'); return new UserResource($user); } /** * Update the specified resource in storage. * * @param UpdateUserRequest $request * @param User $user * @return UserResource */ public function update(UpdateUserRequest $request, User $user) { $role = Role::find($request->role_id); $user->name = $request->name; $user->email = $request->email; if(!empty($request->password)) { $user->password = Hash::make($request->password) ?? $user->password; } if ($user->save()) { if ($role) { $user->syncRoles($role); } return new UserResource($user); } } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy(User $user) { $this->authorize('user-delete'); $user->delete(); return response()->noContent(); } } ================================================ FILE: app/Http/Controllers/Auth/AuthenticatedSessionController.php ================================================ authenticate(); // $token = $request->session()->regenerate(); $token = $request->user()->createToken($request->userAgent())->plainTextToken; activity() ->performedOn($request->user()) ->causedBy(auth()->user()) ->event('login') ->withProperties(['ip' => $request->ip()]) ->log('User login successfully'); if ($request->wantsJson()) { $user = $request->user(); // Check if email verification is required and if email is verified $emailVerified = !($user instanceof \Illuminate\Contracts\Auth\MustVerifyEmail) || $user->hasVerifiedEmail(); return response()->json([ 'user' => $user, 'token' => $token, 'email_verified' => $emailVerified ]); } return redirect()->intended(RouteServiceProvider::HOME); } /** * Destroy an authenticated session. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\RedirectResponse */ public function logout(Request $request) { activity() ->performedOn($request->user()) ->causedBy(auth()->user()) ->event('logout') ->withProperties(['ip' => $request->ip()]) ->log('User logout successfully'); Auth::guard('web')->logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); if ($request->wantsJson()) { return response()->noContent(); } return redirect('/'); } /** * Create User * @param RegisterRequest $request * @return JsonResponse */ public function register(RegisterRequest $request) { $user = User::where('email', $request['email'])->first(); if ($user) { return response(['error' => 1, 'message' => 'user already exists'], 409); } $user = User::create([ 'email' => $request['email'], 'password' => Hash::make($request['password']), 'name' => $request['name'], ]); // Trigger Registered event which will send verification email if($user instanceof \Illuminate\Contracts\Auth\MustVerifyEmail) { event(new \Illuminate\Auth\Events\Registered($user)); } return $this->successResponse($user, 'Registration Successful. Please verify your email to activate your account.'); } } ================================================ FILE: app/Http/Controllers/Auth/ConfirmPasswordController.php ================================================ middleware('auth'); } } ================================================ FILE: app/Http/Controllers/Auth/ForgotPasswordController.php ================================================ middleware('guest')->except('logout'); } } ================================================ FILE: app/Http/Controllers/Auth/RegisterController.php ================================================ middleware('guest'); } /** * Get a validator for an incoming registration request. * * @param array $data * @return \Illuminate\Contracts\Validation\Validator */ protected function validator(array $data) { return Validator::make($data, [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 'password' => ['required', 'string', 'min:8', 'confirmed'], ]); } /** * Create a new user instance after a valid registration. * * @param array $data * @return \App\Models\User */ protected function create(array $data) { return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), ]); } } ================================================ FILE: app/Http/Controllers/Auth/ResetPasswordController.php ================================================ middleware('throttle:6,1')->only('verify', 'resend'); } /** * Mark the authenticated user's email address as verified. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse */ public function verify(Request $request) { $user = \App\Models\User::findOrFail($request->route('id')); if ($user->hasVerifiedEmail()) { if ($request->wantsJson()) { return response()->json(['message' => 'Email already verified.'], Response::HTTP_OK); } return redirect()->intended($this->redirectTo); } if ($user->markEmailAsVerified()) { event(new \Illuminate\Auth\Events\Verified($user)); } if ($request->wantsJson()) { return response()->json(['message' => 'Email has been verified.'], Response::HTTP_OK); } return redirect()->intended($this->redirectTo.'?verified=1'); } /** * Resend the email verification notification. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse */ public function resend(Request $request) { if ($request->user()->hasVerifiedEmail()) { if ($request->wantsJson()) { return response()->json(['message' => 'Email already verified.'], Response::HTTP_OK); } return redirect()->intended($this->redirectTo); } $request->user()->sendEmailVerificationNotification(); if ($request->wantsJson()) { return response()->json(['message' => 'Verification link sent to your email.'], Response::HTTP_OK); } return back()->with('resent', true); } } ================================================ FILE: app/Http/Controllers/Controller.php ================================================ json([ 'success'=> true, 'message' => $message, 'data' => $data ], $code); } protected function errorResponse($message = null, $code) { return response()->json([ 'success'=> false, 'message' => $message, 'data' => null ], $code); } } ================================================ FILE: app/Http/Controllers/HomeController.php ================================================ middleware('auth'); } /** * Show the application dashboard. * * @return \Illuminate\Contracts\Support\Renderable */ public function index() { return view('home'); } } ================================================ FILE: app/Http/Kernel.php ================================================ */ protected $middleware = [ // \App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustProxies::class, \Illuminate\Http\Middleware\HandleCors::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, ]; /** * The application's route middleware groups. * * @var array> */ protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, \Irabbi360\LaravelApiInspector\Http\Middleware\ApiInspectorMiddleware::class, ], ]; /** * The application's route middleware. * * These middleware may be assigned to groups or used individually. * * @var array */ protected $middlewareAliases = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 'signed' => \App\Http\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified.api' => \App\Http\Middleware\EnsureEmailIsVerified::class, 'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class, 'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class, 'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class, ]; } ================================================ FILE: app/Http/Middleware/Authenticate.php ================================================ expectsJson()) { return route('login'); } } } ================================================ FILE: app/Http/Middleware/EncryptCookies.php ================================================ */ protected $except = [ // ]; } ================================================ FILE: app/Http/Middleware/EnsureEmailIsVerified.php ================================================ user() || ($request->user() instanceof MustVerifyEmail && ! $request->user()->hasVerifiedEmail())) { return response()->json([ 'message' => 'Your email address is not verified.', 'email_verified' => false ], 403); } return $next($request); } } ================================================ FILE: app/Http/Middleware/HandleInvalidSignature.php ================================================ route('id'); $user = \App\Models\User::find($userId); // Check if user exists if (!$user) { return response()->json([ 'message' => 'User not found.', ], 404); } // Check if authenticated user matches the user being verified if ($request->user() && $request->user()->id != $userId) { return response()->json([ 'message' => 'Unauthorized. You can only verify your own email.', ], 403); } // If user is already verified, skip signature validation if ($user->hasVerifiedEmail()) { return response()->json([ 'message' => 'Email already verified.', ], 200); } // Check if signature is valid if (!$request->hasValidSignature()) { return response()->json([ 'message' => 'Invalid or expired verification link.', ], 400); } return $next($request); } catch (InvalidSignatureException $e) { if ($request->wantsJson()) { return response()->json([ 'message' => 'Invalid or expired verification link.', ], 400); } throw $e; } } } ================================================ FILE: app/Http/Middleware/PreventRequestsDuringMaintenance.php ================================================ */ protected $except = [ // ]; } ================================================ FILE: app/Http/Middleware/RedirectIfAuthenticated.php ================================================ check()) { return redirect(RouteServiceProvider::HOME); } } return $next($request); } } ================================================ FILE: app/Http/Middleware/TrimStrings.php ================================================ */ protected $except = [ 'current_password', 'password', 'password_confirmation', ]; } ================================================ FILE: app/Http/Middleware/TrustHosts.php ================================================ */ public function hosts() { return [ $this->allSubdomainsOfApplicationUrl(), ]; } } ================================================ FILE: app/Http/Middleware/TrustProxies.php ================================================ |string|null */ protected $proxies; /** * The headers that should be used to detect proxies. * * @var int */ protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB; } ================================================ FILE: app/Http/Middleware/ValidateSignature.php ================================================ */ protected $except = [ // 'fbclid', // 'utm_campaign', // 'utm_content', // 'utm_medium', // 'utm_source', // 'utm_term', ]; } ================================================ FILE: app/Http/Middleware/VerifyCsrfToken.php ================================================ */ protected $except = [ 'api/*', 'login','register' ]; } ================================================ FILE: app/Http/Requests/Auth/LoginRequest.php ================================================ ['required', 'string', 'email'], 'password' => ['required', 'string'], ]; } /** * Attempt to authenticate the request's credentials. * * @return void * * @throws \Illuminate\Validation\ValidationException */ public function authenticate() { $this->ensureIsNotRateLimited(); if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) { RateLimiter::hit($this->throttleKey()); throw ValidationException::withMessages([ 'email' => trans('auth.failed'), ]); } // Check if email is verified // $user = Auth::user(); // if (! $user->hasVerifiedEmail()) { // Auth::logout(); // throw ValidationException::withMessages([ // 'email' => 'Your email address is not verified. Please check your email to verify your account.', // ]); // } RateLimiter::clear($this->throttleKey()); } /** * Ensure the login request is not rate limited. * * @return void * * @throws \Illuminate\Validation\ValidationException */ public function ensureIsNotRateLimited() { if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) { return; } event(new Lockout($this)); $seconds = RateLimiter::availableIn($this->throttleKey()); throw ValidationException::withMessages([ 'email' => trans('auth.throttle', [ 'seconds' => $seconds, 'minutes' => ceil($seconds / 60), ]), ]); } /** * Get the rate limiting throttle key for the request. * * @return string */ public function throttleKey() { return Str::lower($this->input('email')).'|'.$this->ip(); } } ================================================ FILE: app/Http/Requests/Auth/RegisterRequest.php ================================================ */ public function rules() { return [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 'password' => ['required', 'string', 'min:8', 'confirmed'], ]; } } ================================================ FILE: app/Http/Requests/StoreCategoryRequest.php ================================================ 'required' ]; } } ================================================ FILE: app/Http/Requests/StorePermissionRequest.php ================================================ */ public function rules() { return [ 'name' => 'required' ]; } } ================================================ FILE: app/Http/Requests/StorePostRequest.php ================================================ 'required', 'content' => 'required', 'categories' => 'required' ]; } } ================================================ FILE: app/Http/Requests/StoreRoleRequest.php ================================================ */ public function rules() { return [ 'name' => 'required' ]; } } ================================================ FILE: app/Http/Requests/StoreUserRequest.php ================================================ */ public function rules(): array { return [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 'password' => ['required', 'string', 'min:8'], ]; } } ================================================ FILE: app/Http/Requests/UpdateProfileRequest.php ================================================ */ public function rules() { return [ 'name' => 'required|min:5', 'email' => 'required|email|unique:users,email,'.$this->user()->id ]; } } ================================================ FILE: app/Http/Requests/UpdateUserRequest.php ================================================ */ public function rules(): array { return [ 'name' => ['required', 'string', 'max:255'], 'email' => 'required|string|email|max:255|unique:users,email,'.$this->user->id, 'password' => ['nullable', 'string', 'min:8'], ]; } } ================================================ FILE: app/Http/Resources/ActivityLogResource.php ================================================ */ public function toArray(Request $request): array { return [ 'id' => $this->id, 'log_name' => $this->log_name, 'description' => $this->description, 'subject_type' => $this->subject_type, 'event' => $this->event, 'causer_type' => $this->causer_type, 'causer_id' => $this->causer_id, 'properties' => $this->properties, 'batch_uuid' => $this->batch_uuid, 'created_at' => $this->created_at, 'format_created_at' => $this->created_at->diffForHumans(), ]; } } ================================================ FILE: app/Http/Resources/CategoryResource.php ================================================ $this->id, 'name' => $this->name, 'created_at' => $this->created_at->toDateString() ]; } } ================================================ FILE: app/Http/Resources/PermissionResource.php ================================================ $this->id, 'name' => $this->name, 'guard_name' => $this->guard_name, 'created_at' => $this->created_at->toDateString() ]; } } ================================================ FILE: app/Http/Resources/PostResource.php ================================================ getMedia('*')[0]->getUrl('resized-image'); } catch (Exception $e) { $resized_image=""; } return [ 'id' => $this->id, 'title' => $this->title, 'user_id' => $this->user_id, 'categories' => $this->categories, 'content' => $this->content, 'original_image' => count($this->getMedia('*')) > 0 ? $this->getMedia('*')[0]->getUrl() : null, 'resized_image' => $resized_image, 'created_at' => $this->created_at->toDateString(), 'user' => new UserResource($this->whenLoaded('user')), ]; } } ================================================ FILE: app/Http/Resources/RoleResource.php ================================================ $this->id, 'name' => $this->name, 'guard_name' => $this->guard_name, 'created_at' => $this->created_at->toDateString() ]; } } ================================================ FILE: app/Http/Resources/UserResource.php ================================================ $this->id, 'name' => $this->name, 'email' => $this->email, 'role_id' => $this->roles, 'roles' => $this->roles, 'created_at' => $this->created_at->toDateString() ]; } } ================================================ FILE: app/Models/Category.php ================================================ logOnly(['name', 'text']); // Chain fluent methods for configuration options } /** * Get the posts for the category. */ public function posts() { return $this->belongsToMany(Post::class,'category_post'); } } ================================================ FILE: app/Models/CategoryPost.php ================================================ logOnly(['name', 'text']); // Chain fluent methods for configuration options } public function user() { return $this->belongsTo(User::class); } /** * Get the category that owns the post. */ public function categories() { return $this->belongsToMany(Category::class, 'category_post'); } public function registerMediaCollections(): void { $this->addMediaCollection('images') ->useFallbackUrl('/images/placeholder.jpg') ->useFallbackPath(public_path('/images/placeholder.jpg')); } public function registerMediaConversions(Media $media = null): void { if (env('RESIZE_IMAGE') === true) { $this->addMediaConversion('resized-image') ->width(env('IMAGE_WIDTH', 300)) ->height(env('IMAGE_HEIGHT', 300)); } } } ================================================ FILE: app/Models/User.php ================================================ */ protected $fillable = [ 'name', 'email', 'password', 'name', 'text', ]; /** * The attributes that should be hidden for serialization. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; /** * The attributes that should be cast. * * @var array */ protected $casts = [ 'email_verified_at' => 'datetime', ]; public function sendPasswordResetNotification($token) { $this->notify(new UserResetPasswordNotification($token)); } /** * Send the email verification notification. * * @return void */ public function sendEmailVerificationNotification() { $this->notify(new VerifyEmailNotification()); } public function getActivitylogOptions(): LogOptions { return LogOptions::defaults() ->logOnly(['name', 'text']); // Chain fluent methods for configuration options } } ================================================ FILE: app/Notifications/UserResetPasswordNotification.php ================================================ token .'?email='. $notifiable->getEmailForPasswordReset()); return (new MailMessage) ->line('You are receiving this email because we received a password reset request for your account.') ->action('Reset Password', $resetUrl) ->line('If you did not request a password reset, no further action is required.'); } /** * Get the array representation of the notification. * * @return array */ public function toArray(object $notifiable): array { return [ // ]; } } ================================================ FILE: app/Notifications/VerifyEmailNotification.php ================================================ verificationUrl($notifiable); // Convert /api/email/verify to /verify for the frontend URL $verificationUrl = str_replace('/api/email/verify', '/email/verify', $verificationUrl); return (new MailMessage) ->subject('Verify Email Address') ->line('Please click the button below to verify your email address.') ->action('Verify Email Address', $verificationUrl) ->line('If you did not create an account, no further action is required.'); } } ================================================ FILE: app/Providers/AppServiceProvider.php ================================================ */ protected $policies = [ // 'App\Models\Model' => 'App\Policies\ModelPolicy', ]; /** * Register any authentication / authorization services. * * @return void */ public function boot() { $this->registerPolicies(); $this->registerUserAccessToGates(); } protected function registerUserAccessToGates() { try { foreach (Permission::pluck('name') as $permission) { Gate::define($permission, function ($user) use ($permission) { return $user->roles()->whereHas('permissions', function ($q) use ($permission) { $q->where('name', $permission); })->count() > 0; }); } } catch (\Exception $e) { info('registerUserAccessToGates: Database not found or not yet migrated. Ignoring user permissions while booting app.'); } } } ================================================ FILE: app/Providers/BroadcastServiceProvider.php ================================================ > */ protected $listen = [ Registered::class => [ SendEmailVerificationNotification::class, ], ]; /** * Register any events for your application. * * @return void */ public function boot() { // } /** * Determine if events and listeners should be automatically discovered. * * @return bool */ public function shouldDiscoverEvents() { return false; } } ================================================ FILE: app/Providers/RouteServiceProvider.php ================================================ configureRateLimiting(); $this->routes(function () { Route::middleware('api') ->prefix('api') ->group(base_path('routes/api.php')); Route::middleware('web') ->group(base_path('routes/web.php')); }); } /** * Configure the rate limiters for the application. * * @return void */ protected function configureRateLimiting() { RateLimiter::for('api', function (Request $request) { return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); }); } } ================================================ FILE: artisan ================================================ #!/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); ================================================ FILE: bootstrap/app.php ================================================ 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; ================================================ FILE: bootstrap/cache/.gitignore ================================================ * !.gitignore ================================================ FILE: composer.json ================================================ { "name": "laravel/laravel", "type": "project", "description": "A Laravel Vue SPA starter project", "keywords": ["spa", "laravel", "vue"], "license": "MIT", "require": { "php": "^8.2", "cjmellor/browser-sessions": "^1.3", "guzzlehttp/guzzle": "^7.2", "irabbi360/laravel-api-inspector": "^1.2", "laravel/framework": "^11.0", "laravel/sanctum": "^4.0", "laravel/tinker": "^2.9", "laravel/ui": "^4.2", "spatie/laravel-activitylog": "^4.9", "spatie/laravel-medialibrary": "^11.9.2", "spatie/laravel-permission": "^6.9" }, "require-dev": { "fakerphp/faker": "^1.23", "laravel/pint": "^1.13", "laravel/sail": "^1.26", "mockery/mockery": "^1.6", "nunomaduro/collision": "^8.1", "phpunit/phpunit": "^11.0.1", "spatie/laravel-ignition": "^2.0" }, "autoload": { "psr-4": { "App\\": "app/", "Database\\Factories\\": "database/factories/", "Database\\Seeders\\": "database/seeders/" } }, "autoload-dev": { "psr-4": { "Tests\\": "tests/" } }, "scripts": { "post-autoload-dump": [ "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", "@php artisan package:discover --ansi" ], "post-update-cmd": [ "@php artisan vendor:publish --tag=laravel-assets --ansi --force" ], "post-root-package-install": [ "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" ], "post-create-project-cmd": [ "@php artisan key:generate --ansi" ] }, "extra": { "laravel": { "dont-discover": [] } }, "config": { "optimize-autoloader": true, "preferred-install": "dist", "sort-packages": true, "allow-plugins": { "pestphp/pest-plugin": true } }, "minimum-stability": "stable", "prefer-stable": true } ================================================ FILE: config/activitylog.php ================================================ env('ACTIVITY_LOGGER_ENABLED', true), /* * When the clean-command is executed, all recording activity-log older than * the number of days specified here will be deleted. */ 'delete_records_older_than_days' => 365, /* * If no log name is passed to the activity-log() helper * we use this default log name. */ 'default_log_name' => 'default', /* * You can specify an auth driver here that gets user models. * If this is null we'll use the current Laravel auth driver. */ 'default_auth_driver' => null, /* * If set to true, the subject returns soft deleted models. */ 'subject_returns_soft_deleted_models' => false, /* * This model will be used to log activity-log. * It should implement the Spatie\Activitylog\Contracts\Activity interface * and extend Illuminate\Database\Eloquent\Model. */ 'activity_model' => \Spatie\Activitylog\Models\Activity::class, /* * This is the name of the table that will be created by the migration and * used by the Activity model shipped with this package. */ 'table_name' => env('ACTIVITY_LOGGER_TABLE_NAME', 'activity_log'), /* * This is the database connection that will be used by the migration and * the Activity model shipped with this package. In case it's not set * Laravel's database.default will be used instead. */ 'database_connection' => env('ACTIVITY_LOGGER_DB_CONNECTION'), ]; ================================================ FILE: config/api-inspector.php ================================================ 'Laravel API Inspector', 'enabled' => true, /* * Route where request docs will be served from laravel app. * localhost:8080/api-docs */ 'route_path' => 'api-docs', /* |-------------------------------------------------------------------------- | API Inspector Assets Path |-------------------------------------------------------------------------- | The path to the API Inspector assets. | */ 'assets_path' => 'vendor/api-inspector', 'output' => [ 'openapi' => true, 'postman' => true, 'html' => true, ], /* |-------------------------------------------------------------------------- | Response Capture Configuration |-------------------------------------------------------------------------- | Phase 2: Runtime response capture and caching | */ 'save_responses' => true, 'save_responses_driver' => 'json', // 'cache' or 'json' 'middleware_capture' => true, 'response_ttl' => 3600, // TTL for cached responses in seconds (1 hour) 'auth' => [ 'type' => 'bearer', 'header' => 'Authorization', ], 'response_path' => 'api-docs', // Subfolder name 'storage_path' => 'storage', // 'storage' or 'local' // Use only routes where ->uri start with next string Using Str::startWith( . e.g. - /api/mobile 'only_route_uri_start_with' => 'api/', 'hide_matching' => [ 'api-inspector-docs', 'api-inspector', 'sanctum', 'telescope', 'docs', '_ignition', ], // By default, LAPI groups your routes by the first /path. // This is a set of regex to group your routes by prefix. 'group_by' => [ 'uri_patterns' => [ '^api/v[\d]+/', // `/api/v1/users/store` group as `/api/v1/users`. '^api/', // `/api/users/store` group as `/api/users`. ], ], /* * Can be used to define default response status codes to be shown in the docs */ 'default_responses' => ['200', '400', '401', '403', '404', '405', '422', '429', '500', '503'], /* |-------------------------------------------------------------------------- | Pagination Schema |-------------------------------------------------------------------------- | Define the structure of pagination metadata when @LAPIpagination is used. | Matches Laravel's default pagination response structure. | */ 'pagination_schema' => [ 'data' => 'array', 'links' => [ 'first' => 'string', 'last' => 'string', 'prev' => 'string | null', 'next' => 'string | null', ], 'meta' => [ 'current_page' => 'integer', 'from' => 'integer | null', 'last_page' => 'integer', 'path' => 'string', 'per_page' => 'integer', 'to' => 'integer | null', 'total' => 'integer', 'links' => 'array', ], 'show_pagination' => ['links', 'meta'], ], /* |-------------------------------------------------------------------------- | Analytics, Dashboard, and Advanced Features |-------------------------------------------------------------------------- */ 'analytics' => [ 'enabled' => true, 'track_response_time' => true, 'track_memory_usage' => true, 'track_errors' => true, 'retention_days' => 30, // Keep analytics for 30 days 'track_only_uri_start_with' => 'api/', 'exclude_routes' => [ 'api-inspector-docs', 'api-inspector', 'sanctum', 'telescope', 'docs', '_ignition', ], ], 'dashboard' => [ 'enabled' => true, 'auth_middleware' => ['web'], // Middleware for dashboard protection ], 'webhooks' => [ // 'user.created' => [ // 'event' => 'user.created', // 'description' => 'Fired when a new user is created', // 'url' => 'https://example.com/webhooks/user/created', // 'method' => 'POST', // 'payload' => [ // 'id' => 'integer', // 'email' => 'string', // 'name' => 'string', // ], // 'examples' => [], // 'active' => true, // ], ], 'auth_testing' => [ 'enabled' => true, 'schemes' => ['bearer', 'api-key', 'basic', 'oauth2'], 'test_endpoint_prefix' => '/api/', ], ]; ================================================ FILE: config/app.php ================================================ env('APP_NAME', 'Laravel Vue 3 Stater'), /* |-------------------------------------------------------------------------- | 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'), 'asset_url' => env('ASSET_URL'), /* |-------------------------------------------------------------------------- | 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' => 'UTC', /* |-------------------------------------------------------------------------- | 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' => 'en', 'locales' => [ 'en' => 'EN', 'bn' => 'BN', 'es' => 'ES', 'fr' => 'FR', 'pt-BR' => 'BR', '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' => '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', /* |-------------------------------------------------------------------------- | Maintenance Mode Driver |-------------------------------------------------------------------------- | | These configuration options determine the driver used to determine and | manage Laravel's "maintenance mode" status. The "cache" driver will | allow maintenance mode to be controlled across multiple machines. | | Supported drivers: "file", "cache" | */ 'maintenance' => [ 'driver' => 'file', // 'store' => 'redis', ], /* |-------------------------------------------------------------------------- | 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\Broadcasting\BroadcastServiceProvider::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\Pipeline\PipelineServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class, Illuminate\Redis\RedisServiceProvider::class, Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, Illuminate\Session\SessionServiceProvider::class, Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, /* * Package Service Providers... */ /* * Application Service Providers... */ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::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' => Facade::defaultAliases()->merge([ // 'ExampleClass' => App\Example\ExampleClass::class, ])->toArray(), ]; ================================================ FILE: config/auth.php ================================================ [ '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" | */ 'guards' => [ 'web' => [ 'driver' => 'session', '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 each reset token will 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, 'throttle' => 60, ], ], /* |-------------------------------------------------------------------------- | Password Confirmation Timeout |-------------------------------------------------------------------------- | | Here you may define the amount of seconds before a password confirmation | times out and the user is prompted to re-enter their password via the | confirmation screen. By default, the timeout lasts for three hours. | */ 'password_timeout' => 10800, ]; ================================================ FILE: config/broadcasting.php ================================================ 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' => [ 'host' => env('PUSHER_HOST', 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com', 'port' => env('PUSHER_PORT', 443), 'scheme' => env('PUSHER_SCHEME', 'https'), 'encrypted' => true, 'useTLS' => env('PUSHER_SCHEME', 'https') === 'https', ], 'client_options' => [ // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html ], ], 'ably' => [ 'driver' => 'ably', 'key' => env('ABLY_KEY'), ], 'redis' => [ 'driver' => 'redis', 'connection' => 'default', ], 'log' => [ 'driver' => 'log', ], 'null' => [ 'driver' => 'null', ], ], ]; ================================================ FILE: config/browser-sessions.php ================================================ true, 'browser_session_guard' => env('BROWSER_SESSION_GUARD', 'web'), ]; ================================================ FILE: config/cache.php ================================================ 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. | | Supported drivers: "apc", "array", "database", "file", | "memcached", "redis", "dynamodb", "octane", "null" | */ 'stores' => [ 'apc' => [ 'driver' => 'apc', ], 'array' => [ 'driver' => 'array', 'serialize' => false, ], 'database' => [ 'driver' => 'database', 'table' => 'cache', 'connection' => null, 'lock_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', 'lock_connection' => 'default', ], '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'), ], 'octane' => [ 'driver' => 'octane', ], ], /* |-------------------------------------------------------------------------- | Cache Key Prefix |-------------------------------------------------------------------------- | | When utilizing the APC, database, memcached, Redis, or DynamoDB cache | stores there might be other applications using the same cache. For | that reason, you may prefix every cache key to avoid collisions. | */ 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'), ]; ================================================ FILE: config/cors.php ================================================ ['api/*', 'sanctum/csrf-cookie'], 'allowed_methods' => ['*'], 'allowed_origins' => ['*'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => false, ]; ================================================ FILE: config/database.php ================================================ 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' => '', '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' => '', 'prefix_indexes' => true, 'strict' => true, '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' => '', 'prefix_indexes' => true, 'search_path' => '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' => '', 'prefix_indexes' => true, // 'encrypt' => env('DB_ENCRYPT', 'yes'), // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), ], ], /* |-------------------------------------------------------------------------- | 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', 'laravel'), '_').'_database_'), ], 'default' => [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_DB', '0'), ], 'cache' => [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_CACHE_DB', '1'), ], ], ]; ================================================ FILE: config/filesystems.php ================================================ env('FILESYSTEM_DISK', 'local'), /* |-------------------------------------------------------------------------- | 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 set up for each driver as an example of the required values. | | Supported Drivers: "local", "ftp", "sftp", "s3" | */ 'disks' => [ 'local' => [ 'driver' => 'local', 'root' => storage_path('app'), 'throw' => false, ], 'public' => [ 'driver' => 'local', 'root' => storage_path('app/public'), 'url' => env('APP_URL').'/storage', 'visibility' => 'public', 'throw' => false, ], 's3' => [ 'driver' => 's3', 'key' => env('AWS_ACCESS_KEY_ID'), 'secret' => env('AWS_SECRET_ACCESS_KEY'), 'region' => env('AWS_DEFAULT_REGION'), 'bucket' => env('AWS_BUCKET'), 'url' => env('AWS_URL'), 'endpoint' => env('AWS_ENDPOINT'), 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), 'throw' => false, ], ], /* |-------------------------------------------------------------------------- | Symbolic Links |-------------------------------------------------------------------------- | | Here you may configure the symbolic links that will be created when the | `storage:link` Artisan command is executed. The array keys should be | the locations of the links and the values should be their targets. | */ 'links' => [ public_path('storage') => storage_path('app/public'), ], ]; ================================================ FILE: config/hashing.php ================================================ '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' => 65536, 'threads' => 1, 'time' => 4, ], ]; ================================================ FILE: config/logging.php ================================================ env('LOG_CHANNEL', 'stack'), /* |-------------------------------------------------------------------------- | Deprecations Log Channel |-------------------------------------------------------------------------- | | This option controls the log channel that should be used to log warnings | regarding deprecated PHP and library features. This allows you to get | your application ready for upcoming major versions of dependencies. | */ 'deprecations' => [ 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), 'trace' => false, ], /* |-------------------------------------------------------------------------- | 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' => env('LOG_LEVEL', 'debug'), ], 'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => env('LOG_LEVEL', 'debug'), 'days' => 14, ], 'slack' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel Log', 'emoji' => ':boom:', 'level' => env('LOG_LEVEL', 'critical'), ], 'papertrail' => [ 'driver' => 'monolog', 'level' => env('LOG_LEVEL', 'debug'), 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), 'handler_with' => [ 'host' => env('PAPERTRAIL_URL'), 'port' => env('PAPERTRAIL_PORT'), 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), ], ], 'stderr' => [ 'driver' => 'monolog', 'level' => env('LOG_LEVEL', 'debug'), 'handler' => StreamHandler::class, 'formatter' => env('LOG_STDERR_FORMATTER'), 'with' => [ 'stream' => 'php://stderr', ], ], 'syslog' => [ 'driver' => 'syslog', 'level' => env('LOG_LEVEL', 'debug'), ], 'errorlog' => [ 'driver' => 'errorlog', 'level' => env('LOG_LEVEL', 'debug'), ], 'null' => [ 'driver' => 'monolog', 'handler' => NullHandler::class, ], 'emergency' => [ 'path' => storage_path('logs/laravel.log'), ], ], ]; ================================================ FILE: config/mail.php ================================================ 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", "failover" | */ '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'), 'timeout' => null, 'local_domain' => env('MAIL_EHLO_DOMAIN'), ], 'ses' => [ 'transport' => 'ses', ], 'mailgun' => [ 'transport' => 'mailgun', ], 'postmark' => [ 'transport' => 'postmark', ], 'sendmail' => [ 'transport' => 'sendmail', 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), ], 'log' => [ 'transport' => 'log', 'channel' => env('MAIL_LOG_CHANNEL'), ], 'array' => [ 'transport' => 'array', ], 'failover' => [ 'transport' => 'failover', 'mailers' => [ 'smtp', 'log', ], ], ], /* |-------------------------------------------------------------------------- | 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'), ], ], ]; ================================================ FILE: config/media-library.php ================================================ env('MEDIA_DISK', 'public'), /* * The maximum file size of an item in bytes. * Adding a larger file will result in an exception. */ 'max_file_size' => 1024 * 1024 * 10, // 10MB /* * This queue connection will be used to generate derived and responsive images. * Leave empty to use the default queue connection. */ 'queue_connection_name' => env('QUEUE_CONNECTION', 'sync'), /* * This queue will be used to generate derived and responsive images. * Leave empty to use the default queue. */ 'queue_name' => '', /* * By default all conversions will be performed on a queue. */ 'queue_conversions_by_default' => env('QUEUE_CONVERSIONS_BY_DEFAULT', true), /* * The fully qualified class name of the media model. */ 'media_model' => Spatie\MediaLibrary\MediaCollections\Models\Media::class, /* * When enabled, media collections will be serialised using the default * laravel model serialization behaviour. * * Keep this option disabled if using Media Library Pro components (https://medialibrary.pro) */ 'use_default_collection_serialization' => false, /* * The fully qualified class name of the model used for temporary uploads. * * This model is only used in Media Library Pro (https://medialibrary.pro) */ 'temporary_upload_model' => Spatie\MediaLibraryPro\Models\TemporaryUpload::class, /* * When enabled, Media Library Pro will only process temporary uploads that were uploaded * in the same session. You can opt to disable this for stateless usage of * the pro components. */ 'enable_temporary_uploads_session_affinity' => true, /* * When enabled, Media Library pro will generate thumbnails for uploaded file. */ 'generate_thumbnails_for_temporary_uploads' => true, /* * This is the class that is responsible for naming generated files. */ 'file_namer' => Spatie\MediaLibrary\Support\FileNamer\DefaultFileNamer::class, /* * The class that contains the strategy for determining a media file's path. */ 'path_generator' => Spatie\MediaLibrary\Support\PathGenerator\DefaultPathGenerator::class, /* * Here you can specify which path generator should be used for the given class. */ 'custom_path_generators' => [ // Model::class => PathGenerator::class // or // 'model_morph_alias' => PathGenerator::class ], /* * When urls to files get generated, this class will be called. Use the default * if your files are stored locally above the site root or on s3. */ 'url_generator' => Spatie\MediaLibrary\Support\UrlGenerator\DefaultUrlGenerator::class, /* * Moves media on updating to keep path consistent. Enable it only with a custom * PathGenerator that uses, for example, the media UUID. */ 'moves_media_on_update' => false, /* * Whether to activate versioning when urls to files get generated. * When activated, this attaches a ?v=xx query string to the URL. */ 'version_urls' => false, /* * The media library will try to optimize all converted images by removing * metadata and applying a little bit of compression. These are * the optimizers that will be used by default. */ 'image_optimizers' => [ Spatie\ImageOptimizer\Optimizers\Jpegoptim::class => [ '-m85', // set maximum quality to 85% '--force', // ensure that progressive generation is always done also if a little bigger '--strip-all', // this strips out all text information such as comments and EXIF data '--all-progressive', // this will make sure the resulting image is a progressive one ], Spatie\ImageOptimizer\Optimizers\Pngquant::class => [ '--force', // required parameter for this package ], Spatie\ImageOptimizer\Optimizers\Optipng::class => [ '-i0', // this will result in a non-interlaced, progressive scanned image '-o2', // this set the optimization level to two (multiple IDAT compression trials) '-quiet', // required parameter for this package ], Spatie\ImageOptimizer\Optimizers\Svgo::class => [ '--disable=cleanupIDs', // disabling because it is known to cause troubles ], Spatie\ImageOptimizer\Optimizers\Gifsicle::class => [ '-b', // required parameter for this package '-O3', // this produces the slowest but best results ], Spatie\ImageOptimizer\Optimizers\Cwebp::class => [ '-m 6', // for the slowest compression method in order to get the best compression. '-pass 10', // for maximizing the amount of analysis pass. '-mt', // multithreading for some speed improvements. '-q 90', //quality factor that brings the least noticeable changes. ], Spatie\ImageOptimizer\Optimizers\Avifenc::class => [ '-a cq-level=23', // constant quality level, lower values mean better quality and greater file size (0-63). '-j all', // number of jobs (worker threads, "all" uses all available cores). '--min 0', // min quantizer for color (0-63). '--max 63', // max quantizer for color (0-63). '--minalpha 0', // min quantizer for alpha (0-63). '--maxalpha 63', // max quantizer for alpha (0-63). '-a end-usage=q', // rate control mode set to Constant Quality mode. '-a tune=ssim', // SSIM as tune the encoder for distortion metric. ], ], /* * These generators will be used to create an image of media files. */ 'image_generators' => [ Spatie\MediaLibrary\Conversions\ImageGenerators\Image::class, Spatie\MediaLibrary\Conversions\ImageGenerators\Webp::class, Spatie\MediaLibrary\Conversions\ImageGenerators\Avif::class, Spatie\MediaLibrary\Conversions\ImageGenerators\Pdf::class, Spatie\MediaLibrary\Conversions\ImageGenerators\Svg::class, Spatie\MediaLibrary\Conversions\ImageGenerators\Video::class, ], /* * The path where to store temporary files while performing image conversions. * If set to null, storage_path('media-library/temp') will be used. */ 'temporary_directory_path' => null, /* * The engine that should perform the image conversions. * Should be either `gd` or `imagick`. */ 'image_driver' => env('IMAGE_DRIVER', 'gd'), /* * FFMPEG & FFProbe binaries paths, only used if you try to generate video * thumbnails and have installed the php-ffmpeg/php-ffmpeg composer * dependency. */ 'ffmpeg_path' => env('FFMPEG_PATH', '/usr/bin/ffmpeg'), 'ffprobe_path' => env('FFPROBE_PATH', '/usr/bin/ffprobe'), /* * Here you can override the class names of the jobs used by this package. Make sure * your custom jobs extend the ones provided by the package. */ 'jobs' => [ 'perform_conversions' => Spatie\MediaLibrary\Conversions\Jobs\PerformConversionsJob::class, 'generate_responsive_images' => Spatie\MediaLibrary\ResponsiveImages\Jobs\GenerateResponsiveImagesJob::class, ], /* * When using the addMediaFromUrl method you may want to replace the default downloader. * This is particularly useful when the url of the image is behind a firewall and * need to add additional flags, possibly using curl. */ 'media_downloader' => Spatie\MediaLibrary\Downloaders\DefaultDownloader::class, 'remote' => [ /* * Any extra headers that should be included when uploading media to * a remote disk. Even though supported headers may vary between * different drivers, a sensible default has been provided. * * Supported by S3: CacheControl, Expires, StorageClass, * ServerSideEncryption, Metadata, ACL, ContentEncoding */ 'extra_headers' => [ 'CacheControl' => 'max-age=604800', ], ], 'responsive_images' => [ /* * This class is responsible for calculating the target widths of the responsive * images. By default we optimize for filesize and create variations that each are 30% * smaller than the previous one. More info in the documentation. * * https://docs.spatie.be/laravel-medialibrary/v9/advanced-usage/generating-responsive-images */ 'width_calculator' => Spatie\MediaLibrary\ResponsiveImages\WidthCalculator\FileSizeOptimizedWidthCalculator::class, /* * By default rendering media to a responsive image will add some javascript and a tiny placeholder. * This ensures that the browser can already determine the correct layout. */ 'use_tiny_placeholders' => true, /* * This class will generate the tiny placeholder used for progressive image loading. By default * the media library will use a tiny blurred jpg image. */ 'tiny_placeholder_generator' => Spatie\MediaLibrary\ResponsiveImages\TinyPlaceholderGenerator\Blurred::class, ], /* * When enabling this option, a route will be registered that will enable * the Media Library Pro Vue and React components to move uploaded files * in a S3 bucket to their right place. */ 'enable_vapor_uploads' => env('ENABLE_MEDIA_LIBRARY_VAPOR_UPLOADS', false), /* * When converting Media instances to response the media library will add * a `loading` attribute to the `img` tag. Here you can set the default * value of that attribute. * * Possible values: 'lazy', 'eager', 'auto' or null if you don't want to set any loading instruction. * * More info: https://css-tricks.com/native-lazy-loading/ */ 'default_loading_attribute_value' => null, /* * You can specify a prefix for that is used for storing all media. * If you set this to `/my-subdir`, all your media will be stored in a `/my-subdir` directory. */ 'prefix' => env('MEDIA_PREFIX', ''), ]; ================================================ FILE: config/permission.php ================================================ [ /* * When using the "HasPermissions" trait from this package, we need to know which * Eloquent model should be used to retrieve your permissions. Of course, it * is often just the "Permission" model but you may use whatever you like. * * The model you want to use as a Permission model needs to implement the * `Spatie\Permission\Contracts\Permission` contract. */ 'permission' => Spatie\Permission\Models\Permission::class, /* * When using the "HasRoles" trait from this package, we need to know which * Eloquent model should be used to retrieve your roles. Of course, it * is often just the "Role" model but you may use whatever you like. * * The model you want to use as a Role model needs to implement the * `Spatie\Permission\Contracts\Role` contract. */ 'role' => Spatie\Permission\Models\Role::class, ], 'table_names' => [ /* * When using the "HasRoles" trait from this package, we need to know which * table should be used to retrieve your roles. We have chosen a basic * default value but you may easily change it to any table you like. */ 'roles' => 'roles', /* * When using the "HasPermissions" trait from this package, we need to know which * table should be used to retrieve your permissions. We have chosen a basic * default value but you may easily change it to any table you like. */ 'permissions' => 'permissions', /* * When using the "HasPermissions" trait from this package, we need to know which * table should be used to retrieve your models permissions. We have chosen a * basic default value but you may easily change it to any table you like. */ 'model_has_permissions' => 'model_has_permissions', /* * When using the "HasRoles" trait from this package, we need to know which * table should be used to retrieve your models roles. We have chosen a * basic default value but you may easily change it to any table you like. */ 'model_has_roles' => 'model_has_roles', /* * When using the "HasRoles" trait from this package, we need to know which * table should be used to retrieve your roles permissions. We have chosen a * basic default value but you may easily change it to any table you like. */ 'role_has_permissions' => 'role_has_permissions', ], 'column_names' => [ /* * Change this if you want to name the related pivots other than defaults */ 'role_pivot_key' => null, //default 'role_id', 'permission_pivot_key' => null, //default 'permission_id', /* * Change this if you want to name the related model primary key other than * `model_id`. * * For example, this would be nice if your primary keys are all UUIDs. In * that case, name this `model_uuid`. */ 'model_morph_key' => 'model_id', /* * Change this if you want to use the teams feature and your related model's * foreign key is other than `team_id`. */ 'team_foreign_key' => 'team_id', ], /* * When set to true, the method for checking permissions will be registered on the gate. * Set this to false, if you want to implement custom logic for checking permissions. */ 'register_permission_check_method' => true, /* * When set to true the package implements teams using the 'team_foreign_key'. If you want * the migrations to register the 'team_foreign_key', you must set this to true * before doing the migration. If you already did the migration then you must make a new * migration to also add 'team_foreign_key' to 'roles', 'model_has_roles', and * 'model_has_permissions'(view the latest version of package's migration file) */ 'teams' => false, /* * When set to true, the required permission names are added to the exception * message. This could be considered an information leak in some contexts, so * the default setting is false here for optimum safety. */ 'display_permission_in_exception' => false, /* * When set to true, the required role names are added to the exception * message. This could be considered an information leak in some contexts, so * the default setting is false here for optimum safety. */ 'display_role_in_exception' => false, /* * By default wildcard permission lookups are disabled. */ 'enable_wildcard_permission' => false, 'cache' => [ /* * By default all permissions are cached for 24 hours to speed up performance. * When permissions or roles are updated the cache is flushed automatically. */ 'expiration_time' => \DateInterval::createFromDateString('24 hours'), /* * The cache key used to store all permissions. */ 'key' => 'spatie.permission.cache', /* * You may optionally indicate a specific cache driver to use for permission and * role caching using any of the `store` drivers listed in the cache.php config * file. Using 'default' here means to use the `default` set in cache.php. */ 'store' => 'default', ], ]; ================================================ FILE: config/queue.php ================================================ 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, 'after_commit' => false, ], 'beanstalkd' => [ 'driver' => 'beanstalkd', 'host' => 'localhost', 'queue' => 'default', 'retry_after' => 90, 'block_for' => 0, 'after_commit' => false, ], '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', 'default'), 'suffix' => env('SQS_SUFFIX'), 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 'after_commit' => false, ], 'redis' => [ 'driver' => 'redis', 'connection' => 'default', 'queue' => env('REDIS_QUEUE', 'default'), 'retry_after' => 90, 'block_for' => null, 'after_commit' => false, ], ], /* |-------------------------------------------------------------------------- | 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-uuids'), 'database' => env('DB_CONNECTION', 'mysql'), 'table' => 'failed_jobs', ], ]; ================================================ FILE: config/sanctum.php ================================================ explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( '%s%s', 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', Sanctum::currentApplicationUrlWithPort() ))), /* |-------------------------------------------------------------------------- | Sanctum Guards |-------------------------------------------------------------------------- | | This array contains the authentication guards that will be checked when | Sanctum is trying to authenticate a request. If none of these guards | are able to authenticate the request, Sanctum will use the bearer | token that's present on an incoming request for authentication. | */ 'guard' => ['web'], /* |-------------------------------------------------------------------------- | Expiration Minutes |-------------------------------------------------------------------------- | | This value controls the number of minutes until an issued token will be | considered expired. If this value is null, personal access tokens do | not expire. This won't tweak the lifetime of first-party sessions. | */ 'expiration' => null, /* |-------------------------------------------------------------------------- | Token Prefix |-------------------------------------------------------------------------- | | Sanctum can prefix new tokens in order to take advantage of numerous | security scanning initiatives maintained by open source platforms | that notify developers if they commit tokens into repositories. | | See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning | */ 'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''), /* |-------------------------------------------------------------------------- | Sanctum Middleware |-------------------------------------------------------------------------- | | When authenticating your first-party SPA with Sanctum you may need to | customize some of the middleware Sanctum uses while processing the | request. You may change the middleware listed below as required. | */ 'middleware' => [ 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, 'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class, 'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, ], ]; ================================================ FILE: config/services.php ================================================ [ 'domain' => env('MAILGUN_DOMAIN'), 'secret' => env('MAILGUN_SECRET'), 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), 'scheme' => 'https', ], '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'), ], ]; ================================================ FILE: config/session.php ================================================ 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'), /* |-------------------------------------------------------------------------- | 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 |-------------------------------------------------------------------------- | | While using one of the framework's cache driven session backends 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". | | Affects: "apc", "dynamodb", "memcached", "redis" | */ 'store' => env('SESSION_STORE'), /* |-------------------------------------------------------------------------- | 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', Str::slug(env('APP_NAME', 'laravel'), '_').'_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'), /* |-------------------------------------------------------------------------- | 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 when it can't 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 | will set this value to "lax" since this is a secure default value. | | Supported: "lax", "strict", "none", null | */ 'same_site' => 'lax', ]; ================================================ FILE: config/view.php ================================================ [ 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')) ), ]; ================================================ FILE: database/.gitignore ================================================ *.sqlite* ================================================ FILE: database/factories/UserFactory.php ================================================ */ class UserFactory extends Factory { /** * Define the model's default state. * * @return array */ public function definition() { return [ 'name' => fake()->name(), 'email' => fake()->unique()->safeEmail(), 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 'remember_token' => Str::random(10), ]; } /** * Indicate that the model's email address should be unverified. * * @return static */ public function unverified() { return $this->state(fn (array $attributes) => [ 'email_verified_at' => null, ]); } } ================================================ FILE: database/migrations/2014_10_12_000000_create_users_table.php ================================================ id(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('users'); } }; ================================================ FILE: database/migrations/2014_10_12_100000_create_password_resets_table.php ================================================ string('email')->index(); $table->string('token'); $table->timestamp('created_at')->nullable(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('password_resets'); } }; ================================================ FILE: database/migrations/2019_08_19_000000_create_failed_jobs_table.php ================================================ id(); $table->string('uuid')->unique(); $table->text('connection'); $table->text('queue'); $table->longText('payload'); $table->longText('exception'); $table->timestamp('failed_at')->useCurrent(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('failed_jobs'); } }; ================================================ FILE: database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php ================================================ id(); $table->morphs('tokenable'); $table->string('name'); $table->string('token', 64)->unique(); $table->text('abilities')->nullable(); $table->timestamp('last_used_at')->nullable(); $table->timestamp('expires_at')->nullable(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('personal_access_tokens'); } }; ================================================ FILE: database/migrations/2022_09_30_181156_create_posts_table.php ================================================ id(); $table->string('title'); $table->unsignedBigInteger('user_id'); $table->longText('content'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('posts'); } }; ================================================ FILE: database/migrations/2022_09_30_181227_create_categories_table.php ================================================ id(); $table->string('name'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('categories'); } }; ================================================ FILE: database/migrations/2023_09_25_045349_create_jobs_table.php ================================================ 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'); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('jobs'); } }; ================================================ FILE: database/migrations/2023_10_02_010617_create_category_post_table.php ================================================ unsignedBigInteger('category_id'); $table->unsignedBigInteger('post_id'); $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade'); $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade'); $table->primary(['category_id', 'post_id']); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('category_post'); } }; ================================================ FILE: database/migrations/2023_10_02_175025_create_media_table.php ================================================ id(); $table->morphs('model'); $table->uuid('uuid')->nullable()->unique(); $table->string('collection_name'); $table->string('name'); $table->string('file_name'); $table->string('mime_type')->nullable(); $table->string('disk'); $table->string('conversions_disk')->nullable(); $table->unsignedBigInteger('size'); $table->json('manipulations'); $table->json('custom_properties'); $table->json('generated_conversions'); $table->json('responsive_images'); $table->unsignedInteger('order_column')->nullable()->index(); $table->nullableTimestamps(); }); } }; ================================================ FILE: database/migrations/2024_11_25_022836_create_permission_tables.php ================================================ engine('InnoDB'); $table->bigIncrements('id'); // permission id $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) $table->string('guard_name'); // For MyISAM use string('guard_name', 25); $table->timestamps(); $table->unique(['name', 'guard_name']); }); Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) { //$table->engine('InnoDB'); $table->bigIncrements('id'); // role id if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable(); $table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index'); } $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) $table->string('guard_name'); // For MyISAM use string('guard_name', 25); $table->timestamps(); if ($teams || config('permission.testing')) { $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']); } else { $table->unique(['name', 'guard_name']); } }); Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) { $table->unsignedBigInteger($pivotPermission); $table->string('model_type'); $table->unsignedBigInteger($columnNames['model_morph_key']); $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index'); $table->foreign($pivotPermission) ->references('id') // permission id ->on($tableNames['permissions']) ->onDelete('cascade'); if ($teams) { $table->unsignedBigInteger($columnNames['team_foreign_key']); $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index'); $table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_permission_model_type_primary'); } else { $table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_permission_model_type_primary'); } }); Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) { $table->unsignedBigInteger($pivotRole); $table->string('model_type'); $table->unsignedBigInteger($columnNames['model_morph_key']); $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index'); $table->foreign($pivotRole) ->references('id') // role id ->on($tableNames['roles']) ->onDelete('cascade'); if ($teams) { $table->unsignedBigInteger($columnNames['team_foreign_key']); $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index'); $table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'], 'model_has_roles_role_model_type_primary'); } else { $table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'], 'model_has_roles_role_model_type_primary'); } }); Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) { $table->unsignedBigInteger($pivotPermission); $table->unsignedBigInteger($pivotRole); $table->foreign($pivotPermission) ->references('id') // permission id ->on($tableNames['permissions']) ->onDelete('cascade'); $table->foreign($pivotRole) ->references('id') // role id ->on($tableNames['roles']) ->onDelete('cascade'); $table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary'); }); app('cache') ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null) ->forget(config('permission.cache.key')); } /** * Reverse the migrations. */ public function down(): void { $tableNames = config('permission.table_names'); if (empty($tableNames)) { throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.'); } Schema::drop($tableNames['role_has_permissions']); Schema::drop($tableNames['model_has_roles']); Schema::drop($tableNames['model_has_permissions']); Schema::drop($tableNames['roles']); Schema::drop($tableNames['permissions']); } }; ================================================ FILE: database/migrations/2025_01_22_091913_create_sessions_table.php ================================================ string('id')->primary(); $table->foreignId('user_id')->nullable()->index(); $table->string('ip_address', 45)->nullable(); $table->text('user_agent')->nullable(); $table->longText('payload'); $table->integer('last_activity')->index(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('sessions'); } }; ================================================ FILE: database/migrations/2025_01_23_093055_create_activity_log_table.php ================================================ create(config('activitylog.table_name'), function (Blueprint $table) { $table->bigIncrements('id'); $table->string('log_name')->nullable(); $table->text('description'); $table->nullableMorphs('subject', 'subject'); $table->nullableMorphs('causer', 'causer'); $table->json('properties')->nullable(); $table->timestamps(); $table->index('log_name'); }); } public function down() { Schema::connection(config('activitylog.database_connection'))->dropIfExists(config('activitylog.table_name')); } } ================================================ FILE: database/migrations/2025_01_23_093056_add_event_column_to_activity_log_table.php ================================================ table(config('activitylog.table_name'), function (Blueprint $table) { $table->string('event')->nullable()->after('subject_type'); }); } public function down() { Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) { $table->dropColumn('event'); }); } } ================================================ FILE: database/migrations/2025_01_23_093057_add_batch_uuid_column_to_activity_log_table.php ================================================ table(config('activitylog.table_name'), function (Blueprint $table) { $table->uuid('batch_uuid')->nullable()->after('properties'); }); } public function down() { Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) { $table->dropColumn('batch_uuid'); }); } } ================================================ FILE: database/migrations/2026_01_05_114017_create_api_inspector_analytics_table.php ================================================ id(); $table->string('route')->index(); $table->string('method'); $table->string('uri'); $table->unsignedInteger('status_code'); $table->float('duration_ms')->default(0); $table->bigInteger('memory_usage')->default(0); $table->ipAddress('ip_address')->nullable(); $table->text('user_agent')->nullable(); $table->text('error')->nullable(); $table->timestamp('recorded_at')->index(); $table->timestamps(); // Indexes for common queries $table->index(['route', 'recorded_at']); $table->index(['status_code', 'recorded_at']); $table->index(['created_at']); }); } public function down(): void { Schema::dropIfExists('api_inspector_analytics'); } }; ================================================ FILE: database/seeders/CreateAdminUserSeeder.php ================================================ 'Fazle', 'email' => 'admin@demo.com', 'password' => bcrypt('12345678') ]); $role = Role::create(['name' => 'admin']); $role2 = Role::create(['name' => 'user']); $permissions = [ 'post-list', 'post-create', 'post-edit', 'post-delete' ]; $role2->syncPermissions($permissions); Category::create(['name' => 'Vue.js']); Category::create(['name' => 'Cat 2']); $permissions = Permission::pluck('id','id')->all(); $role->syncPermissions($permissions); $user->assignRole([$role->id]); } } ================================================ FILE: database/seeders/DatabaseSeeder.php ================================================ call(PermissionTableSeeder::class); $this->call(CreateAdminUserSeeder::class); // $this->call(RoleSeeder::class); // \App\Models\User::factory(10)->create(); // \App\Models\User::factory()->create([ // 'name' => 'Test User', // 'email' => 'test@example.com', // ]); } } ================================================ FILE: database/seeders/PermissionTableSeeder.php ================================================ $permission]); } } } ================================================ FILE: lang/en/auth.php ================================================ 'These credentials do not match our records.', 'password' => 'The provided password is incorrect.', 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', ]; ================================================ FILE: lang/en/pagination.php ================================================ '« Previous', 'next' => 'Next »', ]; ================================================ FILE: lang/en/passwords.php ================================================ 'Your password has been reset!', 'sent' => 'We have emailed your password reset link!', 'throttled' => 'Please wait before retrying.', 'token' => 'This password reset token is invalid.', 'user' => "We can't find a user with that email address.", ]; ================================================ FILE: lang/en/validation.php ================================================ 'The :attribute must be accepted.', 'accepted_if' => 'The :attribute must be accepted when :other is :value.', '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 must only contain letters.', 'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.', 'alpha_num' => 'The :attribute must 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' => [ 'array' => 'The :attribute must have between :min and :max items.', 'file' => 'The :attribute must be between :min and :max kilobytes.', 'numeric' => 'The :attribute must be between :min and :max.', 'string' => 'The :attribute must be between :min and :max characters.', ], 'boolean' => 'The :attribute field must be true or false.', 'confirmed' => 'The :attribute confirmation does not match.', 'current_password' => 'The password is incorrect.', '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.', 'declined' => 'The :attribute must be declined.', 'declined_if' => 'The :attribute must be declined when :other is :value.', '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.', 'doesnt_end_with' => 'The :attribute may not end with one of the following: :values.', 'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.', 'email' => 'The :attribute must be a valid email address.', 'ends_with' => 'The :attribute must end with one of the following: :values.', 'enum' => 'The selected :attribute is invalid.', 'exists' => 'The selected :attribute is invalid.', 'file' => 'The :attribute must be a file.', 'filled' => 'The :attribute field must have a value.', 'gt' => [ 'array' => 'The :attribute must have more than :value items.', 'file' => 'The :attribute must be greater than :value kilobytes.', 'numeric' => 'The :attribute must be greater than :value.', 'string' => 'The :attribute must be greater than :value characters.', ], 'gte' => [ 'array' => 'The :attribute must have :value items or more.', 'file' => 'The :attribute must be greater than or equal to :value kilobytes.', 'numeric' => 'The :attribute must be greater than or equal to :value.', 'string' => 'The :attribute must be greater than or equal to :value characters.', ], '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' => [ 'array' => 'The :attribute must have less than :value items.', 'file' => 'The :attribute must be less than :value kilobytes.', 'numeric' => 'The :attribute must be less than :value.', 'string' => 'The :attribute must be less than :value characters.', ], 'lte' => [ 'array' => 'The :attribute must not have more than :value items.', 'file' => 'The :attribute must be less than or equal to :value kilobytes.', 'numeric' => 'The :attribute must be less than or equal to :value.', 'string' => 'The :attribute must be less than or equal to :value characters.', ], 'mac_address' => 'The :attribute must be a valid MAC address.', 'max' => [ 'array' => 'The :attribute must not have more than :max items.', 'file' => 'The :attribute must not be greater than :max kilobytes.', 'numeric' => 'The :attribute must not be greater than :max.', 'string' => 'The :attribute must not be greater than :max characters.', ], 'max_digits' => 'The :attribute must not have more than :max digits.', 'mimes' => 'The :attribute must be a file of type: :values.', 'mimetypes' => 'The :attribute must be a file of type: :values.', 'min' => [ 'array' => 'The :attribute must have at least :min items.', 'file' => 'The :attribute must be at least :min kilobytes.', 'numeric' => 'The :attribute must be at least :min.', 'string' => 'The :attribute must be at least :min characters.', ], 'min_digits' => 'The :attribute must have at least :min digits.', 'multiple_of' => 'The :attribute must be a multiple of :value.', 'not_in' => 'The selected :attribute is invalid.', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => 'The :attribute must be a number.', 'password' => [ 'letters' => 'The :attribute must contain at least one letter.', 'mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.', 'numbers' => 'The :attribute must contain at least one number.', 'symbols' => 'The :attribute must contain at least one symbol.', 'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.', ], 'present' => 'The :attribute field must be present.', 'prohibited' => 'The :attribute field is prohibited.', 'prohibited_if' => 'The :attribute field is prohibited when :other is :value.', 'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.', 'prohibits' => 'The :attribute field prohibits :other from being present.', 'regex' => 'The :attribute format is invalid.', 'required' => 'The :attribute field is required.', 'required_array_keys' => 'The :attribute field must contain entries for: :values.', 'required_if' => 'The :attribute field is required when :other is :value.', 'required_if_accepted' => 'The :attribute field is required when :other is accepted.', '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' => [ 'array' => 'The :attribute must contain :size items.', 'file' => 'The :attribute must be :size kilobytes.', 'numeric' => 'The :attribute must be :size.', 'string' => 'The :attribute must be :size characters.', ], '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 timezone.', 'unique' => 'The :attribute has already been taken.', 'uploaded' => 'The :attribute failed to upload.', 'url' => 'The :attribute must be a valid URL.', '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 our attribute placeholder | with something more reader friendly such as "E-Mail Address" instead | of "email". This simply helps us make our message more expressive. | */ 'attributes' => [], ]; ================================================ FILE: package.json ================================================ { "private": true, "type": "module", "scripts": { "dev": "vite", "build": "vite build" }, "devDependencies": { "@popperjs/core": "^2.11.8", "@vitejs/plugin-vue": "^4.3.4", "axios": "^1.7.4", "concurrently": "^9.0.1", "bootstrap": "^5.3.2", "laravel-vite-plugin": "^1.0", "lodash": "^4.17.21", "postcss": "^8.4.30", "sass": "^1.68.0", "vite": "^5.0", "vue": "^3.5.11" }, "dependencies": { "@casl/ability": "^6.5.0", "@casl/vue": "^2.2.1", "@ckeditor/ckeditor5-build-classic": "^40.0.0", "@ckeditor/ckeditor5-vue": "^5.1.0", "js-cookie": "^3.0.5", "laravel-vue-pagination": "^4.1.1", "pinia": "^2.2.4", "pinia-plugin-persistedstate": "^3.2.1", "vee-validate": "^4.11.7", "vue-i18n": "^9.4.1", "vue-multiselect-listbox": "^0.4.5", "vue-router": "^4.2.5", "vue-select": "^4.0.0-beta.5", "vue-sweetalert2": "^5.0.11" } } ================================================ FILE: phpunit.xml ================================================ ./tests/Unit ./tests/Feature ./app ================================================ FILE: public/.htaccess ================================================ Options -MultiViews -Indexes RewriteEngine On # Handle Authorization Header RewriteCond %{HTTP:Authorization} . RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] # Redirect Trailing Slashes If Not A Folder... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} (.+)/$ RewriteRule ^ %1 [L,R=301] # Send Requests To Front Controller... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L] ================================================ FILE: public/index.php ================================================ make(Kernel::class); $response = $kernel->handle( $request = Request::capture() )->send(); $kernel->terminate($request, $response); ================================================ FILE: public/robots.txt ================================================ User-agent: * Disallow: ================================================ FILE: public/vendor/api-inspector/.vite/manifest.json ================================================ { "resources/js/app.js": { "file": "js/app.js", "name": "app", "src": "resources/js/app.js", "isEntry": true, "css": [ "css/app.css" ] } } ================================================ FILE: public/vendor/api-inspector/css/app.css ================================================ .topbar[data-v-0325c2e2]{background:#1e1e1e;border-bottom:1px solid #3e3e42;position:sticky;top:0;z-index:100}.topbar-top[data-v-0325c2e2]{max-width:1400px;margin:0 auto;padding:16px 20px;display:flex;align-items:center;justify-content:space-between;gap:30px;min-height:70px}.api-branding[data-v-0325c2e2]{display:flex;align-items:center;gap:15px;flex-shrink:0}.api-title[data-v-0325c2e2]{color:#fff;font-size:1.4em;font-weight:600;display:flex;align-items:center;gap:12px;margin:0}.github-link[data-v-0325c2e2]{display:inline-flex;align-items:center;transition:opacity .2s;flex-shrink:0}.github-link[data-v-0325c2e2]:hover{opacity:.8}.github-link svg[data-v-0325c2e2]{width:28px;height:28px}.api-version[data-v-0325c2e2]{color:#999;font-size:.85em;white-space:nowrap}.version-badge[data-v-0325c2e2]{background:#06c;color:#fff;padding:4px 10px;border-radius:3px;font-size:.8em;margin-left:8px;font-weight:600}.topbar-controls[data-v-0325c2e2]{display:flex;gap:12px;align-items:center;flex-shrink:0}.btn-auth[data-v-0325c2e2]{background:#ff9800;padding:10px}.btn-auth[data-v-0325c2e2]:hover{background:#d28006}.btn-auth.authenticated[data-v-0325c2e2]{background:#49cc90}.auth-modal-overlay[data-v-0325c2e2]{position:fixed;inset:0;background:#000000b3;display:flex;align-items:center;justify-content:center;z-index:2000;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.auth-modal[data-v-0325c2e2]{background:#252526;border:1px solid #3e3e42;border-radius:8px;box-shadow:0 20px 60px #00000080;width:100%;max-width:500px;max-height:90vh;overflow-y:auto;animation:modalSlideIn-0325c2e2 .3s ease-out}@keyframes modalSlideIn-0325c2e2{0%{opacity:0;transform:translateY(-20px)}to{opacity:1;transform:translateY(0)}}.auth-modal-header[data-v-0325c2e2]{padding:24px;border-bottom:1px solid #3e3e42;display:flex;justify-content:space-between;align-items:center}.auth-modal-header h3[data-v-0325c2e2]{color:#fff;font-size:1.3em;margin:0;font-weight:600}.btn-modal-close[data-v-0325c2e2]{background:none;border:none;color:#999;font-size:24px;cursor:pointer;padding:0;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all .2s}.btn-modal-close[data-v-0325c2e2]:hover{background:#3e3e42;color:#fff}.auth-modal-body[data-v-0325c2e2]{padding:24px}.auth-method-selector[data-v-0325c2e2]{margin-bottom:24px}.auth-method-label[data-v-0325c2e2]{display:block;color:#fff;font-weight:600;font-size:14px;margin-bottom:12px}.auth-method-options[data-v-0325c2e2]{display:flex;gap:16px}.auth-method-option[data-v-0325c2e2]{display:flex;align-items:center;gap:8px;color:#ccc;cursor:pointer;font-size:14px;flex:1}.auth-method-option input[type=radio][data-v-0325c2e2]{cursor:pointer;width:16px;height:16px}.auth-method-option[data-v-0325c2e2]:hover{color:#fff}.auth-input-section[data-v-0325c2e2]{margin-bottom:24px}.auth-field-label[data-v-0325c2e2]{display:block;color:#fff;font-weight:600;font-size:14px;margin-bottom:8px}.auth-required[data-v-0325c2e2]{color:#f93e3e}.auth-modal-input[data-v-0325c2e2]{width:100%;padding:12px 16px;background:#2a2a2a;border:1px solid #3e3e42;border-radius:4px;color:#fff;font-family:monospace;font-size:14px;transition:all .2s;box-sizing:border-box}.auth-modal-input[data-v-0325c2e2]:focus{outline:none;border-color:#06c;box-shadow:0 0 8px #0066cc4d;background:#333}.auth-input-hint[data-v-0325c2e2]{margin-top:8px;font-size:12px;color:#999;line-height:1.5}.auth-modal-footer[data-v-0325c2e2]{display:flex;gap:12px;justify-content:flex-end}.btn-modal-secondary[data-v-0325c2e2]{padding:12px 24px;background:#3e3e42;color:#ccc;border:1px solid #3e3e42;border-radius:4px;cursor:pointer;font-weight:600;font-size:14px;transition:all .2s}.btn-modal-secondary[data-v-0325c2e2]:hover{background:#4e4e52;color:#fff;border-color:#555}.btn-modal-primary[data-v-0325c2e2]{padding:12px 24px;background:#06c;color:#fff;border:none;border-radius:4px;cursor:pointer;font-weight:600;font-size:14px;transition:all .2s}.btn-modal-primary[data-v-0325c2e2]:hover{background:#0052a3}.btn-modal-primary[data-v-0325c2e2]:active{transform:scale(.98)}.auth-modal-divider[data-v-0325c2e2]{margin:24px 0;padding:12px 0;text-align:center;color:#999;font-size:12px;position:relative}.auth-modal-divider[data-v-0325c2e2]:before{content:"";position:absolute;top:50%;left:0;right:0;height:1px;background:#3e3e42;z-index:0}.auth-modal-divider span[data-v-0325c2e2]{position:relative;background:#252526;padding:0 12px;z-index:1}.auth-modal-logout[data-v-0325c2e2]{padding:16px;background:#2a2a2a;border:1px solid #3e3e42;border-radius:4px}.auth-logout-text[data-v-0325c2e2]{color:#ccc;font-size:13px;margin:0 0 12px;line-height:1.5}.btn-modal-logout[data-v-0325c2e2]{width:100%;padding:10px 16px;background:#f93e3e;color:#fff;border:none;border-radius:4px;cursor:pointer;font-weight:600;font-size:14px;transition:all .2s}.btn-modal-logout[data-v-0325c2e2]:hover{background:#d92e2e}.btn-modal-logout[data-v-0325c2e2]:active{transform:scale(.98);max-width:1400px;margin:0 auto;padding:0 20px 16px;display:flex;gap:8px;align-items:center;border-top:1px solid #2a2a2a}.menu-item[data-v-0325c2e2]{display:inline-flex;align-items:center;gap:8px;padding:10px 18px;color:#bbb;text-decoration:none;border-radius:4px;cursor:pointer;transition:all .2s ease;font-size:14px;border:1px solid transparent;white-space:nowrap;font-weight:500}.menu-item[data-v-0325c2e2]:hover{background:#2a2a2a;color:#fff;border-color:#444}.menu-item.active[data-v-0325c2e2]{background:#06c;color:#fff;border-color:#0052a3}.menu-icon[data-v-0325c2e2]{font-size:16px}.menu-label[data-v-0325c2e2]{font-weight:500}.auth-input-group[data-v-0325c2e2]{display:flex;gap:10px;align-items:center;border-right:1px solid #3e3e42;padding-right:12px}.auth-input-group input[data-v-0325c2e2]{min-height:auto;width:240px;padding:8px 12px;font-size:12px;background:#2a2a2a;border:1px solid #444;color:#ccc;border-radius:4px;font-family:monospace}.auth-input-group input[data-v-0325c2e2]:focus{outline:none;border-color:#06c;box-shadow:0 0 4px #0066cc4d}.auth-input-group input[data-v-0325c2e2]::placeholder{color:#666}.auth-input-group label[data-v-0325c2e2]{color:#999;font-size:12px;margin:0;white-space:nowrap;font-weight:500}.auth-status[data-v-0325c2e2]{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:#999;white-space:nowrap}.auth-status.active[data-v-0325c2e2]{color:#49cc90}.auth-status-dot[data-v-0325c2e2]{width:8px;height:8px;border-radius:50%;background:#999;flex-shrink:0}.auth-status.active .auth-status-dot[data-v-0325c2e2]{background:#49cc90}.btn-logout[data-v-0325c2e2]{background:#f93e3e;color:#fff;border:none;padding:8px 12px;border-radius:4px;cursor:pointer;font-weight:600;font-size:12px;white-space:nowrap;transition:background .2s,transform .1s;display:inline-flex;align-items:center;gap:6px}.btn-logout[data-v-0325c2e2]:hover{background:#d92e2e;transform:scale(1.05)}.btn-logout[data-v-0325c2e2]:active{transform:scale(.98)}.btn[data-v-0325c2e2]{color:#fff;border:none;padding:10px;border-radius:4px;cursor:pointer;font-weight:600;transition:background .2s;text-decoration:none;display:inline-flex;align-items:center;font-size:14px;white-space:nowrap;flex-shrink:0}.btn[data-v-0325c2e2]:hover:not(:disabled){opacity:.9}.btn[data-v-0325c2e2]:disabled{background:#ccc;cursor:not-allowed}.btn-refresh[data-v-0325c2e2]{background:#666}.btn-feature[data-v-0325c2e2]{background:#389f71;text-decoration:none}.btn-postman[data-v-0325c2e2]{background:#ff6c37}.btn-postman[data-v-0325c2e2]:hover{opacity:.9}.btn-openapi[data-v-0325c2e2]{background:#008c45}.btn-openapi[data-v-0325c2e2]:hover{opacity:.9}.loading-spinner[data-v-0325c2e2]{width:20px;height:20px;border:3px solid #ccc;border-top-color:#06c;border-radius:50%;animation:spin-0325c2e2 1s linear infinite;flex-shrink:0}@keyframes spin-0325c2e2{to{transform:rotate(360deg)}}@media(max-width:1200px){.topbar-top[data-v-0325c2e2]{gap:20px}.api-title[data-v-0325c2e2]{font-size:1.2em}.topbar-controls[data-v-0325c2e2]{gap:10px}.auth-input-group input[data-v-0325c2e2]{width:200px}}@media(max-width:900px){.topbar-top[data-v-0325c2e2]{flex-wrap:wrap;min-height:auto}.api-branding[data-v-0325c2e2]{flex-basis:100%}.topbar-controls[data-v-0325c2e2]{flex-basis:100%;justify-content:flex-end}.topbar-menu[data-v-0325c2e2]{flex-basis:100%;padding:12px 20px;border-top:1px solid #2a2a2a}.menu-item[data-v-0325c2e2]{padding:8px 14px;font-size:13px}.auth-input-group input[data-v-0325c2e2]{width:180px}}@media(max-width:768px){.topbar-top[data-v-0325c2e2]{padding:12px 15px;gap:15px}.api-title[data-v-0325c2e2]{font-size:1.1em}.github-link svg[data-v-0325c2e2]{width:24px;height:24px}.topbar-menu[data-v-0325c2e2]{padding:10px 15px}.menu-item[data-v-0325c2e2]{padding:8px 12px;font-size:12px}.auth-input-group[data-v-0325c2e2]{padding-right:10px}.auth-input-group input[data-v-0325c2e2]{width:150px;padding:6px 10px}.btn-logout[data-v-0325c2e2]{padding:6px 10px;font-size:11px}.btn[data-v-0325c2e2]{padding:8px 15px;font-size:12px}}@media(max-width:600px){.topbar-top[data-v-0325c2e2]{flex-direction:column;align-items:flex-start}.api-branding[data-v-0325c2e2]{width:100%}.topbar-controls[data-v-0325c2e2]{width:100%;gap:8px;flex-wrap:wrap}.topbar-menu[data-v-0325c2e2]{width:100%}.auth-input-group[data-v-0325c2e2]{flex-wrap:wrap;border-right:none;padding-right:0;width:100%}.auth-input-group label[data-v-0325c2e2]{flex-basis:100%}.auth-input-group input[data-v-0325c2e2]{width:100%;min-width:120px}.menu-item[data-v-0325c2e2]{flex:1;justify-content:center;padding:8px 10px}.menu-label[data-v-0325c2e2]{display:none}.menu-icon[data-v-0325c2e2]{font-size:18px}.btn[data-v-0325c2e2]{flex:1;justify-content:center;padding:8px 10px}}@media(max-width:480px){.topbar-top[data-v-0325c2e2]{padding:10px 12px}.api-title[data-v-0325c2e2]{font-size:.95em}.api-version[data-v-0325c2e2]{display:none}.github-link svg[data-v-0325c2e2]{width:20px;height:20px}.topbar-menu[data-v-0325c2e2]{padding:8px 12px}.menu-item[data-v-0325c2e2]{padding:6px 8px;font-size:11px}.auth-input-group[data-v-0325c2e2]{gap:8px}.auth-input-group label[data-v-0325c2e2]{display:none}.auth-input-group input[data-v-0325c2e2]{padding:6px 8px}.auth-status[data-v-0325c2e2]{font-size:10px}.btn-logout[data-v-0325c2e2]{padding:6px 10px;font-size:10px}.btn[data-v-0325c2e2]{padding:6px 12px;font-size:11px}}.sidebar[data-v-a3eda4e9]{width:320px;background:#252526;border-right:1px solid #3e3e42;overflow-y:auto;overflow-x:hidden;padding:0 0 20px;flex-shrink:0;max-height:100%}.sidebar[data-v-a3eda4e9]::-webkit-scrollbar{width:8px}.sidebar[data-v-a3eda4e9]::-webkit-scrollbar-track{background:#252526}.sidebar[data-v-a3eda4e9]::-webkit-scrollbar-thumb{background:#555;border-radius:4px}.sidebar[data-v-a3eda4e9]::-webkit-scrollbar-thumb:hover{background:#666}.sidebar-search[data-v-a3eda4e9]{padding:15px;border-bottom:1px solid #3e3e42;flex-shrink:0;position:sticky;top:0;background:#252526;z-index:10}.search-input-group[data-v-a3eda4e9]{position:relative;display:flex;align-items:center;gap:8px}.search-icon[data-v-a3eda4e9]{width:18px;height:18px;color:#999;flex-shrink:0;pointer-events:none;position:absolute;left:10px}.search-input[data-v-a3eda4e9]{width:100%;padding:8px 8px 8px 36px;background:#2a2a2a;border:1px solid #3e3e42;border-radius:4px;color:#ccc;font-size:13px;font-family:inherit;transition:border-color .2s,background .2s}.search-input[data-v-a3eda4e9]:focus{outline:none;border-color:#06c;background:#333}.search-input[data-v-a3eda4e9]::placeholder{color:#666}.clear-button[data-v-a3eda4e9]{position:absolute;right:8px;background:none;border:none;color:#999;cursor:pointer;padding:4px 6px;font-size:14px;transition:color .2s;display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:2px}.clear-button[data-v-a3eda4e9]:hover{color:#ccc;background:#3e3e42}.no-results[data-v-a3eda4e9]{color:#999;font-size:12px;padding:10px;text-align:center;margin-top:8px}.sidebar>div[data-v-a3eda4e9]:not(.sidebar-search){overflow-y:auto}.sidebar-group[data-v-a3eda4e9]{margin-bottom:0}.sidebar-group-title[data-v-a3eda4e9]{color:#999;font-size:.85em;font-weight:600;padding:10px 20px;text-transform:uppercase;letter-spacing:1px}.sidebar-route[data-v-a3eda4e9]{padding:10px 20px;cursor:pointer;border-left:3px solid transparent;transition:background .2s,border-color .2s;display:flex;align-items:center;gap:10px;color:#ccc}.sidebar-route[data-v-a3eda4e9]:hover{background:#333}.sidebar-route.active[data-v-a3eda4e9]{background:#06c;border-left-color:#06c;color:#fff}.route-method-badge[data-v-a3eda4e9]{font-size:.7em;font-weight:600;padding:3px 6px;border-radius:3px;min-width:40px;text-align:center;text-transform:uppercase}.route-method-badge.get[data-v-a3eda4e9]{background:#61affe;color:#fff}.route-method-badge.post[data-v-a3eda4e9]{background:#49cc90;color:#fff}.route-method-badge.put[data-v-a3eda4e9]{background:#fca130;color:#fff}.route-method-badge.delete[data-v-a3eda4e9]{background:#f93e3e;color:#fff}.route-method-badge.patch[data-v-a3eda4e9]{background:#50e3c2;color:#fff}.route-path[data-v-a3eda4e9]{font-family:Courier New,monospace;font-size:.85em;flex:1;overflow:hidden;text-overflow:ellipsis}.detail-header[data-v-45e22525]{padding:15px 15px 10px;background:#fff;border-bottom:1px solid #e0e0e0;flex-shrink:0}.detail-method-path[data-v-45e22525]{display:flex;align-items:center;gap:15px;margin-bottom:15px}.detail-method-badge[data-v-45e22525]{font-size:.85em;font-weight:600;padding:6px 12px;border-radius:3px;text-transform:uppercase;min-width:50px;text-align:center}.detail-method-badge.get[data-v-45e22525]{background:#61affe;color:#fff}.detail-method-badge.post[data-v-45e22525]{background:#49cc90;color:#fff}.detail-method-badge.put[data-v-45e22525]{background:#fca130;color:#fff}.detail-method-badge.delete[data-v-45e22525]{background:#f93e3e;color:#fff}.detail-method-badge.patch[data-v-45e22525]{background:#50e3c2;color:#fff}.detail-path[data-v-45e22525]{font-family:Courier New,monospace;font-size:1.1em;font-weight:600;color:#3e3e42}.detail-description[data-v-45e22525]{color:#666;font-size:.95em;margin-bottom:10px}.auth-badge[data-v-45e22525]{display:inline-block;background:#fff3cd;color:#856404;padding:1px 5px;border-radius:5px;font-size:.8em;border:1px solid #ffc107}.section[data-v-79f128c3]{margin-bottom:40px}.section-title[data-v-79f128c3]{font-size:1.1em;font-weight:600;margin-bottom:15px;color:#1e1e1e;border-bottom:2px solid #0066cc;padding-bottom:10px}.expandable[data-v-79f128c3]{border:1px solid #e0e0e0;border-radius:4px;overflow:hidden}.expandable-header[data-v-79f128c3]{background:#f5f5f5;padding:5px 10px;cursor:pointer;display:flex;justify-content:space-between;align-items:center;-webkit-user-select:none;user-select:none}.expandable-header[data-v-79f128c3]:hover{background:#efefef}.toggle-icon[data-v-79f128c3]{transition:transform .2s;color:#999}.expandable-content[data-v-79f128c3]{padding:10px;background:#fff;border-top:1px solid #e0e0e0}table[data-v-79f128c3]{width:100%;border-collapse:collapse;font-size:.9em}thead[data-v-79f128c3]{background:#fafafa}th[data-v-79f128c3]{text-align:left;padding:5px 10px;font-weight:600;color:#666;border-bottom:1px solid #e0e0e0}td[data-v-79f128c3]{padding:12px;border-bottom:1px solid #f0f0f0}tr[data-v-79f128c3]:hover{background:#fafafa}.param-name[data-v-79f128c3]{font-family:Courier New,monospace;font-weight:600;color:#06c}.param-type[data-v-79f128c3]{font-family:Courier New,monospace;color:#666;background:#f5f5f5;padding:2px 6px;border-radius:3px}.section[data-v-155d9b8e]{margin-bottom:40px}.section-title[data-v-155d9b8e]{font-size:1.1em;font-weight:600;margin-bottom:15px;color:#1e1e1e;border-bottom:2px solid #0066cc;padding-bottom:10px}.form-fields-info[data-v-155d9b8e]{display:grid;gap:12px}.form-field-info[data-v-155d9b8e]{padding:12px;background:#f5f5f5;border:1px solid #e0e0e0;border-radius:4px}.field-label-info[data-v-155d9b8e]{display:flex;gap:8px;align-items:center;margin-bottom:8px;font-weight:600;font-size:13px}.field-name-info[data-v-155d9b8e]{color:#2196f3;font-family:monospace;font-weight:700}.field-required-badge[data-v-155d9b8e]{background:#ffebee;color:#c62828;padding:2px 6px;border-radius:3px;font-size:11px;font-weight:700}.field-optional-badge[data-v-155d9b8e]{background:#e3f2fd;color:#1565c0;padding:2px 6px;border-radius:3px;font-size:11px;font-weight:700}.field-meta-info[data-v-155d9b8e]{display:flex;flex-direction:column;gap:4px;font-size:12px;color:#666}.field-type-info[data-v-155d9b8e]{display:block}.field-example-info[data-v-155d9b8e]{display:block;font-family:monospace;background:#fff;padding:4px 6px;border-radius:2px}.field-desc-info[data-v-155d9b8e]{display:block;font-style:italic;color:#888}.section[data-v-def58604]{margin-bottom:40px}.section-title[data-v-def58604]{font-size:1.1em;font-weight:600;margin-bottom:15px;color:#1e1e1e;border-bottom:2px solid #0066cc;padding-bottom:10px}.request-tester[data-v-def58604]{background:#fff;border:1px solid #e0e0e0;border-radius:4px;padding:10px}.input-group[data-v-def58604]{position:relative;display:flex;align-items:center;margin-bottom:15px}.input-with-icon[data-v-def58604]{width:100%;padding:10px 40px 10px 10px;border:1px solid #e0e0e0;border-radius:4px;font-family:Courier New,monospace;font-size:13px;background-color:#f9f9f9;transition:border-color .2s}.input-with-icon[data-v-def58604]:focus{outline:none;border-color:#06c;box-shadow:0 0 0 3px #0066cc1a}.copy-icon[data-v-def58604]{position:absolute;right:8px;background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;color:#666;transition:color .2s}.copy-icon[data-v-def58604]:hover{color:#06c}.tester-tabs[data-v-def58604]{display:flex;gap:0;border-bottom:2px solid #e0e0e0;margin-bottom:20px}.tab-btn[data-v-def58604]{flex:1;padding:12px 16px;border:none;background:#f5f5f5;cursor:pointer;font-size:14px;font-weight:600;color:#666;transition:all .3s ease;border-bottom:3px solid transparent}.tab-btn[data-v-def58604]:hover{background:#e8e8e8}.tab-btn.active[data-v-def58604]{background:#fff;color:#333;border-bottom-color:#2196f3}.form-fields-container[data-v-def58604]{display:grid;gap:15px;margin-bottom:20px}.form-field-minimal[data-v-def58604]{display:flex;flex-direction:column;gap:6px}.field-header-minimal[data-v-def58604]{display:flex;align-items:center;gap:8px}.field-label-minimal[data-v-def58604]{font-weight:600;color:#333;font-size:14px;margin:0;display:flex;align-items:center;gap:8px}.badge-required[data-v-def58604]{display:inline-block;background:#ffebee;color:#c62828;padding:1px 5px;border-radius:3px;font-size:.7em;font-weight:600}.param-description[data-v-def58604]{font-size:12px;color:#666;font-style:italic;margin-top:4px}.input-minimal[data-v-def58604]{width:100%;padding:10px;border:1px solid #e0e0e0;border-radius:4px;font-family:Courier New,monospace;font-size:13px;transition:border-color .2s}.input-minimal[data-v-def58604]:focus{outline:none;border-color:#06c;box-shadow:0 0 0 3px #0066cc1a}.json-editor-container[data-v-def58604]{margin-bottom:20px;position:relative}.json-editor-header[data-v-def58604]{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.json-editor-header label[data-v-def58604]{display:block;font-weight:600;margin:0}.json-editor-actions[data-v-def58604]{display:flex;gap:8px}.btn-small[data-v-def58604]{padding:4px 12px;font-size:12px;background:#f0f0f0;border:1px solid #d0d0d0;border-radius:4px;cursor:pointer;transition:all .2s}.btn-small[data-v-def58604]:hover{background:#e0e0e0;border-color:#b0b0b0}.saved-examples-panel[data-v-def58604]{position:absolute;top:40px;right:0;background:#fff;border:1px solid #ddd;border-radius:4px;box-shadow:0 4px 12px #00000026;width:350px;max-height:400px;overflow-y:auto;z-index:1000}.saved-examples-header[data-v-def58604]{padding:12px;border-bottom:1px solid #eee;display:flex;justify-content:space-between;align-items:center}.saved-examples-header h4[data-v-def58604]{margin:0;font-size:14px;font-weight:600}.btn-close[data-v-def58604]{background:none;border:none;font-size:16px;cursor:pointer;padding:0}.no-examples[data-v-def58604]{padding:16px 12px;text-align:center;color:#999;font-size:13px}.examples-list[data-v-def58604]{max-height:350px;overflow-y:auto}.example-item[data-v-def58604]{padding:10px 12px;border-bottom:1px solid #f0f0f0;display:flex;flex-direction:column;gap:6px}.example-item[data-v-def58604]:last-child{border-bottom:none}.example-name[data-v-def58604]{font-weight:600;font-size:13px;color:#333;word-break:break-word}.example-timestamp[data-v-def58604]{font-size:11px;color:#999}.example-actions[data-v-def58604]{display:flex;gap:6px}.btn-action[data-v-def58604]{flex:1;padding:6px;font-size:12px;background:#f5f5f5;border:1px solid #ddd;border-radius:3px;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:4px}.btn-action[data-v-def58604]:hover{background:#e8e8e8;border-color:#b0b0b0}.btn-action.btn-delete[data-v-def58604]:hover{background:#ffebee;border-color:#ef5350;color:#c62828}.json-editor-footer[data-v-def58604]{margin-top:10px;display:flex;gap:8px}.btn-secondary[data-v-def58604]{flex:1;padding:10px 16px;background:#f0f0f0;color:#333;border:1px solid #ddd;border-radius:4px;cursor:pointer;font-weight:600;transition:all .2s}.btn-secondary[data-v-def58604]:hover{background:#e0e0e0;border-color:#b0b0b0}.json-editor-container label[data-v-def58604]{display:block;margin-bottom:8px;font-weight:600}.json-editor[data-v-def58604]{width:100%;padding:10px;font-family:monospace;border:1px solid #ddd;border-radius:4px;font-size:13px}.json-editor[data-v-def58604]:focus{outline:none;border-color:#2196f3;box-shadow:0 0 4px #2196f333}.btn[data-v-def58604]{background:#06c;color:#fff;border:none;padding:10px 20px;border-radius:4px;cursor:pointer;font-weight:600;transition:background .2s}.btn[data-v-def58604]:hover:not(:disabled){background:#0052a3}.btn[data-v-def58604]:disabled{background:#ccc;cursor:not-allowed}.section[data-v-4a3ad82c]{margin-bottom:40px}.section-title[data-v-4a3ad82c]{font-size:1.1em;font-weight:600;margin-bottom:15px;color:#1e1e1e;border-bottom:2px solid #0066cc;padding-bottom:10px}pre[data-v-4a3ad82c]{font-family:Courier New,monospace;font-size:.85em;line-height:1.5;background-color:#1e1e1e;color:#fff;transition:background-color .2s ease}pre[data-v-4a3ad82c]:hover{background-color:#2a2a2a}.copy-btn[data-v-4a3ad82c]{background-color:#06c;color:#fff;border:none;padding:8px 16px;border-radius:4px;cursor:pointer;font-size:.9em;font-weight:500;transition:all .3s ease;display:flex;align-items:center;gap:6px;white-space:nowrap}.copy-btn[data-v-4a3ad82c]:hover{background-color:#0052a3;transform:translateY(-2px);box-shadow:0 2px 8px #0066cc4d}.copy-btn[data-v-4a3ad82c]:active{transform:translateY(0);box-shadow:0 1px 4px #06c3}.pre-copy-icon[data-v-4a3ad82c]{position:absolute;top:25px;right:25px;background:none;border:none;font-size:1.2em;cursor:pointer;padding:4px 8px;border-radius:4px;transition:all .2s ease;z-index:10;line-height:1}.pre-copy-icon[data-v-4a3ad82c]:hover{background-color:#0066cc1a;transform:scale(1.15)}.pre-copy-icon[data-v-4a3ad82c]:active{transform:scale(.95)}.section[data-v-ab00471f]{margin-bottom:40px}.section-title[data-v-ab00471f]{font-size:1.1em;font-weight:600;margin-bottom:15px;color:#1e1e1e;border-bottom:2px solid #0066cc;padding-bottom:10px}.response-section[data-v-ab00471f]{background:#f5f5f5;border:1px solid #e0e0e0;border-radius:4px;padding:15px;margin-top:20px}.response-status[data-v-ab00471f]{font-weight:600;margin-bottom:15px}.response-status.success[data-v-ab00471f]{color:#27ae60}.response-status.error[data-v-ab00471f]{color:#e74c3c}.response-code[data-v-ab00471f]{background:#fff;border:1px solid #e0e0e0;border-radius:4px;padding:15px;overflow-x:auto;font-family:Courier New,monospace;font-size:.85em;white-space:pre-wrap;word-wrap:break-word}.btn[data-v-ab00471f]{background:#06c;color:#fff;border:none;padding:10px 20px;border-radius:4px;cursor:pointer;font-weight:600;transition:background .2s}.btn[data-v-ab00471f]:hover{background:#0052a3}.section[data-v-2e6a99d1]{margin-bottom:40px}.section-title[data-v-2e6a99d1]{font-size:1.1em;font-weight:600;margin-bottom:15px;color:#1e1e1e;border-bottom:2px solid #0066cc;padding-bottom:10px}.saved-responses[data-v-2e6a99d1]{margin-top:20px}.saved-response-item[data-v-2e6a99d1]{background:#fff;border:1px solid #e0e0e0;border-radius:4px;padding:15px;margin-bottom:10px;display:flex;justify-content:space-between;align-items:center;transition:background .2s}.saved-response-item[data-v-2e6a99d1]:hover{background:#fafafa}.saved-response-content[data-v-2e6a99d1]{flex:1;cursor:pointer}.saved-response-time[data-v-2e6a99d1]{color:#999;font-size:.85em;margin-top:5px}.delete-btn[data-v-2e6a99d1]{background:#ef4444;color:#fff;border:none;border-radius:4px;padding:6px 12px;cursor:pointer;font-size:16px;transition:background .2s;margin-left:10px}.delete-btn[data-v-2e6a99d1]:hover{background:#dc2626}.tabs-component[data-v-cbcf88f8]{width:100%}.tab-header[data-v-cbcf88f8]{display:flex;border-bottom:2px solid #e0e0e0;gap:0;background:#f9f9f9}.tab[data-v-cbcf88f8]{flex:1;padding:12px 16px;border:none;background:transparent;cursor:pointer;font-size:14px;font-weight:500;color:#666;transition:all .3s ease;border-bottom:3px solid transparent;margin-bottom:-2px}.tab[data-v-cbcf88f8]:hover{color:#333;background:#f0f0f0}.tab.active[data-v-cbcf88f8]{color:#2c3e50;border-bottom-color:#42b983}.tab-body[data-v-cbcf88f8]{padding:20px 0;min-height:200px}.api-info-container[data-v-8f8eb8b4]{display:flex;flex-direction:column;gap:40px}.info-section[data-v-8f8eb8b4]{background:#fff;border-radius:8px;border:1px solid #e5e7eb;padding:28px;display:grid;gap:24px}.info-group[data-v-8f8eb8b4]{display:grid;grid-template-columns:140px 1fr;gap:20px;align-items:start}.info-label[data-v-8f8eb8b4]{font-weight:600;color:#1f2937;font-size:14px}.info-value[data-v-8f8eb8b4]{color:#6b7280;font-size:14px;display:flex;align-items:center;gap:12px;flex-wrap:wrap}.method-badge[data-v-8f8eb8b4]{display:inline-block;font-weight:700;padding:4px 12px;border-radius:4px;font-size:13px;font-family:monospace;min-width:60px;text-align:center}.method-get[data-v-8f8eb8b4]{background:#dcfce7;color:#15803d}.method-post[data-v-8f8eb8b4]{background:#fef08a;color:#854d0e}.method-put[data-v-8f8eb8b4]{background:#fecaca;color:#991b1b}.method-delete[data-v-8f8eb8b4]{background:#fee2e2;color:#7f1d1d}.method-patch[data-v-8f8eb8b4]{background:#dbeafe;color:#0c4a6e}.middlewares-value[data-v-8f8eb8b4]{display:flex;gap:8px;flex-wrap:wrap}.middleware-badge[data-v-8f8eb8b4]{background:#f3f4f6;color:#4b5563;padding:4px 10px;border-radius:3px;font-size:12px;border:1px solid #e5e7eb;font-family:monospace}.info-link[data-v-8f8eb8b4]{color:#2563eb;font-size:14px;cursor:pointer;display:flex;align-items:center;gap:6px;transition:color .2s}.info-link[data-v-8f8eb8b4]:hover{color:#1d4ed8}.arrow[data-v-8f8eb8b4]{font-size:18px;font-weight:300;display:inline-block;transition:transform .2s ease}.arrow.expanded[data-v-8f8eb8b4]{transform:rotate(90deg)}.collapsible-content[data-v-8f8eb8b4]{margin-top:12px;padding:12px;background:#f9fafb;border-left:3px solid #2563eb;border-radius:4px;animation:slideDown-8f8eb8b4 .2s ease}@keyframes slideDown-8f8eb8b4{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.response-codes-list[data-v-8f8eb8b4]{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:8px}.response[data-v-8f8eb8b4]{padding:10px 16px;background:#fff;border:none;border-radius:4px;font-family:monospace;font-size:13px;font-weight:600;color:#fff;width:100%;display:inline-block}.response-200[data-v-8f8eb8b4],.response-201[data-v-8f8eb8b4],.response-204[data-v-8f8eb8b4]{background:#10b981;color:#fff}.response-400[data-v-8f8eb8b4],.response-401[data-v-8f8eb8b4],.response-403[data-v-8f8eb8b4],.response-404[data-v-8f8eb8b4],.response-405[data-v-8f8eb8b4],.response-409[data-v-8f8eb8b4]{background:#f87171;color:#fff}.response-422[data-v-8f8eb8b4],.response-429[data-v-8f8eb8b4]{background:#fbbf24;color:#78350f}.response-500[data-v-8f8eb8b4],.response-502[data-v-8f8eb8b4],.response-503[data-v-8f8eb8b4]{background:#f87171;color:#fff}.curl-command[data-v-8f8eb8b4]{display:flex;flex-direction:column;gap:12px}.curl-command>div[data-v-8f8eb8b4]{width:100%}.curl-command textarea[data-v-8f8eb8b4]{width:100%;background:#1f2937;padding:12px;border-radius:4px;border:1px solid #374151;font-size:12px;font-family:Monaco,Courier New,monospace;color:#e5e7eb;line-height:1.6;box-sizing:border-box}.curl-command code[data-v-8f8eb8b4]{flex:1;background:#fff;padding:10px;border-radius:4px;border:1px solid #e5e7eb;font-size:12px;overflow-x:auto;white-space:nowrap;color:#374151}.copy-btn[data-v-8f8eb8b4]{align-self:center;width:120px;padding:8px 16px;background:#d1d5db;color:#374151;border:none;border-radius:4px;font-size:12px;font-weight:600;cursor:pointer;transition:background .2s;white-space:nowrap;height:fit-content}.copy-btn[data-v-8f8eb8b4]:hover{background:#bfdbfe}.copy-btn[data-v-8f8eb8b4]:active{background:#93c5fd}.empty-content[data-v-8f8eb8b4]{padding:12px;text-align:center;color:#9ca3af;font-size:13px}.section[data-v-8f8eb8b4]{margin-bottom:40px}.section-title[data-v-8f8eb8b4]{font-size:1.1em;font-weight:600;margin-bottom:15px;color:#1e1e1e;border-bottom:2px solid #0066cc;padding-bottom:10px}.form-fields-info[data-v-8f8eb8b4]{display:grid;gap:12px}.form-field-info[data-v-8f8eb8b4]{padding:12px;background:#f5f5f5;border:1px solid #e0e0e0;border-radius:4px}.field-label-info[data-v-8f8eb8b4]{display:flex;gap:8px;align-items:center;margin-bottom:8px;font-weight:600;font-size:13px}.field-name-info[data-v-8f8eb8b4]{color:#2196f3;font-family:monospace;font-weight:700}.field-required-badge[data-v-8f8eb8b4]{background:#ffebee;color:#c62828;padding:2px 6px;border-radius:3px;font-size:11px;font-weight:700}.field-optional-badge[data-v-8f8eb8b4]{background:#e3f2fd;color:#1565c0;padding:2px 6px;border-radius:3px;font-size:11px;font-weight:700}.field-meta-info[data-v-8f8eb8b4]{display:flex;flex-direction:column;gap:4px;font-size:12px;color:#666}.field-type-info[data-v-8f8eb8b4]{display:block}.field-example-info[data-v-8f8eb8b4]{display:block;font-family:monospace;background:#fff;padding:4px 6px;border-radius:2px}.field-desc-info[data-v-8f8eb8b4]{display:block;font-style:italic;color:#888}code[data-v-8f8eb8b4]{background:#f3f4f6;padding:2px 6px;border-radius:3px;font-family:monospace;font-size:12px;color:#374151}.endpoint-detail[data-v-d0e6e422]{flex:1;display:flex;flex-direction:column;overflow:hidden}.detail-body[data-v-d0e6e422]{flex:1;overflow-y:auto;padding:0;display:flex;gap:0}.detail-body-left[data-v-d0e6e422]{flex:1;overflow-y:auto;padding:10px 20px;border-right:1px solid #e0e0e0;background:#fff}.detail-body-right[data-v-d0e6e422]{flex:1;overflow-y:auto;padding:10px 20px;background:#f9f9f9}.empty-state[data-v-d0e6e422]{display:flex;flex-direction:column;align-items:center;justify-content:center;color:#999;padding:40px 20px;min-height:200px}.empty-state-icon[data-v-d0e6e422]{font-size:4em;margin-bottom:20px;opacity:.3}.tab-content[data-v-d0e6e422]{animation:fadeIn-d0e6e422 .3s ease}@keyframes fadeIn-d0e6e422{0%{opacity:0}to{opacity:1}}.app-container[data-v-0a7e40cc]{display:flex;flex-direction:column;height:100vh;overflow:hidden}.main-container[data-v-0a7e40cc]{display:flex;flex:1;overflow:hidden}.content[data-v-0a7e40cc]{flex:1;display:flex;flex-direction:column;overflow:hidden}.empty-state[data-v-0a7e40cc]{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#999}.empty-state-icon[data-v-0a7e40cc]{font-size:4em;margin-bottom:20px;opacity:.3}.toasts-container[data-v-40e4e9e9]{position:fixed;top:20px;right:20px;z-index:9999;display:flex;flex-direction:column;gap:10px;pointer-events:none}.toast[data-v-40e4e9e9]{padding:12px 20px;border-radius:6px;box-shadow:0 4px 12px #00000026;animation:slideIn-40e4e9e9 .3s ease-out;font-size:14px;max-width:300px;pointer-events:auto}.toast-content[data-v-40e4e9e9]{display:flex;align-items:center;gap:8px}.toast-icon[data-v-40e4e9e9]{font-weight:700;font-size:16px}.toast.success[data-v-40e4e9e9]{background-color:#10b981;color:#fff;border-left:4px solid #059669}.toast.error[data-v-40e4e9e9]{background-color:#ef4444;color:#fff;border-left:4px solid #dc2626}.toast.info[data-v-40e4e9e9]{background-color:#3b82f6;color:#fff;border-left:4px solid #1d4ed8}@keyframes slideIn-40e4e9e9{0%{transform:translate(400px);opacity:0}to{transform:translate(0);opacity:1}}*{margin:0;padding:0;box-sizing:border-box}body{font-family:Roboto,sans-serif;background:#fafafa;color:#3e3e42;line-height:1.6}#api-inspector{display:flex;flex-direction:column;height:100vh;overflow:auto}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:#f1f1f1}::-webkit-scrollbar-thumb{background:#888;border-radius:4px}::-webkit-scrollbar-thumb:hover{background:#555}.flex-col{flex-direction:column}.gap-3{gap:12px}.gap-4{gap:16px}.items-center{align-items:center}.p-4{padding:16px!important}.p-6{padding:24px!important}.mb-4{margin-bottom:16px!important}.mb-5{margin-bottom:20px!important}.pb-5{padding-bottom:7rem!important}.mt-4{margin-top:16px!important}.me-1{margin-right:5px!important}.bg-white{background:#fff!important}.loading-spinner{width:20px;height:20px;border:3px solid #ccc;border-top-color:#06c;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.badge{display:inline-block;padding:4px 8px;border-radius:3px;font-size:.75em;font-weight:600;text-transform:uppercase}.badge-get{background:#61affe;color:#fff}.badge-post{background:#49cc90;color:#fff}.badge-put{background:#fca130;color:#fff}.badge-delete{background:#f93e3e;color:#fff}.badge-patch{background:#50e3c2;color:#fff}textarea,input,select{width:100%;padding:10px;border:1px solid #e0e0e0;border-radius:4px;font-family:Courier New,monospace;font-size:.9em}textarea:focus,input:focus,select:focus{outline:none;border-color:#06c;box-shadow:0 0 0 3px #0066cc1a}.btn{color:#fff;border:none;padding:10px;border-radius:4px;cursor:pointer;font-weight:600;transition:background .2s}.btn:hover:not(:disabled){background:#0052a3}.btn:disabled{background:#ccc;cursor:not-allowed}.btn-sm{padding:6px 12px;font-size:.9em}.auth-bg{background:#ff9800!important}table{width:100%;border-collapse:collapse;font-size:.9em}thead{background:#fafafa}th{text-align:left;padding:12px;font-weight:600;color:#666;border-bottom:1px solid #e0e0e0}td{padding:12px;border-bottom:1px solid #f0f0f0}tr:hover{background:#fafafa}.text-center{text-align:center!important}.mb-4{margin-bottom:16px}.fs-small{font-size:.875em}.fs-20{font-size:20px}.font-bold{font-weight:700}.justify-between{justify-content:space-between}.flex{display:flex}.ml-3{margin-left:12px}.mb-0{margin-bottom:0!important}.me-2{margin-right:8px}.pb-0{padding-bottom:0!important}.app-container{display:flex;flex-direction:column;height:100vh;overflow:hidden}.main-container{display:flex;flex:1;overflow:hidden}.content{flex:1;display:flex;flex-direction:column;overflow:hidden}.empty-state{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#999}.empty-state-icon{font-size:4em;margin-bottom:20px;opacity:.3}.dashboard-container{padding:24px;background:#f9fafb;min-height:100vh;overflow-y:auto}.dashboard-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:32px}.dashboard-header h1{font-size:28px;font-weight:700;color:#1f2937;margin:0}.btn-refresh{padding:8px 16px;background:#2563eb;color:#fff;border:none;border-radius:6px;cursor:pointer;font-weight:600;transition:background .2s}.btn-refresh:hover{background:#1d4ed8}.time-range-select{padding:8px 12px;border:1px solid #d1d5db;border-radius:6px;background:#fff;font-size:14px;cursor:pointer}.overview-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:16px;margin-bottom:32px}.stat-card{background:#fff;padding:20px;border-radius:8px;border:1px solid #e5e7eb;box-shadow:0 1px 3px #0000000d}.stat-label{font-size:12px;font-weight:600;color:#6b7280;text-transform:uppercase;margin-bottom:8px}.stat-value{font-size:28px;font-weight:700;color:#1f2937;margin-bottom:8px}.stat-value.error{color:#dc2626}.stat-change{font-size:12px;color:#6b7280}.stat-description{font-size:12px;color:#9ca3af;margin-top:4px}.charts-section{display:grid;grid-template-columns:repeat(auto-fit,minmax(400px,1fr));gap:16px;margin-bottom:32px}.chart-card{background:#fff;padding:20px;border-radius:8px;border:1px solid #e5e7eb;box-shadow:0 1px 3px #0000000d}.chart-card h3{margin-top:0;margin-bottom:16px;color:#1f2937;font-size:16px}.chart-placeholder{height:300px;background:#f9fafb;border-radius:6px;display:flex;align-items:center;justify-content:center;color:#9ca3af}.table-section{margin-bottom:24px}.table-card{background:#fff;padding:20px;border-radius:8px;border:1px solid #e5e7eb;box-shadow:0 1px 3px #0000000d}.table-card h3{margin-top:0;margin-bottom:16px;color:#1f2937;font-size:16px}.data-table{width:100%;border-collapse:collapse;font-size:14px}.data-table thead{background:#f9fafb;border-bottom:1px solid #e5e7eb}.data-table th{padding:12px;text-align:left;font-weight:600;color:#6b7280}.data-table td{padding:12px;border-bottom:1px solid #e5e7eb;color:#374151}.data-table tbody tr:hover{background:#f9fafb}.status-badge{display:inline-block;padding:4px 8px;border-radius:4px;font-weight:600;font-size:12px}.status-200,.status-201,.status-204{background:#dcfce7;color:#15803d}.status-400,.status-401,.status-403,.status-404,.status-405,.status-409{background:#fee2e2;color:#991b1b}.status-422,.status-429{background:#fef08a;color:#854d0e}.status-500,.status-502,.status-503{background:#fee2e2;color:#991b1b}.method-badge{display:inline-block;padding:4px 8px;border-radius:4px;font-weight:600;font-size:12px;color:#fff}.method-GET{background:#10b981}.method-POST{background:#f59e0b}.method-PUT{background:#8b5cf6}.method-DELETE{background:#ef4444}.method-PATCH{background:#0ea5e9}.route-name{font-family:monospace;color:#2563eb;font-weight:500}.duration.slow,.error-rate.high{color:#dc2626;font-weight:600}.error-message{font-family:monospace;font-size:12px;max-width:400px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dashboard-container{padding:20px;background:#f8fafc;min-height:100vh}.dashboard-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:30px;background:#fff;padding:20px;border-radius:8px;box-shadow:0 1px 3px #0000001a}.dashboard-header h1{margin:0;font-size:28px;color:#1e293b}.header-actions{display:flex;gap:12px;align-items:center}.btn-refresh{padding:8px 16px;background:#3b82f6;color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:14px;font-weight:500;transition:all .3s ease}.btn-refresh:hover{background:#2563eb;transform:translateY(-2px);box-shadow:0 4px 12px #3b82f64d}.time-range-select{padding:8px 12px;border:1px solid #e2e8f0;border-radius:6px;font-size:14px;background:#fff;cursor:pointer;transition:all .3s ease}.time-range-select:hover{border-color:#cbd5e1}.time-range-select:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.overview-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:20px;margin-bottom:30px}.stat-card{background:#fff;padding:20px;border-radius:8px;box-shadow:0 1px 3px #0000001a;transition:all .3s ease}.stat-card:hover{box-shadow:0 4px 12px #00000026;transform:translateY(-2px)}.stat-label{font-size:12px;font-weight:600;color:#64748b;text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px}.stat-value{font-size:32px;font-weight:700;color:#1e293b;margin-bottom:8px}.stat-value.error{color:#ef4444}.stat-description{font-size:13px;color:#64748b;margin:4px 0}.stat-change{font-size:13px;font-weight:600;color:#64748b;margin-top:4px}.stat-change.positive{color:#10b981}.stat-change.negative{color:#ef4444}.charts-section{display:grid;grid-template-columns:repeat(auto-fit,minmax(400px,1fr));gap:20px;margin-bottom:30px}.chart-card{background:#fff;padding:20px;border-radius:8px;box-shadow:0 1px 3px #0000001a}.chart-card h3{margin:0 0 15px;font-size:16px;color:#1e293b;font-weight:600}.chart-placeholder{position:relative;height:300px;width:100%}.chart-placeholder canvas{max-height:300px}.table-section{margin-bottom:30px}.table-card{background:#fff;padding:20px;border-radius:8px;box-shadow:0 1px 3px #0000001a}.table-card h3{margin:0 0 15px;font-size:16px;color:#1e293b;font-weight:600}.data-table{width:100%;border-collapse:collapse}.data-table thead{background:#f1f5f9}.data-table th{padding:12px;text-align:left;font-size:12px;font-weight:600;color:#64748b;text-transform:uppercase;letter-spacing:.5px;border-bottom:2px solid #e2e8f0}.data-table td{padding:12px;border-bottom:1px solid #e2e8f0;font-size:13px;color:#475569}.data-table tbody tr:hover{background:#f8fafc}.status-badge{display:inline-flex;align-items:center;justify-content:center;width:50px;height:30px;border-radius:4px;font-size:12px;font-weight:600;color:#fff}.status-badge.status-200,.status-badge.status-201{background:#10b981}.status-badge.status-400,.status-badge.status-401,.status-badge.status-403,.status-badge.status-404,.status-badge.status-422{background:#f59e0b}.status-badge.status-500,.status-badge.status-503{background:#ef4444}.method-badge{display:inline-flex;align-items:center;justify-content:center;min-width:45px;padding:4px 8px;border-radius:4px;font-size:11px;font-weight:700;color:#fff}.method-badge.method-GET{background:#3b82f6}.method-badge.method-POST{background:#10b981}.method-badge.method-PUT{background:#f59e0b}.method-badge.method-DELETE{background:#ef4444}.method-badge.method-PATCH{background:#8b5cf6}.route-name{font-family:Monaco,Courier New,monospace;font-size:12px;color:#1e293b;font-weight:500}.duration{font-weight:600;color:#1e293b}.duration.slow{color:#ef4444;font-weight:700}.error-rate{font-weight:600}.error-rate.high{color:#ef4444}.error-message{color:#ef4444;font-family:Monaco,Courier New,monospace;font-size:12px;max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.route-row{transition:background .2s ease}.route-row:hover{background:#f0fdf4}.error-row{background:#fef2f2;transition:background .2s ease}.error-row:hover{background:#fee2e2}@media(max-width:768px){.dashboard-container{padding:12px}.dashboard-header{flex-direction:column;gap:12px;align-items:flex-start}.header-actions{width:100%;flex-wrap:wrap}.overview-grid,.charts-section{grid-template-columns:1fr}.data-table{font-size:12px}.data-table th,.data-table td{padding:8px}}.justify-between{display:flex;justify-content:space-between}.text-truncate{max-width:600px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} ================================================ FILE: public/vendor/api-inspector/js/app.js ================================================ function _r(e){const t=Object.create(null);for(const s of e.split(","))t[s]=1;return s=>s in t}const _t={},Ks=[],Le=()=>{},Rc=()=>!1,qi=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),yr=e=>e.startsWith("onUpdate:"),Gt=Object.assign,xr=(e,t)=>{const s=e.indexOf(t);s>-1&&e.splice(s,1)},sd=Object.prototype.hasOwnProperty,gt=(e,t)=>sd.call(e,t),J=Array.isArray,Gs=e=>Jn(e)==="[object Map]",cn=e=>Jn(e)==="[object Set]",ra=e=>Jn(e)==="[object Date]",st=e=>typeof e=="function",It=e=>typeof e=="string",Se=e=>typeof e=="symbol",yt=e=>e!==null&&typeof e=="object",Oc=e=>(yt(e)||st(e))&&st(e.then)&&st(e.catch),Tc=Object.prototype.toString,Jn=e=>Tc.call(e),nd=e=>Jn(e).slice(8,-1),Ec=e=>Jn(e)==="[object Object]",vr=e=>It(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Mn=_r(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Ui=e=>{const t=Object.create(null);return(s=>t[s]||(t[s]=e(s)))},id=/-\w/g,xe=Ui(e=>e.replace(id,t=>t.slice(1).toUpperCase())),od=/\B([A-Z])/g,ys=Ui(e=>e.replace(od,"-$1").toLowerCase()),Ki=Ui(e=>e.charAt(0).toUpperCase()+e.slice(1)),mo=Ui(e=>e?`on${Ki(e)}`:""),ps=(e,t)=>!Object.is(e,t),vi=(e,...t)=>{for(let s=0;s{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:n,value:s})},Gi=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let aa;const Yi=()=>aa||(aa=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function wr(e){if(J(e)){const t={};for(let s=0;s{if(s){const n=s.split(ad);n.length>1&&(t[n[0].trim()]=n[1].trim())}}),t}function kt(e){let t="";if(It(e))t=e;else if(J(e))for(let s=0;sBs(s,t))}const Lc=e=>!!(e&&e.__v_isRef===!0),H=e=>It(e)?e:e==null?"":J(e)||yt(e)&&(e.toString===Tc||!st(e.toString))?Lc(e)?H(e.value):JSON.stringify(e,Fc,2):String(e),Fc=(e,t)=>Lc(t)?Fc(e,t.value):Gs(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((s,[n,i],o)=>(s[bo(n,o)+" =>"]=i,s),{})}:cn(t)?{[`Set(${t.size})`]:[...t.values()].map(s=>bo(s))}:Se(t)?bo(t):yt(t)&&!J(t)&&!Ec(t)?String(t):t,bo=(e,t="")=>{var s;return Se(e)?`Symbol(${(s=e.description)!=null?s:t})`:e};let le;class fd{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this.parent=le,!t&&le&&(this.index=(le.scopes||(le.scopes=[])).push(this)-1)}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,s;if(this.scopes)for(t=0,s=this.scopes.length;t0&&--this._on===0&&(le=this.prevScope,this.prevScope=void 0)}stop(t){if(this._active){this._active=!1;let s,n;for(s=0,n=this.effects.length;s0)return;if(Pn){let t=Pn;for(Pn=void 0;t;){const s=t.next;t.next=void 0,t.flags&=-9,t=s}}let e;for(;Cn;){let t=Cn;for(Cn=void 0;t;){const s=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(n){e||(e=n)}t=s}}if(e)throw e}function Vc(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function jc(e){let t,s=e.depsTail,n=s;for(;n;){const i=n.prevDep;n.version===-1?(n===s&&(s=i),Cr(n),gd(n)):t=n,n.dep.activeLink=n.prevActiveLink,n.prevActiveLink=void 0,n=i}e.deps=t,e.depsTail=s}function Wo(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(Hc(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function Hc(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===Nn)||(e.globalVersion=Nn,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!Wo(e))))return;e.flags|=2;const t=e.dep,s=wt,n=we;wt=e,we=!0;try{Vc(e);const i=e.fn(e._value);(t.version===0||ps(i,e._value))&&(e.flags|=128,e._value=i,t.version++)}catch(i){throw t.version++,i}finally{wt=s,we=n,jc(e),e.flags&=-3}}function Cr(e,t=!1){const{dep:s,prevSub:n,nextSub:i}=e;if(n&&(n.nextSub=i,e.prevSub=void 0),i&&(i.prevSub=n,e.nextSub=void 0),s.subs===e&&(s.subs=n,!n&&s.computed)){s.computed.flags&=-5;for(let o=s.computed.deps;o;o=o.nextDep)Cr(o,!0)}!t&&!--s.sc&&s.map&&s.map.delete(s.key)}function gd(e){const{prevDep:t,nextDep:s}=e;t&&(t.nextDep=s,e.prevDep=void 0),s&&(s.prevDep=t,e.nextDep=void 0)}let we=!0;const zc=[];function Ze(){zc.push(we),we=!1}function ts(){const e=zc.pop();we=e===void 0?!0:e}function la(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const s=wt;wt=void 0;try{t()}finally{wt=s}}}let Nn=0;class md{constructor(t,s){this.sub=t,this.dep=s,this.version=s.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class Pr{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(t){if(!wt||!we||wt===this.computed)return;let s=this.activeLink;if(s===void 0||s.sub!==wt)s=this.activeLink=new md(wt,this),wt.deps?(s.prevDep=wt.depsTail,wt.depsTail.nextDep=s,wt.depsTail=s):wt.deps=wt.depsTail=s,Wc(s);else if(s.version===-1&&(s.version=this.version,s.nextDep)){const n=s.nextDep;n.prevDep=s.prevDep,s.prevDep&&(s.prevDep.nextDep=n),s.prevDep=wt.depsTail,s.nextDep=void 0,wt.depsTail.nextDep=s,wt.depsTail=s,wt.deps===s&&(wt.deps=n)}return s}trigger(t){this.version++,Nn++,this.notify(t)}notify(t){kr();try{for(let s=this.subs;s;s=s.prevSub)s.sub.notify()&&s.sub.dep.notify()}finally{Mr()}}}function Wc(e){if(e.dep.sc++,e.sub.flags&4){const t=e.dep.computed;if(t&&!e.dep.subs){t.flags|=20;for(let n=t.deps;n;n=n.nextDep)Wc(n)}const s=e.dep.subs;s!==e&&(e.prevSub=s,s&&(s.nextSub=e)),e.dep.subs=e}}const qo=new WeakMap,Ds=Symbol(""),Uo=Symbol(""),Bn=Symbol("");function zt(e,t,s){if(we&&wt){let n=qo.get(e);n||qo.set(e,n=new Map);let i=n.get(s);i||(n.set(s,i=new Pr),i.map=n,i.key=s),i.track()}}function qe(e,t,s,n,i,o){const r=qo.get(e);if(!r){Nn++;return}const a=l=>{l&&l.trigger()};if(kr(),t==="clear")r.forEach(a);else{const l=J(e),c=l&&vr(s);if(l&&s==="length"){const u=Number(n);r.forEach((h,d)=>{(d==="length"||d===Bn||!Se(d)&&d>=u)&&a(h)})}else switch((s!==void 0||r.has(void 0))&&a(r.get(s)),c&&a(r.get(Bn)),t){case"add":l?c&&a(r.get("length")):(a(r.get(Ds)),Gs(e)&&a(r.get(Uo)));break;case"delete":l||(a(r.get(Ds)),Gs(e)&&a(r.get(Uo)));break;case"set":Gs(e)&&a(r.get(Ds));break}}Mr()}function Hs(e){const t=pt(e);return t===e?t:(zt(t,"iterate",Bn),be(e)?t:t.map(ke))}function Xi(e){return zt(e=pt(e),"iterate",Bn),e}function rs(e,t){return es(e)?Is(e)?tn(ke(t)):tn(t):ke(t)}const bd={__proto__:null,[Symbol.iterator](){return yo(this,Symbol.iterator,e=>rs(this,e))},concat(...e){return Hs(this).concat(...e.map(t=>J(t)?Hs(t):t))},entries(){return yo(this,"entries",e=>(e[1]=rs(this,e[1]),e))},every(e,t){return Be(this,"every",e,t,void 0,arguments)},filter(e,t){return Be(this,"filter",e,t,s=>s.map(n=>rs(this,n)),arguments)},find(e,t){return Be(this,"find",e,t,s=>rs(this,s),arguments)},findIndex(e,t){return Be(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return Be(this,"findLast",e,t,s=>rs(this,s),arguments)},findLastIndex(e,t){return Be(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return Be(this,"forEach",e,t,void 0,arguments)},includes(...e){return xo(this,"includes",e)},indexOf(...e){return xo(this,"indexOf",e)},join(e){return Hs(this).join(e)},lastIndexOf(...e){return xo(this,"lastIndexOf",e)},map(e,t){return Be(this,"map",e,t,void 0,arguments)},pop(){return hn(this,"pop")},push(...e){return hn(this,"push",e)},reduce(e,...t){return ca(this,"reduce",e,t)},reduceRight(e,...t){return ca(this,"reduceRight",e,t)},shift(){return hn(this,"shift")},some(e,t){return Be(this,"some",e,t,void 0,arguments)},splice(...e){return hn(this,"splice",e)},toReversed(){return Hs(this).toReversed()},toSorted(e){return Hs(this).toSorted(e)},toSpliced(...e){return Hs(this).toSpliced(...e)},unshift(...e){return hn(this,"unshift",e)},values(){return yo(this,"values",e=>rs(this,e))}};function yo(e,t,s){const n=Xi(e),i=n[t]();return n!==e&&!be(e)&&(i._next=i.next,i.next=()=>{const o=i._next();return o.done||(o.value=s(o.value)),o}),i}const _d=Array.prototype;function Be(e,t,s,n,i,o){const r=Xi(e),a=r!==e&&!be(e),l=r[t];if(l!==_d[t]){const h=l.apply(e,o);return a?ke(h):h}let c=s;r!==e&&(a?c=function(h,d){return s.call(this,rs(e,h),d,e)}:s.length>2&&(c=function(h,d){return s.call(this,h,d,e)}));const u=l.call(r,c,n);return a&&i?i(u):u}function ca(e,t,s,n){const i=Xi(e);let o=s;return i!==e&&(be(e)?s.length>3&&(o=function(r,a,l){return s.call(this,r,a,l,e)}):o=function(r,a,l){return s.call(this,r,rs(e,a),l,e)}),i[t](o,...n)}function xo(e,t,s){const n=pt(e);zt(n,"iterate",Bn);const i=n[t](...s);return(i===-1||i===!1)&&Or(s[0])?(s[0]=pt(s[0]),n[t](...s)):i}function hn(e,t,s=[]){Ze(),kr();const n=pt(e)[t].apply(e,s);return Mr(),ts(),n}const yd=_r("__proto__,__v_isRef,__isVue"),qc=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Se));function xd(e){Se(e)||(e=String(e));const t=pt(this);return zt(t,"has",e),t.hasOwnProperty(e)}class Uc{constructor(t=!1,s=!1){this._isReadonly=t,this._isShallow=s}get(t,s,n){if(s==="__v_skip")return t.__v_skip;const i=this._isReadonly,o=this._isShallow;if(s==="__v_isReactive")return!i;if(s==="__v_isReadonly")return i;if(s==="__v_isShallow")return o;if(s==="__v_raw")return n===(i?o?Od:Xc:o?Yc:Gc).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(n)?t:void 0;const r=J(t);if(!i){let l;if(r&&(l=bd[s]))return l;if(s==="hasOwnProperty")return xd}const a=Reflect.get(t,s,Kt(t)?t:n);if((Se(s)?qc.has(s):yd(s))||(i||zt(t,"get",s),o))return a;if(Kt(a)){const l=r&&vr(s)?a:a.value;return i&&yt(l)?Go(l):l}return yt(a)?i?Go(a):Zs(a):a}}class Kc extends Uc{constructor(t=!1){super(!1,t)}set(t,s,n,i){let o=t[s];const r=J(t)&&vr(s);if(!this._isShallow){const c=es(o);if(!be(n)&&!es(n)&&(o=pt(o),n=pt(n)),!r&&Kt(o)&&!Kt(n))return c||(o.value=n),!0}const a=r?Number(s)e,si=e=>Reflect.getPrototypeOf(e);function Md(e,t,s){return function(...n){const i=this.__v_raw,o=pt(i),r=Gs(o),a=e==="entries"||e===Symbol.iterator&&r,l=e==="keys"&&r,c=i[e](...n),u=s?Ko:t?tn:ke;return!t&&zt(o,"iterate",l?Uo:Ds),{next(){const{value:h,done:d}=c.next();return d?{value:h,done:d}:{value:a?[u(h[0]),u(h[1])]:u(h),done:d}},[Symbol.iterator](){return this}}}}function ni(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function Cd(e,t){const s={get(i){const o=this.__v_raw,r=pt(o),a=pt(i);e||(ps(i,a)&&zt(r,"get",i),zt(r,"get",a));const{has:l}=si(r),c=t?Ko:e?tn:ke;if(l.call(r,i))return c(o.get(i));if(l.call(r,a))return c(o.get(a));o!==r&&o.get(i)},get size(){const i=this.__v_raw;return!e&&zt(pt(i),"iterate",Ds),i.size},has(i){const o=this.__v_raw,r=pt(o),a=pt(i);return e||(ps(i,a)&&zt(r,"has",i),zt(r,"has",a)),i===a?o.has(i):o.has(i)||o.has(a)},forEach(i,o){const r=this,a=r.__v_raw,l=pt(a),c=t?Ko:e?tn:ke;return!e&&zt(l,"iterate",Ds),a.forEach((u,h)=>i.call(o,c(u),c(h),r))}};return Gt(s,e?{add:ni("add"),set:ni("set"),delete:ni("delete"),clear:ni("clear")}:{add(i){!t&&!be(i)&&!es(i)&&(i=pt(i));const o=pt(this);return si(o).has.call(o,i)||(o.add(i),qe(o,"add",i,i)),this},set(i,o){!t&&!be(o)&&!es(o)&&(o=pt(o));const r=pt(this),{has:a,get:l}=si(r);let c=a.call(r,i);c||(i=pt(i),c=a.call(r,i));const u=l.call(r,i);return r.set(i,o),c?ps(o,u)&&qe(r,"set",i,o):qe(r,"add",i,o),this},delete(i){const o=pt(this),{has:r,get:a}=si(o);let l=r.call(o,i);l||(i=pt(i),l=r.call(o,i)),a&&a.call(o,i);const c=o.delete(i);return l&&qe(o,"delete",i,void 0),c},clear(){const i=pt(this),o=i.size!==0,r=i.clear();return o&&qe(i,"clear",void 0,void 0),r}}),["keys","values","entries",Symbol.iterator].forEach(i=>{s[i]=Md(i,e,t)}),s}function Ar(e,t){const s=Cd(e,t);return(n,i,o)=>i==="__v_isReactive"?!e:i==="__v_isReadonly"?e:i==="__v_raw"?n:Reflect.get(gt(s,i)&&i in n?s:n,i,o)}const Pd={get:Ar(!1,!1)},Ad={get:Ar(!1,!0)},Rd={get:Ar(!0,!1)};const Gc=new WeakMap,Yc=new WeakMap,Xc=new WeakMap,Od=new WeakMap;function Td(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Ed(e){return e.__v_skip||!Object.isExtensible(e)?0:Td(nd(e))}function Zs(e){return es(e)?e:Rr(e,!1,wd,Pd,Gc)}function Jc(e){return Rr(e,!1,kd,Ad,Yc)}function Go(e){return Rr(e,!0,Sd,Rd,Xc)}function Rr(e,t,s,n,i){if(!yt(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const o=Ed(e);if(o===0)return e;const r=i.get(e);if(r)return r;const a=new Proxy(e,o===2?n:s);return i.set(e,a),a}function Is(e){return es(e)?Is(e.__v_raw):!!(e&&e.__v_isReactive)}function es(e){return!!(e&&e.__v_isReadonly)}function be(e){return!!(e&&e.__v_isShallow)}function Or(e){return e?!!e.__v_raw:!1}function pt(e){const t=e&&e.__v_raw;return t?pt(t):e}function Dd(e){return!gt(e,"__v_skip")&&Object.isExtensible(e)&&Dc(e,"__v_skip",!0),e}const ke=e=>yt(e)?Zs(e):e,tn=e=>yt(e)?Go(e):e;function Kt(e){return e?e.__v_isRef===!0:!1}function et(e){return Qc(e,!1)}function Id(e){return Qc(e,!0)}function Qc(e,t){return Kt(e)?e:new Ld(e,t)}class Ld{constructor(t,s){this.dep=new Pr,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=s?t:pt(t),this._value=s?t:ke(t),this.__v_isShallow=s}get value(){return this.dep.track(),this._value}set value(t){const s=this._rawValue,n=this.__v_isShallow||be(t)||es(t);t=n?t:pt(t),ps(t,s)&&(this._rawValue=t,this._value=n?t:ke(t),this.dep.trigger())}}function _e(e){return Kt(e)?e.value:e}const Fd={get:(e,t,s)=>t==="__v_raw"?e:_e(Reflect.get(e,t,s)),set:(e,t,s,n)=>{const i=e[t];return Kt(i)&&!Kt(s)?(i.value=s,!0):Reflect.set(e,t,s,n)}};function Zc(e){return Is(e)?e:new Proxy(e,Fd)}class Nd{constructor(t,s,n){this.fn=t,this.setter=s,this._value=void 0,this.dep=new Pr(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=Nn-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!s,this.isSSR=n}notify(){if(this.flags|=16,!(this.flags&8)&&wt!==this)return $c(this,!0),!0}get value(){const t=this.dep.track();return Hc(this),t&&(t.version=this.dep.version),this._value}set value(t){this.setter&&this.setter(t)}}function Bd(e,t,s=!1){let n,i;return st(e)?n=e:(n=e.get,i=e.set),new Nd(n,i,s)}const ii={},Ri=new WeakMap;let As;function $d(e,t=!1,s=As){if(s){let n=Ri.get(s);n||Ri.set(s,n=[]),n.push(e)}}function Vd(e,t,s=_t){const{immediate:n,deep:i,once:o,scheduler:r,augmentJob:a,call:l}=s,c=S=>i?S:be(S)||i===!1||i===0?Ue(S,1):Ue(S);let u,h,d,f,p=!1,g=!1;if(Kt(e)?(h=()=>e.value,p=be(e)):Is(e)?(h=()=>c(e),p=!0):J(e)?(g=!0,p=e.some(S=>Is(S)||be(S)),h=()=>e.map(S=>{if(Kt(S))return S.value;if(Is(S))return c(S);if(st(S))return l?l(S,2):S()})):st(e)?t?h=l?()=>l(e,2):e:h=()=>{if(d){Ze();try{d()}finally{ts()}}const S=As;As=u;try{return l?l(e,3,[f]):e(f)}finally{As=S}}:h=Le,t&&i){const S=h,w=i===!0?1/0:i;h=()=>Ue(S(),w)}const _=pd(),b=()=>{u.stop(),_&&_.active&&xr(_.effects,u)};if(o&&t){const S=t;t=(...w)=>{S(...w),b()}}let v=g?new Array(e.length).fill(ii):ii;const M=S=>{if(!(!(u.flags&1)||!u.dirty&&!S))if(t){const w=u.run();if(i||p||(g?w.some((R,k)=>ps(R,v[k])):ps(w,v))){d&&d();const R=As;As=u;try{const k=[w,v===ii?void 0:g&&v[0]===ii?[]:v,f];v=w,l?l(t,3,k):t(...k)}finally{As=R}}}else u.run()};return a&&a(M),u=new Nc(h),u.scheduler=r?()=>r(M,!1):M,f=S=>$d(S,!1,u),d=u.onStop=()=>{const S=Ri.get(u);if(S){if(l)l(S,4);else for(const w of S)w();Ri.delete(u)}},t?n?M(!0):v=u.run():r?r(M.bind(null,!0),!0):u.run(),b.pause=u.pause.bind(u),b.resume=u.resume.bind(u),b.stop=b,b}function Ue(e,t=1/0,s){if(t<=0||!yt(e)||e.__v_skip||(s=s||new Map,(s.get(e)||0)>=t))return e;if(s.set(e,t),t--,Kt(e))Ue(e.value,t,s);else if(J(e))for(let n=0;n{Ue(n,t,s)});else if(Ec(e)){for(const n in e)Ue(e[n],t,s);for(const n of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,n)&&Ue(e[n],t,s)}return e}function Qn(e,t,s,n){try{return n?e(...n):e()}catch(i){Ji(i,t,s)}}function Ne(e,t,s,n){if(st(e)){const i=Qn(e,t,s,n);return i&&Oc(i)&&i.catch(o=>{Ji(o,t,s)}),i}if(J(e)){const i=[];for(let o=0;o>>1,i=ee[n],o=$n(i);o=$n(s)?ee.push(e):ee.splice(Hd(t),0,e),e.flags|=1,eu()}}function eu(){Oi||(Oi=tu.then(nu))}function zd(e){J(e)?Ys.push(...e):as&&e.id===-1?as.splice(qs+1,0,e):e.flags&1||(Ys.push(e),e.flags|=1),eu()}function ua(e,t,s=Te+1){for(;s$n(s)-$n(n));if(Ys.length=0,as){as.push(...t);return}for(as=t,qs=0;qse.id==null?e.flags&2?-1:1/0:e.id;function nu(e){try{for(Te=0;Te{n._d&&Ii(-1);const o=Ti(t);let r;try{r=e(...i)}finally{Ti(o),n._d&&Ii(1)}return r};return n._n=!0,n._c=!0,n._d=!0,n}function se(e,t){if($t===null)return e;const s=no($t),n=e.dirs||(e.dirs=[]);for(let i=0;i1)return s&&st(t)?t.call(n&&n.proxy):t}}const Wd=Symbol.for("v-scx"),qd=()=>Je(Wd);function Qe(e,t,s){return ou(e,t,s)}function ou(e,t,s=_t){const{immediate:n,deep:i,flush:o,once:r}=s,a=Gt({},s),l=t&&n||!t&&o!=="post";let c;if(Hn){if(o==="sync"){const f=qd();c=f.__watcherHandles||(f.__watcherHandles=[])}else if(!l){const f=()=>{};return f.stop=Le,f.resume=Le,f.pause=Le,f}}const u=Wt;a.call=(f,p,g)=>Ne(f,u,p,g);let h=!1;o==="post"?a.scheduler=f=>{Zt(f,u&&u.suspense)}:o!=="sync"&&(h=!0,a.scheduler=(f,p)=>{p?f():Tr(f)}),a.augmentJob=f=>{t&&(f.flags|=4),h&&(f.flags|=2,u&&(f.id=u.uid,f.i=u))};const d=Vd(e,t,a);return Hn&&(c?c.push(d):l&&d()),d}function Ud(e,t,s){const n=this.proxy,i=It(e)?e.includes(".")?ru(n,e):()=>n[e]:e.bind(n,n);let o;st(t)?o=t:(o=t.handler,s=t);const r=Zn(this),a=ou(i,o.bind(n),s);return r(),a}function ru(e,t){const s=t.split(".");return()=>{let n=e;for(let i=0;ie.__isTeleport,An=e=>e&&(e.disabled||e.disabled===""),ha=e=>e&&(e.defer||e.defer===""),da=e=>typeof SVGElement<"u"&&e instanceof SVGElement,fa=e=>typeof MathMLElement=="function"&&e instanceof MathMLElement,Yo=(e,t)=>{const s=e&&e.to;return It(s)?t?t(s):null:s},lu={name:"Teleport",__isTeleport:!0,process(e,t,s,n,i,o,r,a,l,c){const{mc:u,pc:h,pbc:d,o:{insert:f,querySelector:p,createText:g,createComment:_}}=c,b=An(t.props);let{shapeFlag:v,children:M,dynamicChildren:S}=t;if(e==null){const w=t.el=g(""),R=t.anchor=g("");f(w,s,n),f(R,s,n);const k=(C,O)=>{v&16&&u(M,C,O,i,o,r,a,l)},P=()=>{const C=t.target=Yo(t.props,p),O=cu(C,t,g,f);C&&(r!=="svg"&&da(C)?r="svg":r!=="mathml"&&fa(C)&&(r="mathml"),i&&i.isCE&&(i.ce._teleportTargets||(i.ce._teleportTargets=new Set)).add(C),b||(k(C,O),Si(t,!1)))};b&&(k(s,R),Si(t,!0)),ha(t.props)?(t.el.__isMounted=!1,Zt(()=>{P(),delete t.el.__isMounted},o)):P()}else{if(ha(t.props)&&e.el.__isMounted===!1){Zt(()=>{lu.process(e,t,s,n,i,o,r,a,l,c)},o);return}t.el=e.el,t.targetStart=e.targetStart;const w=t.anchor=e.anchor,R=t.target=e.target,k=t.targetAnchor=e.targetAnchor,P=An(e.props),C=P?s:R,O=P?w:k;if(r==="svg"||da(R)?r="svg":(r==="mathml"||fa(R))&&(r="mathml"),S?(d(e.dynamicChildren,S,C,i,o,r,a),Fr(e,t,!0)):l||h(e,t,C,O,i,o,r,a,!1),b)P?t.props&&e.props&&t.props.to!==e.props.to&&(t.props.to=e.props.to):oi(t,s,w,c,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const B=t.target=Yo(t.props,p);B&&oi(t,B,null,c,0)}else P&&oi(t,R,k,c,1);Si(t,b)}},remove(e,t,s,{um:n,o:{remove:i}},o){const{shapeFlag:r,children:a,anchor:l,targetStart:c,targetAnchor:u,target:h,props:d}=e;if(h&&(i(c),i(u)),o&&i(l),r&16){const f=o||!An(d);for(let p=0;pRn(p,t&&(J(t)?t[g]:t),s,n,i));return}if(Xs(n)&&!i){n.shapeFlag&512&&n.type.__asyncResolved&&n.component.subTree.component&&Rn(e,t,s,n.component.subTree);return}const o=n.shapeFlag&4?no(n.component):n.el,r=i?null:o,{i:a,r:l}=e,c=t&&t.r,u=a.refs===_t?a.refs={}:a.refs,h=a.setupState,d=pt(h),f=h===_t?Rc:p=>gt(d,p);if(c!=null&&c!==l){if(pa(t),It(c))u[c]=null,f(c)&&(h[c]=null);else if(Kt(c)){c.value=null;const p=t;p.k&&(u[p.k]=null)}}if(st(l))Qn(l,a,12,[r,u]);else{const p=It(l),g=Kt(l);if(p||g){const _=()=>{if(e.f){const b=p?f(l)?h[l]:u[l]:l.value;if(i)J(b)&&xr(b,o);else if(J(b))b.includes(o)||b.push(o);else if(p)u[l]=[o],f(l)&&(h[l]=u[l]);else{const v=[o];l.value=v,e.k&&(u[e.k]=v)}}else p?(u[l]=r,f(l)&&(h[l]=r)):g&&(l.value=r,e.k&&(u[e.k]=r))};if(r){const b=()=>{_(),Ei.delete(e)};b.id=-1,Ei.set(e,b),Zt(b,s)}else pa(e),_()}}}function pa(e){const t=Ei.get(e);t&&(t.flags|=8,Ei.delete(e))}Yi().requestIdleCallback;Yi().cancelIdleCallback;const Xs=e=>!!e.type.__asyncLoader,du=e=>e.type.__isKeepAlive;function Jd(e,t){fu(e,"a",t)}function Qd(e,t){fu(e,"da",t)}function fu(e,t,s=Wt){const n=e.__wdc||(e.__wdc=()=>{let i=s;for(;i;){if(i.isDeactivated)return;i=i.parent}return e()});if(Zi(t,n,s),s){let i=s.parent;for(;i&&i.parent;)du(i.parent.vnode)&&Zd(n,t,s,i),i=i.parent}}function Zd(e,t,s,n){const i=Zi(t,e,n,!0);pu(()=>{xr(n[t],i)},s)}function Zi(e,t,s=Wt,n=!1){if(s){const i=s[e]||(s[e]=[]),o=t.__weh||(t.__weh=(...r)=>{Ze();const a=Zn(s),l=Ne(t,s,e,r);return a(),ts(),l});return n?i.unshift(o):i.push(o),o}}const ns=e=>(t,s=Wt)=>{(!Hn||e==="sp")&&Zi(e,(...n)=>t(...n),s)},tf=ns("bm"),to=ns("m"),ef=ns("bu"),sf=ns("u"),nf=ns("bum"),pu=ns("um"),of=ns("sp"),rf=ns("rtg"),af=ns("rtc");function lf(e,t=Wt){Zi("ec",e,t)}const cf="components";function Xo(e,t){return hf(cf,e,!0,t)||e}const uf=Symbol.for("v-ndc");function hf(e,t,s=!0,n=!1){const i=$t||Wt;if(i){const o=i.type;{const a=Jf(o,!1);if(a&&(a===t||a===xe(t)||a===Ki(xe(t))))return o}const r=ga(i[e]||o[e],t)||ga(i.appContext[e],t);return!r&&n?o:r}}function ga(e,t){return e&&(e[t]||e[xe(t)]||e[Ki(xe(t))])}function Vt(e,t,s,n){let i;const o=s,r=J(e);if(r||It(e)){const a=r&&Is(e);let l=!1,c=!1;a&&(l=!be(e),c=es(e),e=Xi(e)),i=new Array(e.length);for(let u=0,h=e.length;ut(a,l,void 0,o));else{const a=Object.keys(e);i=new Array(a.length);for(let l=0,c=a.length;l0;return L(),Ie(ut,null,[Pt("slot",s,n)],c?-2:64)}let o=e[t];o&&o._c&&(o._d=!1),L();const r=o&&gu(o(s)),a=s.key||r&&r.key,l=Ie(ut,{key:(a&&!Se(a)?a:`_${t}`)+(!r&&n?"_fb":"")},r||[],r&&e._===1?64:-2);return o&&o._c&&(o._d=!0),l}function gu(e){return e.some(t=>jn(t)?!(t.type===ss||t.type===ut&&!gu(t.children)):!0)?e:null}const Jo=e=>e?Du(e)?no(e):Jo(e.parent):null,On=Gt(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>Jo(e.parent),$root:e=>Jo(e.root),$host:e=>e.ce,$emit:e=>e.emit,$options:e=>bu(e),$forceUpdate:e=>e.f||(e.f=()=>{Tr(e.update)}),$nextTick:e=>e.n||(e.n=Qi.bind(e.proxy)),$watch:e=>Ud.bind(e)}),vo=(e,t)=>e!==_t&&!e.__isScriptSetup&>(e,t),ff={get({_:e},t){if(t==="__v_skip")return!0;const{ctx:s,setupState:n,data:i,props:o,accessCache:r,type:a,appContext:l}=e;if(t[0]!=="$"){const d=r[t];if(d!==void 0)switch(d){case 1:return n[t];case 2:return i[t];case 4:return s[t];case 3:return o[t]}else{if(vo(n,t))return r[t]=1,n[t];if(i!==_t&>(i,t))return r[t]=2,i[t];if(gt(o,t))return r[t]=3,o[t];if(s!==_t&>(s,t))return r[t]=4,s[t];Qo&&(r[t]=0)}}const c=On[t];let u,h;if(c)return t==="$attrs"&&zt(e.attrs,"get",""),c(e);if((u=a.__cssModules)&&(u=u[t]))return u;if(s!==_t&>(s,t))return r[t]=4,s[t];if(h=l.config.globalProperties,gt(h,t))return h[t]},set({_:e},t,s){const{data:n,setupState:i,ctx:o}=e;return vo(i,t)?(i[t]=s,!0):n!==_t&>(n,t)?(n[t]=s,!0):gt(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(o[t]=s,!0)},has({_:{data:e,setupState:t,accessCache:s,ctx:n,appContext:i,props:o,type:r}},a){let l;return!!(s[a]||e!==_t&&a[0]!=="$"&>(e,a)||vo(t,a)||gt(o,a)||gt(n,a)||gt(On,a)||gt(i.config.globalProperties,a)||(l=r.__cssModules)&&l[a])},defineProperty(e,t,s){return s.get!=null?e._.accessCache[t]=0:gt(s,"value")&&this.set(e,t,s.value,null),Reflect.defineProperty(e,t,s)}};function ma(e){return J(e)?e.reduce((t,s)=>(t[s]=null,t),{}):e}let Qo=!0;function pf(e){const t=bu(e),s=e.proxy,n=e.ctx;Qo=!1,t.beforeCreate&&ba(t.beforeCreate,e,"bc");const{data:i,computed:o,methods:r,watch:a,provide:l,inject:c,created:u,beforeMount:h,mounted:d,beforeUpdate:f,updated:p,activated:g,deactivated:_,beforeDestroy:b,beforeUnmount:v,destroyed:M,unmounted:S,render:w,renderTracked:R,renderTriggered:k,errorCaptured:P,serverPrefetch:C,expose:O,inheritAttrs:B,components:U,directives:at,filters:Ct}=t;if(c&&gf(c,n,null),r)for(const Y in r){const nt=r[Y];st(nt)&&(n[Y]=nt.bind(s))}if(i){const Y=i.call(s,s);yt(Y)&&(e.data=Zs(Y))}if(Qo=!0,o)for(const Y in o){const nt=o[Y],xt=st(nt)?nt.bind(s,s):st(nt.get)?nt.get.bind(s,s):Le,Xt=!st(nt)&&st(nt.set)?nt.set.bind(s):Le,Jt=qt({get:xt,set:Xt});Object.defineProperty(n,Y,{enumerable:!0,configurable:!0,get:()=>Jt.value,set:Et=>Jt.value=Et})}if(a)for(const Y in a)mu(a[Y],n,s,Y);if(l){const Y=st(l)?l.call(s):l;Reflect.ownKeys(Y).forEach(nt=>{wi(nt,Y[nt])})}u&&ba(u,e,"c");function tt(Y,nt){J(nt)?nt.forEach(xt=>Y(xt.bind(s))):nt&&Y(nt.bind(s))}if(tt(tf,h),tt(to,d),tt(ef,f),tt(sf,p),tt(Jd,g),tt(Qd,_),tt(lf,P),tt(af,R),tt(rf,k),tt(nf,v),tt(pu,S),tt(of,C),J(O))if(O.length){const Y=e.exposed||(e.exposed={});O.forEach(nt=>{Object.defineProperty(Y,nt,{get:()=>s[nt],set:xt=>s[nt]=xt,enumerable:!0})})}else e.exposed||(e.exposed={});w&&e.render===Le&&(e.render=w),B!=null&&(e.inheritAttrs=B),U&&(e.components=U),at&&(e.directives=at),C&&hu(e)}function gf(e,t,s=Le){J(e)&&(e=Zo(e));for(const n in e){const i=e[n];let o;yt(i)?"default"in i?o=Je(i.from||n,i.default,!0):o=Je(i.from||n):o=Je(i),Kt(o)?Object.defineProperty(t,n,{enumerable:!0,configurable:!0,get:()=>o.value,set:r=>o.value=r}):t[n]=o}}function ba(e,t,s){Ne(J(e)?e.map(n=>n.bind(t.proxy)):e.bind(t.proxy),t,s)}function mu(e,t,s,n){let i=n.includes(".")?ru(s,n):()=>s[n];if(It(e)){const o=t[e];st(o)&&Qe(i,o)}else if(st(e))Qe(i,e.bind(s));else if(yt(e))if(J(e))e.forEach(o=>mu(o,t,s,n));else{const o=st(e.handler)?e.handler.bind(s):t[e.handler];st(o)&&Qe(i,o,e)}}function bu(e){const t=e.type,{mixins:s,extends:n}=t,{mixins:i,optionsCache:o,config:{optionMergeStrategies:r}}=e.appContext,a=o.get(t);let l;return a?l=a:!i.length&&!s&&!n?l=t:(l={},i.length&&i.forEach(c=>Di(l,c,r,!0)),Di(l,t,r)),yt(t)&&o.set(t,l),l}function Di(e,t,s,n=!1){const{mixins:i,extends:o}=t;o&&Di(e,o,s,!0),i&&i.forEach(r=>Di(e,r,s,!0));for(const r in t)if(!(n&&r==="expose")){const a=mf[r]||s&&s[r];e[r]=a?a(e[r],t[r]):t[r]}return e}const mf={data:_a,props:ya,emits:ya,methods:xn,computed:xn,beforeCreate:Qt,created:Qt,beforeMount:Qt,mounted:Qt,beforeUpdate:Qt,updated:Qt,beforeDestroy:Qt,beforeUnmount:Qt,destroyed:Qt,unmounted:Qt,activated:Qt,deactivated:Qt,errorCaptured:Qt,serverPrefetch:Qt,components:xn,directives:xn,watch:_f,provide:_a,inject:bf};function _a(e,t){return t?e?function(){return Gt(st(e)?e.call(this,this):e,st(t)?t.call(this,this):t)}:t:e}function bf(e,t){return xn(Zo(e),Zo(t))}function Zo(e){if(J(e)){const t={};for(let s=0;st==="modelValue"||t==="model-value"?e.modelModifiers:e[`${t}Modifiers`]||e[`${xe(t)}Modifiers`]||e[`${ys(t)}Modifiers`];function wf(e,t,...s){if(e.isUnmounted)return;const n=e.vnode.props||_t;let i=s;const o=t.startsWith("update:"),r=o&&vf(n,t.slice(7));r&&(r.trim&&(i=s.map(u=>It(u)?u.trim():u)),r.number&&(i=s.map(Gi)));let a,l=n[a=mo(t)]||n[a=mo(xe(t))];!l&&o&&(l=n[a=mo(ys(t))]),l&&Ne(l,e,6,i);const c=n[a+"Once"];if(c){if(!e.emitted)e.emitted={};else if(e.emitted[a])return;e.emitted[a]=!0,Ne(c,e,6,i)}}const Sf=new WeakMap;function yu(e,t,s=!1){const n=s?Sf:t.emitsCache,i=n.get(e);if(i!==void 0)return i;const o=e.emits;let r={},a=!1;if(!st(e)){const l=c=>{const u=yu(c,t,!0);u&&(a=!0,Gt(r,u))};!s&&t.mixins.length&&t.mixins.forEach(l),e.extends&&l(e.extends),e.mixins&&e.mixins.forEach(l)}return!o&&!a?(yt(e)&&n.set(e,null),null):(J(o)?o.forEach(l=>r[l]=null):Gt(r,o),yt(e)&&n.set(e,r),r)}function eo(e,t){return!e||!qi(t)?!1:(t=t.slice(2).replace(/Once$/,""),gt(e,t[0].toLowerCase()+t.slice(1))||gt(e,ys(t))||gt(e,t))}function xa(e){const{type:t,vnode:s,proxy:n,withProxy:i,propsOptions:[o],slots:r,attrs:a,emit:l,render:c,renderCache:u,props:h,data:d,setupState:f,ctx:p,inheritAttrs:g}=e,_=Ti(e);let b,v;try{if(s.shapeFlag&4){const S=i||n,w=S;b=De(c.call(w,S,u,h,f,d,p)),v=a}else{const S=t;b=De(S.length>1?S(h,{attrs:a,slots:r,emit:l}):S(h,null)),v=t.props?a:kf(a)}}catch(S){Tn.length=0,Ji(S,e,1),b=Pt(ss)}let M=b;if(v&&g!==!1){const S=Object.keys(v),{shapeFlag:w}=M;S.length&&w&7&&(o&&S.some(yr)&&(v=Mf(v,o)),M=en(M,v,!1,!0))}return s.dirs&&(M=en(M,null,!1,!0),M.dirs=M.dirs?M.dirs.concat(s.dirs):s.dirs),s.transition&&Dr(M,s.transition),b=M,Ti(_),b}const kf=e=>{let t;for(const s in e)(s==="class"||s==="style"||qi(s))&&((t||(t={}))[s]=e[s]);return t},Mf=(e,t)=>{const s={};for(const n in e)(!yr(n)||!(n.slice(9)in t))&&(s[n]=e[n]);return s};function Cf(e,t,s){const{props:n,children:i,component:o}=e,{props:r,children:a,patchFlag:l}=t,c=o.emitsOptions;if(t.dirs||t.transition)return!0;if(s&&l>=0){if(l&1024)return!0;if(l&16)return n?va(n,r,c):!!r;if(l&8){const u=t.dynamicProps;for(let h=0;hObject.create(xu),wu=e=>Object.getPrototypeOf(e)===xu;function Af(e,t,s,n=!1){const i={},o=vu();e.propsDefaults=Object.create(null),Su(e,t,i,o);for(const r in e.propsOptions[0])r in i||(i[r]=void 0);s?e.props=n?i:Jc(i):e.type.props?e.props=i:e.props=o,e.attrs=o}function Rf(e,t,s,n){const{props:i,attrs:o,vnode:{patchFlag:r}}=e,a=pt(i),[l]=e.propsOptions;let c=!1;if((n||r>0)&&!(r&16)){if(r&8){const u=e.vnode.dynamicProps;for(let h=0;h{l=!0;const[d,f]=ku(h,t,!0);Gt(r,d),f&&a.push(...f)};!s&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}if(!o&&!l)return yt(e)&&n.set(e,Ks),Ks;if(J(o))for(let u=0;ue==="_"||e==="_ctx"||e==="$stable",Lr=e=>J(e)?e.map(De):[De(e)],Tf=(e,t,s)=>{if(t._n)return t;const n=Er((...i)=>Lr(t(...i)),s);return n._c=!1,n},Mu=(e,t,s)=>{const n=e._ctx;for(const i in e){if(Ir(i))continue;const o=e[i];if(st(o))t[i]=Tf(i,o,n);else if(o!=null){const r=Lr(o);t[i]=()=>r}}},Cu=(e,t)=>{const s=Lr(t);e.slots.default=()=>s},Pu=(e,t,s)=>{for(const n in t)(s||!Ir(n))&&(e[n]=t[n])},Ef=(e,t,s)=>{const n=e.slots=vu();if(e.vnode.shapeFlag&32){const i=t._;i?(Pu(n,t,s),s&&Dc(n,"_",i,!0)):Mu(t,n)}else t&&Cu(e,t)},Df=(e,t,s)=>{const{vnode:n,slots:i}=e;let o=!0,r=_t;if(n.shapeFlag&32){const a=t._;a?s&&a===1?o=!1:Pu(i,t,s):(o=!t.$stable,Mu(t,i)),r=t}else t&&(Cu(e,t),r={default:1});if(o)for(const a in i)!Ir(a)&&r[a]==null&&delete i[a]},Zt=Bf;function If(e){return Lf(e)}function Lf(e,t){const s=Yi();s.__VUE__=!0;const{insert:n,remove:i,patchProp:o,createElement:r,createText:a,createComment:l,setText:c,setElementText:u,parentNode:h,nextSibling:d,setScopeId:f=Le,insertStaticContent:p}=e,g=(y,x,A,T=null,I=null,E=null,j=void 0,V=null,$=!!x.dynamicChildren)=>{if(y===x)return;y&&!dn(y,x)&&(T=D(y),Et(y,I,E,!0),y=null),x.patchFlag===-2&&($=!1,x.dynamicChildren=null);const{type:F,ref:X,shapeFlag:W}=x;switch(F){case so:_(y,x,A,T);break;case ss:b(y,x,A,T);break;case So:y==null&&v(x,A,T,j);break;case ut:U(y,x,A,T,I,E,j,V,$);break;default:W&1?w(y,x,A,T,I,E,j,V,$):W&6?at(y,x,A,T,I,E,j,V,$):(W&64||W&128)&&F.process(y,x,A,T,I,E,j,V,$,K)}X!=null&&I?Rn(X,y&&y.ref,E,x||y,!x):X==null&&y&&y.ref!=null&&Rn(y.ref,null,E,y,!0)},_=(y,x,A,T)=>{if(y==null)n(x.el=a(x.children),A,T);else{const I=x.el=y.el;x.children!==y.children&&c(I,x.children)}},b=(y,x,A,T)=>{y==null?n(x.el=l(x.children||""),A,T):x.el=y.el},v=(y,x,A,T)=>{[y.el,y.anchor]=p(y.children,x,A,T,y.el,y.anchor)},M=({el:y,anchor:x},A,T)=>{let I;for(;y&&y!==x;)I=d(y),n(y,A,T),y=I;n(x,A,T)},S=({el:y,anchor:x})=>{let A;for(;y&&y!==x;)A=d(y),i(y),y=A;i(x)},w=(y,x,A,T,I,E,j,V,$)=>{if(x.type==="svg"?j="svg":x.type==="math"&&(j="mathml"),y==null)R(x,A,T,I,E,j,V,$);else{const F=y.el&&y.el._isVueCE?y.el:null;try{F&&F._beginPatch(),C(y,x,I,E,j,V,$)}finally{F&&F._endPatch()}}},R=(y,x,A,T,I,E,j,V)=>{let $,F;const{props:X,shapeFlag:W,transition:G,dirs:Q}=y;if($=y.el=r(y.type,E,X&&X.is,X),W&8?u($,y.children):W&16&&P(y.children,$,null,T,I,wo(y,E),j,V),Q&&ws(y,null,T,"created"),k($,y,y.scopeId,j,T),X){for(const vt in X)vt!=="value"&&!Mn(vt)&&o($,vt,null,X[vt],E,T);"value"in X&&o($,"value",null,X.value,E),(F=X.onVnodeBeforeMount)&&Re(F,T,y)}Q&&ws(y,null,T,"beforeMount");const ct=Ff(I,G);ct&&G.beforeEnter($),n($,x,A),((F=X&&X.onVnodeMounted)||ct||Q)&&Zt(()=>{F&&Re(F,T,y),ct&&G.enter($),Q&&ws(y,null,T,"mounted")},I)},k=(y,x,A,T,I)=>{if(A&&f(y,A),T)for(let E=0;E{for(let F=$;F{const V=x.el=y.el;let{patchFlag:$,dynamicChildren:F,dirs:X}=x;$|=y.patchFlag&16;const W=y.props||_t,G=x.props||_t;let Q;if(A&&Ss(A,!1),(Q=G.onVnodeBeforeUpdate)&&Re(Q,A,x,y),X&&ws(x,y,A,"beforeUpdate"),A&&Ss(A,!0),(W.innerHTML&&G.innerHTML==null||W.textContent&&G.textContent==null)&&u(V,""),F?O(y.dynamicChildren,F,V,A,T,wo(x,I),E):j||nt(y,x,V,null,A,T,wo(x,I),E,!1),$>0){if($&16)B(V,W,G,A,I);else if($&2&&W.class!==G.class&&o(V,"class",null,G.class,I),$&4&&o(V,"style",W.style,G.style,I),$&8){const ct=x.dynamicProps;for(let vt=0;vt{Q&&Re(Q,A,x,y),X&&ws(x,y,A,"updated")},T)},O=(y,x,A,T,I,E,j)=>{for(let V=0;V{if(x!==A){if(x!==_t)for(const E in x)!Mn(E)&&!(E in A)&&o(y,E,x[E],null,I,T);for(const E in A){if(Mn(E))continue;const j=A[E],V=x[E];j!==V&&E!=="value"&&o(y,E,V,j,I,T)}"value"in A&&o(y,"value",x.value,A.value,I)}},U=(y,x,A,T,I,E,j,V,$)=>{const F=x.el=y?y.el:a(""),X=x.anchor=y?y.anchor:a("");let{patchFlag:W,dynamicChildren:G,slotScopeIds:Q}=x;Q&&(V=V?V.concat(Q):Q),y==null?(n(F,A,T),n(X,A,T),P(x.children||[],A,X,I,E,j,V,$)):W>0&&W&64&&G&&y.dynamicChildren&&y.dynamicChildren.length===G.length?(O(y.dynamicChildren,G,A,I,E,j,V),(x.key!=null||I&&x===I.subTree)&&Fr(y,x,!0)):nt(y,x,A,X,I,E,j,V,$)},at=(y,x,A,T,I,E,j,V,$)=>{x.slotScopeIds=V,y==null?x.shapeFlag&512?I.ctx.activate(x,A,T,j,$):Ct(x,A,T,I,E,j,$):rt(y,x,$)},Ct=(y,x,A,T,I,E,j)=>{const V=y.component=qf(y,T,I);if(du(y)&&(V.ctx.renderer=K),Kf(V,!1,j),V.asyncDep){if(I&&I.registerDep(V,tt,j),!y.el){const $=V.subTree=Pt(ss);b(null,$,x,A),y.placeholder=$.el}}else tt(V,y,x,A,I,E,j)},rt=(y,x,A)=>{const T=x.component=y.component;if(Cf(y,x,A))if(T.asyncDep&&!T.asyncResolved){Y(T,x,A);return}else T.next=x,T.update();else x.el=y.el,T.vnode=x},tt=(y,x,A,T,I,E,j)=>{const V=()=>{if(y.isMounted){let{next:W,bu:G,u:Q,parent:ct,vnode:vt}=y;{const Pe=Au(y);if(Pe){W&&(W.el=vt.el,Y(y,W,j)),Pe.asyncDep.then(()=>{y.isUnmounted||V()});return}}let mt=W,oe;Ss(y,!1),W?(W.el=vt.el,Y(y,W,j)):W=vt,G&&vi(G),(oe=W.props&&W.props.onVnodeBeforeUpdate)&&Re(oe,ct,W,vt),Ss(y,!0);const re=xa(y),Ce=y.subTree;y.subTree=re,g(Ce,re,h(Ce.el),D(Ce),y,I,E),W.el=re.el,mt===null&&Pf(y,re.el),Q&&Zt(Q,I),(oe=W.props&&W.props.onVnodeUpdated)&&Zt(()=>Re(oe,ct,W,vt),I)}else{let W;const{el:G,props:Q}=x,{bm:ct,m:vt,parent:mt,root:oe,type:re}=y,Ce=Xs(x);Ss(y,!1),ct&&vi(ct),!Ce&&(W=Q&&Q.onVnodeBeforeMount)&&Re(W,mt,x),Ss(y,!0);{oe.ce&&oe.ce._def.shadowRoot!==!1&&oe.ce._injectChildStyle(re);const Pe=y.subTree=xa(y);g(null,Pe,A,T,y,I,E),x.el=Pe.el}if(vt&&Zt(vt,I),!Ce&&(W=Q&&Q.onVnodeMounted)){const Pe=x;Zt(()=>Re(W,mt,Pe),I)}(x.shapeFlag&256||mt&&Xs(mt.vnode)&&mt.vnode.shapeFlag&256)&&y.a&&Zt(y.a,I),y.isMounted=!0,x=A=T=null}};y.scope.on();const $=y.effect=new Nc(V);y.scope.off();const F=y.update=$.run.bind($),X=y.job=$.runIfDirty.bind($);X.i=y,X.id=y.uid,$.scheduler=()=>Tr(X),Ss(y,!0),F()},Y=(y,x,A)=>{x.component=y;const T=y.vnode.props;y.vnode=x,y.next=null,Rf(y,x.props,T,A),Df(y,x.children,A),Ze(),ua(y),ts()},nt=(y,x,A,T,I,E,j,V,$=!1)=>{const F=y&&y.children,X=y?y.shapeFlag:0,W=x.children,{patchFlag:G,shapeFlag:Q}=x;if(G>0){if(G&128){Xt(F,W,A,T,I,E,j,V,$);return}else if(G&256){xt(F,W,A,T,I,E,j,V,$);return}}Q&8?(X&16&&Lt(F,I,E),W!==F&&u(A,W)):X&16?Q&16?Xt(F,W,A,T,I,E,j,V,$):Lt(F,I,E,!0):(X&8&&u(A,""),Q&16&&P(W,A,T,I,E,j,V,$))},xt=(y,x,A,T,I,E,j,V,$)=>{y=y||Ks,x=x||Ks;const F=y.length,X=x.length,W=Math.min(F,X);let G;for(G=0;GX?Lt(y,I,E,!0,!1,W):P(x,A,T,I,E,j,V,$,W)},Xt=(y,x,A,T,I,E,j,V,$)=>{let F=0;const X=x.length;let W=y.length-1,G=X-1;for(;F<=W&&F<=G;){const Q=y[F],ct=x[F]=$?ls(x[F]):De(x[F]);if(dn(Q,ct))g(Q,ct,A,null,I,E,j,V,$);else break;F++}for(;F<=W&&F<=G;){const Q=y[W],ct=x[G]=$?ls(x[G]):De(x[G]);if(dn(Q,ct))g(Q,ct,A,null,I,E,j,V,$);else break;W--,G--}if(F>W){if(F<=G){const Q=G+1,ct=QG)for(;F<=W;)Et(y[F],I,E,!0),F++;else{const Q=F,ct=F,vt=new Map;for(F=ct;F<=G;F++){const he=x[F]=$?ls(x[F]):De(x[F]);he.key!=null&&vt.set(he.key,F)}let mt,oe=0;const re=G-ct+1;let Ce=!1,Pe=0;const un=new Array(re);for(F=0;F=re){Et(he,I,E,!0);continue}let Ae;if(he.key!=null)Ae=vt.get(he.key);else for(mt=ct;mt<=G;mt++)if(un[mt-ct]===0&&dn(he,x[mt])){Ae=mt;break}Ae===void 0?Et(he,I,E,!0):(un[Ae-ct]=F+1,Ae>=Pe?Pe=Ae:Ce=!0,g(he,x[Ae],A,null,I,E,j,V,$),oe++)}const na=Ce?Nf(un):Ks;for(mt=na.length-1,F=re-1;F>=0;F--){const he=ct+F,Ae=x[he],ia=x[he+1],oa=he+1{const{el:E,type:j,transition:V,children:$,shapeFlag:F}=y;if(F&6){Jt(y.component.subTree,x,A,T);return}if(F&128){y.suspense.move(x,A,T);return}if(F&64){j.move(y,x,A,K);return}if(j===ut){n(E,x,A);for(let W=0;W<$.length;W++)Jt($[W],x,A,T);n(y.anchor,x,A);return}if(j===So){M(y,x,A);return}if(T!==2&&F&1&&V)if(T===0)V.beforeEnter(E),n(E,x,A),Zt(()=>V.enter(E),I);else{const{leave:W,delayLeave:G,afterLeave:Q}=V,ct=()=>{y.ctx.isUnmounted?i(E):n(E,x,A)},vt=()=>{E._isLeaving&&E[Xd](!0),W(E,()=>{ct(),Q&&Q()})};G?G(E,ct,vt):vt()}else n(E,x,A)},Et=(y,x,A,T=!1,I=!1)=>{const{type:E,props:j,ref:V,children:$,dynamicChildren:F,shapeFlag:X,patchFlag:W,dirs:G,cacheIndex:Q}=y;if(W===-2&&(I=!1),V!=null&&(Ze(),Rn(V,null,A,y,!0),ts()),Q!=null&&(x.renderCache[Q]=void 0),X&256){x.ctx.deactivate(y);return}const ct=X&1&&G,vt=!Xs(y);let mt;if(vt&&(mt=j&&j.onVnodeBeforeUnmount)&&Re(mt,x,y),X&6)ue(y.component,A,T);else{if(X&128){y.suspense.unmount(A,T);return}ct&&ws(y,null,x,"beforeUnmount"),X&64?y.type.remove(y,x,A,K,T):F&&!F.hasOnce&&(E!==ut||W>0&&W&64)?Lt(F,x,A,!1,!0):(E===ut&&W&384||!I&&X&16)&&Lt($,x,A),T&&pe(y)}(vt&&(mt=j&&j.onVnodeUnmounted)||ct)&&Zt(()=>{mt&&Re(mt,x,y),ct&&ws(y,null,x,"unmounted")},A)},pe=y=>{const{type:x,el:A,anchor:T,transition:I}=y;if(x===ut){ie(A,T);return}if(x===So){S(y);return}const E=()=>{i(A),I&&!I.persisted&&I.afterLeave&&I.afterLeave()};if(y.shapeFlag&1&&I&&!I.persisted){const{leave:j,delayLeave:V}=I,$=()=>j(A,E);V?V(y.el,E,$):$()}else E()},ie=(y,x)=>{let A;for(;y!==x;)A=d(y),i(y),y=A;i(x)},ue=(y,x,A)=>{const{bum:T,scope:I,job:E,subTree:j,um:V,m:$,a:F}=y;Sa($),Sa(F),T&&vi(T),I.stop(),E&&(E.flags|=8,Et(j,y,x,A)),V&&Zt(V,x),Zt(()=>{y.isUnmounted=!0},x)},Lt=(y,x,A,T=!1,I=!1,E=0)=>{for(let j=E;j{if(y.shapeFlag&6)return D(y.component.subTree);if(y.shapeFlag&128)return y.suspense.next();const x=d(y.anchor||y.el),A=x&&x[au];return A?d(A):x};let q=!1;const z=(y,x,A)=>{let T;y==null?x._vnode&&(Et(x._vnode,null,null,!0),T=x._vnode.component):g(x._vnode||null,y,x,null,null,null,A),x._vnode=y,q||(q=!0,ua(T),su(),q=!1)},K={p:g,um:Et,m:Jt,r:pe,mt:Ct,mc:P,pc:nt,pbc:O,n:D,o:e};return{render:z,hydrate:void 0,createApp:xf(z)}}function wo({type:e,props:t},s){return s==="svg"&&e==="foreignObject"||s==="mathml"&&e==="annotation-xml"&&t&&t.encoding&&t.encoding.includes("html")?void 0:s}function Ss({effect:e,job:t},s){s?(e.flags|=32,t.flags|=4):(e.flags&=-33,t.flags&=-5)}function Ff(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function Fr(e,t,s=!1){const n=e.children,i=t.children;if(J(n)&&J(i))for(let o=0;o>1,e[s[a]]0&&(t[n]=s[o-1]),s[o]=n)}}for(o=s.length,r=s[o-1];o-- >0;)s[o]=r,r=t[r];return s}function Au(e){const t=e.subTree.component;if(t)return t.asyncDep&&!t.asyncResolved?t:Au(t)}function Sa(e){if(e)for(let t=0;te.__isSuspense;function Bf(e,t){t&&t.pendingBranch?J(e)?t.effects.push(...e):t.effects.push(e):zd(e)}const ut=Symbol.for("v-fgt"),so=Symbol.for("v-txt"),ss=Symbol.for("v-cmt"),So=Symbol.for("v-stc"),Tn=[];let fe=null;function L(e=!1){Tn.push(fe=e?null:[])}function $f(){Tn.pop(),fe=Tn[Tn.length-1]||null}let Vn=1;function Ii(e,t=!1){Vn+=e,e<0&&fe&&t&&(fe.hasOnce=!0)}function Tu(e){return e.dynamicChildren=Vn>0?fe||Ks:null,$f(),Vn>0&&fe&&fe.push(e),e}function N(e,t,s,n,i,o){return Tu(m(e,t,s,n,i,o,!0))}function Ie(e,t,s,n,i){return Tu(Pt(e,t,s,n,i,!0))}function jn(e){return e?e.__v_isVNode===!0:!1}function dn(e,t){return e.type===t.type&&e.key===t.key}const Eu=({key:e})=>e??null,ki=({ref:e,ref_key:t,ref_for:s})=>(typeof e=="number"&&(e=""+e),e!=null?It(e)||Kt(e)||st(e)?{i:$t,r:e,k:t,f:!!s}:e:null);function m(e,t=null,s=null,n=0,i=null,o=e===ut?0:1,r=!1,a=!1){const l={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Eu(t),ref:t&&ki(t),scopeId:iu,slotScopeIds:null,children:s,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:o,patchFlag:n,dynamicProps:i,dynamicChildren:null,appContext:null,ctx:$t};return a?(Nr(l,s),o&128&&e.normalize(l)):s&&(l.shapeFlag|=It(s)?8:16),Vn>0&&!r&&fe&&(l.patchFlag>0||o&6)&&l.patchFlag!==32&&fe.push(l),l}const Pt=Vf;function Vf(e,t=null,s=null,n=0,i=null,o=!1){if((!e||e===uf)&&(e=ss),jn(e)){const a=en(e,t,!0);return s&&Nr(a,s),Vn>0&&!o&&fe&&(a.shapeFlag&6?fe[fe.indexOf(e)]=a:fe.push(a)),a.patchFlag=-2,a}if(Qf(e)&&(e=e.__vccOpts),t){t=jf(t);let{class:a,style:l}=t;a&&!It(a)&&(t.class=kt(a)),yt(l)&&(Or(l)&&!J(l)&&(l=Gt({},l)),t.style=wr(l))}const r=It(e)?1:Ou(e)?128:Kd(e)?64:yt(e)?4:st(e)?2:0;return m(e,t,s,n,i,r,o,!0)}function jf(e){return e?Or(e)||wu(e)?Gt({},e):e:null}function en(e,t,s=!1,n=!1){const{props:i,ref:o,patchFlag:r,children:a,transition:l}=e,c=t?Hf(i||{},t):i,u={__v_isVNode:!0,__v_skip:!0,type:e.type,props:c,key:c&&Eu(c),ref:t&&t.ref?s&&o?J(o)?o.concat(ki(t)):[o,ki(t)]:ki(t):o,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:a,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==ut?r===-1?16:r|16:r,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:l,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&en(e.ssContent),ssFallback:e.ssFallback&&en(e.ssFallback),placeholder:e.placeholder,el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return l&&n&&Dr(u,l.clone(u)),u}function me(e=" ",t=0){return Pt(so,null,e,t)}function dt(e="",t=!1){return t?(L(),Ie(ss,null,e)):Pt(ss,null,e)}function De(e){return e==null||typeof e=="boolean"?Pt(ss):J(e)?Pt(ut,null,e.slice()):jn(e)?ls(e):Pt(so,null,String(e))}function ls(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:en(e)}function Nr(e,t){let s=0;const{shapeFlag:n}=e;if(t==null)t=null;else if(J(t))s=16;else if(typeof t=="object")if(n&65){const i=t.default;i&&(i._c&&(i._d=!1),Nr(e,i()),i._c&&(i._d=!0));return}else{s=32;const i=t._;!i&&!wu(t)?t._ctx=$t:i===3&&$t&&($t.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else st(t)?(t={default:t,_ctx:$t},s=32):(t=String(t),n&64?(s=16,t=[me(t)]):s=8);e.children=t,e.shapeFlag|=s}function Hf(...e){const t={};for(let s=0;sWt||$t;let Li,er;{const e=Yi(),t=(s,n)=>{let i;return(i=e[s])||(i=e[s]=[]),i.push(n),o=>{i.length>1?i.forEach(r=>r(o)):i[0](o)}};Li=t("__VUE_INSTANCE_SETTERS__",s=>Wt=s),er=t("__VUE_SSR_SETTERS__",s=>Hn=s)}const Zn=e=>{const t=Wt;return Li(e),e.scope.on(),()=>{e.scope.off(),Li(t)}},ka=()=>{Wt&&Wt.scope.off(),Li(null)};function Du(e){return e.vnode.shapeFlag&4}let Hn=!1;function Kf(e,t=!1,s=!1){t&&er(t);const{props:n,children:i}=e.vnode,o=Du(e);Af(e,n,o,t),Ef(e,i,s||t);const r=o?Gf(e,t):void 0;return t&&er(!1),r}function Gf(e,t){const s=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,ff);const{setup:n}=s;if(n){Ze();const i=e.setupContext=n.length>1?Xf(e):null,o=Zn(e),r=Qn(n,e,0,[e.props,i]),a=Oc(r);if(ts(),o(),(a||e.sp)&&!Xs(e)&&hu(e),a){if(r.then(ka,ka),t)return r.then(l=>{Ma(e,l)}).catch(l=>{Ji(l,e,0)});e.asyncDep=r}else Ma(e,r)}else Iu(e)}function Ma(e,t,s){st(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:yt(t)&&(e.setupState=Zc(t)),Iu(e)}function Iu(e,t,s){const n=e.type;e.render||(e.render=n.render||Le);{const i=Zn(e);Ze();try{pf(e)}finally{ts(),i()}}}const Yf={get(e,t){return zt(e,"get",""),e[t]}};function Xf(e){const t=s=>{e.exposed=s||{}};return{attrs:new Proxy(e.attrs,Yf),slots:e.slots,emit:e.emit,expose:t}}function no(e){return e.exposed?e.exposeProxy||(e.exposeProxy=new Proxy(Zc(Dd(e.exposed)),{get(t,s){if(s in t)return t[s];if(s in On)return On[s](e)},has(t,s){return s in t||s in On}})):e.proxy}function Jf(e,t=!0){return st(e)?e.displayName||e.name:e.name||t&&e.__name}function Qf(e){return st(e)&&"__vccOpts"in e}const qt=(e,t)=>Bd(e,t,Hn);function Lu(e,t,s){try{Ii(-1);const n=arguments.length;return n===2?yt(t)&&!J(t)?jn(t)?Pt(e,null,[t]):Pt(e,t):Pt(e,null,t):(n>3?s=Array.prototype.slice.call(arguments,2):n===3&&jn(s)&&(s=[s]),Pt(e,t,s))}finally{Ii(1)}}const Zf="3.5.26";let sr;const Ca=typeof window<"u"&&window.trustedTypes;if(Ca)try{sr=Ca.createPolicy("vue",{createHTML:e=>e})}catch{}const Fu=sr?e=>sr.createHTML(e):e=>e,tp="http://www.w3.org/2000/svg",ep="http://www.w3.org/1998/Math/MathML",ze=typeof document<"u"?document:null,Pa=ze&&ze.createElement("template"),sp={insert:(e,t,s)=>{t.insertBefore(e,s||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,s,n)=>{const i=t==="svg"?ze.createElementNS(tp,e):t==="mathml"?ze.createElementNS(ep,e):s?ze.createElement(e,{is:s}):ze.createElement(e);return e==="select"&&n&&n.multiple!=null&&i.setAttribute("multiple",n.multiple),i},createText:e=>ze.createTextNode(e),createComment:e=>ze.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>ze.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,s,n,i,o){const r=s?s.previousSibling:t.lastChild;if(i&&(i===o||i.nextSibling))for(;t.insertBefore(i.cloneNode(!0),s),!(i===o||!(i=i.nextSibling)););else{Pa.innerHTML=Fu(n==="svg"?`${e}`:n==="mathml"?`${e}`:e);const a=Pa.content;if(n==="svg"||n==="mathml"){const l=a.firstChild;for(;l.firstChild;)a.appendChild(l.firstChild);a.removeChild(l)}t.insertBefore(a,s)}return[r?r.nextSibling:t.firstChild,s?s.previousSibling:t.lastChild]}},np=Symbol("_vtc");function ip(e,t,s){const n=e[np];n&&(t=(t?[t,...n]:[...n]).join(" ")),t==null?e.removeAttribute("class"):s?e.setAttribute("class",t):e.className=t}const Fi=Symbol("_vod"),Nu=Symbol("_vsh"),Ts={name:"show",beforeMount(e,{value:t},{transition:s}){e[Fi]=e.style.display==="none"?"":e.style.display,s&&t?s.beforeEnter(e):fn(e,t)},mounted(e,{value:t},{transition:s}){s&&t&&s.enter(e)},updated(e,{value:t,oldValue:s},{transition:n}){!t!=!s&&(n?t?(n.beforeEnter(e),fn(e,!0),n.enter(e)):n.leave(e,()=>{fn(e,!1)}):fn(e,t))},beforeUnmount(e,{value:t}){fn(e,t)}};function fn(e,t){e.style.display=t?e[Fi]:"none",e[Nu]=!t}const op=Symbol(""),rp=/(?:^|;)\s*display\s*:/;function ap(e,t,s){const n=e.style,i=It(s);let o=!1;if(s&&!i){if(t)if(It(t))for(const r of t.split(";")){const a=r.slice(0,r.indexOf(":")).trim();s[a]==null&&Mi(n,a,"")}else for(const r in t)s[r]==null&&Mi(n,r,"");for(const r in s)r==="display"&&(o=!0),Mi(n,r,s[r])}else if(i){if(t!==s){const r=n[op];r&&(s+=";"+r),n.cssText=s,o=rp.test(s)}}else t&&e.removeAttribute("style");Fi in e&&(e[Fi]=o?n.display:"",e[Nu]&&(n.display="none"))}const Aa=/\s*!important$/;function Mi(e,t,s){if(J(s))s.forEach(n=>Mi(e,t,n));else if(s==null&&(s=""),t.startsWith("--"))e.setProperty(t,s);else{const n=lp(e,t);Aa.test(s)?e.setProperty(ys(n),s.replace(Aa,""),"important"):e[n]=s}}const Ra=["Webkit","Moz","ms"],ko={};function lp(e,t){const s=ko[t];if(s)return s;let n=xe(t);if(n!=="filter"&&n in e)return ko[t]=n;n=Ki(n);for(let i=0;iMo||(dp.then(()=>Mo=0),Mo=Date.now());function pp(e,t){const s=n=>{if(!n._vts)n._vts=Date.now();else if(n._vts<=s.attached)return;Ne(gp(n,s.value),t,5,[n])};return s.value=e,s.attached=fp(),s}function gp(e,t){if(J(t)){const s=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{s.call(e),e._stopped=!0},t.map(n=>i=>!i._stopped&&n&&n(i))}else return t}const La=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,mp=(e,t,s,n,i,o)=>{const r=i==="svg";t==="class"?ip(e,n,r):t==="style"?ap(e,s,n):qi(t)?yr(t)||up(e,t,s,n,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):bp(e,t,n,r))?(Ea(e,t,n),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&Ta(e,t,n,r,o,t!=="value")):e._isVueCE&&(/[A-Z]/.test(t)||!It(n))?Ea(e,xe(t),n,o,t):(t==="true-value"?e._trueValue=n:t==="false-value"&&(e._falseValue=n),Ta(e,t,n,r))};function bp(e,t,s,n){if(n)return!!(t==="innerHTML"||t==="textContent"||t in e&&La(t)&&st(s));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="autocorrect"||t==="sandbox"&&e.tagName==="IFRAME"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const i=e.tagName;if(i==="IMG"||i==="VIDEO"||i==="CANVAS"||i==="SOURCE")return!1}return La(t)&&It(s)?!1:t in e}const ms=e=>{const t=e.props["onUpdate:modelValue"]||!1;return J(t)?s=>vi(t,s):t};function _p(e){e.target.composing=!0}function Fa(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const ye=Symbol("_assign");function Na(e,t,s){return t&&(e=e.trim()),s&&(e=Gi(e)),e}const Ls={created(e,{modifiers:{lazy:t,trim:s,number:n}},i){e[ye]=ms(i);const o=n||i.props&&i.props.type==="number";Ke(e,t?"change":"input",r=>{r.target.composing||e[ye](Na(e.value,s,o))}),(s||o)&&Ke(e,"change",()=>{e.value=Na(e.value,s,o)}),t||(Ke(e,"compositionstart",_p),Ke(e,"compositionend",Fa),Ke(e,"change",Fa))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,oldValue:s,modifiers:{lazy:n,trim:i,number:o}},r){if(e[ye]=ms(r),e.composing)return;const a=(o||e.type==="number")&&!/^0\d/.test(e.value)?Gi(e.value):e.value,l=t??"";a!==l&&(document.activeElement===e&&e.type!=="range"&&(n&&t===s||i&&e.value.trim()===l)||(e.value=l))}},yp={deep:!0,created(e,t,s){e[ye]=ms(s),Ke(e,"change",()=>{const n=e._modelValue,i=sn(e),o=e.checked,r=e[ye];if(J(n)){const a=Sr(n,i),l=a!==-1;if(o&&!l)r(n.concat(i));else if(!o&&l){const c=[...n];c.splice(a,1),r(c)}}else if(cn(n)){const a=new Set(n);o?a.add(i):a.delete(i),r(a)}else r(Vu(e,o))})},mounted:Ba,beforeUpdate(e,t,s){e[ye]=ms(s),Ba(e,t,s)}};function Ba(e,{value:t,oldValue:s},n){e._modelValue=t;let i;if(J(t))i=Sr(t,n.props.value)>-1;else if(cn(t))i=t.has(n.props.value);else{if(t===s)return;i=Bs(t,Vu(e,!0))}e.checked!==i&&(e.checked=i)}const Bu={created(e,{value:t},s){e.checked=Bs(t,s.props.value),e[ye]=ms(s),Ke(e,"change",()=>{e[ye](sn(e))})},beforeUpdate(e,{value:t,oldValue:s},n){e[ye]=ms(n),t!==s&&(e.checked=Bs(t,n.props.value))}},$u={deep:!0,created(e,{value:t,modifiers:{number:s}},n){const i=cn(t);Ke(e,"change",()=>{const o=Array.prototype.filter.call(e.options,r=>r.selected).map(r=>s?Gi(sn(r)):sn(r));e[ye](e.multiple?i?new Set(o):o:o[0]),e._assigning=!0,Qi(()=>{e._assigning=!1})}),e[ye]=ms(n)},mounted(e,{value:t}){$a(e,t)},beforeUpdate(e,t,s){e[ye]=ms(s)},updated(e,{value:t}){e._assigning||$a(e,t)}};function $a(e,t){const s=e.multiple,n=J(t);if(!(s&&!n&&!cn(t))){for(let i=0,o=e.options.length;iString(c)===String(a)):r.selected=Sr(t,a)>-1}else r.selected=t.has(a);else if(Bs(sn(r),t)){e.selectedIndex!==i&&(e.selectedIndex=i);return}}!s&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function sn(e){return"_value"in e?e._value:e.value}function Vu(e,t){const s=t?"_trueValue":"_falseValue";return s in e?e[s]:t}const xp={created(e,t,s){ri(e,t,s,null,"created")},mounted(e,t,s){ri(e,t,s,null,"mounted")},beforeUpdate(e,t,s,n){ri(e,t,s,n,"beforeUpdate")},updated(e,t,s,n){ri(e,t,s,n,"updated")}};function vp(e,t){switch(e){case"SELECT":return $u;case"TEXTAREA":return Ls;default:switch(t){case"checkbox":return yp;case"radio":return Bu;default:return Ls}}}function ri(e,t,s,n,i){const r=vp(e.tagName,s.props&&s.props.type)[i];r&&r(e,t,s,n)}const wp=["ctrl","shift","alt","meta"],Sp={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>wp.some(s=>e[`${s}Key`]&&!t.includes(s))},kp=(e,t)=>{const s=e._withMods||(e._withMods={}),n=t.join(".");return s[n]||(s[n]=((i,...o)=>{for(let r=0;r{const s=e._withKeys||(e._withKeys={}),n=t.join(".");return s[n]||(s[n]=(i=>{if(!("key"in i))return;const o=ys(i.key);if(t.some(r=>r===o||Mp[r]===o))return e(i)}))},Cp=Gt({patchProp:mp},sp);let Va;function Pp(){return Va||(Va=If(Cp))}const Ap=((...e)=>{const t=Pp().createApp(...e),{mount:s}=t;return t.mount=n=>{const i=Op(n);if(!i)return;const o=t._component;!st(o)&&!o.render&&!o.template&&(o.template=i.innerHTML),i.nodeType===1&&(i.textContent="");const r=s(i,!1,Rp(i));return i instanceof Element&&(i.removeAttribute("v-cloak"),i.setAttribute("data-v-app","")),r},t});function Rp(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function Op(e){return It(e)?document.querySelector(e):e}const ne=(e,t)=>{const s=e.__vccOpts||e;for(const[n,i]of t)s[n]=i;return s},Tp={};function Ep(e,t){const s=Xo("Toast"),n=Xo("router-view");return L(),N(ut,null,[Pt(s),Pt(n)],64)}const Dp=ne(Tp,[["render",Ep]]),ja=et([]),Ha=et(window.ApiInspector);function Hu(){return ja.value=[{id:"home",label:"Home",icon:"🏠",href:Ha.value.basePath},{id:"api-stats",label:"API Stats",icon:"📚",href:Ha.value.basePath+"/stats"}],{menus:ja}}const za="data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='utf-8'?%3e%3c!--%20Uploaded%20to:%20SVG%20Repo,%20www.svgrepo.com,%20Generator:%20SVG%20Repo%20Mixer%20Tools%20--%3e%3csvg%20fill='%23ffffff'%20width='18px'%20height='18px'%20viewBox='0%200%201920%201920'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='m0%201016.081%20409.186%20409.073%2079.85-79.736-272.867-272.979h1136.415V959.611H216.169l272.866-272.866-79.85-79.85L0%201016.082ZM1465.592%20305.32l315.445%20315.445h-315.445V305.32Zm402.184%20242.372-329.224-329.11C1507.042%20187.07%201463.334%20169%201418.835%20169h-743.83v677.647h112.94V281.941h564.706v451.765h451.765v903.53H787.946V1185.47H675.003v564.705h1242.353V667.522c0-44.498-18.07-88.207-49.581-119.83Z'%20fill-rule='evenodd'/%3e%3c/svg%3e",Ip={class:"topbar"},Lp={class:"topbar-top pb-0"},Fp={class:"api-branding"},Np={class:"api-title"},Bp={class:"api-version"},$p={class:"version-badge"},Vp={class:"topbar-controls"},jp={key:0,xmlns:"http://www.w3.org/2000/svg",width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round",class:"me-1 feather-lock"},Hp={key:1,xmlns:"http://www.w3.org/2000/svg",width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round",class:"me-1 feather-unlock"},zp={class:"auth-modal-body"},Wp={class:"auth-method-selector"},qp={class:"auth-method-options"},Up={class:"auth-method-option"},Kp={class:"auth-input-section"},Gp={key:0,class:"auth-field-label"},Yp=["placeholder"],Xp={class:"auth-input-hint"},Jp={key:0},Qp={key:0,class:"auth-modal-divider"},Zp={key:1,class:"auth-modal-logout"},tg=["src"],eg=["src"],sg={key:1,class:"loading-spinner"},ng={class:"topbar-menu pb-0"},ig={key:0,class:"menu-icon"},og={class:"menu-label"},rg={__name:"Topbar",props:{apiData:{type:Object,default:()=>({title:"API Inspector",version:"1.0.0"})},loading:{type:Boolean,default:!1},authToken:{type:String,default:""},menus:{type:Array,default:()=>[]}},emits:["refresh","update:authToken","menu-click"],setup(e,{emit:t}){const s=e,n=t,i=et(null),o=et(!1),r=et(""),a=et("bearer"),l=_=>{i.value=_.id,n("menu-click",_)},c=()=>{n("update:authToken",r.value),h()},u=()=>{r.value="",n("update:authToken",""),h()},h=()=>{o.value=!1,r.value=s.authToken},d=()=>{r.value=s.authToken,o.value=!0},f=()=>{window.open("https://github.com/irabbi360/laravel-api-inspector/issues/new","_blank")},p=async()=>{try{const b=await fetch("/api/api-inspector-docs/postman");if(!b.ok)throw new Error("Failed to download Postman collection");const v=await b.blob(),M=window.URL.createObjectURL(v),S=document.createElement("a");S.href=M,S.download="postman_collection.json",document.body.appendChild(S),S.click(),document.body.removeChild(S),window.URL.revokeObjectURL(M)}catch(_){console.error("Error downloading Postman collection:",_),alert("Failed to download Postman collection")}},g=async()=>{try{const b=await fetch("/api/api-inspector-docs/openapi");if(!b.ok)throw new Error("Failed to download OpenAPI specification");const v=await b.blob(),M=window.URL.createObjectURL(v),S=document.createElement("a");S.href=M,S.download="openapi.json",document.body.appendChild(S),S.click(),document.body.removeChild(S),window.URL.revokeObjectURL(M)}catch(_){console.error("Error downloading OpenAPI specification:",_),alert("Failed to download OpenAPI specification")}};return(_,b)=>{const v=Xo("router-link");return L(),N("div",Ip,[m("div",Lp,[m("div",Fp,[m("div",Np,[me(H(e.apiData.title)+" ",1),b[5]||(b[5]=m("a",{href:"https://github.com/irabbi360/laravel-api-inspector",target:"_blank",class:"github-link"},[m("svg",{width:"30",height:"30",viewBox:"0 0 98 98",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},[m("path",{fill:"#fff","fill-rule":"evenodd","clip-rule":"evenodd",d:"M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"})])],-1))]),m("div",Bp,[b[6]||(b[6]=me(" Version ",-1)),m("span",$p,H(e.apiData.version),1)])]),m("div",Vp,[m("button",{onClick:b[0]||(b[0]=M=>d()),class:kt(["btn","btn-auth",{authenticated:e.authToken}])},[e.authToken?(L(),N("svg",jp,[...b[7]||(b[7]=[m("rect",{x:"3",y:"11",width:"18",height:"11",rx:"2",ry:"2"},null,-1),m("path",{d:"M7 11V7a5 5 0 0 1 10 0v4"},null,-1)])])):(L(),N("svg",Hp,[...b[8]||(b[8]=[m("rect",{x:"3",y:"11",width:"18",height:"11",rx:"2",ry:"2"},null,-1),m("path",{d:"M7 11V7a5 5 0 0 1 9.9-1"},null,-1)])])),me(" "+H(e.authToken?"Authenticated":"Authorize"),1)],2),o.value?(L(),N("div",{key:0,class:"auth-modal-overlay",onClick:h},[m("div",{class:"auth-modal",onClick:b[3]||(b[3]=kp(()=>{},["stop"]))},[m("div",{class:"auth-modal-header"},[b[9]||(b[9]=m("h3",null,"API Authorization",-1)),m("button",{class:"btn-modal-close",onClick:h},"✕")]),m("div",zp,[m("div",Wp,[b[11]||(b[11]=m("label",{class:"auth-method-label"},"Authorization Type",-1)),m("div",qp,[m("label",Up,[se(m("input",{type:"radio","onUpdate:modelValue":b[1]||(b[1]=M=>a.value=M),value:"bearer"},null,512),[[Bu,a.value]]),b[10]||(b[10]=m("span",null,"Bearer Token",-1))])])]),m("div",Kp,[a.value==="bearer"?(L(),N("label",Gp,[...b[12]||(b[12]=[me(" Bearer Token ",-1),m("span",{class:"auth-required"},"*",-1)])])):dt("",!0),se(m("input",{"onUpdate:modelValue":b[2]||(b[2]=M=>r.value=M),type:"password",placeholder:a.value==="bearer"?"Enter your Bearer token...":"Enter your API key...",class:"auth-modal-input",onKeyup:ju(c,["enter"])},null,40,Yp),[[Ls,r.value]]),m("div",Xp,[a.value==="bearer"?(L(),N("span",Jp," Enter your API Bearer token for authentication. ")):dt("",!0)])]),m("div",{class:"auth-modal-footer"},[m("button",{class:"btn-modal-secondary",onClick:h},"Cancel"),m("button",{class:"btn-modal-primary",onClick:c},"Apply Authorization")]),e.authToken?(L(),N("div",Qp,[...b[13]||(b[13]=[m("span",null,"Currently Authenticated",-1)])])):dt("",!0),e.authToken?(L(),N("div",Zp,[b[14]||(b[14]=m("p",{class:"auth-logout-text"},"You are currently authenticated. Click below to logout.",-1)),m("button",{class:"btn-modal-logout",onClick:u},"Logout")])):dt("",!0)])])])):dt("",!0),m("button",{onClick:p,class:"btn btn-postman",title:"Download Postman Collection"},[m("img",{src:_e(za),alt:"Export Icon",class:"export-icon me-1"},null,8,tg),b[15]||(b[15]=me(" Postman ",-1))]),m("button",{onClick:g,class:"btn btn-openapi",title:"Download OpenAPI Specification"},[m("img",{src:_e(za),alt:"Export Icon",class:"export-icon me-1"},null,8,eg),b[16]||(b[16]=me(" OpenAPI ",-1))]),m("button",{class:"btn btn-feature",onClick:f}," Feature Request "),e.loading?(L(),N("div",sg)):(L(),N("button",{key:2,onClick:b[4]||(b[4]=M=>_.$emit("refresh")),class:"btn btn-refresh"},[...b[17]||(b[17]=[m("svg",{xmlns:"http://www.w3.org/2000/svg",width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round",class:"me-1 feather-refresh-cw"},[m("polyline",{points:"23 4 23 10 17 10"}),m("polyline",{points:"1 20 1 14 7 14"}),m("path",{d:"M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"})],-1),me(" Refresh ",-1)])]))])]),m("nav",ng,[(L(!0),N(ut,null,Vt(e.menus,M=>(L(),Ie(v,{key:M.id,to:M.href,class:kt(["menu-item",{active:M.active}]),onClick:S=>l(M)},{default:Er(()=>[M.icon?(L(),N("span",ig,H(M.icon),1)):dt("",!0),m("span",og,H(M.label),1)]),_:2},1032,["to","class","onClick"]))),128))])])}}},zu=ne(rg,[["__scopeId","data-v-0325c2e2"]]),ag={class:"sidebar"},lg={class:"sidebar-search"},cg={class:"search-input-group"},ug={key:0,class:"no-results"},hg={class:"sidebar-group-title"},dg=["onClick"],fg=["title"],pg={__name:"Sidebar",props:{groupedRoutes:{type:Object,default:()=>({})},selectedRoute:{type:Object,default:null}},emits:["select-endpoint"],setup(e){const t=e,s=et(""),n=o=>t.selectedRoute?t.selectedRoute.http_method===o.http_method&&t.selectedRoute.uri===o.uri:!1,i=qt(()=>{if(!s.value.trim())return t.groupedRoutes;const o=s.value.toLowerCase().trim(),r={};return Object.entries(t.groupedRoutes).forEach(([a,l])=>{const c=l.filter(u=>{const h=u.uri.toLowerCase().includes(o),d=u.http_method.toLowerCase().includes(o),f=a.toLowerCase().includes(o);return h||d||f});c.length>0&&(r[a]=c)}),r});return(o,r)=>(L(),N("div",ag,[m("div",lg,[m("div",cg,[r[3]||(r[3]=m("svg",{class:"search-icon",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor"},[m("circle",{cx:"11",cy:"11",r:"8"}),m("path",{d:"m21 21-4.35-4.35"})],-1)),se(m("input",{"onUpdate:modelValue":r[0]||(r[0]=a=>s.value=a),type:"text",class:"search-input",placeholder:"Search endpoints...",onKeydown:r[1]||(r[1]=ju(a=>s.value="",["escape"]))},null,544),[[Ls,s.value]]),s.value?(L(),N("button",{key:0,class:"clear-button",onClick:r[2]||(r[2]=a=>s.value=""),title:"Clear search"}," ✕ ")):dt("",!0)]),s.value&&Object.keys(i.value).length===0?(L(),N("div",ug," No endpoints found ")):dt("",!0)]),(L(!0),N(ut,null,Vt(i.value,(a,l)=>(L(),N("div",{key:l,class:"sidebar-group"},[m("div",hg,H(l),1),(L(!0),N(ut,null,Vt(a,c=>(L(),N("div",{key:`${c.http_method}-${c.uri}`,class:kt(["sidebar-route",{active:n(c)}]),onClick:u=>o.$emit("select-endpoint",c)},[m("span",{class:kt(["route-method-badge",c.http_method.toLowerCase()])},H(c.http_method),3),m("span",{class:"route-path",title:c.uri},H(c.uri),9,fg)],10,dg))),128))]))),128))]))}},gg=ne(pg,[["__scopeId","data-v-a3eda4e9"]]),mg={class:"detail-header flex justify-between"},bg={class:"detail-description"},_g={class:"fs-20 font-bold me-2"},yg={key:0,class:"auth-badge"},xg={class:"detail-method-path"},vg={class:"detail-path text-truncate"},wg={__name:"DetailHeader",props:{route:{type:Object,required:!0}},setup(e){return(t,s)=>(L(),N("div",mg,[m("div",bg,[m("span",_g,H(e.route.description),1),e.route.requires_auth?(L(),N("span",yg,"Requires Auth")):dt("",!0)]),m("div",xg,[m("span",{class:kt(["detail-method-badge",e.route.http_method.toLowerCase()])},H(e.route.http_method),3),m("span",vg,H(e.route.uri),1)])]))}},Sg=ne(wg,[["__scopeId","data-v-45e22525"]]),kg={key:0,class:"section mb-4"},Mg={class:"expandable"},Cg={key:0,class:"expandable-content"},Pg={class:"param-name"},Ag={class:"param-type"},Rg={__name:"ParametersSection",props:{parameters:{type:Object,default:null}},setup(e){const t=et(!0);return(s,n)=>e.parameters&&Object.keys(e.parameters).length>0?(L(),N("div",kg,[n[3]||(n[3]=m("div",{class:"section-title"},"Parameters",-1)),m("div",Mg,[m("div",{class:"expandable-header",onClick:n[0]||(n[0]=i=>t.value=!t.value)},[...n[1]||(n[1]=[m("span",null,"Route Parameters",-1),m("span",{class:"toggle-icon"},"▼",-1)])]),t.value?(L(),N("div",Cg,[m("table",null,[n[2]||(n[2]=m("thead",null,[m("tr",null,[m("th",null,"Name"),m("th",null,"Type"),m("th",null,"Description")])],-1)),m("tbody",null,[(L(!0),N(ut,null,Vt(e.parameters,(i,o)=>(L(),N("tr",{key:o},[m("td",null,[m("span",Pg,H(o),1)]),m("td",null,[m("span",Ag,H(i.type||"string"),1)]),m("td",null,"@"+H(i.description||""),1)]))),128))])])])):dt("",!0)])])):dt("",!0)}},Og=ne(Rg,[["__scopeId","data-v-79f128c3"]]),Tg={key:0,class:"section"},Eg={class:"form-fields-info"},Dg={class:"field-label-info"},Ig={class:"field-name-info"},Lg={class:"field-meta-info"},Fg={class:"field-type-info"},Ng={key:0,class:"field-example-info"},Bg={key:1,class:"field-desc-info"},$g={__name:"RequestBodySection",props:{requestRules:{type:Object,default:null}},setup(e){return(t,s)=>e.requestRules&&Object.keys(e.requestRules).length>0?(L(),N("div",Tg,[s[1]||(s[1]=m("div",{class:"section-title"},"Request Body Parameters",-1)),m("div",Eg,[(L(!0),N(ut,null,Vt(e.requestRules,(n,i)=>(L(),N("div",{key:i,class:"form-field-info"},[m("div",Dg,[m("span",Ig,H(i),1),m("span",{class:kt([n.required?"field-required-badge":"field-optional-badge"])},H(n.required?"REQUIRED":"OPTIONAL"),3)]),m("div",Lg,[m("span",Fg,[s[0]||(s[0]=me("Type: ",-1)),m("strong",null,H(n.type||"mixed"),1)]),n.example?(L(),N("span",Ng,"Example: "+H(n.example),1)):dt("",!0),n.description?(L(),N("span",Bg,H(n.description),1)):dt("",!0)])]))),128))])])):dt("",!0)}},Vg=ne($g,[["__scopeId","data-v-155d9b8e"]]);let jg=0;const ai=et([]);function io(){const e=(s,n="success",i=3e3)=>{const o=jg++,r={id:o,message:s,type:n,duration:i,visible:!0};return ai.value.push(r),setTimeout(()=>{t(o)},i),o},t=s=>{const n=ai.value.findIndex(i=>i.id===s);n>-1&&ai.value.splice(n,1)};return{toasts:ai,showToast:e,removeToast:t}}function Hg(){const{showToast:e}=io(),t=n=>{const i=document.createElement("textarea");i.value=n,i.style.position="fixed",i.style.left="-999999px",document.body.appendChild(i),i.focus(),i.select();try{document.execCommand("copy"),e("Response schema copied to clipboard!","success")}catch(o){e("Failed to copy response schema","error"),console.error("Fallback copy error:",o)}document.body.removeChild(i)};return{copyToClipboard:n=>{navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(n).then(()=>{e("Response schema copied to clipboard!","success")}).catch(i=>{e("Failed to copy response schema","error"),console.error("Clipboard API error:",i),t(n)}):t(n)}}}const zg={class:"section"},Wg={class:"request-tester"},qg={class:"input-group"},Ug=["value"],Kg={key:0,class:"form-group"},Gg={class:"form-fields-container"},Yg=["onUpdate:modelValue","placeholder"],Xg={key:1,class:"form-group"},Jg={class:"form-fields-container"},Qg={key:0,class:"badge-required"},Zg=["onUpdate:modelValue","placeholder"],tm={key:0,class:"param-description"},em={key:2,class:"tester-tabs"},sm={key:3,class:"json-editor-container"},nm={class:"json-editor-header"},im={class:"json-editor-actions"},om={key:0,class:"saved-examples-panel"},rm={key:0,class:"no-examples"},am={key:1,class:"examples-list"},lm={class:"example-name"},cm={class:"example-timestamp"},um={class:"example-actions"},hm=["onClick"],dm=["onClick"],fm=["onClick"],pm={key:4,class:"form-fields-container"},gm={class:"field-header-minimal"},mm={class:"field-label-minimal"},bm={key:0,class:"badge-required"},_m=["onUpdate:modelValue","type","placeholder"],ym=["disabled"],xm={__name:"RequestTester",props:{requestBody:{type:String,default:"{}"},requestRules:{type:Object,default:null},sending:{type:Boolean,default:!1},route:{type:Object,default:null},pathParams:{type:Object,default:()=>({})},queryParams:{type:Object,default:()=>({})}},emits:["update:requestBody","send-request","update:pathParams","update:queryParams","update:queryParams"],setup(e,{emit:t}){const{copyToClipboard:s}=Hg(),n=e,i=t,o=et(!0),r=et({}),a=et(n.pathParams);et(n.queryParams);const l=et(n.queryParams);et(n.queryParams);const c=et("{}"),u=qt(()=>n.requestRules&&Object.keys(n.requestRules).length>0),h=qt(()=>{if(!n.route||!n.route.uri)return{};const k=n.route.uri.match(/{([^}]+)}/g);if(!k)return{};const P={};return k.forEach(C=>{const O=C.replace(/{|}/g,"");P[O]=n.pathParams[O]||""}),P}),d=()=>{const k={};Object.keys(r.value).forEach(P=>{k[P]=r.value[P]}),c.value=JSON.stringify(k,null,2),i("update:requestBody",c.value)},f=k=>{c.value=k,i("update:requestBody",k)},p=et(!1),g=et([]),_=()=>{p.value=!p.value,p.value&&v()},b=async()=>{if(!n.route)return;const k=prompt("Enter a name for this example:","Example "+new Date().toLocaleTimeString());if(k)try{(await fetch(`${window.location.origin}/api/api-inspector-docs/save-request-example`,{method:"POST",headers:{"Content-Type":"application/json","X-Requested-With":"XMLHttpRequest","X-CSRF-TOKEN":document.querySelector('meta[name="csrf-token"]')?.getAttribute("content")||""},body:JSON.stringify({route_uri:n.route.uri,route_method:n.route.http_method,body:c.value,name:k})})).ok?(alert("Example saved successfully!"),v()):alert("Failed to save example")}catch(P){console.error("Error saving example:",P),alert("Error saving example")}},v=async()=>{if(n.route)try{const k=await fetch(`${window.location.origin}/api/api-inspector-docs/get-request-examples?uri=${encodeURIComponent(n.route.uri)}&method=${n.route.http_method}`,{headers:{"X-Requested-With":"XMLHttpRequest"}});if(k.ok){const P=await k.json();g.value=P.examples||[]}}catch(k){console.error("Error loading examples:",k)}},M=k=>{c.value=k.body,i("update:requestBody",k.body),p.value=!1},S=k=>{navigator.clipboard.writeText(k.body),alert("Example copied to clipboard!")},w=async k=>{if(n.route&&confirm("Are you sure you want to delete this example?"))try{const P=g.value[k];(await fetch(`${window.location.origin}/api/api-inspector-docs/delete-request-example`,{method:"POST",headers:{"Content-Type":"application/json","X-Requested-With":"XMLHttpRequest","X-CSRF-TOKEN":document.querySelector('meta[name="csrf-token"]')?.getAttribute("content")||""},body:JSON.stringify({route_uri:n.route.uri,route_method:n.route.http_method,index:k})})).ok?v():alert("Failed to delete example")}catch(P){console.error("Error deleting example:",P),alert("Error deleting example")}},R=k=>k?new Date(k).toLocaleString():"";return Qe(()=>n.requestRules,k=>{if(k){const P={};Object.keys(k).forEach(C=>{P[C]=k[C].example||""}),r.value=P}},{immediate:!0}),Qe(()=>n.requestBody,k=>{c.value=k||"{}"},{immediate:!0}),Qe(()=>n.queryParams,k=>{k&&(l.value={...k})},{immediate:!0}),to(()=>{v()}),(k,P)=>(L(),N("div",zg,[P[13]||(P[13]=m("div",{class:"section-title"},"Send Request",-1)),m("div",Wg,[m("div",null,[m("div",qg,[m("input",{type:"text",value:e.route?e.route.uri:"",disabled:"",class:"input-with-icon"},null,8,Ug),m("button",{class:"copy-icon",title:"Copy Endpoint URL",onClick:P[0]||(P[0]=C=>_e(s)(e.route?e.route.uri:""))},[...P[8]||(P[8]=[m("svg",{xmlns:"http://www.w3.org/2000/svg",width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round",class:"feather feather-copy"},[m("rect",{x:"9",y:"9",width:"13",height:"13",rx:"2",ry:"2"}),m("path",{d:"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"})],-1)])])])]),h.value&&Object.keys(h.value).length>0?(L(),N("div",Kg,[P[9]||(P[9]=m("label",null,[m("strong",null,"Path Parameters")],-1)),m("div",Gg,[(L(!0),N(ut,null,Vt(h.value,(C,O)=>(L(),N("div",{key:O,class:"form-group"},[m("label",null,H(O),1),se(m("input",{"onUpdate:modelValue":B=>a.value[O]=B,type:"text",placeholder:`Enter ${O}`,onInput:P[1]||(P[1]=B=>k.$emit("update:pathParams",a.value))},null,40,Yg),[[Ls,a.value[O]]])]))),128))])])):dt("",!0),Object.keys(l.value).length>0?(L(),N("div",Xg,[P[10]||(P[10]=m("label",null,[m("strong",null,"Query Parameters")],-1)),m("div",Jg,[(L(!0),N(ut,null,Vt(l.value,(C,O)=>(L(),N("div",{key:O,class:"form-group"},[m("label",null,[me(H(O)+" ",1),C.required?(L(),N("span",Qg,"REQUIRED")):dt("",!0)]),se(m("input",{"onUpdate:modelValue":B=>l.value[O]=B,type:"text",placeholder:`Enter ${O}`,onInput:P[2]||(P[2]=B=>k.$emit("update:queryParams",l.value))},null,40,Zg),[[Ls,l.value[O]]]),C.description?(L(),N("div",tm,H(C.description),1)):dt("",!0)]))),128))])])):dt("",!0),u.value?(L(),N("div",em,[m("button",{class:kt(["tab-btn",{active:o.value}]),onClick:P[3]||(P[3]=C=>o.value=!0)}," JSON ",2),u.value?(L(),N("button",{key:0,class:kt(["tab-btn",{active:!o.value}]),onClick:P[4]||(P[4]=C=>o.value=!1)}," Form ",2)):dt("",!0)])):dt("",!0),o.value&&u.value?(L(),N("div",sm,[m("div",nm,[P[11]||(P[11]=m("label",null,[m("strong",null,"Request Body (JSON)")],-1)),m("div",im,[m("button",{class:"btn-small",onClick:_,title:"Manage saved examples"}," 📋 "+H(g.value.length),1)])]),p.value?(L(),N("div",om,[m("div",{class:"saved-examples-header"},[P[12]||(P[12]=m("h4",null,"Saved Examples",-1)),m("button",{class:"btn-close",onClick:_},"✕")]),g.value.length===0?(L(),N("div",rm," No saved examples yet. Save your first example below! ")):(L(),N("div",am,[(L(!0),N(ut,null,Vt(g.value,(C,O)=>(L(),N("div",{key:O,class:"example-item"},[m("div",lm,H(C.name),1),m("div",cm,H(R(C.timestamp)),1),m("div",um,[m("button",{class:"btn-action",onClick:B=>M(C),title:"Load example"},"📥",8,hm),m("button",{class:"btn-action",onClick:B=>S(C),title:"Copy to clipboard"},"📋",8,dm),m("button",{class:"btn-action btn-delete",onClick:B=>w(O),title:"Delete"},"🗑️",8,fm)])]))),128))]))])):dt("",!0),se(m("textarea",{"onUpdate:modelValue":P[5]||(P[5]=C=>c.value=C),class:"json-editor",rows:"8",placeholder:"{}",onInput:P[6]||(P[6]=C=>f(C.target.value))},null,544),[[Ls,c.value]]),m("div",{class:"json-editor-footer"},[m("button",{class:"btn-secondary",onClick:b,title:"Save current JSON as example"}," 💾 Save as Example ")])])):(L(),N("div",pm,[(L(!0),N(ut,null,Vt(e.requestRules,(C,O)=>(L(),N("div",{key:O,class:"form-field-minimal"},[m("div",gm,[m("label",mm,[me(H(O)+" ",1),C.required?(L(),N("span",bm,"REQUIRED")):dt("",!0)])]),se(m("input",{"onUpdate:modelValue":B=>r.value[O]=B,type:k.text,placeholder:`Enter ${O}`,class:"input-minimal",onInput:d},null,40,_m),[[xp,r.value[O]]])]))),128))])),m("button",{class:"btn",disabled:e.sending,onClick:P[7]||(P[7]=C=>k.$emit("send-request"))},H(e.sending?"Sending...":"Send Request"),9,ym)])]))}},vm=ne(xm,[["__scopeId","data-v-def58604"]]),wm={key:0,class:"section"},Sm={class:"bg-white",style:{border:"1px solid #e0e0e0","border-radius":"4px",padding:"15px",position:"relative"}},km={style:{padding:"10px","border-radius":"4px","overflow-x":"auto",cursor:"pointer",margin:"0"},title:"Click to copy"},Mm={key:1,class:"section"},Cm={__name:"ResponseSchema",props:{schema:{type:Object,default:null}},setup(e){const{showToast:t}=useToast(),s=e;et(!1),et("Copy schema to clipboard");const n=r=>{const a=["resource_class"],l={};return Object.keys(r).forEach(c=>{if(a.includes(c))return;const u=r[c];typeof u=="object"&&u!==null&&u.schema&&typeof u.schema=="object"?l[c]=n(u.schema):typeof u=="object"&&u!==null?l[c]=n(u):l[c]=u}),l},i=r=>{const a=document.createElement("textarea");a.value=r,a.style.position="fixed",a.style.left="-999999px",document.body.appendChild(a),a.focus(),a.select();try{document.execCommand("copy"),t("Response schema copied to clipboard!","success")}catch(l){t("Failed to copy response schema","error"),console.error("Fallback copy error:",l)}document.body.removeChild(a)},o=()=>{const r=JSON.stringify(n(s.schema),null,2);navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(r).then(()=>{t("Response schema copied to clipboard!","success")}).catch(a=>{t("Failed to copy response schema","error"),console.error("Clipboard API error:",a),i(r)}):i(r)};return(r,a)=>e.schema&&e.schema.data&&Object.keys(e.schema.data).length>0?(L(),N("div",wm,[a[0]||(a[0]=m("div",{class:"section-title"},"Response Schema",-1)),m("div",Sm,[m("button",{onClick:o,class:"pre-copy-icon",title:"Copy JSON schema"},"📋"),m("pre",km,H(JSON.stringify(n(e.schema),null,2)),1)])])):(L(),N("div",Mm,[...a[1]||(a[1]=[m("div",null,"No response schema available.",-1)])]))}},Pm=ne(Cm,[["__scopeId","data-v-4a3ad82c"]]),Am={key:0,class:"section"},Rm={class:"response-section"},Om={class:"response-code"},Tm={__name:"ResponseViewer",props:{response:{type:Object,default:null}},emits:["save-response"],setup(e){const t=n=>({200:"OK",201:"Created",204:"No Content",400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",500:"Internal Server Error"})[n]||"Unknown",s=n=>{if(typeof n=="string")try{return JSON.stringify(JSON.parse(n),null,2)}catch{return n}return JSON.stringify(n,null,2)};return(n,i)=>e.response?(L(),N("div",Am,[i[1]||(i[1]=m("div",{class:"section-title"},"Response",-1)),m("div",Rm,[m("div",{class:kt(["response-status",e.response.status<400?"success":"error"])}," Status: "+H(e.response.status)+" "+H(t(e.response.status)),3),m("div",Om,H(s(e.response.data)),1),e.response?.is_saved?dt("",!0):(L(),N("button",{key:0,class:"btn",style:{"margin-top":"15px"},onClick:i[0]||(i[0]=o=>n.$emit("save-response"))}," Save Response "))])])):dt("",!0)}},Em=ne(Tm,[["__scopeId","data-v-ab00471f"]]),Dm={key:0,class:"section"},Im={class:"saved-responses"},Lm=["onClick"],Fm={class:"saved-response-time"},Nm=["onClick"],Bm={__name:"SavedResponses",props:{responses:{type:Array,default:()=>[]},route:{type:Object,default:null}},emits:["view-response","delete-response"],setup(e,{emit:t}){const s=e,n=t,{showToast:i}=io(),o=async r=>{if(s.route)try{(await fetch(`${window.location.origin}/api/api-inspector-docs/delete-response`,{method:"DELETE",headers:{"Content-Type":"application/json","X-Requested-With":"XMLHttpRequest","X-CSRF-TOKEN":document.querySelector('meta[name="csrf-token"]')?.getAttribute("content")||""},body:JSON.stringify({route_uri:s.route.uri,route_method:s.route.http_method,index:r})})).ok?(n("delete-response",r),i("Response deleted successfully","success")):i("Failed to delete response","error")}catch(a){console.error("Error deleting response:",a),i("Error deleting response","error")}};return(r,a)=>e.responses&&e.responses.length>0?(L(),N("div",Dm,[a[0]||(a[0]=m("div",{class:"section-title"},"Saved Responses History",-1)),m("div",Im,[(L(!0),N(ut,null,Vt(e.responses,(l,c)=>(L(),N("div",{key:c,class:"saved-response-item"},[m("div",{class:"saved-response-content",onClick:u=>r.$emit("view-response",{is_saved:!0,...l})},[m("div",null,[m("strong",null,"Response "+H(e.responses.length-c),1)]),m("div",Fm,H(new Date(l.timestamp).toLocaleString()),1)],8,Lm),m("button",{class:"delete-btn",onClick:u=>o(c),title:"Delete this response"}," ✕ ",8,Nm)]))),128))])])):dt("",!0)}},$m=ne(Bm,[["__scopeId","data-v-2e6a99d1"]]),Vm={class:"tabs-component"},jm={class:"tab-header"},Hm=["onClick"],zm={class:"tab-body"},Wm={__name:"Tabs",props:{tabs:{type:Array,required:!0},modelValue:{type:Number,default:0}},emits:["update:modelValue"],setup(e){return(t,s)=>(L(),N("div",Vm,[m("div",jm,[(L(!0),N(ut,null,Vt(e.tabs,(n,i)=>(L(),N("button",{key:i,class:kt(["tab",{active:e.modelValue===i}]),onClick:o=>t.$emit("update:modelValue",i)},H(n),11,Hm))),128))]),m("div",zm,[df(t.$slots,"default",{activeTab:e.modelValue},void 0)])]))}},qm=ne(Wm,[["__scopeId","data-v-cbcf88f8"]]),Um={class:"api-info-container"},Km={key:0,class:"info-section"},Gm={class:"info-group"},Ym={class:"info-value"},Xm={class:"info-group"},Jm={class:"info-value"},Qm={class:"info-group"},Zm={class:"info-value"},tb={key:0,class:"info-group"},eb={class:"info-value middlewares-value"},sb={class:"info-group"},nb={class:"info-link"},ib={class:"collapsible-content"},ob={class:"response-codes-list"},rb={key:0,class:"empty-content"},ab={class:"info-group"},lb={class:"info-link"},cb={class:"collapsible-content"},ub={class:"curl-command"},hb={readonly:"",rows:"6"},db={__name:"ApiInfo",props:{apiInfo:{type:Object,default:null},requestRules:{type:Object,default:null},parameters:{type:Object,default:null}},setup(e){const{showToast:t}=useToast(),s=e,n=et(!1),i=et({statusCodes:!1,curl:!1}),o=h=>{i.value[h]=!i.value[h]},r=qt(()=>{if(!s.apiInfo)return"";const h=s.apiInfo.http_method||"GET";let d=s.apiInfo.uri||"/";const f=window.location.origin,p=d.match(/{([^}]+)}/g)||[],g={};p.forEach(S=>{const w=S.replace(/{|}/g,"");g[w]=`{${w}}`});let _=`${f}${d}`;s.parameters&&typeof s.parameters=="object"&&Object.keys(s.parameters).forEach(S=>{_=_.replace(`{${S}}`,`{${S}}`)});let b=`curl \\ -X ${h} \\ `;b+=` -H "Content-Type: application/json" \\ `,b+=` -H "Accept: application/json" \\ `,p.length>0&&(b+=` -H "# Path Parameters:" \\ `,Object.keys(g).forEach(S=>{b+=` -H "# ${S}: " \\ `})),b+=` "${_}"`;const v=[];if(s.requestRules&&Object.entries(s.requestRules).forEach(([S,w])=>{(h==="GET"||h==="DELETE")&&v.push({name:S,example:w.example||""})}),v.length>0&&(h==="GET"||h==="DELETE")&&(b+="?",v.forEach((S,w)=>{b+=`${S.name}=${S.example||"value"}`,w0){const S=Object.entries(s.requestRules);S.forEach(([w,R],k)=>{const P=R.example||"",C=typeof P=="string"?`"${P}"`:P;b+=` "${w}": ${C}`,k{navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(h).then(()=>{t("Curl command copied to clipboard!","success")}).catch(d=>{t("Failed to copy curl command","error"),n.value=!0,console.error("Clipboard API error:",d),u(h)}):u(h)},l={200:"OK",201:"Created",204:"No Content",400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",409:"Conflict",422:"Unprocessable Entity",429:"Too Many Requests",500:"Internal Server Error",502:"Bad Gateway",503:"Service Unavailable"},c=h=>l[h]||"Unknown Status",u=h=>{try{const d=document.createElement("textarea");d.value=h,d.style.position="fixed",d.style.opacity="0",d.style.pointerEvents="none",document.body.appendChild(d),d.select(),d.setSelectionRange(0,99999),document.execCommand("copy")?t("Curl command copied to clipboard!","success"):(t("Failed to copy curl command","error"),n.value=!0),document.body.removeChild(d)}catch(d){console.error("Fallback copy error:",d),t("Could not copy curl command. Please try again.","error")}};return(h,d)=>(L(),N("div",Um,[e.apiInfo?(L(),N("div",Km,[m("div",Gm,[d[3]||(d[3]=m("div",{class:"info-label"},"Method",-1)),m("div",Ym,[m("span",{class:kt(["method-badge",`method-${(e.apiInfo.http_method||"GET").toLowerCase()}`])},H(e.apiInfo.http_method),3)])]),m("div",Xm,[d[4]||(d[4]=m("div",{class:"info-label"},"Controller",-1)),m("div",Jm,H(e.apiInfo.controller||"-"),1)]),m("div",Qm,[d[5]||(d[5]=m("div",{class:"info-label"},"Function",-1)),m("div",Zm,H(e.apiInfo.method||"-"),1)]),e.apiInfo.middleware&&e.apiInfo.middleware.length>0?(L(),N("div",tb,[d[6]||(d[6]=m("div",{class:"info-label"},"Middlewares",-1)),m("div",eb,[(L(!0),N(ut,null,Vt(e.apiInfo.middleware,(f,p)=>(L(),N("span",{key:p,class:"middleware-badge"},H(f),1))),128))])])):dt("",!0),m("div",sb,[d[7]||(d[7]=m("div",{class:"info-label"},"Status Codes",-1)),m("div",nb,[m("div",null,[m("span",{class:kt(["arrow",{expanded:i.value.statusCodes}])},"›",2),m("span",{onClick:d[0]||(d[0]=f=>o("statusCodes"))},H(i.value.statusCodes?"Hide":"Show")+" Response codes for this request",1),se(m("div",ib,[m("div",ob,[(L(!0),N(ut,null,Vt(e.apiInfo.responses||[],f=>(L(),N("div",{key:f,class:kt(["response",`response-${f}`])}," - "+H(f)+"   "+H(c(f)),3))),128))]),!e.apiInfo.responses||e.apiInfo.responses.length===0?(L(),N("div",rb," No response codes defined ")):dt("",!0)],512),[[Ts,i.value.statusCodes]])])])]),m("div",ab,[d[8]||(d[8]=m("div",{class:"info-label"},"Curl",-1)),m("div",lb,[m("div",null,[m("span",{class:kt(["arrow",{expanded:i.value.curl}])},"›",2),m("span",{onClick:d[1]||(d[1]=f=>o("curl"))},H(i.value.curl?"Hide":"Show")+" curl command",1),se(m("div",cb,[m("div",ub,[m("div",null,[m("textarea",hb,H(r.value),1)]),m("button",{class:"copy-btn",onClick:d[2]||(d[2]=f=>a(r.value))},"Copy")])],512),[[Ts,i.value.curl]])])])])])):dt("",!0)]))}},fb=ne(db,[["__scopeId","data-v-8f8eb8b4"]]),pb={class:"endpoint-detail"},gb={class:"detail-body"},mb={class:"detail-body-left"},bb={class:"detail-body-right"},_b={class:"tab-content"},yb={key:1,class:"empty-state"},xb={key:1},vb={class:"tab-content"},wb={key:1,class:"empty-state"},Sb={class:"tab-content"},kb={key:1,class:"empty-state"},Mb={class:"tab-content"},Cb={key:1,class:"empty-state"},Pb={class:"tab-content"},Ab={__name:"EndpointDetail",props:{route:{type:Object,required:!0},requestBody:{type:String,default:"{}"},lastResponse:{type:Object,default:null},savedResponses:{type:Array,default:()=>[]},sending:{type:Boolean,default:!1},pathParams:{type:Object,default:()=>({})},queryParams:{type:Object,default:()=>({})}},emits:["update:requestBody","send-request","save-response","view-response","update:pathParams","update:queryParams","delete-response"],setup(e){const t=e,s=et(0);return Qe(()=>t.lastResponse,n=>{n&&(s.value=1)}),(n,i)=>(L(),N("div",pb,[Pt(Sg,{route:e.route},null,8,["route"]),m("div",gb,[m("div",mb,[Pt(Og,{parameters:e.route.parameters},null,8,["parameters"]),Pt(vm,{"request-body":e.requestBody,"request-rules":e.route.request_rules,sending:e.sending,route:e.route,"path-params":e.pathParams,"query-params":e.queryParams,"onUpdate:requestBody":i[0]||(i[0]=o=>n.$emit("update:requestBody",o)),onSendRequest:i[1]||(i[1]=o=>n.$emit("send-request")),"onUpdate:pathParams":i[2]||(i[2]=o=>n.$emit("update:pathParams",o)),"onUpdate:queryParams":i[3]||(i[3]=o=>n.$emit("update:queryParams",o))},null,8,["request-body","request-rules","sending","route","path-params","query-params"])]),m("div",bb,[Pt(qm,{modelValue:s.value,"onUpdate:modelValue":i[7]||(i[7]=o=>s.value=o),tabs:["Request Body","Response","Saved Responses","Response Schema","Info"]},{default:Er(({activeTab:o})=>[se(m("div",_b,[e.route.request_rules&&Object.keys(e.route.request_rules).length>0?(L(),Ie(Vg,{key:0,"request-rules":e.route.request_rules},null,8,["request-rules"])):(L(),N("div",yb,[i[10]||(i[10]=m("div",{class:"empty-state-icon"},"📄",-1)),e.route.http_method!=="GET"&&e.route.http_method!=="DELETE"?(L(),N(ut,{key:0},[i[8]||(i[8]=m("p",null,"Request body not available!",-1)),i[9]||(i[9]=m("p",null,"Please use the request rules for expected payload.",-1))],64)):dt("",!0),e.route.http_method==="GET"?(L(),N("p",xb," This endpoint does not accept a request body. ")):dt("",!0)]))],512),[[Ts,o===0]]),se(m("div",vb,[e.lastResponse?(L(),Ie(Em,{key:0,response:e.lastResponse,schema:e.route.response_schema,onSaveResponse:i[4]||(i[4]=r=>n.$emit("save-response"))},null,8,["response","schema"])):(L(),N("div",wb,[...i[11]||(i[11]=[m("div",{class:"empty-state-icon"},"📄",-1),m("p",null,"Send a request to see the response",-1)])]))],512),[[Ts,o===1]]),se(m("div",Sb,[e.savedResponses&&e.savedResponses.length>0?(L(),Ie($m,{key:0,responses:e.savedResponses,route:e.route,onViewResponse:i[5]||(i[5]=r=>n.$emit("view-response",r)),onDeleteResponse:i[6]||(i[6]=r=>n.$emit("delete-response",r))},null,8,["responses","route"])):(L(),N("div",kb,[...i[12]||(i[12]=[m("div",{class:"empty-state-icon"},"📄",-1),m("p",null,"Saved responses empty!",-1)])]))],512),[[Ts,o===2]]),se(m("div",Mb,[e.route.response_schema&&Object.keys(e.route.response_schema).length>0?(L(),Ie(Pm,{key:0,schema:e.route.response_schema},null,8,["schema"])):(L(),N("div",Cb,[...i[13]||(i[13]=[m("div",{class:"empty-state-icon"},"📄",-1),m("p",{class:"text-center"},"Response schema not available!",-1),m("p",{class:"text-center"},"Please use the resource class to define the response schema.",-1)])]))],512),[[Ts,o===3]]),se(m("div",Pb,[Pt(fb,{"api-info":e.route,"request-rules":e.route.request_rules,parameters:e.route.parameters},null,8,["api-info","request-rules","parameters"])],512),[[Ts,o===4]])]),_:1},8,["modelValue"])])])]))}},Rb=ne(Ab,[["__scopeId","data-v-d0e6e422"]]),Ob={class:"app-container"},Tb={class:"main-container"},Eb={class:"content"},Db={key:1,class:"empty-state"},Ib={class:"text-center mb-4"},Lb={class:"fs-small"},Fb={__name:"Home",setup(e){const t=et(!0),s=et(!1),n=et({routes:[],...window.ApiInspector}),i=et(null),o=et("{}"),r=et(null),a=et([]),l=et(localStorage.getItem("api-docs-auth-token")||""),c=et({}),u=et({}),{showToast:h}=useToast(),{menus:d}=Hu(),f=qt(()=>n.value.routes?n.value.routes.reduce((w,R)=>{const k=R.group||"Other";return w[k]||(w[k]=[]),w[k].push(R),w},{}):{}),p=async()=>{try{t.value=!0;const w=await fetch(`${window.location.origin}/api/api-inspector-docs?groupBy=api_uri`,{headers:{"X-Requested-With":"XMLHttpRequest",Authorization:l.value?`Bearer ${l.value}`:""}});if(!w.ok)throw new Error(`HTTP error! status: ${w.status}`);const R=await w.json();n.value={routes:R.routes||[],title:R.title||window.apiInspector?.title||"API Documentation",version:R.version||"1.0.0"}}catch(w){console.error("Error fetching API data:",w),n.value={routes:[],title:"Error",version:"1.0.0"}}finally{t.value=!1}},g=w=>{if(i.value=JSON.parse(JSON.stringify(w)),w.request_rules&&Object.keys(w.request_rules).length>0){const R={};Object.keys(w.request_rules).forEach(k=>{R[k]=w.request_rules[k].example||""}),o.value=JSON.stringify(R,null,2)}else o.value="{}";w.parameters&&Object.keys(w.parameters).length>0?(c.value={},Object.keys(w.parameters).forEach(R=>{c.value[R]=""})):c.value={},w.query_params&&Object.keys(w.query_params).length>0?(u.value={},Object.keys(w.query_params).forEach(R=>{u.value[R]=""})):u.value={},r.value=null,v()},_=async()=>{if(!i.value)return;const w=Object.entries(c.value).filter(([R,k])=>!k||k.trim()==="");if(w.length>0){const R=w.map(([k])=>k).join(", ");h(`Required path parameters missing: ${R}`,"error");return}try{s.value=!0;let R=i.value.uri;Object.keys(c.value).forEach(at=>{R=R.replace(`{${at}}`,c.value[at])}),R=R.split("?")[0];const k=Object.entries(u.value).filter(([at,Ct])=>Ct&&Ct.trim()!=="").map(([at,Ct])=>`${encodeURIComponent(at)}=${encodeURIComponent(Ct)}`).join("&");k&&(R=R+"?"+k);const P=`${window.location.origin}/${R.replace(/^\//,"")}`,C={method:i.value.http_method,headers:{"Content-Type":"application/json",Accept:"application/json","X-Requested-With":"XMLHttpRequest","X-CSRF-TOKEN":document.querySelector('meta[name="csrf-token"]')?.getAttribute("content")||""}};l.value&&(C.headers.Authorization=`Bearer ${l.value}`),i.value.http_method!=="GET"&&i.value.http_method!=="HEAD"&&(C.body=o.value);const O=await fetch(P,C),B=O.headers.get("content-type");let U="";B?.includes("application/json")?U=await O.json():U=await O.text(),r.value={status:O.status,data:U,timestamp:new Date().toISOString()}}catch(R){console.error("Error sending request:",R),r.value={status:0,data:`Error: ${R.message}`,timestamp:new Date().toISOString()}}finally{s.value=!1}},b=async()=>{if(!(!i.value||!r.value))try{(await fetch(`${window.location.origin}/api/api-inspector-docs/save-response`,{method:"POST",headers:{"Content-Type":"application/json","X-Requested-With":"XMLHttpRequest","X-CSRF-TOKEN":document.querySelector('meta[name="csrf-token"]')?.getAttribute("content")||""},body:JSON.stringify({route_uri:i.value.uri,route_method:i.value.http_method,response:r.value.data,status:r.value.status})})).ok?(v(),h("Response saved successfully!","success")):h("Failed to save response","error")}catch(w){console.error("Error saving response:",w),h("Error saving response","error")}},v=async()=>{if(i.value)try{const w=await fetch(`${window.location.origin}/api/api-inspector-docs/get-saved-responses?uri=${encodeURIComponent(i.value.uri)}&method=${i.value.http_method}`,{headers:{"X-Requested-With":"XMLHttpRequest"}});if(w.ok){const R=await w.json();a.value=R.responses||[]}}catch(w){console.error("Error loading saved responses:",w)}},M=w=>{r.value=w},S=w=>{a.value.length>w&&a.value.splice(w,1)};return Qe(l,w=>{w?localStorage.setItem("api-docs-auth-token",w):localStorage.removeItem("api-docs-auth-token")}),to(()=>{p()}),(w,R)=>(L(),N("div",Ob,[Pt(zu,{"api-data":n.value,loading:t.value,"auth-token":l.value,menus:_e(d),onRefresh:p,"onUpdate:authToken":R[0]||(R[0]=k=>l.value=k)},null,8,["api-data","loading","auth-token","menus"]),m("div",Tb,[Pt(gg,{"grouped-routes":f.value,"selected-route":i.value,onSelectEndpoint:g},null,8,["grouped-routes","selected-route"]),m("div",Eb,[i.value?(L(),Ie(Rb,{key:0,route:i.value,"request-body":o.value,"last-response":r.value,"saved-responses":a.value,sending:s.value,"path-params":c.value,"query-params":u.value,"onUpdate:requestBody":R[1]||(R[1]=k=>o.value=k),onSendRequest:_,onSaveResponse:b,onViewResponse:M,"onUpdate:pathParams":R[2]||(R[2]=k=>c.value=k),"onUpdate:queryParams":R[3]||(R[3]=k=>u.value=k),onDeleteResponse:S},null,8,["route","request-body","last-response","saved-responses","sending","path-params","query-params"])):(L(),N("div",Db,[R[6]||(R[6]=m("div",{class:"empty-state-icon"},"🚀",-1)),m("div",Ib,[m("h4",null,"Welcome to "+H(n.value.title),1),R[4]||(R[4]=m("p",{class:"fs-small"},[m("strong",null,"Laravel API Inspector"),me(" automatically generates API documentation from your Laravel routes,")],-1)),R[5]||(R[5]=m("p",{class:"fs-small"}," FormRequest validation rules, and API Resources. It's like Postman + Swagger combined, but deeply integrated with Laravel.",-1)),m("p",Lb,"Version: "+H(n.value.version),1)]),R[7]||(R[7]=m("p",null,"Select an endpoint from the sidebar to get started",-1))]))])])]))}},Nb=ne(Fb,[["__scopeId","data-v-0a7e40cc"]]);function ti(e){return e+.5|0}const us=(e,t,s)=>Math.max(Math.min(e,s),t);function vn(e){return us(ti(e*2.55),0,255)}function gs(e){return us(ti(e*255),0,255)}function We(e){return us(ti(e/2.55)/100,0,1)}function Wa(e){return us(ti(e*100),0,100)}const ge={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},nr=[..."0123456789ABCDEF"],Bb=e=>nr[e&15],$b=e=>nr[(e&240)>>4]+nr[e&15],li=e=>(e&240)>>4===(e&15),Vb=e=>li(e.r)&&li(e.g)&&li(e.b)&&li(e.a);function jb(e){var t=e.length,s;return e[0]==="#"&&(t===4||t===5?s={r:255&ge[e[1]]*17,g:255&ge[e[2]]*17,b:255&ge[e[3]]*17,a:t===5?ge[e[4]]*17:255}:(t===7||t===9)&&(s={r:ge[e[1]]<<4|ge[e[2]],g:ge[e[3]]<<4|ge[e[4]],b:ge[e[5]]<<4|ge[e[6]],a:t===9?ge[e[7]]<<4|ge[e[8]]:255})),s}const Hb=(e,t)=>e<255?t(e):"";function zb(e){var t=Vb(e)?Bb:$b;return e?"#"+t(e.r)+t(e.g)+t(e.b)+Hb(e.a,t):void 0}const Wb=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function Wu(e,t,s){const n=t*Math.min(s,1-s),i=(o,r=(o+e/30)%12)=>s-n*Math.max(Math.min(r-3,9-r,1),-1);return[i(0),i(8),i(4)]}function qb(e,t,s){const n=(i,o=(i+e/60)%6)=>s-s*t*Math.max(Math.min(o,4-o,1),0);return[n(5),n(3),n(1)]}function Ub(e,t,s){const n=Wu(e,1,.5);let i;for(t+s>1&&(i=1/(t+s),t*=i,s*=i),i=0;i<3;i++)n[i]*=1-t-s,n[i]+=t;return n}function Kb(e,t,s,n,i){return e===i?(t-s)/n+(t.5?u/(2-o-r):u/(o+r),l=Kb(s,n,i,u,o),l=l*60+.5),[l|0,c||0,a]}function $r(e,t,s,n){return(Array.isArray(t)?e(t[0],t[1],t[2]):e(t,s,n)).map(gs)}function Vr(e,t,s){return $r(Wu,e,t,s)}function Gb(e,t,s){return $r(Ub,e,t,s)}function Yb(e,t,s){return $r(qb,e,t,s)}function qu(e){return(e%360+360)%360}function Xb(e){const t=Wb.exec(e);let s=255,n;if(!t)return;t[5]!==n&&(s=t[6]?vn(+t[5]):gs(+t[5]));const i=qu(+t[2]),o=+t[3]/100,r=+t[4]/100;return t[1]==="hwb"?n=Gb(i,o,r):t[1]==="hsv"?n=Yb(i,o,r):n=Vr(i,o,r),{r:n[0],g:n[1],b:n[2],a:s}}function Jb(e,t){var s=Br(e);s[0]=qu(s[0]+t),s=Vr(s),e.r=s[0],e.g=s[1],e.b=s[2]}function Qb(e){if(!e)return;const t=Br(e),s=t[0],n=Wa(t[1]),i=Wa(t[2]);return e.a<255?`hsla(${s}, ${n}%, ${i}%, ${We(e.a)})`:`hsl(${s}, ${n}%, ${i}%)`}const qa={x:"dark",Z:"light",Y:"re",X:"blu",W:"gr",V:"medium",U:"slate",A:"ee",T:"ol",S:"or",B:"ra",C:"lateg",D:"ights",R:"in",Q:"turquois",E:"hi",P:"ro",O:"al",N:"le",M:"de",L:"yello",F:"en",K:"ch",G:"arks",H:"ea",I:"ightg",J:"wh"},Ua={OiceXe:"f0f8ff",antiquewEte:"faebd7",aqua:"ffff",aquamarRe:"7fffd4",azuY:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"0",blanKedOmond:"ffebcd",Xe:"ff",XeviTet:"8a2be2",bPwn:"a52a2a",burlywood:"deb887",caMtXe:"5f9ea0",KartYuse:"7fff00",KocTate:"d2691e",cSO:"ff7f50",cSnflowerXe:"6495ed",cSnsilk:"fff8dc",crimson:"dc143c",cyan:"ffff",xXe:"8b",xcyan:"8b8b",xgTMnPd:"b8860b",xWay:"a9a9a9",xgYF:"6400",xgYy:"a9a9a9",xkhaki:"bdb76b",xmagFta:"8b008b",xTivegYF:"556b2f",xSange:"ff8c00",xScEd:"9932cc",xYd:"8b0000",xsOmon:"e9967a",xsHgYF:"8fbc8f",xUXe:"483d8b",xUWay:"2f4f4f",xUgYy:"2f4f4f",xQe:"ced1",xviTet:"9400d3",dAppRk:"ff1493",dApskyXe:"bfff",dimWay:"696969",dimgYy:"696969",dodgerXe:"1e90ff",fiYbrick:"b22222",flSOwEte:"fffaf0",foYstWAn:"228b22",fuKsia:"ff00ff",gaRsbSo:"dcdcdc",ghostwEte:"f8f8ff",gTd:"ffd700",gTMnPd:"daa520",Way:"808080",gYF:"8000",gYFLw:"adff2f",gYy:"808080",honeyMw:"f0fff0",hotpRk:"ff69b4",RdianYd:"cd5c5c",Rdigo:"4b0082",ivSy:"fffff0",khaki:"f0e68c",lavFMr:"e6e6fa",lavFMrXsh:"fff0f5",lawngYF:"7cfc00",NmoncEffon:"fffacd",ZXe:"add8e6",ZcSO:"f08080",Zcyan:"e0ffff",ZgTMnPdLw:"fafad2",ZWay:"d3d3d3",ZgYF:"90ee90",ZgYy:"d3d3d3",ZpRk:"ffb6c1",ZsOmon:"ffa07a",ZsHgYF:"20b2aa",ZskyXe:"87cefa",ZUWay:"778899",ZUgYy:"778899",ZstAlXe:"b0c4de",ZLw:"ffffe0",lime:"ff00",limegYF:"32cd32",lRF:"faf0e6",magFta:"ff00ff",maPon:"800000",VaquamarRe:"66cdaa",VXe:"cd",VScEd:"ba55d3",VpurpN:"9370db",VsHgYF:"3cb371",VUXe:"7b68ee",VsprRggYF:"fa9a",VQe:"48d1cc",VviTetYd:"c71585",midnightXe:"191970",mRtcYam:"f5fffa",mistyPse:"ffe4e1",moccasR:"ffe4b5",navajowEte:"ffdead",navy:"80",Tdlace:"fdf5e6",Tive:"808000",TivedBb:"6b8e23",Sange:"ffa500",SangeYd:"ff4500",ScEd:"da70d6",pOegTMnPd:"eee8aa",pOegYF:"98fb98",pOeQe:"afeeee",pOeviTetYd:"db7093",papayawEp:"ffefd5",pHKpuff:"ffdab9",peru:"cd853f",pRk:"ffc0cb",plum:"dda0dd",powMrXe:"b0e0e6",purpN:"800080",YbeccapurpN:"663399",Yd:"ff0000",Psybrown:"bc8f8f",PyOXe:"4169e1",saddNbPwn:"8b4513",sOmon:"fa8072",sandybPwn:"f4a460",sHgYF:"2e8b57",sHshell:"fff5ee",siFna:"a0522d",silver:"c0c0c0",skyXe:"87ceeb",UXe:"6a5acd",UWay:"708090",UgYy:"708090",snow:"fffafa",sprRggYF:"ff7f",stAlXe:"4682b4",tan:"d2b48c",teO:"8080",tEstN:"d8bfd8",tomato:"ff6347",Qe:"40e0d0",viTet:"ee82ee",JHt:"f5deb3",wEte:"ffffff",wEtesmoke:"f5f5f5",Lw:"ffff00",LwgYF:"9acd32"};function Zb(){const e={},t=Object.keys(Ua),s=Object.keys(qa);let n,i,o,r,a;for(n=0;n>16&255,o>>8&255,o&255]}return e}let ci;function t_(e){ci||(ci=Zb(),ci.transparent=[0,0,0,0]);const t=ci[e.toLowerCase()];return t&&{r:t[0],g:t[1],b:t[2],a:t.length===4?t[3]:255}}const e_=/^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;function s_(e){const t=e_.exec(e);let s=255,n,i,o;if(t){if(t[7]!==n){const r=+t[7];s=t[8]?vn(r):us(r*255,0,255)}return n=+t[1],i=+t[3],o=+t[5],n=255&(t[2]?vn(n):us(n,0,255)),i=255&(t[4]?vn(i):us(i,0,255)),o=255&(t[6]?vn(o):us(o,0,255)),{r:n,g:i,b:o,a:s}}}function n_(e){return e&&(e.a<255?`rgba(${e.r}, ${e.g}, ${e.b}, ${We(e.a)})`:`rgb(${e.r}, ${e.g}, ${e.b})`)}const Co=e=>e<=.0031308?e*12.92:Math.pow(e,1/2.4)*1.055-.055,zs=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4);function i_(e,t,s){const n=zs(We(e.r)),i=zs(We(e.g)),o=zs(We(e.b));return{r:gs(Co(n+s*(zs(We(t.r))-n))),g:gs(Co(i+s*(zs(We(t.g))-i))),b:gs(Co(o+s*(zs(We(t.b))-o))),a:e.a+s*(t.a-e.a)}}function ui(e,t,s){if(e){let n=Br(e);n[t]=Math.max(0,Math.min(n[t]+n[t]*s,t===0?360:1)),n=Vr(n),e.r=n[0],e.g=n[1],e.b=n[2]}}function Uu(e,t){return e&&Object.assign(t||{},e)}function Ka(e){var t={r:0,g:0,b:0,a:255};return Array.isArray(e)?e.length>=3&&(t={r:e[0],g:e[1],b:e[2],a:255},e.length>3&&(t.a=gs(e[3]))):(t=Uu(e,{r:0,g:0,b:0,a:1}),t.a=gs(t.a)),t}function o_(e){return e.charAt(0)==="r"?s_(e):Xb(e)}class zn{constructor(t){if(t instanceof zn)return t;const s=typeof t;let n;s==="object"?n=Ka(t):s==="string"&&(n=jb(t)||t_(t)||o_(t)),this._rgb=n,this._valid=!!n}get valid(){return this._valid}get rgb(){var t=Uu(this._rgb);return t&&(t.a=We(t.a)),t}set rgb(t){this._rgb=Ka(t)}rgbString(){return this._valid?n_(this._rgb):void 0}hexString(){return this._valid?zb(this._rgb):void 0}hslString(){return this._valid?Qb(this._rgb):void 0}mix(t,s){if(t){const n=this.rgb,i=t.rgb;let o;const r=s===o?.5:s,a=2*r-1,l=n.a-i.a,c=((a*l===-1?a:(a+l)/(1+a*l))+1)/2;o=1-c,n.r=255&c*n.r+o*i.r+.5,n.g=255&c*n.g+o*i.g+.5,n.b=255&c*n.b+o*i.b+.5,n.a=r*n.a+(1-r)*i.a,this.rgb=n}return this}interpolate(t,s){return t&&(this._rgb=i_(this._rgb,t._rgb,s)),this}clone(){return new zn(this.rgb)}alpha(t){return this._rgb.a=gs(t),this}clearer(t){const s=this._rgb;return s.a*=1-t,this}greyscale(){const t=this._rgb,s=ti(t.r*.3+t.g*.59+t.b*.11);return t.r=t.g=t.b=s,this}opaquer(t){const s=this._rgb;return s.a*=1+t,this}negate(){const t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this}lighten(t){return ui(this._rgb,2,t),this}darken(t){return ui(this._rgb,2,-t),this}saturate(t){return ui(this._rgb,1,t),this}desaturate(t){return ui(this._rgb,1,-t),this}rotate(t){return Jb(this._rgb,t),this}}function $e(){}const r_=(()=>{let e=0;return()=>e++})();function it(e){return e==null}function At(e){if(Array.isArray&&Array.isArray(e))return!0;const t=Object.prototype.toString.call(e);return t.slice(0,7)==="[object"&&t.slice(-6)==="Array]"}function ot(e){return e!==null&&Object.prototype.toString.call(e)==="[object Object]"}function Tt(e){return(typeof e=="number"||e instanceof Number)&&isFinite(+e)}function de(e,t){return Tt(e)?e:t}function Z(e,t){return typeof e>"u"?t:e}const a_=(e,t)=>typeof e=="string"&&e.endsWith("%")?parseFloat(e)/100:+e/t,Ku=(e,t)=>typeof e=="string"&&e.endsWith("%")?parseFloat(e)/100*t:+e;function St(e,t,s){if(e&&typeof e.call=="function")return e.apply(s,t)}function bt(e,t,s,n){let i,o,r;if(At(e))for(o=e.length,i=0;ie,x:e=>e.x,y:e=>e.y};function u_(e){const t=e.split("."),s=[];let n="";for(const i of t)n+=i,n.endsWith("\\")?n=n.slice(0,-1)+".":(s.push(n),n="");return s}function h_(e){const t=u_(e);return s=>{for(const n of t){if(n==="")break;s=s&&s[n]}return s}}function bs(e,t){return(Ga[t]||(Ga[t]=h_(t)))(e)}function jr(e){return e.charAt(0).toUpperCase()+e.slice(1)}const qn=e=>typeof e<"u",_s=e=>typeof e=="function",Ya=(e,t)=>{if(e.size!==t.size)return!1;for(const s of e)if(!t.has(s))return!1;return!0};function d_(e){return e.type==="mouseup"||e.type==="click"||e.type==="contextmenu"}const ht=Math.PI,Mt=2*ht,f_=Mt+ht,$i=Number.POSITIVE_INFINITY,p_=ht/180,Dt=ht/2,ks=ht/4,Xa=ht*2/3,hs=Math.log10,Fe=Math.sign;function Dn(e,t,s){return Math.abs(e-t)i-o).pop(),t}function m_(e){return typeof e=="symbol"||typeof e=="object"&&e!==null&&!(Symbol.toPrimitive in e||"toString"in e||"valueOf"in e)}function nn(e){return!m_(e)&&!isNaN(parseFloat(e))&&isFinite(e)}function b_(e,t){const s=Math.round(e);return s-t<=e&&s+t>=e}function Yu(e,t,s){let n,i,o;for(n=0,i=e.length;nl&&c=Math.min(t,s)-n&&e<=Math.max(t,s)+n}function zr(e,t,s){s=s||(r=>e[r]1;)o=i+n>>1,s(o)?i=o:n=o;return{lo:i,hi:n}}const Ye=(e,t,s,n)=>zr(e,s,n?i=>{const o=e[i][t];return oe[i][t]zr(e,s,n=>e[n][t]>=s);function v_(e,t,s){let n=0,i=e.length;for(;nn&&e[i-1]>s;)i--;return n>0||i{const n="_onData"+jr(s),i=e[s];Object.defineProperty(e,s,{configurable:!0,enumerable:!1,value(...o){const r=i.apply(this,o);return e._chartjs.listeners.forEach(a=>{typeof a[n]=="function"&&a[n](...o)}),r}})})}function Za(e,t){const s=e._chartjs;if(!s)return;const n=s.listeners,i=n.indexOf(t);i!==-1&&n.splice(i,1),!(n.length>0)&&(Ju.forEach(o=>{delete e[o]}),delete e._chartjs)}function Qu(e){const t=new Set(e);return t.size===e.length?e:Array.from(t)}const Zu=(function(){return typeof window>"u"?function(e){return e()}:window.requestAnimationFrame})();function th(e,t){let s=[],n=!1;return function(...i){s=i,n||(n=!0,Zu.call(window,()=>{n=!1,e.apply(t,s)}))}}function S_(e,t){let s;return function(...n){return t?(clearTimeout(s),s=setTimeout(e,t,n)):e.apply(this,n),t}}const Wr=e=>e==="start"?"left":e==="end"?"right":"center",jt=(e,t,s)=>e==="start"?t:e==="end"?s:(t+s)/2,k_=(e,t,s,n)=>e===(n?"left":"right")?s:e==="center"?(t+s)/2:t;function eh(e,t,s){const n=t.length;let i=0,o=n;if(e._sorted){const{iScale:r,vScale:a,_parsed:l}=e,c=e.dataset&&e.dataset.options?e.dataset.options.spanGaps:null,u=r.axis,{min:h,max:d,minDefined:f,maxDefined:p}=r.getUserBounds();if(f){if(i=Math.min(Ye(l,u,h).lo,s?n:Ye(t,u,r.getPixelForValue(h)).lo),c){const g=l.slice(0,i+1).reverse().findIndex(_=>!it(_[a.axis]));i-=Math.max(0,g)}i=Bt(i,0,n-1)}if(p){let g=Math.max(Ye(l,r.axis,d,!0).hi+1,s?0:Ye(t,u,r.getPixelForValue(d),!0).hi+1);if(c){const _=l.slice(g-1).findIndex(b=>!it(b[a.axis]));g+=Math.max(0,_)}o=Bt(g,i,n)-i}else o=n-i}return{start:i,count:o}}function sh(e){const{xScale:t,yScale:s,_scaleRanges:n}=e,i={xmin:t.min,xmax:t.max,ymin:s.min,ymax:s.max};if(!n)return e._scaleRanges=i,!0;const o=n.xmin!==t.min||n.xmax!==t.max||n.ymin!==s.min||n.ymax!==s.max;return Object.assign(n,i),o}const hi=e=>e===0||e===1,tl=(e,t,s)=>-(Math.pow(2,10*(e-=1))*Math.sin((e-t)*Mt/s)),el=(e,t,s)=>Math.pow(2,-10*e)*Math.sin((e-t)*Mt/s)+1,In={linear:e=>e,easeInQuad:e=>e*e,easeOutQuad:e=>-e*(e-2),easeInOutQuad:e=>(e/=.5)<1?.5*e*e:-.5*(--e*(e-2)-1),easeInCubic:e=>e*e*e,easeOutCubic:e=>(e-=1)*e*e+1,easeInOutCubic:e=>(e/=.5)<1?.5*e*e*e:.5*((e-=2)*e*e+2),easeInQuart:e=>e*e*e*e,easeOutQuart:e=>-((e-=1)*e*e*e-1),easeInOutQuart:e=>(e/=.5)<1?.5*e*e*e*e:-.5*((e-=2)*e*e*e-2),easeInQuint:e=>e*e*e*e*e,easeOutQuint:e=>(e-=1)*e*e*e*e+1,easeInOutQuint:e=>(e/=.5)<1?.5*e*e*e*e*e:.5*((e-=2)*e*e*e*e+2),easeInSine:e=>-Math.cos(e*Dt)+1,easeOutSine:e=>Math.sin(e*Dt),easeInOutSine:e=>-.5*(Math.cos(ht*e)-1),easeInExpo:e=>e===0?0:Math.pow(2,10*(e-1)),easeOutExpo:e=>e===1?1:-Math.pow(2,-10*e)+1,easeInOutExpo:e=>hi(e)?e:e<.5?.5*Math.pow(2,10*(e*2-1)):.5*(-Math.pow(2,-10*(e*2-1))+2),easeInCirc:e=>e>=1?e:-(Math.sqrt(1-e*e)-1),easeOutCirc:e=>Math.sqrt(1-(e-=1)*e),easeInOutCirc:e=>(e/=.5)<1?-.5*(Math.sqrt(1-e*e)-1):.5*(Math.sqrt(1-(e-=2)*e)+1),easeInElastic:e=>hi(e)?e:tl(e,.075,.3),easeOutElastic:e=>hi(e)?e:el(e,.075,.3),easeInOutElastic(e){return hi(e)?e:e<.5?.5*tl(e*2,.1125,.45):.5+.5*el(e*2-1,.1125,.45)},easeInBack(e){return e*e*((1.70158+1)*e-1.70158)},easeOutBack(e){return(e-=1)*e*((1.70158+1)*e+1.70158)+1},easeInOutBack(e){let t=1.70158;return(e/=.5)<1?.5*(e*e*(((t*=1.525)+1)*e-t)):.5*((e-=2)*e*(((t*=1.525)+1)*e+t)+2)},easeInBounce:e=>1-In.easeOutBounce(1-e),easeOutBounce(e){return e<1/2.75?7.5625*e*e:e<2/2.75?7.5625*(e-=1.5/2.75)*e+.75:e<2.5/2.75?7.5625*(e-=2.25/2.75)*e+.9375:7.5625*(e-=2.625/2.75)*e+.984375},easeInOutBounce:e=>e<.5?In.easeInBounce(e*2)*.5:In.easeOutBounce(e*2-1)*.5+.5};function qr(e){if(e&&typeof e=="object"){const t=e.toString();return t==="[object CanvasPattern]"||t==="[object CanvasGradient]"}return!1}function sl(e){return qr(e)?e:new zn(e)}function Po(e){return qr(e)?e:new zn(e).saturate(.5).darken(.1).hexString()}const M_=["x","y","borderWidth","radius","tension"],C_=["color","borderColor","backgroundColor"];function P_(e){e.set("animation",{delay:void 0,duration:1e3,easing:"easeOutQuart",fn:void 0,from:void 0,loop:void 0,to:void 0,type:void 0}),e.describe("animation",{_fallback:!1,_indexable:!1,_scriptable:t=>t!=="onProgress"&&t!=="onComplete"&&t!=="fn"}),e.set("animations",{colors:{type:"color",properties:C_},numbers:{type:"number",properties:M_}}),e.describe("animations",{_fallback:"animation"}),e.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:t=>t|0}}}})}function A_(e){e.set("layout",{autoPadding:!0,padding:{top:0,right:0,bottom:0,left:0}})}const nl=new Map;function R_(e,t){t=t||{};const s=e+JSON.stringify(t);let n=nl.get(s);return n||(n=new Intl.NumberFormat(e,t),nl.set(s,n)),n}function ei(e,t,s){return R_(t,s).format(e)}const nh={values(e){return At(e)?e:""+e},numeric(e,t,s){if(e===0)return"0";const n=this.chart.options.locale;let i,o=e;if(s.length>1){const c=Math.max(Math.abs(s[0].value),Math.abs(s[s.length-1].value));(c<1e-4||c>1e15)&&(i="scientific"),o=O_(e,s)}const r=hs(Math.abs(o)),a=isNaN(r)?1:Math.max(Math.min(-1*Math.floor(r),20),0),l={notation:i,minimumFractionDigits:a,maximumFractionDigits:a};return Object.assign(l,this.options.ticks.format),ei(e,n,l)},logarithmic(e,t,s){if(e===0)return"0";const n=s[t].significand||e/Math.pow(10,Math.floor(hs(e)));return[1,2,3,5,10,15].includes(n)||t>.8*s.length?nh.numeric.call(this,e,t,s):""}};function O_(e,t){let s=t.length>3?t[2].value-t[1].value:t[1].value-t[0].value;return Math.abs(s)>=1&&e!==Math.floor(e)&&(s=e-Math.floor(e)),s}var oo={formatters:nh};function T_(e){e.set("scale",{display:!0,offset:!1,reverse:!1,beginAtZero:!1,bounds:"ticks",clip:!0,grace:0,grid:{display:!0,lineWidth:1,drawOnChartArea:!0,drawTicks:!0,tickLength:8,tickWidth:(t,s)=>s.lineWidth,tickColor:(t,s)=>s.color,offset:!1},border:{display:!0,dash:[],dashOffset:0,width:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:oo.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),e.route("scale.ticks","color","","color"),e.route("scale.grid","color","","borderColor"),e.route("scale.border","color","","borderColor"),e.route("scale.title","color","","color"),e.describe("scale",{_fallback:!1,_scriptable:t=>!t.startsWith("before")&&!t.startsWith("after")&&t!=="callback"&&t!=="parser",_indexable:t=>t!=="borderDash"&&t!=="tickBorderDash"&&t!=="dash"}),e.describe("scales",{_fallback:"scale"}),e.describe("scale.ticks",{_scriptable:t=>t!=="backdropPadding"&&t!=="callback",_indexable:t=>t!=="backdropPadding"})}const $s=Object.create(null),or=Object.create(null);function Ln(e,t){if(!t)return e;const s=t.split(".");for(let n=0,i=s.length;nn.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(n,i)=>Po(i.backgroundColor),this.hoverBorderColor=(n,i)=>Po(i.borderColor),this.hoverColor=(n,i)=>Po(i.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0,includeInvisible:!1},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(t),this.apply(s)}set(t,s){return Ao(this,t,s)}get(t){return Ln(this,t)}describe(t,s){return Ao(or,t,s)}override(t,s){return Ao($s,t,s)}route(t,s,n,i){const o=Ln(this,t),r=Ln(this,n),a="_"+s;Object.defineProperties(o,{[a]:{value:o[s],writable:!0},[s]:{enumerable:!0,get(){const l=this[a],c=r[i];return ot(l)?Object.assign({},c,l):Z(l,c)},set(l){this[a]=l}}})}apply(t){t.forEach(s=>s(this))}}var Rt=new E_({_scriptable:e=>!e.startsWith("on"),_indexable:e=>e!=="events",hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}},[P_,A_,T_]);function D_(e){return!e||it(e.size)||it(e.family)?null:(e.style?e.style+" ":"")+(e.weight?e.weight+" ":"")+e.size+"px "+e.family}function Vi(e,t,s,n,i){let o=t[i];return o||(o=t[i]=e.measureText(i).width,s.push(i)),o>n&&(n=o),n}function I_(e,t,s,n){n=n||{};let i=n.data=n.data||{},o=n.garbageCollect=n.garbageCollect||[];n.font!==t&&(i=n.data={},o=n.garbageCollect=[],n.font=t),e.save(),e.font=t;let r=0;const a=s.length;let l,c,u,h,d;for(l=0;ls.length){for(l=0;l0&&e.stroke()}}function Xe(e,t,s){return s=s||.5,!t||e&&e.x>t.left-s&&e.xt.top-s&&e.y0&&o.strokeColor!=="";let l,c;for(e.save(),e.font=i.string,N_(e,o),l=0;l+e||0;function Ur(e,t){const s={},n=ot(t),i=n?Object.keys(t):t,o=ot(e)?n?r=>Z(e[r],e[t[r]]):r=>e[r]:()=>e;for(const r of i)s[r]=z_(o(r));return s}function oh(e){return Ur(e,{top:"y",right:"x",bottom:"y",left:"x"})}function Fs(e){return Ur(e,["topLeft","topRight","bottomLeft","bottomRight"])}function Yt(e){const t=oh(e);return t.width=t.left+t.right,t.height=t.top+t.bottom,t}function Nt(e,t){e=e||{},t=t||Rt.font;let s=Z(e.size,t.size);typeof s=="string"&&(s=parseInt(s,10));let n=Z(e.style,t.style);n&&!(""+n).match(j_)&&(console.warn('Invalid font style specified: "'+n+'"'),n=void 0);const i={family:Z(e.family,t.family),lineHeight:H_(Z(e.lineHeight,t.lineHeight),s),size:s,style:n,weight:Z(e.weight,t.weight),string:""};return i.string=D_(i),i}function wn(e,t,s,n){let i,o,r;for(i=0,o=e.length;is&&a===0?0:a+l;return{min:r(n,-Math.abs(o)),max:r(i,o)}}function xs(e,t){return Object.assign(Object.create(e),t)}function Kr(e,t=[""],s,n,i=()=>e[0]){const o=s||e;typeof n>"u"&&(n=ch("_fallback",e));const r={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:e,_rootScopes:o,_fallback:n,_getTarget:i,override:a=>Kr([a,...e],t,o,n)};return new Proxy(r,{deleteProperty(a,l){return delete a[l],delete a._keys,delete e[0][l],!0},get(a,l){return ah(a,l,()=>Q_(l,t,e,a))},getOwnPropertyDescriptor(a,l){return Reflect.getOwnPropertyDescriptor(a._scopes[0],l)},getPrototypeOf(){return Reflect.getPrototypeOf(e[0])},has(a,l){return rl(a).includes(l)},ownKeys(a){return rl(a)},set(a,l,c){const u=a._storage||(a._storage=i());return a[l]=u[l]=c,delete a._keys,!0}})}function on(e,t,s,n){const i={_cacheable:!1,_proxy:e,_context:t,_subProxy:s,_stack:new Set,_descriptors:rh(e,n),setContext:o=>on(e,o,s,n),override:o=>on(e.override(o),t,s,n)};return new Proxy(i,{deleteProperty(o,r){return delete o[r],delete e[r],!0},get(o,r,a){return ah(o,r,()=>U_(o,r,a))},getOwnPropertyDescriptor(o,r){return o._descriptors.allKeys?Reflect.has(e,r)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(e,r)},getPrototypeOf(){return Reflect.getPrototypeOf(e)},has(o,r){return Reflect.has(e,r)},ownKeys(){return Reflect.ownKeys(e)},set(o,r,a){return e[r]=a,delete o[r],!0}})}function rh(e,t={scriptable:!0,indexable:!0}){const{_scriptable:s=t.scriptable,_indexable:n=t.indexable,_allKeys:i=t.allKeys}=e;return{allKeys:i,scriptable:s,indexable:n,isScriptable:_s(s)?s:()=>s,isIndexable:_s(n)?n:()=>n}}const q_=(e,t)=>e?e+jr(t):t,Gr=(e,t)=>ot(t)&&e!=="adapters"&&(Object.getPrototypeOf(t)===null||t.constructor===Object);function ah(e,t,s){if(Object.prototype.hasOwnProperty.call(e,t)||t==="constructor")return e[t];const n=s();return e[t]=n,n}function U_(e,t,s){const{_proxy:n,_context:i,_subProxy:o,_descriptors:r}=e;let a=n[t];return _s(a)&&r.isScriptable(t)&&(a=K_(t,a,e,s)),At(a)&&a.length&&(a=G_(t,a,e,r.isIndexable)),Gr(t,a)&&(a=on(a,i,o&&o[t],r)),a}function K_(e,t,s,n){const{_proxy:i,_context:o,_subProxy:r,_stack:a}=s;if(a.has(e))throw new Error("Recursion detected: "+Array.from(a).join("->")+"->"+e);a.add(e);let l=t(o,r||n);return a.delete(e),Gr(e,l)&&(l=Yr(i._scopes,i,e,l)),l}function G_(e,t,s,n){const{_proxy:i,_context:o,_subProxy:r,_descriptors:a}=s;if(typeof o.index<"u"&&n(e))return t[o.index%t.length];if(ot(t[0])){const l=t,c=i._scopes.filter(u=>u!==l);t=[];for(const u of l){const h=Yr(c,i,e,u);t.push(on(h,o,r&&r[e],a))}}return t}function lh(e,t,s){return _s(e)?e(t,s):e}const Y_=(e,t)=>e===!0?t:typeof e=="string"?bs(t,e):void 0;function X_(e,t,s,n,i){for(const o of t){const r=Y_(s,o);if(r){e.add(r);const a=lh(r._fallback,s,i);if(typeof a<"u"&&a!==s&&a!==n)return a}else if(r===!1&&typeof n<"u"&&s!==n)return null}return!1}function Yr(e,t,s,n){const i=t._rootScopes,o=lh(t._fallback,s,n),r=[...e,...i],a=new Set;a.add(n);let l=ol(a,r,s,o||s,n);return l===null||typeof o<"u"&&o!==s&&(l=ol(a,r,o,l,n),l===null)?!1:Kr(Array.from(a),[""],i,o,()=>J_(t,s,n))}function ol(e,t,s,n,i){for(;s;)s=X_(e,t,s,n,i);return s}function J_(e,t,s){const n=e._getTarget();t in n||(n[t]={});const i=n[t];return At(i)&&ot(s)?s:i||{}}function Q_(e,t,s,n){let i;for(const o of t)if(i=ch(q_(o,e),s),typeof i<"u")return Gr(e,i)?Yr(s,n,e,i):i}function ch(e,t){for(const s of t){if(!s)continue;const n=s[e];if(typeof n<"u")return n}}function rl(e){let t=e._keys;return t||(t=e._keys=Z_(e._scopes)),t}function Z_(e){const t=new Set;for(const s of e)for(const n of Object.keys(s).filter(i=>!i.startsWith("_")))t.add(n);return Array.from(t)}function uh(e,t,s,n){const{iScale:i}=e,{key:o="r"}=this._parsing,r=new Array(n);let a,l,c,u;for(a=0,l=n;ate==="x"?"y":"x";function e0(e,t,s,n){const i=e.skip?t:e,o=t,r=s.skip?t:s,a=ir(o,i),l=ir(r,o);let c=a/(a+l),u=l/(a+l);c=isNaN(c)?0:c,u=isNaN(u)?0:u;const h=n*c,d=n*u;return{previous:{x:o.x-h*(r.x-i.x),y:o.y-h*(r.y-i.y)},next:{x:o.x+d*(r.x-i.x),y:o.y+d*(r.y-i.y)}}}function s0(e,t,s){const n=e.length;let i,o,r,a,l,c=rn(e,0);for(let u=0;u!c.skip)),t.cubicInterpolationMode==="monotone")i0(e,i);else{let c=n?e[e.length-1]:e[0];for(o=0,r=e.length;oe.ownerDocument.defaultView.getComputedStyle(e,null);function a0(e,t){return lo(e).getPropertyValue(t)}const l0=["top","right","bottom","left"];function Ns(e,t,s){const n={};s=s?"-"+s:"";for(let i=0;i<4;i++){const o=l0[i];n[o]=parseFloat(e[t+"-"+o+s])||0}return n.width=n.left+n.right,n.height=n.top+n.bottom,n}const c0=(e,t,s)=>(e>0||t>0)&&(!s||!s.shadowRoot);function u0(e,t){const s=e.touches,n=s&&s.length?s[0]:e,{offsetX:i,offsetY:o}=n;let r=!1,a,l;if(c0(i,o,e.target))a=i,l=o;else{const c=t.getBoundingClientRect();a=n.clientX-c.left,l=n.clientY-c.top,r=!0}return{x:a,y:l,box:r}}function Rs(e,t){if("native"in e)return e;const{canvas:s,currentDevicePixelRatio:n}=t,i=lo(s),o=i.boxSizing==="border-box",r=Ns(i,"padding"),a=Ns(i,"border","width"),{x:l,y:c,box:u}=u0(e,s),h=r.left+(u&&a.left),d=r.top+(u&&a.top);let{width:f,height:p}=t;return o&&(f-=r.width+a.width,p-=r.height+a.height),{x:Math.round((l-h)/f*s.width/n),y:Math.round((c-d)/p*s.height/n)}}function h0(e,t,s){let n,i;if(t===void 0||s===void 0){const o=e&&Jr(e);if(!o)t=e.clientWidth,s=e.clientHeight;else{const r=o.getBoundingClientRect(),a=lo(o),l=Ns(a,"border","width"),c=Ns(a,"padding");t=r.width-c.width-l.width,s=r.height-c.height-l.height,n=ji(a.maxWidth,o,"clientWidth"),i=ji(a.maxHeight,o,"clientHeight")}}return{width:t,height:s,maxWidth:n||$i,maxHeight:i||$i}}const ds=e=>Math.round(e*10)/10;function d0(e,t,s,n){const i=lo(e),o=Ns(i,"margin"),r=ji(i.maxWidth,e,"clientWidth")||$i,a=ji(i.maxHeight,e,"clientHeight")||$i,l=h0(e,t,s);let{width:c,height:u}=l;if(i.boxSizing==="content-box"){const d=Ns(i,"border","width"),f=Ns(i,"padding");c-=f.width+d.width,u-=f.height+d.height}return c=Math.max(0,c-o.width),u=Math.max(0,n?c/n:u-o.height),c=ds(Math.min(c,r,l.maxWidth)),u=ds(Math.min(u,a,l.maxHeight)),c&&!u&&(u=ds(c/2)),(t!==void 0||s!==void 0)&&n&&l.height&&u>l.height&&(u=l.height,c=ds(Math.floor(u*n))),{width:c,height:u}}function al(e,t,s){const n=t||1,i=ds(e.height*n),o=ds(e.width*n);e.height=ds(e.height),e.width=ds(e.width);const r=e.canvas;return r.style&&(s||!r.style.height&&!r.style.width)&&(r.style.height=`${e.height}px`,r.style.width=`${e.width}px`),e.currentDevicePixelRatio!==n||r.height!==i||r.width!==o?(e.currentDevicePixelRatio=n,r.height=i,r.width=o,e.ctx.setTransform(n,0,0,n,0,0),!0):!1}const f0=(function(){let e=!1;try{const t={get passive(){return e=!0,!1}};Xr()&&(window.addEventListener("test",null,t),window.removeEventListener("test",null,t))}catch{}return e})();function ll(e,t){const s=a0(e,t),n=s&&s.match(/^(\d+)(\.\d+)?px$/);return n?+n[1]:void 0}function Os(e,t,s,n){return{x:e.x+s*(t.x-e.x),y:e.y+s*(t.y-e.y)}}function p0(e,t,s,n){return{x:e.x+s*(t.x-e.x),y:n==="middle"?s<.5?e.y:t.y:n==="after"?s<1?e.y:t.y:s>0?t.y:e.y}}function g0(e,t,s,n){const i={x:e.cp2x,y:e.cp2y},o={x:t.cp1x,y:t.cp1y},r=Os(e,i,s),a=Os(i,o,s),l=Os(o,t,s),c=Os(r,a,s),u=Os(a,l,s);return Os(c,u,s)}const m0=function(e,t){return{x(s){return e+e+t-s},setWidth(s){t=s},textAlign(s){return s==="center"?s:s==="right"?"left":"right"},xPlus(s,n){return s-n},leftForLtr(s,n){return s-n}}},b0=function(){return{x(e){return e},setWidth(e){},textAlign(e){return e},xPlus(e,t){return e+t},leftForLtr(e,t){return e}}};function Qs(e,t,s){return e?m0(t,s):b0()}function dh(e,t){let s,n;(t==="ltr"||t==="rtl")&&(s=e.canvas.style,n=[s.getPropertyValue("direction"),s.getPropertyPriority("direction")],s.setProperty("direction",t,"important"),e.prevTextDirection=n)}function fh(e,t){t!==void 0&&(delete e.prevTextDirection,e.canvas.style.setProperty("direction",t[0],t[1]))}function ph(e){return e==="angle"?{between:Un,compare:__,normalize:Ht}:{between:Ge,compare:(t,s)=>t-s,normalize:t=>t}}function cl({start:e,end:t,count:s,loop:n,style:i}){return{start:e%s,end:t%s,loop:n&&(t-e+1)%s===0,style:i}}function _0(e,t,s){const{property:n,start:i,end:o}=s,{between:r,normalize:a}=ph(n),l=t.length;let{start:c,end:u,loop:h}=e,d,f;if(h){for(c+=l,u+=l,d=0,f=l;dl(i,M,b)&&a(i,M)!==0,w=()=>a(o,b)===0||l(o,M,b),R=()=>g||S(),k=()=>!g||w();for(let P=u,C=u;P<=h;++P)v=t[P%r],!v.skip&&(b=c(v[n]),b!==M&&(g=l(b,i,o),_===null&&R()&&(_=a(b,i)===0?P:C),_!==null&&k()&&(p.push(cl({start:_,end:P,loop:d,count:r,style:f})),_=null),C=P,M=b));return _!==null&&p.push(cl({start:_,end:h,loop:d,count:r,style:f})),p}function mh(e,t){const s=[],n=e.segments;for(let i=0;ii&&e[o%t].skip;)o--;return o%=t,{start:i,end:o}}function x0(e,t,s,n){const i=e.length,o=[];let r=t,a=e[t],l;for(l=t+1;l<=s;++l){const c=e[l%i];c.skip||c.stop?a.skip||(n=!1,o.push({start:t%i,end:(l-1)%i,loop:n}),t=r=c.stop?l:null):(r=l,a.skip&&(t=l)),a=c}return r!==null&&o.push({start:t%i,end:r%i,loop:n}),o}function v0(e,t){const s=e.points,n=e.options.spanGaps,i=s.length;if(!i)return[];const o=!!e._loop,{start:r,end:a}=y0(s,i,o,n);if(n===!0)return ul(e,[{start:r,end:a,loop:o}],s,t);const l=aa({chart:t,initial:s.initial,numSteps:r,currentStep:Math.min(n-s.start,r)}))}_refresh(){this._request||(this._running=!0,this._request=Zu.call(window,()=>{this._update(),this._request=null,this._running&&this._refresh()}))}_update(t=Date.now()){let s=0;this._charts.forEach((n,i)=>{if(!n.running||!n.items.length)return;const o=n.items;let r=o.length-1,a=!1,l;for(;r>=0;--r)l=o[r],l._active?(l._total>n.duration&&(n.duration=l._total),l.tick(t),a=!0):(o[r]=o[o.length-1],o.pop());a&&(i.draw(),this._notify(i,n,t,"progress")),o.length||(n.running=!1,this._notify(i,n,t,"complete"),n.initial=!1),s+=o.length}),this._lastDate=t,s===0&&(this._running=!1)}_getAnims(t){const s=this._charts;let n=s.get(t);return n||(n={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},s.set(t,n)),n}listen(t,s,n){this._getAnims(t).listeners[s].push(n)}add(t,s){!s||!s.length||this._getAnims(t).items.push(...s)}has(t){return this._getAnims(t).items.length>0}start(t){const s=this._charts.get(t);s&&(s.running=!0,s.start=Date.now(),s.duration=s.items.reduce((n,i)=>Math.max(n,i._duration),0),this._refresh())}running(t){if(!this._running)return!1;const s=this._charts.get(t);return!(!s||!s.running||!s.items.length)}stop(t){const s=this._charts.get(t);if(!s||!s.items.length)return;const n=s.items;let i=n.length-1;for(;i>=0;--i)n[i].cancel();s.items=[],this._notify(t,s,Date.now(),"complete")}remove(t){return this._charts.delete(t)}}var je=new M0;const dl="transparent",C0={boolean(e,t,s){return s>.5?t:e},color(e,t,s){const n=sl(e||dl),i=n.valid&&sl(t||dl);return i&&i.valid?i.mix(n,s).hexString():t},number(e,t,s){return e+(t-e)*s}};class P0{constructor(t,s,n,i){const o=s[n];i=wn([t.to,i,o,t.from]);const r=wn([t.from,o,i]);this._active=!0,this._fn=t.fn||C0[t.type||typeof r],this._easing=In[t.easing]||In.linear,this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=this._total=Math.floor(t.duration),this._loop=!!t.loop,this._target=s,this._prop=n,this._from=r,this._to=i,this._promises=void 0}active(){return this._active}update(t,s,n){if(this._active){this._notify(!1);const i=this._target[this._prop],o=n-this._start,r=this._duration-o;this._start=n,this._duration=Math.floor(Math.max(r,t.duration)),this._total+=o,this._loop=!!t.loop,this._to=wn([t.to,s,i,t.from]),this._from=wn([t.from,i,s])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(t){const s=t-this._start,n=this._duration,i=this._prop,o=this._from,r=this._loop,a=this._to;let l;if(this._active=o!==a&&(r||s1?2-l:l,l=this._easing(Math.min(1,Math.max(0,l))),this._target[i]=this._fn(o,a,l)}wait(){const t=this._promises||(this._promises=[]);return new Promise((s,n)=>{t.push({res:s,rej:n})})}_notify(t){const s=t?"res":"rej",n=this._promises||[];for(let i=0;i{const o=t[i];if(!ot(o))return;const r={};for(const a of s)r[a]=o[a];(At(o.properties)&&o.properties||[i]).forEach(a=>{(a===i||!n.has(a))&&n.set(a,r)})})}_animateOptions(t,s){const n=s.options,i=R0(t,n);if(!i)return[];const o=this._createAnimations(i,n);return n.$shared&&A0(t.options.$animations,n).then(()=>{t.options=n},()=>{}),o}_createAnimations(t,s){const n=this._properties,i=[],o=t.$animations||(t.$animations={}),r=Object.keys(s),a=Date.now();let l;for(l=r.length-1;l>=0;--l){const c=r[l];if(c.charAt(0)==="$")continue;if(c==="options"){i.push(...this._animateOptions(t,s));continue}const u=s[c];let h=o[c];const d=n.get(c);if(h)if(d&&h.active()){h.update(d,u,a);continue}else h.cancel();if(!d||!d.duration){t[c]=u;continue}o[c]=h=new P0(d,t,c,u),i.push(h)}return i}update(t,s){if(this._properties.size===0){Object.assign(t,s);return}const n=this._createAnimations(t,s);if(n.length)return je.add(this._chart,n),!0}}function A0(e,t){const s=[],n=Object.keys(t);for(let i=0;i0||!s&&o<0)return i.index}return null}function ml(e,t){const{chart:s,_cachedMeta:n}=e,i=s._stacks||(s._stacks={}),{iScale:o,vScale:r,index:a}=n,l=o.axis,c=r.axis,u=D0(o,r,n),h=t.length;let d;for(let f=0;fs[n].axis===t).shift()}function F0(e,t){return xs(e,{active:!1,dataset:void 0,datasetIndex:t,index:t,mode:"default",type:"dataset"})}function N0(e,t,s){return xs(e,{active:!1,dataIndex:t,parsed:void 0,raw:void 0,element:s,index:t,mode:"default",type:"data"})}function pn(e,t){const s=e.controller.index,n=e.vScale&&e.vScale.axis;if(n){t=t||e._parsed;for(const i of t){const o=i._stacks;if(!o||o[n]===void 0||o[n][s]===void 0)return;delete o[n][s],o[n]._visualValues!==void 0&&o[n]._visualValues[s]!==void 0&&delete o[n]._visualValues[s]}}}const To=e=>e==="reset"||e==="none",bl=(e,t)=>t?e:Object.assign({},e),B0=(e,t,s)=>e&&!t.hidden&&t._stacked&&{keys:yh(s,!0),values:null};class vs{static defaults={};static datasetElementType=null;static dataElementType=null;constructor(t,s){this.chart=t,this._ctx=t.ctx,this.index=s,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.supportsDecimation=!1,this.$context=void 0,this._syncList=[],this.datasetElementType=new.target.datasetElementType,this.dataElementType=new.target.dataElementType,this.initialize()}initialize(){const t=this._cachedMeta;this.configure(),this.linkScales(),t._stacked=Ro(t.vScale,t),this.addElements(),this.options.fill&&!this.chart.isPluginEnabled("filler")&&console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options")}updateIndex(t){this.index!==t&&pn(this._cachedMeta),this.index=t}linkScales(){const t=this.chart,s=this._cachedMeta,n=this.getDataset(),i=(h,d,f,p)=>h==="x"?d:h==="r"?p:f,o=s.xAxisID=Z(n.xAxisID,Oo(t,"x")),r=s.yAxisID=Z(n.yAxisID,Oo(t,"y")),a=s.rAxisID=Z(n.rAxisID,Oo(t,"r")),l=s.indexAxis,c=s.iAxisID=i(l,o,r,a),u=s.vAxisID=i(l,r,o,a);s.xScale=this.getScaleForId(o),s.yScale=this.getScaleForId(r),s.rScale=this.getScaleForId(a),s.iScale=this.getScaleForId(c),s.vScale=this.getScaleForId(u)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(t){return this.chart.scales[t]}_getOtherScale(t){const s=this._cachedMeta;return t===s.iScale?s.vScale:s.iScale}reset(){this._update("reset")}_destroy(){const t=this._cachedMeta;this._data&&Za(this._data,this),t._stacked&&pn(t)}_dataCheck(){const t=this.getDataset(),s=t.data||(t.data=[]),n=this._data;if(ot(s)){const i=this._cachedMeta;this._data=E0(s,i)}else if(n!==s){if(n){Za(n,this);const i=this._cachedMeta;pn(i),i._parsed=[]}s&&Object.isExtensible(s)&&w_(s,this),this._syncList=[],this._data=s}}addElements(){const t=this._cachedMeta;this._dataCheck(),this.datasetElementType&&(t.dataset=new this.datasetElementType)}buildOrUpdateElements(t){const s=this._cachedMeta,n=this.getDataset();let i=!1;this._dataCheck();const o=s._stacked;s._stacked=Ro(s.vScale,s),s.stack!==n.stack&&(i=!0,pn(s),s.stack=n.stack),this._resyncElements(t),(i||o!==s._stacked)&&(ml(this,s._parsed),s._stacked=Ro(s.vScale,s))}configure(){const t=this.chart.config,s=t.datasetScopeKeys(this._type),n=t.getOptionScopes(this.getDataset(),s,!0);this.options=t.createResolver(n,this.getContext()),this._parsing=this.options.parsing,this._cachedDataOpts={}}parse(t,s){const{_cachedMeta:n,_data:i}=this,{iScale:o,_stacked:r}=n,a=o.axis;let l=t===0&&s===i.length?!0:n._sorted,c=t>0&&n._parsed[t-1],u,h,d;if(this._parsing===!1)n._parsed=i,n._sorted=!0,d=i;else{At(i[t])?d=this.parseArrayData(n,i,t,s):ot(i[t])?d=this.parseObjectData(n,i,t,s):d=this.parsePrimitiveData(n,i,t,s);const f=()=>h[a]===null||c&&h[a]g||h=0;--d)if(!p()){this.updateRangeFromParsed(c,t,f,l);break}}return c}getAllParsedValues(t){const s=this._cachedMeta._parsed,n=[];let i,o,r;for(i=0,o=s.length;i=0&&tthis.getContext(n,i,s),g=c.resolveNamedOptions(d,f,p,h);return g.$shared&&(g.$shared=l,o[r]=Object.freeze(bl(g,l))),g}_resolveAnimations(t,s,n){const i=this.chart,o=this._cachedDataOpts,r=`animation-${s}`,a=o[r];if(a)return a;let l;if(i.options.animation!==!1){const u=this.chart.config,h=u.datasetAnimationScopeKeys(this._type,s),d=u.getOptionScopes(this.getDataset(),h);l=u.createResolver(d,this.getContext(t,n,s))}const c=new _h(i,l&&l.animations);return l&&l._cacheable&&(o[r]=Object.freeze(c)),c}getSharedOptions(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}includeOptions(t,s){return!s||To(t)||this.chart._animationsDisabled}_getSharedOptions(t,s){const n=this.resolveDataElementOptions(t,s),i=this._sharedOptions,o=this.getSharedOptions(n),r=this.includeOptions(s,o)||o!==i;return this.updateSharedOptions(o,s,n),{sharedOptions:o,includeOptions:r}}updateElement(t,s,n,i){To(i)?Object.assign(t,n):this._resolveAnimations(s,i).update(t,n)}updateSharedOptions(t,s,n){t&&!To(s)&&this._resolveAnimations(void 0,s).update(t,n)}_setStyle(t,s,n,i){t.active=i;const o=this.getStyle(s,i);this._resolveAnimations(s,n,i).update(t,{options:!i&&this.getSharedOptions(o)||o})}removeHoverStyle(t,s,n){this._setStyle(t,n,"active",!1)}setHoverStyle(t,s,n){this._setStyle(t,n,"active",!0)}_removeDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}_setDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}_resyncElements(t){const s=this._data,n=this._cachedMeta.data;for(const[a,l,c]of this._syncList)this[a](l,c);this._syncList=[];const i=n.length,o=s.length,r=Math.min(o,i);r&&this.parse(0,r),o>i?this._insertElements(i,o-i,t):o{for(c.length+=s,a=c.length-1;a>=r;a--)c[a]=c[a-s]};for(l(o),a=t;ai-o))}return e._cache.$bar}function V0(e){const t=e.iScale,s=$0(t,e.type);let n=t._length,i,o,r,a;const l=()=>{r===32767||r===-32768||(qn(a)&&(n=Math.min(n,Math.abs(r-a)||n)),a=r)};for(i=0,o=s.length;i0?i[e-1]:null,a=eMath.abs(a)&&(l=a,c=r),t[s.axis]=c,t._custom={barStart:l,barEnd:c,start:i,end:o,min:r,max:a}}function xh(e,t,s,n){return At(e)?z0(e,t,s,n):t[s.axis]=s.parse(e,n),t}function _l(e,t,s,n){const i=e.iScale,o=e.vScale,r=i.getLabels(),a=i===o,l=[];let c,u,h,d;for(c=s,u=s+n;c=s?1:-1)}function q0(e){let t,s,n,i,o;return e.horizontal?(t=e.base>e.x,s="left",n="right"):(t=e.baseu.controller.options.grouped),o=n.options.stacked,r=[],a=this._cachedMeta.controller.getParsed(s),l=a&&a[n.axis],c=u=>{const h=u._parsed.find(f=>f[n.axis]===l),d=h&&h[u.vScale.axis];if(it(d)||isNaN(d))return!0};for(const u of i)if(!(s!==void 0&&c(u))&&((o===!1||r.indexOf(u.stack)===-1||o===void 0&&u.stack===void 0)&&r.push(u.stack),u.index===t))break;return r.length||r.push(void 0),r}_getStackCount(t){return this._getStacks(void 0,t).length}_getAxisCount(){return this._getAxis().length}getFirstScaleIdForIndexAxis(){const t=this.chart.scales,s=this.chart.options.indexAxis;return Object.keys(t).filter(n=>t[n].axis===s).shift()}_getAxis(){const t={},s=this.getFirstScaleIdForIndexAxis();for(const n of this.chart.data.datasets)t[Z(this.chart.options.indexAxis==="x"?n.xAxisID:n.yAxisID,s)]=!0;return Object.keys(t)}_getStackIndex(t,s,n){const i=this._getStacks(t,n),o=s!==void 0?i.indexOf(s):-1;return o===-1?i.length-1:o}_getRuler(){const t=this.options,s=this._cachedMeta,n=s.iScale,i=[];let o,r;for(o=0,r=s.data.length;o=0;--n)s=Math.max(s,t[n].size(this.resolveDataElementOptions(n))/2);return s>0&&s}getLabelAndValue(t){const s=this._cachedMeta,n=this.chart.data.labels||[],{xScale:i,yScale:o}=s,r=this.getParsed(t),a=i.getLabelForValue(r.x),l=o.getLabelForValue(r.y),c=r._custom;return{label:n[t]||"",value:"("+a+", "+l+(c?", "+c:"")+")"}}update(t){const s=this._cachedMeta.data;this.updateElements(s,0,s.length,t)}updateElements(t,s,n,i){const o=i==="reset",{iScale:r,vScale:a}=this._cachedMeta,{sharedOptions:l,includeOptions:c}=this._getSharedOptions(s,i),u=r.axis,h=a.axis;for(let d=s;dUn(M,a,l,!0)?1:Math.max(S,S*s,w,w*s),p=(M,S,w)=>Un(M,a,l,!0)?-1:Math.min(S,S*s,w,w*s),g=f(0,c,h),_=f(Dt,u,d),b=p(ht,c,h),v=p(ht+Dt,u,d);n=(g-b)/2,i=(_-v)/2,o=-(g+b)/2,r=-(_+v)/2}return{ratioX:n,ratioY:i,offsetX:o,offsetY:r}}class Qr extends vs{static id="doughnut";static defaults={datasetElementType:!1,dataElementType:"arc",animation:{animateRotate:!0,animateScale:!1},animations:{numbers:{type:"number",properties:["circumference","endAngle","innerRadius","outerRadius","startAngle","x","y","offset","borderWidth","spacing"]}},cutout:"50%",rotation:0,circumference:360,radius:"100%",spacing:0,indexAxis:"r"};static descriptors={_scriptable:t=>t!=="spacing",_indexable:t=>t!=="spacing"&&!t.startsWith("borderDash")&&!t.startsWith("hoverBorderDash")};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const s=t.data,{labels:{pointStyle:n,textAlign:i,color:o,useBorderRadius:r,borderRadius:a}}=t.legend.options;return s.labels.length&&s.datasets.length?s.labels.map((l,c)=>{const h=t.getDatasetMeta(0).controller.getStyle(c);return{text:l,fillStyle:h.backgroundColor,fontColor:o,hidden:!t.getDataVisibility(c),lineDash:h.borderDash,lineDashOffset:h.borderDashOffset,lineJoin:h.borderJoinStyle,lineWidth:h.borderWidth,strokeStyle:h.borderColor,textAlign:i,pointStyle:n,borderRadius:r&&(a||h.borderRadius),index:c}}):[]}},onClick(t,s,n){n.chart.toggleDataVisibility(s.index),n.chart.update()}}}};constructor(t,s){super(t,s),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(t,s){const n=this.getDataset().data,i=this._cachedMeta;if(this._parsing===!1)i._parsed=n;else{let o=l=>+n[l];if(ot(n[t])){const{key:l="value"}=this._parsing;o=c=>+bs(n[c],l)}let r,a;for(r=t,a=t+s;r0&&!isNaN(t)?Mt*(Math.abs(t)/s):0}getLabelAndValue(t){const s=this._cachedMeta,n=this.chart,i=n.data.labels||[],o=ei(s._parsed[t],n.options.locale);return{label:i[t]||"",value:o}}getMaxBorderWidth(t){let s=0;const n=this.chart;let i,o,r,a,l;if(!t){for(i=0,o=n.data.datasets.length;i0&&this.getParsed(s-1);for(let w=0;w=v){k.skip=!0;continue}const P=this.getParsed(w),C=it(P[f]),O=k[d]=r.getPixelForValue(P[d],w),B=k[f]=o||C?a.getBasePixel():a.getPixelForValue(l?this.applyStack(a,P,l):P[f],w);k.skip=isNaN(O)||isNaN(B)||C,k.stop=w>0&&Math.abs(P[d]-S[d])>_,g&&(k.parsed=P,k.raw=c.data[w]),h&&(k.options=u||this.resolveDataElementOptions(w,R.active?"active":i)),b||this.updateElement(R,w,k,i),S=P}}getMaxOverflow(){const t=this._cachedMeta,s=t.dataset,n=s.options&&s.options.borderWidth||0,i=t.data||[];if(!i.length)return n;const o=i[0].size(this.resolveDataElementOptions(0)),r=i[i.length-1].size(this.resolveDataElementOptions(i.length-1));return Math.max(n,o,r)/2}draw(){const t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),super.draw()}}class vh extends vs{static id="polarArea";static defaults={dataElementType:"arc",animation:{animateRotate:!0,animateScale:!0},animations:{numbers:{type:"number",properties:["x","y","startAngle","endAngle","innerRadius","outerRadius"]}},indexAxis:"r",startAngle:0};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const s=t.data;if(s.labels.length&&s.datasets.length){const{labels:{pointStyle:n,color:i}}=t.legend.options;return s.labels.map((o,r)=>{const l=t.getDatasetMeta(0).controller.getStyle(r);return{text:o,fillStyle:l.backgroundColor,strokeStyle:l.borderColor,fontColor:i,lineWidth:l.borderWidth,pointStyle:n,hidden:!t.getDataVisibility(r),index:r}})}return[]}},onClick(t,s,n){n.chart.toggleDataVisibility(s.index),n.chart.update()}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};constructor(t,s){super(t,s),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(t){const s=this._cachedMeta,n=this.chart,i=n.data.labels||[],o=ei(s._parsed[t].r,n.options.locale);return{label:i[t]||"",value:o}}parseObjectData(t,s,n,i){return uh.bind(this)(t,s,n,i)}update(t){const s=this._cachedMeta.data;this._updateRadius(),this.updateElements(s,0,s.length,t)}getMinMax(){const t=this._cachedMeta,s={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY};return t.data.forEach((n,i)=>{const o=this.getParsed(i).r;!isNaN(o)&&this.chart.getDataVisibility(i)&&(os.max&&(s.max=o))}),s}_updateRadius(){const t=this.chart,s=t.chartArea,n=t.options,i=Math.min(s.right-s.left,s.bottom-s.top),o=Math.max(i/2,0),r=Math.max(n.cutoutPercentage?o/100*n.cutoutPercentage:1,0),a=(o-r)/t.getVisibleDatasetCount();this.outerRadius=o-a*this.index,this.innerRadius=this.outerRadius-a}updateElements(t,s,n,i){const o=i==="reset",r=this.chart,l=r.options.animation,c=this._cachedMeta.rScale,u=c.xCenter,h=c.yCenter,d=c.getIndexAngle(0)-.5*ht;let f=d,p;const g=360/this.countVisibleElements();for(p=0;p{!isNaN(this.getParsed(i).r)&&this.chart.getDataVisibility(i)&&s++}),s}_computeAngle(t,s,n){return this.chart.getDataVisibility(t)?ve(this.resolveDataElementOptions(t,s).angle||n):0}}class Z0 extends Qr{static id="pie";static defaults={cutout:0,rotation:0,circumference:360,radius:"100%"}}class ty extends vs{static id="radar";static defaults={datasetElementType:"line",dataElementType:"point",indexAxis:"r",showLine:!0,elements:{line:{fill:"start"}}};static overrides={aspectRatio:1,scales:{r:{type:"radialLinear"}}};getLabelAndValue(t){const s=this._cachedMeta.vScale,n=this.getParsed(t);return{label:s.getLabels()[t],value:""+s.getLabelForValue(n[s.axis])}}parseObjectData(t,s,n,i){return uh.bind(this)(t,s,n,i)}update(t){const s=this._cachedMeta,n=s.dataset,i=s.data||[],o=s.iScale.getLabels();if(n.points=i,t!=="resize"){const r=this.resolveDatasetElementOptions(t);this.options.showLine||(r.borderWidth=0);const a={_loop:!0,_fullLoop:o.length===i.length,options:r};this.updateElement(n,void 0,a,t)}this.updateElements(i,0,i.length,t)}updateElements(t,s,n,i){const o=this._cachedMeta.rScale,r=i==="reset";for(let a=s;a0&&this.getParsed(s-1);for(let S=s;S0&&Math.abs(R[f]-M[f])>b,_&&(k.parsed=R,k.raw=c.data[S]),d&&(k.options=h||this.resolveDataElementOptions(S,w.active?"active":i)),v||this.updateElement(w,S,k,i),M=R}this.updateSharedOptions(h,i,u)}getMaxOverflow(){const t=this._cachedMeta,s=t.data||[];if(!this.options.showLine){let a=0;for(let l=s.length-1;l>=0;--l)a=Math.max(a,s[l].size(this.resolveDataElementOptions(l))/2);return a>0&&a}const n=t.dataset,i=n.options&&n.options.borderWidth||0;if(!s.length)return i;const o=s[0].size(this.resolveDataElementOptions(0)),r=s[s.length-1].size(this.resolveDataElementOptions(s.length-1));return Math.max(i,o,r)/2}}var sy=Object.freeze({__proto__:null,BarController:Y0,BubbleController:X0,DoughnutController:Qr,LineController:Q0,PieController:Z0,PolarAreaController:vh,RadarController:ty,ScatterController:ey});function Cs(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}class Zr{static override(t){Object.assign(Zr.prototype,t)}options;constructor(t){this.options=t||{}}init(){}formats(){return Cs()}parse(){return Cs()}format(){return Cs()}add(){return Cs()}diff(){return Cs()}startOf(){return Cs()}endOf(){return Cs()}}var ny={_date:Zr};function iy(e,t,s,n){const{controller:i,data:o,_sorted:r}=e,a=i._cachedMeta.iScale,l=e.dataset&&e.dataset.options?e.dataset.options.spanGaps:null;if(a&&t===a.axis&&t!=="r"&&r&&o.length){const c=a._reversePixels?x_:Ye;if(n){if(i._sharedOptions){const u=o[0],h=typeof u.getRange=="function"&&u.getRange(t);if(h){const d=c(o,t,s-h),f=c(o,t,s+h);return{lo:d.lo,hi:f.hi}}}}else{const u=c(o,t,s);if(l){const{vScale:h}=i._cachedMeta,{_parsed:d}=e,f=d.slice(0,u.lo+1).reverse().findIndex(g=>!it(g[h.axis]));u.lo-=Math.max(0,f);const p=d.slice(u.hi).findIndex(g=>!it(g[h.axis]));u.hi+=Math.max(0,p)}return u}}return{lo:0,hi:o.length-1}}function co(e,t,s,n,i){const o=e.getSortedVisibleDatasetMetas(),r=s[t];for(let a=0,l=o.length;a{l[r]&&l[r](t[s],i)&&(o.push({element:l,datasetIndex:c,index:u}),a=a||l.inRange(t.x,t.y,i))}),n&&!a?[]:o}var ly={modes:{index(e,t,s,n){const i=Rs(t,e),o=s.axis||"x",r=s.includeInvisible||!1,a=s.intersect?Do(e,i,o,n,r):Io(e,i,o,!1,n,r),l=[];return a.length?(e.getSortedVisibleDatasetMetas().forEach(c=>{const u=a[0].index,h=c.data[u];h&&!h.skip&&l.push({element:h,datasetIndex:c.index,index:u})}),l):[]},dataset(e,t,s,n){const i=Rs(t,e),o=s.axis||"xy",r=s.includeInvisible||!1;let a=s.intersect?Do(e,i,o,n,r):Io(e,i,o,!1,n,r);if(a.length>0){const l=a[0].datasetIndex,c=e.getDatasetMeta(l).data;a=[];for(let u=0;us.pos===t)}function wl(e,t){return e.filter(s=>wh.indexOf(s.pos)===-1&&s.box.axis===t)}function mn(e,t){return e.sort((s,n)=>{const i=t?n:s,o=t?s:n;return i.weight===o.weight?i.index-o.index:i.weight-o.weight})}function cy(e){const t=[];let s,n,i,o,r,a;for(s=0,n=(e||[]).length;sc.box.fullSize),!0),n=mn(gn(t,"left"),!0),i=mn(gn(t,"right")),o=mn(gn(t,"top"),!0),r=mn(gn(t,"bottom")),a=wl(t,"x"),l=wl(t,"y");return{fullSize:s,leftAndTop:n.concat(o),rightAndBottom:i.concat(l).concat(r).concat(a),chartArea:gn(t,"chartArea"),vertical:n.concat(i).concat(l),horizontal:o.concat(r).concat(a)}}function Sl(e,t,s,n){return Math.max(e[s],t[s])+Math.max(e[n],t[n])}function Sh(e,t){e.top=Math.max(e.top,t.top),e.left=Math.max(e.left,t.left),e.bottom=Math.max(e.bottom,t.bottom),e.right=Math.max(e.right,t.right)}function fy(e,t,s,n){const{pos:i,box:o}=s,r=e.maxPadding;if(!ot(i)){s.size&&(e[i]-=s.size);const h=n[s.stack]||{size:0,count:1};h.size=Math.max(h.size,s.horizontal?o.height:o.width),s.size=h.size/h.count,e[i]+=s.size}o.getPadding&&Sh(r,o.getPadding());const a=Math.max(0,t.outerWidth-Sl(r,e,"left","right")),l=Math.max(0,t.outerHeight-Sl(r,e,"top","bottom")),c=a!==e.w,u=l!==e.h;return e.w=a,e.h=l,s.horizontal?{same:c,other:u}:{same:u,other:c}}function py(e){const t=e.maxPadding;function s(n){const i=Math.max(t[n]-e[n],0);return e[n]+=i,i}e.y+=s("top"),e.x+=s("left"),s("right"),s("bottom")}function gy(e,t){const s=t.maxPadding;function n(i){const o={left:0,top:0,right:0,bottom:0};return i.forEach(r=>{o[r]=Math.max(t[r],s[r])}),o}return n(e?["left","right"]:["top","bottom"])}function Sn(e,t,s,n){const i=[];let o,r,a,l,c,u;for(o=0,r=e.length,c=0;o{typeof g.beforeLayout=="function"&&g.beforeLayout()});const u=l.reduce((g,_)=>_.box.options&&_.box.options.display===!1?g:g+1,0)||1,h=Object.freeze({outerWidth:t,outerHeight:s,padding:i,availableWidth:o,availableHeight:r,vBoxMaxWidth:o/2/u,hBoxMaxHeight:r/2}),d=Object.assign({},i);Sh(d,Yt(n));const f=Object.assign({maxPadding:d,w:o,h:r,x:i.left,y:i.top},i),p=hy(l.concat(c),h);Sn(a.fullSize,f,h,p),Sn(l,f,h,p),Sn(c,f,h,p)&&Sn(l,f,h,p),py(f),kl(a.leftAndTop,f,h,p),f.x+=f.w,f.y+=f.h,kl(a.rightAndBottom,f,h,p),e.chartArea={left:f.left,top:f.top,right:f.left+f.w,bottom:f.top+f.h,height:f.h,width:f.w},bt(a.chartArea,g=>{const _=g.box;Object.assign(_,e.chartArea),_.update(f.w,f.h,{left:0,top:0,right:0,bottom:0})})}};class kh{acquireContext(t,s){}releaseContext(t){return!1}addEventListener(t,s,n){}removeEventListener(t,s,n){}getDevicePixelRatio(){return 1}getMaximumSize(t,s,n,i){return s=Math.max(0,s||t.width),n=n||t.height,{width:s,height:Math.max(0,i?Math.floor(s/i):n)}}isAttached(t){return!0}updateConfig(t){}}class my extends kh{acquireContext(t){return t&&t.getContext&&t.getContext("2d")||null}updateConfig(t){t.options.animation=!1}}const Ci="$chartjs",by={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},Ml=e=>e===null||e==="";function _y(e,t){const s=e.style,n=e.getAttribute("height"),i=e.getAttribute("width");if(e[Ci]={initial:{height:n,width:i,style:{display:s.display,height:s.height,width:s.width}}},s.display=s.display||"block",s.boxSizing=s.boxSizing||"border-box",Ml(i)){const o=ll(e,"width");o!==void 0&&(e.width=o)}if(Ml(n))if(e.style.height==="")e.height=e.width/(t||2);else{const o=ll(e,"height");o!==void 0&&(e.height=o)}return e}const Mh=f0?{passive:!0}:!1;function yy(e,t,s){e&&e.addEventListener(t,s,Mh)}function xy(e,t,s){e&&e.canvas&&e.canvas.removeEventListener(t,s,Mh)}function vy(e,t){const s=by[e.type]||e.type,{x:n,y:i}=Rs(e,t);return{type:s,chart:t,native:e,x:n!==void 0?n:null,y:i!==void 0?i:null}}function Hi(e,t){for(const s of e)if(s===t||s.contains(t))return!0}function wy(e,t,s){const n=e.canvas,i=new MutationObserver(o=>{let r=!1;for(const a of o)r=r||Hi(a.addedNodes,n),r=r&&!Hi(a.removedNodes,n);r&&s()});return i.observe(document,{childList:!0,subtree:!0}),i}function Sy(e,t,s){const n=e.canvas,i=new MutationObserver(o=>{let r=!1;for(const a of o)r=r||Hi(a.removedNodes,n),r=r&&!Hi(a.addedNodes,n);r&&s()});return i.observe(document,{childList:!0,subtree:!0}),i}const Gn=new Map;let Cl=0;function Ch(){const e=window.devicePixelRatio;e!==Cl&&(Cl=e,Gn.forEach((t,s)=>{s.currentDevicePixelRatio!==e&&t()}))}function ky(e,t){Gn.size||window.addEventListener("resize",Ch),Gn.set(e,t)}function My(e){Gn.delete(e),Gn.size||window.removeEventListener("resize",Ch)}function Cy(e,t,s){const n=e.canvas,i=n&&Jr(n);if(!i)return;const o=th((a,l)=>{const c=i.clientWidth;s(a,l),c{const l=a[0],c=l.contentRect.width,u=l.contentRect.height;c===0&&u===0||o(c,u)});return r.observe(i),ky(e,o),r}function Lo(e,t,s){s&&s.disconnect(),t==="resize"&&My(e)}function Py(e,t,s){const n=e.canvas,i=th(o=>{e.ctx!==null&&s(vy(o,e))},e);return yy(n,t,i),i}class Ay extends kh{acquireContext(t,s){const n=t&&t.getContext&&t.getContext("2d");return n&&n.canvas===t?(_y(t,s),n):null}releaseContext(t){const s=t.canvas;if(!s[Ci])return!1;const n=s[Ci].initial;["height","width"].forEach(o=>{const r=n[o];it(r)?s.removeAttribute(o):s.setAttribute(o,r)});const i=n.style||{};return Object.keys(i).forEach(o=>{s.style[o]=i[o]}),s.width=s.width,delete s[Ci],!0}addEventListener(t,s,n){this.removeEventListener(t,s);const i=t.$proxies||(t.$proxies={}),r={attach:wy,detach:Sy,resize:Cy}[s]||Py;i[s]=r(t,s,n)}removeEventListener(t,s){const n=t.$proxies||(t.$proxies={}),i=n[s];if(!i)return;({attach:Lo,detach:Lo,resize:Lo}[s]||xy)(t,s,i),n[s]=void 0}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(t,s,n,i){return d0(t,s,n,i)}isAttached(t){const s=t&&Jr(t);return!!(s&&s.isConnected)}}function Ry(e){return!Xr()||typeof OffscreenCanvas<"u"&&e instanceof OffscreenCanvas?my:Ay}let is=class{static defaults={};static defaultRoutes=void 0;x;y;active=!1;options;$animations;tooltipPosition(t){const{x:s,y:n}=this.getProps(["x","y"],t);return{x:s,y:n}}hasValue(){return nn(this.x)&&nn(this.y)}getProps(t,s){const n=this.$animations;if(!s||!n)return this;const i={};return t.forEach(o=>{i[o]=n[o]&&n[o].active()?n[o]._to:this[o]}),i}};function Oy(e,t){const s=e.options.ticks,n=Ty(e),i=Math.min(s.maxTicksLimit||n,n),o=s.major.enabled?Dy(t):[],r=o.length,a=o[0],l=o[r-1],c=[];if(r>i)return Iy(t,c,o,r/i),c;const u=Ey(o,t,i);if(r>0){let h,d;const f=r>1?Math.round((l-a)/(r-1)):null;for(gi(t,c,u,it(f)?0:a-f,a),h=0,d=r-1;hi)return l}return Math.max(i,1)}function Dy(e){const t=[];let s,n;for(s=0,n=e.length;se==="left"?"right":e==="right"?"left":e,Pl=(e,t,s)=>t==="top"||t==="left"?e[t]+s:e[t]-s,Al=(e,t)=>Math.min(t||e,e);function Rl(e,t){const s=[],n=e.length/t,i=e.length;let o=0;for(;or+a)))return l}function By(e,t){bt(e,s=>{const n=s.gc,i=n.length/2;let o;if(i>t){for(o=0;on?n:s,n=i&&s>n?s:n,{min:de(s,de(n,s)),max:de(n,de(s,n))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){const t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}getLabelItems(t=this.chart.chartArea){return this._labelItems||(this._labelItems=this._computeLabelItems(t))}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){St(this.options.beforeUpdate,[this])}update(t,s,n){const{beginAtZero:i,grace:o,ticks:r}=this.options,a=r.sampleSize;this.beforeUpdate(),this.maxWidth=t,this.maxHeight=s,this._margins=n=Object.assign({left:0,right:0,top:0,bottom:0},n),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+n.left+n.right:this.height+n.top+n.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=W_(this,o,i),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();const l=a=o||n<=1||!this.isHorizontal()){this.labelRotation=i;return}const u=this._getLabelSizes(),h=u.widest.width,d=u.highest.height,f=Bt(this.chart.width-h,0,this.maxWidth);a=t.offset?this.maxWidth/n:f/(n-1),h+6>a&&(a=f/(n-(t.offset?.5:1)),l=this.maxHeight-bn(t.grid)-s.padding-Ol(t.title,this.chart.options.font),c=Math.sqrt(h*h+d*d),r=Hr(Math.min(Math.asin(Bt((u.highest.height+6)/a,-1,1)),Math.asin(Bt(l/c,-1,1))-Math.asin(Bt(d/c,-1,1)))),r=Math.max(i,Math.min(o,r))),this.labelRotation=r}afterCalculateLabelRotation(){St(this.options.afterCalculateLabelRotation,[this])}afterAutoSkip(){}beforeFit(){St(this.options.beforeFit,[this])}fit(){const t={width:0,height:0},{chart:s,options:{ticks:n,title:i,grid:o}}=this,r=this._isVisible(),a=this.isHorizontal();if(r){const l=Ol(i,s.options.font);if(a?(t.width=this.maxWidth,t.height=bn(o)+l):(t.height=this.maxHeight,t.width=bn(o)+l),n.display&&this.ticks.length){const{first:c,last:u,widest:h,highest:d}=this._getLabelSizes(),f=n.padding*2,p=ve(this.labelRotation),g=Math.cos(p),_=Math.sin(p);if(a){const b=n.mirror?0:_*h.width+g*d.height;t.height=Math.min(this.maxHeight,t.height+b+f)}else{const b=n.mirror?0:g*h.width+_*d.height;t.width=Math.min(this.maxWidth,t.width+b+f)}this._calculatePadding(c,u,_,g)}}this._handleMargins(),a?(this.width=this._length=s.width-this._margins.left-this._margins.right,this.height=t.height):(this.width=t.width,this.height=this._length=s.height-this._margins.top-this._margins.bottom)}_calculatePadding(t,s,n,i){const{ticks:{align:o,padding:r},position:a}=this.options,l=this.labelRotation!==0,c=a!=="top"&&this.axis==="x";if(this.isHorizontal()){const u=this.getPixelForTick(0)-this.left,h=this.right-this.getPixelForTick(this.ticks.length-1);let d=0,f=0;l?c?(d=i*t.width,f=n*s.height):(d=n*t.height,f=i*s.width):o==="start"?f=s.width:o==="end"?d=t.width:o!=="inner"&&(d=t.width/2,f=s.width/2),this.paddingLeft=Math.max((d-u+r)*this.width/(this.width-u),0),this.paddingRight=Math.max((f-h+r)*this.width/(this.width-h),0)}else{let u=s.height/2,h=t.height/2;o==="start"?(u=0,h=t.height):o==="end"&&(u=s.height,h=0),this.paddingTop=u+r,this.paddingBottom=h+r}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){St(this.options.afterFit,[this])}isHorizontal(){const{axis:t,position:s}=this.options;return s==="top"||s==="bottom"||t==="x"}isFullSize(){return this.options.fullSize}_convertTicksToLabels(t){this.beforeTickToLabelConversion(),this.generateTickLabels(t);let s,n;for(s=0,n=t.length;s({width:r[C]||0,height:a[C]||0});return{first:P(0),last:P(s-1),widest:P(R),highest:P(k),widths:r,heights:a}}getLabelForValue(t){return t}getPixelForValue(t,s){return NaN}getValueForPixel(t){}getPixelForTick(t){const s=this.ticks;return t<0||t>s.length-1?null:this.getPixelForValue(s[t].value)}getPixelForDecimal(t){this._reversePixels&&(t=1-t);const s=this._startPixel+t*this._length;return y_(this._alignToPixels?Ms(this.chart,s,0):s)}getDecimalForPixel(t){const s=(t-this._startPixel)/this._length;return this._reversePixels?1-s:s}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){const{min:t,max:s}=this;return t<0&&s<0?s:t>0&&s>0?t:0}getContext(t){const s=this.ticks||[];if(t>=0&&ta*i?a/n:l/i:l*i0}_computeGridLineItems(t){const s=this.axis,n=this.chart,i=this.options,{grid:o,position:r,border:a}=i,l=o.offset,c=this.isHorizontal(),h=this.ticks.length+(l?1:0),d=bn(o),f=[],p=a.setContext(this.getContext()),g=p.display?p.width:0,_=g/2,b=function(tt){return Ms(n,tt,g)};let v,M,S,w,R,k,P,C,O,B,U,at;if(r==="top")v=b(this.bottom),k=this.bottom-d,C=v-_,B=b(t.top)+_,at=t.bottom;else if(r==="bottom")v=b(this.top),B=t.top,at=b(t.bottom)-_,k=v+_,C=this.top+d;else if(r==="left")v=b(this.right),R=this.right-d,P=v-_,O=b(t.left)+_,U=t.right;else if(r==="right")v=b(this.left),O=t.left,U=b(t.right)-_,R=v+_,P=this.left+d;else if(s==="x"){if(r==="center")v=b((t.top+t.bottom)/2+.5);else if(ot(r)){const tt=Object.keys(r)[0],Y=r[tt];v=b(this.chart.scales[tt].getPixelForValue(Y))}B=t.top,at=t.bottom,k=v+_,C=k+d}else if(s==="y"){if(r==="center")v=b((t.left+t.right)/2);else if(ot(r)){const tt=Object.keys(r)[0],Y=r[tt];v=b(this.chart.scales[tt].getPixelForValue(Y))}R=v-_,P=R-d,O=t.left,U=t.right}const Ct=Z(i.ticks.maxTicksLimit,h),rt=Math.max(1,Math.ceil(h/Ct));for(M=0;M0&&(Lt-=ie/2);break}Jt={left:Lt,top:ue,width:ie+Et.width,height:pe+Et.height,color:rt.backdropColor}}_.push({label:S,font:C,textOffset:U,options:{rotation:g,color:Y,strokeColor:nt,strokeWidth:xt,textAlign:Xt,textBaseline:at,translation:[w,R],backdrop:Jt}})}return _}_getXAxisLabelAlignment(){const{position:t,ticks:s}=this.options;if(-ve(this.labelRotation))return t==="top"?"left":"right";let i="center";return s.align==="start"?i="left":s.align==="end"?i="right":s.align==="inner"&&(i="inner"),i}_getYAxisLabelAlignment(t){const{position:s,ticks:{crossAlign:n,mirror:i,padding:o}}=this.options,r=this._getLabelSizes(),a=t+o,l=r.widest.width;let c,u;return s==="left"?i?(u=this.right+o,n==="near"?c="left":n==="center"?(c="center",u+=l/2):(c="right",u+=l)):(u=this.right-a,n==="near"?c="right":n==="center"?(c="center",u-=l/2):(c="left",u=this.left)):s==="right"?i?(u=this.left+o,n==="near"?c="right":n==="center"?(c="center",u-=l/2):(c="left",u-=l)):(u=this.left+a,n==="near"?c="left":n==="center"?(c="center",u+=l/2):(c="right",u=this.right)):c="right",{textAlign:c,x:u}}_computeLabelArea(){if(this.options.ticks.mirror)return;const t=this.chart,s=this.options.position;if(s==="left"||s==="right")return{top:0,left:this.left,bottom:t.height,right:this.right};if(s==="top"||s==="bottom")return{top:this.top,left:0,bottom:this.bottom,right:t.width}}drawBackground(){const{ctx:t,options:{backgroundColor:s},left:n,top:i,width:o,height:r}=this;s&&(t.save(),t.fillStyle=s,t.fillRect(n,i,o,r),t.restore())}getLineWidthForValue(t){const s=this.options.grid;if(!this._isVisible()||!s.display)return 0;const i=this.ticks.findIndex(o=>o.value===t);return i>=0?s.setContext(this.getContext(i)).lineWidth:0}drawGrid(t){const s=this.options.grid,n=this.ctx,i=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t));let o,r;const a=(l,c,u)=>{!u.width||!u.color||(n.save(),n.lineWidth=u.width,n.strokeStyle=u.color,n.setLineDash(u.borderDash||[]),n.lineDashOffset=u.borderDashOffset,n.beginPath(),n.moveTo(l.x,l.y),n.lineTo(c.x,c.y),n.stroke(),n.restore())};if(s.display)for(o=0,r=i.length;o{this.draw(o)}}]:[{z:n,draw:o=>{this.drawBackground(),this.drawGrid(o),this.drawTitle()}},{z:i,draw:()=>{this.drawBorder()}},{z:s,draw:o=>{this.drawLabels(o)}}]}getMatchingVisibleMetas(t){const s=this.chart.getSortedVisibleDatasetMetas(),n=this.axis+"AxisID",i=[];let o,r;for(o=0,r=s.length;o{const n=s.split("."),i=n.pop(),o=[e].concat(n).join("."),r=t[s].split("."),a=r.pop(),l=r.join(".");Rt.route(o,i,l,a)})}function qy(e){return"id"in e&&"defaults"in e}class Uy{constructor(){this.controllers=new mi(vs,"datasets",!0),this.elements=new mi(is,"elements"),this.plugins=new mi(Object,"plugins"),this.scales=new mi(js,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...t){this._each("register",t)}remove(...t){this._each("unregister",t)}addControllers(...t){this._each("register",t,this.controllers)}addElements(...t){this._each("register",t,this.elements)}addPlugins(...t){this._each("register",t,this.plugins)}addScales(...t){this._each("register",t,this.scales)}getController(t){return this._get(t,this.controllers,"controller")}getElement(t){return this._get(t,this.elements,"element")}getPlugin(t){return this._get(t,this.plugins,"plugin")}getScale(t){return this._get(t,this.scales,"scale")}removeControllers(...t){this._each("unregister",t,this.controllers)}removeElements(...t){this._each("unregister",t,this.elements)}removePlugins(...t){this._each("unregister",t,this.plugins)}removeScales(...t){this._each("unregister",t,this.scales)}_each(t,s,n){[...s].forEach(i=>{const o=n||this._getRegistryForType(i);n||o.isForType(i)||o===this.plugins&&i.id?this._exec(t,o,i):bt(i,r=>{const a=n||this._getRegistryForType(r);this._exec(t,a,r)})})}_exec(t,s,n){const i=jr(t);St(n["before"+i],[],n),s[t](n),St(n["after"+i],[],n)}_getRegistryForType(t){for(let s=0;so.filter(a=>!r.some(l=>a.plugin.id===l.plugin.id));this._notify(i(s,n),t,"stop"),this._notify(i(n,s),t,"start")}}function Gy(e){const t={},s=[],n=Object.keys(Ee.plugins.items);for(let o=0;o1&&Tl(e[0].toLowerCase());if(n)return n}throw new Error(`Cannot determine type of '${e}' axis. Please provide 'axis' or 'position' option.`)}function El(e,t,s){if(s[t+"AxisID"]===e)return{axis:t}}function ex(e,t){if(t.data&&t.data.datasets){const s=t.data.datasets.filter(n=>n.xAxisID===e||n.yAxisID===e);if(s.length)return El(e,"x",s[0])||El(e,"y",s[0])}return{}}function sx(e,t){const s=$s[e.type]||{scales:{}},n=t.scales||{},i=ar(e.type,t),o=Object.create(null);return Object.keys(n).forEach(r=>{const a=n[r];if(!ot(a))return console.error(`Invalid scale configuration for scale: ${r}`);if(a._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${r}`);const l=lr(r,a,ex(r,e),Rt.scales[a.type]),c=Zy(l,i),u=s.scales||{};o[r]=En(Object.create(null),[{axis:l},a,u[l],u[c]])}),e.data.datasets.forEach(r=>{const a=r.type||e.type,l=r.indexAxis||ar(a,t),u=($s[a]||{}).scales||{};Object.keys(u).forEach(h=>{const d=Qy(h,l),f=r[d+"AxisID"]||d;o[f]=o[f]||Object.create(null),En(o[f],[{axis:d},n[f],u[h]])})}),Object.keys(o).forEach(r=>{const a=o[r];En(a,[Rt.scales[a.type],Rt.scale])}),o}function Ph(e){const t=e.options||(e.options={});t.plugins=Z(t.plugins,{}),t.scales=sx(e,t)}function Ah(e){return e=e||{},e.datasets=e.datasets||[],e.labels=e.labels||[],e}function nx(e){return e=e||{},e.data=Ah(e.data),Ph(e),e}const Dl=new Map,Rh=new Set;function bi(e,t){let s=Dl.get(e);return s||(s=t(),Dl.set(e,s),Rh.add(s)),s}const _n=(e,t,s)=>{const n=bs(t,s);n!==void 0&&e.add(n)};class ix{constructor(t){this._config=nx(t),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(t){this._config.type=t}get data(){return this._config.data}set data(t){this._config.data=Ah(t)}get options(){return this._config.options}set options(t){this._config.options=t}get plugins(){return this._config.plugins}update(){const t=this._config;this.clearCache(),Ph(t)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(t){return bi(t,()=>[[`datasets.${t}`,""]])}datasetAnimationScopeKeys(t,s){return bi(`${t}.transition.${s}`,()=>[[`datasets.${t}.transitions.${s}`,`transitions.${s}`],[`datasets.${t}`,""]])}datasetElementScopeKeys(t,s){return bi(`${t}-${s}`,()=>[[`datasets.${t}.elements.${s}`,`datasets.${t}`,`elements.${s}`,""]])}pluginScopeKeys(t){const s=t.id,n=this.type;return bi(`${n}-plugin-${s}`,()=>[[`plugins.${s}`,...t.additionalOptionScopes||[]]])}_cachedScopes(t,s){const n=this._scopeCache;let i=n.get(t);return(!i||s)&&(i=new Map,n.set(t,i)),i}getOptionScopes(t,s,n){const{options:i,type:o}=this,r=this._cachedScopes(t,n),a=r.get(s);if(a)return a;const l=new Set;s.forEach(u=>{t&&(l.add(t),u.forEach(h=>_n(l,t,h))),u.forEach(h=>_n(l,i,h)),u.forEach(h=>_n(l,$s[o]||{},h)),u.forEach(h=>_n(l,Rt,h)),u.forEach(h=>_n(l,or,h))});const c=Array.from(l);return c.length===0&&c.push(Object.create(null)),Rh.has(s)&&r.set(s,c),c}chartOptionScopes(){const{options:t,type:s}=this;return[t,$s[s]||{},Rt.datasets[s]||{},{type:s},Rt,or]}resolveNamedOptions(t,s,n,i=[""]){const o={$shared:!0},{resolver:r,subPrefixes:a}=Il(this._resolverCache,t,i);let l=r;if(rx(r,s)){o.$shared=!1,n=_s(n)?n():n;const c=this.createResolver(t,n,a);l=on(r,n,c)}for(const c of s)o[c]=l[c];return o}createResolver(t,s,n=[""],i){const{resolver:o}=Il(this._resolverCache,t,n);return ot(s)?on(o,s,void 0,i):o}}function Il(e,t,s){let n=e.get(t);n||(n=new Map,e.set(t,n));const i=s.join();let o=n.get(i);return o||(o={resolver:Kr(t,s),subPrefixes:s.filter(a=>!a.toLowerCase().includes("hover"))},n.set(i,o)),o}const ox=e=>ot(e)&&Object.getOwnPropertyNames(e).some(t=>_s(e[t]));function rx(e,t){const{isScriptable:s,isIndexable:n}=rh(e);for(const i of t){const o=s(i),r=n(i),a=(r||o)&&e[i];if(o&&(_s(a)||ox(a))||r&&At(a))return!0}return!1}var ax="4.5.1";const lx=["top","bottom","left","right","chartArea"];function Ll(e,t){return e==="top"||e==="bottom"||lx.indexOf(e)===-1&&t==="x"}function Fl(e,t){return function(s,n){return s[e]===n[e]?s[t]-n[t]:s[e]-n[e]}}function Nl(e){const t=e.chart,s=t.options.animation;t.notifyPlugins("afterRender"),St(s&&s.onComplete,[e],t)}function cx(e){const t=e.chart,s=t.options.animation;St(s&&s.onProgress,[e],t)}function Oh(e){return Xr()&&typeof e=="string"?e=document.getElementById(e):e&&e.length&&(e=e[0]),e&&e.canvas&&(e=e.canvas),e}const Pi={},Bl=e=>{const t=Oh(e);return Object.values(Pi).filter(s=>s.canvas===t).pop()};function ux(e,t,s){const n=Object.keys(e);for(const i of n){const o=+i;if(o>=t){const r=e[i];delete e[i],(s>0||o>t)&&(e[o+s]=r)}}}function hx(e,t,s,n){return!s||e.type==="mouseout"?null:n?t:e}class Ai{static defaults=Rt;static instances=Pi;static overrides=$s;static registry=Ee;static version=ax;static getChart=Bl;static register(...t){Ee.add(...t),$l()}static unregister(...t){Ee.remove(...t),$l()}constructor(t,s){const n=this.config=new ix(s),i=Oh(t),o=Bl(i);if(o)throw new Error("Canvas is already in use. Chart with ID '"+o.id+"' must be destroyed before the canvas with ID '"+o.canvas.id+"' can be reused.");const r=n.createResolver(n.chartOptionScopes(),this.getContext());this.platform=new(n.platform||Ry(i)),this.platform.updateConfig(n);const a=this.platform.acquireContext(i,r.aspectRatio),l=a&&a.canvas,c=l&&l.height,u=l&&l.width;if(this.id=r_(),this.ctx=a,this.canvas=l,this.width=u,this.height=c,this._options=r,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new Ky,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=S_(h=>this.update(h),r.resizeDelay||0),this._dataChanges=[],Pi[this.id]=this,!a||!l){console.error("Failed to create chart: can't acquire context from the given item");return}je.listen(this,"complete",Nl),je.listen(this,"progress",cx),this._initialize(),this.attached&&this.update()}get aspectRatio(){const{options:{aspectRatio:t,maintainAspectRatio:s},width:n,height:i,_aspectRatio:o}=this;return it(t)?s&&o?o:i?n/i:null:t}get data(){return this.config.data}set data(t){this.config.data=t}get options(){return this._options}set options(t){this.config.options=t}get registry(){return Ee}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():al(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return il(this.canvas,this.ctx),this}stop(){return je.stop(this),this}resize(t,s){je.running(this)?this._resizeBeforeDraw={width:t,height:s}:this._resize(t,s)}_resize(t,s){const n=this.options,i=this.canvas,o=n.maintainAspectRatio&&this.aspectRatio,r=this.platform.getMaximumSize(i,t,s,o),a=n.devicePixelRatio||this.platform.getDevicePixelRatio(),l=this.width?"resize":"attach";this.width=r.width,this.height=r.height,this._aspectRatio=this.aspectRatio,al(this,a,!0)&&(this.notifyPlugins("resize",{size:r}),St(n.onResize,[this,r],this),this.attached&&this._doResize(l)&&this.render())}ensureScalesHaveIDs(){const s=this.options.scales||{};bt(s,(n,i)=>{n.id=i})}buildOrUpdateScales(){const t=this.options,s=t.scales,n=this.scales,i=Object.keys(n).reduce((r,a)=>(r[a]=!1,r),{});let o=[];s&&(o=o.concat(Object.keys(s).map(r=>{const a=s[r],l=lr(r,a),c=l==="r",u=l==="x";return{options:a,dposition:c?"chartArea":u?"bottom":"left",dtype:c?"radialLinear":u?"category":"linear"}}))),bt(o,r=>{const a=r.options,l=a.id,c=lr(l,a),u=Z(a.type,r.dtype);(a.position===void 0||Ll(a.position,c)!==Ll(r.dposition))&&(a.position=r.dposition),i[l]=!0;let h=null;if(l in n&&n[l].type===u)h=n[l];else{const d=Ee.getScale(u);h=new d({id:l,type:u,ctx:this.ctx,chart:this}),n[h.id]=h}h.init(a,t)}),bt(i,(r,a)=>{r||delete n[a]}),bt(n,r=>{Ut.configure(this,r,r.options),Ut.addBox(this,r)})}_updateMetasets(){const t=this._metasets,s=this.data.datasets.length,n=t.length;if(t.sort((i,o)=>i.index-o.index),n>s){for(let i=s;is.length&&delete this._stacks,t.forEach((n,i)=>{s.filter(o=>o===n._dataset).length===0&&this._destroyDatasetMeta(i)})}buildOrUpdateControllers(){const t=[],s=this.data.datasets;let n,i;for(this._removeUnreferencedMetasets(),n=0,i=s.length;n{this.getDatasetMeta(s).controller.reset()},this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(t){const s=this.config;s.update();const n=this._options=s.createResolver(s.chartOptionScopes(),this.getContext()),i=this._animationsDisabled=!n.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),this.notifyPlugins("beforeUpdate",{mode:t,cancelable:!0})===!1)return;const o=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let r=0;for(let c=0,u=this.data.datasets.length;c{c.reset()}),this._updateDatasets(t),this.notifyPlugins("afterUpdate",{mode:t}),this._layers.sort(Fl("z","_idx"));const{_active:a,_lastEvent:l}=this;l?this._eventHandler(l,!0):a.length&&this._updateHoverStyles(a,a,!0),this.render()}_updateScales(){bt(this.scales,t=>{Ut.removeBox(this,t)}),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){const t=this.options,s=new Set(Object.keys(this._listeners)),n=new Set(t.events);(!Ya(s,n)||!!this._responsiveListeners!==t.responsive)&&(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){const{_hiddenIndices:t}=this,s=this._getUniformDataChanges()||[];for(const{method:n,start:i,count:o}of s){const r=n==="_removeElements"?-o:o;ux(t,i,r)}}_getUniformDataChanges(){const t=this._dataChanges;if(!t||!t.length)return;this._dataChanges=[];const s=this.data.datasets.length,n=o=>new Set(t.filter(r=>r[0]===o).map((r,a)=>a+","+r.splice(1).join(","))),i=n(0);for(let o=1;oo.split(",")).map(o=>({method:o[1],start:+o[2],count:+o[3]}))}_updateLayout(t){if(this.notifyPlugins("beforeLayout",{cancelable:!0})===!1)return;Ut.update(this,this.width,this.height,t);const s=this.chartArea,n=s.width<=0||s.height<=0;this._layers=[],bt(this.boxes,i=>{n&&i.position==="chartArea"||(i.configure&&i.configure(),this._layers.push(...i._layers()))},this),this._layers.forEach((i,o)=>{i._idx=o}),this.notifyPlugins("afterLayout")}_updateDatasets(t){if(this.notifyPlugins("beforeDatasetsUpdate",{mode:t,cancelable:!0})!==!1){for(let s=0,n=this.data.datasets.length;s=0;--s)this._drawDataset(t[s]);this.notifyPlugins("afterDatasetsDraw")}_drawDataset(t){const s=this.ctx,n={meta:t,index:t.index,cancelable:!0},i=bh(this,t);this.notifyPlugins("beforeDatasetDraw",n)!==!1&&(i&&ro(s,i),t.controller.draw(),i&&ao(s),n.cancelable=!1,this.notifyPlugins("afterDatasetDraw",n))}isPointInArea(t){return Xe(t,this.chartArea,this._minPadding)}getElementsAtEventForMode(t,s,n,i){const o=ly.modes[s];return typeof o=="function"?o(this,t,n,i):[]}getDatasetMeta(t){const s=this.data.datasets[t],n=this._metasets;let i=n.filter(o=>o&&o._dataset===s).pop();return i||(i={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:s&&s.order||0,index:t,_dataset:s,_parsed:[],_sorted:!1},n.push(i)),i}getContext(){return this.$context||(this.$context=xs(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(t){const s=this.data.datasets[t];if(!s)return!1;const n=this.getDatasetMeta(t);return typeof n.hidden=="boolean"?!n.hidden:!s.hidden}setDatasetVisibility(t,s){const n=this.getDatasetMeta(t);n.hidden=!s}toggleDataVisibility(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}getDataVisibility(t){return!this._hiddenIndices[t]}_updateVisibility(t,s,n){const i=n?"show":"hide",o=this.getDatasetMeta(t),r=o.controller._resolveAnimations(void 0,i);qn(s)?(o.data[s].hidden=!n,this.update()):(this.setDatasetVisibility(t,n),r.update(o,{visible:n}),this.update(a=>a.datasetIndex===t?i:void 0))}hide(t,s){this._updateVisibility(t,s,!1)}show(t,s){this._updateVisibility(t,s,!0)}_destroyDatasetMeta(t){const s=this._metasets[t];s&&s.controller&&s.controller._destroy(),delete this._metasets[t]}_stop(){let t,s;for(this.stop(),je.remove(this),t=0,s=this.data.datasets.length;t{s.addEventListener(this,o,r),t[o]=r},i=(o,r,a)=>{o.offsetX=r,o.offsetY=a,this._eventHandler(o)};bt(this.options.events,o=>n(o,i))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const t=this._responsiveListeners,s=this.platform,n=(l,c)=>{s.addEventListener(this,l,c),t[l]=c},i=(l,c)=>{t[l]&&(s.removeEventListener(this,l,c),delete t[l])},o=(l,c)=>{this.canvas&&this.resize(l,c)};let r;const a=()=>{i("attach",a),this.attached=!0,this.resize(),n("resize",o),n("detach",r)};r=()=>{this.attached=!1,i("resize",o),this._stop(),this._resize(0,0),n("attach",a)},s.isAttached(this.canvas)?a():r()}unbindEvents(){bt(this._listeners,(t,s)=>{this.platform.removeEventListener(this,s,t)}),this._listeners={},bt(this._responsiveListeners,(t,s)=>{this.platform.removeEventListener(this,s,t)}),this._responsiveListeners=void 0}updateHoverStyle(t,s,n){const i=n?"set":"remove";let o,r,a,l;for(s==="dataset"&&(o=this.getDatasetMeta(t[0].datasetIndex),o.controller["_"+i+"DatasetHoverStyle"]()),a=0,l=t.length;a{const a=this.getDatasetMeta(o);if(!a)throw new Error("No dataset found at index "+o);return{datasetIndex:o,element:a.data[r],index:r}});!Ni(n,s)&&(this._active=n,this._lastEvent=null,this._updateHoverStyles(n,s))}notifyPlugins(t,s,n){return this._plugins.notify(this,t,s,n)}isPluginEnabled(t){return this._plugins._cache.filter(s=>s.plugin.id===t).length===1}_updateHoverStyles(t,s,n){const i=this.options.hover,o=(l,c)=>l.filter(u=>!c.some(h=>u.datasetIndex===h.datasetIndex&&u.index===h.index)),r=o(s,t),a=n?t:o(t,s);r.length&&this.updateHoverStyle(r,i.mode,!1),a.length&&i.mode&&this.updateHoverStyle(a,i.mode,!0)}_eventHandler(t,s){const n={event:t,replay:s,cancelable:!0,inChartArea:this.isPointInArea(t)},i=r=>(r.options.events||this.options.events).includes(t.native.type);if(this.notifyPlugins("beforeEvent",n,i)===!1)return;const o=this._handleEvent(t,s,n.inChartArea);return n.cancelable=!1,this.notifyPlugins("afterEvent",n,i),(o||n.changed)&&this.render(),this}_handleEvent(t,s,n){const{_active:i=[],options:o}=this,r=s,a=this._getActiveElements(t,i,n,r),l=d_(t),c=hx(t,this._lastEvent,n,l);n&&(this._lastEvent=null,St(o.onHover,[t,a,this],this),l&&St(o.onClick,[t,a,this],this));const u=!Ni(a,i);return(u||s)&&(this._active=a,this._updateHoverStyles(a,i,s)),this._lastEvent=c,u}_getActiveElements(t,s,n,i){if(t.type==="mouseout")return[];if(!n)return s;const o=this.options.hover;return this.getElementsAtEventForMode(t,o.mode,o,i)}}function $l(){return bt(Ai.instances,e=>e._plugins.invalidate())}function dx(e,t,s){const{startAngle:n,x:i,y:o,outerRadius:r,innerRadius:a,options:l}=t,{borderWidth:c,borderJoinStyle:u}=l,h=Math.min(c/r,Ht(n-s));if(e.beginPath(),e.arc(i,o,r-c/2,n+h/2,s-h/2),a>0){const d=Math.min(c/a,Ht(n-s));e.arc(i,o,a+c/2,s-d/2,n+d/2,!0)}else{const d=Math.min(c/2,r*Ht(n-s));if(u==="round")e.arc(i,o,d,s-ht/2,n+ht/2,!0);else if(u==="bevel"){const f=2*d*d,p=-f*Math.cos(s+ht/2)+i,g=-f*Math.sin(s+ht/2)+o,_=f*Math.cos(n+ht/2)+i,b=f*Math.sin(n+ht/2)+o;e.lineTo(p,g),e.lineTo(_,b)}}e.closePath(),e.moveTo(0,0),e.rect(0,0,e.canvas.width,e.canvas.height),e.clip("evenodd")}function fx(e,t,s){const{startAngle:n,pixelMargin:i,x:o,y:r,outerRadius:a,innerRadius:l}=t;let c=i/a;e.beginPath(),e.arc(o,r,a,n-c,s+c),l>i?(c=i/l,e.arc(o,r,l,s+c,n-c,!0)):e.arc(o,r,i,s+Dt,n-Dt),e.closePath(),e.clip()}function px(e){return Ur(e,["outerStart","outerEnd","innerStart","innerEnd"])}function gx(e,t,s,n){const i=px(e.options.borderRadius),o=(s-t)/2,r=Math.min(o,n*t/2),a=l=>{const c=(s-Math.min(o,l))*n/2;return Bt(l,0,Math.min(o,c))};return{outerStart:a(i.outerStart),outerEnd:a(i.outerEnd),innerStart:Bt(i.innerStart,0,r),innerEnd:Bt(i.innerEnd,0,r)}}function Ws(e,t,s,n){return{x:s+e*Math.cos(t),y:n+e*Math.sin(t)}}function zi(e,t,s,n,i,o){const{x:r,y:a,startAngle:l,pixelMargin:c,innerRadius:u}=t,h=Math.max(t.outerRadius+n+s-c,0),d=u>0?u+n+s+c:0;let f=0;const p=i-l;if(n){const rt=u>0?u-n:0,tt=h>0?h-n:0,Y=(rt+tt)/2,nt=Y!==0?p*Y/(Y+n):p;f=(p-nt)/2}const g=Math.max(.001,p*h-s/ht)/h,_=(p-g)/2,b=l+_+f,v=i-_-f,{outerStart:M,outerEnd:S,innerStart:w,innerEnd:R}=gx(t,d,h,v-b),k=h-M,P=h-S,C=b+M/k,O=v-S/P,B=d+w,U=d+R,at=b+w/B,Ct=v-R/U;if(e.beginPath(),o){const rt=(C+O)/2;if(e.arc(r,a,h,C,rt),e.arc(r,a,h,rt,O),S>0){const xt=Ws(P,O,r,a);e.arc(xt.x,xt.y,S,O,v+Dt)}const tt=Ws(U,v,r,a);if(e.lineTo(tt.x,tt.y),R>0){const xt=Ws(U,Ct,r,a);e.arc(xt.x,xt.y,R,v+Dt,Ct+Math.PI)}const Y=(v-R/d+(b+w/d))/2;if(e.arc(r,a,d,v-R/d,Y,!0),e.arc(r,a,d,Y,b+w/d,!0),w>0){const xt=Ws(B,at,r,a);e.arc(xt.x,xt.y,w,at+Math.PI,b-Dt)}const nt=Ws(k,b,r,a);if(e.lineTo(nt.x,nt.y),M>0){const xt=Ws(k,C,r,a);e.arc(xt.x,xt.y,M,b-Dt,C)}}else{e.moveTo(r,a);const rt=Math.cos(C)*h+r,tt=Math.sin(C)*h+a;e.lineTo(rt,tt);const Y=Math.cos(O)*h+r,nt=Math.sin(O)*h+a;e.lineTo(Y,nt)}e.closePath()}function mx(e,t,s,n,i){const{fullCircles:o,startAngle:r,circumference:a}=t;let l=t.endAngle;if(o){zi(e,t,s,n,l,i);for(let c=0;c=ht&&f===0&&u!=="miter"&&dx(e,t,g),o||(zi(e,t,s,n,g,i),e.stroke())}class _x extends is{static id="arc";static defaults={borderAlign:"center",borderColor:"#fff",borderDash:[],borderDashOffset:0,borderJoinStyle:void 0,borderRadius:0,borderWidth:2,offset:0,spacing:0,angle:void 0,circular:!0,selfJoin:!1};static defaultRoutes={backgroundColor:"backgroundColor"};static descriptors={_scriptable:!0,_indexable:t=>t!=="borderDash"};circumference;endAngle;fullCircles;innerRadius;outerRadius;pixelMargin;startAngle;constructor(t){super(),this.options=void 0,this.circumference=void 0,this.startAngle=void 0,this.endAngle=void 0,this.innerRadius=void 0,this.outerRadius=void 0,this.pixelMargin=0,this.fullCircles=0,t&&Object.assign(this,t)}inRange(t,s,n){const i=this.getProps(["x","y"],n),{angle:o,distance:r}=Xu(i,{x:t,y:s}),{startAngle:a,endAngle:l,innerRadius:c,outerRadius:u,circumference:h}=this.getProps(["startAngle","endAngle","innerRadius","outerRadius","circumference"],n),d=(this.options.spacing+this.options.borderWidth)/2,f=Z(h,l-a),p=Un(o,a,l)&&a!==l,g=f>=Mt||p,_=Ge(r,c+d,u+d);return g&&_}getCenterPoint(t){const{x:s,y:n,startAngle:i,endAngle:o,innerRadius:r,outerRadius:a}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius"],t),{offset:l,spacing:c}=this.options,u=(i+o)/2,h=(r+a+c+l)/2;return{x:s+Math.cos(u)*h,y:n+Math.sin(u)*h}}tooltipPosition(t){return this.getCenterPoint(t)}draw(t){const{options:s,circumference:n}=this,i=(s.offset||0)/4,o=(s.spacing||0)/2,r=s.circular;if(this.pixelMargin=s.borderAlign==="inner"?.33:0,this.fullCircles=n>Mt?Math.floor(n/Mt):0,n===0||this.innerRadius<0||this.outerRadius<0)return;t.save();const a=(this.startAngle+this.endAngle)/2;t.translate(Math.cos(a)*i,Math.sin(a)*i);const l=1-Math.sin(Math.min(ht,n||0)),c=i*l;t.fillStyle=s.backgroundColor,t.strokeStyle=s.borderColor,mx(t,this,c,o,r),bx(t,this,c,o,r),t.restore()}}function Th(e,t,s=t){e.lineCap=Z(s.borderCapStyle,t.borderCapStyle),e.setLineDash(Z(s.borderDash,t.borderDash)),e.lineDashOffset=Z(s.borderDashOffset,t.borderDashOffset),e.lineJoin=Z(s.borderJoinStyle,t.borderJoinStyle),e.lineWidth=Z(s.borderWidth,t.borderWidth),e.strokeStyle=Z(s.borderColor,t.borderColor)}function yx(e,t,s){e.lineTo(s.x,s.y)}function xx(e){return e.stepped?L_:e.tension||e.cubicInterpolationMode==="monotone"?F_:yx}function Eh(e,t,s={}){const n=e.length,{start:i=0,end:o=n-1}=s,{start:r,end:a}=t,l=Math.max(i,r),c=Math.min(o,a),u=ia&&o>a;return{count:n,start:l,loop:t.loop,ilen:c(r+(c?a-S:S))%o,M=()=>{g!==_&&(e.lineTo(u,_),e.lineTo(u,g),e.lineTo(u,b))};for(l&&(f=i[v(0)],e.moveTo(f.x,f.y)),d=0;d<=a;++d){if(f=i[v(d)],f.skip)continue;const S=f.x,w=f.y,R=S|0;R===p?(w_&&(_=w),u=(h*u+S)/++h):(M(),e.lineTo(S,w),p=R,h=0,g=_=w),b=w}M()}function cr(e){const t=e.options,s=t.borderDash&&t.borderDash.length;return!e._decimated&&!e._loop&&!t.tension&&t.cubicInterpolationMode!=="monotone"&&!t.stepped&&!s?wx:vx}function Sx(e){return e.stepped?p0:e.tension||e.cubicInterpolationMode==="monotone"?g0:Os}function kx(e,t,s,n){let i=t._path;i||(i=t._path=new Path2D,t.path(i,s,n)&&i.closePath()),Th(e,t.options),e.stroke(i)}function Mx(e,t,s,n){const{segments:i,options:o}=t,r=cr(t);for(const a of i)Th(e,o,a.style),e.beginPath(),r(e,t,a,{start:s,end:s+n-1})&&e.closePath(),e.stroke()}const Cx=typeof Path2D=="function";function Px(e,t,s,n){Cx&&!t.options.segment?kx(e,t,s,n):Mx(e,t,s,n)}class uo extends is{static id="line";static defaults={borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderWidth:3,capBezierPoints:!0,cubicInterpolationMode:"default",fill:!1,spanGaps:!1,stepped:!1,tension:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};static descriptors={_scriptable:!0,_indexable:t=>t!=="borderDash"&&t!=="fill"};constructor(t){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,t&&Object.assign(this,t)}updateControlPoints(t,s){const n=this.options;if((n.tension||n.cubicInterpolationMode==="monotone")&&!n.stepped&&!this._pointsUpdated){const i=n.spanGaps?this._loop:this._fullLoop;r0(this._points,n,t,i,s),this._pointsUpdated=!0}}set points(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=v0(this,this.options.segment))}first(){const t=this.segments,s=this.points;return t.length&&s[t[0].start]}last(){const t=this.segments,s=this.points,n=t.length;return n&&s[t[n-1].end]}interpolate(t,s){const n=this.options,i=t[s],o=this.points,r=mh(this,{property:s,start:i,end:i});if(!r.length)return;const a=[],l=Sx(n);let c,u;for(c=0,u=r.length;ce.replace("rgb(","rgba(").replace(")",", 0.5)"));function Ih(e){return ur[e%ur.length]}function Lh(e){return jl[e%jl.length]}function Fx(e,t){return e.borderColor=Ih(t),e.backgroundColor=Lh(t),++t}function Nx(e,t){return e.backgroundColor=e.data.map(()=>Ih(t++)),t}function Bx(e,t){return e.backgroundColor=e.data.map(()=>Lh(t++)),t}function $x(e){let t=0;return(s,n)=>{const i=e.getDatasetMeta(n).controller;i instanceof Qr?t=Nx(s,t):i instanceof vh?t=Bx(s,t):i&&(t=Fx(s,t))}}function Hl(e){let t;for(t in e)if(e[t].borderColor||e[t].backgroundColor)return!0;return!1}function Vx(e){return e&&(e.borderColor||e.backgroundColor)}function jx(){return Rt.borderColor!=="rgba(0,0,0,0.1)"||Rt.backgroundColor!=="rgba(0,0,0,0.1)"}var Hx={id:"colors",defaults:{enabled:!0,forceOverride:!1},beforeLayout(e,t,s){if(!s.enabled)return;const{data:{datasets:n},options:i}=e.config,{elements:o}=i,r=Hl(n)||Vx(i)||o&&Hl(o)||jx();if(!s.forceOverride&&r)return;const a=$x(e);n.forEach(a)}};function zx(e,t,s,n,i){const o=i.samples||n;if(o>=s)return e.slice(t,t+s);const r=[],a=(s-2)/(o-2);let l=0;const c=t+s-1;let u=t,h,d,f,p,g;for(r[l++]=e[u],h=0;hf&&(f=p,d=e[v],g=v);r[l++]=d,u=g}return r[l++]=e[c],r}function Wx(e,t,s,n){let i=0,o=0,r,a,l,c,u,h,d,f,p,g;const _=[],b=t+s-1,v=e[t].x,S=e[b].x-v;for(r=t;rg&&(g=c,d=r),i=(o*i+a.x)/++o;else{const R=r-1;if(!it(h)&&!it(d)){const k=Math.min(h,d),P=Math.max(h,d);k!==f&&k!==R&&_.push({...e[k],x:i}),P!==f&&P!==R&&_.push({...e[P],x:i})}r>0&&R!==f&&_.push(e[R]),_.push(a),u=w,o=0,p=g=c,h=d=f=r}}return _}function Fh(e){if(e._decimated){const t=e._data;delete e._decimated,delete e._data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,writable:!0,value:t})}}function zl(e){e.data.datasets.forEach(t=>{Fh(t)})}function qx(e,t){const s=t.length;let n=0,i;const{iScale:o}=e,{min:r,max:a,minDefined:l,maxDefined:c}=o.getUserBounds();return l&&(n=Bt(Ye(t,o.axis,r).lo,0,s-1)),c?i=Bt(Ye(t,o.axis,a).hi+1,n,s)-n:i=s-n,{start:n,count:i}}var Ux={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(e,t,s)=>{if(!s.enabled){zl(e);return}const n=e.width;e.data.datasets.forEach((i,o)=>{const{_data:r,indexAxis:a}=i,l=e.getDatasetMeta(o),c=r||i.data;if(wn([a,e.options.indexAxis])==="y"||!l.controller.supportsDecimation)return;const u=e.scales[l.xAxisID];if(u.type!=="linear"&&u.type!=="time"||e.options.parsing)return;let{start:h,count:d}=qx(l,c);const f=s.threshold||4*n;if(d<=f){Fh(i);return}it(r)&&(i._data=c,delete i.data,Object.defineProperty(i,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(g){this._data=g}}));let p;switch(s.algorithm){case"lttb":p=zx(c,h,d,n,s);break;case"min-max":p=Wx(c,h,d,n);break;default:throw new Error(`Unsupported decimation algorithm '${s.algorithm}'`)}i._decimated=p})},destroy(e){zl(e)}};function Kx(e,t,s){const n=e.segments,i=e.points,o=t.points,r=[];for(const a of n){let{start:l,end:c}=a;c=ho(l,c,i);const u=hr(s,i[l],i[c],a.loop);if(!t.segments){r.push({source:a,target:u,start:i[l],end:i[c]});continue}const h=mh(t,u);for(const d of h){const f=hr(s,o[d.start],o[d.end],d.loop),p=gh(a,i,f);for(const g of p)r.push({source:g,target:d,start:{[s]:Wl(u,f,"start",Math.max)},end:{[s]:Wl(u,f,"end",Math.min)}})}}return r}function hr(e,t,s,n){if(n)return;let i=t[e],o=s[e];return e==="angle"&&(i=Ht(i),o=Ht(o)),{property:e,start:i,end:o}}function Gx(e,t){const{x:s=null,y:n=null}=e||{},i=t.points,o=[];return t.segments.forEach(({start:r,end:a})=>{a=ho(r,a,i);const l=i[r],c=i[a];n!==null?(o.push({x:l.x,y:n}),o.push({x:c.x,y:n})):s!==null&&(o.push({x:s,y:l.y}),o.push({x:s,y:c.y}))}),o}function ho(e,t,s){for(;t>e;t--){const n=s[t];if(!isNaN(n.x)&&!isNaN(n.y))break}return t}function Wl(e,t,s,n){return e&&t?n(e[s],t[s]):e?e[s]:t?t[s]:0}function Nh(e,t){let s=[],n=!1;return At(e)?(n=!0,s=e):s=Gx(e,t),s.length?new uo({points:s,options:{tension:0},_loop:n,_fullLoop:n}):null}function ql(e){return e&&e.fill!==!1}function Yx(e,t,s){let i=e[t].fill;const o=[t];let r;if(!s)return i;for(;i!==!1&&o.indexOf(i)===-1;){if(!Tt(i))return i;if(r=e[i],!r)return!1;if(r.visible)return i;o.push(i),i=r.fill}return!1}function Xx(e,t,s){const n=tv(e);if(ot(n))return isNaN(n.value)?!1:n;let i=parseFloat(n);return Tt(i)&&Math.floor(i)===i?Jx(n[0],t,i,s):["origin","start","end","stack","shape"].indexOf(n)>=0&&n}function Jx(e,t,s,n){return(e==="-"||e==="+")&&(s=t+s),s===t||s<0||s>=n?!1:s}function Qx(e,t){let s=null;return e==="start"?s=t.bottom:e==="end"?s=t.top:ot(e)?s=t.getPixelForValue(e.value):t.getBasePixel&&(s=t.getBasePixel()),s}function Zx(e,t,s){let n;return e==="start"?n=s:e==="end"?n=t.options.reverse?t.min:t.max:ot(e)?n=e.value:n=t.getBaseValue(),n}function tv(e){const t=e.options,s=t.fill;let n=Z(s&&s.target,s);return n===void 0&&(n=!!t.backgroundColor),n===!1||n===null?!1:n===!0?"origin":n}function ev(e){const{scale:t,index:s,line:n}=e,i=[],o=n.segments,r=n.points,a=sv(t,s);a.push(Nh({x:null,y:t.bottom},n));for(let l=0;l=0;--r){const a=i[r].$filler;a&&(a.line.updateControlPoints(o,a.axis),n&&a.fill&&Bo(e.ctx,a,o))}},beforeDatasetsDraw(e,t,s){if(s.drawTime!=="beforeDatasetsDraw")return;const n=e.getSortedVisibleDatasetMetas();for(let i=n.length-1;i>=0;--i){const o=n[i].$filler;ql(o)&&Bo(e.ctx,o,e.chartArea)}},beforeDatasetDraw(e,t,s){const n=t.meta.$filler;!ql(n)||s.drawTime!=="beforeDatasetDraw"||Bo(e.ctx,n,e.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}};const Yl=(e,t)=>{let{boxHeight:s=t,boxWidth:n=t}=e;return e.usePointStyle&&(s=Math.min(s,t),n=e.pointStyleWidth||Math.min(n,t)),{boxWidth:n,boxHeight:s,itemHeight:Math.max(t,s)}},fv=(e,t)=>e!==null&&t!==null&&e.datasetIndex===t.datasetIndex&&e.index===t.index;class Xl extends is{constructor(t){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,s,n){this.maxWidth=t,this.maxHeight=s,this._margins=n,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const t=this.options.labels||{};let s=St(t.generateLabels,[this.chart],this)||[];t.filter&&(s=s.filter(n=>t.filter(n,this.chart.data))),t.sort&&(s=s.sort((n,i)=>t.sort(n,i,this.chart.data))),this.options.reverse&&s.reverse(),this.legendItems=s}fit(){const{options:t,ctx:s}=this;if(!t.display){this.width=this.height=0;return}const n=t.labels,i=Nt(n.font),o=i.size,r=this._computeTitleHeight(),{boxWidth:a,itemHeight:l}=Yl(n,o);let c,u;s.font=i.string,this.isHorizontal()?(c=this.maxWidth,u=this._fitRows(r,o,a,l)+10):(u=this.maxHeight,c=this._fitCols(r,i,a,l)+10),this.width=Math.min(c,t.maxWidth||this.maxWidth),this.height=Math.min(u,t.maxHeight||this.maxHeight)}_fitRows(t,s,n,i){const{ctx:o,maxWidth:r,options:{labels:{padding:a}}}=this,l=this.legendHitBoxes=[],c=this.lineWidths=[0],u=i+a;let h=t;o.textAlign="left",o.textBaseline="middle";let d=-1,f=-u;return this.legendItems.forEach((p,g)=>{const _=n+s/2+o.measureText(p.text).width;(g===0||c[c.length-1]+_+2*a>r)&&(h+=u,c[c.length-(g>0?0:1)]=0,f+=u,d++),l[g]={left:0,top:f,row:d,width:_,height:i},c[c.length-1]+=_+a}),h}_fitCols(t,s,n,i){const{ctx:o,maxHeight:r,options:{labels:{padding:a}}}=this,l=this.legendHitBoxes=[],c=this.columnSizes=[],u=r-t;let h=a,d=0,f=0,p=0,g=0;return this.legendItems.forEach((_,b)=>{const{itemWidth:v,itemHeight:M}=pv(n,s,o,_,i);b>0&&f+M+2*a>u&&(h+=d+a,c.push({width:d,height:f}),p+=d+a,g++,d=f=0),l[b]={left:p,top:f,col:g,width:v,height:M},d=Math.max(d,v),f+=M+a}),h+=d,c.push({width:d,height:f}),h}adjustHitBoxes(){if(!this.options.display)return;const t=this._computeTitleHeight(),{legendHitBoxes:s,options:{align:n,labels:{padding:i},rtl:o}}=this,r=Qs(o,this.left,this.width);if(this.isHorizontal()){let a=0,l=jt(n,this.left+i,this.right-this.lineWidths[a]);for(const c of s)a!==c.row&&(a=c.row,l=jt(n,this.left+i,this.right-this.lineWidths[a])),c.top+=this.top+t+i,c.left=r.leftForLtr(r.x(l),c.width),l+=c.width+i}else{let a=0,l=jt(n,this.top+t+i,this.bottom-this.columnSizes[a].height);for(const c of s)c.col!==a&&(a=c.col,l=jt(n,this.top+t+i,this.bottom-this.columnSizes[a].height)),c.top=l,c.left+=this.left+i,c.left=r.leftForLtr(r.x(c.left),c.width),l+=c.height+i}}isHorizontal(){return this.options.position==="top"||this.options.position==="bottom"}draw(){if(this.options.display){const t=this.ctx;ro(t,this),this._draw(),ao(t)}}_draw(){const{options:t,columnSizes:s,lineWidths:n,ctx:i}=this,{align:o,labels:r}=t,a=Rt.color,l=Qs(t.rtl,this.left,this.width),c=Nt(r.font),{padding:u}=r,h=c.size,d=h/2;let f;this.drawTitle(),i.textAlign=l.textAlign("left"),i.textBaseline="middle",i.lineWidth=.5,i.font=c.string;const{boxWidth:p,boxHeight:g,itemHeight:_}=Yl(r,h),b=function(R,k,P){if(isNaN(p)||p<=0||isNaN(g)||g<0)return;i.save();const C=Z(P.lineWidth,1);if(i.fillStyle=Z(P.fillStyle,a),i.lineCap=Z(P.lineCap,"butt"),i.lineDashOffset=Z(P.lineDashOffset,0),i.lineJoin=Z(P.lineJoin,"miter"),i.lineWidth=C,i.strokeStyle=Z(P.strokeStyle,a),i.setLineDash(Z(P.lineDash,[])),r.usePointStyle){const O={radius:g*Math.SQRT2/2,pointStyle:P.pointStyle,rotation:P.rotation,borderWidth:C},B=l.xPlus(R,p/2),U=k+d;ih(i,O,B,U,r.pointStyleWidth&&p)}else{const O=k+Math.max((h-g)/2,0),B=l.leftForLtr(R,p),U=Fs(P.borderRadius);i.beginPath(),Object.values(U).some(at=>at!==0)?Kn(i,{x:B,y:O,w:p,h:g,radius:U}):i.rect(B,O,p,g),i.fill(),C!==0&&i.stroke()}i.restore()},v=function(R,k,P){Vs(i,P.text,R,k+_/2,c,{strikethrough:P.hidden,textAlign:l.textAlign(P.textAlign)})},M=this.isHorizontal(),S=this._computeTitleHeight();M?f={x:jt(o,this.left+u,this.right-n[0]),y:this.top+u+S,line:0}:f={x:this.left+u,y:jt(o,this.top+S+u,this.bottom-s[0].height),line:0},dh(this.ctx,t.textDirection);const w=_+u;this.legendItems.forEach((R,k)=>{i.strokeStyle=R.fontColor,i.fillStyle=R.fontColor;const P=i.measureText(R.text).width,C=l.textAlign(R.textAlign||(R.textAlign=r.textAlign)),O=p+d+P;let B=f.x,U=f.y;l.setWidth(this.width),M?k>0&&B+O+u>this.right&&(U=f.y+=w,f.line++,B=f.x=jt(o,this.left+u,this.right-n[f.line])):k>0&&U+w>this.bottom&&(B=f.x=B+s[f.line].width+u,f.line++,U=f.y=jt(o,this.top+S+u,this.bottom-s[f.line].height));const at=l.x(B);if(b(at,U,R),B=k_(C,B+p+d,M?B+O:this.right,t.rtl),v(l.x(B),U,R),M)f.x+=O+u;else if(typeof R.text!="string"){const Ct=c.lineHeight;f.y+=$h(R,Ct)+u}else f.y+=w}),fh(this.ctx,t.textDirection)}drawTitle(){const t=this.options,s=t.title,n=Nt(s.font),i=Yt(s.padding);if(!s.display)return;const o=Qs(t.rtl,this.left,this.width),r=this.ctx,a=s.position,l=n.size/2,c=i.top+l;let u,h=this.left,d=this.width;if(this.isHorizontal())d=Math.max(...this.lineWidths),u=this.top+c,h=jt(t.align,h,this.right-d);else{const p=this.columnSizes.reduce((g,_)=>Math.max(g,_.height),0);u=c+jt(t.align,this.top,this.bottom-p-t.labels.padding-this._computeTitleHeight())}const f=jt(a,h,h+d);r.textAlign=o.textAlign(Wr(a)),r.textBaseline="middle",r.strokeStyle=s.color,r.fillStyle=s.color,r.font=n.string,Vs(r,s.text,f,u,n)}_computeTitleHeight(){const t=this.options.title,s=Nt(t.font),n=Yt(t.padding);return t.display?s.lineHeight+n.height:0}_getLegendItemAt(t,s){let n,i,o;if(Ge(t,this.left,this.right)&&Ge(s,this.top,this.bottom)){for(o=this.legendHitBoxes,n=0;no.length>r.length?o:r)),t+s.size/2+n.measureText(i).width}function mv(e,t,s){let n=e;return typeof t.text!="string"&&(n=$h(t,s)),n}function $h(e,t){const s=e.text?e.text.length:0;return t*s}function bv(e,t){return!!((e==="mousemove"||e==="mouseout")&&(t.onHover||t.onLeave)||t.onClick&&(e==="click"||e==="mouseup"))}var _v={id:"legend",_element:Xl,start(e,t,s){const n=e.legend=new Xl({ctx:e.ctx,options:s,chart:e});Ut.configure(e,n,s),Ut.addBox(e,n)},stop(e){Ut.removeBox(e,e.legend),delete e.legend},beforeUpdate(e,t,s){const n=e.legend;Ut.configure(e,n,s),n.options=s},afterUpdate(e){const t=e.legend;t.buildLabels(),t.adjustHitBoxes()},afterEvent(e,t){t.replay||e.legend.handleEvent(t.event)},defaults:{display:!0,position:"top",align:"center",fullSize:!0,reverse:!1,weight:1e3,onClick(e,t,s){const n=t.datasetIndex,i=s.chart;i.isDatasetVisible(n)?(i.hide(n),t.hidden=!0):(i.show(n),t.hidden=!1)},onHover:null,onLeave:null,labels:{color:e=>e.chart.options.color,boxWidth:40,padding:10,generateLabels(e){const t=e.data.datasets,{labels:{usePointStyle:s,pointStyle:n,textAlign:i,color:o,useBorderRadius:r,borderRadius:a}}=e.legend.options;return e._getSortedDatasetMetas().map(l=>{const c=l.controller.getStyle(s?0:void 0),u=Yt(c.borderWidth);return{text:t[l.index].label,fillStyle:c.backgroundColor,fontColor:o,hidden:!l.visible,lineCap:c.borderCapStyle,lineDash:c.borderDash,lineDashOffset:c.borderDashOffset,lineJoin:c.borderJoinStyle,lineWidth:(u.width+u.height)/4,strokeStyle:c.borderColor,pointStyle:n||c.pointStyle,rotation:c.rotation,textAlign:i||c.textAlign,borderRadius:r&&(a||c.borderRadius),datasetIndex:l.index}},this)}},title:{color:e=>e.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:e=>!e.startsWith("on"),labels:{_scriptable:e=>!["generateLabels","filter","sort"].includes(e)}}};class ta extends is{constructor(t){super(),this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,s){const n=this.options;if(this.left=0,this.top=0,!n.display){this.width=this.height=this.right=this.bottom=0;return}this.width=this.right=t,this.height=this.bottom=s;const i=At(n.text)?n.text.length:1;this._padding=Yt(n.padding);const o=i*Nt(n.font).lineHeight+this._padding.height;this.isHorizontal()?this.height=o:this.width=o}isHorizontal(){const t=this.options.position;return t==="top"||t==="bottom"}_drawArgs(t){const{top:s,left:n,bottom:i,right:o,options:r}=this,a=r.align;let l=0,c,u,h;return this.isHorizontal()?(u=jt(a,n,o),h=s+t,c=o-n):(r.position==="left"?(u=n+t,h=jt(a,i,s),l=ht*-.5):(u=o-t,h=jt(a,s,i),l=ht*.5),c=i-s),{titleX:u,titleY:h,maxWidth:c,rotation:l}}draw(){const t=this.ctx,s=this.options;if(!s.display)return;const n=Nt(s.font),o=n.lineHeight/2+this._padding.top,{titleX:r,titleY:a,maxWidth:l,rotation:c}=this._drawArgs(o);Vs(t,s.text,0,0,n,{color:s.color,maxWidth:l,rotation:c,textAlign:Wr(s.align),textBaseline:"middle",translation:[r,a]})}}function yv(e,t){const s=new ta({ctx:e.ctx,options:t,chart:e});Ut.configure(e,s,t),Ut.addBox(e,s),e.titleBlock=s}var xv={id:"title",_element:ta,start(e,t,s){yv(e,s)},stop(e){const t=e.titleBlock;Ut.removeBox(e,t),delete e.titleBlock},beforeUpdate(e,t,s){const n=e.titleBlock;Ut.configure(e,n,s),n.options=s},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const _i=new WeakMap;var vv={id:"subtitle",start(e,t,s){const n=new ta({ctx:e.ctx,options:s,chart:e});Ut.configure(e,n,s),Ut.addBox(e,n),_i.set(e,n)},stop(e){Ut.removeBox(e,_i.get(e)),_i.delete(e)},beforeUpdate(e,t,s){const n=_i.get(e);Ut.configure(e,n,s),n.options=s},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const kn={average(e){if(!e.length)return!1;let t,s,n=new Set,i=0,o=0;for(t=0,s=e.length;ta+l)/n.size,y:i/o}},nearest(e,t){if(!e.length)return!1;let s=t.x,n=t.y,i=Number.POSITIVE_INFINITY,o,r,a;for(o=0,r=e.length;o-1?e.split(` `):e}function wv(e,t){const{element:s,datasetIndex:n,index:i}=t,o=e.getDatasetMeta(n).controller,{label:r,value:a}=o.getLabelAndValue(i);return{chart:e,label:r,parsed:o.getParsed(i),raw:e.data.datasets[n].data[i],formattedValue:a,dataset:o.getDataset(),dataIndex:i,datasetIndex:n,element:s}}function Jl(e,t){const s=e.chart.ctx,{body:n,footer:i,title:o}=e,{boxWidth:r,boxHeight:a}=t,l=Nt(t.bodyFont),c=Nt(t.titleFont),u=Nt(t.footerFont),h=o.length,d=i.length,f=n.length,p=Yt(t.padding);let g=p.height,_=0,b=n.reduce((S,w)=>S+w.before.length+w.lines.length+w.after.length,0);if(b+=e.beforeBody.length+e.afterBody.length,h&&(g+=h*c.lineHeight+(h-1)*t.titleSpacing+t.titleMarginBottom),b){const S=t.displayColors?Math.max(a,l.lineHeight):l.lineHeight;g+=f*S+(b-f)*l.lineHeight+(b-1)*t.bodySpacing}d&&(g+=t.footerMarginTop+d*u.lineHeight+(d-1)*t.footerSpacing);let v=0;const M=function(S){_=Math.max(_,s.measureText(S).width+v)};return s.save(),s.font=c.string,bt(e.title,M),s.font=l.string,bt(e.beforeBody.concat(e.afterBody),M),v=t.displayColors?r+2+t.boxPadding:0,bt(n,S=>{bt(S.before,M),bt(S.lines,M),bt(S.after,M)}),v=0,s.font=u.string,bt(e.footer,M),s.restore(),_+=p.width,{width:_,height:g}}function Sv(e,t){const{y:s,height:n}=t;return se.height-n/2?"bottom":"center"}function kv(e,t,s,n){const{x:i,width:o}=n,r=s.caretSize+s.caretPadding;if(e==="left"&&i+o+r>t.width||e==="right"&&i-o-r<0)return!0}function Mv(e,t,s,n){const{x:i,width:o}=s,{width:r,chartArea:{left:a,right:l}}=e;let c="center";return n==="center"?c=i<=(a+l)/2?"left":"right":i<=o/2?c="left":i>=r-o/2&&(c="right"),kv(c,e,t,s)&&(c="center"),c}function Ql(e,t,s){const n=s.yAlign||t.yAlign||Sv(e,s);return{xAlign:s.xAlign||t.xAlign||Mv(e,t,s,n),yAlign:n}}function Cv(e,t){let{x:s,width:n}=e;return t==="right"?s-=n:t==="center"&&(s-=n/2),s}function Pv(e,t,s){let{y:n,height:i}=e;return t==="top"?n+=s:t==="bottom"?n-=i+s:n-=i/2,n}function Zl(e,t,s,n){const{caretSize:i,caretPadding:o,cornerRadius:r}=e,{xAlign:a,yAlign:l}=s,c=i+o,{topLeft:u,topRight:h,bottomLeft:d,bottomRight:f}=Fs(r);let p=Cv(t,a);const g=Pv(t,l,c);return l==="center"?a==="left"?p+=c:a==="right"&&(p-=c):a==="left"?p-=Math.max(u,d)+i:a==="right"&&(p+=Math.max(h,f)+i),{x:Bt(p,0,n.width-t.width),y:Bt(g,0,n.height-t.height)}}function yi(e,t,s){const n=Yt(s.padding);return t==="center"?e.x+e.width/2:t==="right"?e.x+e.width-n.right:e.x+n.left}function tc(e){return Oe([],He(e))}function Av(e,t,s){return xs(e,{tooltip:t,tooltipItems:s,type:"tooltip"})}function ec(e,t){const s=t&&t.dataset&&t.dataset.tooltip&&t.dataset.tooltip.callbacks;return s?e.override(s):e}const Vh={beforeTitle:$e,title(e){if(e.length>0){const t=e[0],s=t.chart.data.labels,n=s?s.length:0;if(this&&this.options&&this.options.mode==="dataset")return t.dataset.label||"";if(t.label)return t.label;if(n>0&&t.dataIndex"u"?Vh[t].call(s,n):i}class sc extends is{static positioners=kn;constructor(t){super(),this.opacity=0,this._active=[],this._eventPosition=void 0,this._size=void 0,this._cachedAnimations=void 0,this._tooltipItems=[],this.$animations=void 0,this.$context=void 0,this.chart=t.chart,this.options=t.options,this.dataPoints=void 0,this.title=void 0,this.beforeBody=void 0,this.body=void 0,this.afterBody=void 0,this.footer=void 0,this.xAlign=void 0,this.yAlign=void 0,this.x=void 0,this.y=void 0,this.height=void 0,this.width=void 0,this.caretX=void 0,this.caretY=void 0,this.labelColors=void 0,this.labelPointStyles=void 0,this.labelTextColors=void 0}initialize(t){this.options=t,this._cachedAnimations=void 0,this.$context=void 0}_resolveAnimations(){const t=this._cachedAnimations;if(t)return t;const s=this.chart,n=this.options.setContext(this.getContext()),i=n.enabled&&s.options.animation&&n.animations,o=new _h(this.chart,i);return i._cacheable&&(this._cachedAnimations=Object.freeze(o)),o}getContext(){return this.$context||(this.$context=Av(this.chart.getContext(),this,this._tooltipItems))}getTitle(t,s){const{callbacks:n}=s,i=ae(n,"beforeTitle",this,t),o=ae(n,"title",this,t),r=ae(n,"afterTitle",this,t);let a=[];return a=Oe(a,He(i)),a=Oe(a,He(o)),a=Oe(a,He(r)),a}getBeforeBody(t,s){return tc(ae(s.callbacks,"beforeBody",this,t))}getBody(t,s){const{callbacks:n}=s,i=[];return bt(t,o=>{const r={before:[],lines:[],after:[]},a=ec(n,o);Oe(r.before,He(ae(a,"beforeLabel",this,o))),Oe(r.lines,ae(a,"label",this,o)),Oe(r.after,He(ae(a,"afterLabel",this,o))),i.push(r)}),i}getAfterBody(t,s){return tc(ae(s.callbacks,"afterBody",this,t))}getFooter(t,s){const{callbacks:n}=s,i=ae(n,"beforeFooter",this,t),o=ae(n,"footer",this,t),r=ae(n,"afterFooter",this,t);let a=[];return a=Oe(a,He(i)),a=Oe(a,He(o)),a=Oe(a,He(r)),a}_createItems(t){const s=this._active,n=this.chart.data,i=[],o=[],r=[];let a=[],l,c;for(l=0,c=s.length;lt.filter(u,h,d,n))),t.itemSort&&(a=a.sort((u,h)=>t.itemSort(u,h,n))),bt(a,u=>{const h=ec(t.callbacks,u);i.push(ae(h,"labelColor",this,u)),o.push(ae(h,"labelPointStyle",this,u)),r.push(ae(h,"labelTextColor",this,u))}),this.labelColors=i,this.labelPointStyles=o,this.labelTextColors=r,this.dataPoints=a,a}update(t,s){const n=this.options.setContext(this.getContext()),i=this._active;let o,r=[];if(!i.length)this.opacity!==0&&(o={opacity:0});else{const a=kn[n.position].call(this,i,this._eventPosition);r=this._createItems(n),this.title=this.getTitle(r,n),this.beforeBody=this.getBeforeBody(r,n),this.body=this.getBody(r,n),this.afterBody=this.getAfterBody(r,n),this.footer=this.getFooter(r,n);const l=this._size=Jl(this,n),c=Object.assign({},a,l),u=Ql(this.chart,n,c),h=Zl(n,c,u,this.chart);this.xAlign=u.xAlign,this.yAlign=u.yAlign,o={opacity:1,x:h.x,y:h.y,width:l.width,height:l.height,caretX:a.x,caretY:a.y}}this._tooltipItems=r,this.$context=void 0,o&&this._resolveAnimations().update(this,o),t&&n.external&&n.external.call(this,{chart:this.chart,tooltip:this,replay:s})}drawCaret(t,s,n,i){const o=this.getCaretPosition(t,n,i);s.lineTo(o.x1,o.y1),s.lineTo(o.x2,o.y2),s.lineTo(o.x3,o.y3)}getCaretPosition(t,s,n){const{xAlign:i,yAlign:o}=this,{caretSize:r,cornerRadius:a}=n,{topLeft:l,topRight:c,bottomLeft:u,bottomRight:h}=Fs(a),{x:d,y:f}=t,{width:p,height:g}=s;let _,b,v,M,S,w;return o==="center"?(S=f+g/2,i==="left"?(_=d,b=_-r,M=S+r,w=S-r):(_=d+p,b=_+r,M=S-r,w=S+r),v=_):(i==="left"?b=d+Math.max(l,u)+r:i==="right"?b=d+p-Math.max(c,h)-r:b=this.caretX,o==="top"?(M=f,S=M-r,_=b-r,v=b+r):(M=f+g,S=M+r,_=b+r,v=b-r),w=M),{x1:_,x2:b,x3:v,y1:M,y2:S,y3:w}}drawTitle(t,s,n){const i=this.title,o=i.length;let r,a,l;if(o){const c=Qs(n.rtl,this.x,this.width);for(t.x=yi(this,n.titleAlign,n),s.textAlign=c.textAlign(n.titleAlign),s.textBaseline="middle",r=Nt(n.titleFont),a=n.titleSpacing,s.fillStyle=n.titleColor,s.font=r.string,l=0;lv!==0)?(t.beginPath(),t.fillStyle=o.multiKeyBackground,Kn(t,{x:g,y:p,w:c,h:l,radius:b}),t.fill(),t.stroke(),t.fillStyle=r.backgroundColor,t.beginPath(),Kn(t,{x:_,y:p+1,w:c-2,h:l-2,radius:b}),t.fill()):(t.fillStyle=o.multiKeyBackground,t.fillRect(g,p,c,l),t.strokeRect(g,p,c,l),t.fillStyle=r.backgroundColor,t.fillRect(_,p+1,c-2,l-2))}t.fillStyle=this.labelTextColors[n]}drawBody(t,s,n){const{body:i}=this,{bodySpacing:o,bodyAlign:r,displayColors:a,boxHeight:l,boxWidth:c,boxPadding:u}=n,h=Nt(n.bodyFont);let d=h.lineHeight,f=0;const p=Qs(n.rtl,this.x,this.width),g=function(P){s.fillText(P,p.x(t.x+f),t.y+d/2),t.y+=d+o},_=p.textAlign(r);let b,v,M,S,w,R,k;for(s.textAlign=r,s.textBaseline="middle",s.font=h.string,t.x=yi(this,_,n),s.fillStyle=n.bodyColor,bt(this.beforeBody,g),f=a&&_!=="right"?r==="center"?c/2+u:c+2+u:0,S=0,R=i.length;S0&&s.stroke()}_updateAnimationTarget(t){const s=this.chart,n=this.$animations,i=n&&n.x,o=n&&n.y;if(i||o){const r=kn[t.position].call(this,this._active,this._eventPosition);if(!r)return;const a=this._size=Jl(this,t),l=Object.assign({},r,this._size),c=Ql(s,t,l),u=Zl(t,l,c,s);(i._to!==u.x||o._to!==u.y)&&(this.xAlign=c.xAlign,this.yAlign=c.yAlign,this.width=a.width,this.height=a.height,this.caretX=r.x,this.caretY=r.y,this._resolveAnimations().update(this,u))}}_willRender(){return!!this.opacity}draw(t){const s=this.options.setContext(this.getContext());let n=this.opacity;if(!n)return;this._updateAnimationTarget(s);const i={width:this.width,height:this.height},o={x:this.x,y:this.y};n=Math.abs(n)<.001?0:n;const r=Yt(s.padding),a=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;s.enabled&&a&&(t.save(),t.globalAlpha=n,this.drawBackground(o,t,i,s),dh(t,s.textDirection),o.y+=r.top,this.drawTitle(o,t,s),this.drawBody(o,t,s),this.drawFooter(o,t,s),fh(t,s.textDirection),t.restore())}getActiveElements(){return this._active||[]}setActiveElements(t,s){const n=this._active,i=t.map(({datasetIndex:a,index:l})=>{const c=this.chart.getDatasetMeta(a);if(!c)throw new Error("Cannot find a dataset at index "+a);return{datasetIndex:a,element:c.data[l],index:l}}),o=!Ni(n,i),r=this._positionChanged(i,s);(o||r)&&(this._active=i,this._eventPosition=s,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(t,s,n=!0){if(s&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;const i=this.options,o=this._active||[],r=this._getActiveElements(t,o,s,n),a=this._positionChanged(r,t),l=s||!Ni(r,o)||a;return l&&(this._active=r,(i.enabled||i.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,s))),l}_getActiveElements(t,s,n,i){const o=this.options;if(t.type==="mouseout")return[];if(!i)return s.filter(a=>this.chart.data.datasets[a.datasetIndex]&&this.chart.getDatasetMeta(a.datasetIndex).controller.getParsed(a.index)!==void 0);const r=this.chart.getElementsAtEventForMode(t,o.mode,o,n);return o.reverse&&r.reverse(),r}_positionChanged(t,s){const{caretX:n,caretY:i,options:o}=this,r=kn[o.position].call(this,t,s);return r!==!1&&(n!==r.x||i!==r.y)}}var Rv={id:"tooltip",_element:sc,positioners:kn,afterInit(e,t,s){s&&(e.tooltip=new sc({chart:e,options:s}))},beforeUpdate(e,t,s){e.tooltip&&e.tooltip.initialize(s)},reset(e,t,s){e.tooltip&&e.tooltip.initialize(s)},afterDraw(e){const t=e.tooltip;if(t&&t._willRender()){const s={tooltip:t};if(e.notifyPlugins("beforeTooltipDraw",{...s,cancelable:!0})===!1)return;t.draw(e.ctx),e.notifyPlugins("afterTooltipDraw",s)}},afterEvent(e,t){if(e.tooltip){const s=t.replay;e.tooltip.handleEvent(t.event,s,t.inChartArea)&&(t.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(e,t)=>t.bodyFont.size,boxWidth:(e,t)=>t.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:Vh},defaultRoutes:{bodyFont:"font",footerFont:"font",titleFont:"font"},descriptors:{_scriptable:e=>e!=="filter"&&e!=="itemSort"&&e!=="external",_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]},Ov=Object.freeze({__proto__:null,Colors:Hx,Decimation:Ux,Filler:dv,Legend:_v,SubTitle:vv,Title:xv,Tooltip:Rv});const Tv=(e,t,s,n)=>(typeof t=="string"?(s=e.push(t)-1,n.unshift({index:s,label:t})):isNaN(t)&&(s=null),s);function Ev(e,t,s,n){const i=e.indexOf(t);if(i===-1)return Tv(e,t,s,n);const o=e.lastIndexOf(t);return i!==o?s:i}const Dv=(e,t)=>e===null?null:Bt(Math.round(e),0,t);function nc(e){const t=this.getLabels();return e>=0&&es.length-1?null:this.getPixelForValue(s[t].value)}getValueForPixel(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}getBasePixel(){return this.bottom}}function Lv(e,t){const s=[],{bounds:i,step:o,min:r,max:a,precision:l,count:c,maxTicks:u,maxDigits:h,includeBounds:d}=e,f=o||1,p=u-1,{min:g,max:_}=t,b=!it(r),v=!it(a),M=!it(c),S=(_-g)/(h+1);let w=Ja((_-g)/p/f)*f,R,k,P,C;if(w<1e-14&&!b&&!v)return[{value:g},{value:_}];C=Math.ceil(_/w)-Math.floor(g/w),C>p&&(w=Ja(C*w/p/f)*f),it(l)||(R=Math.pow(10,l),w=Math.ceil(w*R)/R),i==="ticks"?(k=Math.floor(g/w)*w,P=Math.ceil(_/w)*w):(k=g,P=_),b&&v&&o&&b_((a-r)/o,w/1e3)?(C=Math.round(Math.min((a-r)/w,u)),w=(a-r)/C,k=r,P=a):M?(k=b?r:k,P=v?a:P,C=c-1,w=(P-k)/C):(C=(P-k)/w,Dn(C,Math.round(C),w/1e3)?C=Math.round(C):C=Math.ceil(C));const O=Math.max(Qa(w),Qa(k));R=Math.pow(10,it(l)?O:l),k=Math.round(k*R)/R,P=Math.round(P*R)/R;let B=0;for(b&&(d&&k!==r?(s.push({value:r}),ka)break;s.push({value:U})}return v&&d&&P!==a?s.length&&Dn(s[s.length-1].value,a,ic(a,S,e))?s[s.length-1].value=a:s.push({value:a}):(!v||P===a)&&s.push({value:P}),s}function ic(e,t,{horizontal:s,minRotation:n}){const i=ve(n),o=(s?Math.sin(i):Math.cos(i))||.001,r=.75*t*(""+e).length;return Math.min(t/o,r)}class Wi extends js{constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._endValue=void 0,this._valueRange=0}parse(t,s){return it(t)||(typeof t=="number"||t instanceof Number)&&!isFinite(+t)?null:+t}handleTickRangeOptions(){const{beginAtZero:t}=this.options,{minDefined:s,maxDefined:n}=this.getUserBounds();let{min:i,max:o}=this;const r=l=>i=s?i:l,a=l=>o=n?o:l;if(t){const l=Fe(i),c=Fe(o);l<0&&c<0?a(0):l>0&&c>0&&r(0)}if(i===o){let l=o===0?1:Math.abs(o*.05);a(o+l),t||r(i-l)}this.min=i,this.max=o}getTickLimit(){const t=this.options.ticks;let{maxTicksLimit:s,stepSize:n}=t,i;return n?(i=Math.ceil(this.max/n)-Math.floor(this.min/n)+1,i>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${n} would result generating up to ${i} ticks. Limiting to 1000.`),i=1e3)):(i=this.computeTickLimit(),s=s||11),s&&(i=Math.min(s,i)),i}computeTickLimit(){return Number.POSITIVE_INFINITY}buildTicks(){const t=this.options,s=t.ticks;let n=this.getTickLimit();n=Math.max(2,n);const i={maxTicks:n,bounds:t.bounds,min:t.min,max:t.max,precision:s.precision,step:s.stepSize,count:s.count,maxDigits:this._maxDigits(),horizontal:this.isHorizontal(),minRotation:s.minRotation||0,includeBounds:s.includeBounds!==!1},o=this._range||this,r=Lv(i,o);return t.bounds==="ticks"&&Yu(r,this,"value"),t.reverse?(r.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),r}configure(){const t=this.ticks;let s=this.min,n=this.max;if(super.configure(),this.options.offset&&t.length){const i=(n-s)/Math.max(t.length-1,1)/2;s-=i,n+=i}this._startValue=s,this._endValue=n,this._valueRange=n-s}getLabelForValue(t){return ei(t,this.chart.options.locale,this.options.ticks.format)}}class Fv extends Wi{static id="linear";static defaults={ticks:{callback:oo.formatters.numeric}};determineDataLimits(){const{min:t,max:s}=this.getMinMax(!0);this.min=Tt(t)?t:0,this.max=Tt(s)?s:1,this.handleTickRangeOptions()}computeTickLimit(){const t=this.isHorizontal(),s=t?this.width:this.height,n=ve(this.options.ticks.minRotation),i=(t?Math.sin(n):Math.cos(n))||.001,o=this._resolveTickFontOptions(0);return Math.ceil(s/Math.min(40,o.lineHeight/i))}getPixelForValue(t){return t===null?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getValueForPixel(t){return this._startValue+this.getDecimalForPixel(t)*this._valueRange}}const Yn=e=>Math.floor(hs(e)),Ps=(e,t)=>Math.pow(10,Yn(e)+t);function oc(e){return e/Math.pow(10,Yn(e))===1}function rc(e,t,s){const n=Math.pow(10,s),i=Math.floor(e/n);return Math.ceil(t/n)-i}function Nv(e,t){const s=t-e;let n=Yn(s);for(;rc(e,t,n)>10;)n++;for(;rc(e,t,n)<10;)n--;return Math.min(n,Yn(e))}function Bv(e,{min:t,max:s}){t=de(e.min,t);const n=[],i=Yn(t);let o=Nv(t,s),r=o<0?Math.pow(10,Math.abs(o)):1;const a=Math.pow(10,o),l=i>o?Math.pow(10,i):0,c=Math.round((t-l)*r)/r,u=Math.floor((t-l)/a/10)*a*10;let h=Math.floor((c-u)/Math.pow(10,o)),d=de(e.min,Math.round((l+u+h*Math.pow(10,o))*r)/r);for(;d=10?h=h<15?15:20:h++,h>=20&&(o++,h=2,r=o>=0?1:r),d=Math.round((l+u+h*Math.pow(10,o))*r)/r;const f=de(e.max,d);return n.push({value:f,major:oc(f),significand:h}),n}class $v extends js{static id="logarithmic";static defaults={ticks:{callback:oo.formatters.logarithmic,major:{enabled:!0}}};constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._valueRange=0}parse(t,s){const n=Wi.prototype.parse.apply(this,[t,s]);if(n===0){this._zero=!0;return}return Tt(n)&&n>0?n:null}determineDataLimits(){const{min:t,max:s}=this.getMinMax(!0);this.min=Tt(t)?Math.max(0,t):null,this.max=Tt(s)?Math.max(0,s):null,this.options.beginAtZero&&(this._zero=!0),this._zero&&this.min!==this._suggestedMin&&!Tt(this._userMin)&&(this.min=t===Ps(this.min,0)?Ps(this.min,-1):Ps(this.min,0)),this.handleTickRangeOptions()}handleTickRangeOptions(){const{minDefined:t,maxDefined:s}=this.getUserBounds();let n=this.min,i=this.max;const o=a=>n=t?n:a,r=a=>i=s?i:a;n===i&&(n<=0?(o(1),r(10)):(o(Ps(n,-1)),r(Ps(i,1)))),n<=0&&o(Ps(i,-1)),i<=0&&r(Ps(n,1)),this.min=n,this.max=i}buildTicks(){const t=this.options,s={min:this._userMin,max:this._userMax},n=Bv(s,this);return t.bounds==="ticks"&&Yu(n,this,"value"),t.reverse?(n.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),n}getLabelForValue(t){return t===void 0?"0":ei(t,this.chart.options.locale,this.options.ticks.format)}configure(){const t=this.min;super.configure(),this._startValue=hs(t),this._valueRange=hs(this.max)-hs(t)}getPixelForValue(t){return(t===void 0||t===0)&&(t=this.min),t===null||isNaN(t)?NaN:this.getPixelForDecimal(t===this.min?0:(hs(t)-this._startValue)/this._valueRange)}getValueForPixel(t){const s=this.getDecimalForPixel(t);return Math.pow(10,this._startValue+s*this._valueRange)}}function dr(e){const t=e.ticks;if(t.display&&e.display){const s=Yt(t.backdropPadding);return Z(t.font&&t.font.size,Rt.font.size)+s.height}return 0}function Vv(e,t,s){return s=At(s)?s:[s],{w:I_(e,t.string,s),h:s.length*t.lineHeight}}function ac(e,t,s,n,i){return e===n||e===i?{start:t-s/2,end:t+s/2}:ei?{start:t-s,end:t}:{start:t,end:t+s}}function jv(e){const t={l:e.left+e._padding.left,r:e.right-e._padding.right,t:e.top+e._padding.top,b:e.bottom-e._padding.bottom},s=Object.assign({},t),n=[],i=[],o=e._pointLabels.length,r=e.options.pointLabels,a=r.centerPointLabels?ht/o:0;for(let l=0;lt.r&&(a=(n.end-t.r)/o,e.r=Math.max(e.r,t.r+a)),i.startt.b&&(l=(i.end-t.b)/r,e.b=Math.max(e.b,t.b+l))}function zv(e,t,s){const n=e.drawingArea,{extra:i,additionalAngle:o,padding:r,size:a}=s,l=e.getPointPosition(t,n+i+r,o),c=Math.round(Hr(Ht(l.angle+Dt))),u=Gv(l.y,a.h,c),h=Uv(c),d=Kv(l.x,a.w,h);return{visible:!0,x:l.x,y:u,textAlign:h,left:d,top:u,right:d+a.w,bottom:u+a.h}}function Wv(e,t){if(!t)return!0;const{left:s,top:n,right:i,bottom:o}=e;return!(Xe({x:s,y:n},t)||Xe({x:s,y:o},t)||Xe({x:i,y:n},t)||Xe({x:i,y:o},t))}function qv(e,t,s){const n=[],i=e._pointLabels.length,o=e.options,{centerPointLabels:r,display:a}=o.pointLabels,l={extra:dr(o)/2,additionalAngle:r?ht/i:0};let c;for(let u=0;u270||s<90)&&(e-=t),e}function Yv(e,t,s){const{left:n,top:i,right:o,bottom:r}=s,{backdropColor:a}=t;if(!it(a)){const l=Fs(t.borderRadius),c=Yt(t.backdropPadding);e.fillStyle=a;const u=n-c.left,h=i-c.top,d=o-n+c.width,f=r-i+c.height;Object.values(l).some(p=>p!==0)?(e.beginPath(),Kn(e,{x:u,y:h,w:d,h:f,radius:l}),e.fill()):e.fillRect(u,h,d,f)}}function Xv(e,t){const{ctx:s,options:{pointLabels:n}}=e;for(let i=t-1;i>=0;i--){const o=e._pointLabelItems[i];if(!o.visible)continue;const r=n.setContext(e.getPointLabelContext(i));Yv(s,r,o);const a=Nt(r.font),{x:l,y:c,textAlign:u}=o;Vs(s,e._pointLabels[i],l,c+a.lineHeight/2,a,{color:r.color,textAlign:u,textBaseline:"middle"})}}function jh(e,t,s,n){const{ctx:i}=e;if(s)i.arc(e.xCenter,e.yCenter,t,0,Mt);else{let o=e.getPointPosition(0,t);i.moveTo(o.x,o.y);for(let r=1;r{const i=St(this.options.pointLabels.callback,[s,n],this);return i||i===0?i:""}).filter((s,n)=>this.chart.getDataVisibility(n))}fit(){const t=this.options;t.display&&t.pointLabels.display?jv(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(t,s,n,i){this.xCenter+=Math.floor((t-s)/2),this.yCenter+=Math.floor((n-i)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,s,n,i))}getIndexAngle(t){const s=Mt/(this._pointLabels.length||1),n=this.options.startAngle||0;return Ht(t*s+ve(n))}getDistanceFromCenterForValue(t){if(it(t))return NaN;const s=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*s:(t-this.min)*s}getValueForDistanceFromCenter(t){if(it(t))return NaN;const s=t/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-s:this.min+s}getPointLabelContext(t){const s=this._pointLabels||[];if(t>=0&&t{if(h!==0||h===0&&this.min<0){l=this.getDistanceFromCenterForValue(u.value);const d=this.getContext(h),f=i.setContext(d),p=o.setContext(d);Jv(this,f,l,r,p)}}),n.display){for(t.save(),a=r-1;a>=0;a--){const u=n.setContext(this.getPointLabelContext(a)),{color:h,lineWidth:d}=u;!d||!h||(t.lineWidth=d,t.strokeStyle=h,t.setLineDash(u.borderDash),t.lineDashOffset=u.borderDashOffset,l=this.getDistanceFromCenterForValue(s.reverse?this.min:this.max),c=this.getPointPosition(a,l),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(c.x,c.y),t.stroke())}t.restore()}}drawBorder(){}drawLabels(){const t=this.ctx,s=this.options,n=s.ticks;if(!n.display)return;const i=this.getIndexAngle(0);let o,r;t.save(),t.translate(this.xCenter,this.yCenter),t.rotate(i),t.textAlign="center",t.textBaseline="middle",this.ticks.forEach((a,l)=>{if(l===0&&this.min>=0&&!s.reverse)return;const c=n.setContext(this.getContext(l)),u=Nt(c.font);if(o=this.getDistanceFromCenterForValue(this.ticks[l].value),c.showLabelBackdrop){t.font=u.string,r=t.measureText(a.label).width,t.fillStyle=c.backdropColor;const h=Yt(c.backdropPadding);t.fillRect(-r/2-h.left,-o-u.size/2-h.top,r+h.width,u.size+h.height)}Vs(t,a.label,0,-o,u,{color:c.color,strokeColor:c.textStrokeColor,strokeWidth:c.textStrokeWidth})}),t.restore()}drawTitle(){}}const fo={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},ce=Object.keys(fo);function lc(e,t){return e-t}function cc(e,t){if(it(t))return null;const s=e._adapter,{parser:n,round:i,isoWeekday:o}=e._parseOpts;let r=t;return typeof n=="function"&&(r=n(r)),Tt(r)||(r=typeof n=="string"?s.parse(r,n):s.parse(r)),r===null?null:(i&&(r=i==="week"&&(nn(o)||o===!0)?s.startOf(r,"isoWeek",o):s.startOf(r,i)),+r)}function uc(e,t,s,n){const i=ce.length;for(let o=ce.indexOf(e);o=ce.indexOf(s);o--){const r=ce[o];if(fo[r].common&&e._adapter.diff(i,n,r)>=t-1)return r}return ce[s?ce.indexOf(s):0]}function e1(e){for(let t=ce.indexOf(e)+1,s=ce.length;t=t?s[n]:s[i];e[o]=!0}}function s1(e,t,s,n){const i=e._adapter,o=+i.startOf(t[0].value,n),r=t[t.length-1].value;let a,l;for(a=o;a<=r;a=+i.add(a,1,n))l=s[a],l>=0&&(t[l].major=!0);return t}function dc(e,t,s){const n=[],i={},o=t.length;let r,a;for(r=0;r+t.value))}initOffsets(t=[]){let s=0,n=0,i,o;this.options.offset&&t.length&&(i=this.getDecimalForValue(t[0]),t.length===1?s=1-i:s=(this.getDecimalForValue(t[1])-i)/2,o=this.getDecimalForValue(t[t.length-1]),t.length===1?n=o:n=(o-this.getDecimalForValue(t[t.length-2]))/2);const r=t.length<3?.5:.25;s=Bt(s,0,r),n=Bt(n,0,r),this._offsets={start:s,end:n,factor:1/(s+1+n)}}_generate(){const t=this._adapter,s=this.min,n=this.max,i=this.options,o=i.time,r=o.unit||uc(o.minUnit,s,n,this._getLabelCapacity(s)),a=Z(i.ticks.stepSize,1),l=r==="week"?o.isoWeekday:!1,c=nn(l)||l===!0,u={};let h=s,d,f;if(c&&(h=+t.startOf(h,"isoWeek",l)),h=+t.startOf(h,c?"day":r),t.diff(n,s,r)>1e5*a)throw new Error(s+" and "+n+" are too far apart with stepSize of "+a+" "+r);const p=i.ticks.source==="data"&&this.getDataTimestamps();for(d=h,f=0;d+g)}getLabelForValue(t){const s=this._adapter,n=this.options.time;return n.tooltipFormat?s.format(t,n.tooltipFormat):s.format(t,n.displayFormats.datetime)}format(t,s){const i=this.options.time.displayFormats,o=this._unit,r=s||i[o];return this._adapter.format(t,r)}_tickFormatFunction(t,s,n,i){const o=this.options,r=o.ticks.callback;if(r)return St(r,[t,s,n],this);const a=o.time.displayFormats,l=this._unit,c=this._majorUnit,u=l&&a[l],h=c&&a[c],d=n[s],f=c&&h&&d&&d.major;return this._adapter.format(t,i||(f?h:u))}generateTickLabels(t){let s,n,i;for(s=0,n=t.length;s0?a:1}getDataTimestamps(){let t=this._cache.data||[],s,n;if(t.length)return t;const i=this.getMatchingVisibleMetas();if(this._normalized&&i.length)return this._cache.data=i[0].controller.getAllParsedValues(this);for(s=0,n=i.length;s=e[n].pos&&t<=e[i].pos&&({lo:n,hi:i}=Ye(e,"pos",t)),{pos:o,time:a}=e[n],{pos:r,time:l}=e[i]):(t>=e[n].time&&t<=e[i].time&&({lo:n,hi:i}=Ye(e,"time",t)),{time:o,pos:a}=e[n],{time:r,pos:l}=e[i]);const c=r-o;return c?a+(l-a)*(t-o)/c:a}class n1 extends fr{static id="timeseries";static defaults=fr.defaults;constructor(t){super(t),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){const t=this._getTimestampsForTable(),s=this._table=this.buildLookupTable(t);this._minPos=xi(s,this.min),this._tableRange=xi(s,this.max)-this._minPos,super.initOffsets(t)}buildLookupTable(t){const{min:s,max:n}=this,i=[],o=[];let r,a,l,c,u;for(r=0,a=t.length;r=s&&c<=n&&i.push(c);if(i.length<2)return[{time:s,pos:0},{time:n,pos:1}];for(r=0,a=i.length;ri-o)}_getTimestampsForTable(){let t=this._cache.all||[];if(t.length)return t;const s=this.getDataTimestamps(),n=this.getLabelTimestamps();return s.length&&n.length?t=this.normalize(s.concat(n)):t=s.length?s:n,t=this._cache.all=t,t}getDecimalForValue(t){return(xi(this._table,t)-this._minPos)/this._tableRange}getValueForPixel(t){const s=this._offsets,n=this.getDecimalForPixel(t)/s.factor-s.end;return xi(this._table,n*this._tableRange+this._minPos,!0)}}var i1=Object.freeze({__proto__:null,CategoryScale:Iv,LinearScale:Fv,LogarithmicScale:$v,RadialLinearScale:Zv,TimeScale:fr,TimeSeriesScale:n1});const o1=[sy,Lx,Ov,i1],r1={class:"app-container"},a1={class:"content"},l1={class:"dashboard-container pb-5"},c1={class:"dashboard-header"},u1={class:"header-actions"},h1={class:"overview-grid"},d1={class:"stat-card"},f1={class:"stat-value"},p1={class:"stat-card"},g1={class:"stat-value"},m1={class:"stat-description"},b1={class:"stat-card"},_1={class:"stat-change"},y1={class:"stat-card"},x1={class:"stat-value"},v1={class:"charts-section"},w1={class:"chart-card"},S1={class:"chart-placeholder"},k1={class:"chart-card"},M1={class:"chart-placeholder"},C1={class:"table-section"},P1={class:"table-card"},A1={class:"data-table"},R1={class:"table-section"},O1={class:"table-card"},T1={class:"data-table"},E1={class:"route-name"},D1={key:0,class:"table-section"},I1={class:"table-card"},L1={class:"data-table errors-table"},F1={class:"error-message"},N1={__name:"Dashboard",setup(e){Ai.register(...o1);const t=et(!1),s=et({routes:[],...window.ApiInspector}),n=et(localStorage.getItem("api-docs-auth-token")||""),{menus:i}=Hu(),o=et("24h"),r=Zs({totalRequests:0,requestsTrend:0,avgResponseTime:0,slowestRoute:"",errorRate:0,errorCount:0,avgMemory:0}),a=et({}),l=et([]),c=et([]);Zs({requestTimeline:null,responseDistribution:null});const u=et(null),h=et(null);let d=null,f=null;to(()=>{p()});const p=async()=>{try{const C=await(await fetch(`/api/api-inspector-docs/analytics?range=${o.value}`)).json();r.totalRequests=C.totalRequests,r.requestsTrend=C.requestsTrend,r.avgResponseTime=C.avgResponseTime,r.slowestRoute=C.slowestRoute,r.errorRate=C.errorRate,r.errorCount=C.errorCount,r.avgMemory=C.avgMemory,a.value=C.statusCodeStats,l.value=C.topRoutes,c.value=C.recentErrors,await Qi(),g(C)}catch(P){console.error("Failed to fetch dashboard data:",P)}},g=P=>{_(P),b(P)},_=P=>{if(!u.value)return;const C=v();d&&d.destroy(),d=new Ai(u.value,{type:"line",data:{labels:C,datasets:[{label:"Requests",data:M(P,C.length),borderColor:"#3b82f6",backgroundColor:"rgba(59, 130, 246, 0.1)",borderWidth:2,tension:.4,fill:!0,pointRadius:4,pointBackgroundColor:"#3b82f6",pointBorderColor:"#fff",pointBorderWidth:2}]},options:{responsive:!0,maintainAspectRatio:!0,plugins:{legend:{display:!0,labels:{font:{size:12},usePointStyle:!0}}},scales:{y:{beginAtZero:!0,grid:{color:"rgba(0, 0, 0, 0.05)"},ticks:{font:{size:11}}},x:{grid:{display:!1},ticks:{font:{size:11}}}}}})},b=P=>{if(!h.value)return;const C=P.topRoutes.slice(0,8),O=C.map(U=>U.route.substring(0,20)),B=C.map(U=>U.avg_duration);f&&f.destroy(),f=new Ai(h.value,{type:"bar",data:{labels:O,datasets:[{label:"Avg Response Time (ms)",data:B,backgroundColor:B.map(U=>U>500?"#ef4444":U>200?"#f97316":"#10b981"),borderColor:"rgba(0, 0, 0, 0.1)",borderWidth:1}]},options:{indexAxis:"y",responsive:!0,maintainAspectRatio:!0,plugins:{legend:{display:!0,labels:{font:{size:12}}}},scales:{x:{beginAtZero:!0,grid:{color:"rgba(0, 0, 0, 0.05)"},ticks:{font:{size:11}}},y:{grid:{display:!1},ticks:{font:{size:11}}}}}})},v=()=>{const P=[],C=new Date;for(let O=11;O>=0;O--){const B=new Date(C.getTime()-O*36e5);P.push(B.getHours().toString().padStart(2,"0")+":00")}return P},M=(P,C)=>{const O=Math.ceil(P.totalRequests/C);return Array.from({length:C},()=>Math.max(1,O+Math.floor(Math.random()*(O*.5)-O*.25)))},S=P=>{const C=Object.values(a.value).reduce((O,B)=>O+B,0);return C>0?(a.value[P]/C*100).toFixed(2):0},w=P=>{const C=l.value.filter(B=>B.status_code===parseInt(P));return C.length===0?"0":(C.reduce((B,U)=>B+U.avg_duration,0)/C.length).toFixed(2)},R=P=>{if(P===0)return"0 B";const C=1024,O=["B","KB","MB","GB"],B=Math.floor(Math.log(Math.abs(P))/Math.log(C));return(P/Math.pow(C,B)).toFixed(2)+" "+O[B]},k=P=>new Date(P).toLocaleTimeString();return(P,C)=>(L(),N("div",r1,[Pt(zu,{"api-data":s.value,loading:t.value,"auth-token":n.value,menus:_e(i),onRefresh:p,"onUpdate:authToken":C[0]||(C[0]=O=>n.value=O)},null,8,["api-data","loading","auth-token","menus"]),m("div",a1,[m("div",l1,[m("div",c1,[C[3]||(C[3]=m("h1",null,"API Inspector Dashboard",-1)),m("div",u1,[se(m("select",{"onUpdate:modelValue":C[1]||(C[1]=O=>o.value=O),onChange:p,class:"time-range-select"},[...C[2]||(C[2]=[m("option",{value:"1h"},"Last 1 Hour",-1),m("option",{value:"24h"},"Last 24 Hours",-1),m("option",{value:"7d"},"Last 7 Days",-1),m("option",{value:"30d"},"Last 30 Days",-1)])],544),[[$u,o.value]])])]),m("div",h1,[m("div",d1,[C[4]||(C[4]=m("div",{class:"stat-label"},"Total Requests",-1)),m("div",f1,H(r.totalRequests),1),m("div",{class:kt(["stat-change",r.requestsTrend>0?"positive":"negative"])},H(r.requestsTrend>0?"↑":"↓")+" "+H(Math.abs(r.requestsTrend))+"% ",3)]),m("div",p1,[C[5]||(C[5]=m("div",{class:"stat-label"},"Avg Response Time",-1)),m("div",g1,H(r.avgResponseTime.toFixed(2))+"ms",1),m("div",m1,H(r.slowestRoute),1)]),m("div",b1,[C[6]||(C[6]=m("div",{class:"stat-label"},"Error Rate",-1)),m("div",{class:kt(["stat-value",r.errorRate>10?"error":""])},H(r.errorRate.toFixed(2))+"% ",3),m("div",_1,H(r.errorCount)+" errors",1)]),m("div",y1,[C[7]||(C[7]=m("div",{class:"stat-label"},"Avg Memory Usage",-1)),m("div",x1,H(R(r.avgMemory)),1),C[8]||(C[8]=m("div",{class:"stat-description"},"Per request",-1))])]),m("div",v1,[m("div",w1,[C[9]||(C[9]=m("h3",null,"Request Timeline",-1)),m("div",S1,[m("canvas",{ref_key:"requestChart",ref:u},null,512)])]),m("div",k1,[C[10]||(C[10]=m("h3",null,"Response Time Distribution",-1)),m("div",M1,[m("canvas",{ref_key:"responseTimeChart",ref:h},null,512)])])]),m("div",C1,[m("div",P1,[C[12]||(C[12]=m("h3",null,"Status Code Distribution",-1)),m("table",A1,[C[11]||(C[11]=m("thead",null,[m("tr",null,[m("th",null,"Status Code"),m("th",null,"Count"),m("th",null,"Percentage"),m("th",null,"Avg Duration")])],-1)),m("tbody",null,[(L(!0),N(ut,null,Vt(a.value,(O,B)=>(L(),N("tr",{key:B,class:kt(`status-${B}`)},[m("td",null,[m("span",{class:kt(["status-badge",`status-${B}`])},H(B),3)]),m("td",null,H(O),1),m("td",null,H(S(B))+"%",1),m("td",null,H(w(B))+"ms",1)],2))),128))])])])]),m("div",R1,[m("div",O1,[C[14]||(C[14]=m("h3",null,"Top Routes by Response Time",-1)),m("table",T1,[C[13]||(C[13]=m("thead",null,[m("tr",null,[m("th",null,"Route"),m("th",null,"Method"),m("th",null,"Requests"),m("th",null,"Avg Time"),m("th",null,"Min/Max"),m("th",null,"Error Rate")])],-1)),m("tbody",null,[(L(!0),N(ut,null,Vt(l.value,O=>(L(),N("tr",{key:O.route,class:"route-row"},[m("td",E1,H(O.route),1),m("td",null,[m("span",{class:kt(["method-badge",`method-${O.method}`])},H(O.method),3)]),m("td",null,H(O.count),1),m("td",null,[m("span",{class:kt(["duration",O.avg_duration>500?"slow":""])},H(O.avg_duration.toFixed(2))+"ms ",3)]),m("td",null,H(O.min)+"ms / "+H(O.max)+"ms",1),m("td",null,[m("span",{class:kt(["error-rate",O.errorRate>10?"high":""])},H(O.errorRate.toFixed(2))+"% ",3)])]))),128))])])])]),c.value.length>0?(L(),N("div",D1,[m("div",I1,[C[16]||(C[16]=m("h3",null,"Recent Errors (Last 24h)",-1)),m("table",L1,[C[15]||(C[15]=m("thead",null,[m("tr",null,[m("th",null,"Time"),m("th",null,"Route"),m("th",null,"Status"),m("th",null,"Error"),m("th",null,"IP")])],-1)),m("tbody",null,[(L(!0),N(ut,null,Vt(c.value.slice(0,10),(O,B)=>(L(),N("tr",{key:B,class:"error-row"},[m("td",null,H(k(O.recorded_at)),1),m("td",null,H(O.route),1),m("td",null,[m("span",{class:kt(["status-badge",`status-${O.status_code}`])},H(O.status_code),3)]),m("td",F1,H(O.error),1),m("td",null,H(O.ip_address),1)]))),128))])])])])):dt("",!0)])])]))}},B1={class:"toasts-container"},$1={class:"toast-content"},V1={class:"toast-icon"},j1={__name:"Toast",setup(e){const{toasts:t}=io(),s=n=>({success:"✓",error:"✕",info:"ℹ"})[n]||"✓";return(n,i)=>(L(),Ie(Yd,{to:"body"},[m("div",B1,[(L(!0),N(ut,null,Vt(_e(t),o=>(L(),N("div",{key:o.id,class:kt(["toast",o.type])},[m("div",$1,[m("span",V1,H(s(o.type)),1),m("span",null,H(o.message),1)])],2))),128))])]))}},H1=ne(j1,[["__scopeId","data-v-40e4e9e9"]]);const Us=typeof document<"u";function Hh(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function z1(e){return e.__esModule||e[Symbol.toStringTag]==="Module"||e.default&&Hh(e.default)}const ft=Object.assign;function Vo(e,t){const s={};for(const n in t){const i=t[n];s[n]=Me(i)?i.map(e):e(i)}return s}const Fn=()=>{},Me=Array.isArray;function fc(e,t){const s={};for(const n in e)s[n]=n in t?t[n]:e[n];return s}const zh=/#/g,W1=/&/g,q1=/\//g,U1=/=/g,K1=/\?/g,Wh=/\+/g,G1=/%5B/g,Y1=/%5D/g,qh=/%5E/g,X1=/%60/g,Uh=/%7B/g,J1=/%7C/g,Kh=/%7D/g,Q1=/%20/g;function ea(e){return e==null?"":encodeURI(""+e).replace(J1,"|").replace(G1,"[").replace(Y1,"]")}function Z1(e){return ea(e).replace(Uh,"{").replace(Kh,"}").replace(qh,"^")}function pr(e){return ea(e).replace(Wh,"%2B").replace(Q1,"+").replace(zh,"%23").replace(W1,"%26").replace(X1,"`").replace(Uh,"{").replace(Kh,"}").replace(qh,"^")}function tw(e){return pr(e).replace(U1,"%3D")}function ew(e){return ea(e).replace(zh,"%23").replace(K1,"%3F")}function sw(e){return ew(e).replace(q1,"%2F")}function Xn(e){if(e==null)return null;try{return decodeURIComponent(""+e)}catch{}return""+e}const nw=/\/$/,iw=e=>e.replace(nw,"");function jo(e,t,s="/"){let n,i={},o="",r="";const a=t.indexOf("#");let l=t.indexOf("?");return l=a>=0&&l>a?-1:l,l>=0&&(n=t.slice(0,l),o=t.slice(l,a>0?a:t.length),i=e(o.slice(1))),a>=0&&(n=n||t.slice(0,a),r=t.slice(a,t.length)),n=lw(n??t,s),{fullPath:n+o+r,path:n,query:i,hash:Xn(r)}}function ow(e,t){const s=t.query?e(t.query):"";return t.path+(s&&"?")+s+(t.hash||"")}function pc(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function rw(e,t,s){const n=t.matched.length-1,i=s.matched.length-1;return n>-1&&n===i&&an(t.matched[n],s.matched[i])&&Gh(t.params,s.params)&&e(t.query)===e(s.query)&&t.hash===s.hash}function an(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function Gh(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(var s in e)if(!aw(e[s],t[s]))return!1;return!0}function aw(e,t){return Me(e)?gc(e,t):Me(t)?gc(t,e):e?.valueOf()===t?.valueOf()}function gc(e,t){return Me(t)?e.length===t.length&&e.every((s,n)=>s===t[n]):e.length===1&&e[0]===t}function lw(e,t){if(e.startsWith("/"))return e;if(!e)return t;const s=t.split("/"),n=e.split("/"),i=n[n.length-1];(i===".."||i===".")&&n.push("");let o=s.length-1,r,a;for(r=0;r1&&o--;else break;return s.slice(0,o).join("/")+"/"+n.slice(r).join("/")}const os={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0};let gr=(function(e){return e.pop="pop",e.push="push",e})({}),Ho=(function(e){return e.back="back",e.forward="forward",e.unknown="",e})({});function cw(e){if(!e)if(Us){const t=document.querySelector("base");e=t&&t.getAttribute("href")||"/",e=e.replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return e[0]!=="/"&&e[0]!=="#"&&(e="/"+e),iw(e)}const uw=/^[^#]+#/;function hw(e,t){return e.replace(uw,"#")+t}function dw(e,t){const s=document.documentElement.getBoundingClientRect(),n=e.getBoundingClientRect();return{behavior:t.behavior,left:n.left-s.left-(t.left||0),top:n.top-s.top-(t.top||0)}}const po=()=>({left:window.scrollX,top:window.scrollY});function fw(e){let t;if("el"in e){const s=e.el,n=typeof s=="string"&&s.startsWith("#"),i=typeof s=="string"?n?document.getElementById(s.slice(1)):document.querySelector(s):s;if(!i)return;t=dw(i,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left!=null?t.left:window.scrollX,t.top!=null?t.top:window.scrollY)}function mc(e,t){return(history.state?history.state.position-t:-1)+e}const mr=new Map;function pw(e,t){mr.set(e,t)}function gw(e){const t=mr.get(e);return mr.delete(e),t}function mw(e){return typeof e=="string"||e&&typeof e=="object"}function Yh(e){return typeof e=="string"||typeof e=="symbol"}let Ot=(function(e){return e[e.MATCHER_NOT_FOUND=1]="MATCHER_NOT_FOUND",e[e.NAVIGATION_GUARD_REDIRECT=2]="NAVIGATION_GUARD_REDIRECT",e[e.NAVIGATION_ABORTED=4]="NAVIGATION_ABORTED",e[e.NAVIGATION_CANCELLED=8]="NAVIGATION_CANCELLED",e[e.NAVIGATION_DUPLICATED=16]="NAVIGATION_DUPLICATED",e})({});const Xh=Symbol("");Ot.MATCHER_NOT_FOUND+"",Ot.NAVIGATION_GUARD_REDIRECT+"",Ot.NAVIGATION_ABORTED+"",Ot.NAVIGATION_CANCELLED+"",Ot.NAVIGATION_DUPLICATED+"";function ln(e,t){return ft(new Error,{type:e,[Xh]:!0},t)}function Ve(e,t){return e instanceof Error&&Xh in e&&(t==null||!!(e.type&t))}const bw=["params","query","hash"];function _w(e){if(typeof e=="string")return e;if(e.path!=null)return e.path;const t={};for(const s of bw)s in e&&(t[s]=e[s]);return JSON.stringify(t,null,2)}function yw(e){const t={};if(e===""||e==="?")return t;const s=(e[0]==="?"?e.slice(1):e).split("&");for(let n=0;ni&&pr(i)):[n&&pr(n)]).forEach(i=>{i!==void 0&&(t+=(t.length?"&":"")+s,i!=null&&(t+="="+i))})}return t}function xw(e){const t={};for(const s in e){const n=e[s];n!==void 0&&(t[s]=Me(n)?n.map(i=>i==null?null:""+i):n==null?n:""+n)}return t}const vw=Symbol(""),_c=Symbol(""),sa=Symbol(""),Jh=Symbol(""),br=Symbol("");function yn(){let e=[];function t(n){return e.push(n),()=>{const i=e.indexOf(n);i>-1&&e.splice(i,1)}}function s(){e=[]}return{add:t,list:()=>e.slice(),reset:s}}function cs(e,t,s,n,i,o=r=>r()){const r=n&&(n.enterCallbacks[i]=n.enterCallbacks[i]||[]);return()=>new Promise((a,l)=>{const c=d=>{d===!1?l(ln(Ot.NAVIGATION_ABORTED,{from:s,to:t})):d instanceof Error?l(d):mw(d)?l(ln(Ot.NAVIGATION_GUARD_REDIRECT,{from:t,to:d})):(r&&n.enterCallbacks[i]===r&&typeof d=="function"&&r.push(d),a())},u=o(()=>e.call(n&&n.instances[i],t,s,c));let h=Promise.resolve(u);e.length<3&&(h=h.then(c)),h.catch(d=>l(d))})}function zo(e,t,s,n,i=o=>o()){const o=[];for(const r of e)for(const a in r.components){let l=r.components[a];if(!(t!=="beforeRouteEnter"&&!r.instances[a]))if(Hh(l)){const c=(l.__vccOpts||l)[t];c&&o.push(cs(c,s,n,r,a,i))}else{let c=l();o.push(()=>c.then(u=>{if(!u)throw new Error(`Couldn't resolve component "${a}" at "${r.path}"`);const h=z1(u)?u.default:u;r.mods[a]=u,r.components[a]=h;const d=(h.__vccOpts||h)[t];return d&&cs(d,s,n,r,a,i)()}))}}return o}function ww(e,t){const s=[],n=[],i=[],o=Math.max(t.matched.length,e.matched.length);for(let r=0;ran(c,a))?n.push(a):s.push(a));const l=e.matched[r];l&&(t.matched.find(c=>an(c,l))||i.push(l))}return[s,n,i]}let Sw=()=>location.protocol+"//"+location.host;function Qh(e,t){const{pathname:s,search:n,hash:i}=t,o=e.indexOf("#");if(o>-1){let r=i.includes(e.slice(o))?e.slice(o).length:1,a=i.slice(r);return a[0]!=="/"&&(a="/"+a),pc(a,"")}return pc(s,e)+n+i}function kw(e,t,s,n){let i=[],o=[],r=null;const a=({state:d})=>{const f=Qh(e,location),p=s.value,g=t.value;let _=0;if(d){if(s.value=f,t.value=d,r&&r===p){r=null;return}_=g?d.position-g.position:0}else n(f);i.forEach(b=>{b(s.value,p,{delta:_,type:gr.pop,direction:_?_>0?Ho.forward:Ho.back:Ho.unknown})})};function l(){r=s.value}function c(d){i.push(d);const f=()=>{const p=i.indexOf(d);p>-1&&i.splice(p,1)};return o.push(f),f}function u(){if(document.visibilityState==="hidden"){const{history:d}=window;if(!d.state)return;d.replaceState(ft({},d.state,{scroll:po()}),"")}}function h(){for(const d of o)d();o=[],window.removeEventListener("popstate",a),window.removeEventListener("pagehide",u),document.removeEventListener("visibilitychange",u)}return window.addEventListener("popstate",a),window.addEventListener("pagehide",u),document.addEventListener("visibilitychange",u),{pauseListeners:l,listen:c,destroy:h}}function yc(e,t,s,n=!1,i=!1){return{back:e,current:t,forward:s,replaced:n,position:window.history.length,scroll:i?po():null}}function Mw(e){const{history:t,location:s}=window,n={value:Qh(e,s)},i={value:t.state};i.value||o(n.value,{back:null,current:n.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function o(l,c,u){const h=e.indexOf("#"),d=h>-1?(s.host&&document.querySelector("base")?e:e.slice(h))+l:Sw()+e+l;try{t[u?"replaceState":"pushState"](c,"",d),i.value=c}catch(f){console.error(f),s[u?"replace":"assign"](d)}}function r(l,c){o(l,ft({},t.state,yc(i.value.back,l,i.value.forward,!0),c,{position:i.value.position}),!0),n.value=l}function a(l,c){const u=ft({},i.value,t.state,{forward:l,scroll:po()});o(u.current,u,!0),o(l,ft({},yc(n.value,l,null),{position:u.position+1},c),!1),n.value=l}return{location:n,state:i,push:a,replace:r}}function Cw(e){e=cw(e);const t=Mw(e),s=kw(e,t.state,t.location,t.replace);function n(o,r=!0){r||s.pauseListeners(),history.go(o)}const i=ft({location:"",base:e,go:n,createHref:hw.bind(null,e)},t,s);return Object.defineProperty(i,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(i,"state",{enumerable:!0,get:()=>t.state.value}),i}let Es=(function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.Group=2]="Group",e})({});var Ft=(function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.ParamRegExp=2]="ParamRegExp",e[e.ParamRegExpEnd=3]="ParamRegExpEnd",e[e.EscapeNext=4]="EscapeNext",e})(Ft||{});const Pw={type:Es.Static,value:""},Aw=/[a-zA-Z0-9_]/;function Rw(e){if(!e)return[[]];if(e==="/")return[[Pw]];if(!e.startsWith("/"))throw new Error(`Invalid path "${e}"`);function t(f){throw new Error(`ERR (${s})/"${c}": ${f}`)}let s=Ft.Static,n=s;const i=[];let o;function r(){o&&i.push(o),o=[]}let a=0,l,c="",u="";function h(){c&&(s===Ft.Static?o.push({type:Es.Static,value:c}):s===Ft.Param||s===Ft.ParamRegExp||s===Ft.ParamRegExpEnd?(o.length>1&&(l==="*"||l==="+")&&t(`A repeatable param (${c}) must be alone in its segment. eg: '/:ids+.`),o.push({type:Es.Param,value:c,regexp:u,repeatable:l==="*"||l==="+",optional:l==="*"||l==="?"})):t("Invalid state to consume buffer"),c="")}function d(){c+=l}for(;at.length?t.length===1&&t[0]===te.Static+te.Segment?1:-1:0}function Zh(e,t){let s=0;const n=e.score,i=t.score;for(;s0&&t[t.length-1]<0}const Iw={strict:!1,end:!0,sensitive:!1};function Lw(e,t,s){const n=Ew(Rw(e.path),s),i=ft(n,{record:e,parent:t,children:[],alias:[]});return t&&!i.record.aliasOf==!t.record.aliasOf&&t.children.push(i),i}function Fw(e,t){const s=[],n=new Map;t=fc(Iw,t);function i(h){return n.get(h)}function o(h,d,f){const p=!f,g=Sc(h);g.aliasOf=f&&f.record;const _=fc(t,h),b=[g];if("alias"in h){const S=typeof h.alias=="string"?[h.alias]:h.alias;for(const w of S)b.push(Sc(ft({},g,{components:f?f.record.components:g.components,path:w,aliasOf:f?f.record:g})))}let v,M;for(const S of b){const{path:w}=S;if(d&&w[0]!=="/"){const R=d.record.path,k=R[R.length-1]==="/"?"":"/";S.path=d.record.path+(w&&k+w)}if(v=Lw(S,d,_),f?f.alias.push(v):(M=M||v,M!==v&&M.alias.push(v),p&&h.name&&!kc(v)&&r(h.name)),td(v)&&l(v),g.children){const R=g.children;for(let k=0;k{r(M)}:Fn}function r(h){if(Yh(h)){const d=n.get(h);d&&(n.delete(h),s.splice(s.indexOf(d),1),d.children.forEach(r),d.alias.forEach(r))}else{const d=s.indexOf(h);d>-1&&(s.splice(d,1),h.record.name&&n.delete(h.record.name),h.children.forEach(r),h.alias.forEach(r))}}function a(){return s}function l(h){const d=$w(h,s);s.splice(d,0,h),h.record.name&&!kc(h)&&n.set(h.record.name,h)}function c(h,d){let f,p={},g,_;if("name"in h&&h.name){if(f=n.get(h.name),!f)throw ln(Ot.MATCHER_NOT_FOUND,{location:h});_=f.record.name,p=ft(wc(d.params,f.keys.filter(M=>!M.optional).concat(f.parent?f.parent.keys.filter(M=>M.optional):[]).map(M=>M.name)),h.params&&wc(h.params,f.keys.map(M=>M.name))),g=f.stringify(p)}else if(h.path!=null)g=h.path,f=s.find(M=>M.re.test(g)),f&&(p=f.parse(g),_=f.record.name);else{if(f=d.name?n.get(d.name):s.find(M=>M.re.test(d.path)),!f)throw ln(Ot.MATCHER_NOT_FOUND,{location:h,currentLocation:d});_=f.record.name,p=ft({},d.params,h.params),g=f.stringify(p)}const b=[];let v=f;for(;v;)b.unshift(v.record),v=v.parent;return{name:_,path:g,params:p,matched:b,meta:Bw(b)}}e.forEach(h=>o(h));function u(){s.length=0,n.clear()}return{addRoute:o,resolve:c,removeRoute:r,clearRoutes:u,getRoutes:a,getRecordMatcher:i}}function wc(e,t){const s={};for(const n of t)n in e&&(s[n]=e[n]);return s}function Sc(e){const t={path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:e.aliasOf,beforeEnter:e.beforeEnter,props:Nw(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:"components"in e?e.components||null:e.component&&{default:e.component}};return Object.defineProperty(t,"mods",{value:{}}),t}function Nw(e){const t={},s=e.props||!1;if("component"in e)t.default=s;else for(const n in e.components)t[n]=typeof s=="object"?s[n]:s;return t}function kc(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function Bw(e){return e.reduce((t,s)=>ft(t,s.meta),{})}function $w(e,t){let s=0,n=t.length;for(;s!==n;){const o=s+n>>1;Zh(e,t[o])<0?n=o:s=o+1}const i=Vw(e);return i&&(n=t.lastIndexOf(i,n-1)),n}function Vw(e){let t=e;for(;t=t.parent;)if(td(t)&&Zh(e,t)===0)return t}function td({record:e}){return!!(e.name||e.components&&Object.keys(e.components).length||e.redirect)}function Mc(e){const t=Je(sa),s=Je(Jh),n=qt(()=>{const l=_e(e.to);return t.resolve(l)}),i=qt(()=>{const{matched:l}=n.value,{length:c}=l,u=l[c-1],h=s.matched;if(!u||!h.length)return-1;const d=h.findIndex(an.bind(null,u));if(d>-1)return d;const f=Cc(l[c-2]);return c>1&&Cc(u)===f&&h[h.length-1].path!==f?h.findIndex(an.bind(null,l[c-2])):d}),o=qt(()=>i.value>-1&&qw(s.params,n.value.params)),r=qt(()=>i.value>-1&&i.value===s.matched.length-1&&Gh(s.params,n.value.params));function a(l={}){if(Ww(l)){const c=t[_e(e.replace)?"replace":"push"](_e(e.to)).catch(Fn);return e.viewTransition&&typeof document<"u"&&"startViewTransition"in document&&document.startViewTransition(()=>c),c}return Promise.resolve()}return{route:n,href:qt(()=>n.value.href),isActive:o,isExactActive:r,navigate:a}}function jw(e){return e.length===1?e[0]:e}const Hw=uu({name:"RouterLink",compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"},viewTransition:Boolean},useLink:Mc,setup(e,{slots:t}){const s=Zs(Mc(e)),{options:n}=Je(sa),i=qt(()=>({[Pc(e.activeClass,n.linkActiveClass,"router-link-active")]:s.isActive,[Pc(e.exactActiveClass,n.linkExactActiveClass,"router-link-exact-active")]:s.isExactActive}));return()=>{const o=t.default&&jw(t.default(s));return e.custom?o:Lu("a",{"aria-current":s.isExactActive?e.ariaCurrentValue:null,href:s.href,onClick:s.navigate,class:i.value},o)}}}),zw=Hw;function Ww(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&!(e.button!==void 0&&e.button!==0)){if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function qw(e,t){for(const s in t){const n=t[s],i=e[s];if(typeof n=="string"){if(n!==i)return!1}else if(!Me(i)||i.length!==n.length||n.some((o,r)=>o.valueOf()!==i[r].valueOf()))return!1}return!0}function Cc(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const Pc=(e,t,s)=>e??t??s,Uw=uu({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},compatConfig:{MODE:3},setup(e,{attrs:t,slots:s}){const n=Je(br),i=qt(()=>e.route||n.value),o=Je(_c,0),r=qt(()=>{let c=_e(o);const{matched:u}=i.value;let h;for(;(h=u[c])&&!h.components;)c++;return c}),a=qt(()=>i.value.matched[r.value]);wi(_c,qt(()=>r.value+1)),wi(vw,a),wi(br,i);const l=et();return Qe(()=>[l.value,a.value,e.name],([c,u,h],[d,f,p])=>{u&&(u.instances[h]=c,f&&f!==u&&c&&c===d&&(u.leaveGuards.size||(u.leaveGuards=f.leaveGuards),u.updateGuards.size||(u.updateGuards=f.updateGuards))),c&&u&&(!f||!an(u,f)||!d)&&(u.enterCallbacks[h]||[]).forEach(g=>g(c))},{flush:"post"}),()=>{const c=i.value,u=e.name,h=a.value,d=h&&h.components[u];if(!d)return Ac(s.default,{Component:d,route:c});const f=h.props[u],p=f?f===!0?c.params:typeof f=="function"?f(c):f:null,_=Lu(d,ft({},p,t,{onVnodeUnmounted:b=>{b.component.isUnmounted&&(h.instances[u]=null)},ref:l}));return Ac(s.default,{Component:_,route:c})||_}}});function Ac(e,t){if(!e)return null;const s=e(t);return s.length===1?s[0]:s}const Kw=Uw;function Gw(e){const t=Fw(e.routes,e),s=e.parseQuery||yw,n=e.stringifyQuery||bc,i=e.history,o=yn(),r=yn(),a=yn(),l=Id(os);let c=os;Us&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const u=Vo.bind(null,D=>""+D),h=Vo.bind(null,sw),d=Vo.bind(null,Xn);function f(D,q){let z,K;return Yh(D)?(z=t.getRecordMatcher(D),K=q):K=D,t.addRoute(K,z)}function p(D){const q=t.getRecordMatcher(D);q&&t.removeRoute(q)}function g(){return t.getRoutes().map(D=>D.record)}function _(D){return!!t.getRecordMatcher(D)}function b(D,q){if(q=ft({},q||l.value),typeof D=="string"){const A=jo(s,D,q.path),T=t.resolve({path:A.path},q),I=i.createHref(A.fullPath);return ft(A,T,{params:d(T.params),hash:Xn(A.hash),redirectedFrom:void 0,href:I})}let z;if(D.path!=null)z=ft({},D,{path:jo(s,D.path,q.path).path});else{const A=ft({},D.params);for(const T in A)A[T]==null&&delete A[T];z=ft({},D,{params:h(A)}),q.params=h(q.params)}const K=t.resolve(z,q),lt=D.hash||"";K.params=u(d(K.params));const y=ow(n,ft({},D,{hash:Z1(lt),path:K.path})),x=i.createHref(y);return ft({fullPath:y,hash:lt,query:n===bc?xw(D.query):D.query||{}},K,{redirectedFrom:void 0,href:x})}function v(D){return typeof D=="string"?jo(s,D,l.value.path):ft({},D)}function M(D,q){if(c!==D)return ln(Ot.NAVIGATION_CANCELLED,{from:q,to:D})}function S(D){return k(D)}function w(D){return S(ft(v(D),{replace:!0}))}function R(D,q){const z=D.matched[D.matched.length-1];if(z&&z.redirect){const{redirect:K}=z;let lt=typeof K=="function"?K(D,q):K;return typeof lt=="string"&&(lt=lt.includes("?")||lt.includes("#")?lt=v(lt):{path:lt},lt.params={}),ft({query:D.query,hash:D.hash,params:lt.path!=null?{}:D.params},lt)}}function k(D,q){const z=c=b(D),K=l.value,lt=D.state,y=D.force,x=D.replace===!0,A=R(z,K);if(A)return k(ft(v(A),{state:typeof A=="object"?ft({},lt,A.state):lt,force:y,replace:x}),q||z);const T=z;T.redirectedFrom=q;let I;return!y&&rw(n,K,z)&&(I=ln(Ot.NAVIGATION_DUPLICATED,{to:T,from:K}),Jt(K,K,!0,!1)),(I?Promise.resolve(I):O(T,K)).catch(E=>Ve(E)?Ve(E,Ot.NAVIGATION_GUARD_REDIRECT)?E:Xt(E):nt(E,T,K)).then(E=>{if(E){if(Ve(E,Ot.NAVIGATION_GUARD_REDIRECT))return k(ft({replace:x},v(E.to),{state:typeof E.to=="object"?ft({},lt,E.to.state):lt,force:y}),q||T)}else E=U(T,K,!0,x,lt);return B(T,K,E),E})}function P(D,q){const z=M(D,q);return z?Promise.reject(z):Promise.resolve()}function C(D){const q=ie.values().next().value;return q&&typeof q.runWithContext=="function"?q.runWithContext(D):D()}function O(D,q){let z;const[K,lt,y]=ww(D,q);z=zo(K.reverse(),"beforeRouteLeave",D,q);for(const A of K)A.leaveGuards.forEach(T=>{z.push(cs(T,D,q))});const x=P.bind(null,D,q);return z.push(x),Lt(z).then(()=>{z=[];for(const A of o.list())z.push(cs(A,D,q));return z.push(x),Lt(z)}).then(()=>{z=zo(lt,"beforeRouteUpdate",D,q);for(const A of lt)A.updateGuards.forEach(T=>{z.push(cs(T,D,q))});return z.push(x),Lt(z)}).then(()=>{z=[];for(const A of y)if(A.beforeEnter)if(Me(A.beforeEnter))for(const T of A.beforeEnter)z.push(cs(T,D,q));else z.push(cs(A.beforeEnter,D,q));return z.push(x),Lt(z)}).then(()=>(D.matched.forEach(A=>A.enterCallbacks={}),z=zo(y,"beforeRouteEnter",D,q,C),z.push(x),Lt(z))).then(()=>{z=[];for(const A of r.list())z.push(cs(A,D,q));return z.push(x),Lt(z)}).catch(A=>Ve(A,Ot.NAVIGATION_CANCELLED)?A:Promise.reject(A))}function B(D,q,z){a.list().forEach(K=>C(()=>K(D,q,z)))}function U(D,q,z,K,lt){const y=M(D,q);if(y)return y;const x=q===os,A=Us?history.state:{};z&&(K||x?i.replace(D.fullPath,ft({scroll:x&&A&&A.scroll},lt)):i.push(D.fullPath,lt)),l.value=D,Jt(D,q,z,x),Xt()}let at;function Ct(){at||(at=i.listen((D,q,z)=>{if(!ue.listening)return;const K=b(D),lt=R(K,ue.currentRoute.value);if(lt){k(ft(lt,{replace:!0,force:!0}),K).catch(Fn);return}c=K;const y=l.value;Us&&pw(mc(y.fullPath,z.delta),po()),O(K,y).catch(x=>Ve(x,Ot.NAVIGATION_ABORTED|Ot.NAVIGATION_CANCELLED)?x:Ve(x,Ot.NAVIGATION_GUARD_REDIRECT)?(k(ft(v(x.to),{force:!0}),K).then(A=>{Ve(A,Ot.NAVIGATION_ABORTED|Ot.NAVIGATION_DUPLICATED)&&!z.delta&&z.type===gr.pop&&i.go(-1,!1)}).catch(Fn),Promise.reject()):(z.delta&&i.go(-z.delta,!1),nt(x,K,y))).then(x=>{x=x||U(K,y,!1),x&&(z.delta&&!Ve(x,Ot.NAVIGATION_CANCELLED)?i.go(-z.delta,!1):z.type===gr.pop&&Ve(x,Ot.NAVIGATION_ABORTED|Ot.NAVIGATION_DUPLICATED)&&i.go(-1,!1)),B(K,y,x)}).catch(Fn)}))}let rt=yn(),tt=yn(),Y;function nt(D,q,z){Xt(D);const K=tt.list();return K.length?K.forEach(lt=>lt(D,q,z)):console.error(D),Promise.reject(D)}function xt(){return Y&&l.value!==os?Promise.resolve():new Promise((D,q)=>{rt.add([D,q])})}function Xt(D){return Y||(Y=!D,Ct(),rt.list().forEach(([q,z])=>D?z(D):q()),rt.reset()),D}function Jt(D,q,z,K){const{scrollBehavior:lt}=e;if(!Us||!lt)return Promise.resolve();const y=!z&&gw(mc(D.fullPath,0))||(K||!z)&&history.state&&history.state.scroll||null;return Qi().then(()=>lt(D,q,y)).then(x=>x&&fw(x)).catch(x=>nt(x,D,q))}const Et=D=>i.go(D);let pe;const ie=new Set,ue={currentRoute:l,listening:!0,addRoute:f,removeRoute:p,clearRoutes:t.clearRoutes,hasRoute:_,getRoutes:g,resolve:b,options:e,push:S,replace:w,go:Et,back:()=>Et(-1),forward:()=>Et(1),beforeEach:o.add,beforeResolve:r.add,afterEach:a.add,onError:tt.add,isReady:xt,install(D){D.component("RouterLink",zw),D.component("RouterView",Kw),D.config.globalProperties.$router=ue,Object.defineProperty(D.config.globalProperties,"$route",{enumerable:!0,get:()=>_e(l)}),Us&&!pe&&l.value===os&&(pe=!0,S(i.location).catch(K=>{}));const q={};for(const K in os)Object.defineProperty(q,K,{get:()=>l.value[K],enumerable:!0});D.provide(sa,ue),D.provide(Jh,Jc(q)),D.provide(br,l);const z=D.unmount;ie.add(D),D.unmount=function(){ie.delete(D),ie.size<1&&(c=os,at&&at(),at=null,l.value=os,pe=!1,Y=!1),z()}}};function Lt(D){return D.reduce((q,z)=>q.then(()=>C(z)),Promise.resolve())}return ue}window.ApiInspector.basePath="/"+window.ApiInspector.path;window.location.pathname.startsWith(window.ApiInspector.basePath)||(window.ApiInspector.basePath=window.location.pathname);let ed=window.ApiInspector.basePath+"/";(window.ApiInspector.path===""||window.ApiInspector.path==="/")&&(ed="/",window.ApiInspector.basePath="");const Yw=Gw({routes:[{path:window.ApiInspector.basePath,name:"home",component:Nb},{path:window.ApiInspector.basePath+"/stats",name:"dashboard",component:N1}],history:Cw(),base:ed}),go=Ap(Dp);window.useToast=io;go.component("Toast",H1);go.use(Yw);go.mixin({computed:{ApiInspector:()=>window.ApiInspector}});go.mount("#api-inspector"); ================================================ FILE: resources/css/app.css ================================================ a { text-decoration: none !important; } ================================================ FILE: resources/js/app.js ================================================ import './bootstrap'; import { createApp } from 'vue'; import { createPinia } from 'pinia' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' import { Bootstrap5Pagination } from 'laravel-vue-pagination'; import router from './routes/index' import VueSweetalert2 from "vue-sweetalert2"; import { abilitiesPlugin } from '@casl/vue'; import ability from './services/ability'; import vSelect from "vue-select"; import useAuth from './composables/auth'; import i18n from "./plugins/i18n"; import 'sweetalert2/dist/sweetalert2.min.css'; import 'vue-select/dist/vue-select.css'; const pinia = createPinia(); pinia.use(piniaPluginPersistedstate); const app = createApp({ created() { useAuth().getUser() } }); import ExampleComponent from './components/ExampleComponent.vue'; app.component('example-component', ExampleComponent); app.use(pinia) app.use(router) app.use(VueSweetalert2) app.use(i18n) app.use(abilitiesPlugin, ability) app.component('Pagination', Bootstrap5Pagination) app.component("v-select", vSelect); app.mount('#app') ================================================ FILE: resources/js/bootstrap.js ================================================ import _ from 'lodash'; window._ = _; import 'bootstrap'; /** * We'll load the axios HTTP library which allows us to easily issue requests * to our Laravel back-end. This library automatically handles sending the * CSRF token as a header based on the value of the "XSRF" token cookie. */ import axios from 'axios'; window.axios = axios; window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; window.axios.defaults.withCredentials = true window.axios.interceptors.response.use( response => response, error => { // Check for email verification required (403 with email_verified: false) // if (error.response?.status === 403 && error.response?.data?.email_verified === false) { // if (location.pathname !== '/verify') { // location.assign('/verify') // } // return Promise.reject(error) // } if (error.response?.status === 401 || error.response?.status === 419) { if (location.pathname !== '/login'){ location.assign('/login') } } return Promise.reject(error) } ) /** * Echo exposes an expressive API for subscribing to channels and listening * for events that are broadcast by Laravel. Echo and event broadcasting * allows your team to easily build robust real-time web applications. */ // import Echo from 'laravel-echo'; // import Pusher from 'pusher-js'; // window.Pusher = Pusher; // window.Echo = new Echo({ // broadcaster: 'pusher', // key: import.meta.env.VITE_PUSHER_APP_KEY, // wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`, // wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80, // wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443, // forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https', // enabledTransports: ['ws', 'wss'], // }); ================================================ FILE: resources/js/components/Admin/Create.vue ================================================ ================================================ FILE: resources/js/components/Admin/Edit.vue ================================================ ================================================ FILE: resources/js/components/Admin/Index.vue ================================================ ================================================ FILE: resources/js/components/DropZone.vue ================================================ ================================================ FILE: resources/js/components/DualListBox.vue ================================================ ================================================ FILE: resources/js/components/ExampleComponent.vue ================================================ ================================================ FILE: resources/js/components/Footer.vue ================================================ ================================================ FILE: resources/js/components/LocaleSwitcher.vue ================================================ ================================================ FILE: resources/js/components/Nav.vue ================================================ ================================================ FILE: resources/js/components/TextEditorComponent.vue ================================================ ================================================ FILE: resources/js/components/includes/AdminNavbar.vue ================================================ ================================================ FILE: resources/js/components/includes/AdminSidebar.vue ================================================ ================================================ FILE: resources/js/components/includes/Breadcrumb.vue ================================================ ================================================ FILE: resources/js/composables/activityLogs.js ================================================ import {ref, inject, computed} from 'vue' import {useRoute, useRouter} from "vue-router"; import axios from "axios"; export default function useActivityLogs() { const route = useRoute(); const router = useRouter(); const activities = ref(); const activeFilter = ref(route.query.filter || 'all'); const searchTerm = ref(route.query.search || ''); // Pagination const currentPage = ref(parseInt(route.query.page) || 1); // Current page const perPage = ref(15); // Items per page const total = ref(0); // Total number of items // Pagination Helpers const totalPages = computed(() => Math.ceil(total.value / perPage.value)); const rangeStart = computed(() => (currentPage.value - 1) * perPage.value + 1); const rangeEnd = computed(() => Math.min(currentPage.value * perPage.value, total.value) ); const isLoading = ref(false) const getActivityLogs = (() => { const params = { filter: activeFilter.value !== 'all' ? activeFilter.value : undefined, search: searchTerm.value || undefined, page: currentPage.value, per_page: perPage.value, }; axios.get(`/api/activity-logs/`, { params }) .then(({data}) => { activities.value = data; total.value = data.meta.total }) }); const changePage = (page) => { if (page >= 1 && page <= totalPages.value) { currentPage.value = page; applyFilters(); } }; const updateFilter = (filter) => { activeFilter.value = filter; applyFilters(); }; const applyFilters = () => { setTimeout(() => { router.push({ query: { filter: activeFilter.value !== 'all' ? activeFilter.value : undefined, search: searchTerm.value || undefined, page: currentPage.value, }, }); }, 300) }; return { getActivityLogs, activities, activeFilter, isLoading, rangeStart, rangeEnd, total, currentPage, totalPages, changePage, updateFilter, searchTerm, applyFilters, } } ================================================ FILE: resources/js/composables/auth.js ================================================ import { ref, reactive, inject } from 'vue' import { useRouter } from "vue-router"; import { AbilityBuilder, createMongoAbility } from '@casl/ability'; import { ABILITY_TOKEN } from '@casl/vue'; import {useAuthStore} from "@/store/auth"; let user = reactive({ name: '', email: '', }) export default function useAuth() { const authStore = useAuthStore(); const processing = ref(false) const validationErrors = ref({}) const router = useRouter() const swal = inject('$swal') const ability = inject(ABILITY_TOKEN) const loginForm = reactive({ email: '', password: '', remember: false }) const forgotForm = reactive({ email: '', }) const resetForm = reactive({ email: '', token: '', password: '', password_confirmation: '' }) const registerForm = reactive({ name: '', email: '', password: '', password_confirmation: '' }) const submitLogin = async () => { if (processing.value) return processing.value = true validationErrors.value = {} await axios.post('/login', loginForm) .then(async response => { await authStore.getUser() // await authStore.dispatch('auth/getUser') await loginUser() // Check if email verification is required if (response.data.email_verified === false) { swal({ icon: 'warning', title: 'Email Verification Required', text: 'Please verify your email address to continue.', showConfirmButton: true, }) await router.push({ name: 'auth.verify' }) } else { swal({ icon: 'success', title: 'Login successfully', showConfirmButton: false, timer: 1500 }) await router.push({ name: 'admin.index' }) } }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => processing.value = false) } const submitRegister = async () => { if (processing.value) return processing.value = true validationErrors.value = {} await axios.post('/register', registerForm) .then(async response => { // await store.dispatch('auth/getUser') // await loginUser() swal({ icon: 'success', title: 'Registration successfully', showConfirmButton: false, timer: 1500 }) await router.push({ name: 'auth.login' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => processing.value = false) } const submitForgotPassword = async () => { if (processing.value) return processing.value = true validationErrors.value = {} await axios.post('/api/forget-password', forgotForm) .then(async response => { swal({ icon: 'success', title: 'We have emailed your password reset link! Please check your mail inbox.', showConfirmButton: false, timer: 1500 }) // await router.push({ name: 'admin.index' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => processing.value = false) } const submitResetPassword = async () => { if (processing.value) return processing.value = true validationErrors.value = {} await axios.post('/api/reset-password', resetForm) .then(async response => { swal({ icon: 'success', title: 'Password successfully changed.', showConfirmButton: false, timer: 1500 }) await router.push({ name: 'auth.login' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => processing.value = false) } const loginUser = () => { user = authStore.user // Cookies.set('loggedIn', true) getAbilities() } const getUser = async () => { if (authStore.authenticated) { await authStore.getUser() await loginUser() } } const logout = async () => { if (processing.value) return processing.value = true axios.post('/logout') .then(response => { user.name = '' user.email = '' authStore.logout() router.push({ name: 'auth.login' }) }) .catch(error => { // swal({ // icon: 'error', // title: error.response.status, // text: error.response.statusText // }) }) .finally(() => { processing.value = false // Cookies.remove('loggedIn') }) } const getAbilities = async() => { await axios.get('/api/abilities') .then(response => { const permissions = response.data const { can, rules } = new AbilityBuilder(createMongoAbility) can(permissions) ability.update(rules) }) } return { loginForm, registerForm, forgotForm, resetForm, validationErrors, processing, submitLogin, submitRegister, submitForgotPassword, submitResetPassword, user, getUser, logout, getAbilities } } ================================================ FILE: resources/js/composables/categories.js ================================================ import { ref, inject } from 'vue' import { useRouter } from 'vue-router' export default function useCategories() { const categories = ref([]) const categoryList = ref([]) const category = ref({ name: '' }) const router = useRouter() const validationErrors = ref({}) const isLoading = ref(false) const swal = inject('$swal') const getCategories = async ( page = 1, search_id = '', search_title = '', search_global = '', order_column = 'created_at', order_direction = 'desc' ) => { axios.get('/api/categories?page=' + page + '&search_id=' + search_id + '&search_title=' + search_title + '&search_global=' + search_global + '&order_column=' + order_column + '&order_direction=' + order_direction) .then(response => { categories.value = response.data; }) } const getCategory = async (id) => { axios.get('/api/categories/' + id) .then(response => { category.value = response.data.data; }) } const storeCategory = async (category) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} axios.post('/api/categories', category) .then(response => { router.push({name: 'categories.index'}) swal({ icon: 'success', title: 'Category saved successfully' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => isLoading.value = false) } const updateCategory = async (category) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} axios.put('/api/categories/' + category.id, category) .then(response => { router.push({name: 'categories.index'}) swal({ icon: 'success', title: 'Category updated successfully' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => isLoading.value = false) } const deleteCategory = async (id) => { swal({ title: 'Are you sure?', text: 'You won\'t be able to revert this action!', icon: 'warning', showCancelButton: true, confirmButtonText: 'Yes, delete it!', confirmButtonColor: '#ef4444', timer: 20000, timerProgressBar: true, reverseButtons: true }) .then(result => { if (result.isConfirmed) { axios.delete('/api/categories/' + id) .then(response => { getCategories() router.push({name: 'categories.index'}) swal({ icon: 'success', title: 'Category deleted successfully' }) }) .catch(error => { swal({ icon: 'error', title: 'Something went wrong' }) }) } }) } const getCategoryList = async () => { axios.get('/api/category-list') .then(response => { categoryList.value = response.data.data; }) } return { categoryList, categories, category, getCategories, getCategoryList, getCategory, storeCategory, updateCategory, deleteCategory, validationErrors, isLoading } } ================================================ FILE: resources/js/composables/permissions.js ================================================ import { ref, inject,markRaw } from 'vue' import { useRouter } from 'vue-router' export default function usePermissions() { const permissions = ref([]) const allPermission = ref([]) const permission = ref({ name: '' }) const router = useRouter() const validationErrors = ref({}) const isLoading = ref(false) const swal = inject('$swal') const getPermissions = async ( page = 1, search_id = '', search_title = '', search_global = '', order_column = 'created_at', order_direction = 'desc' ) => { axios.get('/api/permissions?page=' + page + '&search_id=' + search_id + '&search_title=' + search_title + '&search_global=' + search_global + '&order_column=' + order_column + '&order_direction=' + order_direction) .then(response => { permissions.value = response.data; }) } const getAllPermissions = async () => { axios.get('/api/permissions/') .then(response => { allPermission.value = response.data.data; }) } const getPermission = async (id) => { axios.get('/api/permissions/' + id) .then(response => { permission.value = response.data.data; }) } const storePermission = async (permission) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} axios.post('/api/permissions', permission) .then(response => { router.push({name: 'permissions.index'}) swal({ icon: 'success', title: 'Permission saved successfully' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => isLoading.value = false) } const updatePermission = async (permission) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} axios.put('/api/permissions/' + permission.id, permission) .then(response => { router.push({name: 'permissions.index'}) swal({ icon: 'success', title: 'Permission updated successfully' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => isLoading.value = false) } const deletePermission = async (id) => { swal({ title: 'Are you sure?', text: 'You won\'t be able to revert this action!', icon: 'warning', showCancelButton: true, confirmButtonText: 'Yes, delete it!', confirmButtonColor: '#ef4444', timer: 20000, timerProgressBar: true, reverseButtons: true }) .then(result => { if (result.isConfirmed) { axios.delete('/api/permissions/' + id) .then(response => { getRoles() router.push({name: 'permissions.index'}) swal({ icon: 'success', title: 'Permission deleted successfully' }) }) .catch(error => { swal({ icon: 'error', title: 'Something went wrong' }) }) } }) } return { permissions, allPermission, permission, getAllPermissions, getPermissions, getPermission, storePermission, updatePermission, deletePermission, validationErrors, isLoading } } ================================================ FILE: resources/js/composables/posts.js ================================================ import { ref, inject } from 'vue' import { useRouter } from 'vue-router' export default function usePosts() { const posts = ref({}) const post = ref({ title: '', content: '', category_id: '', thumbnail: '' }) const router = useRouter() const validationErrors = ref({}) const isLoading = ref(false) const swal = inject('$swal') const getPosts = async ( page = 1, search_category = '', search_id = '', search_title = '', search_content = '', search_global = '', order_column = 'created_at', order_direction = 'desc' ) => { axios.get('/api/posts?page=' + page + '&search_category=' + search_category + '&search_id=' + search_id + '&search_title=' + search_title + '&search_content=' + search_content + '&search_global=' + search_global + '&order_column=' + order_column + '&order_direction=' + order_direction) .then(response => { posts.value = response.data; }) } const getPost = async (id) => { axios.get('/api/posts/' + id) .then(response => { post.value = response.data.data; }) } const storePost = async (post) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} let serializedPost = new FormData() for (let item in post) { if (post.hasOwnProperty(item)) { serializedPost.append(item, post[item]) } } axios.post('/api/posts', serializedPost,{ headers: { "content-type": "multipart/form-data" } }) .then(response => { router.push({name: 'posts.index'}) swal({ icon: 'success', title: 'Post saved successfully' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => isLoading.value = false) } const updatePost = async (post) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} axios.put('/api/posts/' + post.id, post) .then(response => { router.push({name: 'posts.index'}) swal({ icon: 'success', title: 'Post updated successfully' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => isLoading.value = false) } const deletePost = async (id) => { swal({ title: 'Are you sure?', text: 'You won\'t be able to revert this action!', icon: 'warning', showCancelButton: true, confirmButtonText: 'Yes, delete it!', confirmButtonColor: '#ef4444', timer: 20000, timerProgressBar: true, reverseButtons: true }) .then(result => { if (result.isConfirmed) { axios.delete('/api/posts/' + id) .then(response => { getPosts() router.push({name: 'posts.index'}) swal({ icon: 'success', title: 'Post deleted successfully' }) }) .catch(error => { swal({ icon: 'error', title: 'Something went wrong' }) }) } }) } return { posts, post, getPosts, getPost, storePost, updatePost, deletePost, validationErrors, isLoading } } ================================================ FILE: resources/js/composables/profile.js ================================================ import { ref, inject } from 'vue' import { useRouter } from 'vue-router' import {useAuthStore} from "@/store/auth"; export default function useProfile() { const profile = ref({ name: '', email: '', }) const store = useAuthStore() const router = useRouter() const validationErrors = ref({}) const isLoading = ref(false) const swal = inject('$swal') const getProfile = async () => { profile.value = store.user // axios.get('/api/user') // .then(({data}) => { // profile.value = data.data; // }) } const updateProfile = async (profile) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} axios.put('/api/user', profile) .then(({data}) => { if (data.success) { store.user = data.data // router.push({name: 'profile.index'}) swal({ icon: 'success', title: 'Profile updated successfully' }) } }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => isLoading.value = false) } return { profile, getProfile, updateProfile, validationErrors, isLoading } } ================================================ FILE: resources/js/composables/roles.js ================================================ import {ref, inject} from 'vue' import {useRouter} from 'vue-router' export default function useRoles() { const roles = ref([]) const role = ref({ name: '' }) const roleList = ref([]) const rolePermissionList = ref([]) const router = useRouter() const validationErrors = ref({}) const isLoading = ref(false) const swal = inject('$swal') const getRoles = async ( page = 1, search_id = '', search_title = '', search_global = '', order_column = 'created_at', order_direction = 'desc' ) => { axios.get('/api/roles?page=' + page + '&search_id=' + search_id + '&search_title=' + search_title + '&search_global=' + search_global + '&order_column=' + order_column + '&order_direction=' + order_direction) .then(response => { roles.value = response.data; }) } const getRole = async (id) => { axios.get('/api/roles/' + id) .then(response => { role.value = response.data.data; }) } const getRolePermissions = async (id) => { axios.get('/api/role-permissions/' + id) .then(response => { rolePermissionList.value = response.data.data; }) } const storeRole = async (role) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} axios.post('/api/roles', role) .then(response => { router.push({name: 'roles.index'}) swal({ icon: 'success', title: 'Role saved successfully' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => isLoading.value = false) } const updateRole = async (role) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} axios.put('/api/roles/' + role.id, role) .then(response => { router.push({name: 'roles.index'}) swal({ icon: 'success', title: 'Role updated successfully' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => isLoading.value = false) } const updateRolePermissions = async (role, permissions) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} axios.put('/api/role-permissions', {permissions: JSON.stringify(permissions), role_id: role.id}) // .then(response => { // router.push({name: 'roles.index'}) // swal({ // icon: 'success', // title: 'Role updated successfully' // }) // }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => { isLoading.value = false updateRole(role) }) } const deleteRole = async (id) => { swal({ title: 'Are you sure?', text: 'You won\'t be able to revert this action!', icon: 'warning', showCancelButton: true, confirmButtonText: 'Yes, delete it!', confirmButtonColor: '#ef4444', timer: 20000, timerProgressBar: true, reverseButtons: true }) .then(result => { if (result.isConfirmed) { axios.delete('/api/roles/' + id) .then(response => { getRoles() router.push({name: 'roles.index'}) swal({ icon: 'success', title: 'Role deleted successfully' }) }) .catch(error => { swal({ icon: 'error', title: 'Something went wrong' }) }) } }) } const getRoleList = async () => { axios.get('/api/role-list') .then(response => { roleList.value = response.data.data; }) } return { roles, role, roleList, getRoleList, getRoles, rolePermissionList, getRolePermissions, getRole, storeRole, updateRole, updateRolePermissions, deleteRole, validationErrors, isLoading } } ================================================ FILE: resources/js/composables/users.js ================================================ import { ref, inject } from 'vue' import { useRouter } from 'vue-router' export default function useUsers() { const users = ref([]) const user = ref({ name: '' }) const router = useRouter() const validationErrors = ref({}) const isLoading = ref(false) const swal = inject('$swal') const getUsers = async ( page = 1, search_id = '', search_title = '', search_global = '', order_column = 'created_at', order_direction = 'desc' ) => { axios.get('/api/users?page=' + page + '&search_id=' + search_id + '&search_title=' + search_title + '&search_global=' + search_global + '&order_column=' + order_column + '&order_direction=' + order_direction) .then(response => { users.value = response.data; }) } const getUser = async (id) => { axios.get('/api/users/' + id) .then(response => { user.value = response.data.data; }) } const storeUser = async (user) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} let serializedPost = new FormData() for (let item in user) { if (user.hasOwnProperty(item)) { serializedPost.append(item, user[item]) } } axios.post('/api/users', serializedPost) .then(response => { router.push({name: 'users.index'}) swal({ icon: 'success', title: 'User saved successfully' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => isLoading.value = false) } const updateUser = async (user) => { if (isLoading.value) return; isLoading.value = true validationErrors.value = {} axios.put('/api/users/' + user.id, user) .then(response => { router.push({name: 'users.index'}) swal({ icon: 'success', title: 'User updated successfully' }) }) .catch(error => { if (error.response?.data) { validationErrors.value = error.response.data.errors } }) .finally(() => isLoading.value = false) } const deleteUser = async (id) => { swal({ title: 'Are you sure?', text: 'You won\'t be able to revert this action!', icon: 'warning', showCancelButton: true, confirmButtonText: 'Yes, delete it!', confirmButtonColor: '#ef4444', timer: 20000, timerProgressBar: true, reverseButtons: true }) .then(result => { if (result.isConfirmed) { axios.delete('/api/users/' + id) .then(response => { getUsers() router.push({name: 'users.index'}) swal({ icon: 'success', title: 'User deleted successfully' }) }) .catch(error => { swal({ icon: 'error', title: 'Something went wrong' }) }) } }) } return { users, user, getUsers, getUser, storeUser, updateUser, deleteUser, validationErrors, isLoading } } ================================================ FILE: resources/js/lang/bn.json ================================================ { "welcome_starter_title": "Laravel Vue 3 Starter-এ স্বাগতম", "ok": "Ok", "cancel": "Cancel" } ================================================ FILE: resources/js/lang/en.json ================================================ { "welcome_starter_title": "Welcome to Laravel Vue 3 Boilerplate", "ok": "Ok", "cancel": "Cancel", "error_alert_title": "Oops...", "error_alert_text": "Something went wrong! Please try again.", "token_expired_alert_title": "Session Expired!", "token_expired_alert_text": "Please log in again to continue.", "login": "Log In", "register": "Register", "page_not_found": "Page Not Found", "go_home": "Go Home", "logout": "Logout", "email": "Email", "remember_me": "Remember Me", "password": "Password", "forgot_password": "Forgot Your Password?", "confirm_password": "Confirm Password", "name": "Name", "toggle_navigation": "Toggle navigation", "home": "Home", "you_are_logged_in": "You are logged in!", "reset_password": "Reset Password", "send_password_reset_link": "Send Password Reset Link", "settings": "Settings", "profile": "Profile", "your_info": "Your Info", "info_updated": "Your info has been updated!", "update": "Update", "your_password": "Your Password", "password_updated": "Your password has been updated!", "new_password": "New Password", "login_with": "Login with", "register_with": "Register with", "verify_email": "Verify Email", "send_verification_link": "Send Verification Link", "resend_verification_link": "Resend Verification Link ?", "failed_to_verify_email": "Failed to verify email.", "verify_email_address": "We sent you an email with an the verification link.", "verify_your_email_address": "Verify Your Email Address", "fresh_verification_link_sent": "A fresh verification link has been sent to your email address.", "before_proceeding_check_email": "Before proceeding, please check your email for a verification link.", "if_you_did_not_receive_the_email": "If you did not receive the email", "click_here_to_request_another": "click here to request another", "verifying_email": "Verifying your email...", "email_verified_successfully": "Your email has been verified successfully!", "redirecting_to_dashboard": "Redirecting to dashboard...", "verification_link_invalid": "The verification link is invalid or has expired." } ================================================ FILE: resources/js/lang/es.json ================================================ { "welcome_starter_title": "Bienvenido a Laravel Vue 3 Starter", "ok": "De Acuerdo", "cancel": "Cancelar", "error_alert_title": "Ha ocurrido un problema", "error_alert_text": "¡Algo salió mal! Inténtalo de nuevo.", "token_expired_alert_title": "!Sesión Expirada!", "token_expired_alert_text": "Por favor inicie sesión de nuevo para continuar.", "login": "Iniciar Sesión", "register": "Registro", "page_not_found": "Página No Encontrada", "go_home": "Ir a Inicio", "logout": "Cerrar Sesión", "email": "Correo Electrónico", "remember_me": "Recuérdame", "password": "Contraseña", "forgot_password": "¿Olvidaste tu contraseña?", "confirm_password": "Confirmar Contraseña", "name": "Nombre", "toggle_navigation": "Cambiar Navegación", "home": "Inicio", "you_are_logged_in": "¡Has iniciado sesión!", "reset_password": "Restablecer la contraseña", "send_password_reset_link": "Enviar Enlace de Restablecimiento de Contraseña", "settings": "Configuraciones", "profile": "Perfil", "your_info": "Tu Información", "info_updated": "¡Tu información ha sido actualizada!", "update": "Actualizar", "your_password": "Tu Contraseña", "password_updated": "¡Tu contraseña ha sido actualizada!", "new_password": "Nueva Contraseña", "login_with": "Iniciar Sesión con", "register_with": "Registro con" } ================================================ FILE: resources/js/lang/fr.json ================================================ { "welcome_starter_title": "Bienvenue dans Laravel Vue 3 Starter", "ok": "Ok", "cancel": "Annuler", "error_alert_title": "Oups...", "error_alert_text": "Quelque chose a mal tourné ! Veuillez réessayer.", "token_expired_alert_title": "Session expirée !", "token_expired_alert_text": "Veuillez vous reconnecter pour continuer.", "login": "Connexion", "register": "Inscription", "page_not_found": "Page non trouvée", "go_home": "Retour à l'accueil", "logout": "Déconnexion", "email": "Email", "remember_me": "Se souvenir de moi", "password": "Mot de passe", "forgot_password": "Vous avez oublié votre mot de passe ?", "confirm_password": "Confirmer le mot de passe", "name": "Nom", "toggle_navigation": "Basculer la navigation", "home": "Accueil", "you_are_logged_in": "Vous êtes connecté !", "reset_password": "Réinitialisation du mot de passe", "send_password_reset_link": "Envoyer le lien de réinitialisation du mot de passe", "settings": "Paramètres", "profile": "Profil", "your_info": "Vos informations", "info_updated": "Vos informations ont été mises à jour !", "update": "Mettre à jour", "your_password": "Votre mot de passe", "password_updated": "Votre mot de passe a été mis à jour !", "new_password": "Nouveau mot de passe", "login_with": "Connectez-vous avec", "register_with": "S'inscrire avec", "verify_email": "Vérifier l'e-mail", "send_verification_link": "Envoyer le lien de vérification", "resend_verification_link": "Renvoyer le lien de vérification ?", "failed_to_verify_email": "Nous n'avons pas réussi à vérifier votre email.", "verify_email_address": "Nous vous avons envoyé un e-mail avec un lien de vérification.", "verify_your_email_address": "Verify Your Email Address", "fresh_verification_link_sent": "A fresh verification link has been sent to your email address.", "before_proceeding_check_email": "Before proceeding, please check your email for a verification link.", "if_you_did_not_receive_the_email": "If you did not receive the email", "click_here_to_request_another": "click here to request another", "verifying_email": "Verifying your email...", "email_verified_successfully": "Your email has been verified successfully!", "redirecting_to_dashboard": "Redirecting to dashboard...", "verification_link_invalid": "The verification link is invalid or has expired." } ================================================ FILE: resources/js/lang/pt-BR.json ================================================ { "welcome_starter_title": "Bem-vindo ao Laravel Vue 3 Starter", "ok": "Ok", "cancel": "Cancelar", "error_alert_title": "Oops...", "error_alert_text": "Algo deu errado! Por favor, tente novamente.", "token_expired_alert_title": "Sessão expirada!", "token_expired_alert_text": "Faça login novamente para continuar.", "login": "Entrar", "register": "Cadastrar", "page_not_found": "Página não encontrada", "go_home": "Inicio", "logout": "Sair", "email": "Email", "remember_me": "Lembre-me", "password": "Senha", "forgot_password": "Esqueceu sua senha?", "confirm_password": "Confirmar Senha", "name": "Nome", "toggle_navigation": "Alternar de navegação", "home": "Inicio", "you_are_logged_in": "Você está logado!", "reset_password": "Trocar Senha", "send_password_reset_link": "Enviar link de redefinição de senha", "settings": "Configurações", "profile": "Perfil", "your_info": "Suas informações", "info_updated": "Suas informações foram atualizadas!", "update": "Atualizar", "your_password": "Sua senha", "password_updated": "Sua senha foi atualizada!", "new_password": "Nova Senha", "login_with": "Entrar", "register_with": "Registre-se", "verify_email": "verificar email", "send_verification_link": "Enviar link de verificação", "resend_verification_link": "Reenviar link de verificação?", "failed_to_verify_email": "Falha ao verificar o email.", "verify_email_address": "Enviamos um e-mail com o link de verificação.", "verify_your_email_address": "Verify Your Email Address", "fresh_verification_link_sent": "A fresh verification link has been sent to your email address.", "before_proceeding_check_email": "Before proceeding, please check your email for a verification link.", "if_you_did_not_receive_the_email": "If you did not receive the email", "click_here_to_request_another": "click here to request another", "verifying_email": "Verifying your email...", "email_verified_successfully": "Your email has been verified successfully!", "redirecting_to_dashboard": "Redirecting to dashboard...", "verification_link_invalid": "The verification link is invalid or has expired." } ================================================ FILE: resources/js/lang/zh-CN.json ================================================ { "welcome_starter_title": "欢迎来到Laravel Vue 3入门版", "ok": "确定", "cancel": "取消", "error_alert_title": "错误...", "error_alert_text": "遇到一些错误,请稍后重试~", "token_expired_alert_title": "验证过期!", "token_expired_alert_text": "请稍后重新登录系统", "login": "登录", "register": "注册", "page_not_found": "页面不存在", "go_home": "返回首页", "logout": "退出", "email": "邮箱", "remember_me": "记住我", "password": "密码", "forgot_password": "忘记密码?", "confirm_password": "重复密码", "name": "用户名", "toggle_navigation": "切换导航", "home": "首页", "you_are_logged_in": "您已经登录!", "reset_password": "重置密码", "send_password_reset_link": "发送重置链接", "settings": "设置", "profile": "个人设置", "your_info": "您的个人信息", "info_updated": "您的个人信息已经更改!", "update": "更新", "your_password": "您的密码", "password_updated": "您的密码已经更新!", "new_password": "新密码", "login_with": "登录", "register_with": "注册" } ================================================ FILE: resources/js/layouts/Admin.vue ================================================ ================================================ FILE: resources/js/layouts/Authenticated.vue ================================================ ================================================ FILE: resources/js/layouts/Error.vue ================================================ ================================================ FILE: resources/js/layouts/Guest.vue ================================================ ================================================ FILE: resources/js/plugins/i18n.js ================================================ import {createI18n} from 'vue-i18n' import {useLangStore} from "@/store/lang"; const i18n = createI18n({ legacy: false, // you must set `false`, to use Composition API globalInjection: true, runtimeOnly: false, locale: 'en', // set locale fallbackLocale: 'en', // set fallback locale messages: {} // set locale messages }) /** * @param {String} locale */ export async function loadMessages(locale) { if (Object.keys(i18n.global.getLocaleMessage(locale)).length === 0) { const messages = await import(/* webpackChunkName: '' */ `../lang/${locale}.json`); i18n.global.setLocaleMessage(locale, messages); } if (i18n.locale !== locale) { i18n.locale = locale i18n.global.locale.value = locale; } } (async () => { try { // Load initial locale message (e.g., 'en') await loadMessages('en'); const store = await useLangStore(); const { langLocale } = store; // Update messages based on store locale if (langLocale !== i18n.locale) { await loadMessages(langLocale); } } catch (error) { console.error('Error loading messages:', error); } })(); export default i18n; ================================================ FILE: resources/js/routes/index.js ================================================ import { createRouter, createWebHistory } from "vue-router"; import routes from './routes.js' const router = createRouter({ history: createWebHistory(), routes }) /*router.beforeEach((to, from, next) => { if (store.getters.user) { if (to.matched.some(route => route.meta.guard === 'guest')) next({ name: 'home' }) else next(); } else { if (to.matched.some(route => route.meta.guard === 'auth')) next({ name: 'login' }) else next(); } })*/ export default router; ================================================ FILE: resources/js/routes/routes.js ================================================ import {useAuthStore} from "@/store/auth"; const AuthenticatedLayout = () => import('../layouts/Authenticated.vue') const GuestLayout = () => import('../layouts/Guest.vue'); const PostsIndex = () => import('../views/admin/posts/Index.vue'); const PostsCreate = () => import('../views/admin/posts/Create.vue'); const PostsEdit = () => import('../views/admin/posts/Edit.vue'); function requireLogin(to, from, next) { const auth = useAuthStore() let isLogin = false; isLogin = !!auth.authenticated; if (isLogin) { next() } else { next('/login') } } function guest(to, from, next) { const auth = useAuthStore() let isLogin; isLogin = !!auth.authenticated; if (isLogin) { next('/') } else { next() } } export default [ { path: '/', // redirect: { name: 'login' }, component: GuestLayout, children: [ { path: '/', name: 'home', component: () => import('../views/home/index.vue'), }, { path: 'posts', name: 'public-posts.index', component: () => import('../views/posts/index.vue'), }, { path: 'posts/:id', name: 'public-posts.details', component: () => import('../views/posts/details.vue'), }, { path: 'category/:id', name: 'category-posts.index', component: () => import('../views/category/posts.vue'), }, { path: 'login', name: 'auth.login', component: () => import('../views/login/Login.vue'), beforeEnter: guest, }, { path: 'register', name: 'auth.register', component: () => import('../views/register/index.vue'), beforeEnter: guest, }, { path: 'forgot-password', name: 'auth.forgot-password', component: () => import('../views/auth/passwords/Email.vue'), beforeEnter: guest, }, { path: 'reset-password/:token', name: 'auth.reset-password', component: () => import('../views/auth/passwords/Reset.vue'), beforeEnter: guest, }, { path: 'verify', name: 'auth.verify', component: () => import('../views/auth/Verify.vue'), }, { path: 'email/verify/:id/:hash', name: 'auth.verify-email', component: () => import('../views/auth/Verify.vue'), // beforeEnter: requireLogin, }, ] }, { path: '/admin', component: AuthenticatedLayout, // redirect: { // name: 'admin.index' // }, beforeEnter: requireLogin, children: [ { name: 'admin.index', path: '', component: () => import('../views/admin/index.vue'), meta: { breadCrumb: 'Admin' } }, { name: 'profile.index', path: 'profile', component: () => import('../views/admin/profile/index.vue'), meta: { breadCrumb: 'Profile' } }, { name: 'posts.index', path: 'posts', component: PostsIndex, meta: { breadCrumb: 'Posts' } }, { name: 'posts.create', path: 'posts/create', component: PostsCreate, meta: { breadCrumb: 'Add new post' } }, { name: 'posts.edit', path: 'posts/edit/:id', component: PostsEdit, meta: { breadCrumb: 'Edit post' } }, { name: 'categories.index', path: 'categories', component: () => import('../views/admin/categories/Index.vue'), meta: { breadCrumb: 'Categories' } }, { name: 'categories.create', path: 'categories/create', component: () => import('../views/admin/categories/Create.vue'), meta: { breadCrumb: 'Add new category' } }, { name: 'categories.edit', path: 'categories/edit/:id', component: () => import('../views/admin/categories/Edit.vue'), meta: { breadCrumb: 'Edit Category' } }, { name: 'permissions.index', path: 'permissions', component: () => import('../views/admin/permissions/Index.vue'), meta: { breadCrumb: 'Permissions' } }, { name: 'permissions.create', path: 'permissions/create', component: () => import('../views/admin/permissions/Create.vue'), meta: { breadCrumb: 'Create Permission' } }, { name: 'permissions.edit', path: 'permissions/edit/:id', component: () => import('../views/admin/permissions/Edit.vue'), meta: { breadCrumb: 'Permission Edit' } }, { name: 'roles.index', path: 'roles', component: () => import('../views/admin/roles/Index.vue'), meta: { breadCrumb: 'Roles' } }, { name: 'roles.create', path: 'roles/create', component: () => import('../views/admin/roles/Create.vue'), meta: { breadCrumb: 'Create Role' } }, { name: 'roles.edit', path: 'roles/edit/:id', component: () => import('../views/admin/roles/Edit.vue'), meta: { breadCrumb: 'Role Edit' } }, { name: 'users.index', path: 'users', component: () => import('../views/admin/users/Index.vue'), meta: { breadCrumb: 'Users' } }, { name: 'users.create', path: 'users/create', component: () => import('../views/admin/users/Create.vue'), meta: { breadCrumb: 'Add New' } }, { name: 'users.edit', path: 'users/edit/:id', component: () => import('../views/admin/users/Edit.vue'), meta: { breadCrumb: 'User Edit' } }, { name: 'browser_sessions.index', path: 'browser-sessions', component: () => import('../views/admin/browser-sessions/Index.vue'), meta: { breadCrumb: 'Browser Sessions' } }, { name: 'activity_log.index', path: 'activity-log-logs', component: () => import('../views/admin/activity-log/Index.vue'), meta: { breadCrumb: 'Activity Logs' } }, ] }, { path: "/:pathMatch(.*)*", name: 'NotFound', component: () => import("../views/errors/404.vue"), }, ]; ================================================ FILE: resources/js/services/ability.js ================================================ import { AbilityBuilder, createMongoAbility } from '@casl/ability' const { can, cannot, build } = new AbilityBuilder(createMongoAbility); export default build(); ================================================ FILE: resources/js/store/auth.js ================================================ import {defineStore} from 'pinia' import axios from 'axios'; import {ref} from "vue"; export const useAuthStore = defineStore('auth', () => { const authenticated = ref(false) const user = ref({}) const login = (() => { return axios.get('/api/user').then(({data}) => { user.value = data authenticated.value = true }).catch(({res}) => { user.value = {} authenticated.value = false }) }) const getUser = (() => { return axios.get('/api/user').then(({data}) => { if (data.success) { user.value = data.data authenticated.value = true // router.push({name: 'dashboard'}) } else { user.value = {} authenticated.value = false } }).catch(({res}) => { user.value = {} authenticated.value = false }) }) const logout = (() => { user.value = {} authenticated.value = false }) return {authenticated, user, login, getUser, logout} }, { persist: true }) ================================================ FILE: resources/js/store/lang.js ================================================ import Cookies from 'js-cookie' import {defineStore} from "pinia"; import {ref} from "vue"; export const useLangStore = defineStore('lang', () => { const { locale, locales } = window.config const langLocale = ref(getLocale(locales, locale)) const langLocales = locales const setLocale = (newLocale) => { langLocale.value = newLocale Cookies.set('locale', newLocale, { expires: 365 }) } return { langLocale, langLocales, setLocale } }, { persist: true }) /** * @param {String[]} locales * @param {String} fallback * @return {String} */ function getLocale (locales, fallback) { const locale = Cookies.get('locale') if (Object.prototype.hasOwnProperty.call(locales, locale)) { return locale } else if (locale) { Cookies.remove('locale') } return fallback } ================================================ FILE: resources/js/validation/rules.js ================================================ const required = (value, args, { field }) => { if (!value) { return `The ${field} field is required.` } return true } const email = (value, args, { field }) => { if (!value) { return `The ${field} field is required.` } return true } const min = (value, [limit], { field }) => { if (!value || !value.length) { return true } if (value.length < limit) { return `The ${field} must be at least ${limit} characters.` } return true } export { required, min, email } ================================================ FILE: resources/js/views/admin/activity-log/Index.vue ================================================ ================================================ FILE: resources/js/views/admin/browser-sessions/Index.vue ================================================ ================================================ FILE: resources/js/views/admin/categories/Create.vue ================================================ ================================================ FILE: resources/js/views/admin/categories/Edit.vue ================================================ ================================================ FILE: resources/js/views/admin/categories/Index.vue ================================================ ================================================ FILE: resources/js/views/admin/index.vue ================================================ ================================================ FILE: resources/js/views/admin/permissions/Create.vue ================================================ ================================================ FILE: resources/js/views/admin/permissions/Edit.vue ================================================ ================================================ FILE: resources/js/views/admin/permissions/Index.vue ================================================ ================================================ FILE: resources/js/views/admin/posts/Create.vue ================================================ ================================================ FILE: resources/js/views/admin/posts/Edit.vue ================================================ ================================================ FILE: resources/js/views/admin/posts/Index.vue ================================================ ================================================ FILE: resources/js/views/admin/profile/index.vue ================================================ ================================================ FILE: resources/js/views/admin/roles/Create.vue ================================================ ================================================ FILE: resources/js/views/admin/roles/Edit.vue ================================================ ================================================ FILE: resources/js/views/admin/roles/Index.vue ================================================ ================================================ FILE: resources/js/views/admin/users/Create.vue ================================================ ================================================ FILE: resources/js/views/admin/users/Edit.vue ================================================ ================================================ FILE: resources/js/views/admin/users/Index.vue ================================================ ================================================ FILE: resources/js/views/auth/Verify.vue ================================================ ================================================ FILE: resources/js/views/auth/passwords/Confirm.vue ================================================ ================================================ FILE: resources/js/views/auth/passwords/Email.vue ================================================ ================================================ FILE: resources/js/views/auth/passwords/Reset.vue ================================================ ================================================ FILE: resources/js/views/category/posts.vue ================================================ ================================================ FILE: resources/js/views/errors/404.vue ================================================ ================================================ FILE: resources/js/views/home/index.vue ================================================ ================================================ FILE: resources/js/views/login/Login.vue ================================================ ================================================ FILE: resources/js/views/posts/details.vue ================================================ ================================================ FILE: resources/js/views/posts/index.vue ================================================ ================================================ FILE: resources/js/views/register/index.vue ================================================ ================================================ FILE: resources/sass/_custom.scss ================================================ .activity-timeline { position: relative; } .activity-item { padding: 1.5rem; border-radius: 12px; transition: all 0.3s ease; border: 1px solid rgba(0, 0, 0, 0.05); margin-bottom: 1rem; } .activity-item:hover { background-color: #f8f9fa; transform: translateX(5px); } .activity-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; color: white; } .activity-date { font-size: 0.85rem; color: #6c757d; } .activity-user img { width: 32px; height: 32px; border-radius: 50%; } .filter-badge { cursor: pointer; transition: all 0.3s ease; background-color: #ba9bc2; border: 1px solid rgba(0, 0, 0, 0.1); } .filter-badge:hover { background-color: #e9ecef; } .filter-badge.active { background-color: #0d6efd; color: white; } .search-box { border-radius: 10px; border: 1px solid rgba(0, 0, 0, 0.1); padding: 0.75rem 1rem; } .status-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 6px; } .bg-success-soft { background-color: #d1e7dd; } .bg-danger-soft { background-color: #f8d7da; } .bg-warning-soft { background-color: #fff3cd; } .bg-info-soft { background-color: #cff4fc; } ================================================ FILE: resources/sass/_variables.scss ================================================ // Body $body-bg: #f8fafc; // Typography $font-family-sans-serif: 'Nunito', sans-serif; $font-size-base: 0.9rem; $line-height-base: 1.6; ================================================ FILE: resources/sass/app.scss ================================================ // Fonts @import url('https://fonts.bunny.net/css?family=Nunito'); // Variables //@import 'variables'; // Bootstrap @import 'bootstrap/scss/bootstrap'; @import "custom"; body { background-color: #f0f2fc !important; } a { text-decoration: none !important; } ================================================ FILE: resources/views/auth/login.blade.php ================================================ @extends('layouts.app') @section('content')
{{ __('Login') }}
@csrf
@error('email') {{ $message }} @enderror
@error('password') {{ $message }} @enderror
@if (Route::has('password.request')) {{ __('Forgot Your Password?') }} @endif
@endsection ================================================ FILE: resources/views/auth/passwords/confirm.blade.php ================================================ @extends('layouts.app') @section('content')
{{ __('Confirm Password') }}
{{ __('Please confirm your password before continuing.') }}
@csrf
@error('password') {{ $message }} @enderror
@if (Route::has('password.request')) {{ __('Forgot Your Password?') }} @endif
@endsection ================================================ FILE: resources/views/auth/passwords/email.blade.php ================================================ @extends('layouts.app') @section('content')
{{ __('Reset Password') }}
@if (session('status')) @endif
@csrf
@error('email') {{ $message }} @enderror
@endsection ================================================ FILE: resources/views/auth/passwords/reset.blade.php ================================================ @extends('layouts.app') @section('content')
{{ __('Reset Password') }}
@csrf
@error('email') {{ $message }} @enderror
@error('password') {{ $message }} @enderror
@endsection ================================================ FILE: resources/views/auth/register.blade.php ================================================ @extends('layouts.app') @section('content')
{{ __('Register') }}
@csrf
@error('name') {{ $message }} @enderror
@error('email') {{ $message }} @enderror
@error('password') {{ $message }} @enderror
@endsection ================================================ FILE: resources/views/auth/verify.blade.php ================================================ @extends('layouts.app') @section('content')
{{ __('Verify Your Email Address') }}
@if (session('resent')) @endif {{ __('Before proceeding, please check your email for a verification link.') }} {{ __('If you did not receive the email') }},
@csrf .
@endsection ================================================ FILE: resources/views/home.blade.php ================================================ @extends('layouts.app') @section('content')
{{ __('Dashboard') }}
@if (session('status')) @endif {{ __('You are logged in!') }}
@endsection ================================================ FILE: resources/views/layouts/app.blade.php ================================================ {{ config('app.name', 'Laravel') }} @vite(['resources/sass/app.scss', 'resources/js/app.js'])
@yield('content')
================================================ FILE: resources/views/layouts/master.blade.php ================================================ {{ config('app.name', 'Laravel') }} @vite(['resources/sass/app.scss', 'resources/js/app.js'])
@yield('content')
================================================ FILE: resources/views/main-view.blade.php ================================================ @php $config = [ 'appName' => config('app.name'), 'locale' => $locale = app()->getLocale(), 'locales' => config('app.locales'), ]; @endphp Laravel Vue 3 Stater @vite(['resources/sass/app.scss', 'resources/js/app.js']) ================================================ FILE: resources/views/welcome.blade.php ================================================ Laravel
@if (Route::has('login')) @endif
Laravel has wonderful, thorough documentation covering every aspect of the framework. Whether you are new to the framework or have previous experience with Laravel, we recommend reading all of the documentation from beginning to end.
Laracasts offers thousands of video tutorials on Laravel, PHP, and JavaScript development. Check them out, see for yourself, and massively level up your development skills in the process.
Laravel News is a community driven portal and newsletter aggregating all of the latest and most important news in the Laravel ecosystem, including new package releases and tutorials.
Vibrant Ecosystem
Laravel's robust library of first-party tools and libraries, such as Forge, Vapor, Nova, and Envoyer help you take your projects to the next level. Pair them with powerful open source libraries like Cashier, Dusk, Echo, Horizon, Sanctum, Telescope, and more.
Laravel v{{ Illuminate\Foundation\Application::VERSION }} (PHP v{{ PHP_VERSION }})
================================================ FILE: routes/api.php ================================================ name('forget.password.post'); Route::post('reset-password', [ResetPasswordController::class, 'reset'])->name('password.reset'); // Email Verification Routes (API) Route::get('/email/verify/{id}/{hash}', [VerificationController::class, 'verify']) ->middleware(['auth:sanctum', \App\Http\Middleware\HandleInvalidSignature::class]) ->name('verification.verify'); Route::middleware('auth:sanctum')->group(function () { Route::post('/email/verification-notification', [VerificationController::class, 'resend']) ->middleware('throttle:6,1') ->name('verification.resend'); }); // Protected routes requiring authentication AND verified email // NOTE: Previous array syntax was incorrect: 'verified' was a stray element and ignored. Route::group(['middleware' => ['auth:sanctum','verified.api']], function() { Route::group(['middleware' => ['verified.api']], function() {}); Route::apiResource('users', UserController::class); Route::apiResource('posts', PostController::class); Route::apiResource('categories', CategoryController::class); Route::apiResource('roles', RoleController::class); Route::get('role-list', [RoleController::class, 'getList']); Route::get('role-permissions/{id}', [PermissionController::class, 'getRolePermissions']); Route::put('/role-permissions', [PermissionController::class, 'updateRolePermissions']); Route::apiResource('permissions', PermissionController::class); Route::get('category-list', [CategoryController::class, 'getList']); Route::get('/user', [ProfileController::class, 'user']); Route::put('/user', [ProfileController::class, 'update']); // Browser Sessions Route::get('browser-sessions', [BrowserSessionController::class, 'index']); Route::post('logout-other-devices', [BrowserSessionController::class, 'logoutOtherDevices']); // Activity log Route::get('activity-logs', ActivityLogController::class); Route::get('abilities', function(Request $request) { return $request->user()->roles()->with('permissions') ->get() ->pluck('permissions') ->flatten() ->pluck('name') ->unique() ->values() ->toArray(); }); }); Route::get('category-list', [CategoryController::class, 'getList']); Route::get('get-posts', [PostController::class, 'getPosts']); Route::get('get-category-posts/{id}', [PostController::class, 'getCategoryByPosts']); Route::get('get-post/{id}', [PostController::class, 'getPost']); ================================================ FILE: routes/channels.php ================================================ id === (int) $id; }); ================================================ FILE: routes/console.php ================================================ comment(Inspiring::quote()); })->purpose('Display an inspiring quote'); ================================================ FILE: routes/web.php ================================================ middleware(['signed', 'throttle:6,1']) ->name('verification.verify'); Route::post('/email/resend', [VerificationController::class, 'resend']) ->middleware(['throttle:6,1']) ->name('verification.resend');*/ //Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home'); Route::view('/{any?}', 'main-view') ->name('dashboard') ->where('any', '.*'); ================================================ FILE: storage/app/.gitignore ================================================ * !public/ !.gitignore ================================================ FILE: storage/framework/.gitignore ================================================ compiled.php config.php down events.scanned.php maintenance.php routes.php routes.scanned.php schedule-* services.json ================================================ FILE: storage/framework/cache/.gitignore ================================================ * !data/ !.gitignore ================================================ FILE: storage/framework/sessions/.gitignore ================================================ * !.gitignore ================================================ FILE: storage/framework/testing/.gitignore ================================================ * !.gitignore ================================================ FILE: storage/framework/views/.gitignore ================================================ * !.gitignore ================================================ FILE: storage/logs/.gitignore ================================================ * !.gitignore ================================================ FILE: tests/CreatesApplication.php ================================================ make(Kernel::class)->bootstrap(); return $app; } } ================================================ FILE: tests/Feature/ExampleTest.php ================================================ get('/'); $response->assertStatus(200); } } ================================================ FILE: tests/TestCase.php ================================================ assertTrue(true); } } ================================================ FILE: vite.config.js ================================================ import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import vue from '@vitejs/plugin-vue'; import path from 'path'; export default defineConfig({ plugins: [ laravel({ input: [ 'resources/sass/app.scss', 'resources/js/app.js', ], // reactivityTransform: true, refresh: true, }), vue({ template: { transformAssetUrls: { base: null, includeAbsolute: false, }, }, }), ], // build: { // chunkSizeWarningLimit: 1600, // }, resolve: { alias: { vue: 'vue/dist/vue.esm-bundler.js', '@': path.resolve(__dirname, './resources/js'), }, } }); ================================================ FILE: vue.config.js ================================================ module.exports = { // Delete the prefetch plugin chainWebpack: config => { config.plugins.delete('prefetch') } }