Sfoglia il codice sorgente

Inicializando proyecto

JGRL 4 giorni fa
commit
5dcdcaae37
100 ha cambiato i file con 11913 aggiunte e 0 eliminazioni
  1. 126 0
      dgonz/.gitignore
  2. 22 0
      dgonz/LICENSE
  3. 69 0
      dgonz/README.md
  4. 6 0
      dgonz/app/.htaccess
  5. 15 0
      dgonz/app/Common.php
  6. 202 0
      dgonz/app/Config/App.php
  7. 92 0
      dgonz/app/Config/Autoload.php
  8. 34 0
      dgonz/app/Config/Boot/development.php
  9. 25 0
      dgonz/app/Config/Boot/production.php
  10. 38 0
      dgonz/app/Config/Boot/testing.php
  11. 36 0
      dgonz/app/Config/CURLRequest.php
  12. 198 0
      dgonz/app/Config/Cache.php
  13. 79 0
      dgonz/app/Config/Constants.php
  14. 216 0
      dgonz/app/Config/ContentSecurityPolicy.php
  15. 107 0
      dgonz/app/Config/Cookie.php
  16. 105 0
      dgonz/app/Config/Cors.php
  17. 204 0
      dgonz/app/Config/Database.php
  18. 43 0
      dgonz/app/Config/DocTypes.php
  19. 126 0
      dgonz/app/Config/Email.php
  20. 109 0
      dgonz/app/Config/Encryption.php
  21. 57 0
      dgonz/app/Config/Events.php
  22. 106 0
      dgonz/app/Config/Exceptions.php
  23. 37 0
      dgonz/app/Config/Feature.php
  24. 110 0
      dgonz/app/Config/Filters.php
  25. 12 0
      dgonz/app/Config/ForeignCharacters.php
  26. 73 0
      dgonz/app/Config/Format.php
  27. 44 0
      dgonz/app/Config/Generators.php
  28. 42 0
      dgonz/app/Config/Honeypot.php
  29. 40 0
      dgonz/app/Config/Hostnames.php
  30. 33 0
      dgonz/app/Config/Images.php
  31. 63 0
      dgonz/app/Config/Kint.php
  32. 151 0
      dgonz/app/Config/Logger.php
  33. 65 0
      dgonz/app/Config/Migrations.php
  34. 534 0
      dgonz/app/Config/Mimes.php
  35. 82 0
      dgonz/app/Config/Modules.php
  36. 32 0
      dgonz/app/Config/Optimize.php
  37. 37 0
      dgonz/app/Config/Pager.php
  38. 90 0
      dgonz/app/Config/Paths.php
  39. 28 0
      dgonz/app/Config/Publisher.php
  40. 6 0
      dgonz/app/Config/Routes.php
  41. 149 0
      dgonz/app/Config/Routing.php
  42. 86 0
      dgonz/app/Config/Security.php
  43. 32 0
      dgonz/app/Config/Services.php
  44. 128 0
      dgonz/app/Config/Session.php
  45. 147 0
      dgonz/app/Config/Toolbar.php
  46. 262 0
      dgonz/app/Config/UserAgents.php
  47. 44 0
      dgonz/app/Config/Validation.php
  48. 73 0
      dgonz/app/Config/View.php
  49. 62 0
      dgonz/app/Config/WorkerMode.php
  50. 45 0
      dgonz/app/Controllers/BaseController.php
  51. 11 0
      dgonz/app/Controllers/Home.php
  52. 0 0
      dgonz/app/Database/Migrations/.gitkeep
  53. 0 0
      dgonz/app/Database/Seeds/.gitkeep
  54. 0 0
      dgonz/app/Filters/.gitkeep
  55. 0 0
      dgonz/app/Helpers/.gitkeep
  56. 0 0
      dgonz/app/Language/.gitkeep
  57. 4 0
      dgonz/app/Language/en/Validation.php
  58. 0 0
      dgonz/app/Libraries/.gitkeep
  59. 0 0
      dgonz/app/Models/.gitkeep
  60. 0 0
      dgonz/app/ThirdParty/.gitkeep
  61. 7 0
      dgonz/app/Views/errors/cli/error_404.php
  62. 65 0
      dgonz/app/Views/errors/cli/error_exception.php
  63. 5 0
      dgonz/app/Views/errors/cli/production.php
  64. 194 0
      dgonz/app/Views/errors/html/debug.css
  65. 116 0
      dgonz/app/Views/errors/html/debug.js
  66. 84 0
      dgonz/app/Views/errors/html/error_400.php
  67. 84 0
      dgonz/app/Views/errors/html/error_404.php
  68. 429 0
      dgonz/app/Views/errors/html/error_exception.php
  69. 25 0
      dgonz/app/Views/errors/html/production.php
  70. 209 0
      dgonz/app/Views/welcome_message.php
  71. 11 0
      dgonz/app/index.html
  72. 128 0
      dgonz/builds
  73. 43 0
      dgonz/composer.json
  74. 2118 0
      dgonz/composer.lock
  75. 69 0
      dgonz/env
  76. 64 0
      dgonz/phpunit.dist.xml
  77. 112 0
      dgonz/preload.php
  78. 49 0
      dgonz/public/.htaccess
  79. BIN
      dgonz/public/favicon.ico
  80. 39 0
      dgonz/public/frontend/.gitignore
  81. 42 0
      dgonz/public/frontend/README.md
  82. 1 0
      dgonz/public/frontend/env.d.ts
  83. 13 0
      dgonz/public/frontend/index.html
  84. 2986 0
      dgonz/public/frontend/package-lock.json
  85. 31 0
      dgonz/public/frontend/package.json
  86. BIN
      dgonz/public/frontend/public/favicon.ico
  87. 11 0
      dgonz/public/frontend/src/App.vue
  88. 9 0
      dgonz/public/frontend/src/main.ts
  89. 8 0
      dgonz/public/frontend/src/router/index.ts
  90. 18 0
      dgonz/public/frontend/tsconfig.app.json
  91. 11 0
      dgonz/public/frontend/tsconfig.json
  92. 27 0
      dgonz/public/frontend/tsconfig.node.json
  93. 18 0
      dgonz/public/frontend/vite.config.ts
  94. 59 0
      dgonz/public/index.php
  95. 2 0
      dgonz/public/robots.txt
  96. 87 0
      dgonz/spark
  97. 6 0
      dgonz/tests/.htaccess
  98. 118 0
      dgonz/tests/README.md
  99. 37 0
      dgonz/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php
  100. 41 0
      dgonz/tests/_support/Database/Seeds/ExampleSeeder.php

+ 126 - 0
dgonz/.gitignore

@@ -0,0 +1,126 @@
+#-------------------------
+# Operating Specific Junk Files
+#-------------------------
+
+# OS X
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# OS X Thumbnails
+._*
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+# Linux
+*~
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+#-------------------------
+# Environment Files
+#-------------------------
+# These should never be under version control,
+# as it poses a security risk.
+.env
+.vagrant
+Vagrantfile
+
+#-------------------------
+# Temporary Files
+#-------------------------
+/writable/cache/*
+!/writable/cache/index.html
+
+/writable/logs/*
+!/writable/logs/index.html
+
+/writable/session/*
+!/writable/session/index.html
+
+/writable/uploads/*
+!/writable/uploads/index.html
+
+/writable/debugbar/*
+!/writable/debugbar/index.html
+
+php_errors.log
+
+#-------------------------
+# User Guide Temp Files
+#-------------------------
+/user_guide_src/build/*
+/user_guide_src/cilexer/build/*
+/user_guide_src/cilexer/dist/*
+/user_guide_src/cilexer/pycilexer.egg-info/*
+
+#-------------------------
+# Test Files
+#-------------------------
+/tests/coverage*
+
+# Don't save phpunit under version control.
+/phpunit
+
+#-------------------------
+# Composer
+#-------------------------
+vendor/
+
+#-------------------------
+# IDE / Development Files
+#-------------------------
+
+# Modules Testing
+_modules/*
+
+# phpenv local config
+.php-version
+
+# Jetbrains editors (PHPStorm, etc)
+.idea/
+*.iml
+
+# NetBeans
+/nbproject/
+/build/
+/nbbuild/
+/dist/
+/nbdist/
+/nbactions.xml
+/nb-configuration.xml
+/.nb-gradle/
+
+# Sublime Text
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+*.sublime-workspace
+*.sublime-project
+.phpintel
+/api/
+
+# Visual Studio Code
+.vscode/
+
+/results/
+/phpunit.xml

+ 22 - 0
dgonz/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2014-2019 British Columbia Institute of Technology
+Copyright (c) 2019-present CodeIgniter Foundation
+
+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.

+ 69 - 0
dgonz/README.md

@@ -0,0 +1,69 @@
+# CodeIgniter 4 Application Starter
+
+## What is CodeIgniter?
+
+CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure.
+More information can be found at the [official site](https://codeigniter.com).
+
+This repository holds a composer-installable app starter.
+It has been built from the
+[development repository](https://github.com/codeigniter4/CodeIgniter4).
+
+More information about the plans for version 4 can be found in [CodeIgniter 4](https://forum.codeigniter.com/forumdisplay.php?fid=28) on the forums.
+
+You can read the [user guide](https://codeigniter.com/user_guide/)
+corresponding to the latest version of the framework.
+
+## Installation & updates
+
+`composer create-project codeigniter4/appstarter` then `composer update` whenever
+there is a new release of the framework.
+
+When updating, check the release notes to see if there are any changes you might need to apply
+to your `app` folder. The affected files can be copied or merged from
+`vendor/codeigniter4/framework/app`.
+
+## Setup
+
+Copy `env` to `.env` and tailor for your app, specifically the baseURL
+and any database settings.
+
+## Important Change with index.php
+
+`index.php` is no longer in the root of the project! It has been moved inside the *public* folder,
+for better security and separation of components.
+
+This means that you should configure your web server to "point" to your project's *public* folder, and
+not to the project root. A better practice would be to configure a virtual host to point there. A poor practice would be to point your web server to the project root and expect to enter *public/...*, as the rest of your logic and the
+framework are exposed.
+
+**Please** read the user guide for a better explanation of how CI4 works!
+
+## Repository Management
+
+We use GitHub issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages.
+We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss
+FEATURE REQUESTS.
+
+This repository is a "distribution" one, built by our release preparation script.
+Problems with it can be raised on our forum, or as issues in the main repository.
+
+## Server Requirements
+
+PHP version 8.2 or higher is required, with the following extensions installed:
+
+- [intl](http://php.net/manual/en/intl.requirements.php)
+- [mbstring](http://php.net/manual/en/mbstring.installation.php)
+
+> [!WARNING]
+> - The end of life date for PHP 7.4 was November 28, 2022.
+> - The end of life date for PHP 8.0 was November 26, 2023.
+> - The end of life date for PHP 8.1 was December 31, 2025.
+> - If you are still using below PHP 8.2, you should upgrade immediately.
+> - The end of life date for PHP 8.2 will be December 31, 2026.
+
+Additionally, make sure that the following extensions are enabled in your PHP:
+
+- json (enabled by default - don't turn it off)
+- [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) if you plan to use MySQL
+- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use the HTTP\CURLRequest library

+ 6 - 0
dgonz/app/.htaccess

@@ -0,0 +1,6 @@
+<IfModule authz_core_module>
+	Require all denied
+</IfModule>
+<IfModule !authz_core_module>
+	Deny from all
+</IfModule>

+ 15 - 0
dgonz/app/Common.php

@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * The goal of this file is to allow developers a location
+ * where they can overwrite core procedural functions and
+ * replace them with their own. This file is loaded during
+ * the bootstrap process and is called during the framework's
+ * execution.
+ *
+ * This can be looked at as a `master helper` file that is
+ * loaded early on, and may also contain additional functions
+ * that you'd like to use throughout your entire application
+ *
+ * @see: https://codeigniter.com/user_guide/extending/common.html
+ */

+ 202 - 0
dgonz/app/Config/App.php

@@ -0,0 +1,202 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class App extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Base Site URL
+     * --------------------------------------------------------------------------
+     *
+     * URL to your CodeIgniter root. Typically, this will be your base URL,
+     * WITH a trailing slash:
+     *
+     * E.g., http://example.com/
+     */
+    public string $baseURL = 'http://localhost:8080/';
+
+    /**
+     * Allowed Hostnames in the Site URL other than the hostname in the baseURL.
+     * If you want to accept multiple Hostnames, set this.
+     *
+     * E.g.,
+     * When your site URL ($baseURL) is 'http://example.com/', and your site
+     * also accepts 'http://media.example.com/' and 'http://accounts.example.com/':
+     *     ['media.example.com', 'accounts.example.com']
+     *
+     * @var list<string>
+     */
+    public array $allowedHostnames = [];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Index File
+     * --------------------------------------------------------------------------
+     *
+     * Typically, this will be your `index.php` file, unless you've renamed it to
+     * something else. If you have configured your web server to remove this file
+     * from your site URIs, set this variable to an empty string.
+     */
+    public string $indexPage = 'index.php';
+
+    /**
+     * --------------------------------------------------------------------------
+     * URI PROTOCOL
+     * --------------------------------------------------------------------------
+     *
+     * This item determines which server global should be used to retrieve the
+     * URI string. The default setting of 'REQUEST_URI' works for most servers.
+     * If your links do not seem to work, try one of the other delicious flavors:
+     *
+     *  'REQUEST_URI': Uses $_SERVER['REQUEST_URI']
+     * 'QUERY_STRING': Uses $_SERVER['QUERY_STRING']
+     *    'PATH_INFO': Uses $_SERVER['PATH_INFO']
+     *
+     * WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
+     */
+    public string $uriProtocol = 'REQUEST_URI';
+
+    /*
+    |--------------------------------------------------------------------------
+    | Allowed URL Characters
+    |--------------------------------------------------------------------------
+    |
+    | This lets you specify which characters are permitted within your URLs.
+    | When someone tries to submit a URL with disallowed characters they will
+    | get a warning message.
+    |
+    | As a security measure you are STRONGLY encouraged to restrict URLs to
+    | as few characters as possible.
+    |
+    | By default, only these are allowed: `a-z 0-9~%.:_-`
+    |
+    | Set an empty string to allow all characters -- but only if you are insane.
+    |
+    | The configured value is actually a regular expression character group
+    | and it will be used as: '/\A[<permittedURIChars>]+\z/iu'
+    |
+    | DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
+    |
+    */
+    public string $permittedURIChars = 'a-z 0-9~%.:_\-';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Default Locale
+     * --------------------------------------------------------------------------
+     *
+     * The Locale roughly represents the language and location that your visitor
+     * is viewing the site from. It affects the language strings and other
+     * strings (like currency markers, numbers, etc), that your program
+     * should run under for this request.
+     */
+    public string $defaultLocale = 'en';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Negotiate Locale
+     * --------------------------------------------------------------------------
+     *
+     * If true, the current Request object will automatically determine the
+     * language to use based on the value of the Accept-Language header.
+     *
+     * If false, no automatic detection will be performed.
+     */
+    public bool $negotiateLocale = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Supported Locales
+     * --------------------------------------------------------------------------
+     *
+     * If $negotiateLocale is true, this array lists the locales supported
+     * by the application in descending order of priority. If no match is
+     * found, the first locale will be used.
+     *
+     * IncomingRequest::setLocale() also uses this list.
+     *
+     * @var list<string>
+     */
+    public array $supportedLocales = ['en'];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Application Timezone
+     * --------------------------------------------------------------------------
+     *
+     * The default timezone that will be used in your application to display
+     * dates with the date helper, and can be retrieved through app_timezone()
+     *
+     * @see https://www.php.net/manual/en/timezones.php for list of timezones
+     *      supported by PHP.
+     */
+    public string $appTimezone = 'UTC';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Default Character Set
+     * --------------------------------------------------------------------------
+     *
+     * This determines which character set is used by default in various methods
+     * that require a character set to be provided.
+     *
+     * @see http://php.net/htmlspecialchars for a list of supported charsets.
+     */
+    public string $charset = 'UTF-8';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Force Global Secure Requests
+     * --------------------------------------------------------------------------
+     *
+     * If true, this will force every request made to this application to be
+     * made via a secure connection (HTTPS). If the incoming request is not
+     * secure, the user will be redirected to a secure version of the page
+     * and the HTTP Strict Transport Security (HSTS) header will be set.
+     */
+    public bool $forceGlobalSecureRequests = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Reverse Proxy IPs
+     * --------------------------------------------------------------------------
+     *
+     * If your server is behind a reverse proxy, you must whitelist the proxy
+     * IP addresses from which CodeIgniter should trust headers such as
+     * X-Forwarded-For or Client-IP in order to properly identify
+     * the visitor's IP address.
+     *
+     * You need to set a proxy IP address or IP address with subnets and
+     * the HTTP header for the client IP address.
+     *
+     * Here are some examples:
+     *     [
+     *         '10.0.1.200'     => 'X-Forwarded-For',
+     *         '192.168.5.0/24' => 'X-Real-IP',
+     *     ]
+     *
+     * @var array<string, string>
+     */
+    public array $proxyIPs = [];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Content Security Policy
+     * --------------------------------------------------------------------------
+     *
+     * Enables the Response's Content Secure Policy to restrict the sources that
+     * can be used for images, scripts, CSS files, audio, video, etc. If enabled,
+     * the Response object will populate default values for the policy from the
+     * `ContentSecurityPolicy.php` file. Controllers can always add to those
+     * restrictions at run time.
+     *
+     * For a better understanding of CSP, see these documents:
+     *
+     * @see http://www.html5rocks.com/en/tutorials/security/content-security-policy/
+     * @see http://www.w3.org/TR/CSP/
+     */
+    public bool $CSPEnabled = false;
+}

+ 92 - 0
dgonz/app/Config/Autoload.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\AutoloadConfig;
+
+/**
+ * -------------------------------------------------------------------
+ * AUTOLOADER CONFIGURATION
+ * -------------------------------------------------------------------
+ *
+ * This file defines the namespaces and class maps so the Autoloader
+ * can find the files as needed.
+ *
+ * NOTE: If you use an identical key in $psr4 or $classmap, then
+ *       the values in this file will overwrite the framework's values.
+ *
+ * NOTE: This class is required prior to Autoloader instantiation,
+ *       and does not extend BaseConfig.
+ */
+class Autoload extends AutoloadConfig
+{
+    /**
+     * -------------------------------------------------------------------
+     * Namespaces
+     * -------------------------------------------------------------------
+     * This maps the locations of any namespaces in your application to
+     * their location on the file system. These are used by the autoloader
+     * to locate files the first time they have been instantiated.
+     *
+     * The 'Config' (APPPATH . 'Config') and 'CodeIgniter' (SYSTEMPATH) are
+     * already mapped for you.
+     *
+     * You may change the name of the 'App' namespace if you wish,
+     * but this should be done prior to creating any namespaced classes,
+     * else you will need to modify all of those classes for this to work.
+     *
+     * @var array<string, list<string>|string>
+     */
+    public $psr4 = [
+        APP_NAMESPACE => APPPATH,
+    ];
+
+    /**
+     * -------------------------------------------------------------------
+     * Class Map
+     * -------------------------------------------------------------------
+     * The class map provides a map of class names and their exact
+     * location on the drive. Classes loaded in this manner will have
+     * slightly faster performance because they will not have to be
+     * searched for within one or more directories as they would if they
+     * were being autoloaded through a namespace.
+     *
+     * Prototype:
+     *   $classmap = [
+     *       'MyClass'   => '/path/to/class/file.php'
+     *   ];
+     *
+     * @var array<string, string>
+     */
+    public $classmap = [];
+
+    /**
+     * -------------------------------------------------------------------
+     * Files
+     * -------------------------------------------------------------------
+     * The files array provides a list of paths to __non-class__ files
+     * that will be autoloaded. This can be useful for bootstrap operations
+     * or for loading functions.
+     *
+     * Prototype:
+     *   $files = [
+     *       '/path/to/my/file.php',
+     *   ];
+     *
+     * @var list<string>
+     */
+    public $files = [];
+
+    /**
+     * -------------------------------------------------------------------
+     * Helpers
+     * -------------------------------------------------------------------
+     * Prototype:
+     *   $helpers = [
+     *       'form',
+     *   ];
+     *
+     * @var list<string>
+     */
+    public $helpers = [];
+}

+ 34 - 0
dgonz/app/Config/Boot/development.php

@@ -0,0 +1,34 @@
+<?php
+
+/*
+ |--------------------------------------------------------------------------
+ | ERROR DISPLAY
+ |--------------------------------------------------------------------------
+ | In development, we want to show as many errors as possible to help
+ | make sure they don't make it to production. And save us hours of
+ | painful debugging.
+ |
+ | If you set 'display_errors' to '1', CI4's detailed error report will show.
+ */
+error_reporting(E_ALL);
+ini_set('display_errors', '1');
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG BACKTRACES
+ |--------------------------------------------------------------------------
+ | If true, this constant will tell the error screens to display debug
+ | backtraces along with the other error information. If you would
+ | prefer to not see this, set this value to false.
+ */
+defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG MODE
+ |--------------------------------------------------------------------------
+ | Debug mode is an experimental flag that can allow changes throughout
+ | the system. This will control whether Kint is loaded, and a few other
+ | items. It can always be used within your own application too.
+ */
+defined('CI_DEBUG') || define('CI_DEBUG', true);

+ 25 - 0
dgonz/app/Config/Boot/production.php

@@ -0,0 +1,25 @@
+<?php
+
+/*
+ |--------------------------------------------------------------------------
+ | ERROR DISPLAY
+ |--------------------------------------------------------------------------
+ | Don't show ANY in production environments. Instead, let the system catch
+ | it and display a generic error message.
+ |
+ | If you set 'display_errors' to '1', CI4's detailed error report will show.
+ */
+error_reporting(E_ALL & ~E_DEPRECATED);
+// If you want to suppress more types of errors.
+// error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED);
+ini_set('display_errors', '0');
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG MODE
+ |--------------------------------------------------------------------------
+ | Debug mode is an experimental flag that can allow changes throughout
+ | the system. It's not widely used currently, and may not survive
+ | release of the framework.
+ */
+defined('CI_DEBUG') || define('CI_DEBUG', false);

+ 38 - 0
dgonz/app/Config/Boot/testing.php

@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * The environment testing is reserved for PHPUnit testing. It has special
+ * conditions built into the framework at various places to assist with that.
+ * You can’t use it for your development.
+ */
+
+/*
+ |--------------------------------------------------------------------------
+ | ERROR DISPLAY
+ |--------------------------------------------------------------------------
+ | In development, we want to show as many errors as possible to help
+ | make sure they don't make it to production. And save us hours of
+ | painful debugging.
+ */
+error_reporting(E_ALL);
+ini_set('display_errors', '1');
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG BACKTRACES
+ |--------------------------------------------------------------------------
+ | If true, this constant will tell the error screens to display debug
+ | backtraces along with the other error information. If you would
+ | prefer to not see this, set this value to false.
+ */
+defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG MODE
+ |--------------------------------------------------------------------------
+ | Debug mode is an experimental flag that can allow changes throughout
+ | the system. It's not widely used currently, and may not survive
+ | release of the framework.
+ */
+defined('CI_DEBUG') || define('CI_DEBUG', true);

+ 36 - 0
dgonz/app/Config/CURLRequest.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class CURLRequest extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * CURLRequest Share Connection Options
+     * --------------------------------------------------------------------------
+     *
+     * Share connection options between requests.
+     *
+     * @var list<int>
+     *
+     * @see https://www.php.net/manual/en/curl.constants.php#constant.curl-lock-data-connect
+     */
+    public array $shareConnectionOptions = [
+        CURL_LOCK_DATA_CONNECT,
+        CURL_LOCK_DATA_DNS,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * CURLRequest Share Options
+     * --------------------------------------------------------------------------
+     *
+     * Whether share options between requests or not.
+     *
+     * If true, all the options won't be reset between requests.
+     * It may cause an error request with unnecessary headers.
+     */
+    public bool $shareOptions = false;
+}

+ 198 - 0
dgonz/app/Config/Cache.php

@@ -0,0 +1,198 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Cache\CacheInterface;
+use CodeIgniter\Cache\Handlers\ApcuHandler;
+use CodeIgniter\Cache\Handlers\DummyHandler;
+use CodeIgniter\Cache\Handlers\FileHandler;
+use CodeIgniter\Cache\Handlers\MemcachedHandler;
+use CodeIgniter\Cache\Handlers\PredisHandler;
+use CodeIgniter\Cache\Handlers\RedisHandler;
+use CodeIgniter\Cache\Handlers\WincacheHandler;
+use CodeIgniter\Config\BaseConfig;
+
+class Cache extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Primary Handler
+     * --------------------------------------------------------------------------
+     *
+     * The name of the preferred handler that should be used. If for some reason
+     * it is not available, the $backupHandler will be used in its place.
+     */
+    public string $handler = 'file';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Backup Handler
+     * --------------------------------------------------------------------------
+     *
+     * The name of the handler that will be used in case the first one is
+     * unreachable. Often, 'file' is used here since the filesystem is
+     * always available, though that's not always practical for the app.
+     */
+    public string $backupHandler = 'dummy';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Key Prefix
+     * --------------------------------------------------------------------------
+     *
+     * This string is added to all cache item names to help avoid collisions
+     * if you run multiple applications with the same cache engine.
+     */
+    public string $prefix = '';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Default TTL
+     * --------------------------------------------------------------------------
+     *
+     * The default number of seconds to save items when none is specified.
+     *
+     * WARNING: This is not used by framework handlers where 60 seconds is
+     * hard-coded, but may be useful to projects and modules. This will replace
+     * the hard-coded value in a future release.
+     */
+    public int $ttl = 60;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Reserved Characters
+     * --------------------------------------------------------------------------
+     *
+     * A string of reserved characters that will not be allowed in keys or tags.
+     * Strings that violate this restriction will cause handlers to throw.
+     * Default: {}()/\@:
+     *
+     * NOTE: The default set is required for PSR-6 compliance.
+     */
+    public string $reservedCharacters = '{}()/\@:';
+
+    /**
+     * --------------------------------------------------------------------------
+     * File settings
+     * --------------------------------------------------------------------------
+     *
+     * Your file storage preferences can be specified below, if you are using
+     * the File driver.
+     *
+     * @var array{storePath?: string, mode?: int}
+     */
+    public array $file = [
+        'storePath' => WRITEPATH . 'cache/',
+        'mode'      => 0640,
+    ];
+
+    /**
+     * -------------------------------------------------------------------------
+     * Memcached settings
+     * -------------------------------------------------------------------------
+     *
+     * Your Memcached servers can be specified below, if you are using
+     * the Memcached drivers.
+     *
+     * @see https://codeigniter.com/user_guide/libraries/caching.html#memcached
+     *
+     * @var array{host?: string, port?: int, weight?: int, raw?: bool}
+     */
+    public array $memcached = [
+        'host'   => '127.0.0.1',
+        'port'   => 11211,
+        'weight' => 1,
+        'raw'    => false,
+    ];
+
+    /**
+     * -------------------------------------------------------------------------
+     * Redis settings
+     * -------------------------------------------------------------------------
+     *
+     * Your Redis server can be specified below, if you are using
+     * the Redis or Predis drivers.
+     *
+     * @var array{
+     *     host?: string,
+     *     password?: string|null,
+     *     port?: int,
+     *     timeout?: int,
+     *     async?: bool,
+     *     persistent?: bool,
+     *     database?: int
+     * }
+     */
+    public array $redis = [
+        'host'       => '127.0.0.1',
+        'password'   => null,
+        'port'       => 6379,
+        'timeout'    => 0,
+        'async'      => false, // specific to Predis and ignored by the native Redis extension
+        'persistent' => false,
+        'database'   => 0,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Available Cache Handlers
+     * --------------------------------------------------------------------------
+     *
+     * This is an array of cache engine alias' and class names. Only engines
+     * that are listed here are allowed to be used.
+     *
+     * @var array<string, class-string<CacheInterface>>
+     */
+    public array $validHandlers = [
+        'apcu'      => ApcuHandler::class,
+        'dummy'     => DummyHandler::class,
+        'file'      => FileHandler::class,
+        'memcached' => MemcachedHandler::class,
+        'predis'    => PredisHandler::class,
+        'redis'     => RedisHandler::class,
+        'wincache'  => WincacheHandler::class,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Web Page Caching: Cache Include Query String
+     * --------------------------------------------------------------------------
+     *
+     * Whether to take the URL query string into consideration when generating
+     * output cache files. Valid options are:
+     *
+     *    false = Disabled
+     *    true  = Enabled, take all query parameters into account.
+     *            Please be aware that this may result in numerous cache
+     *            files generated for the same page over and over again.
+     *    ['q'] = Enabled, but only take into account the specified list
+     *            of query parameters.
+     *
+     * @var bool|list<string>
+     */
+    public $cacheQueryString = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Web Page Caching: Cache Status Codes
+     * --------------------------------------------------------------------------
+     *
+     * HTTP status codes that are allowed to be cached. Only responses with
+     * these status codes will be cached by the PageCache filter.
+     *
+     * Default: [] - Cache all status codes (backward compatible)
+     *
+     * Recommended: [200] - Only cache successful responses
+     *
+     * You can also use status codes like:
+     *   [200, 404, 410] - Cache successful responses and specific error codes
+     *   [200, 201, 202, 203, 204] - All 2xx successful responses
+     *
+     * WARNING: Using [] may cache temporary error pages (404, 500, etc).
+     * Consider restricting to [200] for production applications to avoid
+     * caching errors that should be temporary.
+     *
+     * @var list<int>
+     */
+    public array $cacheStatusCodes = [];
+}

+ 79 - 0
dgonz/app/Config/Constants.php

@@ -0,0 +1,79 @@
+<?php
+
+/*
+ | --------------------------------------------------------------------
+ | App Namespace
+ | --------------------------------------------------------------------
+ |
+ | This defines the default Namespace that is used throughout
+ | CodeIgniter to refer to the Application directory. Change
+ | this constant to change the namespace that all application
+ | classes should use.
+ |
+ | NOTE: changing this will require manually modifying the
+ | existing namespaces of App\* namespaced-classes.
+ */
+defined('APP_NAMESPACE') || define('APP_NAMESPACE', 'App');
+
+/*
+ | --------------------------------------------------------------------------
+ | Composer Path
+ | --------------------------------------------------------------------------
+ |
+ | The path that Composer's autoload file is expected to live. By default,
+ | the vendor folder is in the Root directory, but you can customize that here.
+ */
+defined('COMPOSER_PATH') || define('COMPOSER_PATH', ROOTPATH . 'vendor/autoload.php');
+
+/*
+ |--------------------------------------------------------------------------
+ | Timing Constants
+ |--------------------------------------------------------------------------
+ |
+ | Provide simple ways to work with the myriad of PHP functions that
+ | require information to be in seconds.
+ */
+defined('SECOND') || define('SECOND', 1);
+defined('MINUTE') || define('MINUTE', 60);
+defined('HOUR')   || define('HOUR', 3600);
+defined('DAY')    || define('DAY', 86400);
+defined('WEEK')   || define('WEEK', 604800);
+defined('MONTH')  || define('MONTH', 2_592_000);
+defined('YEAR')   || define('YEAR', 31_536_000);
+defined('DECADE') || define('DECADE', 315_360_000);
+
+/*
+ | --------------------------------------------------------------------------
+ | Exit Status Codes
+ | --------------------------------------------------------------------------
+ |
+ | Used to indicate the conditions under which the script is exit()ing.
+ | While there is no universal standard for error codes, there are some
+ | broad conventions.  Three such conventions are mentioned below, for
+ | those who wish to make use of them.  The CodeIgniter defaults were
+ | chosen for the least overlap with these conventions, while still
+ | leaving room for others to be defined in future versions and user
+ | applications.
+ |
+ | The three main conventions used for determining exit status codes
+ | are as follows:
+ |
+ |    Standard C/C++ Library (stdlibc):
+ |       http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
+ |       (This link also contains other GNU-specific conventions)
+ |    BSD sysexits.h:
+ |       http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits
+ |    Bash scripting:
+ |       http://tldp.org/LDP/abs/html/exitcodes.html
+ |
+ */
+defined('EXIT_SUCCESS')        || define('EXIT_SUCCESS', 0);        // no errors
+defined('EXIT_ERROR')          || define('EXIT_ERROR', 1);          // generic error
+defined('EXIT_CONFIG')         || define('EXIT_CONFIG', 3);         // configuration error
+defined('EXIT_UNKNOWN_FILE')   || define('EXIT_UNKNOWN_FILE', 4);   // file not found
+defined('EXIT_UNKNOWN_CLASS')  || define('EXIT_UNKNOWN_CLASS', 5);  // unknown class
+defined('EXIT_UNKNOWN_METHOD') || define('EXIT_UNKNOWN_METHOD', 6); // unknown class member
+defined('EXIT_USER_INPUT')     || define('EXIT_USER_INPUT', 7);     // invalid user input
+defined('EXIT_DATABASE')       || define('EXIT_DATABASE', 8);       // database error
+defined('EXIT__AUTO_MIN')      || define('EXIT__AUTO_MIN', 9);      // lowest automatically-assigned error code
+defined('EXIT__AUTO_MAX')      || define('EXIT__AUTO_MAX', 125);    // highest automatically-assigned error code

+ 216 - 0
dgonz/app/Config/ContentSecurityPolicy.php

@@ -0,0 +1,216 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Stores the default settings for the ContentSecurityPolicy, if you
+ * choose to use it. The values here will be read in and set as defaults
+ * for the site. If needed, they can be overridden on a page-by-page basis.
+ *
+ * Suggested reference for explanations:
+ *
+ * @see https://www.html5rocks.com/en/tutorials/security/content-security-policy/
+ */
+class ContentSecurityPolicy extends BaseConfig
+{
+    // -------------------------------------------------------------------------
+    // Broadbrush CSP management
+    // -------------------------------------------------------------------------
+
+    /**
+     * Default CSP report context
+     */
+    public bool $reportOnly = false;
+
+    /**
+     * Specifies a URL where a browser will send reports
+     * when a content security policy is violated.
+     */
+    public ?string $reportURI = null;
+
+    /**
+     * Specifies a reporting endpoint to which violation reports ought to be sent.
+     */
+    public ?string $reportTo = null;
+
+    /**
+     * Instructs user agents to rewrite URL schemes, changing
+     * HTTP to HTTPS. This directive is for websites with
+     * large numbers of old URLs that need to be rewritten.
+     */
+    public bool $upgradeInsecureRequests = false;
+
+    // -------------------------------------------------------------------------
+    // CSP DIRECTIVES SETTINGS
+    // NOTE: once you set a policy to 'none', it cannot be further restricted
+    // -------------------------------------------------------------------------
+
+    /**
+     * Will default to `'self'` if not overridden
+     *
+     * @var list<string>|string|null
+     */
+    public $defaultSrc;
+
+    /**
+     * Lists allowed scripts' URLs.
+     *
+     * @var list<string>|string
+     */
+    public $scriptSrc = 'self';
+
+    /**
+     * Specifies valid sources for JavaScript <script> elements.
+     *
+     * @var list<string>|string
+     */
+    public array|string $scriptSrcElem = 'self';
+
+    /**
+     * Specifies valid sources for JavaScript inline event
+     * handlers and JavaScript URLs.
+     *
+     * @var list<string>|string
+     */
+    public array|string $scriptSrcAttr = 'self';
+
+    /**
+     * Lists allowed stylesheets' URLs.
+     *
+     * @var list<string>|string
+     */
+    public $styleSrc = 'self';
+
+    /**
+     * Specifies valid sources for stylesheets <link> elements.
+     *
+     * @var list<string>|string
+     */
+    public array|string $styleSrcElem = 'self';
+
+    /**
+     * Specifies valid sources for stylesheets inline
+     * style attributes and `<style>` elements.
+     *
+     * @var list<string>|string
+     */
+    public array|string $styleSrcAttr = 'self';
+
+    /**
+     * Defines the origins from which images can be loaded.
+     *
+     * @var list<string>|string
+     */
+    public $imageSrc = 'self';
+
+    /**
+     * Restricts the URLs that can appear in a page's `<base>` element.
+     *
+     * Will default to self if not overridden
+     *
+     * @var list<string>|string|null
+     */
+    public $baseURI;
+
+    /**
+     * Lists the URLs for workers and embedded frame contents
+     *
+     * @var list<string>|string
+     */
+    public $childSrc = 'self';
+
+    /**
+     * Limits the origins that you can connect to (via XHR,
+     * WebSockets, and EventSource).
+     *
+     * @var list<string>|string
+     */
+    public $connectSrc = 'self';
+
+    /**
+     * Specifies the origins that can serve web fonts.
+     *
+     * @var list<string>|string
+     */
+    public $fontSrc;
+
+    /**
+     * Lists valid endpoints for submission from `<form>` tags.
+     *
+     * @var list<string>|string
+     */
+    public $formAction = 'self';
+
+    /**
+     * Specifies the sources that can embed the current page.
+     * This directive applies to `<frame>`, `<iframe>`, `<embed>`,
+     * and `<applet>` tags. This directive can't be used in
+     * `<meta>` tags and applies only to non-HTML resources.
+     *
+     * @var list<string>|string|null
+     */
+    public $frameAncestors;
+
+    /**
+     * The frame-src directive restricts the URLs which may
+     * be loaded into nested browsing contexts.
+     *
+     * @var list<string>|string|null
+     */
+    public $frameSrc;
+
+    /**
+     * Restricts the origins allowed to deliver video and audio.
+     *
+     * @var list<string>|string|null
+     */
+    public $mediaSrc;
+
+    /**
+     * Allows control over Flash and other plugins.
+     *
+     * @var list<string>|string
+     */
+    public $objectSrc = 'self';
+
+    /**
+     * @var list<string>|string|null
+     */
+    public $manifestSrc;
+
+    /**
+     * @var list<string>|string
+     */
+    public array|string $workerSrc = [];
+
+    /**
+     * Limits the kinds of plugins a page may invoke.
+     *
+     * @var list<string>|string|null
+     */
+    public $pluginTypes;
+
+    /**
+     * List of actions allowed.
+     *
+     * @var list<string>|string|null
+     */
+    public $sandbox;
+
+    /**
+     * Nonce placeholder for style tags.
+     */
+    public string $styleNonceTag = '{csp-style-nonce}';
+
+    /**
+     * Nonce placeholder for script tags.
+     */
+    public string $scriptNonceTag = '{csp-script-nonce}';
+
+    /**
+     * Replace nonce tag automatically?
+     */
+    public bool $autoNonce = true;
+}

+ 107 - 0
dgonz/app/Config/Cookie.php

@@ -0,0 +1,107 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use DateTimeInterface;
+
+class Cookie extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Prefix
+     * --------------------------------------------------------------------------
+     *
+     * Set a cookie name prefix if you need to avoid collisions.
+     */
+    public string $prefix = '';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Expires Timestamp
+     * --------------------------------------------------------------------------
+     *
+     * Default expires timestamp for cookies. Setting this to `0` will mean the
+     * cookie will not have the `Expires` attribute and will behave as a session
+     * cookie.
+     *
+     * @var DateTimeInterface|int|string
+     */
+    public $expires = 0;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Path
+     * --------------------------------------------------------------------------
+     *
+     * Typically will be a forward slash.
+     */
+    public string $path = '/';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Domain
+     * --------------------------------------------------------------------------
+     *
+     * Set to `.your-domain.com` for site-wide cookies.
+     */
+    public string $domain = '';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Secure
+     * --------------------------------------------------------------------------
+     *
+     * Cookie will only be set if a secure HTTPS connection exists.
+     */
+    public bool $secure = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie HTTPOnly
+     * --------------------------------------------------------------------------
+     *
+     * Cookie will only be accessible via HTTP(S) (no JavaScript).
+     */
+    public bool $httponly = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie SameSite
+     * --------------------------------------------------------------------------
+     *
+     * Configure cookie SameSite setting. Allowed values are:
+     * - None
+     * - Lax
+     * - Strict
+     * - ''
+     *
+     * Alternatively, you can use the constant names:
+     * - `Cookie::SAMESITE_NONE`
+     * - `Cookie::SAMESITE_LAX`
+     * - `Cookie::SAMESITE_STRICT`
+     *
+     * Defaults to `Lax` for compatibility with modern browsers. Setting `''`
+     * (empty string) means default SameSite attribute set by browsers (`Lax`)
+     * will be set on cookies. If set to `None`, `$secure` must also be set.
+     *
+     * @var ''|'Lax'|'None'|'Strict'
+     */
+    public string $samesite = 'Lax';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Cookie Raw
+     * --------------------------------------------------------------------------
+     *
+     * This flag allows setting a "raw" cookie, i.e., its name and value are
+     * not URL encoded using `rawurlencode()`.
+     *
+     * If this is set to `true`, cookie names should be compliant of RFC 2616's
+     * list of allowed characters.
+     *
+     * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes
+     * @see https://tools.ietf.org/html/rfc2616#section-2.2
+     */
+    public bool $raw = false;
+}

+ 105 - 0
dgonz/app/Config/Cors.php

@@ -0,0 +1,105 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Cross-Origin Resource Sharing (CORS) Configuration
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
+ */
+class Cors extends BaseConfig
+{
+    /**
+     * The default CORS configuration.
+     *
+     * @var array{
+     *      allowedOrigins: list<string>,
+     *      allowedOriginsPatterns: list<string>,
+     *      supportsCredentials: bool,
+     *      allowedHeaders: list<string>,
+     *      exposedHeaders: list<string>,
+     *      allowedMethods: list<string>,
+     *      maxAge: int,
+     *  }
+     */
+    public array $default = [
+        /**
+         * Origins for the `Access-Control-Allow-Origin` header.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
+         *
+         * E.g.:
+         *   - ['http://localhost:8080']
+         *   - ['https://www.example.com']
+         */
+        'allowedOrigins' => [],
+
+        /**
+         * Origin regex patterns for the `Access-Control-Allow-Origin` header.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
+         *
+         * NOTE: A pattern specified here is part of a regular expression. It will
+         *       be actually `#\A<pattern>\z#`.
+         *
+         * E.g.:
+         *   - ['https://\w+\.example\.com']
+         */
+        'allowedOriginsPatterns' => [],
+
+        /**
+         * Weather to send the `Access-Control-Allow-Credentials` header.
+         *
+         * The Access-Control-Allow-Credentials response header tells browsers whether
+         * the server allows cross-origin HTTP requests to include credentials.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
+         */
+        'supportsCredentials' => false,
+
+        /**
+         * Set headers to allow.
+         *
+         * The Access-Control-Allow-Headers response header is used in response to
+         * a preflight request which includes the Access-Control-Request-Headers to
+         * indicate which HTTP headers can be used during the actual request.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
+         */
+        'allowedHeaders' => [],
+
+        /**
+         * Set headers to expose.
+         *
+         * The Access-Control-Expose-Headers response header allows a server to
+         * indicate which response headers should be made available to scripts running
+         * in the browser, in response to a cross-origin request.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
+         */
+        'exposedHeaders' => [],
+
+        /**
+         * Set methods to allow.
+         *
+         * The Access-Control-Allow-Methods response header specifies one or more
+         * methods allowed when accessing a resource in response to a preflight
+         * request.
+         *
+         * E.g.:
+         *   - ['GET', 'POST', 'PUT', 'DELETE']
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
+         */
+        'allowedMethods' => [],
+
+        /**
+         * Set how many seconds the results of a preflight request can be cached.
+         *
+         * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
+         */
+        'maxAge' => 7200,
+    ];
+}

+ 204 - 0
dgonz/app/Config/Database.php

@@ -0,0 +1,204 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Database\Config;
+
+/**
+ * Database Configuration
+ */
+class Database extends Config
+{
+    /**
+     * The directory that holds the Migrations and Seeds directories.
+     */
+    public string $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR;
+
+    /**
+     * Lets you choose which connection group to use if no other is specified.
+     */
+    public string $defaultGroup = 'default';
+
+    /**
+     * The default database connection.
+     *
+     * @var array<string, mixed>
+     */
+    public array $default = [
+        'DSN'          => '',
+        'hostname'     => 'localhost',
+        'username'     => '',
+        'password'     => '',
+        'database'     => '',
+        'DBDriver'     => 'MySQLi',
+        'DBPrefix'     => '',
+        'pConnect'     => false,
+        'DBDebug'      => true,
+        'charset'      => 'utf8mb4',
+        'DBCollat'     => 'utf8mb4_general_ci',
+        'swapPre'      => '',
+        'encrypt'      => false,
+        'compress'     => false,
+        'strictOn'     => false,
+        'failover'     => [],
+        'port'         => 3306,
+        'numberNative' => false,
+        'foundRows'    => false,
+        'dateFormat'   => [
+            'date'     => 'Y-m-d',
+            'datetime' => 'Y-m-d H:i:s',
+            'time'     => 'H:i:s',
+        ],
+    ];
+
+    //    /**
+    //     * Sample database connection for SQLite3.
+    //     *
+    //     * @var array<string, mixed>
+    //     */
+    //    public array $default = [
+    //        'database'    => 'database.db',
+    //        'DBDriver'    => 'SQLite3',
+    //        'DBPrefix'    => '',
+    //        'DBDebug'     => true,
+    //        'swapPre'     => '',
+    //        'failover'    => [],
+    //        'foreignKeys' => true,
+    //        'busyTimeout' => 1000,
+    //        'synchronous' => null,
+    //        'dateFormat'  => [
+    //            'date'     => 'Y-m-d',
+    //            'datetime' => 'Y-m-d H:i:s',
+    //            'time'     => 'H:i:s',
+    //        ],
+    //    ];
+
+    //    /**
+    //     * Sample database connection for Postgre.
+    //     *
+    //     * @var array<string, mixed>
+    //     */
+    //    public array $default = [
+    //        'DSN'        => '',
+    //        'hostname'   => 'localhost',
+    //        'username'   => 'root',
+    //        'password'   => 'root',
+    //        'database'   => 'ci4',
+    //        'schema'     => 'public',
+    //        'DBDriver'   => 'Postgre',
+    //        'DBPrefix'   => '',
+    //        'pConnect'   => false,
+    //        'DBDebug'    => true,
+    //        'charset'    => 'utf8',
+    //        'swapPre'    => '',
+    //        'failover'   => [],
+    //        'port'       => 5432,
+    //        'dateFormat' => [
+    //            'date'     => 'Y-m-d',
+    //            'datetime' => 'Y-m-d H:i:s',
+    //            'time'     => 'H:i:s',
+    //        ],
+    //    ];
+
+    //    /**
+    //     * Sample database connection for SQLSRV.
+    //     *
+    //     * @var array<string, mixed>
+    //     */
+    //    public array $default = [
+    //        'DSN'        => '',
+    //        'hostname'   => 'localhost',
+    //        'username'   => 'root',
+    //        'password'   => 'root',
+    //        'database'   => 'ci4',
+    //        'schema'     => 'dbo',
+    //        'DBDriver'   => 'SQLSRV',
+    //        'DBPrefix'   => '',
+    //        'pConnect'   => false,
+    //        'DBDebug'    => true,
+    //        'charset'    => 'utf8',
+    //        'swapPre'    => '',
+    //        'encrypt'    => false,
+    //        'failover'   => [],
+    //        'port'       => 1433,
+    //        'dateFormat' => [
+    //            'date'     => 'Y-m-d',
+    //            'datetime' => 'Y-m-d H:i:s',
+    //            'time'     => 'H:i:s',
+    //        ],
+    //    ];
+
+    //    /**
+    //     * Sample database connection for OCI8.
+    //     *
+    //     * You may need the following environment variables:
+    //     *   NLS_LANG                = 'AMERICAN_AMERICA.UTF8'
+    //     *   NLS_DATE_FORMAT         = 'YYYY-MM-DD HH24:MI:SS'
+    //     *   NLS_TIMESTAMP_FORMAT    = 'YYYY-MM-DD HH24:MI:SS'
+    //     *   NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS'
+    //     *
+    //     * @var array<string, mixed>
+    //     */
+    //    public array $default = [
+    //        'DSN'        => 'localhost:1521/FREEPDB1',
+    //        'username'   => 'root',
+    //        'password'   => 'root',
+    //        'DBDriver'   => 'OCI8',
+    //        'DBPrefix'   => '',
+    //        'pConnect'   => false,
+    //        'DBDebug'    => true,
+    //        'charset'    => 'AL32UTF8',
+    //        'swapPre'    => '',
+    //        'failover'   => [],
+    //        'dateFormat' => [
+    //            'date'     => 'Y-m-d',
+    //            'datetime' => 'Y-m-d H:i:s',
+    //            'time'     => 'H:i:s',
+    //        ],
+    //    ];
+
+    /**
+     * This database connection is used when running PHPUnit database tests.
+     *
+     * @var array<string, mixed>
+     */
+    public array $tests = [
+        'DSN'         => '',
+        'hostname'    => '127.0.0.1',
+        'username'    => '',
+        'password'    => '',
+        'database'    => ':memory:',
+        'DBDriver'    => 'SQLite3',
+        'DBPrefix'    => 'db_',  // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS
+        'pConnect'    => false,
+        'DBDebug'     => true,
+        'charset'     => 'utf8',
+        'DBCollat'    => '',
+        'swapPre'     => '',
+        'encrypt'     => false,
+        'compress'    => false,
+        'strictOn'    => true,
+        'failover'    => [],
+        'port'        => 3306,
+        'foreignKeys' => true,
+        'busyTimeout' => 1000,
+        'synchronous' => null,
+        'dateFormat'  => [
+            'date'     => 'Y-m-d',
+            'datetime' => 'Y-m-d H:i:s',
+            'time'     => 'H:i:s',
+        ],
+    ];
+
+    public function __construct()
+    {
+        parent::__construct();
+
+        // Ensure that we always set the database group to 'tests' if
+        // we are currently running an automated test suite, so that
+        // we don't overwrite live data on accident.
+        if (ENVIRONMENT === 'testing') {
+            $this->defaultGroup = 'tests';
+        }
+    }
+}

+ 43 - 0
dgonz/app/Config/DocTypes.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace Config;
+
+class DocTypes
+{
+    /**
+     * List of valid document types.
+     *
+     * @var array<string, string>
+     */
+    public array $list = [
+        'xhtml11'           => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
+        'xhtml1-strict'     => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
+        'xhtml1-trans'      => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
+        'xhtml1-frame'      => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
+        'xhtml-basic11'     => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
+        'html5'             => '<!DOCTYPE html>',
+        'html4-strict'      => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
+        'html4-trans'       => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
+        'html4-frame'       => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
+        'mathml1'           => '<!DOCTYPE math SYSTEM "http://www.w3.org/Math/DTD/mathml1/mathml.dtd">',
+        'mathml2'           => '<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">',
+        'svg10'             => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">',
+        'svg11'             => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">',
+        'svg11-basic'       => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd">',
+        'svg11-tiny'        => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">',
+        'xhtml-math-svg-xh' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">',
+        'xhtml-math-svg-sh' => '<!DOCTYPE svg:svg PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">',
+        'xhtml-rdfa-1'      => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">',
+        'xhtml-rdfa-2'      => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.1//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd">',
+    ];
+
+    /**
+     * Whether to remove the solidus (`/`) character for void HTML elements (e.g. `<input>`)
+     * for HTML5 compatibility.
+     *
+     * Set to:
+     *    `true` - to be HTML5 compatible
+     *    `false` - to be XHTML compatible
+     */
+    public bool $html5 = true;
+}

+ 126 - 0
dgonz/app/Config/Email.php

@@ -0,0 +1,126 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Email extends BaseConfig
+{
+    public string $fromEmail  = '';
+    public string $fromName   = '';
+    public string $recipients = '';
+
+    /**
+     * The "user agent"
+     */
+    public string $userAgent = 'CodeIgniter';
+
+    /**
+     * The mail sending protocol: mail, sendmail, smtp
+     */
+    public string $protocol = 'mail';
+
+    /**
+     * The server path to Sendmail.
+     */
+    public string $mailPath = '/usr/sbin/sendmail';
+
+    /**
+     * SMTP Server Hostname
+     */
+    public string $SMTPHost = '';
+
+    /**
+     * Which SMTP authentication method to use: login, plain
+     */
+    public string $SMTPAuthMethod = 'login';
+
+    /**
+     * SMTP Username
+     */
+    public string $SMTPUser = '';
+
+    /**
+     * SMTP Password
+     */
+    public string $SMTPPass = '';
+
+    /**
+     * SMTP Port
+     */
+    public int $SMTPPort = 25;
+
+    /**
+     * SMTP Timeout (in seconds)
+     */
+    public int $SMTPTimeout = 5;
+
+    /**
+     * Enable persistent SMTP connections
+     */
+    public bool $SMTPKeepAlive = false;
+
+    /**
+     * SMTP Encryption.
+     *
+     * @var string '', 'tls' or 'ssl'. 'tls' will issue a STARTTLS command
+     *             to the server. 'ssl' means implicit SSL. Connection on port
+     *             465 should set this to ''.
+     */
+    public string $SMTPCrypto = 'tls';
+
+    /**
+     * Enable word-wrap
+     */
+    public bool $wordWrap = true;
+
+    /**
+     * Character count to wrap at
+     */
+    public int $wrapChars = 76;
+
+    /**
+     * Type of mail, either 'text' or 'html'
+     */
+    public string $mailType = 'text';
+
+    /**
+     * Character set (utf-8, iso-8859-1, etc.)
+     */
+    public string $charset = 'UTF-8';
+
+    /**
+     * Whether to validate the email address
+     */
+    public bool $validate = false;
+
+    /**
+     * Email Priority. 1 = highest. 5 = lowest. 3 = normal
+     */
+    public int $priority = 3;
+
+    /**
+     * Newline character. (Use “\r\n” to comply with RFC 822)
+     */
+    public string $CRLF = "\r\n";
+
+    /**
+     * Newline character. (Use “\r\n” to comply with RFC 822)
+     */
+    public string $newline = "\r\n";
+
+    /**
+     * Enable BCC Batch Mode.
+     */
+    public bool $BCCBatchMode = false;
+
+    /**
+     * Number of emails in each BCC batch
+     */
+    public int $BCCBatchSize = 200;
+
+    /**
+     * Enable notify message from server
+     */
+    public bool $DSN = false;
+}

+ 109 - 0
dgonz/app/Config/Encryption.php

@@ -0,0 +1,109 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Encryption configuration.
+ *
+ * These are the settings used for encryption, if you don't pass a parameter
+ * array to the encrypter for creation/initialization.
+ */
+class Encryption extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Encryption Key Starter
+     * --------------------------------------------------------------------------
+     *
+     * If you use the Encryption class you must set an encryption key (seed).
+     * You need to ensure it is long enough for the cipher and mode you plan to use.
+     * See the user guide for more info.
+     */
+    public string $key = '';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Previous Encryption Keys
+     * --------------------------------------------------------------------------
+     *
+     * When rotating encryption keys, add old keys here to maintain ability
+     * to decrypt data encrypted with previous keys. Encryption always uses
+     * the current $key. Decryption tries current key first, then falls back
+     * to previous keys if decryption fails.
+     *
+     * In .env file, use comma-separated string:
+     *   encryption.previousKeys = hex2bin:9be8c64fcea509867...,hex2bin:3f5a1d8e9c2b7a4f6...
+     *
+     * @var list<string>|string
+     */
+    public array|string $previousKeys = '';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Encryption Driver to Use
+     * --------------------------------------------------------------------------
+     *
+     * One of the supported encryption drivers.
+     *
+     * Available drivers:
+     * - OpenSSL
+     * - Sodium
+     */
+    public string $driver = 'OpenSSL';
+
+    /**
+     * --------------------------------------------------------------------------
+     * SodiumHandler's Padding Length in Bytes
+     * --------------------------------------------------------------------------
+     *
+     * This is the number of bytes that will be padded to the plaintext message
+     * before it is encrypted. This value should be greater than zero.
+     *
+     * See the user guide for more information on padding.
+     */
+    public int $blockSize = 16;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Encryption digest
+     * --------------------------------------------------------------------------
+     *
+     * HMAC digest to use, e.g. 'SHA512' or 'SHA256'. Default value is 'SHA512'.
+     */
+    public string $digest = 'SHA512';
+
+    /**
+     * Whether the cipher-text should be raw. If set to false, then it will be base64 encoded.
+     * This setting is only used by OpenSSLHandler.
+     *
+     * Set to false for CI3 Encryption compatibility.
+     */
+    public bool $rawData = true;
+
+    /**
+     * Encryption key info.
+     * This setting is only used by OpenSSLHandler.
+     *
+     * Set to 'encryption' for CI3 Encryption compatibility.
+     */
+    public string $encryptKeyInfo = '';
+
+    /**
+     * Authentication key info.
+     * This setting is only used by OpenSSLHandler.
+     *
+     * Set to 'authentication' for CI3 Encryption compatibility.
+     */
+    public string $authKeyInfo = '';
+
+    /**
+     * Cipher to use.
+     * This setting is only used by OpenSSLHandler.
+     *
+     * Set to 'AES-128-CBC' to decrypt encrypted data that encrypted
+     * by CI3 Encryption default configuration.
+     */
+    public string $cipher = 'AES-256-CTR';
+}

+ 57 - 0
dgonz/app/Config/Events.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Events\Events;
+use CodeIgniter\Exceptions\FrameworkException;
+use CodeIgniter\HotReloader\HotReloader;
+
+/*
+ * --------------------------------------------------------------------
+ * Application Events
+ * --------------------------------------------------------------------
+ * Events allow you to tap into the execution of the program without
+ * modifying or extending core files. This file provides a central
+ * location to define your events, though they can always be added
+ * at run-time, also, if needed.
+ *
+ * You create code that can execute by subscribing to events with
+ * the 'on()' method. This accepts any form of callable, including
+ * Closures, that will be executed when the event is triggered.
+ *
+ * Example:
+ *      Events::on('create', [$myInstance, 'myMethod']);
+ */
+
+Events::on('pre_system', static function (): void {
+    if (ENVIRONMENT !== 'testing') {
+        $value = ini_get('zlib.output_compression');
+
+        if (filter_var($value, FILTER_VALIDATE_BOOLEAN) || (int) $value > 0) {
+            throw FrameworkException::forEnabledZlibOutputCompression();
+        }
+
+        while (ob_get_level() > 0) {
+            ob_end_flush();
+        }
+
+        ob_start(static fn ($buffer) => $buffer);
+    }
+
+    /*
+     * --------------------------------------------------------------------
+     * Debug Toolbar Listeners.
+     * --------------------------------------------------------------------
+     * If you delete, they will no longer be collected.
+     */
+    if (CI_DEBUG && ! is_cli()) {
+        Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect');
+        service('toolbar')->respond();
+        // Hot Reload route - for framework use on the hot reloader.
+        if (ENVIRONMENT === 'development') {
+            service('routes')->get('__hot-reload', static function (): void {
+                (new HotReloader())->run();
+            });
+        }
+    }
+});

+ 106 - 0
dgonz/app/Config/Exceptions.php

@@ -0,0 +1,106 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Debug\ExceptionHandler;
+use CodeIgniter\Debug\ExceptionHandlerInterface;
+use Psr\Log\LogLevel;
+use Throwable;
+
+/**
+ * Setup how the exception handler works.
+ */
+class Exceptions extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * LOG EXCEPTIONS?
+     * --------------------------------------------------------------------------
+     * If true, then exceptions will be logged
+     * through Services::Log.
+     *
+     * Default: true
+     */
+    public bool $log = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * DO NOT LOG STATUS CODES
+     * --------------------------------------------------------------------------
+     * Any status codes here will NOT be logged if logging is turned on.
+     * By default, only 404 (Page Not Found) exceptions are ignored.
+     *
+     * @var list<int>
+     */
+    public array $ignoreCodes = [404];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Error Views Path
+     * --------------------------------------------------------------------------
+     * This is the path to the directory that contains the 'cli' and 'html'
+     * directories that hold the views used to generate errors.
+     *
+     * Default: APPPATH.'Views/errors'
+     */
+    public string $errorViewPath = APPPATH . 'Views/errors';
+
+    /**
+     * --------------------------------------------------------------------------
+     * HIDE FROM DEBUG TRACE
+     * --------------------------------------------------------------------------
+     * Any data that you would like to hide from the debug trace.
+     * In order to specify 2 levels, use "/" to separate.
+     * ex. ['server', 'setup/password', 'secret_token']
+     *
+     * @var list<string>
+     */
+    public array $sensitiveDataInTrace = [];
+
+    /**
+     * --------------------------------------------------------------------------
+     * WHETHER TO THROW AN EXCEPTION ON DEPRECATED ERRORS
+     * --------------------------------------------------------------------------
+     * If set to `true`, DEPRECATED errors are only logged and no exceptions are
+     * thrown. This option also works for user deprecations.
+     */
+    public bool $logDeprecations = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * LOG LEVEL THRESHOLD FOR DEPRECATIONS
+     * --------------------------------------------------------------------------
+     * If `$logDeprecations` is set to `true`, this sets the log level
+     * to which the deprecation will be logged. This should be one of the log
+     * levels recognized by PSR-3.
+     *
+     * The related `Config\Logger::$threshold` should be adjusted, if needed,
+     * to capture logging the deprecations.
+     */
+    public string $deprecationLogLevel = LogLevel::WARNING;
+
+    /*
+     * DEFINE THE HANDLERS USED
+     * --------------------------------------------------------------------------
+     * Given the HTTP status code, returns exception handler that
+     * should be used to deal with this error. By default, it will run CodeIgniter's
+     * default handler and display the error information in the expected format
+     * for CLI, HTTP, or AJAX requests, as determined by is_cli() and the expected
+     * response format.
+     *
+     * Custom handlers can be returned if you want to handle one or more specific
+     * error codes yourself like:
+     *
+     *      if (in_array($statusCode, [400, 404, 500])) {
+     *          return new \App\Libraries\MyExceptionHandler();
+     *      }
+     *      if ($exception instanceOf PageNotFoundException) {
+     *          return new \App\Libraries\MyExceptionHandler();
+     *      }
+     */
+    public function handler(int $statusCode, Throwable $exception): ExceptionHandlerInterface
+    {
+        return new ExceptionHandler($this);
+    }
+}

+ 37 - 0
dgonz/app/Config/Feature.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Enable/disable backward compatibility breaking features.
+ */
+class Feature extends BaseConfig
+{
+    /**
+     * Use improved new auto routing instead of the legacy version.
+     */
+    public bool $autoRoutesImproved = true;
+
+    /**
+     * Use filter execution order in 4.4 or before.
+     */
+    public bool $oldFilterOrder = false;
+
+    /**
+     * The behavior of `limit(0)` in Query Builder.
+     *
+     * If true, `limit(0)` returns all records. (the behavior of 4.4.x or before in version 4.x.)
+     * If false, `limit(0)` returns no records. (the behavior of 3.1.9 or later in version 3.x.)
+     */
+    public bool $limitZeroAsAll = true;
+
+    /**
+     * Use strict location negotiation.
+     *
+     * By default, the locale is selected based on a loose comparison of the language code (ISO 639-1)
+     * Enabling strict comparison will also consider the region code (ISO 3166-1 alpha-2).
+     */
+    public bool $strictLocaleNegotiation = false;
+}

+ 110 - 0
dgonz/app/Config/Filters.php

@@ -0,0 +1,110 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\Filters as BaseFilters;
+use CodeIgniter\Filters\Cors;
+use CodeIgniter\Filters\CSRF;
+use CodeIgniter\Filters\DebugToolbar;
+use CodeIgniter\Filters\ForceHTTPS;
+use CodeIgniter\Filters\Honeypot;
+use CodeIgniter\Filters\InvalidChars;
+use CodeIgniter\Filters\PageCache;
+use CodeIgniter\Filters\PerformanceMetrics;
+use CodeIgniter\Filters\SecureHeaders;
+
+class Filters extends BaseFilters
+{
+    /**
+     * Configures aliases for Filter classes to
+     * make reading things nicer and simpler.
+     *
+     * @var array<string, class-string|list<class-string>>
+     *
+     * [filter_name => classname]
+     * or [filter_name => [classname1, classname2, ...]]
+     */
+    public array $aliases = [
+        'csrf'          => CSRF::class,
+        'toolbar'       => DebugToolbar::class,
+        'honeypot'      => Honeypot::class,
+        'invalidchars'  => InvalidChars::class,
+        'secureheaders' => SecureHeaders::class,
+        'cors'          => Cors::class,
+        'forcehttps'    => ForceHTTPS::class,
+        'pagecache'     => PageCache::class,
+        'performance'   => PerformanceMetrics::class,
+    ];
+
+    /**
+     * List of special required filters.
+     *
+     * The filters listed here are special. They are applied before and after
+     * other kinds of filters, and always applied even if a route does not exist.
+     *
+     * Filters set by default provide framework functionality. If removed,
+     * those functions will no longer work.
+     *
+     * @see https://codeigniter.com/user_guide/incoming/filters.html#provided-filters
+     *
+     * @var array{before: list<string>, after: list<string>}
+     */
+    public array $required = [
+        'before' => [
+            'forcehttps', // Force Global Secure Requests
+            'pagecache',  // Web Page Caching
+        ],
+        'after' => [
+            'pagecache',   // Web Page Caching
+            'performance', // Performance Metrics
+            'toolbar',     // Debug Toolbar
+        ],
+    ];
+
+    /**
+     * List of filter aliases that are always
+     * applied before and after every request.
+     *
+     * @var array{
+     *     before: array<string, array{except: list<string>|string}>|list<string>,
+     *     after: array<string, array{except: list<string>|string}>|list<string>
+     * }
+     */
+    public array $globals = [
+        'before' => [
+            // 'honeypot',
+            // 'csrf',
+            // 'invalidchars',
+        ],
+        'after' => [
+            // 'honeypot',
+            // 'secureheaders',
+        ],
+    ];
+
+    /**
+     * List of filter aliases that works on a
+     * particular HTTP method (GET, POST, etc.).
+     *
+     * Example:
+     * 'POST' => ['foo', 'bar']
+     *
+     * If you use this, you should disable auto-routing because auto-routing
+     * permits any HTTP method to access a controller. Accessing the controller
+     * with a method you don't expect could bypass the filter.
+     *
+     * @var array<string, list<string>>
+     */
+    public array $methods = [];
+
+    /**
+     * List of filter aliases that should run on any
+     * before or after URI patterns.
+     *
+     * Example:
+     * 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
+     *
+     * @var array<string, array<string, list<string>>>
+     */
+    public array $filters = [];
+}

+ 12 - 0
dgonz/app/Config/ForeignCharacters.php

@@ -0,0 +1,12 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\ForeignCharacters as BaseForeignCharacters;
+
+/**
+ * @immutable
+ */
+class ForeignCharacters extends BaseForeignCharacters
+{
+}

+ 73 - 0
dgonz/app/Config/Format.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Format\JSONFormatter;
+use CodeIgniter\Format\XMLFormatter;
+
+class Format extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Available Response Formats
+     * --------------------------------------------------------------------------
+     *
+     * When you perform content negotiation with the request, these are the
+     * available formats that your application supports. This is currently
+     * only used with the API\ResponseTrait. A valid Formatter must exist
+     * for the specified format.
+     *
+     * These formats are only checked when the data passed to the respond()
+     * method is an array.
+     *
+     * @var list<string>
+     */
+    public array $supportedResponseFormats = [
+        'application/json',
+        'application/xml', // machine-readable XML
+        'text/xml', // human-readable XML
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Formatters
+     * --------------------------------------------------------------------------
+     *
+     * Lists the class to use to format responses with of a particular type.
+     * For each mime type, list the class that should be used. Formatters
+     * can be retrieved through the getFormatter() method.
+     *
+     * @var array<string, string>
+     */
+    public array $formatters = [
+        'application/json' => JSONFormatter::class,
+        'application/xml'  => XMLFormatter::class,
+        'text/xml'         => XMLFormatter::class,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Formatters Options
+     * --------------------------------------------------------------------------
+     *
+     * Additional Options to adjust default formatters behaviour.
+     * For each mime type, list the additional options that should be used.
+     *
+     * @var array<string, int>
+     */
+    public array $formatterOptions = [
+        'application/json' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
+        'application/xml'  => 0,
+        'text/xml'         => 0,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Maximum depth for JSON encoding.
+     * --------------------------------------------------------------------------
+     *
+     * This value determines how deep the JSON encoder will traverse nested structures.
+     */
+    public int $jsonEncodeDepth = 512;
+}

+ 44 - 0
dgonz/app/Config/Generators.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Generators extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Generator Commands' Views
+     * --------------------------------------------------------------------------
+     *
+     * This array defines the mapping of generator commands to the view files
+     * they are using. If you need to customize them for your own, copy these
+     * view files in your own folder and indicate the location here.
+     *
+     * You will notice that the views have special placeholders enclosed in
+     * curly braces `{...}`. These placeholders are used internally by the
+     * generator commands in processing replacements, thus you are warned
+     * not to delete them or modify the names. If you will do so, you may
+     * end up disrupting the scaffolding process and throw errors.
+     *
+     * YOU HAVE BEEN WARNED!
+     *
+     * @var array<string, array<string, string>|string>
+     */
+    public array $views = [
+        'make:cell' => [
+            'class' => 'CodeIgniter\Commands\Generators\Views\cell.tpl.php',
+            'view'  => 'CodeIgniter\Commands\Generators\Views\cell_view.tpl.php',
+        ],
+        'make:command'      => 'CodeIgniter\Commands\Generators\Views\command.tpl.php',
+        'make:config'       => 'CodeIgniter\Commands\Generators\Views\config.tpl.php',
+        'make:controller'   => 'CodeIgniter\Commands\Generators\Views\controller.tpl.php',
+        'make:entity'       => 'CodeIgniter\Commands\Generators\Views\entity.tpl.php',
+        'make:filter'       => 'CodeIgniter\Commands\Generators\Views\filter.tpl.php',
+        'make:migration'    => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php',
+        'make:model'        => 'CodeIgniter\Commands\Generators\Views\model.tpl.php',
+        'make:seeder'       => 'CodeIgniter\Commands\Generators\Views\seeder.tpl.php',
+        'make:validation'   => 'CodeIgniter\Commands\Generators\Views\validation.tpl.php',
+        'session:migration' => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php',
+    ];
+}

+ 42 - 0
dgonz/app/Config/Honeypot.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Honeypot extends BaseConfig
+{
+    /**
+     * Makes Honeypot visible or not to human
+     */
+    public bool $hidden = true;
+
+    /**
+     * Honeypot Label Content
+     */
+    public string $label = 'Fill This Field';
+
+    /**
+     * Honeypot Field Name
+     */
+    public string $name = 'honeypot';
+
+    /**
+     * Honeypot HTML Template
+     */
+    public string $template = '<label>{label}</label><input type="text" name="{name}" value="">';
+
+    /**
+     * Honeypot container
+     *
+     * If you enabled CSP, you can remove `style="display:none"`.
+     */
+    public string $container = '<div style="display:none">{template}</div>';
+
+    /**
+     * The id attribute for Honeypot container tag
+     *
+     * Used when CSP is enabled.
+     */
+    public string $containerId = 'hpc';
+}

+ 40 - 0
dgonz/app/Config/Hostnames.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace Config;
+
+class Hostnames
+{
+    // List of known two-part TLDs for subdomain extraction
+    public const TWO_PART_TLDS = [
+        'co.uk', 'org.uk', 'gov.uk', 'ac.uk', 'sch.uk', 'ltd.uk', 'plc.uk',
+        'com.au', 'net.au', 'org.au', 'edu.au', 'gov.au', 'asn.au', 'id.au',
+        'co.jp', 'ac.jp', 'go.jp', 'or.jp', 'ne.jp', 'gr.jp',
+        'co.nz', 'org.nz', 'govt.nz', 'ac.nz', 'net.nz', 'geek.nz', 'maori.nz', 'school.nz',
+        'co.in', 'net.in', 'org.in', 'ind.in', 'ac.in', 'gov.in', 'res.in',
+        'com.cn', 'net.cn', 'org.cn', 'gov.cn', 'edu.cn',
+        'com.sg', 'net.sg', 'org.sg', 'gov.sg', 'edu.sg', 'per.sg',
+        'co.za', 'org.za', 'gov.za', 'ac.za', 'net.za',
+        'co.kr', 'or.kr', 'go.kr', 'ac.kr', 'ne.kr', 'pe.kr',
+        'co.th', 'or.th', 'go.th', 'ac.th', 'net.th', 'in.th',
+        'com.my', 'net.my', 'org.my', 'edu.my', 'gov.my', 'mil.my', 'name.my',
+        'com.mx', 'org.mx', 'net.mx', 'edu.mx', 'gob.mx',
+        'com.br', 'net.br', 'org.br', 'gov.br', 'edu.br', 'art.br', 'eng.br',
+        'co.il', 'org.il', 'ac.il', 'gov.il', 'net.il', 'muni.il',
+        'co.id', 'or.id', 'ac.id', 'go.id', 'net.id', 'web.id', 'my.id',
+        'com.hk', 'edu.hk', 'gov.hk', 'idv.hk', 'net.hk', 'org.hk',
+        'com.tw', 'net.tw', 'org.tw', 'edu.tw', 'gov.tw', 'idv.tw',
+        'com.sa', 'net.sa', 'org.sa', 'gov.sa', 'edu.sa', 'sch.sa', 'med.sa',
+        'co.ae', 'net.ae', 'org.ae', 'gov.ae', 'ac.ae', 'sch.ae',
+        'com.tr', 'net.tr', 'org.tr', 'gov.tr', 'edu.tr', 'av.tr', 'gen.tr',
+        'co.ke', 'or.ke', 'go.ke', 'ac.ke', 'sc.ke', 'me.ke', 'mobi.ke', 'info.ke',
+        'com.ng', 'org.ng', 'gov.ng', 'edu.ng', 'net.ng', 'sch.ng', 'name.ng',
+        'com.pk', 'net.pk', 'org.pk', 'gov.pk', 'edu.pk', 'fam.pk',
+        'com.eg', 'edu.eg', 'gov.eg', 'org.eg', 'net.eg',
+        'com.cy', 'net.cy', 'org.cy', 'gov.cy', 'ac.cy',
+        'com.lk', 'org.lk', 'edu.lk', 'gov.lk', 'net.lk', 'int.lk',
+        'com.bd', 'net.bd', 'org.bd', 'ac.bd', 'gov.bd', 'mil.bd',
+        'com.ar', 'net.ar', 'org.ar', 'gov.ar', 'edu.ar', 'mil.ar',
+        'gob.cl', 'com.pl', 'net.pl', 'org.pl', 'gov.pl', 'edu.pl',
+        'co.ir', 'ac.ir', 'org.ir', 'id.ir', 'gov.ir', 'sch.ir', 'net.ir',
+    ];
+}

+ 33 - 0
dgonz/app/Config/Images.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Images\Handlers\GDHandler;
+use CodeIgniter\Images\Handlers\ImageMagickHandler;
+
+class Images extends BaseConfig
+{
+    /**
+     * Default handler used if no other handler is specified.
+     */
+    public string $defaultHandler = 'gd';
+
+    /**
+     * The path to the image library.
+     * Required for ImageMagick, GraphicsMagick, or NetPBM.
+     *
+     * @deprecated 4.7.0 No longer used.
+     */
+    public string $libraryPath = '/usr/local/bin/convert';
+
+    /**
+     * The available handler classes.
+     *
+     * @var array<string, string>
+     */
+    public array $handlers = [
+        'gd'      => GDHandler::class,
+        'imagick' => ImageMagickHandler::class,
+    ];
+}

+ 63 - 0
dgonz/app/Config/Kint.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace Config;
+
+use Kint\Parser\ConstructablePluginInterface;
+use Kint\Renderer\Rich\TabPluginInterface;
+use Kint\Renderer\Rich\ValuePluginInterface;
+
+/**
+ * --------------------------------------------------------------------------
+ * Kint
+ * --------------------------------------------------------------------------
+ *
+ * We use Kint's `RichRenderer` and `CLIRenderer`. This area contains options
+ * that you can set to customize how Kint works for you.
+ *
+ * @see https://kint-php.github.io/kint/ for details on these settings.
+ */
+class Kint
+{
+    /*
+    |--------------------------------------------------------------------------
+    | Global Settings
+    |--------------------------------------------------------------------------
+    */
+
+    /**
+     * @var list<class-string<ConstructablePluginInterface>|ConstructablePluginInterface>|null
+     */
+    public $plugins;
+
+    public int $maxDepth           = 6;
+    public bool $displayCalledFrom = true;
+    public bool $expanded          = false;
+
+    /*
+    |--------------------------------------------------------------------------
+    | RichRenderer Settings
+    |--------------------------------------------------------------------------
+    */
+    public string $richTheme = 'aante-light.css';
+    public bool $richFolder  = false;
+
+    /**
+     * @var array<string, class-string<ValuePluginInterface>>|null
+     */
+    public $richObjectPlugins;
+
+    /**
+     * @var array<string, class-string<TabPluginInterface>>|null
+     */
+    public $richTabPlugins;
+
+    /*
+    |--------------------------------------------------------------------------
+    | CLI Settings
+    |--------------------------------------------------------------------------
+    */
+    public bool $cliColors      = true;
+    public bool $cliForceUTF8   = false;
+    public bool $cliDetectWidth = true;
+    public int $cliMinWidth     = 40;
+}

+ 151 - 0
dgonz/app/Config/Logger.php

@@ -0,0 +1,151 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Log\Handlers\FileHandler;
+use CodeIgniter\Log\Handlers\HandlerInterface;
+
+class Logger extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Error Logging Threshold
+     * --------------------------------------------------------------------------
+     *
+     * You can enable error logging by setting a threshold over zero. The
+     * threshold determines what gets logged. Any values below or equal to the
+     * threshold will be logged.
+     *
+     * Threshold options are:
+     *
+     * - 0 = Disables logging, Error logging TURNED OFF
+     * - 1 = Emergency Messages - System is unusable
+     * - 2 = Alert Messages - Action Must Be Taken Immediately
+     * - 3 = Critical Messages - Application component unavailable, unexpected exception.
+     * - 4 = Runtime Errors - Don't need immediate action, but should be monitored.
+     * - 5 = Warnings - Exceptional occurrences that are not errors.
+     * - 6 = Notices - Normal but significant events.
+     * - 7 = Info - Interesting events, like user logging in, etc.
+     * - 8 = Debug - Detailed debug information.
+     * - 9 = All Messages
+     *
+     * You can also pass an array with threshold levels to show individual error types
+     *
+     *     array(1, 2, 3, 8) = Emergency, Alert, Critical, and Debug messages
+     *
+     * For a live site you'll usually enable Critical or higher (3) to be logged otherwise
+     * your log files will fill up very fast.
+     *
+     * @var int|list<int>
+     */
+    public $threshold = (ENVIRONMENT === 'production') ? 4 : 9;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Date Format for Logs
+     * --------------------------------------------------------------------------
+     *
+     * Each item that is logged has an associated date. You can use PHP date
+     * codes to set your own date formatting
+     */
+    public string $dateFormat = 'Y-m-d H:i:s';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Log Handlers
+     * --------------------------------------------------------------------------
+     *
+     * The logging system supports multiple actions to be taken when something
+     * is logged. This is done by allowing for multiple Handlers, special classes
+     * designed to write the log to their chosen destinations, whether that is
+     * a file on the getServer, a cloud-based service, or even taking actions such
+     * as emailing the dev team.
+     *
+     * Each handler is defined by the class name used for that handler, and it
+     * MUST implement the `CodeIgniter\Log\Handlers\HandlerInterface` interface.
+     *
+     * The value of each key is an array of configuration items that are sent
+     * to the constructor of each handler. The only required configuration item
+     * is the 'handles' element, which must be an array of integer log levels.
+     * This is most easily handled by using the constants defined in the
+     * `Psr\Log\LogLevel` class.
+     *
+     * Handlers are executed in the order defined in this array, starting with
+     * the handler on top and continuing down.
+     *
+     * @var array<class-string<HandlerInterface>, array<string, int|list<string>|string>>
+     */
+    public array $handlers = [
+        /*
+         * --------------------------------------------------------------------
+         * File Handler
+         * --------------------------------------------------------------------
+         */
+        FileHandler::class => [
+            // The log levels that this handler will handle.
+            'handles' => [
+                'critical',
+                'alert',
+                'emergency',
+                'debug',
+                'error',
+                'info',
+                'notice',
+                'warning',
+            ],
+
+            /*
+             * The default filename extension for log files.
+             * An extension of 'php' allows for protecting the log files via basic
+             * scripting, when they are to be stored under a publicly accessible directory.
+             *
+             * NOTE: Leaving it blank will default to 'log'.
+             */
+            'fileExtension' => '',
+
+            /*
+             * The file system permissions to be applied on newly created log files.
+             *
+             * IMPORTANT: This MUST be an integer (no quotes) and you MUST use octal
+             * integer notation (i.e. 0700, 0644, etc.)
+             */
+            'filePermissions' => 0644,
+
+            /*
+             * Logging Directory Path
+             *
+             * By default, logs are written to WRITEPATH . 'logs/'
+             * Specify a different destination here, if desired.
+             */
+            'path' => '',
+        ],
+
+        /*
+         * The ChromeLoggerHandler requires the use of the Chrome web browser
+         * and the ChromeLogger extension. Uncomment this block to use it.
+         */
+        // 'CodeIgniter\Log\Handlers\ChromeLoggerHandler' => [
+        //     /*
+        //      * The log levels that this handler will handle.
+        //      */
+        //     'handles' => ['critical', 'alert', 'emergency', 'debug',
+        //                   'error', 'info', 'notice', 'warning'],
+        // ],
+
+        /*
+         * The ErrorlogHandler writes the logs to PHP's native `error_log()` function.
+         * Uncomment this block to use it.
+         */
+        // 'CodeIgniter\Log\Handlers\ErrorlogHandler' => [
+        //     /* The log levels this handler can handle. */
+        //     'handles' => ['critical', 'alert', 'emergency', 'debug', 'error', 'info', 'notice', 'warning'],
+        //
+        //     /*
+        //     * The message type where the error should go. Can be 0 or 4, or use the
+        //     * class constants: `ErrorlogHandler::TYPE_OS` (0) or `ErrorlogHandler::TYPE_SAPI` (4)
+        //     */
+        //     'messageType' => 0,
+        // ],
+    ];
+}

+ 65 - 0
dgonz/app/Config/Migrations.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Migrations extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Enable/Disable Migrations
+     * --------------------------------------------------------------------------
+     *
+     * Migrations are enabled by default.
+     *
+     * You should enable migrations whenever you intend to do a schema migration
+     * and disable it back when you're done.
+     */
+    public bool $enabled = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Migrations Table
+     * --------------------------------------------------------------------------
+     *
+     * This is the name of the table that will store the current migrations state.
+     * When migrations runs it will store in a database table which migration
+     * files have already been run.
+     */
+    public string $table = 'migrations';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Timestamp Format
+     * --------------------------------------------------------------------------
+     *
+     * This is the format that will be used when creating new migrations
+     * using the CLI command:
+     *   > php spark make:migration
+     *
+     * NOTE: if you set an unsupported format, migration runner will not find
+     *       your migration files.
+     *
+     * Supported formats:
+     * - YmdHis_
+     * - Y-m-d-His_
+     * - Y_m_d_His_
+     */
+    public string $timestampFormat = 'Y-m-d-His_';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Enable/Disable Migration Lock
+     * --------------------------------------------------------------------------
+     *
+     * Locking is disabled by default.
+     *
+     * When enabled, it will prevent multiple migration processes
+     * from running at the same time by using a lock mechanism.
+     *
+     * This is useful in production environments to avoid conflicts
+     * or race conditions during concurrent deployments.
+     */
+    public bool $lock = false;
+}

+ 534 - 0
dgonz/app/Config/Mimes.php

@@ -0,0 +1,534 @@
+<?php
+
+namespace Config;
+
+/**
+ * This file contains an array of mime types.  It is used by the
+ * Upload class to help identify allowed file types.
+ *
+ * When more than one variation for an extension exist (like jpg, jpeg, etc)
+ * the most common one should be first in the array to aid the guess*
+ * methods. The same applies when more than one mime-type exists for a
+ * single extension.
+ *
+ * When working with mime types, please make sure you have the ´fileinfo´
+ * extension enabled to reliably detect the media types.
+ */
+class Mimes
+{
+    /**
+     * Map of extensions to mime types.
+     *
+     * @var array<string, list<string>|string>
+     */
+    public static array $mimes = [
+        'hqx' => [
+            'application/mac-binhex40',
+            'application/mac-binhex',
+            'application/x-binhex40',
+            'application/x-mac-binhex40',
+        ],
+        'cpt' => 'application/mac-compactpro',
+        'csv' => [
+            'text/csv',
+            'text/x-comma-separated-values',
+            'text/comma-separated-values',
+            'application/vnd.ms-excel',
+            'application/x-csv',
+            'text/x-csv',
+            'application/csv',
+            'application/excel',
+            'application/vnd.msexcel',
+            'text/plain',
+        ],
+        'bin' => [
+            'application/macbinary',
+            'application/mac-binary',
+            'application/octet-stream',
+            'application/x-binary',
+            'application/x-macbinary',
+        ],
+        'dms' => 'application/octet-stream',
+        'lha' => 'application/octet-stream',
+        'lzh' => 'application/octet-stream',
+        'exe' => [
+            'application/octet-stream',
+            'application/vnd.microsoft.portable-executable',
+            'application/x-dosexec',
+            'application/x-msdownload',
+        ],
+        'class' => 'application/octet-stream',
+        'psd'   => [
+            'application/x-photoshop',
+            'image/vnd.adobe.photoshop',
+        ],
+        'so'  => 'application/octet-stream',
+        'sea' => 'application/octet-stream',
+        'dll' => 'application/octet-stream',
+        'oda' => 'application/oda',
+        'pdf' => [
+            'application/pdf',
+            'application/force-download',
+            'application/x-download',
+        ],
+        'ai' => [
+            'application/pdf',
+            'application/postscript',
+        ],
+        'eps'  => 'application/postscript',
+        'ps'   => 'application/postscript',
+        'smi'  => 'application/smil',
+        'smil' => 'application/smil',
+        'mif'  => 'application/vnd.mif',
+        'xls'  => [
+            'application/vnd.ms-excel',
+            'application/msexcel',
+            'application/x-msexcel',
+            'application/x-ms-excel',
+            'application/x-excel',
+            'application/x-dos_ms_excel',
+            'application/xls',
+            'application/x-xls',
+            'application/excel',
+            'application/download',
+            'application/vnd.ms-office',
+            'application/msword',
+        ],
+        'ppt' => [
+            'application/vnd.ms-powerpoint',
+            'application/powerpoint',
+            'application/vnd.ms-office',
+            'application/msword',
+        ],
+        'pptx' => [
+            'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+        ],
+        'wbxml' => 'application/wbxml',
+        'wmlc'  => 'application/wmlc',
+        'dcr'   => 'application/x-director',
+        'dir'   => 'application/x-director',
+        'dxr'   => 'application/x-director',
+        'dvi'   => 'application/x-dvi',
+        'gtar'  => 'application/x-gtar',
+        'gz'    => 'application/x-gzip',
+        'gzip'  => 'application/x-gzip',
+        'php'   => [
+            'application/x-php',
+            'application/x-httpd-php',
+            'application/php',
+            'text/php',
+            'text/x-php',
+            'application/x-httpd-php-source',
+        ],
+        'php4'  => 'application/x-httpd-php',
+        'php3'  => 'application/x-httpd-php',
+        'phtml' => 'application/x-httpd-php',
+        'phps'  => 'application/x-httpd-php-source',
+        'js'    => [
+            'application/x-javascript',
+            'text/plain',
+        ],
+        'swf' => 'application/x-shockwave-flash',
+        'sit' => 'application/x-stuffit',
+        'tar' => 'application/x-tar',
+        'tgz' => [
+            'application/x-tar',
+            'application/x-gzip-compressed',
+        ],
+        'z'     => 'application/x-compress',
+        'xhtml' => 'application/xhtml+xml',
+        'xht'   => 'application/xhtml+xml',
+        'zip'   => [
+            'application/x-zip',
+            'application/zip',
+            'application/x-zip-compressed',
+            'application/s-compressed',
+            'multipart/x-zip',
+        ],
+        'rar' => [
+            'application/vnd.rar',
+            'application/x-rar',
+            'application/rar',
+            'application/x-rar-compressed',
+        ],
+        'mid'  => 'audio/midi',
+        'midi' => 'audio/midi',
+        'mpga' => 'audio/mpeg',
+        'mp2'  => 'audio/mpeg',
+        'mp3'  => [
+            'audio/mpeg',
+            'audio/mpg',
+            'audio/mpeg3',
+            'audio/mp3',
+        ],
+        'aif' => [
+            'audio/x-aiff',
+            'audio/aiff',
+        ],
+        'aiff' => [
+            'audio/x-aiff',
+            'audio/aiff',
+        ],
+        'aifc' => 'audio/x-aiff',
+        'ram'  => 'audio/x-pn-realaudio',
+        'rm'   => 'audio/x-pn-realaudio',
+        'rpm'  => 'audio/x-pn-realaudio-plugin',
+        'ra'   => 'audio/x-realaudio',
+        'rv'   => 'video/vnd.rn-realvideo',
+        'wav'  => [
+            'audio/x-wav',
+            'audio/wave',
+            'audio/wav',
+        ],
+        'bmp' => [
+            'image/bmp',
+            'image/x-bmp',
+            'image/x-bitmap',
+            'image/x-xbitmap',
+            'image/x-win-bitmap',
+            'image/x-windows-bmp',
+            'image/ms-bmp',
+            'image/x-ms-bmp',
+            'application/bmp',
+            'application/x-bmp',
+            'application/x-win-bitmap',
+        ],
+        'gif' => 'image/gif',
+        'jpg' => [
+            'image/jpeg',
+            'image/pjpeg',
+        ],
+        'jpeg' => [
+            'image/jpeg',
+            'image/pjpeg',
+        ],
+        'jpe' => [
+            'image/jpeg',
+            'image/pjpeg',
+        ],
+        'jp2' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'j2k' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'jpf' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'jpg2' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'jpx' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'jpm' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'mj2' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'mjp2' => [
+            'image/jp2',
+            'video/mj2',
+            'image/jpx',
+            'image/jpm',
+        ],
+        'png' => [
+            'image/png',
+            'image/x-png',
+        ],
+        'webp' => 'image/webp',
+        'tif'  => 'image/tiff',
+        'tiff' => 'image/tiff',
+        'css'  => [
+            'text/css',
+            'text/plain',
+        ],
+        'html' => [
+            'text/html',
+            'text/plain',
+        ],
+        'htm' => [
+            'text/html',
+            'text/plain',
+        ],
+        'shtml' => [
+            'text/html',
+            'text/plain',
+        ],
+        'txt'  => 'text/plain',
+        'text' => 'text/plain',
+        'log'  => [
+            'text/plain',
+            'text/x-log',
+        ],
+        'rtx' => 'text/richtext',
+        'rtf' => 'text/rtf',
+        'xml' => [
+            'application/xml',
+            'text/xml',
+            'text/plain',
+        ],
+        'xsl' => [
+            'application/xml',
+            'text/xsl',
+            'text/xml',
+        ],
+        'mpeg' => 'video/mpeg',
+        'mpg'  => 'video/mpeg',
+        'mpe'  => 'video/mpeg',
+        'qt'   => 'video/quicktime',
+        'mov'  => 'video/quicktime',
+        'avi'  => [
+            'video/x-msvideo',
+            'video/msvideo',
+            'video/avi',
+            'application/x-troff-msvideo',
+        ],
+        'movie' => 'video/x-sgi-movie',
+        'doc'   => [
+            'application/msword',
+            'application/vnd.ms-office',
+        ],
+        'docx' => [
+            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+            'application/zip',
+            'application/msword',
+            'application/x-zip',
+        ],
+        'dot' => [
+            'application/msword',
+            'application/vnd.ms-office',
+        ],
+        'dotx' => [
+            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+            'application/zip',
+            'application/msword',
+        ],
+        'xlsx' => [
+            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+            'application/zip',
+            'application/vnd.ms-excel',
+            'application/msword',
+            'application/x-zip',
+        ],
+        'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
+        'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
+        'word' => [
+            'application/msword',
+            'application/octet-stream',
+        ],
+        'xl'   => 'application/excel',
+        'eml'  => 'message/rfc822',
+        'json' => [
+            'application/json',
+            'text/json',
+        ],
+        'pem' => [
+            'application/x-x509-user-cert',
+            'application/x-pem-file',
+            'application/octet-stream',
+        ],
+        'p10' => [
+            'application/x-pkcs10',
+            'application/pkcs10',
+        ],
+        'p12' => 'application/x-pkcs12',
+        'p7a' => 'application/x-pkcs7-signature',
+        'p7c' => [
+            'application/pkcs7-mime',
+            'application/x-pkcs7-mime',
+        ],
+        'p7m' => [
+            'application/pkcs7-mime',
+            'application/x-pkcs7-mime',
+        ],
+        'p7r' => 'application/x-pkcs7-certreqresp',
+        'p7s' => 'application/pkcs7-signature',
+        'crt' => [
+            'application/x-x509-ca-cert',
+            'application/x-x509-user-cert',
+            'application/pkix-cert',
+        ],
+        'crl' => [
+            'application/pkix-crl',
+            'application/pkcs-crl',
+        ],
+        'der' => 'application/x-x509-ca-cert',
+        'kdb' => 'application/octet-stream',
+        'pgp' => 'application/pgp',
+        'gpg' => 'application/gpg-keys',
+        'sst' => 'application/octet-stream',
+        'csr' => 'application/octet-stream',
+        'rsa' => 'application/x-pkcs7',
+        'cer' => [
+            'application/pkix-cert',
+            'application/x-x509-ca-cert',
+        ],
+        '3g2' => 'video/3gpp2',
+        '3gp' => [
+            'video/3gp',
+            'video/3gpp',
+        ],
+        'mp4' => 'video/mp4',
+        'm4a' => 'audio/x-m4a',
+        'f4v' => [
+            'video/mp4',
+            'video/x-f4v',
+        ],
+        'flv'  => 'video/x-flv',
+        'webm' => 'video/webm',
+        'aac'  => 'audio/x-acc',
+        'm4u'  => 'application/vnd.mpegurl',
+        'm3u'  => 'text/plain',
+        'xspf' => 'application/xspf+xml',
+        'vlc'  => 'application/videolan',
+        'wmv'  => [
+            'video/x-ms-wmv',
+            'video/x-ms-asf',
+        ],
+        'au'   => 'audio/x-au',
+        'ac3'  => 'audio/ac3',
+        'flac' => 'audio/x-flac',
+        'ogg'  => [
+            'audio/ogg',
+            'video/ogg',
+            'application/ogg',
+        ],
+        'kmz' => [
+            'application/vnd.google-earth.kmz',
+            'application/zip',
+            'application/x-zip',
+        ],
+        'kml' => [
+            'application/vnd.google-earth.kml+xml',
+            'application/xml',
+            'text/xml',
+        ],
+        'ics'  => 'text/calendar',
+        'ical' => 'text/calendar',
+        'zsh'  => 'text/x-scriptzsh',
+        '7zip' => [
+            'application/x-compressed',
+            'application/x-zip-compressed',
+            'application/zip',
+            'multipart/x-zip',
+        ],
+        'cdr' => [
+            'application/cdr',
+            'application/coreldraw',
+            'application/x-cdr',
+            'application/x-coreldraw',
+            'image/cdr',
+            'image/x-cdr',
+            'zz-application/zz-winassoc-cdr',
+        ],
+        'wma' => [
+            'audio/x-ms-wma',
+            'video/x-ms-asf',
+        ],
+        'jar' => [
+            'application/java-archive',
+            'application/x-java-application',
+            'application/x-jar',
+            'application/x-compressed',
+        ],
+        'svg' => [
+            'image/svg+xml',
+            'image/svg',
+            'application/xml',
+            'text/xml',
+        ],
+        'vcf' => 'text/x-vcard',
+        'srt' => [
+            'text/srt',
+            'text/plain',
+        ],
+        'vtt' => [
+            'text/vtt',
+            'text/plain',
+        ],
+        'ico' => [
+            'image/x-icon',
+            'image/x-ico',
+            'image/vnd.microsoft.icon',
+        ],
+        'stl' => [
+            'application/sla',
+            'application/vnd.ms-pki.stl',
+            'application/x-navistyle',
+            'model/stl',
+            'application/octet-stream',
+        ],
+    ];
+
+    /**
+     * Attempts to determine the best mime type for the given file extension.
+     *
+     * @return string|null The mime type found, or none if unable to determine.
+     */
+    public static function guessTypeFromExtension(string $extension)
+    {
+        $extension = trim(strtolower($extension), '. ');
+
+        if (! array_key_exists($extension, static::$mimes)) {
+            return null;
+        }
+
+        return is_array(static::$mimes[$extension]) ? static::$mimes[$extension][0] : static::$mimes[$extension];
+    }
+
+    /**
+     * Attempts to determine the best file extension for a given mime type.
+     *
+     * @param string|null $proposedExtension - default extension (in case there is more than one with the same mime type)
+     *
+     * @return string|null The extension determined, or null if unable to match.
+     */
+    public static function guessExtensionFromType(string $type, ?string $proposedExtension = null)
+    {
+        $type = trim(strtolower($type), '. ');
+
+        $proposedExtension = trim(strtolower($proposedExtension ?? ''));
+
+        if (
+            $proposedExtension !== ''
+            && array_key_exists($proposedExtension, static::$mimes)
+            && in_array($type, (array) static::$mimes[$proposedExtension], true)
+        ) {
+            // The detected mime type matches with the proposed extension.
+            return $proposedExtension;
+        }
+
+        // Reverse check the mime type list if no extension was proposed.
+        // This search is order sensitive!
+        foreach (static::$mimes as $ext => $types) {
+            if (in_array($type, (array) $types, true)) {
+                return $ext;
+            }
+        }
+
+        return null;
+    }
+}

+ 82 - 0
dgonz/app/Config/Modules.php

@@ -0,0 +1,82 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Modules\Modules as BaseModules;
+
+/**
+ * Modules Configuration.
+ *
+ * NOTE: This class is required prior to Autoloader instantiation,
+ *       and does not extend BaseConfig.
+ */
+class Modules extends BaseModules
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Enable Auto-Discovery?
+     * --------------------------------------------------------------------------
+     *
+     * If true, then auto-discovery will happen across all elements listed in
+     * $aliases below. If false, no auto-discovery will happen at all,
+     * giving a slight performance boost.
+     *
+     * @var bool
+     */
+    public $enabled = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Enable Auto-Discovery Within Composer Packages?
+     * --------------------------------------------------------------------------
+     *
+     * If true, then auto-discovery will happen across all namespaces loaded
+     * by Composer, as well as the namespaces configured locally.
+     *
+     * @var bool
+     */
+    public $discoverInComposer = true;
+
+    /**
+     * The Composer package list for Auto-Discovery
+     * This setting is optional.
+     *
+     * E.g.:
+     *   [
+     *       'only' => [
+     *           // List up all packages to auto-discover
+     *           'codeigniter4/shield',
+     *       ],
+     *   ]
+     *   or
+     *   [
+     *       'exclude' => [
+     *           // List up packages to exclude.
+     *           'pestphp/pest',
+     *       ],
+     *   ]
+     *
+     * @var array{only?: list<string>, exclude?: list<string>}
+     */
+    public $composerPackages = [];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Auto-Discovery Rules
+     * --------------------------------------------------------------------------
+     *
+     * Aliases list of all discovery classes that will be active and used during
+     * the current application request.
+     *
+     * If it is not listed, only the base application elements will be used.
+     *
+     * @var list<string>
+     */
+    public $aliases = [
+        'events',
+        'filters',
+        'registrars',
+        'routes',
+        'services',
+    ];
+}

+ 32 - 0
dgonz/app/Config/Optimize.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace Config;
+
+/**
+ * Optimization Configuration.
+ *
+ * NOTE: This class does not extend BaseConfig for performance reasons.
+ *       So you cannot replace the property values with Environment Variables.
+ *
+ * WARNING: Do not use these options when running the app in the Worker Mode.
+ */
+class Optimize
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Config Caching
+     * --------------------------------------------------------------------------
+     *
+     * @see https://codeigniter.com/user_guide/concepts/factories.html#config-caching
+     */
+    public bool $configCacheEnabled = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Config Caching
+     * --------------------------------------------------------------------------
+     *
+     * @see https://codeigniter.com/user_guide/concepts/autoloader.html#file-locator-caching
+     */
+    public bool $locatorCacheEnabled = false;
+}

+ 37 - 0
dgonz/app/Config/Pager.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Pager extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Templates
+     * --------------------------------------------------------------------------
+     *
+     * Pagination links are rendered out using views to configure their
+     * appearance. This array contains aliases and the view names to
+     * use when rendering the links.
+     *
+     * Within each view, the Pager object will be available as $pager,
+     * and the desired group as $pagerGroup;
+     *
+     * @var array<string, string>
+     */
+    public array $templates = [
+        'default_full'   => 'CodeIgniter\Pager\Views\default_full',
+        'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
+        'default_head'   => 'CodeIgniter\Pager\Views\default_head',
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Items Per Page
+     * --------------------------------------------------------------------------
+     *
+     * The default number of results shown in a single page.
+     */
+    public int $perPage = 20;
+}

+ 90 - 0
dgonz/app/Config/Paths.php

@@ -0,0 +1,90 @@
+<?php
+
+namespace Config;
+
+/**
+ * Paths
+ *
+ * Holds the paths that are used by the system to
+ * locate the main directories, app, system, etc.
+ *
+ * Modifying these allows you to restructure your application,
+ * share a system folder between multiple applications, and more.
+ *
+ * All paths are relative to the project's root folder.
+ *
+ * NOTE: This class is required prior to Autoloader instantiation,
+ *       and does not extend BaseConfig.
+ */
+class Paths
+{
+    /**
+     * ---------------------------------------------------------------
+     * SYSTEM FOLDER NAME
+     * ---------------------------------------------------------------
+     *
+     * This must contain the name of your "system" folder. Include
+     * the path if the folder is not in the same directory as this file.
+     */
+    public string $systemDirectory = __DIR__ . '/../../vendor/codeigniter4/framework/system';
+
+    /**
+     * ---------------------------------------------------------------
+     * APPLICATION FOLDER NAME
+     * ---------------------------------------------------------------
+     *
+     * If you want this front controller to use a different "app"
+     * folder than the default one you can set its name here. The folder
+     * can also be renamed or relocated anywhere on your server. If
+     * you do, use a full server path.
+     *
+     * @see http://codeigniter.com/user_guide/general/managing_apps.html
+     */
+    public string $appDirectory = __DIR__ . '/..';
+
+    /**
+     * ---------------------------------------------------------------
+     * WRITABLE DIRECTORY NAME
+     * ---------------------------------------------------------------
+     *
+     * This variable must contain the name of your "writable" directory.
+     * The writable directory allows you to group all directories that
+     * need write permission to a single place that can be tucked away
+     * for maximum security, keeping it out of the app and/or
+     * system directories.
+     */
+    public string $writableDirectory = __DIR__ . '/../../writable';
+
+    /**
+     * ---------------------------------------------------------------
+     * TESTS DIRECTORY NAME
+     * ---------------------------------------------------------------
+     *
+     * This variable must contain the name of your "tests" directory.
+     */
+    public string $testsDirectory = __DIR__ . '/../../tests';
+
+    /**
+     * ---------------------------------------------------------------
+     * VIEW DIRECTORY NAME
+     * ---------------------------------------------------------------
+     *
+     * This variable must contain the name of the directory that
+     * contains the view files used by your application. By
+     * default this is in `app/Views`. This value
+     * is used when no value is provided to `Services::renderer()`.
+     */
+    public string $viewDirectory = __DIR__ . '/../Views';
+
+    /**
+     * ---------------------------------------------------------------
+     * ENVIRONMENT DIRECTORY NAME
+     * ---------------------------------------------------------------
+     *
+     * This variable must contain the name of the directory where
+     * the .env file is located.
+     * Please consider security implications when changing this
+     * value - the directory should not be publicly accessible.
+     */
+    public string $envDirectory = __DIR__ . '/../../';
+}

+ 28 - 0
dgonz/app/Config/Publisher.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\Publisher as BasePublisher;
+
+/**
+ * Publisher Configuration
+ *
+ * Defines basic security restrictions for the Publisher class
+ * to prevent abuse by injecting malicious files into a project.
+ */
+class Publisher extends BasePublisher
+{
+    /**
+     * A list of allowed destinations with a (pseudo-)regex
+     * of allowed files for each destination.
+     * Attempts to publish to directories not in this list will
+     * result in a PublisherException. Files that do no fit the
+     * pattern will cause copy/merge to fail.
+     *
+     * @var array<string, string>
+     */
+    public $restrictions = [
+        ROOTPATH => '*',
+        FCPATH   => '#\.(s?css|js|map|html?|xml|json|webmanifest|ttf|eot|woff2?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i',
+    ];
+}

+ 6 - 0
dgonz/app/Config/Routes.php

@@ -0,0 +1,6 @@
+<?php
+
+use CodeIgniter\Router\RouteCollection;
+
+/** @var RouteCollection $routes */
+$routes->get('/', 'Home::index');

+ 149 - 0
dgonz/app/Config/Routing.php

@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * This file is part of CodeIgniter 4 framework.
+ *
+ * (c) CodeIgniter Foundation <admin@codeigniter.com>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Config;
+
+use CodeIgniter\Config\Routing as BaseRouting;
+
+/**
+ * Routing configuration
+ */
+class Routing extends BaseRouting
+{
+    /**
+     * For Defined Routes.
+     * An array of files that contain route definitions.
+     * Route files are read in order, with the first match
+     * found taking precedence.
+     *
+     * Default: APPPATH . 'Config/Routes.php'
+     *
+     * @var list<string>
+     */
+    public array $routeFiles = [
+        APPPATH . 'Config/Routes.php',
+    ];
+
+    /**
+     * For Defined Routes and Auto Routing.
+     * The default namespace to use for Controllers when no other
+     * namespace has been specified.
+     *
+     * Default: 'App\Controllers'
+     */
+    public string $defaultNamespace = 'App\Controllers';
+
+    /**
+     * For Auto Routing.
+     * The default controller to use when no other controller has been
+     * specified.
+     *
+     * Default: 'Home'
+     */
+    public string $defaultController = 'Home';
+
+    /**
+     * For Defined Routes and Auto Routing.
+     * The default method to call on the controller when no other
+     * method has been set in the route.
+     *
+     * Default: 'index'
+     */
+    public string $defaultMethod = 'index';
+
+    /**
+     * For Auto Routing.
+     * Whether to translate dashes in URIs for controller/method to underscores.
+     * Primarily useful when using the auto-routing.
+     *
+     * Default: false
+     */
+    public bool $translateURIDashes = false;
+
+    /**
+     * Sets the class/method that should be called if routing doesn't
+     * find a match. It can be the controller/method name like: Users::index
+     *
+     * This setting is passed to the Router class and handled there.
+     *
+     * If you want to use a closure, you will have to set it in the
+     * routes file by calling:
+     *
+     * $routes->set404Override(function() {
+     *    // Do something here
+     * });
+     *
+     * Example:
+     *  public $override404 = 'App\Errors::show404';
+     */
+    public ?string $override404 = null;
+
+    /**
+     * If TRUE, the system will attempt to match the URI against
+     * Controllers by matching each segment against folders/files
+     * in APPPATH/Controllers, when a match wasn't found against
+     * defined routes.
+     *
+     * If FALSE, will stop searching and do NO automatic routing.
+     */
+    public bool $autoRoute = false;
+
+    /**
+     * If TRUE, the system will look for attributes on controller
+     * class and methods that can run before and after the
+     * controller/method.
+     *
+     * If FALSE, will ignore any attributes.
+     */
+    public bool $useControllerAttributes = true;
+
+    /**
+     * For Defined Routes.
+     * If TRUE, will enable the use of the 'prioritize' option
+     * when defining routes.
+     *
+     * Default: false
+     */
+    public bool $prioritize = false;
+
+    /**
+     * For Defined Routes.
+     * If TRUE, matched multiple URI segments will be passed as one parameter.
+     *
+     * Default: false
+     */
+    public bool $multipleSegmentsOneParam = false;
+
+    /**
+     * For Auto Routing (Improved).
+     * Map of URI segments and namespaces.
+     *
+     * The key is the first URI segment. The value is the controller namespace.
+     * E.g.,
+     *   [
+     *       'blog' => 'Acme\Blog\Controllers',
+     *   ]
+     *
+     * @var array<string, string>
+     */
+    public array $moduleRoutes = [];
+
+    /**
+     * For Auto Routing (Improved).
+     * Whether to translate dashes in URIs for controller/method to CamelCase.
+     * E.g., blog-controller -> BlogController
+     *
+     * If you enable this, $translateURIDashes is ignored.
+     *
+     * Default: false
+     */
+    public bool $translateUriToCamelCase = true;
+}

+ 86 - 0
dgonz/app/Config/Security.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Security extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Protection Method
+     * --------------------------------------------------------------------------
+     *
+     * Protection Method for Cross Site Request Forgery protection.
+     *
+     * @var string 'cookie' or 'session'
+     */
+    public string $csrfProtection = 'cookie';
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Token Randomization
+     * --------------------------------------------------------------------------
+     *
+     * Randomize the CSRF Token for added security.
+     */
+    public bool $tokenRandomize = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Token Name
+     * --------------------------------------------------------------------------
+     *
+     * Token name for Cross Site Request Forgery protection.
+     */
+    public string $tokenName = 'csrf_test_name';
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Header Name
+     * --------------------------------------------------------------------------
+     *
+     * Header name for Cross Site Request Forgery protection.
+     */
+    public string $headerName = 'X-CSRF-TOKEN';
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Cookie Name
+     * --------------------------------------------------------------------------
+     *
+     * Cookie name for Cross Site Request Forgery protection.
+     */
+    public string $cookieName = 'csrf_cookie_name';
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Expires
+     * --------------------------------------------------------------------------
+     *
+     * Expiration time for Cross Site Request Forgery protection cookie.
+     *
+     * Defaults to two hours (in seconds).
+     */
+    public int $expires = 7200;
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Regenerate
+     * --------------------------------------------------------------------------
+     *
+     * Regenerate CSRF Token on every submission.
+     */
+    public bool $regenerate = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * CSRF Redirect
+     * --------------------------------------------------------------------------
+     *
+     * Redirect to previous page with error on failure.
+     *
+     * @see https://codeigniter4.github.io/userguide/libraries/security.html#redirection-on-failure
+     */
+    public bool $redirect = (ENVIRONMENT === 'production');
+}

+ 32 - 0
dgonz/app/Config/Services.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseService;
+
+/**
+ * Services Configuration file.
+ *
+ * Services are simply other classes/libraries that the system uses
+ * to do its job. This is used by CodeIgniter to allow the core of the
+ * framework to be swapped out easily without affecting the usage within
+ * the rest of your application.
+ *
+ * This file holds any application-specific services, or service overrides
+ * that you might need. An example has been included with the general
+ * method format you should use for your service methods. For more examples,
+ * see the core Services file at system/Config/Services.php.
+ */
+class Services extends BaseService
+{
+    /*
+     * public static function example($getShared = true)
+     * {
+     *     if ($getShared) {
+     *         return static::getSharedInstance('example');
+     *     }
+     *
+     *     return new \CodeIgniter\Example();
+     * }
+     */
+}

+ 128 - 0
dgonz/app/Config/Session.php

@@ -0,0 +1,128 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Session\Handlers\BaseHandler;
+use CodeIgniter\Session\Handlers\FileHandler;
+
+class Session extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Session Driver
+     * --------------------------------------------------------------------------
+     *
+     * The session storage driver to use:
+     * - `CodeIgniter\Session\Handlers\ArrayHandler` (for testing)
+     * - `CodeIgniter\Session\Handlers\FileHandler`
+     * - `CodeIgniter\Session\Handlers\DatabaseHandler`
+     * - `CodeIgniter\Session\Handlers\MemcachedHandler`
+     * - `CodeIgniter\Session\Handlers\RedisHandler`
+     *
+     * @var class-string<BaseHandler>
+     */
+    public string $driver = FileHandler::class;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Cookie Name
+     * --------------------------------------------------------------------------
+     *
+     * The session cookie name, must contain only [0-9a-z_-] characters
+     */
+    public string $cookieName = 'ci_session';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Expiration
+     * --------------------------------------------------------------------------
+     *
+     * The number of SECONDS you want the session to last.
+     * Setting to 0 (zero) means expire when the browser is closed.
+     */
+    public int $expiration = 7200;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Save Path
+     * --------------------------------------------------------------------------
+     *
+     * The location to save sessions to and is driver dependent.
+     *
+     * For the 'files' driver, it's a path to a writable directory.
+     * WARNING: Only absolute paths are supported!
+     *
+     * For the 'database' driver, it's a table name.
+     * Please read up the manual for the format with other session drivers.
+     *
+     * IMPORTANT: You are REQUIRED to set a valid save path!
+     */
+    public string $savePath = WRITEPATH . 'session';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Match IP
+     * --------------------------------------------------------------------------
+     *
+     * Whether to match the user's IP address when reading the session data.
+     *
+     * WARNING: If you're using the database driver, don't forget to update
+     *          your session table's PRIMARY KEY when changing this setting.
+     */
+    public bool $matchIP = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Time to Update
+     * --------------------------------------------------------------------------
+     *
+     * How many seconds between CI regenerating the session ID.
+     */
+    public int $timeToUpdate = 300;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Regenerate Destroy
+     * --------------------------------------------------------------------------
+     *
+     * Whether to destroy session data associated with the old session ID
+     * when auto-regenerating the session ID. When set to FALSE, the data
+     * will be later deleted by the garbage collector.
+     */
+    public bool $regenerateDestroy = false;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Session Database Group
+     * --------------------------------------------------------------------------
+     *
+     * DB Group for the database session.
+     */
+    public ?string $DBGroup = null;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Lock Retry Interval (microseconds)
+     * --------------------------------------------------------------------------
+     *
+     * This is used for RedisHandler.
+     *
+     * Time (microseconds) to wait if lock cannot be acquired.
+     * The default is 100,000 microseconds (= 0.1 seconds).
+     */
+    public int $lockRetryInterval = 100_000;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Lock Max Retries
+     * --------------------------------------------------------------------------
+     *
+     * This is used for RedisHandler.
+     *
+     * Maximum number of lock acquisition attempts.
+     * The default is 300 times. That is lock timeout is about 30 (0.1 * 300)
+     * seconds.
+     */
+    public int $lockMaxRetries = 300;
+}

+ 147 - 0
dgonz/app/Config/Toolbar.php

@@ -0,0 +1,147 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Debug\Toolbar\Collectors\Database;
+use CodeIgniter\Debug\Toolbar\Collectors\Events;
+use CodeIgniter\Debug\Toolbar\Collectors\Files;
+use CodeIgniter\Debug\Toolbar\Collectors\Logs;
+use CodeIgniter\Debug\Toolbar\Collectors\Routes;
+use CodeIgniter\Debug\Toolbar\Collectors\Timers;
+use CodeIgniter\Debug\Toolbar\Collectors\Views;
+
+/**
+ * --------------------------------------------------------------------------
+ * Debug Toolbar
+ * --------------------------------------------------------------------------
+ *
+ * The Debug Toolbar provides a way to see information about the performance
+ * and state of your application during that page display. By default it will
+ * NOT be displayed under production environments, and will only display if
+ * `CI_DEBUG` is true, since if it's not, there's not much to display anyway.
+ */
+class Toolbar extends BaseConfig
+{
+    /**
+     * --------------------------------------------------------------------------
+     * Toolbar Collectors
+     * --------------------------------------------------------------------------
+     *
+     * List of toolbar collectors that will be called when Debug Toolbar
+     * fires up and collects data from.
+     *
+     * @var list<class-string>
+     */
+    public array $collectors = [
+        Timers::class,
+        Database::class,
+        Logs::class,
+        Views::class,
+        // \CodeIgniter\Debug\Toolbar\Collectors\Cache::class,
+        Files::class,
+        Routes::class,
+        Events::class,
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Collect Var Data
+     * --------------------------------------------------------------------------
+     *
+     * If set to false var data from the views will not be collected. Useful to
+     * avoid high memory usage when there are lots of data passed to the view.
+     */
+    public bool $collectVarData = true;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Max History
+     * --------------------------------------------------------------------------
+     *
+     * `$maxHistory` sets a limit on the number of past requests that are stored,
+     * helping to conserve file space used to store them. You can set it to
+     * 0 (zero) to not have any history stored, or -1 for unlimited history.
+     */
+    public int $maxHistory = 20;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Toolbar Views Path
+     * --------------------------------------------------------------------------
+     *
+     * The full path to the the views that are used by the toolbar.
+     * This MUST have a trailing slash.
+     */
+    public string $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Max Queries
+     * --------------------------------------------------------------------------
+     *
+     * If the Database Collector is enabled, it will log every query that the
+     * the system generates so they can be displayed on the toolbar's timeline
+     * and in the query log. This can lead to memory issues in some instances
+     * with hundreds of queries.
+     *
+     * `$maxQueries` defines the maximum amount of queries that will be stored.
+     */
+    public int $maxQueries = 100;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Watched Directories
+     * --------------------------------------------------------------------------
+     *
+     * Contains an array of directories that will be watched for changes and
+     * used to determine if the hot-reload feature should reload the page or not.
+     * We restrict the values to keep performance as high as possible.
+     *
+     * NOTE: The ROOTPATH will be prepended to all values.
+     *
+     * @var list<string>
+     */
+    public array $watchedDirectories = [
+        'app',
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Watched File Extensions
+     * --------------------------------------------------------------------------
+     *
+     * Contains an array of file extensions that will be watched for changes and
+     * used to determine if the hot-reload feature should reload the page or not.
+     *
+     * @var list<string>
+     */
+    public array $watchedExtensions = [
+        'php', 'css', 'js', 'html', 'svg', 'json', 'env',
+    ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Ignored HTTP Headers
+     * --------------------------------------------------------------------------
+     *
+     * CodeIgniter Debug Toolbar normally injects HTML and JavaScript into every
+     * HTML response. This is correct for full page loads, but it breaks requests
+     * that expect only a clean HTML fragment.
+     *
+     * Libraries like HTMX, Unpoly, and Hotwire (Turbo) update parts of the page or
+     * manage navigation on the client side. Injecting the Debug Toolbar into their
+     * responses can cause invalid HTML, duplicated scripts, or JavaScript errors
+     * (such as infinite loops or "Maximum call stack size exceeded").
+     *
+     * Any request containing one of the following headers is treated as a
+     * client-managed or partial request, and the Debug Toolbar injection is skipped.
+     *
+     * @var array<string, string|null>
+     */
+    public array $disableOnHeaders = [
+        'X-Requested-With' => 'xmlhttprequest', // AJAX requests
+        'HX-Request'       => 'true',           // HTMX requests
+        'X-Up-Version'     => null,             // Unpoly partial requests
+    ];
+}

+ 262 - 0
dgonz/app/Config/UserAgents.php

@@ -0,0 +1,262 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * -------------------------------------------------------------------
+ * User Agents
+ * -------------------------------------------------------------------
+ *
+ * This file contains four arrays of user agent data. It is used by the
+ * User Agent Class to help identify browser, platform, robot, and
+ * mobile device data. The array keys are used to identify the device
+ * and the array values are used to set the actual name of the item.
+ */
+class UserAgents extends BaseConfig
+{
+    /**
+     * -------------------------------------------------------------------
+     * OS Platforms
+     * -------------------------------------------------------------------
+     *
+     * @var array<string, string>
+     */
+    public array $platforms = [
+        'windows nt 10.0' => 'Windows 10',
+        'windows nt 6.3'  => 'Windows 8.1',
+        'windows nt 6.2'  => 'Windows 8',
+        'windows nt 6.1'  => 'Windows 7',
+        'windows nt 6.0'  => 'Windows Vista',
+        'windows nt 5.2'  => 'Windows 2003',
+        'windows nt 5.1'  => 'Windows XP',
+        'windows nt 5.0'  => 'Windows 2000',
+        'windows nt 4.0'  => 'Windows NT 4.0',
+        'winnt4.0'        => 'Windows NT 4.0',
+        'winnt 4.0'       => 'Windows NT',
+        'winnt'           => 'Windows NT',
+        'windows 98'      => 'Windows 98',
+        'win98'           => 'Windows 98',
+        'windows 95'      => 'Windows 95',
+        'win95'           => 'Windows 95',
+        'windows phone'   => 'Windows Phone',
+        'windows'         => 'Unknown Windows OS',
+        'android'         => 'Android',
+        'blackberry'      => 'BlackBerry',
+        'iphone'          => 'iOS',
+        'ipad'            => 'iOS',
+        'ipod'            => 'iOS',
+        'os x'            => 'Mac OS X',
+        'ppc mac'         => 'Power PC Mac',
+        'freebsd'         => 'FreeBSD',
+        'ppc'             => 'Macintosh',
+        'linux'           => 'Linux',
+        'debian'          => 'Debian',
+        'sunos'           => 'Sun Solaris',
+        'beos'            => 'BeOS',
+        'apachebench'     => 'ApacheBench',
+        'aix'             => 'AIX',
+        'irix'            => 'Irix',
+        'osf'             => 'DEC OSF',
+        'hp-ux'           => 'HP-UX',
+        'netbsd'          => 'NetBSD',
+        'bsdi'            => 'BSDi',
+        'openbsd'         => 'OpenBSD',
+        'gnu'             => 'GNU/Linux',
+        'unix'            => 'Unknown Unix OS',
+        'symbian'         => 'Symbian OS',
+    ];
+
+    /**
+     * -------------------------------------------------------------------
+     * Browsers
+     * -------------------------------------------------------------------
+     *
+     * The order of this array should NOT be changed. Many browsers return
+     * multiple browser types so we want to identify the subtype first.
+     *
+     * @var array<string, string>
+     */
+    public array $browsers = [
+        'OPR'    => 'Opera',
+        'Flock'  => 'Flock',
+        'Edge'   => 'Spartan',
+        'Edg'    => 'Edge',
+        'Chrome' => 'Chrome',
+        // Opera 10+ always reports Opera/9.80 and appends Version/<real version> to the user agent string
+        'Opera.*?Version'   => 'Opera',
+        'Opera'             => 'Opera',
+        'MSIE'              => 'Internet Explorer',
+        'Internet Explorer' => 'Internet Explorer',
+        'Trident.* rv'      => 'Internet Explorer',
+        'Shiira'            => 'Shiira',
+        'Firefox'           => 'Firefox',
+        'Chimera'           => 'Chimera',
+        'Phoenix'           => 'Phoenix',
+        'Firebird'          => 'Firebird',
+        'Camino'            => 'Camino',
+        'Netscape'          => 'Netscape',
+        'OmniWeb'           => 'OmniWeb',
+        'Safari'            => 'Safari',
+        'Mozilla'           => 'Mozilla',
+        'Konqueror'         => 'Konqueror',
+        'icab'              => 'iCab',
+        'Lynx'              => 'Lynx',
+        'Links'             => 'Links',
+        'hotjava'           => 'HotJava',
+        'amaya'             => 'Amaya',
+        'IBrowse'           => 'IBrowse',
+        'Maxthon'           => 'Maxthon',
+        'Ubuntu'            => 'Ubuntu Web Browser',
+        'Vivaldi'           => 'Vivaldi',
+    ];
+
+    /**
+     * -------------------------------------------------------------------
+     * Mobiles
+     * -------------------------------------------------------------------
+     *
+     * @var array<string, string>
+     */
+    public array $mobiles = [
+        // legacy array, old values commented out
+        'mobileexplorer' => 'Mobile Explorer',
+        // 'openwave'             => 'Open Wave',
+        // 'opera mini'           => 'Opera Mini',
+        // 'operamini'            => 'Opera Mini',
+        // 'elaine'               => 'Palm',
+        'palmsource' => 'Palm',
+        // 'digital paths'        => 'Palm',
+        // 'avantgo'              => 'Avantgo',
+        // 'xiino'                => 'Xiino',
+        'palmscape' => 'Palmscape',
+        // 'nokia'                => 'Nokia',
+        // 'ericsson'             => 'Ericsson',
+        // 'blackberry'           => 'BlackBerry',
+        // 'motorola'             => 'Motorola'
+
+        // Phones and Manufacturers
+        'motorola'             => 'Motorola',
+        'nokia'                => 'Nokia',
+        'palm'                 => 'Palm',
+        'iphone'               => 'Apple iPhone',
+        'ipad'                 => 'iPad',
+        'ipod'                 => 'Apple iPod Touch',
+        'sony'                 => 'Sony Ericsson',
+        'ericsson'             => 'Sony Ericsson',
+        'blackberry'           => 'BlackBerry',
+        'cocoon'               => 'O2 Cocoon',
+        'blazer'               => 'Treo',
+        'lg'                   => 'LG',
+        'amoi'                 => 'Amoi',
+        'xda'                  => 'XDA',
+        'mda'                  => 'MDA',
+        'vario'                => 'Vario',
+        'htc'                  => 'HTC',
+        'samsung'              => 'Samsung',
+        'sharp'                => 'Sharp',
+        'sie-'                 => 'Siemens',
+        'alcatel'              => 'Alcatel',
+        'benq'                 => 'BenQ',
+        'ipaq'                 => 'HP iPaq',
+        'mot-'                 => 'Motorola',
+        'playstation portable' => 'PlayStation Portable',
+        'playstation 3'        => 'PlayStation 3',
+        'playstation vita'     => 'PlayStation Vita',
+        'hiptop'               => 'Danger Hiptop',
+        'nec-'                 => 'NEC',
+        'panasonic'            => 'Panasonic',
+        'philips'              => 'Philips',
+        'sagem'                => 'Sagem',
+        'sanyo'                => 'Sanyo',
+        'spv'                  => 'SPV',
+        'zte'                  => 'ZTE',
+        'sendo'                => 'Sendo',
+        'nintendo dsi'         => 'Nintendo DSi',
+        'nintendo ds'          => 'Nintendo DS',
+        'nintendo 3ds'         => 'Nintendo 3DS',
+        'wii'                  => 'Nintendo Wii',
+        'open web'             => 'Open Web',
+        'openweb'              => 'OpenWeb',
+
+        // Operating Systems
+        'android'    => 'Android',
+        'symbian'    => 'Symbian',
+        'SymbianOS'  => 'SymbianOS',
+        'elaine'     => 'Palm',
+        'series60'   => 'Symbian S60',
+        'windows ce' => 'Windows CE',
+
+        // Browsers
+        'obigo'         => 'Obigo',
+        'netfront'      => 'Netfront Browser',
+        'openwave'      => 'Openwave Browser',
+        'mobilexplorer' => 'Mobile Explorer',
+        'operamini'     => 'Opera Mini',
+        'opera mini'    => 'Opera Mini',
+        'opera mobi'    => 'Opera Mobile',
+        'fennec'        => 'Firefox Mobile',
+
+        // Other
+        'digital paths' => 'Digital Paths',
+        'avantgo'       => 'AvantGo',
+        'xiino'         => 'Xiino',
+        'novarra'       => 'Novarra Transcoder',
+        'vodafone'      => 'Vodafone',
+        'docomo'        => 'NTT DoCoMo',
+        'o2'            => 'O2',
+
+        // Fallback
+        'mobile'     => 'Generic Mobile',
+        'wireless'   => 'Generic Mobile',
+        'j2me'       => 'Generic Mobile',
+        'midp'       => 'Generic Mobile',
+        'cldc'       => 'Generic Mobile',
+        'up.link'    => 'Generic Mobile',
+        'up.browser' => 'Generic Mobile',
+        'smartphone' => 'Generic Mobile',
+        'cellphone'  => 'Generic Mobile',
+    ];
+
+    /**
+     * -------------------------------------------------------------------
+     * Robots
+     * -------------------------------------------------------------------
+     *
+     * There are hundred of bots but these are the most common.
+     *
+     * @var array<string, string>
+     */
+    public array $robots = [
+        'googlebot'            => 'Googlebot',
+        'google-pagerenderer'  => 'Google Page Renderer',
+        'google-read-aloud'    => 'Google Read Aloud',
+        'google-safety'        => 'Google Safety Bot',
+        'msnbot'               => 'MSNBot',
+        'baiduspider'          => 'Baiduspider',
+        'bingbot'              => 'Bing',
+        'bingpreview'          => 'BingPreview',
+        'slurp'                => 'Inktomi Slurp',
+        'yahoo'                => 'Yahoo',
+        'ask jeeves'           => 'Ask Jeeves',
+        'fastcrawler'          => 'FastCrawler',
+        'infoseek'             => 'InfoSeek Robot 1.0',
+        'lycos'                => 'Lycos',
+        'yandex'               => 'YandexBot',
+        'mediapartners-google' => 'MediaPartners Google',
+        'CRAZYWEBCRAWLER'      => 'Crazy Webcrawler',
+        'adsbot-google'        => 'AdsBot Google',
+        'feedfetcher-google'   => 'Feedfetcher Google',
+        'curious george'       => 'Curious George',
+        'ia_archiver'          => 'Alexa Crawler',
+        'MJ12bot'              => 'Majestic-12',
+        'Uptimebot'            => 'Uptimebot',
+        'duckduckbot'          => 'DuckDuckBot',
+        'sogou'                => 'Sogou Spider',
+        'exabot'               => 'Exabot',
+        'bot'                  => 'Generic Bot',
+        'crawler'              => 'Generic Crawler',
+        'spider'               => 'Generic Spider',
+    ];
+}

+ 44 - 0
dgonz/app/Config/Validation.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Validation\StrictRules\CreditCardRules;
+use CodeIgniter\Validation\StrictRules\FileRules;
+use CodeIgniter\Validation\StrictRules\FormatRules;
+use CodeIgniter\Validation\StrictRules\Rules;
+
+class Validation extends BaseConfig
+{
+    // --------------------------------------------------------------------
+    // Setup
+    // --------------------------------------------------------------------
+
+    /**
+     * Stores the classes that contain the
+     * rules that are available.
+     *
+     * @var list<string>
+     */
+    public array $ruleSets = [
+        Rules::class,
+        FormatRules::class,
+        FileRules::class,
+        CreditCardRules::class,
+    ];
+
+    /**
+     * Specifies the views that are used to display the
+     * errors.
+     *
+     * @var array<string, string>
+     */
+    public array $templates = [
+        'list'   => 'CodeIgniter\Validation\Views\list',
+        'single' => 'CodeIgniter\Validation\Views\single',
+    ];
+
+    // --------------------------------------------------------------------
+    // Rules
+    // --------------------------------------------------------------------
+}

+ 73 - 0
dgonz/app/Config/View.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\View as BaseView;
+use CodeIgniter\View\ViewDecoratorInterface;
+
+class View extends BaseView
+{
+    /**
+     * When false, the view method will clear the data between each
+     * call. This keeps your data safe and ensures there is no accidental
+     * leaking between calls, so you would need to explicitly pass the data
+     * to each view. You might prefer to have the data stick around between
+     * calls so that it is available to all views. If that is the case,
+     * set $saveData to true.
+     *
+     * @var bool
+     */
+    public $saveData = true;
+
+    /**
+     * Parser Filters map a filter name with any PHP callable. When the
+     * Parser prepares a variable for display, it will chain it
+     * through the filters in the order defined, inserting any parameters.
+     * To prevent potential abuse, all filters MUST be defined here
+     * in order for them to be available for use within the Parser.
+     *
+     * Examples:
+     *  { title|esc(js) }
+     *  { created_on|date(Y-m-d)|esc(attr) }
+     *
+     * @var array<string, (callable(mixed): mixed)&string>
+     */
+    public $filters = [];
+
+    /**
+     * Parser Plugins provide a way to extend the functionality provided
+     * by the core Parser by creating aliases that will be replaced with
+     * any callable. Can be single or tag pair.
+     *
+     * @var array<string, (callable(mixed...): mixed)|((callable(mixed...): mixed)&string)|list<(callable(mixed...): mixed)&string>>
+     */
+    public $plugins = [];
+
+    /**
+     * View Decorators are class methods that will be run in sequence to
+     * have a chance to alter the generated output just prior to caching
+     * the results.
+     *
+     * All classes must implement CodeIgniter\View\ViewDecoratorInterface
+     *
+     * @var list<class-string<ViewDecoratorInterface>>
+     */
+    public array $decorators = [];
+
+    /**
+     * Subdirectory within app/Views for namespaced view overrides.
+     *
+     * Namespaced views will be searched in:
+     *
+     *   app/Views/{$appOverridesFolder}/{Namespace}/{view_path}.{php|html...}
+     *
+     * This allows application-level overrides for package or module views
+     * without modifying vendor source files.
+     *
+     * Examples:
+     *   'overrides' -> app/Views/overrides/Example/Blog/post/card.php
+     *   'vendor'    -> app/Views/vendor/Example/Blog/post/card.php
+     *   ''          -> app/Views/Example/Blog/post/card.php (direct mapping)
+     */
+    public string $appOverridesFolder = 'overrides';
+}

+ 62 - 0
dgonz/app/Config/WorkerMode.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace Config;
+
+/**
+ * This configuration controls how CodeIgniter behaves when running
+ * in worker mode (with FrankenPHP).
+ */
+class WorkerMode
+{
+    /**
+     * Persistent Services
+     *
+     * List of service names that should persist across requests.
+     * These services will NOT be reset between requests.
+     *
+     * Services not in this list will be reset for each request to prevent
+     * state leakage.
+     *
+     * Recommended persistent services:
+     * - `autoloader`: PSR-4 autoloading configuration
+     * - `locator`: File locator
+     * - `exceptions`: Exception handler
+     * - `commands`: CLI commands registry
+     * - `codeigniter`: Main application instance
+     * - `superglobals`: Superglobals wrapper
+     * - `routes`: Router configuration
+     * - `cache`: Cache instance
+     *
+     * @var list<string>
+     */
+    public array $persistentServices = [
+        'autoloader',
+        'locator',
+        'exceptions',
+        'commands',
+        'codeigniter',
+        'superglobals',
+        'routes',
+        'cache',
+    ];
+
+    /**
+     * Reset Event Listeners
+     *
+     * List of event names whose listeners should be removed between requests.
+     * Use this if you register event listeners inside other event callbacks
+     * (rather than at the top level of Config/Events.php), which would cause
+     * them to accumulate across requests in worker mode.
+     *
+     * @var list<string>
+     */
+    public array $resetEventListeners = [];
+
+    /**
+     * Force Garbage Collection
+     *
+     * Whether to force garbage collection after each request.
+     * Helps prevent memory leaks at a small performance cost.
+     */
+    public bool $forceGarbageCollection = true;
+}

+ 45 - 0
dgonz/app/Controllers/BaseController.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace App\Controllers;
+
+use CodeIgniter\Controller;
+use CodeIgniter\HTTP\RequestInterface;
+use CodeIgniter\HTTP\ResponseInterface;
+use Psr\Log\LoggerInterface;
+
+/**
+ * BaseController provides a convenient place for loading components
+ * and performing functions that are needed by all your controllers.
+ *
+ * Extend this class in any new controllers:
+ * ```
+ *     class Home extends BaseController
+ * ```
+ *
+ * For security, be sure to declare any new methods as protected or private.
+ */
+abstract class BaseController extends Controller
+{
+    /**
+     * Be sure to declare properties for any property fetch you initialized.
+     * The creation of dynamic property is deprecated in PHP 8.2.
+     */
+
+    // protected $session;
+
+    /**
+     * @return void
+     */
+    public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
+    {
+        // Load here all helpers you want to be available in your controllers that extend BaseController.
+        // Caution: Do not put the this below the parent::initController() call below.
+        // $this->helpers = ['form', 'url'];
+
+        // Caution: Do not edit this line.
+        parent::initController($request, $response, $logger);
+
+        // Preload any models, libraries, etc, here.
+        // $this->session = service('session');
+    }
+}

+ 11 - 0
dgonz/app/Controllers/Home.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace App\Controllers;
+
+class Home extends BaseController
+{
+    public function index(): string
+    {
+        return view('welcome_message');
+    }
+}

+ 0 - 0
dgonz/app/Database/Migrations/.gitkeep


+ 0 - 0
dgonz/app/Database/Seeds/.gitkeep


+ 0 - 0
dgonz/app/Filters/.gitkeep


+ 0 - 0
dgonz/app/Helpers/.gitkeep


+ 0 - 0
dgonz/app/Language/.gitkeep


+ 4 - 0
dgonz/app/Language/en/Validation.php

@@ -0,0 +1,4 @@
+<?php
+
+// override core en language system validation or define your own en language validation message
+return [];

+ 0 - 0
dgonz/app/Libraries/.gitkeep


+ 0 - 0
dgonz/app/Models/.gitkeep


+ 0 - 0
dgonz/app/ThirdParty/.gitkeep


+ 7 - 0
dgonz/app/Views/errors/cli/error_404.php

@@ -0,0 +1,7 @@
+<?php
+
+use CodeIgniter\CLI\CLI;
+
+CLI::error('ERROR: ' . $code);
+CLI::write($message);
+CLI::newLine();

+ 65 - 0
dgonz/app/Views/errors/cli/error_exception.php

@@ -0,0 +1,65 @@
+<?php
+
+use CodeIgniter\CLI\CLI;
+
+// The main Exception
+CLI::write('[' . $exception::class . ']', 'light_gray', 'red');
+CLI::write($message);
+CLI::write('at ' . CLI::color(clean_path($exception->getFile()) . ':' . $exception->getLine(), 'green'));
+CLI::newLine();
+
+$last = $exception;
+
+while ($prevException = $last->getPrevious()) {
+    $last = $prevException;
+
+    CLI::write('  Caused by:');
+    CLI::write('  [' . $prevException::class . ']', 'red');
+    CLI::write('  ' . $prevException->getMessage());
+    CLI::write('  at ' . CLI::color(clean_path($prevException->getFile()) . ':' . $prevException->getLine(), 'green'));
+    CLI::newLine();
+}
+
+// The backtrace
+if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) {
+    $backtraces = $last->getTrace();
+
+    if ($backtraces) {
+        CLI::write('Backtrace:', 'green');
+    }
+
+    foreach ($backtraces as $i => $error) {
+        $padFile  = '    '; // 4 spaces
+        $padClass = '       '; // 7 spaces
+        $c        = str_pad($i + 1, 3, ' ', STR_PAD_LEFT);
+
+        if (isset($error['file'])) {
+            $filepath = clean_path($error['file']) . ':' . $error['line'];
+
+            CLI::write($c . $padFile . CLI::color($filepath, 'yellow'));
+        } else {
+            CLI::write($c . $padFile . CLI::color('[internal function]', 'yellow'));
+        }
+
+        $function = '';
+
+        if (isset($error['class'])) {
+            $type = ($error['type'] === '->') ? '()' . $error['type'] : $error['type'];
+            $function .= $padClass . $error['class'] . $type . $error['function'];
+        } elseif (! isset($error['class']) && isset($error['function'])) {
+            $function .= $padClass . $error['function'];
+        }
+
+        $args = implode(', ', array_map(static fn ($value): string => match (true) {
+            is_object($value) => 'Object(' . $value::class . ')',
+            is_array($value)  => $value !== [] ? '[...]' : '[]',
+            $value === null   => 'null', // return the lowercased version
+            default           => var_export($value, true),
+        }, array_values($error['args'] ?? [])));
+
+        $function .= '(' . $args . ')';
+
+        CLI::write($function);
+        CLI::newLine();
+    }
+}

+ 5 - 0
dgonz/app/Views/errors/cli/production.php

@@ -0,0 +1,5 @@
+<?php
+
+// On the CLI, we still want errors in productions
+// so just use the exception template.
+include __DIR__ . '/error_exception.php';

+ 194 - 0
dgonz/app/Views/errors/html/debug.css

@@ -0,0 +1,194 @@
+:root {
+    --main-bg-color: #fff;
+    --main-text-color: #555;
+    --dark-text-color: #222;
+    --light-text-color: #c7c7c7;
+    --brand-primary-color: #DC4814;
+    --light-bg-color: #ededee;
+    --dark-bg-color: #404040;
+}
+
+body {
+    height: 100%;
+    background: var(--main-bg-color);
+    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
+    color: var(--main-text-color);
+    font-weight: 300;
+    margin: 0;
+    padding: 0;
+}
+h1 {
+    font-weight: lighter;
+    font-size: 3rem;
+    color: var(--dark-text-color);
+    margin: 0;
+}
+h1.headline {
+    margin-top: 20%;
+    font-size: 5rem;
+}
+.text-center {
+    text-align: center;
+}
+p.lead {
+    font-size: 1.6rem;
+}
+.container {
+    max-width: 75rem;
+    margin: 0 auto;
+    padding: 1rem;
+}
+.header {
+    background: var(--light-bg-color);
+    color: var(--dark-text-color);
+    margin-top: 2.17rem;
+}
+.header .container {
+    padding: 1rem;
+}
+.header h1 {
+    font-size: 2.5rem;
+    font-weight: 500;
+}
+.header p {
+    font-size: 1.2rem;
+    margin: 0;
+    line-height: 2.5;
+}
+.header a {
+    color: var(--brand-primary-color);
+    margin-left: 2rem;
+    display: none;
+    text-decoration: none;
+}
+.header:hover a {
+    display: inline;
+}
+
+.environment {
+    background: var(--brand-primary-color);
+    color: var(--main-bg-color);
+    text-align: center;
+    padding: calc(4px + 0.2083vw);
+    width: 100%;
+    top: 0;
+    position: fixed;
+}
+
+.source {
+    background: #343434;
+    color: var(--light-text-color);
+    padding: 0.5em 1em;
+    border-radius: 5px;
+    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+    font-size: 0.85rem;
+    margin: 0;
+    overflow-x: scroll;
+}
+.source span.line {
+    line-height: 1.4;
+}
+.source span.line .number {
+    color: #666;
+}
+.source .line .highlight {
+    display: block;
+    background: var(--dark-text-color);
+    color: var(--light-text-color);
+}
+.source span.highlight .number {
+    color: #fff;
+}
+
+.tabs {
+    list-style: none;
+    list-style-position: inside;
+    margin: 0;
+    padding: 0;
+    margin-bottom: -1px;
+}
+.tabs li {
+    display: inline;
+}
+.tabs a:link,
+.tabs a:visited {
+    padding: 0 1rem;
+    line-height: 2.7;
+    text-decoration: none;
+    color: var(--dark-text-color);
+    background: var(--light-bg-color);
+    border: 1px solid rgba(0,0,0,0.15);
+    border-bottom: 0;
+    border-top-left-radius: 5px;
+    border-top-right-radius: 5px;
+    display: inline-block;
+}
+.tabs a:hover {
+    background: var(--light-bg-color);
+    border-color: rgba(0,0,0,0.15);
+}
+.tabs a.active {
+    background: var(--main-bg-color);
+    color: var(--main-text-color);
+}
+.tab-content {
+    background: var(--main-bg-color);
+    border: 1px solid rgba(0,0,0,0.15);
+}
+.content {
+    padding: 1rem;
+}
+.hide {
+    display: none;
+}
+
+.alert {
+    margin-top: 2rem;
+    display: block;
+    text-align: center;
+    line-height: 3.0;
+    background: #d9edf7;
+    border: 1px solid #bcdff1;
+    border-radius: 5px;
+    color: #31708f;
+}
+
+table {
+    width: 100%;
+    overflow: hidden;
+}
+th {
+    text-align: left;
+    border-bottom: 1px solid #e7e7e7;
+    padding-bottom: 0.5rem;
+}
+td {
+    padding: 0.2rem 0.5rem 0.2rem 0;
+}
+tr:hover td {
+    background: #f1f1f1;
+}
+td pre {
+    white-space: pre-wrap;
+}
+
+.trace a {
+    color: inherit;
+}
+.trace table {
+    width: auto;
+}
+.trace tr td:first-child {
+    min-width: 5em;
+    font-weight: bold;
+}
+.trace td {
+    background: var(--light-bg-color);
+    padding: 0 1rem;
+}
+.trace td pre {
+    margin: 0;
+}
+.args {
+    display: none;
+}

+ 116 - 0
dgonz/app/Views/errors/html/debug.js

@@ -0,0 +1,116 @@
+var tabLinks    = new Array();
+var contentDivs = new Array();
+
+function init()
+{
+    // Grab the tab links and content divs from the page
+    var tabListItems = document.getElementById('tabs').childNodes;
+    console.log(tabListItems);
+    for (var i = 0; i < tabListItems.length; i ++)
+    {
+        if (tabListItems[i].nodeName == "LI")
+        {
+            var tabLink     = getFirstChildWithTagName(tabListItems[i], 'A');
+            var id          = getHash(tabLink.getAttribute('href'));
+            tabLinks[id]    = tabLink;
+            contentDivs[id] = document.getElementById(id);
+        }
+    }
+
+    // Assign onclick events to the tab links, and
+    // highlight the first tab
+    var i = 0;
+
+    for (var id in tabLinks)
+    {
+        tabLinks[id].onclick = showTab;
+        tabLinks[id].onfocus = function () {
+            this.blur()
+        };
+        if (i == 0)
+        {
+            tabLinks[id].className = 'active';
+        }
+        i ++;
+    }
+
+    // Hide all content divs except the first
+    var i = 0;
+
+    for (var id in contentDivs)
+    {
+        if (i != 0)
+        {
+            console.log(contentDivs[id]);
+            contentDivs[id].className = 'content hide';
+        }
+        i ++;
+    }
+}
+
+function showTab()
+{
+    var selectedId = getHash(this.getAttribute('href'));
+
+    // Highlight the selected tab, and dim all others.
+    // Also show the selected content div, and hide all others.
+    for (var id in contentDivs)
+    {
+        if (id == selectedId)
+        {
+            tabLinks[id].className    = 'active';
+            contentDivs[id].className = 'content';
+        }
+        else
+        {
+            tabLinks[id].className    = '';
+            contentDivs[id].className = 'content hide';
+        }
+    }
+
+    // Stop the browser following the link
+    return false;
+}
+
+function getFirstChildWithTagName(element, tagName)
+{
+    for (var i = 0; i < element.childNodes.length; i ++)
+    {
+        if (element.childNodes[i].nodeName == tagName)
+        {
+            return element.childNodes[i];
+        }
+    }
+}
+
+function getHash(url)
+{
+    var hashPos = url.lastIndexOf('#');
+    return url.substring(hashPos + 1);
+}
+
+function toggle(elem)
+{
+    elem = document.getElementById(elem);
+
+    if (elem.style && elem.style['display'])
+    {
+        // Only works with the "style" attr
+        var disp = elem.style['display'];
+    }
+    else if (elem.currentStyle)
+    {
+        // For MSIE, naturally
+        var disp = elem.currentStyle['display'];
+    }
+    else if (window.getComputedStyle)
+    {
+        // For most other browsers
+        var disp = document.defaultView.getComputedStyle(elem, null).getPropertyValue('display');
+    }
+
+    // Toggle the state of the "display" style
+    elem.style.display = disp == 'block' ? 'none' : 'block';
+
+    return false;
+}

+ 84 - 0
dgonz/app/Views/errors/html/error_400.php

@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title><?= lang('Errors.badRequest') ?></title>
+
+    <style>
+        div.logo {
+            height: 200px;
+            width: 155px;
+            display: inline-block;
+            opacity: 0.08;
+            position: absolute;
+            top: 2rem;
+            left: 50%;
+            margin-left: -73px;
+        }
+        body {
+            height: 100%;
+            background: #fafafa;
+            font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+            color: #777;
+            font-weight: 300;
+        }
+        h1 {
+            font-weight: lighter;
+            letter-spacing: normal;
+            font-size: 3rem;
+            margin-top: 0;
+            margin-bottom: 0;
+            color: #222;
+        }
+        .wrap {
+            max-width: 1024px;
+            margin: 5rem auto;
+            padding: 2rem;
+            background: #fff;
+            text-align: center;
+            border: 1px solid #efefef;
+            border-radius: 0.5rem;
+            position: relative;
+        }
+        pre {
+            white-space: normal;
+            margin-top: 1.5rem;
+        }
+        code {
+            background: #fafafa;
+            border: 1px solid #efefef;
+            padding: 0.5rem 1rem;
+            border-radius: 5px;
+            display: block;
+        }
+        p {
+            margin-top: 1.5rem;
+        }
+        .footer {
+            margin-top: 2rem;
+            border-top: 1px solid #efefef;
+            padding: 1em 2em 0 2em;
+            font-size: 85%;
+            color: #999;
+        }
+        a:active,
+        a:link,
+        a:visited {
+            color: #dd4814;
+        }
+    </style>
+</head>
+<body>
+<div class="wrap">
+    <h1>400</h1>
+
+    <p>
+        <?php if (ENVIRONMENT !== 'production') : ?>
+            <?= nl2br(esc($message)) ?>
+        <?php else : ?>
+            <?= lang('Errors.sorryBadRequest') ?>
+        <?php endif; ?>
+    </p>
+</div>
+</body>
+</html>

+ 84 - 0
dgonz/app/Views/errors/html/error_404.php

@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title><?= lang('Errors.pageNotFound') ?></title>
+
+    <style>
+        div.logo {
+            height: 200px;
+            width: 155px;
+            display: inline-block;
+            opacity: 0.08;
+            position: absolute;
+            top: 2rem;
+            left: 50%;
+            margin-left: -73px;
+        }
+        body {
+            height: 100%;
+            background: #fafafa;
+            font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+            color: #777;
+            font-weight: 300;
+        }
+        h1 {
+            font-weight: lighter;
+            letter-spacing: normal;
+            font-size: 3rem;
+            margin-top: 0;
+            margin-bottom: 0;
+            color: #222;
+        }
+        .wrap {
+            max-width: 1024px;
+            margin: 5rem auto;
+            padding: 2rem;
+            background: #fff;
+            text-align: center;
+            border: 1px solid #efefef;
+            border-radius: 0.5rem;
+            position: relative;
+        }
+        pre {
+            white-space: normal;
+            margin-top: 1.5rem;
+        }
+        code {
+            background: #fafafa;
+            border: 1px solid #efefef;
+            padding: 0.5rem 1rem;
+            border-radius: 5px;
+            display: block;
+        }
+        p {
+            margin-top: 1.5rem;
+        }
+        .footer {
+            margin-top: 2rem;
+            border-top: 1px solid #efefef;
+            padding: 1em 2em 0 2em;
+            font-size: 85%;
+            color: #999;
+        }
+        a:active,
+        a:link,
+        a:visited {
+            color: #dd4814;
+        }
+    </style>
+</head>
+<body>
+    <div class="wrap">
+        <h1>404</h1>
+
+        <p>
+            <?php if (ENVIRONMENT !== 'production') : ?>
+                <?= nl2br(esc($message)) ?>
+            <?php else : ?>
+                <?= lang('Errors.sorryCannotFind') ?>
+            <?php endif; ?>
+        </p>
+    </div>
+</body>
+</html>

+ 429 - 0
dgonz/app/Views/errors/html/error_exception.php

@@ -0,0 +1,429 @@
+<?php
+use CodeIgniter\HTTP\Header;
+use CodeIgniter\CodeIgniter;
+
+$errorId = uniqid('error', true);
+?>
+<!doctype html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <meta name="robots" content="noindex">
+
+    <title><?= esc($title) ?></title>
+    <style>
+        <?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
+    </style>
+
+    <script>
+        <?= file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.js') ?>
+    </script>
+</head>
+<body onload="init()">
+
+    <!-- Header -->
+    <div class="header">
+        <div class="environment">
+            Displayed at <?= esc(date('H:i:s')) ?> &mdash;
+            PHP: <?= esc(PHP_VERSION) ?>  &mdash;
+            CodeIgniter: <?= esc(CodeIgniter::CI_VERSION) ?> --
+            Environment: <?= ENVIRONMENT ?>
+        </div>
+        <div class="container">
+            <h1><?= esc($title), esc($exception->getCode() ? ' #' . $exception->getCode() : '') ?></h1>
+            <p>
+                <?= nl2br(esc($exception->getMessage())) ?>
+                <a href="https://www.duckduckgo.com/?q=<?= urlencode($title . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())) ?>"
+                   rel="noreferrer" target="_blank">search &rarr;</a>
+            </p>
+        </div>
+    </div>
+
+    <!-- Source -->
+    <div class="container">
+        <p><b><?= esc(clean_path($file)) ?></b> at line <b><?= esc($line) ?></b></p>
+
+        <?php if (is_file($file)) : ?>
+            <div class="source">
+                <?= static::highlightFile($file, $line, 15); ?>
+            </div>
+        <?php endif; ?>
+    </div>
+
+    <div class="container">
+        <?php
+        $last = $exception;
+
+        while ($prevException = $last->getPrevious()) {
+            $last = $prevException;
+            ?>
+
+    <pre>
+    Caused by:
+    <?= esc($prevException::class), esc($prevException->getCode() ? ' #' . $prevException->getCode() : '') ?>
+
+    <?= nl2br(esc($prevException->getMessage())) ?>
+    <a href="https://www.duckduckgo.com/?q=<?= urlencode($prevException::class . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $prevException->getMessage())) ?>"
+       rel="noreferrer" target="_blank">search &rarr;</a>
+    <?= esc(clean_path($prevException->getFile()) . ':' . $prevException->getLine()) ?>
+    </pre>
+
+        <?php
+        }
+        ?>
+    </div>
+
+    <?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) : ?>
+    <div class="container">
+
+        <ul class="tabs" id="tabs">
+            <li><a href="#backtrace">Backtrace</a></li>
+            <li><a href="#server">Server</a></li>
+            <li><a href="#request">Request</a></li>
+            <li><a href="#response">Response</a></li>
+            <li><a href="#files">Files</a></li>
+            <li><a href="#memory">Memory</a></li>
+        </ul>
+
+        <div class="tab-content">
+
+            <!-- Backtrace -->
+            <div class="content" id="backtrace">
+
+                <ol class="trace">
+                <?php foreach ($trace as $index => $row) : ?>
+
+                    <li>
+                        <p>
+                            <!-- Trace info -->
+                            <?php if (isset($row['file']) && is_file($row['file'])) : ?>
+                                <?php
+                                if (isset($row['function']) && in_array($row['function'], ['include', 'include_once', 'require', 'require_once'], true)) {
+                                    echo esc($row['function'] . ' ' . clean_path($row['file']));
+                                } else {
+                                    echo esc(clean_path($row['file']) . ' : ' . $row['line']);
+                                }
+                                ?>
+                            <?php else: ?>
+                                {PHP internal code}
+                            <?php endif; ?>
+
+                            <!-- Class/Method -->
+                            <?php if (isset($row['class'])) : ?>
+                                &nbsp;&nbsp;&mdash;&nbsp;&nbsp;<?= esc($row['class'] . $row['type'] . $row['function']) ?>
+                                <?php if (! empty($row['args'])) : ?>
+                                    <?php $argsId = $errorId . 'args' . $index ?>
+                                    ( <a href="#" onclick="return toggle('<?= esc($argsId, 'attr') ?>');">arguments</a> )
+                                    <div class="args" id="<?= esc($argsId, 'attr') ?>">
+                                        <table cellspacing="0">
+
+                                        <?php
+                                        $params = null;
+                                        // Reflection by name is not available for closure function
+                                        if (! str_ends_with($row['function'], '}')) {
+                                            $mirror = isset($row['class']) ? new ReflectionMethod($row['class'], $row['function']) : new ReflectionFunction($row['function']);
+                                            $params = $mirror->getParameters();
+                                        }
+
+                                        foreach ($row['args'] as $key => $value) : ?>
+                                            <tr>
+                                                <td><code><?= esc(isset($params[$key]) ? '$' . $params[$key]->name : "#{$key}") ?></code></td>
+                                                <td><pre><?= esc(print_r($value, true)) ?></pre></td>
+                                            </tr>
+                                        <?php endforeach ?>
+
+                                        </table>
+                                    </div>
+                                <?php else : ?>
+                                    ()
+                                <?php endif; ?>
+                            <?php endif; ?>
+
+                            <?php if (! isset($row['class']) && isset($row['function'])) : ?>
+                                &nbsp;&nbsp;&mdash;&nbsp;&nbsp;    <?= esc($row['function']) ?>()
+                            <?php endif; ?>
+                        </p>
+
+                        <!-- Source? -->
+                        <?php if (isset($row['file']) && is_file($row['file']) && isset($row['class'])) : ?>
+                            <div class="source">
+                                <?= static::highlightFile($row['file'], $row['line']) ?>
+                            </div>
+                        <?php endif; ?>
+                    </li>
+
+                <?php endforeach; ?>
+                </ol>
+
+            </div>
+
+            <!-- Server -->
+            <div class="content" id="server">
+                <?php foreach (['_SERVER', '_SESSION'] as $var) : ?>
+                    <?php
+                    if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
+                        continue;
+                    } ?>
+
+                    <h3>$<?= esc($var) ?></h3>
+
+                    <table>
+                        <thead>
+                            <tr>
+                                <th>Key</th>
+                                <th>Value</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <?php foreach ($GLOBALS[$var] as $key => $value) : ?>
+                            <tr>
+                                <td><?= esc($key) ?></td>
+                                <td>
+                                    <?php if (is_string($value)) : ?>
+                                        <?= esc($value) ?>
+                                    <?php else: ?>
+                                        <pre><?= esc(print_r($value, true)) ?></pre>
+                                    <?php endif; ?>
+                                </td>
+                            </tr>
+                        <?php endforeach; ?>
+                        </tbody>
+                    </table>
+
+                <?php endforeach ?>
+
+                <!-- Constants -->
+                <?php $constants = get_defined_constants(true); ?>
+                <?php if (! empty($constants['user'])) : ?>
+                    <h3>Constants</h3>
+
+                    <table>
+                        <thead>
+                            <tr>
+                                <th>Key</th>
+                                <th>Value</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <?php foreach ($constants['user'] as $key => $value) : ?>
+                            <tr>
+                                <td><?= esc($key) ?></td>
+                                <td>
+                                    <?php if (is_string($value)) : ?>
+                                        <?= esc($value) ?>
+                                    <?php else: ?>
+                                        <pre><?= esc(print_r($value, true)) ?></pre>
+                                    <?php endif; ?>
+                                </td>
+                            </tr>
+                        <?php endforeach; ?>
+                        </tbody>
+                    </table>
+                <?php endif; ?>
+            </div>
+
+            <!-- Request -->
+            <div class="content" id="request">
+                <?php $request = service('request'); ?>
+
+                <table>
+                    <tbody>
+                        <tr>
+                            <td style="width: 10em">Path</td>
+                            <td><?= esc($request->getUri()) ?></td>
+                        </tr>
+                        <tr>
+                            <td>HTTP Method</td>
+                            <td><?= esc($request->getMethod()) ?></td>
+                        </tr>
+                        <tr>
+                            <td>IP Address</td>
+                            <td><?= esc($request->getIPAddress()) ?></td>
+                        </tr>
+                        <tr>
+                            <td style="width: 10em">Is AJAX Request?</td>
+                            <td><?= $request->isAJAX() ? 'yes' : 'no' ?></td>
+                        </tr>
+                        <tr>
+                            <td>Is CLI Request?</td>
+                            <td><?= $request->isCLI() ? 'yes' : 'no' ?></td>
+                        </tr>
+                        <tr>
+                            <td>Is Secure Request?</td>
+                            <td><?= $request->isSecure() ? 'yes' : 'no' ?></td>
+                        </tr>
+                        <tr>
+                            <td>User Agent</td>
+                            <td><?= esc($request->getUserAgent()->getAgentString()) ?></td>
+                        </tr>
+
+                    </tbody>
+                </table>
+
+
+                <?php $empty = true; ?>
+                <?php foreach (['_GET', '_POST', '_COOKIE'] as $var) : ?>
+                    <?php
+                    if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
+                        continue;
+                    } ?>
+
+                    <?php $empty = false; ?>
+
+                    <h3>$<?= esc($var) ?></h3>
+
+                    <table style="width: 100%">
+                        <thead>
+                            <tr>
+                                <th>Key</th>
+                                <th>Value</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <?php foreach ($GLOBALS[$var] as $key => $value) : ?>
+                            <tr>
+                                <td><?= esc($key) ?></td>
+                                <td>
+                                    <?php if (is_string($value)) : ?>
+                                        <?= esc($value) ?>
+                                    <?php else: ?>
+                                        <pre><?= esc(print_r($value, true)) ?></pre>
+                                    <?php endif; ?>
+                                </td>
+                            </tr>
+                        <?php endforeach; ?>
+                        </tbody>
+                    </table>
+
+                <?php endforeach ?>
+
+                <?php if ($empty) : ?>
+
+                    <div class="alert">
+                        No $_GET, $_POST, or $_COOKIE Information to show.
+                    </div>
+
+                <?php endif; ?>
+
+                <?php $headers = $request->headers(); ?>
+                <?php if (! empty($headers)) : ?>
+
+                    <h3>Headers</h3>
+
+                    <table>
+                        <thead>
+                            <tr>
+                                <th>Header</th>
+                                <th>Value</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <?php foreach ($headers as $name => $value) : ?>
+                            <tr>
+                                <td><?= esc($name, 'html') ?></td>
+                                <td>
+                                <?php
+                                if ($value instanceof Header) {
+                                    echo esc($value->getValueLine(), 'html');
+                                } else {
+                                    foreach ($value as $i => $header) {
+                                        echo ' ('. $i+1 . ') ' . esc($header->getValueLine(), 'html');
+                                    }
+                                }
+                                ?>
+                                </td>
+                            </tr>
+                        <?php endforeach; ?>
+                        </tbody>
+                    </table>
+
+                <?php endif; ?>
+            </div>
+
+            <!-- Response -->
+            <?php
+                $response = service('response');
+                $response->setStatusCode(http_response_code());
+            ?>
+            <div class="content" id="response">
+                <table>
+                    <tr>
+                        <td style="width: 15em">Response Status</td>
+                        <td><?= esc($response->getStatusCode() . ' - ' . $response->getReasonPhrase()) ?></td>
+                    </tr>
+                </table>
+
+                <?php $headers = $response->headers(); ?>
+                <?php if (! empty($headers)) : ?>
+                    <h3>Headers</h3>
+
+                    <table>
+                        <thead>
+                            <tr>
+                                <th>Header</th>
+                                <th>Value</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <?php foreach ($headers as $name => $value) : ?>
+                            <tr>
+                                <td><?= esc($name, 'html') ?></td>
+                                <td>
+                                <?php
+                                if ($value instanceof Header) {
+                                    echo esc($response->getHeaderLine($name), 'html');
+                                } else {
+                                    foreach ($value as $i => $header) {
+                                        echo ' ('. $i+1 . ') ' . esc($header->getValueLine(), 'html');
+                                    }
+                                }
+                                ?>
+                                </td>
+                            </tr>
+                        <?php endforeach; ?>
+                        </tbody>
+                    </table>
+
+                <?php endif; ?>
+            </div>
+
+            <!-- Files -->
+            <div class="content" id="files">
+                <?php $files = get_included_files(); ?>
+
+                <ol>
+                <?php foreach ($files as $file) :?>
+                    <li><?= esc(clean_path($file)) ?></li>
+                <?php endforeach ?>
+                </ol>
+            </div>
+
+            <!-- Memory -->
+            <div class="content" id="memory">
+
+                <table>
+                    <tbody>
+                        <tr>
+                            <td>Memory Usage</td>
+                            <td><?= esc(static::describeMemory(memory_get_usage(true))) ?></td>
+                        </tr>
+                        <tr>
+                            <td style="width: 12em">Peak Memory Usage:</td>
+                            <td><?= esc(static::describeMemory(memory_get_peak_usage(true))) ?></td>
+                        </tr>
+                        <tr>
+                            <td>Memory Limit:</td>
+                            <td><?= esc(ini_get('memory_limit')) ?></td>
+                        </tr>
+                    </tbody>
+                </table>
+
+            </div>
+
+        </div>  <!-- /tab-content -->
+
+    </div> <!-- /container -->
+    <?php endif; ?>
+
+</body>
+</html>

+ 25 - 0
dgonz/app/Views/errors/html/production.php

@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <meta name="robots" content="noindex">
+
+    <title><?= lang('Errors.whoops') ?></title>
+
+    <style>
+        <?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
+    </style>
+</head>
+<body>
+
+    <div class="container text-center">
+
+        <h1 class="headline"><?= lang('Errors.whoops') ?></h1>
+
+        <p class="lead"><?= lang('Errors.weHitASnag') ?></p>
+
+    </div>
+
+</body>
+
+</html>

File diff suppressed because it is too large
+ 209 - 0
dgonz/app/Views/welcome_message.php


+ 11 - 0
dgonz/app/index.html

@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 128 - 0
dgonz/builds

@@ -0,0 +1,128 @@
+#!/usr/bin/env php
+<?php
+
+define('LATEST_RELEASE', '^4.7');
+define('DEVELOP_BRANCH', 'dev-develop');
+define('NEXT_MINOR', '^4.8-dev');
+define('GITHUB_URL', 'https://github.com/codeigniter4/codeigniter4');
+
+/*
+ * --------------------------------------------------------------------
+ * Stability Toggle
+ * --------------------------------------------------------------------
+ * Use this script to toggle the CodeIgniter dependency between the
+ * latest stable release and the most recent development update.
+ *
+ * Usage: php builds [release|development|next]
+ */
+
+$branch = $argv[1] ?? '';
+
+// Determine the requested stability
+if ($branch === '' || ! in_array($branch, ['release', 'development', 'next'], true)) {
+    echo 'Usage: php builds [release|development|next]' . PHP_EOL;
+
+    exit;
+}
+
+$modified = [];
+
+// Locate each file and update it for the requested stability
+
+$file = __DIR__ . DIRECTORY_SEPARATOR . 'composer.json';
+
+if (is_file($file)) {
+    $contents = file_get_contents($file);
+
+    if ((string) $contents !== '') {
+        $array = json_decode($contents, true);
+
+        if (is_array($array)) {
+            if ($branch !== 'release') {
+                $array['minimum-stability'] = 'dev';
+                $array['prefer-stable']     = true;
+                $array['repositories'] ??= [];
+
+                $found = false;
+
+                foreach ($array['repositories'] as $repository) {
+                    if ($repository['url'] === GITHUB_URL) {
+                        $found = true;
+                        break;
+                    }
+                }
+
+                if (! $found) {
+                    $array['repositories'][] = [
+                        'type' => 'vcs',
+                        'url'  => GITHUB_URL,
+                    ];
+                }
+
+                $array['require']['codeigniter4/codeigniter4'] = $branch === 'next' ? NEXT_MINOR : DEVELOP_BRANCH;
+                unset($array['require']['codeigniter4/framework']);
+            } else {
+                unset($array['minimum-stability']);
+
+                if (isset($array['repositories'])) {
+                    foreach ($array['repositories'] as $i => $repository) {
+                        if ($repository['url'] === GITHUB_URL) {
+                            unset($array['repositories'][$i]);
+                            break;
+                        }
+                    }
+
+                    if ($array['repositories'] === []) {
+                        unset($array['repositories']);
+                    }
+                }
+
+                $array['require']['codeigniter4/framework'] = LATEST_RELEASE;
+                unset($array['require']['codeigniter4/codeigniter4']);
+            }
+
+            file_put_contents($file, json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL);
+
+            $modified[] = $file;
+        } else {
+            echo 'Warning: Unable to decode composer.json! Skipping...' . PHP_EOL;
+        }
+    } else {
+        echo 'Warning: Unable to read composer.json! Skipping...' . PHP_EOL;
+    }
+}
+
+$files = [
+    __DIR__ . DIRECTORY_SEPARATOR . 'app/Config/Paths.php',
+    __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.dist.xml',
+    __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml',
+];
+
+foreach ($files as $file) {
+    if (is_file($file)) {
+        $contents = file_get_contents($file);
+
+        if ($branch !== 'release') {
+            $contents = str_replace('vendor/codeigniter4/framework', 'vendor/codeigniter4/codeigniter4', $contents);
+        } else {
+            $contents = str_replace('vendor/codeigniter4/codeigniter4', 'vendor/codeigniter4/framework', $contents);
+        }
+
+        file_put_contents($file, $contents);
+
+        $modified[] = $file;
+    }
+}
+
+if ($modified === []) {
+    echo 'No files modified.' . PHP_EOL;
+} else {
+    echo 'The following files were modified:' . PHP_EOL;
+
+    foreach ($modified as $file) {
+        echo " * {$file}" . PHP_EOL;
+    }
+}
+
+echo 'Run `composer update` to sync changes with your vendor folder.' . PHP_EOL;
+echo 'Don\'t forget to update the project files in app folder from "vendor/codeigniter4/*/app/".' . PHP_EOL;

+ 43 - 0
dgonz/composer.json

@@ -0,0 +1,43 @@
+{
+    "name": "codeigniter4/appstarter",
+    "description": "CodeIgniter4 starter app",
+    "license": "MIT",
+    "type": "project",
+    "homepage": "https://codeigniter.com",
+    "support": {
+        "forum": "https://forum.codeigniter.com/",
+        "source": "https://github.com/codeigniter4/CodeIgniter4",
+        "slack": "https://codeigniterchat.slack.com"
+    },
+    "require": {
+        "php": "^8.2",
+        "codeigniter4/framework": "^4.7"
+    },
+    "require-dev": {
+        "fakerphp/faker": "^1.9",
+        "mikey179/vfsstream": "^1.6",
+        "phpunit/phpunit": "^10.5.16"
+    },
+    "autoload": {
+        "psr-4": {
+            "App\\": "app/",
+            "Config\\": "app/Config/"
+        },
+        "exclude-from-classmap": [
+            "**/Database/Migrations/**"
+        ]
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Tests\\Support\\": "tests/_support"
+        }
+    },
+    "config": {
+        "optimize-autoloader": true,
+        "preferred-install": "dist",
+        "sort-packages": true
+    },
+    "scripts": {
+        "test": "phpunit"
+    }
+}

+ 2118 - 0
dgonz/composer.lock

@@ -0,0 +1,2118 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+        "This file is @generated automatically"
+    ],
+    "content-hash": "f5cce40800fa5dae1504b9364f585e6a",
+    "packages": [
+        {
+            "name": "codeigniter4/framework",
+            "version": "v4.7.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/codeigniter4/framework.git",
+                "reference": "ab9bf33caa3ccc25b1a4652234d7d0eb1d1937de"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/codeigniter4/framework/zipball/ab9bf33caa3ccc25b1a4652234d7d0eb1d1937de",
+                "reference": "ab9bf33caa3ccc25b1a4652234d7d0eb1d1937de",
+                "shasum": ""
+            },
+            "require": {
+                "ext-intl": "*",
+                "ext-mbstring": "*",
+                "laminas/laminas-escaper": "^2.18",
+                "php": "^8.2",
+                "psr/log": "^3.0"
+            },
+            "require-dev": {
+                "codeigniter/coding-standard": "^1.7",
+                "fakerphp/faker": "^1.24",
+                "friendsofphp/php-cs-fixer": "^3.47.1",
+                "kint-php/kint": "^6.1",
+                "mikey179/vfsstream": "^1.6.12",
+                "nexusphp/cs-config": "^3.6",
+                "phpunit/phpunit": "^10.5.16 || ^11.2",
+                "predis/predis": "^3.0"
+            },
+            "suggest": {
+                "ext-apcu": "If you use Cache class ApcuHandler",
+                "ext-curl": "If you use CURLRequest class",
+                "ext-dom": "If you use TestResponse",
+                "ext-exif": "If you run Image class tests",
+                "ext-fileinfo": "Improves mime type detection for files",
+                "ext-gd": "If you use Image class GDHandler",
+                "ext-imagick": "If you use Image class ImageMagickHandler",
+                "ext-libxml": "If you use TestResponse",
+                "ext-memcache": "If you use Cache class MemcachedHandler with Memcache",
+                "ext-memcached": "If you use Cache class MemcachedHandler with Memcached",
+                "ext-mysqli": "If you use MySQL",
+                "ext-oci8": "If you use Oracle Database",
+                "ext-pcntl": "If you use Signals",
+                "ext-pgsql": "If you use PostgreSQL",
+                "ext-posix": "If you use Signals",
+                "ext-readline": "Improves CLI::input() usability",
+                "ext-redis": "If you use Cache class RedisHandler",
+                "ext-simplexml": "If you format XML",
+                "ext-sodium": "If you use Encryption SodiumHandler",
+                "ext-sqlite3": "If you use SQLite3",
+                "ext-sqlsrv": "If you use SQL Server",
+                "ext-xdebug": "If you use CIUnitTestCase::assertHeaderEmitted()"
+            },
+            "type": "project",
+            "autoload": {
+                "psr-4": {
+                    "CodeIgniter\\": "system/"
+                },
+                "exclude-from-classmap": [
+                    "**/Database/Migrations/**"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "The CodeIgniter framework v4",
+            "homepage": "https://codeigniter.com",
+            "support": {
+                "forum": "https://forum.codeigniter.com/",
+                "slack": "https://codeigniterchat.slack.com",
+                "source": "https://github.com/codeigniter4/CodeIgniter4"
+            },
+            "time": "2026-05-22T11:21:33+00:00"
+        },
+        {
+            "name": "laminas/laminas-escaper",
+            "version": "2.18.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/laminas/laminas-escaper.git",
+                "reference": "06f211dfffff18d91844c1f55250d5d13c007e18"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/06f211dfffff18d91844c1f55250d5d13c007e18",
+                "reference": "06f211dfffff18d91844c1f55250d5d13c007e18",
+                "shasum": ""
+            },
+            "require": {
+                "ext-ctype": "*",
+                "ext-mbstring": "*",
+                "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
+            },
+            "conflict": {
+                "zendframework/zend-escaper": "*"
+            },
+            "require-dev": {
+                "infection/infection": "^0.31.0",
+                "laminas/laminas-coding-standard": "~3.1.0",
+                "phpunit/phpunit": "^11.5.42",
+                "psalm/plugin-phpunit": "^0.19.5",
+                "vimeo/psalm": "^6.13.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Laminas\\Escaper\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs",
+            "homepage": "https://laminas.dev",
+            "keywords": [
+                "escaper",
+                "laminas"
+            ],
+            "support": {
+                "chat": "https://laminas.dev/chat",
+                "docs": "https://docs.laminas.dev/laminas-escaper/",
+                "forum": "https://discourse.laminas.dev",
+                "issues": "https://github.com/laminas/laminas-escaper/issues",
+                "rss": "https://github.com/laminas/laminas-escaper/releases.atom",
+                "source": "https://github.com/laminas/laminas-escaper"
+            },
+            "funding": [
+                {
+                    "url": "https://funding.communitybridge.org/projects/laminas-project",
+                    "type": "community_bridge"
+                }
+            ],
+            "time": "2025-10-14T18:31:13+00:00"
+        },
+        {
+            "name": "psr/log",
+            "version": "3.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.0.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Log\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "https://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "homepage": "https://github.com/php-fig/log",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/log/tree/3.0.2"
+            },
+            "time": "2024-09-11T13:17:53+00:00"
+        }
+    ],
+    "packages-dev": [
+        {
+            "name": "fakerphp/faker",
+            "version": "v1.24.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/FakerPHP/Faker.git",
+                "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5",
+                "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.4 || ^8.0",
+                "psr/container": "^1.0 || ^2.0",
+                "symfony/deprecation-contracts": "^2.2 || ^3.0"
+            },
+            "conflict": {
+                "fzaninotto/faker": "*"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.4.1",
+                "doctrine/persistence": "^1.3 || ^2.0",
+                "ext-intl": "*",
+                "phpunit/phpunit": "^9.5.26",
+                "symfony/phpunit-bridge": "^5.4.16"
+            },
+            "suggest": {
+                "doctrine/orm": "Required to use Faker\\ORM\\Doctrine",
+                "ext-curl": "Required by Faker\\Provider\\Image to download images.",
+                "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.",
+                "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.",
+                "ext-mbstring": "Required for multibyte Unicode string functionality."
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Faker\\": "src/Faker/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "François Zaninotto"
+                }
+            ],
+            "description": "Faker is a PHP library that generates fake data for you.",
+            "keywords": [
+                "data",
+                "faker",
+                "fixtures"
+            ],
+            "support": {
+                "issues": "https://github.com/FakerPHP/Faker/issues",
+                "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1"
+            },
+            "time": "2024-11-21T13:46:39+00:00"
+        },
+        {
+            "name": "mikey179/vfsstream",
+            "version": "v1.6.12",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/bovigo/vfsStream.git",
+                "reference": "fe695ec993e0a55c3abdda10a9364eb31c6f1bf0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/fe695ec993e0a55c3abdda10a9364eb31c6f1bf0",
+                "reference": "fe695ec993e0a55c3abdda10a9364eb31c6f1bf0",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^7.5||^8.5||^9.6",
+                "yoast/phpunit-polyfills": "^2.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.6.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "org\\bovigo\\vfs\\": "src/main/php"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Frank Kleine",
+                    "homepage": "http://frankkleine.de/",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Virtual file system to mock the real file system in unit tests.",
+            "homepage": "http://vfs.bovigo.org/",
+            "support": {
+                "issues": "https://github.com/bovigo/vfsStream/issues",
+                "source": "https://github.com/bovigo/vfsStream/tree/master",
+                "wiki": "https://github.com/bovigo/vfsStream/wiki"
+            },
+            "time": "2024-08-29T18:43:31+00:00"
+        },
+        {
+            "name": "myclabs/deep-copy",
+            "version": "1.13.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/myclabs/DeepCopy.git",
+                "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+                "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1 || ^8.0"
+            },
+            "conflict": {
+                "doctrine/collections": "<1.6.8",
+                "doctrine/common": "<2.13.3 || >=3 <3.2.2"
+            },
+            "require-dev": {
+                "doctrine/collections": "^1.6.8",
+                "doctrine/common": "^2.13.3 || ^3.2.2",
+                "phpspec/prophecy": "^1.10",
+                "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/DeepCopy/deep_copy.php"
+                ],
+                "psr-4": {
+                    "DeepCopy\\": "src/DeepCopy/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Create deep copies (clones) of your objects",
+            "keywords": [
+                "clone",
+                "copy",
+                "duplicate",
+                "object",
+                "object graph"
+            ],
+            "support": {
+                "issues": "https://github.com/myclabs/DeepCopy/issues",
+                "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
+            },
+            "funding": [
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2025-08-01T08:46:24+00:00"
+        },
+        {
+            "name": "nikic/php-parser",
+            "version": "v5.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/nikic/PHP-Parser.git",
+                "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
+                "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
+                "shasum": ""
+            },
+            "require": {
+                "ext-ctype": "*",
+                "ext-json": "*",
+                "ext-tokenizer": "*",
+                "php": ">=7.4"
+            },
+            "require-dev": {
+                "ircmaxell/php-yacc": "^0.0.7",
+                "phpunit/phpunit": "^9.0"
+            },
+            "bin": [
+                "bin/php-parse"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PhpParser\\": "lib/PhpParser"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Nikita Popov"
+                }
+            ],
+            "description": "A PHP parser written in PHP",
+            "keywords": [
+                "parser",
+                "php"
+            ],
+            "support": {
+                "issues": "https://github.com/nikic/PHP-Parser/issues",
+                "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
+            },
+            "time": "2025-12-06T11:56:16+00:00"
+        },
+        {
+            "name": "phar-io/manifest",
+            "version": "2.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phar-io/manifest.git",
+                "reference": "54750ef60c58e43759730615a392c31c80e23176"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
+                "reference": "54750ef60c58e43759730615a392c31c80e23176",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-libxml": "*",
+                "ext-phar": "*",
+                "ext-xmlwriter": "*",
+                "phar-io/version": "^3.0.1",
+                "php": "^7.2 || ^8.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Heuer",
+                    "email": "sebastian@phpeople.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+            "support": {
+                "issues": "https://github.com/phar-io/manifest/issues",
+                "source": "https://github.com/phar-io/manifest/tree/2.0.4"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/theseer",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-03-03T12:33:53+00:00"
+        },
+        {
+            "name": "phar-io/version",
+            "version": "3.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phar-io/version.git",
+                "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+                "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2 || ^8.0"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Heuer",
+                    "email": "sebastian@phpeople.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Library for handling version information and constraints",
+            "support": {
+                "issues": "https://github.com/phar-io/version/issues",
+                "source": "https://github.com/phar-io/version/tree/3.2.1"
+            },
+            "time": "2022-02-21T01:04:05+00:00"
+        },
+        {
+            "name": "phpunit/php-code-coverage",
+            "version": "10.1.16",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+                "reference": "7e308268858ed6baedc8704a304727d20bc07c77"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77",
+                "reference": "7e308268858ed6baedc8704a304727d20bc07c77",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-libxml": "*",
+                "ext-xmlwriter": "*",
+                "nikic/php-parser": "^4.19.1 || ^5.1.0",
+                "php": ">=8.1",
+                "phpunit/php-file-iterator": "^4.1.0",
+                "phpunit/php-text-template": "^3.0.1",
+                "sebastian/code-unit-reverse-lookup": "^3.0.0",
+                "sebastian/complexity": "^3.2.0",
+                "sebastian/environment": "^6.1.0",
+                "sebastian/lines-of-code": "^2.0.2",
+                "sebastian/version": "^4.0.1",
+                "theseer/tokenizer": "^1.2.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.1"
+            },
+            "suggest": {
+                "ext-pcov": "PHP extension that provides line coverage",
+                "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "10.1.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+            "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+            "keywords": [
+                "coverage",
+                "testing",
+                "xunit"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+                "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
+                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-08-22T04:31:57+00:00"
+        },
+        {
+            "name": "phpunit/php-file-iterator",
+            "version": "4.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+                "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c",
+                "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+            "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+            "keywords": [
+                "filesystem",
+                "iterator"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+                "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
+                "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-08-31T06:24:48+00:00"
+        },
+        {
+            "name": "phpunit/php-invoker",
+            "version": "4.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-invoker.git",
+                "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
+                "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "ext-pcntl": "*",
+                "phpunit/phpunit": "^10.0"
+            },
+            "suggest": {
+                "ext-pcntl": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Invoke callables with a timeout",
+            "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+            "keywords": [
+                "process"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+                "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-02-03T06:56:09+00:00"
+        },
+        {
+            "name": "phpunit/php-text-template",
+            "version": "3.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-text-template.git",
+                "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748",
+                "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Simple template engine.",
+            "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+            "keywords": [
+                "template"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+                "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
+                "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-08-31T14:07:24+00:00"
+        },
+        {
+            "name": "phpunit/php-timer",
+            "version": "6.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-timer.git",
+                "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d",
+                "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "6.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Utility class for timing",
+            "homepage": "https://github.com/sebastianbergmann/php-timer/",
+            "keywords": [
+                "timer"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+                "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-02-03T06:57:52+00:00"
+        },
+        {
+            "name": "phpunit/phpunit",
+            "version": "10.5.63",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/phpunit.git",
+                "reference": "33198268dad71e926626b618f3ec3966661e4d90"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/33198268dad71e926626b618f3ec3966661e4d90",
+                "reference": "33198268dad71e926626b618f3ec3966661e4d90",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-json": "*",
+                "ext-libxml": "*",
+                "ext-mbstring": "*",
+                "ext-xml": "*",
+                "ext-xmlwriter": "*",
+                "myclabs/deep-copy": "^1.13.4",
+                "phar-io/manifest": "^2.0.4",
+                "phar-io/version": "^3.2.1",
+                "php": ">=8.1",
+                "phpunit/php-code-coverage": "^10.1.16",
+                "phpunit/php-file-iterator": "^4.1.0",
+                "phpunit/php-invoker": "^4.0.0",
+                "phpunit/php-text-template": "^3.0.1",
+                "phpunit/php-timer": "^6.0.0",
+                "sebastian/cli-parser": "^2.0.1",
+                "sebastian/code-unit": "^2.0.0",
+                "sebastian/comparator": "^5.0.5",
+                "sebastian/diff": "^5.1.1",
+                "sebastian/environment": "^6.1.0",
+                "sebastian/exporter": "^5.1.4",
+                "sebastian/global-state": "^6.0.2",
+                "sebastian/object-enumerator": "^5.0.0",
+                "sebastian/recursion-context": "^5.0.1",
+                "sebastian/type": "^4.0.0",
+                "sebastian/version": "^4.0.1"
+            },
+            "suggest": {
+                "ext-soap": "To be able to generate mocks based on WSDL files"
+            },
+            "bin": [
+                "phpunit"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "10.5-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "src/Framework/Assert/Functions.php"
+                ],
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "The PHP Unit Testing framework.",
+            "homepage": "https://phpunit.de/",
+            "keywords": [
+                "phpunit",
+                "testing",
+                "xunit"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+                "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.63"
+            },
+            "funding": [
+                {
+                    "url": "https://phpunit.de/sponsors.html",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                },
+                {
+                    "url": "https://liberapay.com/sebastianbergmann",
+                    "type": "liberapay"
+                },
+                {
+                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
+                    "type": "thanks_dev"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2026-01-27T05:48:37+00:00"
+        },
+        {
+            "name": "psr/container",
+            "version": "2.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/container.git",
+                "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+                "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Container\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "https://www.php-fig.org/"
+                }
+            ],
+            "description": "Common Container Interface (PHP FIG PSR-11)",
+            "homepage": "https://github.com/php-fig/container",
+            "keywords": [
+                "PSR-11",
+                "container",
+                "container-interface",
+                "container-interop",
+                "psr"
+            ],
+            "support": {
+                "issues": "https://github.com/php-fig/container/issues",
+                "source": "https://github.com/php-fig/container/tree/2.0.2"
+            },
+            "time": "2021-11-05T16:47:00+00:00"
+        },
+        {
+            "name": "sebastian/cli-parser",
+            "version": "2.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/cli-parser.git",
+                "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084",
+                "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library for parsing CLI options",
+            "homepage": "https://github.com/sebastianbergmann/cli-parser",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
+                "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
+                "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-03-02T07:12:49+00:00"
+        },
+        {
+            "name": "sebastian/code-unit",
+            "version": "2.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/code-unit.git",
+                "reference": "a81fee9eef0b7a76af11d121767abc44c104e503"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503",
+                "reference": "a81fee9eef0b7a76af11d121767abc44c104e503",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Collection of value objects that represent the PHP code units",
+            "homepage": "https://github.com/sebastianbergmann/code-unit",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/code-unit/issues",
+                "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-02-03T06:58:43+00:00"
+        },
+        {
+            "name": "sebastian/code-unit-reverse-lookup",
+            "version": "3.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+                "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
+                "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Looks up which function or method a line of code belongs to",
+            "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
+                "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-02-03T06:59:15+00:00"
+        },
+        {
+            "name": "sebastian/comparator",
+            "version": "5.0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/comparator.git",
+                "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55dfef806eb7dfeb6e7a6935601fef866f8ca48d",
+                "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-mbstring": "*",
+                "php": ">=8.1",
+                "sebastian/diff": "^5.0",
+                "sebastian/exporter": "^5.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "5.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Volker Dusch",
+                    "email": "github@wallbash.com"
+                },
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@2bepublished.at"
+                }
+            ],
+            "description": "Provides the functionality to compare PHP values for equality",
+            "homepage": "https://github.com/sebastianbergmann/comparator",
+            "keywords": [
+                "comparator",
+                "compare",
+                "equality"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/comparator/issues",
+                "security": "https://github.com/sebastianbergmann/comparator/security/policy",
+                "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.5"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                },
+                {
+                    "url": "https://liberapay.com/sebastianbergmann",
+                    "type": "liberapay"
+                },
+                {
+                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
+                    "type": "thanks_dev"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2026-01-24T09:25:16+00:00"
+        },
+        {
+            "name": "sebastian/complexity",
+            "version": "3.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/complexity.git",
+                "reference": "68ff824baeae169ec9f2137158ee529584553799"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799",
+                "reference": "68ff824baeae169ec9f2137158ee529584553799",
+                "shasum": ""
+            },
+            "require": {
+                "nikic/php-parser": "^4.18 || ^5.0",
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "3.2-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library for calculating the complexity of PHP code units",
+            "homepage": "https://github.com/sebastianbergmann/complexity",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/complexity/issues",
+                "security": "https://github.com/sebastianbergmann/complexity/security/policy",
+                "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-12-21T08:37:17+00:00"
+        },
+        {
+            "name": "sebastian/diff",
+            "version": "5.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/diff.git",
+                "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e",
+                "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0",
+                "symfony/process": "^6.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "5.1-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Kore Nordmann",
+                    "email": "mail@kore-nordmann.de"
+                }
+            ],
+            "description": "Diff implementation",
+            "homepage": "https://github.com/sebastianbergmann/diff",
+            "keywords": [
+                "diff",
+                "udiff",
+                "unidiff",
+                "unified diff"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/diff/issues",
+                "security": "https://github.com/sebastianbergmann/diff/security/policy",
+                "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-03-02T07:15:17+00:00"
+        },
+        {
+            "name": "sebastian/environment",
+            "version": "6.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/environment.git",
+                "reference": "8074dbcd93529b357029f5cc5058fd3e43666984"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984",
+                "reference": "8074dbcd93529b357029f5cc5058fd3e43666984",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "suggest": {
+                "ext-posix": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "6.1-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Provides functionality to handle HHVM/PHP environments",
+            "homepage": "https://github.com/sebastianbergmann/environment",
+            "keywords": [
+                "Xdebug",
+                "environment",
+                "hhvm"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/environment/issues",
+                "security": "https://github.com/sebastianbergmann/environment/security/policy",
+                "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-03-23T08:47:14+00:00"
+        },
+        {
+            "name": "sebastian/exporter",
+            "version": "5.1.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/exporter.git",
+                "reference": "0735b90f4da94969541dac1da743446e276defa6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0735b90f4da94969541dac1da743446e276defa6",
+                "reference": "0735b90f4da94969541dac1da743446e276defa6",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "php": ">=8.1",
+                "sebastian/recursion-context": "^5.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "5.1-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Volker Dusch",
+                    "email": "github@wallbash.com"
+                },
+                {
+                    "name": "Adam Harvey",
+                    "email": "aharvey@php.net"
+                },
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@gmail.com"
+                }
+            ],
+            "description": "Provides the functionality to export PHP variables for visualization",
+            "homepage": "https://www.github.com/sebastianbergmann/exporter",
+            "keywords": [
+                "export",
+                "exporter"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/exporter/issues",
+                "security": "https://github.com/sebastianbergmann/exporter/security/policy",
+                "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.4"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                },
+                {
+                    "url": "https://liberapay.com/sebastianbergmann",
+                    "type": "liberapay"
+                },
+                {
+                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
+                    "type": "thanks_dev"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2025-09-24T06:09:11+00:00"
+        },
+        {
+            "name": "sebastian/global-state",
+            "version": "6.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/global-state.git",
+                "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
+                "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1",
+                "sebastian/object-reflector": "^3.0",
+                "sebastian/recursion-context": "^5.0"
+            },
+            "require-dev": {
+                "ext-dom": "*",
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "6.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Snapshotting of global state",
+            "homepage": "https://www.github.com/sebastianbergmann/global-state",
+            "keywords": [
+                "global state"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/global-state/issues",
+                "security": "https://github.com/sebastianbergmann/global-state/security/policy",
+                "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-03-02T07:19:19+00:00"
+        },
+        {
+            "name": "sebastian/lines-of-code",
+            "version": "2.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+                "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0",
+                "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0",
+                "shasum": ""
+            },
+            "require": {
+                "nikic/php-parser": "^4.18 || ^5.0",
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library for counting the lines of code in PHP source code",
+            "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+                "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
+                "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-12-21T08:38:20+00:00"
+        },
+        {
+            "name": "sebastian/object-enumerator",
+            "version": "5.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+                "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906",
+                "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1",
+                "sebastian/object-reflector": "^3.0",
+                "sebastian/recursion-context": "^5.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "5.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+            "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+                "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-02-03T07:08:32+00:00"
+        },
+        {
+            "name": "sebastian/object-reflector",
+            "version": "3.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/object-reflector.git",
+                "reference": "24ed13d98130f0e7122df55d06c5c4942a577957"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957",
+                "reference": "24ed13d98130f0e7122df55d06c5c4942a577957",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Allows reflection of object attributes, including inherited and non-public ones",
+            "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+                "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-02-03T07:06:18+00:00"
+        },
+        {
+            "name": "sebastian/recursion-context",
+            "version": "5.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/recursion-context.git",
+                "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/47e34210757a2f37a97dcd207d032e1b01e64c7a",
+                "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "5.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Adam Harvey",
+                    "email": "aharvey@php.net"
+                }
+            ],
+            "description": "Provides functionality to recursively process PHP variables",
+            "homepage": "https://github.com/sebastianbergmann/recursion-context",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+                "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
+                "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                },
+                {
+                    "url": "https://liberapay.com/sebastianbergmann",
+                    "type": "liberapay"
+                },
+                {
+                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
+                    "type": "thanks_dev"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2025-08-10T07:50:56+00:00"
+        },
+        {
+            "name": "sebastian/type",
+            "version": "4.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/type.git",
+                "reference": "462699a16464c3944eefc02ebdd77882bd3925bf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf",
+                "reference": "462699a16464c3944eefc02ebdd77882bd3925bf",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^10.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Collection of value objects that represent the types of the PHP type system",
+            "homepage": "https://github.com/sebastianbergmann/type",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/type/issues",
+                "source": "https://github.com/sebastianbergmann/type/tree/4.0.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-02-03T07:10:45+00:00"
+        },
+        {
+            "name": "sebastian/version",
+            "version": "4.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/version.git",
+                "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17",
+                "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+            "homepage": "https://github.com/sebastianbergmann/version",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/version/issues",
+                "source": "https://github.com/sebastianbergmann/version/tree/4.0.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-02-07T11:34:05+00:00"
+        },
+        {
+            "name": "symfony/deprecation-contracts",
+            "version": "v3.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/deprecation-contracts.git",
+                "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b",
+                "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=8.1"
+            },
+            "type": "library",
+            "extra": {
+                "thanks": {
+                    "url": "https://github.com/symfony/contracts",
+                    "name": "symfony/contracts"
+                },
+                "branch-alias": {
+                    "dev-main": "3.7-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "function.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "A generic function and convention to trigger deprecation notices",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/nicolas-grekas",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2026-04-13T15:52:40+00:00"
+        },
+        {
+            "name": "theseer/tokenizer",
+            "version": "1.3.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/theseer/tokenizer.git",
+                "reference": "b7489ce515e168639d17feec34b8847c326b0b3c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c",
+                "reference": "b7489ce515e168639d17feec34b8847c326b0b3c",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-tokenizer": "*",
+                "ext-xmlwriter": "*",
+                "php": "^7.2 || ^8.0"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+            "support": {
+                "issues": "https://github.com/theseer/tokenizer/issues",
+                "source": "https://github.com/theseer/tokenizer/tree/1.3.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/theseer",
+                    "type": "github"
+                }
+            ],
+            "time": "2025-11-17T20:03:58+00:00"
+        }
+    ],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": {},
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": {
+        "php": "^8.2"
+    },
+    "platform-dev": {},
+    "plugin-api-version": "2.9.0"
+}

+ 69 - 0
dgonz/env

@@ -0,0 +1,69 @@
+#--------------------------------------------------------------------
+# Example Environment Configuration file
+#
+# This file can be used as a starting point for your own
+# custom .env files, and contains most of the possible settings
+# available in a default install.
+#
+# By default, all of the settings are commented out. If you want
+# to override the setting, you must un-comment it by removing the '#'
+# at the beginning of the line.
+#--------------------------------------------------------------------
+
+#--------------------------------------------------------------------
+# ENVIRONMENT
+#--------------------------------------------------------------------
+
+# CI_ENVIRONMENT = production
+
+#--------------------------------------------------------------------
+# APP
+#--------------------------------------------------------------------
+
+# app.baseURL = ''
+# If you have trouble with `.`, you could also use `_`.
+# app_baseURL = ''
+# app.forceGlobalSecureRequests = false
+# app.CSPEnabled = false
+
+#--------------------------------------------------------------------
+# DATABASE
+#--------------------------------------------------------------------
+
+# database.default.hostname = localhost
+# database.default.database = ci4
+# database.default.username = root
+# database.default.password = root
+# database.default.DBDriver = MySQLi
+# database.default.DBPrefix =
+# database.default.port = 3306
+
+# If you use MySQLi as tests, first update the values of Config\Database::$tests.
+# database.tests.hostname = localhost
+# database.tests.database = ci4_test
+# database.tests.username = root
+# database.tests.password = root
+# database.tests.DBDriver = MySQLi
+# database.tests.DBPrefix =
+# database.tests.charset = utf8mb4
+# database.tests.DBCollat = utf8mb4_general_ci
+# database.tests.port = 3306
+
+#--------------------------------------------------------------------
+# ENCRYPTION
+#--------------------------------------------------------------------
+
+# encryption.key =
+
+#--------------------------------------------------------------------
+# SESSION
+#--------------------------------------------------------------------
+
+# session.driver = 'CodeIgniter\Session\Handlers\FileHandler'
+# session.savePath = null
+
+#--------------------------------------------------------------------
+# LOGGER
+#--------------------------------------------------------------------
+
+# logger.threshold = 4

+ 64 - 0
dgonz/phpunit.dist.xml

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
+    bootstrap="vendor/codeigniter4/framework/system/Test/bootstrap.php"
+    backupGlobals="false"
+    beStrictAboutOutputDuringTests="true"
+    colors="true"
+    columns="max"
+    failOnRisky="true"
+    failOnWarning="true"
+    cacheDirectory="build/.phpunit.cache"
+>
+    <coverage pathCoverage="false" ignoreDeprecatedCodeUnits="true">
+        <report>
+            <clover outputFile="build/logs/clover.xml"/>
+            <html outputDirectory="build/logs/html"/>
+            <php outputFile="build/logs/coverage.serialized"/>
+            <text outputFile="php://stdout" showUncoveredFiles="false"/>
+        </report>
+    </coverage>
+
+    <testsuites>
+        <testsuite name="App">
+            <directory>./tests</directory>
+        </testsuite>
+    </testsuites>
+
+    <logging>
+        <testdoxHtml outputFile="build/logs/testdox.html"/>
+        <testdoxText outputFile="build/logs/testdox.txt"/>
+        <junit outputFile="build/logs/logfile.xml"/>
+    </logging>
+
+    <source>
+        <include>
+            <directory suffix=".php">./app</directory>
+        </include>
+        <exclude>
+            <directory suffix=".php">./app/Views</directory>
+            <file>./app/Config/Routes.php</file>
+        </exclude>
+    </source>
+
+    <php>
+        <server name="app.baseURL" value="http://example.com/"/>
+        <server name="CODEIGNITER_SCREAM_DEPRECATIONS" value="0"/>
+        <!-- Directory containing phpunit.xml -->
+        <const name="HOMEPATH" value="./"/>
+        <!-- Directory containing the Paths config file -->
+        <const name="CONFIGPATH" value="./app/Config/"/>
+        <!-- Directory containing the front controller (index.php) -->
+        <const name="PUBLICPATH" value="./public/"/>
+        <!-- Database configuration -->
+        <!-- Uncomment to provide your own database for testing
+            <env name="database.tests.hostname" value="localhost"/>
+            <env name="database.tests.database" value="tests"/>
+            <env name="database.tests.username" value="tests_user"/>
+            <env name="database.tests.password" value=""/>
+            <env name="database.tests.DBDriver" value="MySQLi"/>
+            <env name="database.tests.DBPrefix" value="tests_"/>
+            -->
+    </php>
+</phpunit>

+ 112 - 0
dgonz/preload.php

@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * This file is part of CodeIgniter 4 framework.
+ *
+ * (c) CodeIgniter Foundation <admin@codeigniter.com>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+use CodeIgniter\Boot;
+use Config\Paths;
+
+/*
+ *---------------------------------------------------------------
+ * Sample file for Preloading
+ *---------------------------------------------------------------
+ * See https://www.php.net/manual/en/opcache.preloading.php
+ *
+ * How to Use:
+ *   0. Copy this file to your project root folder.
+ *   1. Set the $paths property of the preload class below.
+ *   2. Set opcache.preload in php.ini.
+ *     php.ini:
+ *     opcache.preload=/path/to/preload.php
+ */
+
+// Load the paths config file
+require __DIR__ . '/app/Config/Paths.php';
+
+// Path to the front controller
+define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR);
+
+class preload
+{
+    /**
+     * @var array Paths to preload.
+     */
+    private array $paths = [
+        [
+            'include' => __DIR__ . '/vendor/codeigniter4/framework/system', // Change this path if using manual installation
+            'exclude' => [
+                // Not needed if you don't use them.
+                '/system/Database/OCI8/',
+                '/system/Database/Postgre/',
+                '/system/Database/SQLite3/',
+                '/system/Database/SQLSRV/',
+                // Not needed for web apps.
+                '/system/Database/Seeder.php',
+                '/system/Test/',
+                '/system/CLI/',
+                '/system/Commands/',
+                '/system/Publisher/',
+                '/system/ComposerScripts.php',
+                // Not Class/Function files.
+                '/system/Config/Routes.php',
+                '/system/Language/',
+                '/system/bootstrap.php',
+                '/system/util_bootstrap.php',
+                '/system/rewrite.php',
+                '/Views/',
+                // Errors occur.
+                '/system/ThirdParty/',
+            ],
+        ],
+    ];
+
+    public function __construct()
+    {
+        $this->loadAutoloader();
+    }
+
+    private function loadAutoloader(): void
+    {
+        $paths = new Paths();
+        require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'Boot.php';
+
+        Boot::preload($paths);
+    }
+
+    /**
+     * Load PHP files.
+     */
+    public function load(): void
+    {
+        foreach ($this->paths as $path) {
+            $directory = new RecursiveDirectoryIterator($path['include']);
+            $fullTree  = new RecursiveIteratorIterator($directory);
+            $phpFiles  = new RegexIterator(
+                $fullTree,
+                '/.+((?<!Test)+\.php$)/i',
+                RecursiveRegexIterator::GET_MATCH,
+            );
+
+            foreach ($phpFiles as $key => $file) {
+                foreach ($path['exclude'] as $exclude) {
+                    if (str_contains($file[0], $exclude)) {
+                        continue 2;
+                    }
+                }
+
+                require_once $file[0];
+                // Uncomment only for debugging (to inspect which files are included).
+                // Never use this in production - preload scripts must not generate output.
+                // echo 'Loaded: ' . $file[0] . "\n";
+            }
+        }
+    }
+}
+
+(new preload())->load();

+ 49 - 0
dgonz/public/.htaccess

@@ -0,0 +1,49 @@
+# Disable directory browsing
+Options -Indexes
+
+# ----------------------------------------------------------------------
+# Rewrite engine
+# ----------------------------------------------------------------------
+
+# Turning on the rewrite engine is necessary for the following rules and features.
+# FollowSymLinks must be enabled for this to work.
+<IfModule mod_rewrite.c>
+	Options +FollowSymlinks
+	RewriteEngine On
+
+	# If you installed CodeIgniter in a subfolder, you will need to
+	# change the following line to match the subfolder you need.
+	# http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase
+	# RewriteBase /
+
+	# Redirect Trailing Slashes...
+	RewriteCond %{REQUEST_FILENAME} !-d
+	RewriteCond %{REQUEST_URI} (.+)/$
+	RewriteRule ^ %1 [L,R=301]
+
+	# Rewrite "www.example.com -> example.com"
+	RewriteCond %{HTTPS} !=on
+	RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
+	RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
+
+	# Checks to see if the user is attempting to access a valid file,
+	# such as an image or css document, if this isn't true it sends the
+	# request to the front controller, index.php
+	RewriteCond %{REQUEST_FILENAME} !-f
+	RewriteCond %{REQUEST_FILENAME} !-d
+	RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA]
+
+	# Ensure Authorization header is passed along
+	RewriteCond %{HTTP:Authorization} .
+	RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
+</IfModule>
+
+<IfModule !mod_rewrite.c>
+	# If we don't have mod_rewrite installed, all 404's
+	# can be sent to index.php, and everything works as normal.
+	ErrorDocument 404 index.php
+</IfModule>
+
+# Disable server signature start
+ServerSignature Off
+# Disable server signature end

BIN
dgonz/public/favicon.ico


+ 39 - 0
dgonz/public/frontend/.gitignore

@@ -0,0 +1,39 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+.DS_Store
+dist
+dist-ssr
+coverage
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+*.tsbuildinfo
+
+.eslintcache
+
+# Cypress
+/cypress/videos/
+/cypress/screenshots/
+
+# Vitest
+__screenshots__/
+
+# Vite
+*.timestamp-*-*.mjs

+ 42 - 0
dgonz/public/frontend/README.md

@@ -0,0 +1,42 @@
+# frontend
+
+This template should help get you started developing with Vue 3 in Vite.
+
+## Recommended IDE Setup
+
+[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
+
+## Recommended Browser Setup
+
+- Chromium-based browsers (Chrome, Edge, Brave, etc.):
+  - [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)
+  - [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters)
+- Firefox:
+  - [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/)
+  - [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/)
+
+## Type Support for `.vue` Imports in TS
+
+TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
+
+## Customize configuration
+
+See [Vite Configuration Reference](https://vite.dev/config/).
+
+## Project Setup
+
+```sh
+npm install
+```
+
+### Compile and Hot-Reload for Development
+
+```sh
+npm run dev
+```
+
+### Type-Check, Compile and Minify for Production
+
+```sh
+npm run build
+```

+ 1 - 0
dgonz/public/frontend/env.d.ts

@@ -0,0 +1 @@
+/// <reference types="vite/client" />

+ 13 - 0
dgonz/public/frontend/index.html

@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="UTF-8">
+    <link rel="icon" href="/favicon.ico">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Vite App</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>

+ 2986 - 0
dgonz/public/frontend/package-lock.json

@@ -0,0 +1,2986 @@
+{
+  "name": "frontend",
+  "version": "0.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "frontend",
+      "version": "0.0.0",
+      "dependencies": {
+        "vue": "^3.5.32",
+        "vue-router": "^5.0.4"
+      },
+      "devDependencies": {
+        "@tsconfig/node24": "^24.0.4",
+        "@types/node": "^24.12.2",
+        "@vitejs/plugin-vue": "^6.0.6",
+        "@vue/tsconfig": "^0.9.1",
+        "npm-run-all2": "^8.0.4",
+        "typescript": "~6.0.0",
+        "vite": "^8.0.8",
+        "vite-plugin-vue-devtools": "^8.1.1",
+        "vue-tsc": "^3.2.6"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+      "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.29.7",
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.1.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
+      "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
+      "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.29.7",
+        "@babel/generator": "^7.29.7",
+        "@babel/helper-compilation-targets": "^7.29.7",
+        "@babel/helper-module-transforms": "^7.29.7",
+        "@babel/helpers": "^7.29.7",
+        "@babel/parser": "^7.29.7",
+        "@babel/template": "^7.29.7",
+        "@babel/traverse": "^7.29.7",
+        "@babel/types": "^7.29.7",
+        "@jridgewell/remapping": "^2.3.5",
+        "convert-source-map": "^2.0.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.3",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
+      "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.29.7",
+        "@babel/types": "^7.29.7",
+        "@jridgewell/gen-mapping": "^0.3.12",
+        "@jridgewell/trace-mapping": "^0.3.28",
+        "jsesc": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-annotate-as-pure": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz",
+      "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
+      "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/compat-data": "^7.29.7",
+        "@babel/helper-validator-option": "^7.29.7",
+        "browserslist": "^4.24.0",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-create-class-features-plugin": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz",
+      "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.29.7",
+        "@babel/helper-member-expression-to-functions": "^7.29.7",
+        "@babel/helper-optimise-call-expression": "^7.29.7",
+        "@babel/helper-replace-supers": "^7.29.7",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7",
+        "@babel/traverse": "^7.29.7",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-globals": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
+      "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-member-expression-to-functions": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz",
+      "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.29.7",
+        "@babel/types": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
+      "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.29.7",
+        "@babel/types": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
+      "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.29.7",
+        "@babel/helper-validator-identifier": "^7.29.7",
+        "@babel/traverse": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-optimise-call-expression": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz",
+      "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
+      "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-replace-supers": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz",
+      "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-member-expression-to-functions": "^7.29.7",
+        "@babel/helper-optimise-call-expression": "^7.29.7",
+        "@babel/traverse": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz",
+      "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.29.7",
+        "@babel/types": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+      "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+      "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
+      "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
+      "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.29.7",
+        "@babel/types": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
+      "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.29.7"
+      },
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-decorators": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.7.tgz",
+      "integrity": "sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.29.7",
+        "@babel/helper-plugin-utils": "^7.29.7",
+        "@babel/plugin-syntax-decorators": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-decorators": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.29.7.tgz",
+      "integrity": "sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-attributes": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz",
+      "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-meta": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+      "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-jsx": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz",
+      "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-typescript": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz",
+      "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-typescript": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz",
+      "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.29.7",
+        "@babel/helper-create-class-features-plugin": "^7.29.7",
+        "@babel/helper-plugin-utils": "^7.29.7",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7",
+        "@babel/plugin-syntax-typescript": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
+      "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.29.7",
+        "@babel/parser": "^7.29.7",
+        "@babel/types": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz",
+      "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.29.7",
+        "@babel/generator": "^7.29.7",
+        "@babel/helper-globals": "^7.29.7",
+        "@babel/parser": "^7.29.7",
+        "@babel/template": "^7.29.7",
+        "@babel/types": "^7.29.7",
+        "debug": "^4.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
+      "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.29.7",
+        "@babel/helper-validator-identifier": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@emnapi/core": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+      "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/wasi-threads": "1.2.1",
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@emnapi/runtime": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+      "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@emnapi/wasi-threads": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
+      "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.13",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+      "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/remapping": {
+      "version": "2.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+      "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.31",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@napi-rs/wasm-runtime": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
+      "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@tybys/wasm-util": "^0.10.1"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/Brooooooklyn"
+      },
+      "peerDependencies": {
+        "@emnapi/core": "^1.7.1",
+        "@emnapi/runtime": "^1.7.1"
+      }
+    },
+    "node_modules/@oxc-project/types": {
+      "version": "0.133.0",
+      "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
+      "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
+      "devOptional": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/Boshen"
+      }
+    },
+    "node_modules/@polka/url": {
+      "version": "1.0.0-next.29",
+      "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
+      "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@rolldown/binding-android-arm64": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
+      "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-darwin-arm64": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz",
+      "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-darwin-x64": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz",
+      "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-freebsd-x64": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz",
+      "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz",
+      "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-arm64-gnu": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz",
+      "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-arm64-musl": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz",
+      "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-ppc64-gnu": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz",
+      "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-s390x-gnu": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz",
+      "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-x64-gnu": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
+      "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-x64-musl": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
+      "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-openharmony-arm64": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz",
+      "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-wasm32-wasi": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz",
+      "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
+      "cpu": [
+        "wasm32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/core": "1.10.0",
+        "@emnapi/runtime": "1.10.0",
+        "@napi-rs/wasm-runtime": "^1.1.4"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-win32-arm64-msvc": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz",
+      "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-win32-x64-msvc": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz",
+      "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/pluginutils": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
+      "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
+      "devOptional": true,
+      "license": "MIT"
+    },
+    "node_modules/@tsconfig/node24": {
+      "version": "24.0.4",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node24/-/node24-24.0.4.tgz",
+      "integrity": "sha512-2A933l5P5oCbv6qSxHs7ckKwobs8BDAe9SJ/Xr2Hy+nDlwmLE1GhFh/g/vXGRZWgxBg9nX/5piDtHR9Dkw/XuA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@tybys/wasm-util": {
+      "version": "0.10.2",
+      "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
+      "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@types/jsesc": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/@types/jsesc/-/jsesc-2.5.1.tgz",
+      "integrity": "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==",
+      "license": "MIT"
+    },
+    "node_modules/@types/node": {
+      "version": "24.12.4",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz",
+      "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==",
+      "devOptional": true,
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~7.16.0"
+      }
+    },
+    "node_modules/@vitejs/plugin-vue": {
+      "version": "6.0.7",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.7.tgz",
+      "integrity": "sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@rolldown/pluginutils": "^1.0.1"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "peerDependencies": {
+        "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+        "vue": "^3.2.25"
+      }
+    },
+    "node_modules/@volar/language-core": {
+      "version": "2.4.28",
+      "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz",
+      "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/source-map": "2.4.28"
+      }
+    },
+    "node_modules/@volar/source-map": {
+      "version": "2.4.28",
+      "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz",
+      "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@volar/typescript": {
+      "version": "2.4.28",
+      "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz",
+      "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/language-core": "2.4.28",
+        "path-browserify": "^1.0.1",
+        "vscode-uri": "^3.0.8"
+      }
+    },
+    "node_modules/@vue-macros/common": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.2.tgz",
+      "integrity": "sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-sfc": "^3.5.22",
+        "ast-kit": "^2.1.2",
+        "local-pkg": "^1.1.2",
+        "magic-string-ast": "^1.0.2",
+        "unplugin-utils": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/vue-macros"
+      },
+      "peerDependencies": {
+        "vue": "^2.7.0 || ^3.2.25"
+      },
+      "peerDependenciesMeta": {
+        "vue": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vue/babel-helper-vue-transform-on": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz",
+      "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@vue/babel-plugin-jsx": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz",
+      "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.27.1",
+        "@babel/helper-plugin-utils": "^7.27.1",
+        "@babel/plugin-syntax-jsx": "^7.27.1",
+        "@babel/template": "^7.27.2",
+        "@babel/traverse": "^7.28.0",
+        "@babel/types": "^7.28.2",
+        "@vue/babel-helper-vue-transform-on": "1.5.0",
+        "@vue/babel-plugin-resolve-type": "1.5.0",
+        "@vue/shared": "^3.5.18"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      },
+      "peerDependenciesMeta": {
+        "@babel/core": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vue/babel-plugin-resolve-type": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz",
+      "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.27.1",
+        "@babel/helper-module-imports": "^7.27.1",
+        "@babel/helper-plugin-utils": "^7.27.1",
+        "@babel/parser": "^7.28.0",
+        "@vue/compiler-sfc": "^3.5.18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@vue/compiler-core": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.35.tgz",
+      "integrity": "sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.29.3",
+        "@vue/shared": "3.5.35",
+        "entities": "^7.0.1",
+        "estree-walker": "^2.0.2",
+        "source-map-js": "^1.2.1"
+      }
+    },
+    "node_modules/@vue/compiler-dom": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.35.tgz",
+      "integrity": "sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-core": "3.5.35",
+        "@vue/shared": "3.5.35"
+      }
+    },
+    "node_modules/@vue/compiler-sfc": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.35.tgz",
+      "integrity": "sha512-G5VPMcXTSywXBgtFOZOnHKBxKSrwXUcvY1iaF5/hRcy7t0J6CH/d8ha9F4nzi00Fax1eLV0QHM7v4mQu68jydw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.29.3",
+        "@vue/compiler-core": "3.5.35",
+        "@vue/compiler-dom": "3.5.35",
+        "@vue/compiler-ssr": "3.5.35",
+        "@vue/shared": "3.5.35",
+        "estree-walker": "^2.0.2",
+        "magic-string": "^0.30.21",
+        "postcss": "^8.5.15",
+        "source-map-js": "^1.2.1"
+      }
+    },
+    "node_modules/@vue/compiler-ssr": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.35.tgz",
+      "integrity": "sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-dom": "3.5.35",
+        "@vue/shared": "3.5.35"
+      }
+    },
+    "node_modules/@vue/devtools-api": {
+      "version": "8.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.2.tgz",
+      "integrity": "sha512-vA0O112YqyDuNA1s7Yb2gCgToQ/OxOWiFDO5ThLCcDy0ldHnSd1dUTaSYhOldbqoNgumE4dxtGAoAaSUKUD1Zg==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/devtools-kit": "^8.1.2"
+      }
+    },
+    "node_modules/@vue/devtools-core": {
+      "version": "8.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-8.1.2.tgz",
+      "integrity": "sha512-ZGGyaSBP4/+bN2Nd9ZHNYAVDRIzMw1rv2RyXWtyZlo6mQal+IDmTvKY4V+DjAEBhaXt30mHmsgYp1yXJ/2tIWg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vue/devtools-kit": "^8.1.2",
+        "@vue/devtools-shared": "^8.1.2"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.0"
+      }
+    },
+    "node_modules/@vue/devtools-kit": {
+      "version": "8.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.2.tgz",
+      "integrity": "sha512-f75/upc+GCyjXErpgPGz4582ujS0L/adAltGy+tqXMGUJpgAcfGr6CxnnhpZY8BHuMYt6KpbF8uaFrrQG66rGQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/devtools-shared": "^8.1.2",
+        "birpc": "^2.6.1",
+        "hookable": "^5.5.3",
+        "perfect-debounce": "^2.0.0"
+      }
+    },
+    "node_modules/@vue/devtools-shared": {
+      "version": "8.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.2.tgz",
+      "integrity": "sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==",
+      "license": "MIT"
+    },
+    "node_modules/@vue/language-core": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.3.tgz",
+      "integrity": "sha512-X6p+7nfY7vVT6dQwUJ+v0Jfq/lwIfhL2jMi91dQ3ln4hnlGXlxsDu/FNkeyHYgvYtyQy18ZX76IZy7X4diDbiQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/language-core": "2.4.28",
+        "@vue/compiler-dom": "^3.5.0",
+        "@vue/shared": "^3.5.0",
+        "alien-signals": "^3.2.0",
+        "muggle-string": "^0.4.1",
+        "path-browserify": "^1.0.1",
+        "picomatch": "^4.0.4"
+      }
+    },
+    "node_modules/@vue/reactivity": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.35.tgz",
+      "integrity": "sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/shared": "3.5.35"
+      }
+    },
+    "node_modules/@vue/runtime-core": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.35.tgz",
+      "integrity": "sha512-A/xFNX9loIcWDygeQuNCfKuh0CoYBzxhqEMNah5TSFg9Z53DrFYEN2qi5CU9necjM1OWYegYREUTHmXTmhfXtg==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/reactivity": "3.5.35",
+        "@vue/shared": "3.5.35"
+      }
+    },
+    "node_modules/@vue/runtime-dom": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.35.tgz",
+      "integrity": "sha512-odrJ1C391dbGnyDRh8U+rnP7J2amIEzfmRk5vXy7xi3aZhEXofTvpi0T4HJb6jlNqQZTNPR5MPHSB3RHNkIORA==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/reactivity": "3.5.35",
+        "@vue/runtime-core": "3.5.35",
+        "@vue/shared": "3.5.35",
+        "csstype": "^3.2.3"
+      }
+    },
+    "node_modules/@vue/server-renderer": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.35.tgz",
+      "integrity": "sha512-NkebSOYdB97wi8OQcO3HqzZSlymJi/aWsN/7h74OSVhRTm6qGs3Jp3e0rCXynmWwSlKeRrnlIug+ilYoHBmQDA==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-ssr": "3.5.35",
+        "@vue/shared": "3.5.35"
+      },
+      "peerDependencies": {
+        "vue": "3.5.35"
+      }
+    },
+    "node_modules/@vue/shared": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.35.tgz",
+      "integrity": "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==",
+      "license": "MIT"
+    },
+    "node_modules/@vue/tsconfig": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.9.1.tgz",
+      "integrity": "sha512-buvjm+9NzLCJL29KY1j1991YYJ5e6275OiK+G4jtmfIb+z4POywbdm0wXusT9adVWqe0xqg70TbI7+mRx4uU9w==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "typescript": ">= 5.8",
+        "vue": "^3.4.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        },
+        "vue": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/acorn": {
+      "version": "8.16.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+      "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+      "license": "MIT",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/alien-signals": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.2.1.tgz",
+      "integrity": "sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/ansi-styles": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+      "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/ansis": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz",
+      "integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/ast-kit": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz",
+      "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.28.5",
+        "pathe": "^2.0.3"
+      },
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      }
+    },
+    "node_modules/ast-walker-scope": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.9.0.tgz",
+      "integrity": "sha512-IJdzo2vLiElBxKzwS36VsCue/62d6IdWjnPB2v3nuPKeWGynp6FF/CYoLa5i/3jXH/z97ZDdsXz6abpgM6w07A==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.29.2",
+        "@babel/types": "^7.29.0",
+        "ast-kit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      }
+    },
+    "node_modules/baseline-browser-mapping": {
+      "version": "2.10.33",
+      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz",
+      "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "baseline-browser-mapping": "dist/cli.cjs"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/birpc": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz",
+      "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.28.2",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
+      "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "baseline-browser-mapping": "^2.10.12",
+        "caniuse-lite": "^1.0.30001782",
+        "electron-to-chromium": "^1.5.328",
+        "node-releases": "^2.0.36",
+        "update-browserslist-db": "^1.2.3"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/bundle-name": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+      "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "run-applescript": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001793",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz",
+      "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "CC-BY-4.0"
+    },
+    "node_modules/chokidar": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
+      "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^5.0.0"
+      },
+      "engines": {
+        "node": ">= 20.19.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/confbox": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz",
+      "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==",
+      "license": "MIT"
+    },
+    "node_modules/convert-source-map": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+      "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/cross-spawn/node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/cross-spawn/node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/csstype": {
+      "version": "3.2.3",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+      "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+      "license": "MIT"
+    },
+    "node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/default-browser": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz",
+      "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "bundle-name": "^4.1.0",
+        "default-browser-id": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/default-browser-id": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz",
+      "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/define-lazy-prop": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+      "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/detect-libc": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+      "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+      "devOptional": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.5.367",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.367.tgz",
+      "integrity": "sha512-4Mk/mrynCNQ+atY40D3UpmhLWB6AHMbYMlIrPhHcMF6x0L7O0b052FCAsxw1LlaR++UFuNg3D/A6XCuGDa0guQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/entities": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
+      "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/error-stack-parser-es": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz",
+      "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+      "license": "MIT"
+    },
+    "node_modules/exsolve": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz",
+      "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==",
+      "license": "MIT"
+    },
+    "node_modules/fdir": {
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+      "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "picomatch": "^3 || ^4"
+      },
+      "peerDependenciesMeta": {
+        "picomatch": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/hookable": {
+      "version": "5.5.3",
+      "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
+      "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
+      "license": "MIT"
+    },
+    "node_modules/is-docker": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+      "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-in-ssh": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz",
+      "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-inside-container": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+      "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-docker": "^3.0.0"
+      },
+      "bin": {
+        "is-inside-container": "cli.js"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-wsl": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz",
+      "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-inside-container": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz",
+      "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/jsesc": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+      "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+      "license": "MIT",
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz",
+      "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "license": "MIT",
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/kolorist": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
+      "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lightningcss": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+      "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+      "devOptional": true,
+      "license": "MPL-2.0",
+      "dependencies": {
+        "detect-libc": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "optionalDependencies": {
+        "lightningcss-android-arm64": "1.32.0",
+        "lightningcss-darwin-arm64": "1.32.0",
+        "lightningcss-darwin-x64": "1.32.0",
+        "lightningcss-freebsd-x64": "1.32.0",
+        "lightningcss-linux-arm-gnueabihf": "1.32.0",
+        "lightningcss-linux-arm64-gnu": "1.32.0",
+        "lightningcss-linux-arm64-musl": "1.32.0",
+        "lightningcss-linux-x64-gnu": "1.32.0",
+        "lightningcss-linux-x64-musl": "1.32.0",
+        "lightningcss-win32-arm64-msvc": "1.32.0",
+        "lightningcss-win32-x64-msvc": "1.32.0"
+      }
+    },
+    "node_modules/lightningcss-android-arm64": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+      "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-darwin-arm64": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+      "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-darwin-x64": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+      "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-freebsd-x64": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+      "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm-gnueabihf": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+      "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm64-gnu": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+      "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm64-musl": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+      "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-x64-gnu": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+      "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-x64-musl": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+      "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-win32-arm64-msvc": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+      "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-win32-x64-msvc": {
+      "version": "1.32.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+      "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/local-pkg": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.2.1.tgz",
+      "integrity": "sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==",
+      "license": "MIT",
+      "dependencies": {
+        "mlly": "^1.7.4",
+        "pkg-types": "^2.3.0",
+        "quansync": "^0.2.11"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/magic-string": {
+      "version": "0.30.21",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+      "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.5"
+      }
+    },
+    "node_modules/magic-string-ast": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.3.tgz",
+      "integrity": "sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==",
+      "license": "MIT",
+      "dependencies": {
+        "magic-string": "^0.30.19"
+      },
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      }
+    },
+    "node_modules/memorystream": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
+      "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/mlly": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz",
+      "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==",
+      "license": "MIT",
+      "dependencies": {
+        "acorn": "^8.16.0",
+        "pathe": "^2.0.3",
+        "pkg-types": "^1.3.1",
+        "ufo": "^1.6.3"
+      }
+    },
+    "node_modules/mlly/node_modules/confbox": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
+      "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
+      "license": "MIT"
+    },
+    "node_modules/mlly/node_modules/pkg-types": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz",
+      "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
+      "license": "MIT",
+      "dependencies": {
+        "confbox": "^0.1.8",
+        "mlly": "^1.7.4",
+        "pathe": "^2.0.1"
+      }
+    },
+    "node_modules/mrmime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
+      "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/muggle-string": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
+      "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
+      "license": "MIT"
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.12",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
+      "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.47",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz",
+      "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/npm-normalize-package-bin": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz",
+      "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/npm-run-all2": {
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-8.0.4.tgz",
+      "integrity": "sha512-wdbB5My48XKp2ZfJUlhnLVihzeuA1hgBnqB2J9ahV77wLS+/YAJAlN8I+X3DIFIPZ3m5L7nplmlbhNiFDmXRDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.2.1",
+        "cross-spawn": "^7.0.6",
+        "memorystream": "^0.3.1",
+        "picomatch": "^4.0.2",
+        "pidtree": "^0.6.0",
+        "read-package-json-fast": "^4.0.0",
+        "shell-quote": "^1.7.3",
+        "which": "^5.0.0"
+      },
+      "bin": {
+        "npm-run-all": "bin/npm-run-all/index.js",
+        "npm-run-all2": "bin/npm-run-all/index.js",
+        "run-p": "bin/run-p/index.js",
+        "run-s": "bin/run-s/index.js"
+      },
+      "engines": {
+        "node": "^20.5.0 || >=22.0.0",
+        "npm": ">= 10"
+      }
+    },
+    "node_modules/obug": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
+      "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==",
+      "dev": true,
+      "funding": [
+        "https://github.com/sponsors/sxzz",
+        "https://opencollective.com/debug"
+      ],
+      "license": "MIT"
+    },
+    "node_modules/ohash": {
+      "version": "2.0.11",
+      "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
+      "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/open": {
+      "version": "11.0.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz",
+      "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "default-browser": "^5.4.0",
+        "define-lazy-prop": "^3.0.0",
+        "is-in-ssh": "^1.0.0",
+        "is-inside-container": "^1.0.0",
+        "powershell-utils": "^0.1.0",
+        "wsl-utils": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/path-browserify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
+      "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pathe": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+      "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+      "license": "MIT"
+    },
+    "node_modules/perfect-debounce": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz",
+      "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==",
+      "license": "MIT"
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+      "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pidtree": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
+      "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "pidtree": "bin/pidtree.js"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/pkg-types": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz",
+      "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==",
+      "license": "MIT",
+      "dependencies": {
+        "confbox": "^0.2.4",
+        "exsolve": "^1.0.8",
+        "pathe": "^2.0.3"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.5.15",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
+      "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "nanoid": "^3.3.12",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/powershell-utils": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz",
+      "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/quansync": {
+      "version": "0.2.11",
+      "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz",
+      "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/antfu"
+        },
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/sxzz"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/read-package-json-fast": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz",
+      "integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "json-parse-even-better-errors": "^4.0.0",
+        "npm-normalize-package-bin": "^4.0.0"
+      },
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
+      "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 20.19.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/rolldown": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
+      "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
+      "devOptional": true,
+      "license": "MIT",
+      "dependencies": {
+        "@oxc-project/types": "=0.133.0",
+        "@rolldown/pluginutils": "^1.0.0"
+      },
+      "bin": {
+        "rolldown": "bin/cli.mjs"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "optionalDependencies": {
+        "@rolldown/binding-android-arm64": "1.0.3",
+        "@rolldown/binding-darwin-arm64": "1.0.3",
+        "@rolldown/binding-darwin-x64": "1.0.3",
+        "@rolldown/binding-freebsd-x64": "1.0.3",
+        "@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
+        "@rolldown/binding-linux-arm64-gnu": "1.0.3",
+        "@rolldown/binding-linux-arm64-musl": "1.0.3",
+        "@rolldown/binding-linux-ppc64-gnu": "1.0.3",
+        "@rolldown/binding-linux-s390x-gnu": "1.0.3",
+        "@rolldown/binding-linux-x64-gnu": "1.0.3",
+        "@rolldown/binding-linux-x64-musl": "1.0.3",
+        "@rolldown/binding-openharmony-arm64": "1.0.3",
+        "@rolldown/binding-wasm32-wasi": "1.0.3",
+        "@rolldown/binding-win32-arm64-msvc": "1.0.3",
+        "@rolldown/binding-win32-x64-msvc": "1.0.3"
+      }
+    },
+    "node_modules/run-applescript": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz",
+      "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/scule": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz",
+      "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
+      "license": "MIT"
+    },
+    "node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shell-quote": {
+      "version": "1.8.4",
+      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz",
+      "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/sirv": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
+      "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@polka/url": "^1.0.0-next.24",
+        "mrmime": "^2.0.0",
+        "totalist": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/tinyglobby": {
+      "version": "0.2.17",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
+      "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+      "license": "MIT",
+      "dependencies": {
+        "fdir": "^6.5.0",
+        "picomatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/SuperchupuDev"
+      }
+    },
+    "node_modules/totalist": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+      "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+      "license": "0BSD",
+      "optional": true
+    },
+    "node_modules/typescript": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
+      "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
+      "devOptional": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/ufo": {
+      "version": "1.6.4",
+      "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz",
+      "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==",
+      "license": "MIT"
+    },
+    "node_modules/undici-types": {
+      "version": "7.16.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+      "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+      "devOptional": true,
+      "license": "MIT"
+    },
+    "node_modules/unplugin": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz",
+      "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/remapping": "^2.3.5",
+        "picomatch": "^4.0.3",
+        "webpack-virtual-modules": "^0.6.2"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/unplugin-utils": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz",
+      "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==",
+      "license": "MIT",
+      "dependencies": {
+        "pathe": "^2.0.3",
+        "picomatch": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+      "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "escalade": "^3.2.0",
+        "picocolors": "^1.1.1"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/vite": {
+      "version": "8.0.16",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
+      "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
+      "devOptional": true,
+      "license": "MIT",
+      "dependencies": {
+        "lightningcss": "^1.32.0",
+        "picomatch": "^4.0.4",
+        "postcss": "^8.5.15",
+        "rolldown": "1.0.3",
+        "tinyglobby": "^0.2.17"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^20.19.0 || >=22.12.0",
+        "@vitejs/devtools": "^0.1.18",
+        "esbuild": "^0.27.0 || ^0.28.0",
+        "jiti": ">=1.21.0",
+        "less": "^4.0.0",
+        "sass": "^1.70.0",
+        "sass-embedded": "^1.70.0",
+        "stylus": ">=0.54.8",
+        "sugarss": "^5.0.0",
+        "terser": "^5.16.0",
+        "tsx": "^4.8.1",
+        "yaml": "^2.4.2"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "@vitejs/devtools": {
+          "optional": true
+        },
+        "esbuild": {
+          "optional": true
+        },
+        "jiti": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        },
+        "tsx": {
+          "optional": true
+        },
+        "yaml": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite-dev-rpc": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/vite-dev-rpc/-/vite-dev-rpc-2.0.0.tgz",
+      "integrity": "sha512-yKwbTwdHKSD2k/aGqyWpPHepo45OQc8lH3/6IfT4ZqeKE26ooKvi4WIEKzqWav8v+9Is8u1k8q54hvOmqASazA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "birpc": "^4.0.0",
+        "vite-hot-client": "^2.2.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 || ^8.0.0"
+      }
+    },
+    "node_modules/vite-dev-rpc/node_modules/birpc": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/birpc/-/birpc-4.0.0.tgz",
+      "integrity": "sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/vite-hot-client": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.2.0.tgz",
+      "integrity": "sha512-76Zs9zrHbH7M7wqeyooGQKdX+yg0pQ0xuQ1PbFp4z5a0Lzn2e5IPFoCswnmqZ4GiwqB4Jo3WcDAMO9jARTJl8w==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0"
+      }
+    },
+    "node_modules/vite-plugin-inspect": {
+      "version": "11.4.1",
+      "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-11.4.1.tgz",
+      "integrity": "sha512-ShOFe2PURXGvRS5OrgmOLZOCwDTD7dEBVt0tMpFPKb9AsvqXKCRGM8QgKrUbRbJYFXScHvDPpGRd28rYidC0tA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansis": "^4.3.0",
+        "error-stack-parser-es": "^1.0.5",
+        "obug": "^2.1.1",
+        "ohash": "^2.0.11",
+        "open": "^11.0.0",
+        "perfect-debounce": "^2.1.0",
+        "sirv": "^3.0.2",
+        "unplugin-utils": "^0.3.1",
+        "vite-dev-rpc": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "vite": "^6.0.0 || ^7.0.0-0 || ^8.0.0-0"
+      },
+      "peerDependenciesMeta": {
+        "@nuxt/kit": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite-plugin-vue-devtools": {
+      "version": "8.1.2",
+      "resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-8.1.2.tgz",
+      "integrity": "sha512-gt5h1CNryR9Hy0tvhSbqY3j0F7aj0pGxBxWLa1lXSiZVkhdWDf0vbCOZyjh8ivFGE6FDHTGy3zkcZGlMZdVHig==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vue/devtools-core": "^8.1.2",
+        "@vue/devtools-kit": "^8.1.2",
+        "@vue/devtools-shared": "^8.1.2",
+        "sirv": "^3.0.2",
+        "vite-plugin-inspect": "^11.3.3",
+        "vite-plugin-vue-inspector": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=v14.21.3"
+      },
+      "peerDependencies": {
+        "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/vite-plugin-vue-inspector": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-6.0.0.tgz",
+      "integrity": "sha512-OpyITJLgZNibxlrik1EmRtvXHDjLRxNPsWkGFTERZs2LgMEdG4W0WoFt5GIgp3a3jRou+eJR8U1zOBk/XQgEbw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.23.0",
+        "@babel/plugin-proposal-decorators": "^7.23.0",
+        "@babel/plugin-syntax-import-attributes": "^7.22.5",
+        "@babel/plugin-syntax-import-meta": "^7.10.4",
+        "@babel/plugin-transform-typescript": "^7.22.15",
+        "@vue/babel-plugin-jsx": "^1.1.5",
+        "@vue/compiler-dom": "^3.3.4",
+        "kolorist": "^1.8.0",
+        "magic-string": "^0.30.4"
+      },
+      "peerDependencies": {
+        "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/vscode-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
+      "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/vue": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.35.tgz",
+      "integrity": "sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-dom": "3.5.35",
+        "@vue/compiler-sfc": "3.5.35",
+        "@vue/runtime-dom": "3.5.35",
+        "@vue/server-renderer": "3.5.35",
+        "@vue/shared": "3.5.35"
+      },
+      "peerDependencies": {
+        "typescript": "*"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vue-router": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.1.0.tgz",
+      "integrity": "sha512-HAbiLzLEHQwxPgvsbOJDAwtavszEgLwri6XfyrsPECIFez8+59xc9LofWVdc/HEaSRT822lJ8H9Ns38VVond5g==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/generator": "^8.0.0-rc.4",
+        "@vue-macros/common": "^3.1.1",
+        "@vue/devtools-api": "^8.1.2",
+        "ast-walker-scope": "^0.9.0",
+        "chokidar": "^5.0.0",
+        "json5": "^2.2.3",
+        "local-pkg": "^1.1.2",
+        "magic-string": "^0.30.21",
+        "mlly": "^1.8.2",
+        "muggle-string": "^0.4.1",
+        "pathe": "^2.0.3",
+        "picomatch": "^4.0.3",
+        "scule": "^1.3.0",
+        "tinyglobby": "^0.2.16",
+        "unplugin": "^3.0.0",
+        "unplugin-utils": "^0.3.1",
+        "yaml": "^2.9.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/posva"
+      },
+      "peerDependencies": {
+        "@pinia/colada": ">=0.21.2",
+        "@vue/compiler-sfc": "^3.5.34",
+        "pinia": "^3.0.4",
+        "vite": "^7.0.0 || ^8.0.0",
+        "vue": "^3.5.34"
+      },
+      "peerDependenciesMeta": {
+        "@pinia/colada": {
+          "optional": true
+        },
+        "@vue/compiler-sfc": {
+          "optional": true
+        },
+        "pinia": {
+          "optional": true
+        },
+        "vite": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vue-router/node_modules/@babel/generator": {
+      "version": "8.0.0-rc.6",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.0-rc.6.tgz",
+      "integrity": "sha512-6mIzgVK8DgEzvIapoQwhXTMnnkuE4STQmVv9H03i/tZ2ml8oev3TRvZJgTenK2Bsq0YWNtzOrFdTyNzCMFtjJQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^8.0.0-rc.6",
+        "@babel/types": "^8.0.0-rc.6",
+        "@jridgewell/gen-mapping": "^0.3.12",
+        "@jridgewell/trace-mapping": "^0.3.28",
+        "@types/jsesc": "^2.5.0",
+        "jsesc": "^3.0.2"
+      },
+      "engines": {
+        "node": "^22.18.0 || >=24.11.0"
+      }
+    },
+    "node_modules/vue-router/node_modules/@babel/helper-string-parser": {
+      "version": "8.0.0-rc.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0-rc.6.tgz",
+      "integrity": "sha512-BCkFy+zN6kXQed3YOT7aJl93NfDSzQc3pBfsvTVPs9gU9X3V0aefEF5kwBT0E+mDWH9QgKaZstYUQN9VdQZT4g==",
+      "license": "MIT",
+      "engines": {
+        "node": "^22.18.0 || >=24.11.0"
+      }
+    },
+    "node_modules/vue-router/node_modules/@babel/helper-validator-identifier": {
+      "version": "8.0.0-rc.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.0-rc.6.tgz",
+      "integrity": "sha512-nVJ+1JcCgntv8d78rRo++o2wuODT0Irknx2BF8Np4Ft2CRgjLqIs4qzSZ8b66yGbBdMWGmZBO9WEZv1hhNiSpg==",
+      "license": "MIT",
+      "engines": {
+        "node": "^22.18.0 || >=24.11.0"
+      }
+    },
+    "node_modules/vue-router/node_modules/@babel/parser": {
+      "version": "8.0.0-rc.6",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.0-rc.6.tgz",
+      "integrity": "sha512-rOS8IpdO7mQELkTPlCsTgPejO0bFuZdEDCGQJouYbYf9e1FLTym7Fei2pEjq8q7MWbX0ravcd7QQYKs1TxOuog==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^8.0.0-rc.6"
+      },
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": "^22.18.0 || >=24.11.0"
+      }
+    },
+    "node_modules/vue-router/node_modules/@babel/types": {
+      "version": "8.0.0-rc.6",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0-rc.6.tgz",
+      "integrity": "sha512-p7/ABylAYlexb31wtRdIfH9L9A0Z2T/9H6zAqzqndkY2PLkvNNc580wGhp/gGKN4Sp9sQvSkhc6Oga8/O+wTyw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^8.0.0-rc.6",
+        "@babel/helper-validator-identifier": "^8.0.0-rc.6"
+      },
+      "engines": {
+        "node": "^22.18.0 || >=24.11.0"
+      }
+    },
+    "node_modules/vue-tsc": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.3.tgz",
+      "integrity": "sha512-SWUEG7YRUeDJHT7Xsuhf02elYX2gxPzzAII7OxDAh4KNOr4QHQ0Lls0YfnaO5GNd560CwVa2HTfdqmA5MqvRqQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/typescript": "2.4.28",
+        "@vue/language-core": "3.3.3"
+      },
+      "bin": {
+        "vue-tsc": "bin/vue-tsc.js"
+      },
+      "peerDependencies": {
+        "typescript": ">=5.0.0"
+      }
+    },
+    "node_modules/webpack-virtual-modules": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
+      "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
+      "license": "MIT"
+    },
+    "node_modules/which": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz",
+      "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^3.1.1"
+      },
+      "bin": {
+        "node-which": "bin/which.js"
+      },
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/wsl-utils": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz",
+      "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-wsl": "^3.1.0",
+        "powershell-utils": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/yaml": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz",
+      "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
+      "license": "ISC",
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/eemeli"
+      }
+    }
+  }
+}

+ 31 - 0
dgonz/public/frontend/package.json

@@ -0,0 +1,31 @@
+{
+  "name": "frontend",
+  "version": "0.0.0",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "run-p type-check \"build-only {@}\" --",
+    "preview": "vite preview",
+    "build-only": "vite build",
+    "type-check": "vue-tsc --build"
+  },
+  "dependencies": {
+    "vue": "^3.5.32",
+    "vue-router": "^5.0.4"
+  },
+  "devDependencies": {
+    "@tsconfig/node24": "^24.0.4",
+    "@types/node": "^24.12.2",
+    "@vitejs/plugin-vue": "^6.0.6",
+    "@vue/tsconfig": "^0.9.1",
+    "npm-run-all2": "^8.0.4",
+    "typescript": "~6.0.0",
+    "vite": "^8.0.8",
+    "vite-plugin-vue-devtools": "^8.1.1",
+    "vue-tsc": "^3.2.6"
+  },
+  "engines": {
+    "node": "^20.19.0 || >=22.12.0"
+  }
+}

BIN
dgonz/public/frontend/public/favicon.ico


+ 11 - 0
dgonz/public/frontend/src/App.vue

@@ -0,0 +1,11 @@
+<script setup lang="ts"></script>
+
+<template>
+  <h1>You did it!</h1>
+  <p>
+    Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
+    documentation
+  </p>
+</template>
+
+<style scoped></style>

+ 9 - 0
dgonz/public/frontend/src/main.ts

@@ -0,0 +1,9 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+import router from './router'
+
+const app = createApp(App)
+
+app.use(router)
+
+app.mount('#app')

+ 8 - 0
dgonz/public/frontend/src/router/index.ts

@@ -0,0 +1,8 @@
+import { createRouter, createWebHistory } from 'vue-router'
+
+const router = createRouter({
+  history: createWebHistory(import.meta.env.BASE_URL),
+  routes: [],
+})
+
+export default router

+ 18 - 0
dgonz/public/frontend/tsconfig.app.json

@@ -0,0 +1,18 @@
+{
+  "extends": "@vue/tsconfig/tsconfig.dom.json",
+  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
+  "exclude": ["src/**/__tests__/*"],
+  "compilerOptions": {
+    // Extra safety for array and object lookups, but may have false positives.
+    "noUncheckedIndexedAccess": true,
+
+    // Path mapping for cleaner imports.
+    "paths": {
+      "@/*": ["./src/*"]
+    },
+
+    // `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking.
+    // Specified here to keep it out of the root directory.
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo"
+  }
+}

+ 11 - 0
dgonz/public/frontend/tsconfig.json

@@ -0,0 +1,11 @@
+{
+  "files": [],
+  "references": [
+    {
+      "path": "./tsconfig.node.json"
+    },
+    {
+      "path": "./tsconfig.app.json"
+    }
+  ]
+}

+ 27 - 0
dgonz/public/frontend/tsconfig.node.json

@@ -0,0 +1,27 @@
+// TSConfig for modules that run in Node.js environment via either transpilation or type-stripping.
+{
+  "extends": "@tsconfig/node24/tsconfig.json",
+  "include": [
+    "vite.config.*",
+    "vitest.config.*",
+    "cypress.config.*",
+    "playwright.config.*",
+    "eslint.config.*"
+  ],
+  "compilerOptions": {
+    // Most tools use transpilation instead of Node.js's native type-stripping.
+    // Bundler mode provides a smoother developer experience.
+    "module": "preserve",
+    "moduleResolution": "bundler",
+
+    // Include Node.js types and avoid accidentally including other `@types/*` packages.
+    "types": ["node"],
+
+    // Disable emitting output during `vue-tsc --build`, which is used for type-checking only.
+    "noEmit": true,
+
+    // `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking.
+    // Specified here to keep it out of the root directory.
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
+  }
+}

+ 18 - 0
dgonz/public/frontend/vite.config.ts

@@ -0,0 +1,18 @@
+import { fileURLToPath, URL } from 'node:url'
+
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import vueDevTools from 'vite-plugin-vue-devtools'
+
+// https://vite.dev/config/
+export default defineConfig({
+  plugins: [
+    vue(),
+    vueDevTools(),
+  ],
+  resolve: {
+    alias: {
+      '@': fileURLToPath(new URL('./src', import.meta.url))
+    },
+  },
+})

+ 59 - 0
dgonz/public/index.php

@@ -0,0 +1,59 @@
+<?php
+
+use CodeIgniter\Boot;
+use Config\Paths;
+
+/*
+ *---------------------------------------------------------------
+ * CHECK PHP VERSION
+ *---------------------------------------------------------------
+ */
+
+$minPhpVersion = '8.2'; // If you update this, don't forget to update `spark`.
+if (version_compare(PHP_VERSION, $minPhpVersion, '<')) {
+    $message = sprintf(
+        'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s',
+        $minPhpVersion,
+        PHP_VERSION,
+    );
+
+    header('HTTP/1.1 503 Service Unavailable.', true, 503);
+    echo $message;
+
+    exit(1);
+}
+
+/*
+ *---------------------------------------------------------------
+ * SET THE CURRENT DIRECTORY
+ *---------------------------------------------------------------
+ */
+
+// Path to the front controller (this file)
+define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR);
+
+// Ensure the current directory is pointing to the front controller's directory
+if (getcwd() . DIRECTORY_SEPARATOR !== FCPATH) {
+    chdir(FCPATH);
+}
+
+/*
+ *---------------------------------------------------------------
+ * BOOTSTRAP THE APPLICATION
+ *---------------------------------------------------------------
+ * This process sets up the path constants, loads and registers
+ * our autoloader, along with Composer's, loads our constants
+ * and fires up an environment-specific bootstrapping.
+ */
+
+// LOAD OUR PATHS CONFIG FILE
+// This is the line that might need to be changed, depending on your folder structure.
+require FCPATH . '../app/Config/Paths.php';
+// ^^^ Change this line if you move your application folder
+
+$paths = new Paths();
+
+// LOAD THE FRAMEWORK BOOTSTRAP FILE
+require $paths->systemDirectory . '/Boot.php';
+
+exit(Boot::bootWeb($paths));

+ 2 - 0
dgonz/public/robots.txt

@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: 

+ 87 - 0
dgonz/spark

@@ -0,0 +1,87 @@
+#!/usr/bin/env php
+<?php
+
+/**
+ * This file is part of CodeIgniter 4 framework.
+ *
+ * (c) CodeIgniter Foundation <admin@codeigniter.com>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+use CodeIgniter\Boot;
+use Config\Paths;
+
+/*
+ * --------------------------------------------------------------------
+ * CODEIGNITER COMMAND-LINE TOOLS
+ * --------------------------------------------------------------------
+ * The main entry point into the CLI system and allows you to run
+ * commands and perform maintenance on your application.
+ */
+
+/*
+ *---------------------------------------------------------------
+ * CHECK SERVER API
+ *---------------------------------------------------------------
+ */
+
+// Refuse to run when called from php-cgi
+if (str_starts_with(PHP_SAPI, 'cgi')) {
+    exit("The cli tool is not supported when running php-cgi. It needs php-cli to function!\n\n");
+}
+
+/*
+ *---------------------------------------------------------------
+ * CHECK PHP VERSION
+ *---------------------------------------------------------------
+ */
+
+$minPhpVersion = '8.2'; // If you update this, don't forget to update `public/index.php`.
+if (version_compare(PHP_VERSION, $minPhpVersion, '<')) {
+    $message = sprintf(
+        'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s',
+        $minPhpVersion,
+        PHP_VERSION,
+    );
+
+    exit($message);
+}
+
+// We want errors to be shown when using it from the CLI.
+error_reporting(E_ALL);
+ini_set('display_errors', '1');
+
+/*
+ *---------------------------------------------------------------
+ * SET THE CURRENT DIRECTORY
+ *---------------------------------------------------------------
+ */
+
+// Path to the front controller
+define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR);
+
+// Ensure the current directory is pointing to the front controller's directory
+chdir(FCPATH);
+
+/*
+ *---------------------------------------------------------------
+ * BOOTSTRAP THE APPLICATION
+ *---------------------------------------------------------------
+ * This process sets up the path constants, loads and registers
+ * our autoloader, along with Composer's, loads our constants
+ * and fires up an environment-specific bootstrapping.
+ */
+
+// LOAD OUR PATHS CONFIG FILE
+// This is the line that might need to be changed, depending on your folder structure.
+require FCPATH . '../app/Config/Paths.php';
+// ^^^ Change this line if you move your application folder
+
+$paths = new Paths();
+
+// LOAD THE FRAMEWORK BOOTSTRAP FILE
+require $paths->systemDirectory . '/Boot.php';
+
+exit(Boot::bootSpark($paths));

+ 6 - 0
dgonz/tests/.htaccess

@@ -0,0 +1,6 @@
+<IfModule authz_core_module>
+	Require all denied
+</IfModule>
+<IfModule !authz_core_module>
+	Deny from all
+</IfModule>

+ 118 - 0
dgonz/tests/README.md

@@ -0,0 +1,118 @@
+# Running Application Tests
+
+This is the quick-start to CodeIgniter testing. Its intent is to describe what
+it takes to set up your application and get it ready to run unit tests.
+It is not intended to be a full description of the test features that you can
+use to test your application. Those details can be found in the documentation.
+
+## Resources
+
+* [CodeIgniter 4 User Guide on Testing](https://codeigniter.com/user_guide/testing/index.html)
+* [PHPUnit docs](https://phpunit.de/documentation.html)
+* [Any tutorials on Unit testing in CI4?](https://forum.codeigniter.com/showthread.php?tid=81830)
+
+## Requirements
+
+It is recommended to use the latest version of PHPUnit. At the time of this
+writing, we are running version 9.x. Support for this has been built into the
+**composer.json** file that ships with CodeIgniter and can easily be installed
+via [Composer](https://getcomposer.org/) if you don't already have it installed globally.
+
+```console
+> composer install
+```
+
+If running under macOS or Linux, you can create a symbolic link to make running tests a touch nicer.
+
+```console
+> ln -s ./vendor/bin/phpunit ./phpunit
+```
+
+You also need to install [XDebug](https://xdebug.org/docs/install) in order
+for code coverage to be calculated successfully. After installing `XDebug`, you must add `xdebug.mode=coverage` in the **php.ini** file to enable code coverage.
+
+## Setting Up
+
+A number of the tests use a running database.
+In order to set up the database edit the details for the `tests` group in
+**app/Config/Database.php** or **.env**.
+Make sure that you provide a database engine that is currently running on your machine.
+More details on a test database setup are in the
+[Testing Your Database](https://codeigniter.com/user_guide/testing/database.html) section of the documentation.
+
+## Running the tests
+
+The entire test suite can be run by simply typing one command-line command from the main directory.
+
+```console
+> ./phpunit
+```
+
+If you are using Windows, use the following command.
+
+```console
+> vendor\bin\phpunit
+```
+
+You can limit tests to those within a single test directory by specifying the
+directory name after phpunit.
+
+```console
+> ./phpunit app/Models
+```
+
+## Generating Code Coverage
+
+To generate coverage information, including HTML reports you can view in your browser,
+you can use the following command:
+
+```console
+> ./phpunit --colors --coverage-text=tests/coverage.txt --coverage-html=tests/coverage/ -d memory_limit=1024m
+```
+
+This runs all of the tests again collecting information about how many lines,
+functions, and files are tested. It also reports the percentage of the code that is covered by tests.
+It is collected in two formats: a simple text file that provides an overview as well
+as a comprehensive collection of HTML files that show the status of every line of code in the project.
+
+The text file can be found at **tests/coverage.txt**.
+The HTML files can be viewed by opening **tests/coverage/index.html** in your favorite browser.
+
+## PHPUnit XML Configuration
+
+The repository has a ``phpunit.dist.xml`` file in the project root that's used for
+PHPUnit configuration. This is used to provide a default configuration if you
+do not have your own configuration file in the project root.
+
+The normal practice would be to copy ``phpunit.dist.xml`` to ``phpunit.xml``
+(which is git ignored), and to tailor it as you see fit.
+For instance, you might wish to exclude database tests, or automatically generate
+HTML code coverage reports.
+
+## Test Cases
+
+Every test needs a *test case*, or class that your tests extend. CodeIgniter 4
+provides one class that you may use directly:
+* `CodeIgniter\Test\CIUnitTestCase`
+
+Most of the time you will want to write your own test cases that extend `CIUnitTestCase`
+to hold functions and services common to your test suites.
+
+## Creating Tests
+
+All tests go in the **tests/** directory. Each test file is a class that extends a
+**Test Case** (see above) and contains methods for the individual tests. These method
+names must start with the word "test" and should have descriptive names for precisely what
+they are testing:
+`testUserCanModifyFile()` `testOutputColorMatchesInput()` `testIsLoggedInFailsWithInvalidUser()`
+
+Writing tests is an art, and there are many resources available to help learn how.
+Review the links above and always pay attention to your code coverage.
+
+### Database Tests
+
+Tests can include migrating, seeding, and testing against a mock or live database.
+Be sure to modify the test case (or create your own) to point to your seed and migrations
+and include any additional steps to be run before tests in the `setUp()` method.
+See [Testing Your Database](https://codeigniter.com/user_guide/testing/database.html)
+for details.

+ 37 - 0
dgonz/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace Tests\Support\Database\Migrations;
+
+use CodeIgniter\Database\Migration;
+
+class ExampleMigration extends Migration
+{
+    protected $DBGroup = 'tests';
+
+    public function up(): void
+    {
+        $this->forge->addField('id');
+        $this->forge->addField([
+            'name'       => ['type' => 'varchar', 'constraint' => 31],
+            'uid'        => ['type' => 'varchar', 'constraint' => 31],
+            'class'      => ['type' => 'varchar', 'constraint' => 63],
+            'icon'       => ['type' => 'varchar', 'constraint' => 31],
+            'summary'    => ['type' => 'varchar', 'constraint' => 255],
+            'created_at' => ['type' => 'datetime', 'null' => true],
+            'updated_at' => ['type' => 'datetime', 'null' => true],
+            'deleted_at' => ['type' => 'datetime', 'null' => true],
+        ]);
+
+        $this->forge->addKey('name');
+        $this->forge->addKey('uid');
+        $this->forge->addKey(['deleted_at', 'id']);
+        $this->forge->addKey('created_at');
+
+        $this->forge->createTable('factories');
+    }
+
+    public function down(): void
+    {
+        $this->forge->dropTable('factories');
+    }
+}

+ 41 - 0
dgonz/tests/_support/Database/Seeds/ExampleSeeder.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace Tests\Support\Database\Seeds;
+
+use CodeIgniter\Database\Seeder;
+
+class ExampleSeeder extends Seeder
+{
+    public function run(): void
+    {
+        $factories = [
+            [
+                'name'    => 'Test Factory',
+                'uid'     => 'test001',
+                'class'   => 'Factories\Tests\NewFactory',
+                'icon'    => 'fas fa-puzzle-piece',
+                'summary' => 'Longer sample text for testing',
+            ],
+            [
+                'name'    => 'Widget Factory',
+                'uid'     => 'widget',
+                'class'   => 'Factories\Tests\WidgetPlant',
+                'icon'    => 'fas fa-puzzle-piece',
+                'summary' => 'Create widgets in your factory',
+            ],
+            [
+                'name'    => 'Evil Factory',
+                'uid'     => 'evil-maker',
+                'class'   => 'Factories\Evil\MyFactory',
+                'icon'    => 'fas fa-book-dead',
+                'summary' => 'Abandon all hope, ye who enter here',
+            ],
+        ];
+
+        $builder = $this->db->table('factories');
+
+        foreach ($factories as $factory) {
+            $builder->insert($factory);
+        }
+    }
+}

Some files were not shown because too many files changed in this diff