diff --git a/cron/ticket_email_parser.php b/cron/ticket_email_parser.php
new file mode 100644
index 00000000..0cf570af
--- /dev/null
+++ b/cron/ticket_email_parser.php
@@ -0,0 +1,536 @@
+ Ticketing > Email-to-ticket parsing. See https://docs.itflow.org/ticket_email_parse -- Quitting..");
+}
+
+// System temp directory & lock
+$temp_dir = sys_get_temp_dir();
+$lock_file_path = "{$temp_dir}/itflow_email_parser_{$installation_id}.lock";
+
+if (file_exists($lock_file_path)) {
+ $file_age = time() - filemtime($lock_file_path);
+ if ($file_age > 300) {
+ unlink($lock_file_path);
+ logApp("Cron-Email-Parser", "warning", "Cron Email Parser detected a lock file was present but was over 5 minutes old so it removed it.");
+ } else {
+ logApp("Cron-Email-Parser", "warning", "Lock file present. Cron Email Parser attempted to execute but was already executing, so instead it terminated.");
+ exit("Script is already running. Exiting.");
+ }
+}
+file_put_contents($lock_file_path, "Locked");
+
+// Ensure lock gets removed even on fatal error
+register_shutdown_function(function() use ($lock_file_path) {
+ if (file_exists($lock_file_path)) {
+ @unlink($lock_file_path);
+ }
+});
+
+// Allowed attachment extensions
+$allowed_extensions = array('jpg', 'jpeg', 'gif', 'png', 'webp', 'pdf', 'txt', 'md', 'doc', 'docx', 'csv', 'xls', 'xlsx', 'xlsm', 'zip', 'tar', 'gz');
+
+/** ------------------------------------------------------------------
+ * Ticket / Reply helpers (unchanged)
+ * ------------------------------------------------------------------ */
+function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message, $attachments, $original_message_file) {
+ global $mysqli, $config_app_name, $company_name, $company_phone, $config_ticket_prefix, $config_ticket_client_general_notifications, $config_ticket_new_ticket_notification_email, $config_base_url, $config_ticket_from_name, $config_ticket_from_email, $config_ticket_default_billable, $allowed_extensions;
+
+ $ticket_number_sql = mysqli_fetch_array(mysqli_query($mysqli, "SELECT config_ticket_next_number FROM settings WHERE company_id = 1"));
+ $ticket_number = intval($ticket_number_sql['config_ticket_next_number']);
+ $new_config_ticket_next_number = $ticket_number + 1;
+ mysqli_query($mysqli, "UPDATE settings SET config_ticket_next_number = $new_config_ticket_next_number WHERE company_id = 1");
+
+ // Clean up the message
+ $message = trim($message);
+ $message = preg_replace('/\s+/', ' ', $message);
+ $message = nl2br($message);
+ $message = "Email from: $contact_name <$contact_email> at $date:-
$message
";
+
+ $ticket_prefix_esc = mysqli_real_escape_string($mysqli, $config_ticket_prefix);
+ $message_esc = mysqli_real_escape_string($mysqli, $message);
+ $contact_email_esc = mysqli_real_escape_string($mysqli, $contact_email);
+ $client_id = intval($client_id);
+
+ $url_key = randomString(156);
+
+ mysqli_query($mysqli, "INSERT INTO tickets SET ticket_prefix = '$ticket_prefix_esc', ticket_number = $ticket_number, ticket_source = 'Email', ticket_subject = '$subject', ticket_details = '$message_esc', ticket_priority = 'Low', ticket_status = 1, ticket_billable = $config_ticket_default_billable, ticket_created_by = 0, ticket_contact_id = $contact_id, ticket_url_key = '$url_key', ticket_client_id = $client_id");
+ $id = mysqli_insert_id($mysqli);
+
+ // Logging
+ logAction("Ticket", "Create", "Email parser: Client contact $contact_email_esc created ticket $ticket_prefix_esc$ticket_number ($subject) ($id)", $client_id, $id);
+
+ mkdirMissing('../uploads/tickets/');
+ $att_dir = "../uploads/tickets/" . $id . "/";
+ mkdirMissing($att_dir);
+
+ // Move original .eml into the ticket folder
+ rename("../uploads/tmp/{$original_message_file}", "{$att_dir}/{$original_message_file}");
+ $original_message_file_esc = mysqli_real_escape_string($mysqli, $original_message_file);
+ mysqli_query($mysqli, "INSERT INTO ticket_attachments SET ticket_attachment_name = 'Original-parsed-email.eml', ticket_attachment_reference_name = '$original_message_file_esc', ticket_attachment_ticket_id = $id");
+
+ // Save non-inline attachments
+ foreach ($attachments as $attachment) {
+ $att_name = $attachment['name'];
+ $att_extension = strtolower(pathinfo($att_name, PATHINFO_EXTENSION));
+
+ if (in_array($att_extension, $allowed_extensions)) {
+ $att_saved_filename = md5(uniqid(rand(), true)) . '.' . $att_extension;
+ $att_saved_path = $att_dir . $att_saved_filename;
+ file_put_contents($att_saved_path, $attachment['content']);
+
+ $ticket_attachment_name = sanitizeInput($att_name);
+ $ticket_attachment_reference_name = sanitizeInput($att_saved_filename);
+
+ $ticket_attachment_name_esc = mysqli_real_escape_string($mysqli, $ticket_attachment_name);
+ $ticket_attachment_reference_name_esc = mysqli_real_escape_string($mysqli, $ticket_attachment_reference_name);
+ mysqli_query($mysqli, "INSERT INTO ticket_attachments SET ticket_attachment_name = '$ticket_attachment_name_esc', ticket_attachment_reference_name = '$ticket_attachment_reference_name_esc', ticket_attachment_ticket_id = $id");
+ } else {
+ $ticket_attachment_name_esc = mysqli_real_escape_string($mysqli, $att_name);
+ logAction("Ticket", "Edit", "Email parser: Blocked attachment $ticket_attachment_name_esc from Client contact $contact_email_esc for ticket $ticket_prefix_esc$ticket_number", $client_id, $id);
+ }
+ }
+
+ // Guest ticket watchers
+ if ($client_id == 0) {
+ mysqli_query($mysqli, "INSERT INTO ticket_watchers SET watcher_email = '$contact_email_esc', watcher_ticket_id = $id");
+ }
+
+ $data = [];
+ if ($config_ticket_client_general_notifications == 1) {
+ $subject_email = "Ticket created - [$config_ticket_prefix$ticket_number] - $subject";
+ $body = "##- Please type your reply above this line -## Hello $contact_name, Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you. Ticket: $config_ticket_prefix$ticket_number Subject: $subject Status: New Portal: View ticket -- $company_name - Support $config_ticket_from_email $company_phone";
+ $data[] = [
+ 'from' => $config_ticket_from_email,
+ 'from_name' => $config_ticket_from_name,
+ 'recipient' => $contact_email,
+ 'recipient_name' => $contact_name,
+ 'subject' => $subject_email,
+ 'body' => mysqli_real_escape_string($mysqli, $body)
+ ];
+ }
+
+ if ($config_ticket_new_ticket_notification_email) {
+ if ($client_id == 0) {
+ $client_name = "Guest";
+ } else {
+ $client_sql = mysqli_query($mysqli, "SELECT client_name FROM clients WHERE client_id = $client_id");
+ $client_row = mysqli_fetch_array($client_sql);
+ $client_name = sanitizeInput($client_row['client_name']);
+ }
+ $email_subject = "$config_app_name - New Ticket - $client_name: $subject";
+ $email_body = "Hello, This is a notification that a new ticket has been raised in ITFlow. Client: $client_name Priority: Low (email parsed) Link: https://$config_base_url/ticket.php?ticket_id=$id --------------------------------$subject $message";
+
+ $data[] = [
+ 'from' => $config_ticket_from_email,
+ 'from_name' => $config_ticket_from_name,
+ 'recipient' => $config_ticket_new_ticket_notification_email,
+ 'recipient_name' => $config_ticket_from_name,
+ 'subject' => $email_subject,
+ 'body' => mysqli_real_escape_string($mysqli, $email_body)
+ ];
+ }
+
+ addToMailQueue($data);
+ customAction('ticket_create', $id);
+
+ return true;
+}
+
+function addReply($from_email, $date, $subject, $ticket_number, $message, $attachments) {
+ global $mysqli, $config_app_name, $company_name, $company_phone, $config_ticket_prefix, $config_base_url, $config_ticket_from_name, $config_ticket_from_email, $allowed_extensions;
+
+ $ticket_reply_type = 'Client';
+ $message_parts = explode("##- Please type your reply above this line -##", $message);
+ $message_body = $message_parts[0];
+ $message_body = trim($message_body);
+ $message_body = preg_replace('/\r\n|\r|\n/', ' ', $message_body);
+ $message_body = nl2br($message_body);
+
+ $message = "Email from: $from_email at $date:- $message_body
";
+
+ $ticket_number_esc = intval($ticket_number);
+ $message_esc = mysqli_real_escape_string($mysqli, $message);
+ $from_email_esc = mysqli_real_escape_string($mysqli, $from_email);
+
+ $row = mysqli_fetch_array(mysqli_query($mysqli, "SELECT ticket_id, ticket_subject, ticket_status, ticket_contact_id, ticket_client_id, contact_email, client_name
+ FROM tickets
+ LEFT JOIN contacts on tickets.ticket_contact_id = contacts.contact_id
+ LEFT JOIN clients on tickets.ticket_client_id = clients.client_id
+ WHERE ticket_number = $ticket_number_esc LIMIT 1"));
+
+ if ($row) {
+ $ticket_id = intval($row['ticket_id']);
+ $ticket_subject = sanitizeInput($row['ticket_subject']);
+ $ticket_status = sanitizeInput($row['ticket_status']);
+ $ticket_reply_contact = intval($row['ticket_contact_id']);
+ $ticket_contact_email = sanitizeInput($row['contact_email']);
+ $client_id = intval($row['ticket_client_id']);
+ $client_name = sanitizeInput($row['client_name']);
+
+ if ($ticket_status == 5) {
+ $config_ticket_prefix_esc = mysqli_real_escape_string($mysqli, $config_ticket_prefix);
+ $ticket_number_esc2 = mysqli_real_escape_string($mysqli, $ticket_number);
+
+ appNotify("Ticket", "Email parser: $from_email attempted to re-open ticket $config_ticket_prefix_esc$ticket_number_esc2 (ID $ticket_id) - check inbox manually to see email", "ticket.php?ticket_id=$ticket_id", $client_id);
+
+ $email_subject = "Action required: This ticket is already closed";
+ $email_body = "Hi there, You've tried to reply to a ticket that is closed - we won't see your response. Please raise a new ticket by sending a new e-mail to our support address below. -- $company_name - Support $config_ticket_from_email $company_phone";
+
+ $data = [
+ [
+ 'from' => $config_ticket_from_email,
+ 'from_name' => $config_ticket_from_name,
+ 'recipient' => $from_email,
+ 'recipient_name' => $from_email,
+ 'subject' => $email_subject,
+ 'body' => mysqli_real_escape_string($mysqli, $email_body)
+ ]
+ ];
+
+ addToMailQueue($data);
+ return true;
+ }
+
+ if (empty($ticket_contact_email) || $ticket_contact_email !== $from_email) {
+ $from_email_esc2 = mysqli_real_escape_string($mysqli, $from_email);
+ $row2 = mysqli_fetch_array(mysqli_query($mysqli, "SELECT contact_id FROM contacts WHERE contact_email = '$from_email_esc2' AND contact_client_id = $client_id LIMIT 1"));
+ if ($row2) {
+ $ticket_reply_contact = intval($row2['contact_id']);
+ } else {
+ $ticket_reply_type = 'Internal';
+ $ticket_reply_contact = '0';
+ $message = "WARNING: Contact email mismatch $message";
+ $message_esc = mysqli_real_escape_string($mysqli, $message);
+ }
+ }
+
+ mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$message_esc', ticket_reply_type = '$ticket_reply_type', ticket_reply_time_worked = '00:00:00', ticket_reply_by = $ticket_reply_contact, ticket_reply_ticket_id = $ticket_id");
+ $reply_id = mysqli_insert_id($mysqli);
+
+ $ticket_dir = "../uploads/tickets/" . $ticket_id . "/";
+ mkdirMissing($ticket_dir);
+
+ foreach ($attachments as $attachment) {
+ $att_name = $attachment['name'];
+ $att_extension = strtolower(pathinfo($att_name, PATHINFO_EXTENSION));
+
+ if (in_array($att_extension, $allowed_extensions)) {
+ $att_saved_filename = md5(uniqid(rand(), true)) . '.' . $att_extension;
+ $att_saved_path = $ticket_dir . $att_saved_filename;
+ file_put_contents($att_saved_path, $attachment['content']);
+
+ $ticket_attachment_name = sanitizeInput($att_name);
+ $ticket_attachment_reference_name = sanitizeInput($att_saved_filename);
+
+ $ticket_attachment_name_esc = mysqli_real_escape_string($mysqli, $ticket_attachment_name);
+ $ticket_attachment_reference_name_esc = mysqli_real_escape_string($mysqli, $ticket_attachment_reference_name);
+ mysqli_query($mysqli, "INSERT INTO ticket_attachments SET ticket_attachment_name = '$ticket_attachment_name_esc', ticket_attachment_reference_name = '$ticket_attachment_reference_name_esc', ticket_attachment_reply_id = $reply_id, ticket_attachment_ticket_id = $ticket_id");
+ } else {
+ $ticket_attachment_name_esc = mysqli_real_escape_string($mysqli, $att_name);
+ logAction("Ticket", "Edit", "Email parser: Blocked attachment $ticket_attachment_name_esc from Client contact $from_email_esc for ticket $config_ticket_prefix$ticket_number_esc", $client_id, $ticket_id);
+ }
+ }
+
+ $ticket_assigned_to_sql = mysqli_query($mysqli, "SELECT ticket_assigned_to FROM tickets WHERE ticket_id = $ticket_id LIMIT 1");
+ if ($ticket_assigned_to_sql) {
+ $row3 = mysqli_fetch_array($ticket_assigned_to_sql);
+ $ticket_assigned_to = intval($row3['ticket_assigned_to']);
+
+ if ($ticket_assigned_to) {
+ $tech_sql = mysqli_query($mysqli, "SELECT user_email, user_name FROM users WHERE user_id = $ticket_assigned_to LIMIT 1");
+ $tech_row = mysqli_fetch_array($tech_sql);
+ $tech_email = sanitizeInput($tech_row['user_email']);
+ $tech_name = sanitizeInput($tech_row['user_name']);
+
+ $email_subject = "$config_app_name - Ticket updated - [$config_ticket_prefix$ticket_number] $ticket_subject";
+ $email_body = "Hello $tech_name, A new reply has been added to the below ticket, check ITFlow for full details. Client: $client_name Ticket: $config_ticket_prefix$ticket_number Subject: $ticket_subject https://$config_base_url/ticket.php?ticket_id=$ticket_id";
+
+ $data = [
+ [
+ 'from' => $config_ticket_from_email,
+ 'from_name' => $config_ticket_from_name,
+ 'recipient' => $tech_email,
+ 'recipient_name' => $tech_name,
+ 'subject' => mysqli_real_escape_string($mysqli, $email_subject),
+ 'body' => mysqli_real_escape_string($mysqli, $email_body)
+ ]
+ ];
+ addToMailQueue($data);
+ }
+ }
+
+ mysqli_query($mysqli, "UPDATE tickets SET ticket_status = 2, ticket_resolved_at = NULL WHERE ticket_id = $ticket_id AND ticket_client_id = $client_id LIMIT 1");
+
+ logAction("Ticket", "Edit", "Email parser: Client contact $from_email_esc updated ticket $config_ticket_prefix$ticket_number_esc ($subject)", $client_id, $ticket_id);
+ customAction('ticket_reply_client', $ticket_id);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/** ------------------------------------------------------------------
+ * Webklex IMAP setup
+ * ------------------------------------------------------------------ */
+use Webklex\PHPIMAP\ClientManager;
+
+$validate_cert = true; // or false based on your configuration
+
+$cm = new ClientManager();
+
+$client = $cm->make([
+ 'host' => $config_imap_host,
+ 'port' => (int)$config_imap_port,
+ 'encryption' => !empty($config_imap_encryption) ? $config_imap_encryption : null, // 'ssl' | 'tls' | null
+ 'validate_cert' => (bool)$validate_cert,
+ 'username' => $config_imap_username,
+ 'password' => $config_imap_password,
+ 'protocol' => 'imap'
+]);
+
+try {
+ $client->connect();
+} catch (\Throwable $e) {
+ echo "Error connecting to IMAP server: " . $e->getMessage();
+ unlink($lock_file_path);
+ exit(1);
+}
+
+$inbox = $client->getFolderByPath('INBOX');
+
+$targetFolderPath = 'ITFlow';
+try {
+ $targetFolder = $client->getFolderByPath($targetFolderPath);
+} catch (\Throwable $e) {
+ $client->createFolder($targetFolderPath);
+ $targetFolder = $client->getFolderByPath($targetFolderPath);
+}
+
+// Fetch unseen messages
+$messages = $inbox->messages()->leaveUnread()->unseen()->get();
+
+// Counters
+$processed_count = 0;
+$unprocessed_count = 0;
+
+// Process messages
+foreach ($messages as $message) {
+ $email_processed = false;
+
+ // Save original RFC822 message as .eml
+ mkdirMissing('../uploads/tmp/');
+ $original_message_file = "processed-eml-" . randomString(200) . ".eml";
+
+ try {
+ // getRawMessage() available in v3; for v2 use getHeader()->raw or getStructure()? We'll try getRawMessage()
+ $raw_message = $message->getRawMessage();
+ } catch (\Throwable $e) {
+ // Fallback to rebuilding from headers + body if raw not available
+ $raw_message = (string)$message->getHeader()->raw . "\r\n\r\n" . ($message->getRawBody() ?? $message->getHTMLBody() ?? $message->getTextBody());
+ }
+ file_put_contents("../uploads/tmp/{$original_message_file}", $raw_message);
+
+ // From
+ $fromCol = $message->getFrom();
+ $fromFirst = ($fromCol && $fromCol->count()) ? $fromCol->first() : null;
+ $from_email = sanitizeInput($fromFirst->mail ?? 'itflow-guest@example.com');
+ $from_name = sanitizeInput($fromFirst->personal ?? 'Unknown');
+
+ $from_domain = explode("@", $from_email);
+ $from_domain = sanitizeInput(end($from_domain));
+
+ // Subject
+ $subject = sanitizeInput((string)$message->getSubject() ?: 'No Subject');
+
+ // Date (string)
+ $dateAttr = $message->getDate(); // Attribute
+ $dateRaw = $dateAttr ? (string)$dateAttr : ''; // e.g. "Tue, 10 Sep 2025 13:22:05 +0000"
+ $ts = $dateRaw ? strtotime($dateRaw) : false;
+ $date = sanitizeInput($ts !== false ? date('Y-m-d H:i:s', $ts) : date('Y-m-d H:i:s'));
+
+ // Body (prefer HTML)
+ $message_body_html = $message->getHTMLBody();
+ $message_body_text = $message->getTextBody();
+ $message_body = $message_body_html ?: nl2br(htmlspecialchars((string)$message_body_text));
+
+ // Handle attachments (inline vs regular)
+ $attachments = [];
+ foreach ($message->getAttachments() as $att) {
+ $attrs = $att->getAttributes(); // v6.2: canonical source
+ $dispo = strtolower((string)($attrs['disposition'] ?? ''));
+ $cid = $attrs['id'] ?? null; // Content-ID
+ $content = $attrs['content'] ?? null; // binary
+ $mime = $att->getMimeType();
+ $name = $att->getName() ?: 'attachment';
+
+ $is_inline = false;
+ if ($dispo === 'inline' && $cid && $content !== null) {
+ $cid_trim = trim($cid, '<>');
+ $dataUri = "data:$mime;base64,".base64_encode($content);
+ $message_body = str_replace(["cid:$cid_trim", "cid:$cid"], $dataUri, $message_body);
+ $is_inline = true;
+ }
+
+ if (!$is_inline && $content !== null) {
+ $attachments[] = ['name' => $name, 'content' => $content];
+ }
+ }
+
+ // Decide whether it's a reply to an existing ticket or a new ticket
+ if (preg_match("/\[$config_ticket_prefix(\d+)\]/", $subject, $ticket_number_matches)) {
+ $ticket_number = intval($ticket_number_matches[1]);
+ if (addReply($from_email, $date, $subject, $ticket_number, $message_body, $attachments)) {
+ $email_processed = true;
+ }
+ } else {
+ // Known contact?
+ $from_email_esc = mysqli_real_escape_string($mysqli, $from_email);
+ $any_contact_sql = mysqli_query($mysqli, "SELECT * FROM contacts WHERE contact_email = '$from_email_esc' LIMIT 1");
+ $rowc = mysqli_fetch_array($any_contact_sql);
+
+ if ($rowc) {
+ $contact_name = sanitizeInput($rowc['contact_name']);
+ $contact_id = intval($rowc['contact_id']);
+ $contact_email = sanitizeInput($rowc['contact_email']);
+ $client_id = intval($rowc['contact_client_id']);
+
+ if (addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message_body, $attachments, $original_message_file)) {
+ $email_processed = true;
+ }
+ } else {
+ // Known domain?
+ $from_domain_esc = mysqli_real_escape_string($mysqli, $from_domain);
+ $domain_sql = mysqli_query($mysqli, "SELECT * FROM domains WHERE domain_name = '$from_domain_esc' LIMIT 1");
+ $rowd = mysqli_fetch_assoc($domain_sql);
+
+ if ($rowd && $from_domain == $rowd['domain_name']) {
+ $client_id = intval($rowd['domain_client_id']);
+
+ // Create a new contact
+ $contact_name = $from_name;
+ $contact_email = $from_email;
+ mysqli_query($mysqli, "INSERT INTO contacts SET contact_name = '".mysqli_real_escape_string($mysqli, $contact_name)."', contact_email = '".mysqli_real_escape_string($mysqli, $contact_email)."', contact_notes = 'Added automatically via email parsing.', contact_client_id = $client_id");
+ $contact_id = mysqli_insert_id($mysqli);
+
+ // Logging
+ logAction("Contact", "Create", "Email parser: created contact " . mysqli_real_escape_string($mysqli, $contact_name) . "", $client_id, $contact_id);
+ customAction('contact_create', $contact_id);
+
+ if (addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message_body, $attachments, $original_message_file)) {
+ $email_processed = true;
+ }
+ } elseif ($config_ticket_email_parse_unknown_senders) {
+ // Unknown sender allowed?
+ $bad_from_pattern = "/daemon|postmaster/i";
+ if (!(preg_match($bad_from_pattern, $from_email))) {
+ if (addTicket(0, $from_name, $from_email, 0, $date, $subject, $message_body, $attachments, $original_message_file)) {
+ $email_processed = true;
+ }
+ }
+ }
+ }
+ }
+
+ // Flag/move based on processing result
+ if ($email_processed) {
+ $processed_count++; // increment first so a move failure doesn't hide the success
+ try {
+ $message->setFlag('Seen');
+ // Move using the Folder object (top-level "ITFlow")
+ $message->move($targetFolderPath);
+ // optional: logApp("Cron-Email-Parser", "info", "Moved message to ITFlow");
+ } catch (\Throwable $e) {
+ // >>> Put the extra logging RIGHT HERE
+ $subj = (string)$message->getSubject();
+ $uid = method_exists($message, 'getUid') ? $message->getUid() : 'n/a';
+ $path = property_exists($targetFolder, 'path') ? $targetFolder->path : 'ITFlow';
+ logApp(
+ "Cron-Email-Parser",
+ "warning",
+ "Move failed (subject=\"$subj\", uid=$uid) to [$path]: ".$e->getMessage()
+ );
+ }
+ } else {
+ $unprocessed_count++;
+ try {
+ $message->setFlag('Flagged');
+ $message->unsetFlag('Seen');
+ } catch (\Throwable $e) {
+ logApp("Cron-Email-Parser", "warning", "Flag update failed: ".$e->getMessage());
+ }
+ }
+
+ // Cleanup temp .eml if still present (e.g., reply path)
+ if (isset($original_message_file)) {
+ $tmp_path = "../uploads/tmp/{$original_message_file}";
+ if (file_exists($tmp_path)) { @unlink($tmp_path); }
+ }
+}
+
+// Expunge & disconnect
+try {
+ $client->expunge();
+} catch (\Throwable $e) {
+ // ignore
+}
+$client->disconnect();
+
+// Execution timing (optional)
+$script_end_time = microtime(true);
+$execution_time = $script_end_time - $script_start_time;
+$execution_time_formatted = number_format($execution_time, 2);
+
+$processed_info = "Processed: $processed_count email(s), Unprocessed: $unprocessed_count email(s)";
+// logAction("Cron-Email-Parser", "Execution", "Cron Email Parser executed in $execution_time_formatted seconds. $processed_info");
+
+// Remove the lock file
+unlink($lock_file_path);
+
+// DEBUG
+echo "\nLock File Path: $lock_file_path\n";
+if (file_exists($lock_file_path)) {
+ echo "\nLock is present\n\n";
+}
+echo "Processed Emails into tickets: $processed_count\n";
+echo "Unprocessed Emails: $unprocessed_count\n";
diff --git a/plugins/composer.json b/plugins/composer.json
new file mode 100644
index 00000000..8d56034c
--- /dev/null
+++ b/plugins/composer.json
@@ -0,0 +1,5 @@
+{
+ "require": {
+ "webklex/php-imap": "^6.2"
+ }
+}
diff --git a/plugins/composer.lock b/plugins/composer.lock
new file mode 100644
index 00000000..b4b5bb03
--- /dev/null
+++ b/plugins/composer.lock
@@ -0,0 +1,1645 @@
+{
+ "_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": "5cc550c87df98ff88db99d5cbe524f1c",
+ "packages": [
+ {
+ "name": "carbonphp/carbon-doctrine-types",
+ "version": "3.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git",
+ "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
+ "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.1"
+ },
+ "conflict": {
+ "doctrine/dbal": "<4.0.0 || >=5.0.0"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^4.0.0",
+ "nesbot/carbon": "^2.71.0 || ^3.0.0",
+ "phpunit/phpunit": "^10.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Carbon\\Doctrine\\": "src/Carbon/Doctrine/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "KyleKatarn",
+ "email": "kylekatarnls@gmail.com"
+ }
+ ],
+ "description": "Types to use Carbon in Doctrine",
+ "keywords": [
+ "carbon",
+ "date",
+ "datetime",
+ "doctrine",
+ "time"
+ ],
+ "support": {
+ "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues",
+ "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/kylekatarnls",
+ "type": "github"
+ },
+ {
+ "url": "https://opencollective.com/Carbon",
+ "type": "open_collective"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-02-09T16:56:22+00:00"
+ },
+ {
+ "name": "doctrine/inflector",
+ "version": "2.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/inflector.git",
+ "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b",
+ "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^12.0 || ^13.0",
+ "phpstan/phpstan": "^1.12 || ^2.0",
+ "phpstan/phpstan-phpunit": "^1.4 || ^2.0",
+ "phpstan/phpstan-strict-rules": "^1.6 || ^2.0",
+ "phpunit/phpunit": "^8.5 || ^12.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Inflector\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ }
+ ],
+ "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.",
+ "homepage": "https://www.doctrine-project.org/projects/inflector.html",
+ "keywords": [
+ "inflection",
+ "inflector",
+ "lowercase",
+ "manipulation",
+ "php",
+ "plural",
+ "singular",
+ "strings",
+ "uppercase",
+ "words"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/inflector/issues",
+ "source": "https://github.com/doctrine/inflector/tree/2.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-10T19:31:58+00:00"
+ },
+ {
+ "name": "illuminate/collections",
+ "version": "v12.28.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/collections.git",
+ "reference": "2737a0477a3f4855a71bf8f3d0b8d32596ded628"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/collections/zipball/2737a0477a3f4855a71bf8f3d0b8d32596ded628",
+ "reference": "2737a0477a3f4855a71bf8f3d0b8d32596ded628",
+ "shasum": ""
+ },
+ "require": {
+ "illuminate/conditionable": "^12.0",
+ "illuminate/contracts": "^12.0",
+ "illuminate/macroable": "^12.0",
+ "php": "^8.2",
+ "symfony/polyfill-php84": "^1.33",
+ "symfony/polyfill-php85": "^1.33"
+ },
+ "suggest": {
+ "illuminate/http": "Required to convert collections to API resources (^12.0).",
+ "symfony/var-dumper": "Required to use the dump method (^7.2)."
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "functions.php",
+ "helpers.php"
+ ],
+ "psr-4": {
+ "Illuminate\\Support\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Collections package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "time": "2025-09-02T15:31:06+00:00"
+ },
+ {
+ "name": "illuminate/conditionable",
+ "version": "v12.28.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/conditionable.git",
+ "reference": "ec677967c1f2faf90b8428919124d2184a4c9b49"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/conditionable/zipball/ec677967c1f2faf90b8428919124d2184a4c9b49",
+ "reference": "ec677967c1f2faf90b8428919124d2184a4c9b49",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Illuminate\\Support\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Conditionable package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "time": "2025-05-13T15:08:45+00:00"
+ },
+ {
+ "name": "illuminate/contracts",
+ "version": "v12.28.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/contracts.git",
+ "reference": "f1c4cf02c9ab81a9ce47940cf261fa2386ed6c5d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/contracts/zipball/f1c4cf02c9ab81a9ce47940cf261fa2386ed6c5d",
+ "reference": "f1c4cf02c9ab81a9ce47940cf261fa2386ed6c5d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.2",
+ "psr/container": "^1.1.1|^2.0.1",
+ "psr/simple-cache": "^1.0|^2.0|^3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Illuminate\\Contracts\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Contracts package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "time": "2025-08-27T18:34:41+00:00"
+ },
+ {
+ "name": "illuminate/macroable",
+ "version": "v12.28.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/macroable.git",
+ "reference": "e862e5648ee34004fa56046b746f490dfa86c613"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/macroable/zipball/e862e5648ee34004fa56046b746f490dfa86c613",
+ "reference": "e862e5648ee34004fa56046b746f490dfa86c613",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Illuminate\\Support\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Macroable package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "time": "2024-07-23T16:31:01+00:00"
+ },
+ {
+ "name": "illuminate/pagination",
+ "version": "v12.28.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/pagination.git",
+ "reference": "1d95e70671177108b202e6ceb61bc7bc9924bdbf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/pagination/zipball/1d95e70671177108b202e6ceb61bc7bc9924bdbf",
+ "reference": "1d95e70671177108b202e6ceb61bc7bc9924bdbf",
+ "shasum": ""
+ },
+ "require": {
+ "ext-filter": "*",
+ "illuminate/collections": "^12.0",
+ "illuminate/contracts": "^12.0",
+ "illuminate/support": "^12.0",
+ "php": "^8.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Illuminate\\Pagination\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Pagination package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "time": "2025-09-02T15:31:06+00:00"
+ },
+ {
+ "name": "illuminate/support",
+ "version": "v12.28.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/support.git",
+ "reference": "487bbe527806615b818e87c364d93ba91f27db9b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/support/zipball/487bbe527806615b818e87c364d93ba91f27db9b",
+ "reference": "487bbe527806615b818e87c364d93ba91f27db9b",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/inflector": "^2.0",
+ "ext-ctype": "*",
+ "ext-filter": "*",
+ "ext-mbstring": "*",
+ "illuminate/collections": "^12.0",
+ "illuminate/conditionable": "^12.0",
+ "illuminate/contracts": "^12.0",
+ "illuminate/macroable": "^12.0",
+ "nesbot/carbon": "^3.8.4",
+ "php": "^8.2",
+ "symfony/polyfill-php83": "^1.33",
+ "symfony/polyfill-php85": "^1.33",
+ "voku/portable-ascii": "^2.0.2"
+ },
+ "conflict": {
+ "tightenco/collect": "<5.5.33"
+ },
+ "replace": {
+ "spatie/once": "*"
+ },
+ "suggest": {
+ "illuminate/filesystem": "Required to use the Composer class (^12.0).",
+ "laravel/serializable-closure": "Required to use the once function (^1.3|^2.0).",
+ "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.7).",
+ "league/uri": "Required to use the Uri class (^7.5.1).",
+ "ramsey/uuid": "Required to use Str::uuid() (^4.7).",
+ "symfony/process": "Required to use the Composer class (^7.2).",
+ "symfony/uid": "Required to use Str::ulid() (^7.2).",
+ "symfony/var-dumper": "Required to use the dd function (^7.2).",
+ "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.6.1)."
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "functions.php",
+ "helpers.php"
+ ],
+ "psr-4": {
+ "Illuminate\\Support\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Support package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "time": "2025-09-03T16:23:04+00:00"
+ },
+ {
+ "name": "nesbot/carbon",
+ "version": "3.10.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/CarbonPHP/carbon.git",
+ "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
+ "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
+ "shasum": ""
+ },
+ "require": {
+ "carbonphp/carbon-doctrine-types": "<100.0",
+ "ext-json": "*",
+ "php": "^8.1",
+ "psr/clock": "^1.0",
+ "symfony/clock": "^6.3.12 || ^7.0",
+ "symfony/polyfill-mbstring": "^1.0",
+ "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0"
+ },
+ "provide": {
+ "psr/clock-implementation": "1.0"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^3.6.3 || ^4.0",
+ "doctrine/orm": "^2.15.2 || ^3.0",
+ "friendsofphp/php-cs-fixer": "^v3.87.1",
+ "kylekatarnls/multi-tester": "^2.5.3",
+ "phpmd/phpmd": "^2.15.0",
+ "phpstan/extension-installer": "^1.4.3",
+ "phpstan/phpstan": "^2.1.22",
+ "phpunit/phpunit": "^10.5.53",
+ "squizlabs/php_codesniffer": "^3.13.4"
+ },
+ "bin": [
+ "bin/carbon"
+ ],
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Carbon\\Laravel\\ServiceProvider"
+ ]
+ },
+ "phpstan": {
+ "includes": [
+ "extension.neon"
+ ]
+ },
+ "branch-alias": {
+ "dev-2.x": "2.x-dev",
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Carbon\\": "src/Carbon/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Brian Nesbitt",
+ "email": "brian@nesbot.com",
+ "homepage": "https://markido.com"
+ },
+ {
+ "name": "kylekatarnls",
+ "homepage": "https://github.com/kylekatarnls"
+ }
+ ],
+ "description": "An API extension for DateTime that supports 281 different languages.",
+ "homepage": "https://carbon.nesbot.com",
+ "keywords": [
+ "date",
+ "datetime",
+ "time"
+ ],
+ "support": {
+ "docs": "https://carbon.nesbot.com/docs",
+ "issues": "https://github.com/CarbonPHP/carbon/issues",
+ "source": "https://github.com/CarbonPHP/carbon"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/kylekatarnls",
+ "type": "github"
+ },
+ {
+ "url": "https://opencollective.com/Carbon#sponsor",
+ "type": "opencollective"
+ },
+ {
+ "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-06T13:39:36+00:00"
+ },
+ {
+ "name": "psr/clock",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/clock.git",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Clock\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for reading the clock.",
+ "homepage": "https://github.com/php-fig/clock",
+ "keywords": [
+ "clock",
+ "now",
+ "psr",
+ "psr-20",
+ "time"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/clock/issues",
+ "source": "https://github.com/php-fig/clock/tree/1.0.0"
+ },
+ "time": "2022-11-25T14:36:26+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": "psr/simple-cache",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/simple-cache.git",
+ "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865",
+ "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\SimpleCache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interfaces for simple caching",
+ "keywords": [
+ "cache",
+ "caching",
+ "psr",
+ "psr-16",
+ "simple-cache"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/simple-cache/tree/3.0.0"
+ },
+ "time": "2021-10-29T13:26:27+00:00"
+ },
+ {
+ "name": "symfony/clock",
+ "version": "v7.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/clock.git",
+ "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24",
+ "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/clock": "^1.0",
+ "symfony/polyfill-php83": "^1.28"
+ },
+ "provide": {
+ "psr/clock-implementation": "1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "Resources/now.php"
+ ],
+ "psr-4": {
+ "Symfony\\Component\\Clock\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Decouples applications from the system clock",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "clock",
+ "psr20",
+ "time"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/clock/tree/v7.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-25T14:21:43+00:00"
+ },
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-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.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-25T14:21:43+00:00"
+ },
+ {
+ "name": "symfony/http-foundation",
+ "version": "v7.3.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/http-foundation.git",
+ "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00",
+ "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3.0",
+ "symfony/polyfill-mbstring": "~1.1",
+ "symfony/polyfill-php83": "^1.27"
+ },
+ "conflict": {
+ "doctrine/dbal": "<3.6",
+ "symfony/cache": "<6.4.12|>=7.0,<7.1.5"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^3.6|^4",
+ "predis/predis": "^1.1|^2.0",
+ "symfony/cache": "^6.4.12|^7.1.5",
+ "symfony/clock": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/expression-language": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/mime": "^6.4|^7.0",
+ "symfony/rate-limiter": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\HttpFoundation\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Defines an object-oriented layer for the HTTP specification",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/http-foundation/tree/v7.3.3"
+ },
+ "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": "2025-08-20T08:04:18+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.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": "2024-12-23T08:48:59+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php83",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php83.git",
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5",
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php83\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.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": "2025-07-08T02:45:35+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php84",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php84.git",
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191",
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php84\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.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": "2025-06-24T13:30:11+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php85",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php85.git",
+ "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
+ "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php85\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.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": "2025-06-23T16:12:55+00:00"
+ },
+ {
+ "name": "symfony/translation",
+ "version": "v7.3.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/translation.git",
+ "reference": "e0837b4cbcef63c754d89a4806575cada743a38d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/e0837b4cbcef63c754d89a4806575cada743a38d",
+ "reference": "e0837b4cbcef63c754d89a4806575cada743a38d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/translation-contracts": "^2.5|^3.0"
+ },
+ "conflict": {
+ "nikic/php-parser": "<5.0",
+ "symfony/config": "<6.4",
+ "symfony/console": "<6.4",
+ "symfony/dependency-injection": "<6.4",
+ "symfony/http-client-contracts": "<2.5",
+ "symfony/http-kernel": "<6.4",
+ "symfony/service-contracts": "<2.5",
+ "symfony/twig-bundle": "<6.4",
+ "symfony/yaml": "<6.4"
+ },
+ "provide": {
+ "symfony/translation-implementation": "2.3|3.0"
+ },
+ "require-dev": {
+ "nikic/php-parser": "^5.0",
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^6.4|^7.0",
+ "symfony/console": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/finder": "^6.4|^7.0",
+ "symfony/http-client-contracts": "^2.5|^3.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/intl": "^6.4|^7.0",
+ "symfony/polyfill-intl-icu": "^1.21",
+ "symfony/routing": "^6.4|^7.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/yaml": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "Resources/functions.php"
+ ],
+ "psr-4": {
+ "Symfony\\Component\\Translation\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides tools to internationalize your application",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/translation/tree/v7.3.3"
+ },
+ "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": "2025-08-01T21:02:37+00:00"
+ },
+ {
+ "name": "symfony/translation-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/translation-contracts.git",
+ "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
+ "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Translation\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to translation",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-27T08:32:26+00:00"
+ },
+ {
+ "name": "voku/portable-ascii",
+ "version": "2.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/voku/portable-ascii.git",
+ "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
+ "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
+ },
+ "suggest": {
+ "ext-intl": "Use Intl for transliterator_transliterate() support"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "voku\\": "src/voku/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Lars Moelleken",
+ "homepage": "https://www.moelleken.org/"
+ }
+ ],
+ "description": "Portable ASCII library - performance optimized (ascii) string functions for php.",
+ "homepage": "https://github.com/voku/portable-ascii",
+ "keywords": [
+ "ascii",
+ "clean",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/voku/portable-ascii/issues",
+ "source": "https://github.com/voku/portable-ascii/tree/2.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/moelleken",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/voku",
+ "type": "github"
+ },
+ {
+ "url": "https://opencollective.com/portable-ascii",
+ "type": "open_collective"
+ },
+ {
+ "url": "https://www.patreon.com/voku",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-11-21T01:49:47+00:00"
+ },
+ {
+ "name": "webklex/php-imap",
+ "version": "6.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Webklex/php-imap.git",
+ "reference": "6b8ef85d621bbbaf52741b00cca8e9237e2b2e05"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Webklex/php-imap/zipball/6b8ef85d621bbbaf52741b00cca8e9237e2b2e05",
+ "reference": "6b8ef85d621bbbaf52741b00cca8e9237e2b2e05",
+ "shasum": ""
+ },
+ "require": {
+ "ext-fileinfo": "*",
+ "ext-iconv": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-openssl": "*",
+ "ext-zip": "*",
+ "illuminate/pagination": ">=5.0.0",
+ "nesbot/carbon": "^2.62.1|^3.2.4",
+ "php": "^8.0.2",
+ "symfony/http-foundation": ">=2.8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5.10"
+ },
+ "suggest": {
+ "symfony/mime": "Recomended for better extension support",
+ "symfony/var-dumper": "Usefull tool for debugging"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Webklex\\PHPIMAP\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Malte Goldenbaum",
+ "email": "github@webklex.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "PHP IMAP client",
+ "homepage": "https://github.com/webklex/php-imap",
+ "keywords": [
+ "imap",
+ "mail",
+ "php-imap",
+ "pop3",
+ "webklex"
+ ],
+ "support": {
+ "issues": "https://github.com/Webklex/php-imap/issues",
+ "source": "https://github.com/Webklex/php-imap/tree/6.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.buymeacoffee.com/webklex",
+ "type": "custom"
+ },
+ {
+ "url": "https://ko-fi.com/webklex",
+ "type": "ko_fi"
+ }
+ ],
+ "time": "2025-04-25T06:02:37+00:00"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": [],
+ "plugin-api-version": "2.2.0"
+}
diff --git a/plugins/vendor/autoload.php b/plugins/vendor/autoload.php
new file mode 100644
index 00000000..165b0733
--- /dev/null
+++ b/plugins/vendor/autoload.php
@@ -0,0 +1,7 @@
+realpath = realpath($opened_path) ?: $opened_path;
+ $opened_path = $this->realpath;
+ $this->handle = fopen($this->realpath, $mode);
+ $this->position = 0;
+
+ return (bool) $this->handle;
+ }
+
+ public function stream_read($count)
+ {
+ $data = fread($this->handle, $count);
+
+ if ($this->position === 0) {
+ $data = preg_replace('{^#!.*\r?\n}', '', $data);
+ }
+
+ $this->position += strlen($data);
+
+ return $data;
+ }
+
+ public function stream_cast($castAs)
+ {
+ return $this->handle;
+ }
+
+ public function stream_close()
+ {
+ fclose($this->handle);
+ }
+
+ public function stream_lock($operation)
+ {
+ return $operation ? flock($this->handle, $operation) : true;
+ }
+
+ public function stream_tell()
+ {
+ return $this->position;
+ }
+
+ public function stream_eof()
+ {
+ return feof($this->handle);
+ }
+
+ public function stream_stat()
+ {
+ return array();
+ }
+
+ public function stream_set_option($option, $arg1, $arg2)
+ {
+ return true;
+ }
+
+ public function url_stat($path, $flags)
+ {
+ $path = substr($path, 17);
+ if (file_exists($path)) {
+ return stat($path);
+ }
+
+ return false;
+ }
+ }
+ }
+
+ if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) {
+ include("phpvfscomposer://" . __DIR__ . '/..'.'/nesbot/carbon/bin/carbon');
+ exit(0);
+ }
+}
+
+include __DIR__ . '/..'.'/nesbot/carbon/bin/carbon';
diff --git a/plugins/vendor/carbonphp/carbon-doctrine-types/LICENSE b/plugins/vendor/carbonphp/carbon-doctrine-types/LICENSE
new file mode 100644
index 00000000..2ee1671d
--- /dev/null
+++ b/plugins/vendor/carbonphp/carbon-doctrine-types/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Carbon
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/plugins/vendor/carbonphp/carbon-doctrine-types/README.md b/plugins/vendor/carbonphp/carbon-doctrine-types/README.md
new file mode 100644
index 00000000..5a18121b
--- /dev/null
+++ b/plugins/vendor/carbonphp/carbon-doctrine-types/README.md
@@ -0,0 +1,14 @@
+# carbonphp/carbon-doctrine-types
+
+Types to use Carbon in Doctrine
+
+## Documentation
+
+[Check how to use in the official Carbon documentation](https://carbon.nesbot.com/symfony/)
+
+This package is an externalization of [src/Carbon/Doctrine](https://github.com/briannesbitt/Carbon/tree/2.71.0/src/Carbon/Doctrine)
+from `nestbot/carbon` package.
+
+Externalization allows to better deal with different versions of dbal. With
+version 4.0 of dbal, it no longer sustainable to be compatible with all version
+using a single code.
diff --git a/plugins/vendor/carbonphp/carbon-doctrine-types/composer.json b/plugins/vendor/carbonphp/carbon-doctrine-types/composer.json
new file mode 100644
index 00000000..abf45c5f
--- /dev/null
+++ b/plugins/vendor/carbonphp/carbon-doctrine-types/composer.json
@@ -0,0 +1,36 @@
+{
+ "name": "carbonphp/carbon-doctrine-types",
+ "description": "Types to use Carbon in Doctrine",
+ "type": "library",
+ "keywords": [
+ "date",
+ "time",
+ "DateTime",
+ "Carbon",
+ "Doctrine"
+ ],
+ "require": {
+ "php": "^8.1"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^4.0.0",
+ "nesbot/carbon": "^2.71.0 || ^3.0.0",
+ "phpunit/phpunit": "^10.3"
+ },
+ "conflict": {
+ "doctrine/dbal": "<4.0.0 || >=5.0.0"
+ },
+ "license": "MIT",
+ "autoload": {
+ "psr-4": {
+ "Carbon\\Doctrine\\": "src/Carbon/Doctrine/"
+ }
+ },
+ "authors": [
+ {
+ "name": "KyleKatarn",
+ "email": "kylekatarnls@gmail.com"
+ }
+ ],
+ "minimum-stability": "dev"
+}
diff --git a/plugins/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonDoctrineType.php b/plugins/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonDoctrineType.php
new file mode 100644
index 00000000..a63a9b8d
--- /dev/null
+++ b/plugins/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonDoctrineType.php
@@ -0,0 +1,16 @@
+
+ */
+ protected function getCarbonClassName(): string
+ {
+ return Carbon::class;
+ }
+
+ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string
+ {
+ $precision = min(
+ $fieldDeclaration['precision'] ?? DateTimeDefaultPrecision::get(),
+ $this->getMaximumPrecision($platform),
+ );
+
+ $type = parent::getSQLDeclaration($fieldDeclaration, $platform);
+
+ if (!$precision) {
+ return $type;
+ }
+
+ if (str_contains($type, '(')) {
+ return preg_replace('/\(\d+\)/', "($precision)", $type);
+ }
+
+ [$before, $after] = explode(' ', "$type ");
+
+ return trim("$before($precision) $after");
+ }
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
+ {
+ if ($value === null) {
+ return $value;
+ }
+
+ if ($value instanceof DateTimeInterface) {
+ return $value->format('Y-m-d H:i:s.u');
+ }
+
+ throw InvalidType::new(
+ $value,
+ static::class,
+ ['null', 'DateTime', 'Carbon']
+ );
+ }
+
+ private function doConvertToPHPValue(mixed $value)
+ {
+ $class = $this->getCarbonClassName();
+
+ if ($value === null || is_a($value, $class)) {
+ return $value;
+ }
+
+ if ($value instanceof DateTimeInterface) {
+ return $class::instance($value);
+ }
+
+ $date = null;
+ $error = null;
+
+ try {
+ $date = $class::parse($value);
+ } catch (Exception $exception) {
+ $error = $exception;
+ }
+
+ if (!$date) {
+ throw ValueNotConvertible::new(
+ $value,
+ static::class,
+ 'Y-m-d H:i:s.u or any format supported by '.$class.'::parse()',
+ $error
+ );
+ }
+
+ return $date;
+ }
+
+ private function getMaximumPrecision(AbstractPlatform $platform): int
+ {
+ if ($platform instanceof DB2Platform) {
+ return 12;
+ }
+
+ if ($platform instanceof OraclePlatform) {
+ return 9;
+ }
+
+ if ($platform instanceof SQLServerPlatform || $platform instanceof SQLitePlatform) {
+ return 3;
+ }
+
+ return 6;
+ }
+}
diff --git a/plugins/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeDefaultPrecision.php b/plugins/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeDefaultPrecision.php
new file mode 100644
index 00000000..cd9896f9
--- /dev/null
+++ b/plugins/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeDefaultPrecision.php
@@ -0,0 +1,30 @@
+ */
+ use CarbonTypeConverter;
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?CarbonImmutable
+ {
+ return $this->doConvertToPHPValue($value);
+ }
+
+ /**
+ * @return class-string
+ */
+ protected function getCarbonClassName(): string
+ {
+ return CarbonImmutable::class;
+ }
+}
diff --git a/plugins/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeType.php b/plugins/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeType.php
new file mode 100644
index 00000000..89e4b790
--- /dev/null
+++ b/plugins/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeType.php
@@ -0,0 +1,24 @@
+ */
+ use CarbonTypeConverter;
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?Carbon
+ {
+ return $this->doConvertToPHPValue($value);
+ }
+}
diff --git a/plugins/vendor/composer/ClassLoader.php b/plugins/vendor/composer/ClassLoader.php
new file mode 100644
index 00000000..afef3fa2
--- /dev/null
+++ b/plugins/vendor/composer/ClassLoader.php
@@ -0,0 +1,572 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
+ *
+ * $loader = new \Composer\Autoload\ClassLoader();
+ *
+ * // register classes with namespaces
+ * $loader->add('Symfony\Component', __DIR__.'/component');
+ * $loader->add('Symfony', __DIR__.'/framework');
+ *
+ * // activate the autoloader
+ * $loader->register();
+ *
+ * // to enable searching the include path (eg. for PEAR packages)
+ * $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier
+ * @author Jordi Boggiano
+ * @see https://www.php-fig.org/psr/psr-0/
+ * @see https://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+ /** @var ?string */
+ private $vendorDir;
+
+ // PSR-4
+ /**
+ * @var array[]
+ * @psalm-var array>
+ */
+ private $prefixLengthsPsr4 = array();
+ /**
+ * @var array[]
+ * @psalm-var array>
+ */
+ private $prefixDirsPsr4 = array();
+ /**
+ * @var array[]
+ * @psalm-var array
+ */
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ /**
+ * @var array[]
+ * @psalm-var array>
+ */
+ private $prefixesPsr0 = array();
+ /**
+ * @var array[]
+ * @psalm-var array
+ */
+ private $fallbackDirsPsr0 = array();
+
+ /** @var bool */
+ private $useIncludePath = false;
+
+ /**
+ * @var string[]
+ * @psalm-var array
+ */
+ private $classMap = array();
+
+ /** @var bool */
+ private $classMapAuthoritative = false;
+
+ /**
+ * @var bool[]
+ * @psalm-var array
+ */
+ private $missingClasses = array();
+
+ /** @var ?string */
+ private $apcuPrefix;
+
+ /**
+ * @var self[]
+ */
+ private static $registeredLoaders = array();
+
+ /**
+ * @param ?string $vendorDir
+ */
+ public function __construct($vendorDir = null)
+ {
+ $this->vendorDir = $vendorDir;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
+ }
+
+ return array();
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return array>
+ */
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return array
+ */
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return array
+ */
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ /**
+ * @return string[] Array of classname => path
+ * @psalm-return array
+ */
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param string[] $classMap Class to filename map
+ * @psalm-param array $classMap
+ *
+ * @return void
+ */
+ public function addClassMap(array $classMap)
+ {
+ if ($this->classMap) {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ } else {
+ $this->classMap = $classMap;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix, either
+ * appending or prepending to the ones previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param string[]|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @return void
+ */
+ public function add($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ if ($prepend) {
+ $this->fallbackDirsPsr0 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ (array) $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace, either
+ * appending or prepending to the ones previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param string[]|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ (array) $paths
+ );
+ }
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+ // Register directories for a new namespace.
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix,
+ * replacing any others previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param string[]|string $paths The PSR-0 base directories
+ *
+ * @return void
+ */
+ public function set($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr0 = (array) $paths;
+ } else {
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace,
+ * replacing any others previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param string[]|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ public function setPsr4($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr4 = (array) $paths;
+ } else {
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Turns on searching the include path for class files.
+ *
+ * @param bool $useIncludePath
+ *
+ * @return void
+ */
+ public function setUseIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return bool
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Turns off searching the prefix and fallback directories for classes
+ * that have not been registered with the class map.
+ *
+ * @param bool $classMapAuthoritative
+ *
+ * @return void
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = $classMapAuthoritative;
+ }
+
+ /**
+ * Should class lookup fail if not found in the current class map?
+ *
+ * @return bool
+ */
+ public function isClassMapAuthoritative()
+ {
+ return $this->classMapAuthoritative;
+ }
+
+ /**
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
+ *
+ * @param string|null $apcuPrefix
+ *
+ * @return void
+ */
+ public function setApcuPrefix($apcuPrefix)
+ {
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
+ }
+
+ /**
+ * The APCu prefix in use, or null if APCu caching is not enabled.
+ *
+ * @return string|null
+ */
+ public function getApcuPrefix()
+ {
+ return $this->apcuPrefix;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ *
+ * @return void
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+
+ if (null === $this->vendorDir) {
+ return;
+ }
+
+ if ($prepend) {
+ self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
+ } else {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ self::$registeredLoaders[$this->vendorDir] = $this;
+ }
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ *
+ * @return void
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+
+ if (null !== $this->vendorDir) {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ }
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return true|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ includeFile($file);
+
+ return true;
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|false The path if found, false otherwise
+ */
+ public function findFile($class)
+ {
+ // class map lookup
+ if (isset($this->classMap[$class])) {
+ return $this->classMap[$class];
+ }
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
+ return false;
+ }
+ if (null !== $this->apcuPrefix) {
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
+ if ($hit) {
+ return $file;
+ }
+ }
+
+ $file = $this->findFileWithExtension($class, '.php');
+
+ // Search for Hack files if we are running on HHVM
+ if (false === $file && defined('HHVM_VERSION')) {
+ $file = $this->findFileWithExtension($class, '.hh');
+ }
+
+ if (null !== $this->apcuPrefix) {
+ apcu_add($this->apcuPrefix.$class, $file);
+ }
+
+ if (false === $file) {
+ // Remember that this class does not exist.
+ $this->missingClasses[$class] = true;
+ }
+
+ return $file;
+ }
+
+ /**
+ * Returns the currently registered loaders indexed by their corresponding vendor directories.
+ *
+ * @return self[]
+ */
+ public static function getRegisteredLoaders()
+ {
+ return self::$registeredLoaders;
+ }
+
+ /**
+ * @param string $class
+ * @param string $ext
+ * @return string|false
+ */
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ $subPath = $class;
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
+ $subPath = substr($subPath, 0, $lastPos);
+ $search = $subPath . '\\';
+ if (isset($this->prefixDirsPsr4[$search])) {
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
+ if (file_exists($file = $dir . $pathEnd)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+
+ return false;
+ }
+}
+
+/**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ *
+ * @param string $file
+ * @return void
+ * @private
+ */
+function includeFile($file)
+{
+ include $file;
+}
diff --git a/plugins/vendor/composer/InstalledVersions.php b/plugins/vendor/composer/InstalledVersions.php
new file mode 100644
index 00000000..d50e0c9f
--- /dev/null
+++ b/plugins/vendor/composer/InstalledVersions.php
@@ -0,0 +1,350 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer;
+
+use Composer\Autoload\ClassLoader;
+use Composer\Semver\VersionParser;
+
+/**
+ * This class is copied in every Composer installed project and available to all
+ *
+ * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
+ *
+ * To require its presence, you can require `composer-runtime-api ^2.0`
+ */
+class InstalledVersions
+{
+ /**
+ * @var mixed[]|null
+ * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}|array{}|null
+ */
+ private static $installed;
+
+ /**
+ * @var bool|null
+ */
+ private static $canGetVendors;
+
+ /**
+ * @var array[]
+ * @psalm-var array}>
+ */
+ private static $installedByVendor = array();
+
+ /**
+ * Returns a list of all package names which are present, either by being installed, replaced or provided
+ *
+ * @return string[]
+ * @psalm-return list
+ */
+ public static function getInstalledPackages()
+ {
+ $packages = array();
+ foreach (self::getInstalled() as $installed) {
+ $packages[] = array_keys($installed['versions']);
+ }
+
+ if (1 === \count($packages)) {
+ return $packages[0];
+ }
+
+ return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
+ }
+
+ /**
+ * Returns a list of all package names with a specific type e.g. 'library'
+ *
+ * @param string $type
+ * @return string[]
+ * @psalm-return list
+ */
+ public static function getInstalledPackagesByType($type)
+ {
+ $packagesByType = array();
+
+ foreach (self::getInstalled() as $installed) {
+ foreach ($installed['versions'] as $name => $package) {
+ if (isset($package['type']) && $package['type'] === $type) {
+ $packagesByType[] = $name;
+ }
+ }
+ }
+
+ return $packagesByType;
+ }
+
+ /**
+ * Checks whether the given package is installed
+ *
+ * This also returns true if the package name is provided or replaced by another package
+ *
+ * @param string $packageName
+ * @param bool $includeDevRequirements
+ * @return bool
+ */
+ public static function isInstalled($packageName, $includeDevRequirements = true)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (isset($installed['versions'][$packageName])) {
+ return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether the given package satisfies a version constraint
+ *
+ * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
+ *
+ * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
+ *
+ * @param VersionParser $parser Install composer/semver to have access to this class and functionality
+ * @param string $packageName
+ * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
+ * @return bool
+ */
+ public static function satisfies(VersionParser $parser, $packageName, $constraint)
+ {
+ $constraint = $parser->parseConstraints($constraint);
+ $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
+
+ return $provided->matches($constraint);
+ }
+
+ /**
+ * Returns a version constraint representing all the range(s) which are installed for a given package
+ *
+ * It is easier to use this via isInstalled() with the $constraint argument if you need to check
+ * whether a given version of a package is installed, and not just whether it exists
+ *
+ * @param string $packageName
+ * @return string Version constraint usable with composer/semver
+ */
+ public static function getVersionRanges($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ $ranges = array();
+ if (isset($installed['versions'][$packageName]['pretty_version'])) {
+ $ranges[] = $installed['versions'][$packageName]['pretty_version'];
+ }
+ if (array_key_exists('aliases', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
+ }
+ if (array_key_exists('replaced', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
+ }
+ if (array_key_exists('provided', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
+ }
+
+ return implode(' || ', $ranges);
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getPrettyVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['pretty_version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['pretty_version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
+ */
+ public static function getReference($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['reference'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['reference'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
+ */
+ public static function getInstallPath($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @return array
+ * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
+ */
+ public static function getRootPackage()
+ {
+ $installed = self::getInstalled();
+
+ return $installed[0]['root'];
+ }
+
+ /**
+ * Returns the raw installed.php data for custom implementations
+ *
+ * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
+ * @return array[]
+ * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}
+ */
+ public static function getRawData()
+ {
+ @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C') {
+ self::$installed = include __DIR__ . '/installed.php';
+ } else {
+ self::$installed = array();
+ }
+ }
+
+ return self::$installed;
+ }
+
+ /**
+ * Returns the raw data of all installed.php which are currently loaded for custom implementations
+ *
+ * @return array[]
+ * @psalm-return list}>
+ */
+ public static function getAllRawData()
+ {
+ return self::getInstalled();
+ }
+
+ /**
+ * Lets you reload the static array from another file
+ *
+ * This is only useful for complex integrations in which a project needs to use
+ * this class but then also needs to execute another project's autoloader in process,
+ * and wants to ensure both projects have access to their version of installed.php.
+ *
+ * A typical case would be PHPUnit, where it would need to make sure it reads all
+ * the data it needs from this class, then call reload() with
+ * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
+ * the project in which it runs can then also use this class safely, without
+ * interference between PHPUnit's dependencies and the project's dependencies.
+ *
+ * @param array[] $data A vendor/composer/installed.php data set
+ * @return void
+ *
+ * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} $data
+ */
+ public static function reload($data)
+ {
+ self::$installed = $data;
+ self::$installedByVendor = array();
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return list}>
+ */
+ private static function getInstalled()
+ {
+ if (null === self::$canGetVendors) {
+ self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
+ }
+
+ $installed = array();
+
+ if (self::$canGetVendors) {
+ foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+ if (isset(self::$installedByVendor[$vendorDir])) {
+ $installed[] = self::$installedByVendor[$vendorDir];
+ } elseif (is_file($vendorDir.'/composer/installed.php')) {
+ $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
+ if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
+ self::$installed = $installed[count($installed) - 1];
+ }
+ }
+ }
+ }
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C') {
+ self::$installed = require __DIR__ . '/installed.php';
+ } else {
+ self::$installed = array();
+ }
+ }
+ $installed[] = self::$installed;
+
+ return $installed;
+ }
+}
diff --git a/plugins/vendor/composer/LICENSE b/plugins/vendor/composer/LICENSE
new file mode 100644
index 00000000..f27399a0
--- /dev/null
+++ b/plugins/vendor/composer/LICENSE
@@ -0,0 +1,21 @@
+
+Copyright (c) Nils Adermann, Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/plugins/vendor/composer/autoload_classmap.php b/plugins/vendor/composer/autoload_classmap.php
new file mode 100644
index 00000000..5dc1606d
--- /dev/null
+++ b/plugins/vendor/composer/autoload_classmap.php
@@ -0,0 +1,24 @@
+ $vendorDir . '/composer/InstalledVersions.php',
+ 'DateError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
+ 'DateException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
+ 'DateInvalidOperationException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateInvalidOperationException.php',
+ 'DateInvalidTimeZoneException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateInvalidTimeZoneException.php',
+ 'DateMalformedIntervalStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedIntervalStringException.php',
+ 'DateMalformedPeriodStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedPeriodStringException.php',
+ 'DateMalformedStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',
+ 'DateObjectError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',
+ 'DateRangeError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',
+ 'Deprecated' => $vendorDir . '/symfony/polyfill-php84/Resources/stubs/Deprecated.php',
+ 'NoDiscard' => $vendorDir . '/symfony/polyfill-php85/Resources/stubs/NoDiscard.php',
+ 'Override' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/Override.php',
+ 'ReflectionConstant' => $vendorDir . '/symfony/polyfill-php84/Resources/stubs/ReflectionConstant.php',
+ 'SQLite3Exception' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',
+);
diff --git a/plugins/vendor/composer/autoload_files.php b/plugins/vendor/composer/autoload_files.php
new file mode 100644
index 00000000..a7d2f8fe
--- /dev/null
+++ b/plugins/vendor/composer/autoload_files.php
@@ -0,0 +1,20 @@
+ $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
+ '662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php',
+ '606a39d89246991a373564698c2d8383' => $vendorDir . '/symfony/polyfill-php85/bootstrap.php',
+ '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
+ '2203a247e6fda86070a5e4e07aed533a' => $vendorDir . '/symfony/clock/Resources/now.php',
+ 'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
+ '9d2b9fc6db0f153a0a149fefb182415e' => $vendorDir . '/symfony/polyfill-php84/bootstrap.php',
+ '23f09fe3194f8c2f70923f90d6702129' => $vendorDir . '/illuminate/collections/functions.php',
+ '60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php',
+ 'f625ee536139dfb962a398b200bdb2bd' => $vendorDir . '/illuminate/support/functions.php',
+ '72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php',
+);
diff --git a/plugins/vendor/composer/autoload_namespaces.php b/plugins/vendor/composer/autoload_namespaces.php
new file mode 100644
index 00000000..b7fc0125
--- /dev/null
+++ b/plugins/vendor/composer/autoload_namespaces.php
@@ -0,0 +1,9 @@
+ array($vendorDir . '/voku/portable-ascii/src/voku'),
+ 'Webklex\\PHPIMAP\\' => array($vendorDir . '/webklex/php-imap/src'),
+ 'Symfony\\Polyfill\\Php85\\' => array($vendorDir . '/symfony/polyfill-php85'),
+ 'Symfony\\Polyfill\\Php84\\' => array($vendorDir . '/symfony/polyfill-php84'),
+ 'Symfony\\Polyfill\\Php83\\' => array($vendorDir . '/symfony/polyfill-php83'),
+ 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
+ 'Symfony\\Contracts\\Translation\\' => array($vendorDir . '/symfony/translation-contracts'),
+ 'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
+ 'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'),
+ 'Symfony\\Component\\Clock\\' => array($vendorDir . '/symfony/clock'),
+ 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
+ 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
+ 'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'),
+ 'Illuminate\\Support\\' => array($vendorDir . '/illuminate/macroable', $vendorDir . '/illuminate/conditionable', $vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/support'),
+ 'Illuminate\\Pagination\\' => array($vendorDir . '/illuminate/pagination'),
+ 'Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'),
+ 'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/src'),
+ 'Carbon\\Doctrine\\' => array($vendorDir . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine'),
+ 'Carbon\\' => array($vendorDir . '/nesbot/carbon/src/Carbon'),
+);
diff --git a/plugins/vendor/composer/autoload_real.php b/plugins/vendor/composer/autoload_real.php
new file mode 100644
index 00000000..d60da886
--- /dev/null
+++ b/plugins/vendor/composer/autoload_real.php
@@ -0,0 +1,80 @@
+= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
+ if ($useStaticLoader) {
+ require __DIR__ . '/autoload_static.php';
+
+ call_user_func(\Composer\Autoload\ComposerStaticInit9b9826e5b5cc7806cd328c4112cca75e::getInitializer($loader));
+ } else {
+ $map = require __DIR__ . '/autoload_namespaces.php';
+ foreach ($map as $namespace => $path) {
+ $loader->set($namespace, $path);
+ }
+
+ $map = require __DIR__ . '/autoload_psr4.php';
+ foreach ($map as $namespace => $path) {
+ $loader->setPsr4($namespace, $path);
+ }
+
+ $classMap = require __DIR__ . '/autoload_classmap.php';
+ if ($classMap) {
+ $loader->addClassMap($classMap);
+ }
+ }
+
+ $loader->register(true);
+
+ if ($useStaticLoader) {
+ $includeFiles = Composer\Autoload\ComposerStaticInit9b9826e5b5cc7806cd328c4112cca75e::$files;
+ } else {
+ $includeFiles = require __DIR__ . '/autoload_files.php';
+ }
+ foreach ($includeFiles as $fileIdentifier => $file) {
+ composerRequire9b9826e5b5cc7806cd328c4112cca75e($fileIdentifier, $file);
+ }
+
+ return $loader;
+ }
+}
+
+/**
+ * @param string $fileIdentifier
+ * @param string $file
+ * @return void
+ */
+function composerRequire9b9826e5b5cc7806cd328c4112cca75e($fileIdentifier, $file)
+{
+ if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
+ $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
+
+ require $file;
+ }
+}
diff --git a/plugins/vendor/composer/autoload_static.php b/plugins/vendor/composer/autoload_static.php
new file mode 100644
index 00000000..00e27ea8
--- /dev/null
+++ b/plugins/vendor/composer/autoload_static.php
@@ -0,0 +1,175 @@
+ __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
+ '662a729f963d39afe703c9d9b7ab4a8c' => __DIR__ . '/..' . '/symfony/polyfill-php83/bootstrap.php',
+ '606a39d89246991a373564698c2d8383' => __DIR__ . '/..' . '/symfony/polyfill-php85/bootstrap.php',
+ '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
+ '2203a247e6fda86070a5e4e07aed533a' => __DIR__ . '/..' . '/symfony/clock/Resources/now.php',
+ 'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
+ '9d2b9fc6db0f153a0a149fefb182415e' => __DIR__ . '/..' . '/symfony/polyfill-php84/bootstrap.php',
+ '23f09fe3194f8c2f70923f90d6702129' => __DIR__ . '/..' . '/illuminate/collections/functions.php',
+ '60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php',
+ 'f625ee536139dfb962a398b200bdb2bd' => __DIR__ . '/..' . '/illuminate/support/functions.php',
+ '72579e7bd17821bb1321b87411366eae' => __DIR__ . '/..' . '/illuminate/support/helpers.php',
+ );
+
+ public static $prefixLengthsPsr4 = array (
+ 'v' =>
+ array (
+ 'voku\\' => 5,
+ ),
+ 'W' =>
+ array (
+ 'Webklex\\PHPIMAP\\' => 16,
+ ),
+ 'S' =>
+ array (
+ 'Symfony\\Polyfill\\Php85\\' => 23,
+ 'Symfony\\Polyfill\\Php84\\' => 23,
+ 'Symfony\\Polyfill\\Php83\\' => 23,
+ 'Symfony\\Polyfill\\Mbstring\\' => 26,
+ 'Symfony\\Contracts\\Translation\\' => 30,
+ 'Symfony\\Component\\Translation\\' => 30,
+ 'Symfony\\Component\\HttpFoundation\\' => 33,
+ 'Symfony\\Component\\Clock\\' => 24,
+ ),
+ 'P' =>
+ array (
+ 'Psr\\SimpleCache\\' => 16,
+ 'Psr\\Container\\' => 14,
+ 'Psr\\Clock\\' => 10,
+ ),
+ 'I' =>
+ array (
+ 'Illuminate\\Support\\' => 19,
+ 'Illuminate\\Pagination\\' => 22,
+ 'Illuminate\\Contracts\\' => 21,
+ ),
+ 'D' =>
+ array (
+ 'Doctrine\\Inflector\\' => 19,
+ ),
+ 'C' =>
+ array (
+ 'Carbon\\Doctrine\\' => 16,
+ 'Carbon\\' => 7,
+ ),
+ );
+
+ public static $prefixDirsPsr4 = array (
+ 'voku\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/voku/portable-ascii/src/voku',
+ ),
+ 'Webklex\\PHPIMAP\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/webklex/php-imap/src',
+ ),
+ 'Symfony\\Polyfill\\Php85\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/polyfill-php85',
+ ),
+ 'Symfony\\Polyfill\\Php84\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/polyfill-php84',
+ ),
+ 'Symfony\\Polyfill\\Php83\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/polyfill-php83',
+ ),
+ 'Symfony\\Polyfill\\Mbstring\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
+ ),
+ 'Symfony\\Contracts\\Translation\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/translation-contracts',
+ ),
+ 'Symfony\\Component\\Translation\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/translation',
+ ),
+ 'Symfony\\Component\\HttpFoundation\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/http-foundation',
+ ),
+ 'Symfony\\Component\\Clock\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/clock',
+ ),
+ 'Psr\\SimpleCache\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/psr/simple-cache/src',
+ ),
+ 'Psr\\Container\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/psr/container/src',
+ ),
+ 'Psr\\Clock\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/psr/clock/src',
+ ),
+ 'Illuminate\\Support\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/illuminate/macroable',
+ 1 => __DIR__ . '/..' . '/illuminate/conditionable',
+ 2 => __DIR__ . '/..' . '/illuminate/collections',
+ 3 => __DIR__ . '/..' . '/illuminate/support',
+ ),
+ 'Illuminate\\Pagination\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/illuminate/pagination',
+ ),
+ 'Illuminate\\Contracts\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/illuminate/contracts',
+ ),
+ 'Doctrine\\Inflector\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/doctrine/inflector/src',
+ ),
+ 'Carbon\\Doctrine\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine',
+ ),
+ 'Carbon\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon',
+ ),
+ );
+
+ public static $classMap = array (
+ 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
+ 'DateError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
+ 'DateException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
+ 'DateInvalidOperationException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateInvalidOperationException.php',
+ 'DateInvalidTimeZoneException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateInvalidTimeZoneException.php',
+ 'DateMalformedIntervalStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedIntervalStringException.php',
+ 'DateMalformedPeriodStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedPeriodStringException.php',
+ 'DateMalformedStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',
+ 'DateObjectError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',
+ 'DateRangeError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',
+ 'Deprecated' => __DIR__ . '/..' . '/symfony/polyfill-php84/Resources/stubs/Deprecated.php',
+ 'NoDiscard' => __DIR__ . '/..' . '/symfony/polyfill-php85/Resources/stubs/NoDiscard.php',
+ 'Override' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/Override.php',
+ 'ReflectionConstant' => __DIR__ . '/..' . '/symfony/polyfill-php84/Resources/stubs/ReflectionConstant.php',
+ 'SQLite3Exception' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',
+ );
+
+ public static function getInitializer(ClassLoader $loader)
+ {
+ return \Closure::bind(function () use ($loader) {
+ $loader->prefixLengthsPsr4 = ComposerStaticInit9b9826e5b5cc7806cd328c4112cca75e::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInit9b9826e5b5cc7806cd328c4112cca75e::$prefixDirsPsr4;
+ $loader->classMap = ComposerStaticInit9b9826e5b5cc7806cd328c4112cca75e::$classMap;
+
+ }, null, ClassLoader::class);
+ }
+}
diff --git a/plugins/vendor/composer/installed.json b/plugins/vendor/composer/installed.json
new file mode 100644
index 00000000..a4d12430
--- /dev/null
+++ b/plugins/vendor/composer/installed.json
@@ -0,0 +1,1701 @@
+{
+ "packages": [
+ {
+ "name": "carbonphp/carbon-doctrine-types",
+ "version": "3.2.0",
+ "version_normalized": "3.2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git",
+ "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
+ "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.1"
+ },
+ "conflict": {
+ "doctrine/dbal": "<4.0.0 || >=5.0.0"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^4.0.0",
+ "nesbot/carbon": "^2.71.0 || ^3.0.0",
+ "phpunit/phpunit": "^10.3"
+ },
+ "time": "2024-02-09T16:56:22+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Carbon\\Doctrine\\": "src/Carbon/Doctrine/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "KyleKatarn",
+ "email": "kylekatarnls@gmail.com"
+ }
+ ],
+ "description": "Types to use Carbon in Doctrine",
+ "keywords": [
+ "carbon",
+ "date",
+ "datetime",
+ "doctrine",
+ "time"
+ ],
+ "support": {
+ "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues",
+ "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/kylekatarnls",
+ "type": "github"
+ },
+ {
+ "url": "https://opencollective.com/Carbon",
+ "type": "open_collective"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../carbonphp/carbon-doctrine-types"
+ },
+ {
+ "name": "doctrine/inflector",
+ "version": "2.1.0",
+ "version_normalized": "2.1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/inflector.git",
+ "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b",
+ "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^12.0 || ^13.0",
+ "phpstan/phpstan": "^1.12 || ^2.0",
+ "phpstan/phpstan-phpunit": "^1.4 || ^2.0",
+ "phpstan/phpstan-strict-rules": "^1.6 || ^2.0",
+ "phpunit/phpunit": "^8.5 || ^12.2"
+ },
+ "time": "2025-08-10T19:31:58+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Inflector\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ }
+ ],
+ "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.",
+ "homepage": "https://www.doctrine-project.org/projects/inflector.html",
+ "keywords": [
+ "inflection",
+ "inflector",
+ "lowercase",
+ "manipulation",
+ "php",
+ "plural",
+ "singular",
+ "strings",
+ "uppercase",
+ "words"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/inflector/issues",
+ "source": "https://github.com/doctrine/inflector/tree/2.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../doctrine/inflector"
+ },
+ {
+ "name": "illuminate/collections",
+ "version": "v12.28.1",
+ "version_normalized": "12.28.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/collections.git",
+ "reference": "2737a0477a3f4855a71bf8f3d0b8d32596ded628"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/collections/zipball/2737a0477a3f4855a71bf8f3d0b8d32596ded628",
+ "reference": "2737a0477a3f4855a71bf8f3d0b8d32596ded628",
+ "shasum": ""
+ },
+ "require": {
+ "illuminate/conditionable": "^12.0",
+ "illuminate/contracts": "^12.0",
+ "illuminate/macroable": "^12.0",
+ "php": "^8.2",
+ "symfony/polyfill-php84": "^1.33",
+ "symfony/polyfill-php85": "^1.33"
+ },
+ "suggest": {
+ "illuminate/http": "Required to convert collections to API resources (^12.0).",
+ "symfony/var-dumper": "Required to use the dump method (^7.2)."
+ },
+ "time": "2025-09-02T15:31:06+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "functions.php",
+ "helpers.php"
+ ],
+ "psr-4": {
+ "Illuminate\\Support\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Collections package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "install-path": "../illuminate/collections"
+ },
+ {
+ "name": "illuminate/conditionable",
+ "version": "v12.28.1",
+ "version_normalized": "12.28.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/conditionable.git",
+ "reference": "ec677967c1f2faf90b8428919124d2184a4c9b49"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/conditionable/zipball/ec677967c1f2faf90b8428919124d2184a4c9b49",
+ "reference": "ec677967c1f2faf90b8428919124d2184a4c9b49",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.2"
+ },
+ "time": "2025-05-13T15:08:45+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Illuminate\\Support\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Conditionable package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "install-path": "../illuminate/conditionable"
+ },
+ {
+ "name": "illuminate/contracts",
+ "version": "v12.28.1",
+ "version_normalized": "12.28.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/contracts.git",
+ "reference": "f1c4cf02c9ab81a9ce47940cf261fa2386ed6c5d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/contracts/zipball/f1c4cf02c9ab81a9ce47940cf261fa2386ed6c5d",
+ "reference": "f1c4cf02c9ab81a9ce47940cf261fa2386ed6c5d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.2",
+ "psr/container": "^1.1.1|^2.0.1",
+ "psr/simple-cache": "^1.0|^2.0|^3.0"
+ },
+ "time": "2025-08-27T18:34:41+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Illuminate\\Contracts\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Contracts package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "install-path": "../illuminate/contracts"
+ },
+ {
+ "name": "illuminate/macroable",
+ "version": "v12.28.1",
+ "version_normalized": "12.28.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/macroable.git",
+ "reference": "e862e5648ee34004fa56046b746f490dfa86c613"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/macroable/zipball/e862e5648ee34004fa56046b746f490dfa86c613",
+ "reference": "e862e5648ee34004fa56046b746f490dfa86c613",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.2"
+ },
+ "time": "2024-07-23T16:31:01+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Illuminate\\Support\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Macroable package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "install-path": "../illuminate/macroable"
+ },
+ {
+ "name": "illuminate/pagination",
+ "version": "v12.28.1",
+ "version_normalized": "12.28.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/pagination.git",
+ "reference": "1d95e70671177108b202e6ceb61bc7bc9924bdbf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/pagination/zipball/1d95e70671177108b202e6ceb61bc7bc9924bdbf",
+ "reference": "1d95e70671177108b202e6ceb61bc7bc9924bdbf",
+ "shasum": ""
+ },
+ "require": {
+ "ext-filter": "*",
+ "illuminate/collections": "^12.0",
+ "illuminate/contracts": "^12.0",
+ "illuminate/support": "^12.0",
+ "php": "^8.2"
+ },
+ "time": "2025-09-02T15:31:06+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Illuminate\\Pagination\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Pagination package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "install-path": "../illuminate/pagination"
+ },
+ {
+ "name": "illuminate/support",
+ "version": "v12.28.1",
+ "version_normalized": "12.28.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/support.git",
+ "reference": "487bbe527806615b818e87c364d93ba91f27db9b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/support/zipball/487bbe527806615b818e87c364d93ba91f27db9b",
+ "reference": "487bbe527806615b818e87c364d93ba91f27db9b",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/inflector": "^2.0",
+ "ext-ctype": "*",
+ "ext-filter": "*",
+ "ext-mbstring": "*",
+ "illuminate/collections": "^12.0",
+ "illuminate/conditionable": "^12.0",
+ "illuminate/contracts": "^12.0",
+ "illuminate/macroable": "^12.0",
+ "nesbot/carbon": "^3.8.4",
+ "php": "^8.2",
+ "symfony/polyfill-php83": "^1.33",
+ "symfony/polyfill-php85": "^1.33",
+ "voku/portable-ascii": "^2.0.2"
+ },
+ "conflict": {
+ "tightenco/collect": "<5.5.33"
+ },
+ "replace": {
+ "spatie/once": "*"
+ },
+ "suggest": {
+ "illuminate/filesystem": "Required to use the Composer class (^12.0).",
+ "laravel/serializable-closure": "Required to use the once function (^1.3|^2.0).",
+ "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.7).",
+ "league/uri": "Required to use the Uri class (^7.5.1).",
+ "ramsey/uuid": "Required to use Str::uuid() (^4.7).",
+ "symfony/process": "Required to use the Composer class (^7.2).",
+ "symfony/uid": "Required to use Str::ulid() (^7.2).",
+ "symfony/var-dumper": "Required to use the dd function (^7.2).",
+ "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.6.1)."
+ },
+ "time": "2025-09-03T16:23:04+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "functions.php",
+ "helpers.php"
+ ],
+ "psr-4": {
+ "Illuminate\\Support\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Support package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "install-path": "../illuminate/support"
+ },
+ {
+ "name": "nesbot/carbon",
+ "version": "3.10.3",
+ "version_normalized": "3.10.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/CarbonPHP/carbon.git",
+ "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
+ "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
+ "shasum": ""
+ },
+ "require": {
+ "carbonphp/carbon-doctrine-types": "<100.0",
+ "ext-json": "*",
+ "php": "^8.1",
+ "psr/clock": "^1.0",
+ "symfony/clock": "^6.3.12 || ^7.0",
+ "symfony/polyfill-mbstring": "^1.0",
+ "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0"
+ },
+ "provide": {
+ "psr/clock-implementation": "1.0"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^3.6.3 || ^4.0",
+ "doctrine/orm": "^2.15.2 || ^3.0",
+ "friendsofphp/php-cs-fixer": "^v3.87.1",
+ "kylekatarnls/multi-tester": "^2.5.3",
+ "phpmd/phpmd": "^2.15.0",
+ "phpstan/extension-installer": "^1.4.3",
+ "phpstan/phpstan": "^2.1.22",
+ "phpunit/phpunit": "^10.5.53",
+ "squizlabs/php_codesniffer": "^3.13.4"
+ },
+ "time": "2025-09-06T13:39:36+00:00",
+ "bin": [
+ "bin/carbon"
+ ],
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Carbon\\Laravel\\ServiceProvider"
+ ]
+ },
+ "phpstan": {
+ "includes": [
+ "extension.neon"
+ ]
+ },
+ "branch-alias": {
+ "dev-2.x": "2.x-dev",
+ "dev-master": "3.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Carbon\\": "src/Carbon/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Brian Nesbitt",
+ "email": "brian@nesbot.com",
+ "homepage": "https://markido.com"
+ },
+ {
+ "name": "kylekatarnls",
+ "homepage": "https://github.com/kylekatarnls"
+ }
+ ],
+ "description": "An API extension for DateTime that supports 281 different languages.",
+ "homepage": "https://carbon.nesbot.com",
+ "keywords": [
+ "date",
+ "datetime",
+ "time"
+ ],
+ "support": {
+ "docs": "https://carbon.nesbot.com/docs",
+ "issues": "https://github.com/CarbonPHP/carbon/issues",
+ "source": "https://github.com/CarbonPHP/carbon"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/kylekatarnls",
+ "type": "github"
+ },
+ {
+ "url": "https://opencollective.com/Carbon#sponsor",
+ "type": "opencollective"
+ },
+ {
+ "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../nesbot/carbon"
+ },
+ {
+ "name": "psr/clock",
+ "version": "1.0.0",
+ "version_normalized": "1.0.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/clock.git",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0"
+ },
+ "time": "2022-11-25T14:36:26+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Clock\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for reading the clock.",
+ "homepage": "https://github.com/php-fig/clock",
+ "keywords": [
+ "clock",
+ "now",
+ "psr",
+ "psr-20",
+ "time"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/clock/issues",
+ "source": "https://github.com/php-fig/clock/tree/1.0.0"
+ },
+ "install-path": "../psr/clock"
+ },
+ {
+ "name": "psr/container",
+ "version": "2.0.2",
+ "version_normalized": "2.0.2.0",
+ "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"
+ },
+ "time": "2021-11-05T16:47:00+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "install-path": "../psr/container"
+ },
+ {
+ "name": "psr/simple-cache",
+ "version": "3.0.0",
+ "version_normalized": "3.0.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/simple-cache.git",
+ "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865",
+ "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "time": "2021-10-29T13:26:27+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Psr\\SimpleCache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interfaces for simple caching",
+ "keywords": [
+ "cache",
+ "caching",
+ "psr",
+ "psr-16",
+ "simple-cache"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/simple-cache/tree/3.0.0"
+ },
+ "install-path": "../psr/simple-cache"
+ },
+ {
+ "name": "symfony/clock",
+ "version": "v7.3.0",
+ "version_normalized": "7.3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/clock.git",
+ "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24",
+ "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/clock": "^1.0",
+ "symfony/polyfill-php83": "^1.28"
+ },
+ "provide": {
+ "psr/clock-implementation": "1.0"
+ },
+ "time": "2024-09-25T14:21:43+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "Resources/now.php"
+ ],
+ "psr-4": {
+ "Symfony\\Component\\Clock\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Decouples applications from the system clock",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "clock",
+ "psr20",
+ "time"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/clock/tree/v7.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../symfony/clock"
+ },
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v3.6.0",
+ "version_normalized": "3.6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "time": "2024-09-25T14:21:43+00:00",
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../symfony/deprecation-contracts"
+ },
+ {
+ "name": "symfony/http-foundation",
+ "version": "v7.3.3",
+ "version_normalized": "7.3.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/http-foundation.git",
+ "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00",
+ "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3.0",
+ "symfony/polyfill-mbstring": "~1.1",
+ "symfony/polyfill-php83": "^1.27"
+ },
+ "conflict": {
+ "doctrine/dbal": "<3.6",
+ "symfony/cache": "<6.4.12|>=7.0,<7.1.5"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^3.6|^4",
+ "predis/predis": "^1.1|^2.0",
+ "symfony/cache": "^6.4.12|^7.1.5",
+ "symfony/clock": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/expression-language": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/mime": "^6.4|^7.0",
+ "symfony/rate-limiter": "^6.4|^7.0"
+ },
+ "time": "2025-08-20T08:04:18+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\HttpFoundation\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Defines an object-oriented layer for the HTTP specification",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/http-foundation/tree/v7.3.3"
+ },
+ "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"
+ }
+ ],
+ "install-path": "../symfony/http-foundation"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.33.0",
+ "version_normalized": "1.33.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "time": "2024-12-23T08:48:59+00:00",
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.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"
+ }
+ ],
+ "install-path": "../symfony/polyfill-mbstring"
+ },
+ {
+ "name": "symfony/polyfill-php83",
+ "version": "v1.33.0",
+ "version_normalized": "1.33.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php83.git",
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5",
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "time": "2025-07-08T02:45:35+00:00",
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php83\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.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"
+ }
+ ],
+ "install-path": "../symfony/polyfill-php83"
+ },
+ {
+ "name": "symfony/polyfill-php84",
+ "version": "v1.33.0",
+ "version_normalized": "1.33.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php84.git",
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191",
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "time": "2025-06-24T13:30:11+00:00",
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php84\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.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"
+ }
+ ],
+ "install-path": "../symfony/polyfill-php84"
+ },
+ {
+ "name": "symfony/polyfill-php85",
+ "version": "v1.33.0",
+ "version_normalized": "1.33.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php85.git",
+ "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
+ "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "time": "2025-06-23T16:12:55+00:00",
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php85\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.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"
+ }
+ ],
+ "install-path": "../symfony/polyfill-php85"
+ },
+ {
+ "name": "symfony/translation",
+ "version": "v7.3.3",
+ "version_normalized": "7.3.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/translation.git",
+ "reference": "e0837b4cbcef63c754d89a4806575cada743a38d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/e0837b4cbcef63c754d89a4806575cada743a38d",
+ "reference": "e0837b4cbcef63c754d89a4806575cada743a38d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/translation-contracts": "^2.5|^3.0"
+ },
+ "conflict": {
+ "nikic/php-parser": "<5.0",
+ "symfony/config": "<6.4",
+ "symfony/console": "<6.4",
+ "symfony/dependency-injection": "<6.4",
+ "symfony/http-client-contracts": "<2.5",
+ "symfony/http-kernel": "<6.4",
+ "symfony/service-contracts": "<2.5",
+ "symfony/twig-bundle": "<6.4",
+ "symfony/yaml": "<6.4"
+ },
+ "provide": {
+ "symfony/translation-implementation": "2.3|3.0"
+ },
+ "require-dev": {
+ "nikic/php-parser": "^5.0",
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^6.4|^7.0",
+ "symfony/console": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/finder": "^6.4|^7.0",
+ "symfony/http-client-contracts": "^2.5|^3.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/intl": "^6.4|^7.0",
+ "symfony/polyfill-intl-icu": "^1.21",
+ "symfony/routing": "^6.4|^7.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/yaml": "^6.4|^7.0"
+ },
+ "time": "2025-08-01T21:02:37+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "Resources/functions.php"
+ ],
+ "psr-4": {
+ "Symfony\\Component\\Translation\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides tools to internationalize your application",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/translation/tree/v7.3.3"
+ },
+ "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"
+ }
+ ],
+ "install-path": "../symfony/translation"
+ },
+ {
+ "name": "symfony/translation-contracts",
+ "version": "v3.6.0",
+ "version_normalized": "3.6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/translation-contracts.git",
+ "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
+ "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "time": "2024-09-27T08:32:26+00:00",
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Translation\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to translation",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../symfony/translation-contracts"
+ },
+ {
+ "name": "voku/portable-ascii",
+ "version": "2.0.3",
+ "version_normalized": "2.0.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/voku/portable-ascii.git",
+ "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
+ "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
+ },
+ "suggest": {
+ "ext-intl": "Use Intl for transliterator_transliterate() support"
+ },
+ "time": "2024-11-21T01:49:47+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "voku\\": "src/voku/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Lars Moelleken",
+ "homepage": "https://www.moelleken.org/"
+ }
+ ],
+ "description": "Portable ASCII library - performance optimized (ascii) string functions for php.",
+ "homepage": "https://github.com/voku/portable-ascii",
+ "keywords": [
+ "ascii",
+ "clean",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/voku/portable-ascii/issues",
+ "source": "https://github.com/voku/portable-ascii/tree/2.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/moelleken",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/voku",
+ "type": "github"
+ },
+ {
+ "url": "https://opencollective.com/portable-ascii",
+ "type": "open_collective"
+ },
+ {
+ "url": "https://www.patreon.com/voku",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../voku/portable-ascii"
+ },
+ {
+ "name": "webklex/php-imap",
+ "version": "6.2.0",
+ "version_normalized": "6.2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Webklex/php-imap.git",
+ "reference": "6b8ef85d621bbbaf52741b00cca8e9237e2b2e05"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Webklex/php-imap/zipball/6b8ef85d621bbbaf52741b00cca8e9237e2b2e05",
+ "reference": "6b8ef85d621bbbaf52741b00cca8e9237e2b2e05",
+ "shasum": ""
+ },
+ "require": {
+ "ext-fileinfo": "*",
+ "ext-iconv": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-openssl": "*",
+ "ext-zip": "*",
+ "illuminate/pagination": ">=5.0.0",
+ "nesbot/carbon": "^2.62.1|^3.2.4",
+ "php": "^8.0.2",
+ "symfony/http-foundation": ">=2.8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5.10"
+ },
+ "suggest": {
+ "symfony/mime": "Recomended for better extension support",
+ "symfony/var-dumper": "Usefull tool for debugging"
+ },
+ "time": "2025-04-25T06:02:37+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.0-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Webklex\\PHPIMAP\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Malte Goldenbaum",
+ "email": "github@webklex.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "PHP IMAP client",
+ "homepage": "https://github.com/webklex/php-imap",
+ "keywords": [
+ "imap",
+ "mail",
+ "php-imap",
+ "pop3",
+ "webklex"
+ ],
+ "support": {
+ "issues": "https://github.com/Webklex/php-imap/issues",
+ "source": "https://github.com/Webklex/php-imap/tree/6.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.buymeacoffee.com/webklex",
+ "type": "custom"
+ },
+ {
+ "url": "https://ko-fi.com/webklex",
+ "type": "ko_fi"
+ }
+ ],
+ "install-path": "../webklex/php-imap"
+ }
+ ],
+ "dev": true,
+ "dev-package-names": []
+}
diff --git a/plugins/vendor/composer/installed.php b/plugins/vendor/composer/installed.php
new file mode 100644
index 00000000..b75cacc2
--- /dev/null
+++ b/plugins/vendor/composer/installed.php
@@ -0,0 +1,248 @@
+ array(
+ 'pretty_version' => 'dev-develop',
+ 'version' => 'dev-develop',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../../',
+ 'aliases' => array(),
+ 'reference' => '981fb9585d0c76e8b9c31812d58dfdd5b56d6454',
+ 'name' => '__root__',
+ 'dev' => true,
+ ),
+ 'versions' => array(
+ '__root__' => array(
+ 'pretty_version' => 'dev-develop',
+ 'version' => 'dev-develop',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../../',
+ 'aliases' => array(),
+ 'reference' => '981fb9585d0c76e8b9c31812d58dfdd5b56d6454',
+ 'dev_requirement' => false,
+ ),
+ 'carbonphp/carbon-doctrine-types' => array(
+ 'pretty_version' => '3.2.0',
+ 'version' => '3.2.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../carbonphp/carbon-doctrine-types',
+ 'aliases' => array(),
+ 'reference' => '18ba5ddfec8976260ead6e866180bd5d2f71aa1d',
+ 'dev_requirement' => false,
+ ),
+ 'doctrine/inflector' => array(
+ 'pretty_version' => '2.1.0',
+ 'version' => '2.1.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../doctrine/inflector',
+ 'aliases' => array(),
+ 'reference' => '6d6c96277ea252fc1304627204c3d5e6e15faa3b',
+ 'dev_requirement' => false,
+ ),
+ 'illuminate/collections' => array(
+ 'pretty_version' => 'v12.28.1',
+ 'version' => '12.28.1.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../illuminate/collections',
+ 'aliases' => array(),
+ 'reference' => '2737a0477a3f4855a71bf8f3d0b8d32596ded628',
+ 'dev_requirement' => false,
+ ),
+ 'illuminate/conditionable' => array(
+ 'pretty_version' => 'v12.28.1',
+ 'version' => '12.28.1.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../illuminate/conditionable',
+ 'aliases' => array(),
+ 'reference' => 'ec677967c1f2faf90b8428919124d2184a4c9b49',
+ 'dev_requirement' => false,
+ ),
+ 'illuminate/contracts' => array(
+ 'pretty_version' => 'v12.28.1',
+ 'version' => '12.28.1.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../illuminate/contracts',
+ 'aliases' => array(),
+ 'reference' => 'f1c4cf02c9ab81a9ce47940cf261fa2386ed6c5d',
+ 'dev_requirement' => false,
+ ),
+ 'illuminate/macroable' => array(
+ 'pretty_version' => 'v12.28.1',
+ 'version' => '12.28.1.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../illuminate/macroable',
+ 'aliases' => array(),
+ 'reference' => 'e862e5648ee34004fa56046b746f490dfa86c613',
+ 'dev_requirement' => false,
+ ),
+ 'illuminate/pagination' => array(
+ 'pretty_version' => 'v12.28.1',
+ 'version' => '12.28.1.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../illuminate/pagination',
+ 'aliases' => array(),
+ 'reference' => '1d95e70671177108b202e6ceb61bc7bc9924bdbf',
+ 'dev_requirement' => false,
+ ),
+ 'illuminate/support' => array(
+ 'pretty_version' => 'v12.28.1',
+ 'version' => '12.28.1.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../illuminate/support',
+ 'aliases' => array(),
+ 'reference' => '487bbe527806615b818e87c364d93ba91f27db9b',
+ 'dev_requirement' => false,
+ ),
+ 'nesbot/carbon' => array(
+ 'pretty_version' => '3.10.3',
+ 'version' => '3.10.3.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../nesbot/carbon',
+ 'aliases' => array(),
+ 'reference' => '8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f',
+ 'dev_requirement' => false,
+ ),
+ 'psr/clock' => array(
+ 'pretty_version' => '1.0.0',
+ 'version' => '1.0.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../psr/clock',
+ 'aliases' => array(),
+ 'reference' => 'e41a24703d4560fd0acb709162f73b8adfc3aa0d',
+ 'dev_requirement' => false,
+ ),
+ 'psr/clock-implementation' => array(
+ 'dev_requirement' => false,
+ 'provided' => array(
+ 0 => '1.0',
+ ),
+ ),
+ 'psr/container' => array(
+ 'pretty_version' => '2.0.2',
+ 'version' => '2.0.2.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../psr/container',
+ 'aliases' => array(),
+ 'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963',
+ 'dev_requirement' => false,
+ ),
+ 'psr/simple-cache' => array(
+ 'pretty_version' => '3.0.0',
+ 'version' => '3.0.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../psr/simple-cache',
+ 'aliases' => array(),
+ 'reference' => '764e0b3939f5ca87cb904f570ef9be2d78a07865',
+ 'dev_requirement' => false,
+ ),
+ 'spatie/once' => array(
+ 'dev_requirement' => false,
+ 'replaced' => array(
+ 0 => '*',
+ ),
+ ),
+ 'symfony/clock' => array(
+ 'pretty_version' => 'v7.3.0',
+ 'version' => '7.3.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/clock',
+ 'aliases' => array(),
+ 'reference' => 'b81435fbd6648ea425d1ee96a2d8e68f4ceacd24',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/deprecation-contracts' => array(
+ 'pretty_version' => 'v3.6.0',
+ 'version' => '3.6.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
+ 'aliases' => array(),
+ 'reference' => '63afe740e99a13ba87ec199bb07bbdee937a5b62',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/http-foundation' => array(
+ 'pretty_version' => 'v7.3.3',
+ 'version' => '7.3.3.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/http-foundation',
+ 'aliases' => array(),
+ 'reference' => '7475561ec27020196c49bb7c4f178d33d7d3dc00',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/polyfill-mbstring' => array(
+ 'pretty_version' => 'v1.33.0',
+ 'version' => '1.33.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
+ 'aliases' => array(),
+ 'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/polyfill-php83' => array(
+ 'pretty_version' => 'v1.33.0',
+ 'version' => '1.33.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/polyfill-php83',
+ 'aliases' => array(),
+ 'reference' => '17f6f9a6b1735c0f163024d959f700cfbc5155e5',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/polyfill-php84' => array(
+ 'pretty_version' => 'v1.33.0',
+ 'version' => '1.33.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/polyfill-php84',
+ 'aliases' => array(),
+ 'reference' => 'd8ced4d875142b6a7426000426b8abc631d6b191',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/polyfill-php85' => array(
+ 'pretty_version' => 'v1.33.0',
+ 'version' => '1.33.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/polyfill-php85',
+ 'aliases' => array(),
+ 'reference' => 'd4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/translation' => array(
+ 'pretty_version' => 'v7.3.3',
+ 'version' => '7.3.3.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/translation',
+ 'aliases' => array(),
+ 'reference' => 'e0837b4cbcef63c754d89a4806575cada743a38d',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/translation-contracts' => array(
+ 'pretty_version' => 'v3.6.0',
+ 'version' => '3.6.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/translation-contracts',
+ 'aliases' => array(),
+ 'reference' => 'df210c7a2573f1913b2d17cc95f90f53a73d8f7d',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/translation-implementation' => array(
+ 'dev_requirement' => false,
+ 'provided' => array(
+ 0 => '2.3|3.0',
+ ),
+ ),
+ 'voku/portable-ascii' => array(
+ 'pretty_version' => '2.0.3',
+ 'version' => '2.0.3.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../voku/portable-ascii',
+ 'aliases' => array(),
+ 'reference' => 'b1d923f88091c6bf09699efcd7c8a1b1bfd7351d',
+ 'dev_requirement' => false,
+ ),
+ 'webklex/php-imap' => array(
+ 'pretty_version' => '6.2.0',
+ 'version' => '6.2.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../webklex/php-imap',
+ 'aliases' => array(),
+ 'reference' => '6b8ef85d621bbbaf52741b00cca8e9237e2b2e05',
+ 'dev_requirement' => false,
+ ),
+ ),
+);
diff --git a/plugins/vendor/composer/platform_check.php b/plugins/vendor/composer/platform_check.php
new file mode 100644
index 00000000..d32d90c6
--- /dev/null
+++ b/plugins/vendor/composer/platform_check.php
@@ -0,0 +1,26 @@
+= 80200)) {
+ $issues[] = 'Your Composer dependencies require a PHP version ">= 8.2.0". You are running ' . PHP_VERSION . '.';
+}
+
+if ($issues) {
+ if (!headers_sent()) {
+ header('HTTP/1.1 500 Internal Server Error');
+ }
+ if (!ini_get('display_errors')) {
+ if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+ fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
+ } elseif (!headers_sent()) {
+ echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
+ }
+ }
+ trigger_error(
+ 'Composer detected issues in your platform: ' . implode(' ', $issues),
+ E_USER_ERROR
+ );
+}
diff --git a/plugins/vendor/doctrine/inflector/LICENSE b/plugins/vendor/doctrine/inflector/LICENSE
new file mode 100644
index 00000000..8c38cc1b
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2006-2015 Doctrine Project
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/plugins/vendor/doctrine/inflector/README.md b/plugins/vendor/doctrine/inflector/README.md
new file mode 100644
index 00000000..6e3a97f7
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/README.md
@@ -0,0 +1,7 @@
+# Doctrine Inflector
+
+Doctrine Inflector is a small library that can perform string manipulations
+with regard to uppercase/lowercase and singular/plural forms of words.
+
+[](https://github.com/doctrine/inflector/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.0.x)
+[](https://codecov.io/gh/doctrine/inflector/branch/2.0.x)
diff --git a/plugins/vendor/doctrine/inflector/composer.json b/plugins/vendor/doctrine/inflector/composer.json
new file mode 100644
index 00000000..6102926f
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/composer.json
@@ -0,0 +1,67 @@
+{
+ "name": "doctrine/inflector",
+ "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.",
+ "license": "MIT",
+ "type": "library",
+ "keywords": [
+ "php",
+ "strings",
+ "words",
+ "manipulation",
+ "inflector",
+ "inflection",
+ "uppercase",
+ "lowercase",
+ "singular",
+ "plural"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ }
+ ],
+ "homepage": "https://www.doctrine-project.org/projects/inflector.html",
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^12.0 || ^13.0",
+ "phpstan/phpstan": "^1.12 || ^2.0",
+ "phpstan/phpstan-phpunit": "^1.4 || ^2.0",
+ "phpstan/phpstan-strict-rules": "^1.6 || ^2.0",
+ "phpunit/phpunit": "^8.5 || ^12.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Inflector\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Doctrine\\Tests\\Inflector\\": "tests"
+ }
+ },
+ "config": {
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true
+ },
+ "sort-packages": true
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/docs/en/index.rst b/plugins/vendor/doctrine/inflector/docs/en/index.rst
new file mode 100644
index 00000000..1e094c8e
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/docs/en/index.rst
@@ -0,0 +1,227 @@
+Introduction
+============
+
+The Doctrine Inflector has methods for inflecting text. The features include pluralization,
+singularization, converting between camelCase and under_score and capitalizing
+words.
+
+Installation
+============
+
+You can install the Inflector with composer:
+
+.. code-block:: console
+
+ $ composer require doctrine/inflector
+
+Usage
+=====
+
+Using the inflector is easy, you can create a new ``Doctrine\Inflector\Inflector`` instance by using
+the ``Doctrine\Inflector\InflectorFactory`` class:
+
+.. code-block:: php
+
+ use Doctrine\Inflector\InflectorFactory;
+
+ $inflector = InflectorFactory::create()->build();
+
+By default it will create an English inflector. If you want to use another language, just pass the language
+you want to create an inflector for to the ``createForLanguage()`` method:
+
+.. code-block:: php
+
+ use Doctrine\Inflector\InflectorFactory;
+ use Doctrine\Inflector\Language;
+
+ $inflector = InflectorFactory::createForLanguage(Language::SPANISH)->build();
+
+The supported languages are as follows:
+
+- ``Language::ENGLISH``
+- ``Language::ESPERANTO``
+- ``Language::FRENCH``
+- ``Language::NORWEGIAN_BOKMAL``
+- ``Language::PORTUGUESE``
+- ``Language::SPANISH``
+- ``Language::TURKISH``
+
+If you want to manually construct the inflector instead of using a factory, you can do so like this:
+
+.. code-block:: php
+
+ use Doctrine\Inflector\CachedWordInflector;
+ use Doctrine\Inflector\RulesetInflector;
+ use Doctrine\Inflector\Rules\English;
+
+ $inflector = new Inflector(
+ new CachedWordInflector(new RulesetInflector(
+ English\Rules::getSingularRuleset()
+ )),
+ new CachedWordInflector(new RulesetInflector(
+ English\Rules::getPluralRuleset()
+ ))
+ );
+
+Adding Languages
+----------------
+
+If you are interested in adding support for your language, take a look at the other languages defined in the
+``Doctrine\Inflector\Rules`` namespace and the tests located in ``Doctrine\Tests\Inflector\Rules``. You can copy
+one of the languages and update the rules for your language.
+
+Once you have done this, send a pull request to the ``doctrine/inflector`` repository with the additions.
+
+Custom Setup
+============
+
+If you want to setup custom singular and plural rules, you can configure these in the factory:
+
+.. code-block:: php
+
+ use Doctrine\Inflector\InflectorFactory;
+ use Doctrine\Inflector\Rules\Pattern;
+ use Doctrine\Inflector\Rules\Patterns;
+ use Doctrine\Inflector\Rules\Ruleset;
+ use Doctrine\Inflector\Rules\Substitution;
+ use Doctrine\Inflector\Rules\Substitutions;
+ use Doctrine\Inflector\Rules\Transformation;
+ use Doctrine\Inflector\Rules\Transformations;
+ use Doctrine\Inflector\Rules\Word;
+
+ $inflector = InflectorFactory::create()
+ ->withSingularRules(
+ new Ruleset(
+ new Transformations(
+ new Transformation(new Pattern('/^(bil)er$/i'), '\1'),
+ new Transformation(new Pattern('/^(inflec|contribu)tors$/i'), '\1ta')
+ ),
+ new Patterns(new Pattern('singulars')),
+ new Substitutions(new Substitution(new Word('spins'), new Word('spinor')))
+ )
+ )
+ ->withPluralRules(
+ new Ruleset(
+ new Transformations(
+ new Transformation(new Pattern('^(bil)er$'), '\1'),
+ new Transformation(new Pattern('^(inflec|contribu)tors$'), '\1ta')
+ ),
+ new Patterns(new Pattern('noflect'), new Pattern('abtuse')),
+ new Substitutions(
+ new Substitution(new Word('amaze'), new Word('amazable')),
+ new Substitution(new Word('phone'), new Word('phonezes'))
+ )
+ )
+ )
+ ->build();
+
+No operation inflector
+----------------------
+
+The ``Doctrine\Inflector\NoopWordInflector`` may be used to configure an inflector that doesn't perform any operation for
+pluralization and/or singularization. If will simply return the input as output.
+
+This is an implementation of the `Null Object design pattern `_.
+
+.. code-block:: php
+
+ use Doctrine\Inflector\Inflector;
+ use Doctrine\Inflector\NoopWordInflector;
+
+ $inflector = new Inflector(new NoopWordInflector(), new NoopWordInflector());
+
+Tableize
+========
+
+Converts ``ModelName`` to ``model_name``:
+
+.. code-block:: php
+
+ echo $inflector->tableize('ModelName'); // model_name
+
+Classify
+========
+
+Converts ``model_name`` to ``ModelName``:
+
+.. code-block:: php
+
+ echo $inflector->classify('model_name'); // ModelName
+
+Camelize
+========
+
+This method uses `Classify`_ and then converts the first character to lowercase:
+
+.. code-block:: php
+
+ echo $inflector->camelize('model_name'); // modelName
+
+Capitalize
+==========
+
+Takes a string and capitalizes all of the words, like PHP's built-in
+``ucwords`` function. This extends that behavior, however, by allowing the
+word delimiters to be configured, rather than only separating on
+whitespace.
+
+Here is an example:
+
+.. code-block:: php
+
+ $string = 'top-o-the-morning to all_of_you!';
+
+ echo $inflector->capitalize($string); // Top-O-The-Morning To All_of_you!
+
+ echo $inflector->capitalize($string, '-_ '); // Top-O-The-Morning To All_Of_You!
+
+Pluralize
+=========
+
+Returns a word in plural form.
+
+.. code-block:: php
+
+ echo $inflector->pluralize('browser'); // browsers
+
+Singularize
+===========
+
+Returns a word in singular form.
+
+.. code-block:: php
+
+ echo $inflector->singularize('browsers'); // browser
+
+Urlize
+======
+
+Generate a URL friendly string from a string of text:
+
+.. code-block:: php
+
+ echo $inflector->urlize('My first blog post'); // my-first-blog-post
+
+Unaccent
+========
+
+You can unaccent a string of text using the ``unaccent()`` method:
+
+.. code-block:: php
+
+ echo $inflector->unaccent('año'); // ano
+
+Legacy API
+==========
+
+The API present in Inflector 1.x is still available, but will be deprecated in a future release and dropped for 3.0.
+Support for languages other than English is available in the 2.0 API only.
+
+Acknowledgements
+================
+
+The language rules in this library have been adapted from several different sources, including but not limited to:
+
+- `Ruby On Rails Inflector `_
+- `ICanBoogie Inflector `_
+- `CakePHP Inflector `_
diff --git a/plugins/vendor/doctrine/inflector/src/CachedWordInflector.php b/plugins/vendor/doctrine/inflector/src/CachedWordInflector.php
new file mode 100644
index 00000000..2d529087
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/CachedWordInflector.php
@@ -0,0 +1,24 @@
+wordInflector = $wordInflector;
+ }
+
+ public function inflect(string $word): string
+ {
+ return $this->cache[$word] ?? $this->cache[$word] = $this->wordInflector->inflect($word);
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/GenericLanguageInflectorFactory.php b/plugins/vendor/doctrine/inflector/src/GenericLanguageInflectorFactory.php
new file mode 100644
index 00000000..166061d2
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/GenericLanguageInflectorFactory.php
@@ -0,0 +1,66 @@
+singularRulesets[] = $this->getSingularRuleset();
+ $this->pluralRulesets[] = $this->getPluralRuleset();
+ }
+
+ final public function build(): Inflector
+ {
+ return new Inflector(
+ new CachedWordInflector(new RulesetInflector(
+ ...$this->singularRulesets
+ )),
+ new CachedWordInflector(new RulesetInflector(
+ ...$this->pluralRulesets
+ ))
+ );
+ }
+
+ final public function withSingularRules(?Ruleset $singularRules, bool $reset = false): LanguageInflectorFactory
+ {
+ if ($reset) {
+ $this->singularRulesets = [];
+ }
+
+ if ($singularRules instanceof Ruleset) {
+ array_unshift($this->singularRulesets, $singularRules);
+ }
+
+ return $this;
+ }
+
+ final public function withPluralRules(?Ruleset $pluralRules, bool $reset = false): LanguageInflectorFactory
+ {
+ if ($reset) {
+ $this->pluralRulesets = [];
+ }
+
+ if ($pluralRules instanceof Ruleset) {
+ array_unshift($this->pluralRulesets, $pluralRules);
+ }
+
+ return $this;
+ }
+
+ abstract protected function getSingularRuleset(): Ruleset;
+
+ abstract protected function getPluralRuleset(): Ruleset;
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Inflector.php b/plugins/vendor/doctrine/inflector/src/Inflector.php
new file mode 100644
index 00000000..610a4cf4
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Inflector.php
@@ -0,0 +1,507 @@
+ 'A',
+ 'Á' => 'A',
+ 'Â' => 'A',
+ 'Ã' => 'A',
+ 'Ä' => 'Ae',
+ 'Æ' => 'Ae',
+ 'Å' => 'Aa',
+ 'æ' => 'a',
+ 'Ç' => 'C',
+ 'È' => 'E',
+ 'É' => 'E',
+ 'Ê' => 'E',
+ 'Ë' => 'E',
+ 'Ì' => 'I',
+ 'Í' => 'I',
+ 'Î' => 'I',
+ 'Ï' => 'I',
+ 'Ñ' => 'N',
+ 'Ò' => 'O',
+ 'Ó' => 'O',
+ 'Ô' => 'O',
+ 'Õ' => 'O',
+ 'Ö' => 'Oe',
+ 'Ù' => 'U',
+ 'Ú' => 'U',
+ 'Û' => 'U',
+ 'Ü' => 'Ue',
+ 'Ý' => 'Y',
+ 'ß' => 'ss',
+ 'à' => 'a',
+ 'á' => 'a',
+ 'â' => 'a',
+ 'ã' => 'a',
+ 'ä' => 'ae',
+ 'å' => 'aa',
+ 'ç' => 'c',
+ 'è' => 'e',
+ 'é' => 'e',
+ 'ê' => 'e',
+ 'ë' => 'e',
+ 'ì' => 'i',
+ 'í' => 'i',
+ 'î' => 'i',
+ 'ï' => 'i',
+ 'ñ' => 'n',
+ 'ò' => 'o',
+ 'ó' => 'o',
+ 'ô' => 'o',
+ 'õ' => 'o',
+ 'ö' => 'oe',
+ 'ù' => 'u',
+ 'ú' => 'u',
+ 'û' => 'u',
+ 'ü' => 'ue',
+ 'ý' => 'y',
+ 'ÿ' => 'y',
+ 'Ā' => 'A',
+ 'ā' => 'a',
+ 'Ă' => 'A',
+ 'ă' => 'a',
+ 'Ą' => 'A',
+ 'ą' => 'a',
+ 'Ć' => 'C',
+ 'ć' => 'c',
+ 'Ĉ' => 'C',
+ 'ĉ' => 'c',
+ 'Ċ' => 'C',
+ 'ċ' => 'c',
+ 'Č' => 'C',
+ 'č' => 'c',
+ 'Ď' => 'D',
+ 'ď' => 'd',
+ 'Đ' => 'D',
+ 'đ' => 'd',
+ 'Ē' => 'E',
+ 'ē' => 'e',
+ 'Ĕ' => 'E',
+ 'ĕ' => 'e',
+ 'Ė' => 'E',
+ 'ė' => 'e',
+ 'Ę' => 'E',
+ 'ę' => 'e',
+ 'Ě' => 'E',
+ 'ě' => 'e',
+ 'Ĝ' => 'G',
+ 'ĝ' => 'g',
+ 'Ğ' => 'G',
+ 'ğ' => 'g',
+ 'Ġ' => 'G',
+ 'ġ' => 'g',
+ 'Ģ' => 'G',
+ 'ģ' => 'g',
+ 'Ĥ' => 'H',
+ 'ĥ' => 'h',
+ 'Ħ' => 'H',
+ 'ħ' => 'h',
+ 'Ĩ' => 'I',
+ 'ĩ' => 'i',
+ 'Ī' => 'I',
+ 'ī' => 'i',
+ 'Ĭ' => 'I',
+ 'ĭ' => 'i',
+ 'Į' => 'I',
+ 'į' => 'i',
+ 'İ' => 'I',
+ 'ı' => 'i',
+ 'IJ' => 'IJ',
+ 'ij' => 'ij',
+ 'Ĵ' => 'J',
+ 'ĵ' => 'j',
+ 'Ķ' => 'K',
+ 'ķ' => 'k',
+ 'ĸ' => 'k',
+ 'Ĺ' => 'L',
+ 'ĺ' => 'l',
+ 'Ļ' => 'L',
+ 'ļ' => 'l',
+ 'Ľ' => 'L',
+ 'ľ' => 'l',
+ 'Ŀ' => 'L',
+ 'ŀ' => 'l',
+ 'Ł' => 'L',
+ 'ł' => 'l',
+ 'Ń' => 'N',
+ 'ń' => 'n',
+ 'Ņ' => 'N',
+ 'ņ' => 'n',
+ 'Ň' => 'N',
+ 'ň' => 'n',
+ 'ʼn' => 'N',
+ 'Ŋ' => 'n',
+ 'ŋ' => 'N',
+ 'Ō' => 'O',
+ 'ō' => 'o',
+ 'Ŏ' => 'O',
+ 'ŏ' => 'o',
+ 'Ő' => 'O',
+ 'ő' => 'o',
+ 'Œ' => 'OE',
+ 'œ' => 'oe',
+ 'Ø' => 'O',
+ 'ø' => 'o',
+ 'Ŕ' => 'R',
+ 'ŕ' => 'r',
+ 'Ŗ' => 'R',
+ 'ŗ' => 'r',
+ 'Ř' => 'R',
+ 'ř' => 'r',
+ 'Ś' => 'S',
+ 'ś' => 's',
+ 'Ŝ' => 'S',
+ 'ŝ' => 's',
+ 'Ş' => 'S',
+ 'ş' => 's',
+ 'Š' => 'S',
+ 'š' => 's',
+ 'Ţ' => 'T',
+ 'ţ' => 't',
+ 'Ť' => 'T',
+ 'ť' => 't',
+ 'Ŧ' => 'T',
+ 'ŧ' => 't',
+ 'Ũ' => 'U',
+ 'ũ' => 'u',
+ 'Ū' => 'U',
+ 'ū' => 'u',
+ 'Ŭ' => 'U',
+ 'ŭ' => 'u',
+ 'Ů' => 'U',
+ 'ů' => 'u',
+ 'Ű' => 'U',
+ 'ű' => 'u',
+ 'Ų' => 'U',
+ 'ų' => 'u',
+ 'Ŵ' => 'W',
+ 'ŵ' => 'w',
+ 'Ŷ' => 'Y',
+ 'ŷ' => 'y',
+ 'Ÿ' => 'Y',
+ 'Ź' => 'Z',
+ 'ź' => 'z',
+ 'Ż' => 'Z',
+ 'ż' => 'z',
+ 'Ž' => 'Z',
+ 'ž' => 'z',
+ 'ſ' => 's',
+ '€' => 'E',
+ '£' => '',
+ ];
+
+ /** @var WordInflector */
+ private $singularizer;
+
+ /** @var WordInflector */
+ private $pluralizer;
+
+ public function __construct(WordInflector $singularizer, WordInflector $pluralizer)
+ {
+ $this->singularizer = $singularizer;
+ $this->pluralizer = $pluralizer;
+ }
+
+ /**
+ * Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'.
+ */
+ public function tableize(string $word): string
+ {
+ $tableized = preg_replace('~(?<=\\w)([A-Z])~u', '_$1', $word);
+
+ if ($tableized === null) {
+ throw new RuntimeException(sprintf(
+ 'preg_replace returned null for value "%s"',
+ $word
+ ));
+ }
+
+ return mb_strtolower($tableized);
+ }
+
+ /**
+ * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'.
+ */
+ public function classify(string $word): string
+ {
+ return str_replace([' ', '_', '-'], '', ucwords($word, ' _-'));
+ }
+
+ /**
+ * Camelizes a word. This uses the classify() method and turns the first character to lowercase.
+ */
+ public function camelize(string $word): string
+ {
+ return lcfirst($this->classify($word));
+ }
+
+ /**
+ * Uppercases words with configurable delimiters between words.
+ *
+ * Takes a string and capitalizes all of the words, like PHP's built-in
+ * ucwords function. This extends that behavior, however, by allowing the
+ * word delimiters to be configured, rather than only separating on
+ * whitespace.
+ *
+ * Here is an example:
+ *
+ * capitalize($string);
+ * // Top-O-The-Morning To All_of_you!
+ *
+ * echo $inflector->capitalize($string, '-_ ');
+ * // Top-O-The-Morning To All_Of_You!
+ * ?>
+ *
+ *
+ * @param string $string The string to operate on.
+ * @param string $delimiters A list of word separators.
+ *
+ * @return string The string with all delimiter-separated words capitalized.
+ */
+ public function capitalize(string $string, string $delimiters = " \n\t\r\0\x0B-"): string
+ {
+ return ucwords($string, $delimiters);
+ }
+
+ /**
+ * Checks if the given string seems like it has utf8 characters in it.
+ *
+ * @param string $string The string to check for utf8 characters in.
+ */
+ public function seemsUtf8(string $string): bool
+ {
+ for ($i = 0; $i < strlen($string); $i++) {
+ if (ord($string[$i]) < 0x80) {
+ continue; // 0bbbbbbb
+ }
+
+ if ((ord($string[$i]) & 0xE0) === 0xC0) {
+ $n = 1; // 110bbbbb
+ } elseif ((ord($string[$i]) & 0xF0) === 0xE0) {
+ $n = 2; // 1110bbbb
+ } elseif ((ord($string[$i]) & 0xF8) === 0xF0) {
+ $n = 3; // 11110bbb
+ } elseif ((ord($string[$i]) & 0xFC) === 0xF8) {
+ $n = 4; // 111110bb
+ } elseif ((ord($string[$i]) & 0xFE) === 0xFC) {
+ $n = 5; // 1111110b
+ } else {
+ return false; // Does not match any model
+ }
+
+ for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
+ if (++$i === strlen($string) || ((ord($string[$i]) & 0xC0) !== 0x80)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Remove any illegal characters, accents, etc.
+ *
+ * @param string $string String to unaccent
+ *
+ * @return string Unaccented string
+ */
+ public function unaccent(string $string): string
+ {
+ if (preg_match('/[\x80-\xff]/', $string) === false) {
+ return $string;
+ }
+
+ if ($this->seemsUtf8($string)) {
+ $string = strtr($string, self::ACCENTED_CHARACTERS);
+ } else {
+ $characters = [];
+
+ // Assume ISO-8859-1 if not UTF-8
+ $characters['in'] =
+ chr(128)
+ . chr(131)
+ . chr(138)
+ . chr(142)
+ . chr(154)
+ . chr(158)
+ . chr(159)
+ . chr(162)
+ . chr(165)
+ . chr(181)
+ . chr(192)
+ . chr(193)
+ . chr(194)
+ . chr(195)
+ . chr(196)
+ . chr(197)
+ . chr(199)
+ . chr(200)
+ . chr(201)
+ . chr(202)
+ . chr(203)
+ . chr(204)
+ . chr(205)
+ . chr(206)
+ . chr(207)
+ . chr(209)
+ . chr(210)
+ . chr(211)
+ . chr(212)
+ . chr(213)
+ . chr(214)
+ . chr(216)
+ . chr(217)
+ . chr(218)
+ . chr(219)
+ . chr(220)
+ . chr(221)
+ . chr(224)
+ . chr(225)
+ . chr(226)
+ . chr(227)
+ . chr(228)
+ . chr(229)
+ . chr(231)
+ . chr(232)
+ . chr(233)
+ . chr(234)
+ . chr(235)
+ . chr(236)
+ . chr(237)
+ . chr(238)
+ . chr(239)
+ . chr(241)
+ . chr(242)
+ . chr(243)
+ . chr(244)
+ . chr(245)
+ . chr(246)
+ . chr(248)
+ . chr(249)
+ . chr(250)
+ . chr(251)
+ . chr(252)
+ . chr(253)
+ . chr(255);
+
+ $characters['out'] = 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy';
+
+ $string = strtr($string, $characters['in'], $characters['out']);
+
+ $doubleChars = [];
+
+ $doubleChars['in'] = [
+ chr(140),
+ chr(156),
+ chr(198),
+ chr(208),
+ chr(222),
+ chr(223),
+ chr(230),
+ chr(240),
+ chr(254),
+ ];
+
+ $doubleChars['out'] = ['OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th'];
+
+ $string = str_replace($doubleChars['in'], $doubleChars['out'], $string);
+ }
+
+ return $string;
+ }
+
+ /**
+ * Convert any passed string to a url friendly string.
+ * Converts 'My first blog post' to 'my-first-blog-post'
+ *
+ * @param string $string String to urlize.
+ *
+ * @return string Urlized string.
+ */
+ public function urlize(string $string): string
+ {
+ // Remove all non url friendly characters with the unaccent function
+ $unaccented = $this->unaccent($string);
+
+ if (function_exists('mb_strtolower')) {
+ $lowered = mb_strtolower($unaccented);
+ } else {
+ $lowered = strtolower($unaccented);
+ }
+
+ $replacements = [
+ '/\W/' => ' ',
+ '/([A-Z]+)([A-Z][a-z])/' => '\1_\2',
+ '/([a-z\d])([A-Z])/' => '\1_\2',
+ '/[^A-Z^a-z^0-9^\/]+/' => '-',
+ ];
+
+ $urlized = $lowered;
+
+ foreach ($replacements as $pattern => $replacement) {
+ $replaced = preg_replace($pattern, $replacement, $urlized);
+
+ if ($replaced === null) {
+ throw new RuntimeException(sprintf(
+ 'preg_replace returned null for value "%s"',
+ $urlized
+ ));
+ }
+
+ $urlized = $replaced;
+ }
+
+ return trim($urlized, '-');
+ }
+
+ /**
+ * Returns a word in singular form.
+ *
+ * @param string $word The word in plural form.
+ *
+ * @return string The word in singular form.
+ */
+ public function singularize(string $word): string
+ {
+ return $this->singularizer->inflect($word);
+ }
+
+ /**
+ * Returns a word in plural form.
+ *
+ * @param string $word The word in singular form.
+ *
+ * @return string The word in plural form.
+ */
+ public function pluralize(string $word): string
+ {
+ return $this->pluralizer->inflect($word);
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/InflectorFactory.php b/plugins/vendor/doctrine/inflector/src/InflectorFactory.php
new file mode 100644
index 00000000..3556b783
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/InflectorFactory.php
@@ -0,0 +1,60 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/English/Uninflected.php b/plugins/vendor/doctrine/inflector/src/Rules/English/Uninflected.php
new file mode 100644
index 00000000..02257de1
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/English/Uninflected.php
@@ -0,0 +1,189 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Esperanto/Uninflected.php b/plugins/vendor/doctrine/inflector/src/Rules/Esperanto/Uninflected.php
new file mode 100644
index 00000000..ed04c931
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Esperanto/Uninflected.php
@@ -0,0 +1,28 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/French/Uninflected.php b/plugins/vendor/doctrine/inflector/src/Rules/French/Uninflected.php
new file mode 100644
index 00000000..1c2b99a3
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/French/Uninflected.php
@@ -0,0 +1,31 @@
+ */
+ public static function getSingular(): iterable
+ {
+ // Reverse of -sce → -scia (fasce → fascia)
+ yield new Transformation(new Pattern('([aeiou])sce$'), '\\1scia');
+
+ // Reverse of -cie → -cia (farmacia → farmacie)
+ yield new Transformation(new Pattern('cie$'), 'cia');
+
+ // Reverse of -gie → -gia (bugia → bugie)
+ yield new Transformation(new Pattern('gie$'), 'gia');
+
+ // Reverse of -ce → -cia (arance → arancia)
+ yield new Transformation(new Pattern('([^aeiou])ce$'), '\1cia');
+
+ // Reverse of -ge → -gia (valige → valigia)
+ yield new Transformation(new Pattern('([^aeiou])ge$'), '\1gia');
+
+ // Reverse of -chi → -co (bachi → baco)
+ yield new Transformation(new Pattern('([bcdfghjklmnpqrstvwxyz][aeiou])chi$'), '\1co');
+
+ // Reverse of -ghi → -go (laghi → lago)
+ yield new Transformation(new Pattern('([bcdfghjklmnpqrstvwxyz][aeiou])ghi$'), '\1go');
+
+ // Reverse of -ci → -co (medici → medico)
+ yield new Transformation(new Pattern('([aeiou][bcdfghjklmnpqrstvwxyz])ci$'), '\1co');
+
+ // Reverse of -gi → -go (psicologi → psicologo)
+ yield new Transformation(new Pattern('([aeiou][bcdfghjklmnpqrstvwxyz])gi$'), '\1go');
+
+ // Reverse of -i → -io (zii → zio, negozi → negozio)
+ // This is more complex due to Italian's stress patterns, but we'll handle the basic case
+ yield new Transformation(new Pattern('([^aeiou])i$'), '\1io');
+
+ // Handle words that end with -i but should go to -co/-go (amici → amico, not amice)
+ yield new Transformation(new Pattern('([^aeiou])ci$'), '\1co');
+ yield new Transformation(new Pattern('([^aeiou])gi$'), '\1go');
+
+ // Reverse of -a → -e
+ yield new Transformation(new Pattern('e$'), 'a');
+
+ // Reverse of -e → -i
+ yield new Transformation(new Pattern('i$'), 'e');
+
+ // Reverse of -o → -i
+ yield new Transformation(new Pattern('i$'), 'o');
+ }
+
+ /** @return iterable */
+ public static function getPlural(): iterable
+ {
+ // Words ending in -scia without stress on 'i' become -sce (e.g. fascia → fasce)
+ yield new Transformation(new Pattern('([aeiou])scia$'), '\\1sce');
+
+ // Words ending in -cia/gia with stress on 'i' keep the 'i' in plural
+ yield new Transformation(new Pattern('cia$'), 'cie'); // e.g. farmacia → farmacie
+ yield new Transformation(new Pattern('gia$'), 'gie'); // e.g. bugia → bugie
+
+ // Words ending in -cia/gia without stress on 'i' lose the 'i' in plural
+ yield new Transformation(new Pattern('([^aeiou])cia$'), '\\1ce'); // e.g. arancia → arance
+ yield new Transformation(new Pattern('([^aeiou])gia$'), '\\1ge'); // e.g. valigia → valige
+
+ // Words ending in -co/-go with stress on 'o' become -chi/-ghi
+ yield new Transformation(new Pattern('([bcdfghjklmnpqrstvwxyz][aeiou])co$'), '\\1chi'); // e.g. baco → bachi
+ yield new Transformation(new Pattern('([bcdfghjklmnpqrstvwxyz][aeiou])go$'), '\\1ghi'); // e.g. lago → laghi
+
+ // Words ending in -co/-go with stress on the penultimate syllable become -ci/-gi
+ yield new Transformation(new Pattern('([aeiou][bcdfghjklmnpqrstvwxyz])co$'), '\\1ci'); // e.g. medico → medici
+ yield new Transformation(new Pattern('([aeiou][bcdfghjklmnpqrstvwxyz])go$'), '\\1gi'); // e.g. psicologo → psicologi
+
+ // Words ending in -io with stress on 'i' keep the 'i' in plural
+ yield new Transformation(new Pattern('([^aeiou])io$'), '\\1i'); // e.g. zio → zii
+
+ // Words ending in -io with stress on 'o' lose the 'i' in plural
+ yield new Transformation(new Pattern('([aeiou])io$'), '\\1i'); // e.g. negozio → negozi
+
+ // Standard ending rules
+ yield new Transformation(new Pattern('a$'), 'e'); // -a → -e
+ yield new Transformation(new Pattern('e$'), 'i'); // -e → -i
+ yield new Transformation(new Pattern('o$'), 'i'); // -o → -i
+ }
+
+ /** @return iterable */
+ public static function getIrregular(): iterable
+ {
+ // Irregular substitutions (singular => plural)
+ $irregulars = [
+ 'ala' => 'ali',
+ 'albergo' => 'alberghi',
+ 'amica' => 'amiche',
+ 'amico' => 'amici',
+ 'ampio' => 'ampi',
+ 'arancia' => 'arance',
+ 'arma' => 'armi',
+ 'asparago' => 'asparagi',
+ 'banca' => 'banche',
+ 'belga' => 'belgi',
+ 'braccio' => 'braccia',
+ 'budello' => 'budella',
+ 'bue' => 'buoi',
+ 'caccia' => 'cacce',
+ 'calcagno' => 'calcagna',
+ 'camicia' => 'camicie',
+ 'cane' => 'cani',
+ 'capitale' => 'capitali',
+ 'carcere' => 'carceri',
+ 'casa' => 'case',
+ 'cavaliere' => 'cavalieri',
+ 'centinaio' => 'centinaia',
+ 'cerchio' => 'cerchia',
+ 'cervello' => 'cervella',
+ 'chiave' => 'chiavi',
+ 'chirurgo' => 'chirurgi',
+ 'ciglio' => 'ciglia',
+ 'città' => 'città',
+ 'corno' => 'corna',
+ 'corpo' => 'corpi',
+ 'crisi' => 'crisi',
+ 'dente' => 'denti',
+ 'dio' => 'dei',
+ 'dito' => 'dita',
+ 'dottore' => 'dottori',
+ 'fiore' => 'fiori',
+ 'fratello' => 'fratelli',
+ 'fuoco' => 'fuochi',
+ 'gamba' => 'gambe',
+ 'ginocchio' => 'ginocchia',
+ 'gioco' => 'giochi',
+ 'giornale' => 'giornali',
+ 'giraffa' => 'giraffe',
+ 'labbro' => 'labbra',
+ 'lenzuolo' => 'lenzuola',
+ 'libro' => 'libri',
+ 'madre' => 'madri',
+ 'maestro' => 'maestri',
+ 'magico' => 'magici',
+ 'mago' => 'maghi',
+ 'maniaco' => 'maniaci',
+ 'manico' => 'manici',
+ 'mano' => 'mani',
+ 'medico' => 'medici',
+ 'membro' => 'membri',
+ 'metropoli' => 'metropoli',
+ 'migliaio' => 'migliaia',
+ 'miglio' => 'miglia',
+ 'mille' => 'mila',
+ 'mio' => 'miei',
+ 'moglie' => 'mogli',
+ 'mosaico' => 'mosaici',
+ 'muro' => 'muri',
+ 'nemico' => 'nemici',
+ 'nome' => 'nomi',
+ 'occhio' => 'occhi',
+ 'orecchio' => 'orecchi',
+ 'osso' => 'ossa',
+ 'paio' => 'paia',
+ 'pane' => 'pani',
+ 'papa' => 'papi',
+ 'pasta' => 'paste',
+ 'penna' => 'penne',
+ 'pesce' => 'pesci',
+ 'piede' => 'piedi',
+ 'pittore' => 'pittori',
+ 'poeta' => 'poeti',
+ 'porco' => 'porci',
+ 'porto' => 'porti',
+ 'problema' => 'problemi',
+ 'ragazzo' => 'ragazzi',
+ 're' => 're',
+ 'rene' => 'reni',
+ 'riso' => 'risa',
+ 'rosa' => 'rosa',
+ 'sale' => 'sali',
+ 'sarto' => 'sarti',
+ 'scuola' => 'scuole',
+ 'serie' => 'serie',
+ 'serramento' => 'serramenta',
+ 'sorella' => 'sorelle',
+ 'specie' => 'specie',
+ 'staio' => 'staia',
+ 'stazione' => 'stazioni',
+ 'strido' => 'strida',
+ 'strillo' => 'strilla',
+ 'studio' => 'studi',
+ 'suo' => 'suoi',
+ 'superficie' => 'superfici',
+ 'tavolo' => 'tavoli',
+ 'tempio' => 'templi',
+ 'treno' => 'treni',
+ 'tuo' => 'tuoi',
+ 'uomo' => 'uomini',
+ 'uovo' => 'uova',
+ 'urlo' => 'urla',
+ 'valigia' => 'valigie',
+ 'vestigio' => 'vestigia',
+ 'vino' => 'vini',
+ 'viola' => 'viola',
+ 'zio' => 'zii',
+ ];
+
+ foreach ($irregulars as $singular => $plural) {
+ yield new Substitution(new Word($singular), new Word($plural));
+ }
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Italian/InflectorFactory.php b/plugins/vendor/doctrine/inflector/src/Rules/Italian/InflectorFactory.php
new file mode 100644
index 00000000..41685c4a
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Italian/InflectorFactory.php
@@ -0,0 +1,21 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Italian/Uninflected.php b/plugins/vendor/doctrine/inflector/src/Rules/Italian/Uninflected.php
new file mode 100644
index 00000000..067a92a6
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Italian/Uninflected.php
@@ -0,0 +1,80 @@
+ */
+ public static function getSingular(): iterable
+ {
+ yield from self::getDefault();
+ }
+
+ /** @return iterable */
+ public static function getPlural(): iterable
+ {
+ yield from self::getDefault();
+ }
+
+ /** @return iterable */
+ private static function getDefault(): iterable
+ {
+ // Invariable words (same form in singular and plural)
+ $invariables = [
+ 'alpaca',
+ 'auto',
+ 'bar',
+ 'blu',
+ 'boia',
+ 'boomerang',
+ 'brindisi',
+ 'campus',
+ 'computer',
+ 'crisi',
+ 'crocevia',
+ 'dopocena',
+ 'film',
+ 'foto',
+ 'fuchsia',
+ 'gnu',
+ 'gorilla',
+ 'gru',
+ 'iguana',
+ 'kamikaze',
+ 'karaoke',
+ 'koala',
+ 'lama',
+ 'menu',
+ 'metropoli',
+ 'moto',
+ 'opossum',
+ 'panda',
+ 'quiz',
+ 'radio',
+ 're',
+ 'scacciapensieri',
+ 'serie',
+ 'smartphone',
+ 'sosia',
+ 'sottoscala',
+ 'specie',
+ 'sport',
+ 'tablet',
+ 'taxi',
+ 'vaglia',
+ 'virtù',
+ 'virus',
+ 'yogurt',
+ 'foto',
+ 'fuchsia',
+ ];
+
+ foreach ($invariables as $word) {
+ yield new Pattern($word);
+ }
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/NorwegianBokmal/Inflectible.php b/plugins/vendor/doctrine/inflector/src/Rules/NorwegianBokmal/Inflectible.php
new file mode 100644
index 00000000..1e952d84
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/NorwegianBokmal/Inflectible.php
@@ -0,0 +1,34 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/NorwegianBokmal/Uninflected.php b/plugins/vendor/doctrine/inflector/src/Rules/NorwegianBokmal/Uninflected.php
new file mode 100644
index 00000000..5d8d3b3a
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/NorwegianBokmal/Uninflected.php
@@ -0,0 +1,30 @@
+pattern = $pattern;
+
+ if (isset($this->pattern[0]) && $this->pattern[0] === '/') {
+ $this->regex = $this->pattern;
+ } else {
+ $this->regex = '/' . $this->pattern . '/i';
+ }
+ }
+
+ public function getPattern(): string
+ {
+ return $this->pattern;
+ }
+
+ public function getRegex(): string
+ {
+ return $this->regex;
+ }
+
+ public function matches(string $word): bool
+ {
+ return preg_match($this->getRegex(), $word) === 1;
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Patterns.php b/plugins/vendor/doctrine/inflector/src/Rules/Patterns.php
new file mode 100644
index 00000000..16594c4f
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Patterns.php
@@ -0,0 +1,29 @@
+getPattern();
+ }, $patterns);
+
+ $this->regex = '/^(?:' . implode('|', $patterns) . ')$/i';
+ }
+
+ public function matches(string $word): bool
+ {
+ return preg_match($this->regex, $word, $regs) === 1;
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Portuguese/Inflectible.php b/plugins/vendor/doctrine/inflector/src/Rules/Portuguese/Inflectible.php
new file mode 100644
index 00000000..0d41fe7e
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Portuguese/Inflectible.php
@@ -0,0 +1,98 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Portuguese/Uninflected.php b/plugins/vendor/doctrine/inflector/src/Rules/Portuguese/Uninflected.php
new file mode 100644
index 00000000..b8e988f8
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Portuguese/Uninflected.php
@@ -0,0 +1,32 @@
+regular = $regular;
+ $this->uninflected = $uninflected;
+ $this->irregular = $irregular;
+ }
+
+ public function getRegular(): Transformations
+ {
+ return $this->regular;
+ }
+
+ public function getUninflected(): Patterns
+ {
+ return $this->uninflected;
+ }
+
+ public function getIrregular(): Substitutions
+ {
+ return $this->irregular;
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Spanish/Inflectible.php b/plugins/vendor/doctrine/inflector/src/Rules/Spanish/Inflectible.php
new file mode 100644
index 00000000..91294609
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Spanish/Inflectible.php
@@ -0,0 +1,47 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Spanish/Uninflected.php b/plugins/vendor/doctrine/inflector/src/Rules/Spanish/Uninflected.php
new file mode 100644
index 00000000..c26ebe9c
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Spanish/Uninflected.php
@@ -0,0 +1,30 @@
+from = $from;
+ $this->to = $to;
+ }
+
+ public function getFrom(): Word
+ {
+ return $this->from;
+ }
+
+ public function getTo(): Word
+ {
+ return $this->to;
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Substitutions.php b/plugins/vendor/doctrine/inflector/src/Rules/Substitutions.php
new file mode 100644
index 00000000..17ee2961
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Substitutions.php
@@ -0,0 +1,57 @@
+substitutions[$substitution->getFrom()->getWord()] = $substitution;
+ }
+ }
+
+ public function getFlippedSubstitutions(): Substitutions
+ {
+ $substitutions = [];
+
+ foreach ($this->substitutions as $substitution) {
+ $substitutions[] = new Substitution(
+ $substitution->getTo(),
+ $substitution->getFrom()
+ );
+ }
+
+ return new Substitutions(...$substitutions);
+ }
+
+ public function inflect(string $word): string
+ {
+ $lowerWord = strtolower($word);
+
+ if (isset($this->substitutions[$lowerWord])) {
+ $firstLetterUppercase = $lowerWord[0] !== $word[0];
+
+ $toWord = $this->substitutions[$lowerWord]->getTo()->getWord();
+
+ if ($firstLetterUppercase) {
+ return strtoupper($toWord[0]) . substr($toWord, 1);
+ }
+
+ return $toWord;
+ }
+
+ return $word;
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Transformation.php b/plugins/vendor/doctrine/inflector/src/Rules/Transformation.php
new file mode 100644
index 00000000..30dcd594
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Transformation.php
@@ -0,0 +1,39 @@
+pattern = $pattern;
+ $this->replacement = $replacement;
+ }
+
+ public function getPattern(): Pattern
+ {
+ return $this->pattern;
+ }
+
+ public function getReplacement(): string
+ {
+ return $this->replacement;
+ }
+
+ public function inflect(string $word): string
+ {
+ return (string) preg_replace($this->pattern->getRegex(), $this->replacement, $word);
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Transformations.php b/plugins/vendor/doctrine/inflector/src/Rules/Transformations.php
new file mode 100644
index 00000000..b6a48fa8
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Transformations.php
@@ -0,0 +1,29 @@
+transformations = $transformations;
+ }
+
+ public function inflect(string $word): string
+ {
+ foreach ($this->transformations as $transformation) {
+ if ($transformation->getPattern()->matches($word)) {
+ return $transformation->inflect($word);
+ }
+ }
+
+ return $word;
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Turkish/Inflectible.php b/plugins/vendor/doctrine/inflector/src/Rules/Turkish/Inflectible.php
new file mode 100644
index 00000000..a2bda0d9
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Turkish/Inflectible.php
@@ -0,0 +1,34 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/Rules/Turkish/Uninflected.php b/plugins/vendor/doctrine/inflector/src/Rules/Turkish/Uninflected.php
new file mode 100644
index 00000000..ec1c37dd
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/Rules/Turkish/Uninflected.php
@@ -0,0 +1,30 @@
+word = $word;
+ }
+
+ public function getWord(): string
+ {
+ return $this->word;
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/RulesetInflector.php b/plugins/vendor/doctrine/inflector/src/RulesetInflector.php
new file mode 100644
index 00000000..12b2ed5b
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/RulesetInflector.php
@@ -0,0 +1,56 @@
+rulesets = array_merge([$ruleset], $rulesets);
+ }
+
+ public function inflect(string $word): string
+ {
+ if ($word === '') {
+ return '';
+ }
+
+ foreach ($this->rulesets as $ruleset) {
+ if ($ruleset->getUninflected()->matches($word)) {
+ return $word;
+ }
+
+ $inflected = $ruleset->getIrregular()->inflect($word);
+
+ if ($inflected !== $word) {
+ return $inflected;
+ }
+
+ $inflected = $ruleset->getRegular()->inflect($word);
+
+ if ($inflected !== $word) {
+ return $inflected;
+ }
+ }
+
+ return $word;
+ }
+}
diff --git a/plugins/vendor/doctrine/inflector/src/WordInflector.php b/plugins/vendor/doctrine/inflector/src/WordInflector.php
new file mode 100644
index 00000000..b88b1d69
--- /dev/null
+++ b/plugins/vendor/doctrine/inflector/src/WordInflector.php
@@ -0,0 +1,10 @@
+all();
+ } elseif (is_array($values)) {
+ $results[] = $values;
+ }
+ }
+
+ return array_merge([], ...$results);
+ }
+
+ /**
+ * Cross join the given arrays, returning all possible permutations.
+ *
+ * @param iterable ...$arrays
+ * @return array
+ */
+ public static function crossJoin(...$arrays)
+ {
+ $results = [[]];
+
+ foreach ($arrays as $index => $array) {
+ $append = [];
+
+ foreach ($results as $product) {
+ foreach ($array as $item) {
+ $product[$index] = $item;
+
+ $append[] = $product;
+ }
+ }
+
+ $results = $append;
+ }
+
+ return $results;
+ }
+
+ /**
+ * Divide an array into two arrays. One with keys and the other with values.
+ *
+ * @param array $array
+ * @return array
+ */
+ public static function divide($array)
+ {
+ return [array_keys($array), array_values($array)];
+ }
+
+ /**
+ * Flatten a multi-dimensional associative array with dots.
+ *
+ * @param iterable $array
+ * @param string $prepend
+ * @return array
+ */
+ public static function dot($array, $prepend = '')
+ {
+ $results = [];
+
+ $flatten = function ($data, $prefix) use (&$results, &$flatten): void {
+ foreach ($data as $key => $value) {
+ $newKey = $prefix.$key;
+
+ if (is_array($value) && ! empty($value)) {
+ $flatten($value, $newKey.'.');
+ } else {
+ $results[$newKey] = $value;
+ }
+ }
+ };
+
+ $flatten($array, $prepend);
+
+ return $results;
+ }
+
+ /**
+ * Convert a flatten "dot" notation array into an expanded array.
+ *
+ * @param iterable $array
+ * @return array
+ */
+ public static function undot($array)
+ {
+ $results = [];
+
+ foreach ($array as $key => $value) {
+ static::set($results, $key, $value);
+ }
+
+ return $results;
+ }
+
+ /**
+ * Get all of the given array except for a specified array of keys.
+ *
+ * @param array $array
+ * @param array|string|int|float $keys
+ * @return array
+ */
+ public static function except($array, $keys)
+ {
+ static::forget($array, $keys);
+
+ return $array;
+ }
+
+ /**
+ * Determine if the given key exists in the provided array.
+ *
+ * @param \ArrayAccess|array $array
+ * @param string|int|float $key
+ * @return bool
+ */
+ public static function exists($array, $key)
+ {
+ if ($array instanceof Enumerable) {
+ return $array->has($key);
+ }
+
+ if ($array instanceof ArrayAccess) {
+ return $array->offsetExists($key);
+ }
+
+ if (is_float($key)) {
+ $key = (string) $key;
+ }
+
+ return array_key_exists($key, $array);
+ }
+
+ /**
+ * Return the first element in an array passing a given truth test.
+ *
+ * @template TKey
+ * @template TValue
+ * @template TFirstDefault
+ *
+ * @param iterable $array
+ * @param (callable(TValue, TKey): bool)|null $callback
+ * @param TFirstDefault|(\Closure(): TFirstDefault) $default
+ * @return TValue|TFirstDefault
+ */
+ public static function first($array, ?callable $callback = null, $default = null)
+ {
+ if (is_null($callback)) {
+ if (empty($array)) {
+ return value($default);
+ }
+
+ if (is_array($array)) {
+ return array_first($array);
+ }
+
+ foreach ($array as $item) {
+ return $item;
+ }
+
+ return value($default);
+ }
+
+ $key = array_find_key($array, $callback);
+
+ return $key !== null ? $array[$key] : value($default);
+ }
+
+ /**
+ * Return the last element in an array passing a given truth test.
+ *
+ * @template TKey
+ * @template TValue
+ * @template TLastDefault
+ *
+ * @param iterable $array
+ * @param (callable(TValue, TKey): bool)|null $callback
+ * @param TLastDefault|(\Closure(): TLastDefault) $default
+ * @return TValue|TLastDefault
+ */
+ public static function last($array, ?callable $callback = null, $default = null)
+ {
+ if (is_null($callback)) {
+ return empty($array) ? value($default) : array_last($array);
+ }
+
+ return static::first(array_reverse($array, true), $callback, $default);
+ }
+
+ /**
+ * Take the first or last {$limit} items from an array.
+ *
+ * @param array $array
+ * @param int $limit
+ * @return array
+ */
+ public static function take($array, $limit)
+ {
+ if ($limit < 0) {
+ return array_slice($array, $limit, abs($limit));
+ }
+
+ return array_slice($array, 0, $limit);
+ }
+
+ /**
+ * Flatten a multi-dimensional array into a single level.
+ *
+ * @param iterable $array
+ * @param int $depth
+ * @return array
+ */
+ public static function flatten($array, $depth = INF)
+ {
+ $result = [];
+
+ foreach ($array as $item) {
+ $item = $item instanceof Collection ? $item->all() : $item;
+
+ if (! is_array($item)) {
+ $result[] = $item;
+ } else {
+ $values = $depth === 1
+ ? array_values($item)
+ : static::flatten($item, $depth - 1);
+
+ foreach ($values as $value) {
+ $result[] = $value;
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get a float item from an array using "dot" notation.
+ */
+ public static function float(ArrayAccess|array $array, string|int|null $key, ?float $default = null): float
+ {
+ $value = Arr::get($array, $key, $default);
+
+ if (! is_float($value)) {
+ throw new InvalidArgumentException(
+ sprintf('Array value for key [%s] must be a float, %s found.', $key, gettype($value))
+ );
+ }
+
+ return $value;
+ }
+
+ /**
+ * Remove one or many array items from a given array using "dot" notation.
+ *
+ * @param array $array
+ * @param array|string|int|float $keys
+ * @return void
+ */
+ public static function forget(&$array, $keys)
+ {
+ $original = &$array;
+
+ $keys = (array) $keys;
+
+ if (count($keys) === 0) {
+ return;
+ }
+
+ foreach ($keys as $key) {
+ // if the exact key exists in the top-level, remove it
+ if (static::exists($array, $key)) {
+ unset($array[$key]);
+
+ continue;
+ }
+
+ $parts = explode('.', $key);
+
+ // clean up before each pass
+ $array = &$original;
+
+ while (count($parts) > 1) {
+ $part = array_shift($parts);
+
+ if (isset($array[$part]) && static::accessible($array[$part])) {
+ $array = &$array[$part];
+ } else {
+ continue 2;
+ }
+ }
+
+ unset($array[array_shift($parts)]);
+ }
+ }
+
+ /**
+ * Get the underlying array of items from the given argument.
+ *
+ * @template TKey of array-key = array-key
+ * @template TValue = mixed
+ *
+ * @param array|Enumerable|Arrayable|WeakMap|Traversable|Jsonable|JsonSerializable|object $items
+ * @return ($items is WeakMap ? list : array)
+ *
+ * @throws \InvalidArgumentException
+ */
+ public static function from($items)
+ {
+ return match (true) {
+ is_array($items) => $items,
+ $items instanceof Enumerable => $items->all(),
+ $items instanceof Arrayable => $items->toArray(),
+ $items instanceof WeakMap => iterator_to_array($items, false),
+ $items instanceof Traversable => iterator_to_array($items),
+ $items instanceof Jsonable => json_decode($items->toJson(), true),
+ $items instanceof JsonSerializable => (array) $items->jsonSerialize(),
+ is_object($items) => (array) $items,
+ default => throw new InvalidArgumentException('Items cannot be represented by a scalar value.'),
+ };
+ }
+
+ /**
+ * Get an item from an array using "dot" notation.
+ *
+ * @param \ArrayAccess|array $array
+ * @param string|int|null $key
+ * @param mixed $default
+ * @return mixed
+ */
+ public static function get($array, $key, $default = null)
+ {
+ if (! static::accessible($array)) {
+ return value($default);
+ }
+
+ if (is_null($key)) {
+ return $array;
+ }
+
+ if (static::exists($array, $key)) {
+ return $array[$key];
+ }
+
+ if (! str_contains($key, '.')) {
+ return $array[$key] ?? value($default);
+ }
+
+ foreach (explode('.', $key) as $segment) {
+ if (static::accessible($array) && static::exists($array, $segment)) {
+ $array = $array[$segment];
+ } else {
+ return value($default);
+ }
+ }
+
+ return $array;
+ }
+
+ /**
+ * Check if an item or items exist in an array using "dot" notation.
+ *
+ * @param \ArrayAccess|array $array
+ * @param string|array $keys
+ * @return bool
+ */
+ public static function has($array, $keys)
+ {
+ $keys = (array) $keys;
+
+ if (! $array || $keys === []) {
+ return false;
+ }
+
+ foreach ($keys as $key) {
+ $subKeyArray = $array;
+
+ if (static::exists($array, $key)) {
+ continue;
+ }
+
+ foreach (explode('.', $key) as $segment) {
+ if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) {
+ $subKeyArray = $subKeyArray[$segment];
+ } else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Determine if all keys exist in an array using "dot" notation.
+ *
+ * @param \ArrayAccess|array $array
+ * @param string|array $keys
+ * @return bool
+ */
+ public static function hasAll($array, $keys)
+ {
+ $keys = (array) $keys;
+
+ if (! $array || $keys === []) {
+ return false;
+ }
+
+ foreach ($keys as $key) {
+ if (! static::has($array, $key)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Determine if any of the keys exist in an array using "dot" notation.
+ *
+ * @param \ArrayAccess|array $array
+ * @param string|array $keys
+ * @return bool
+ */
+ public static function hasAny($array, $keys)
+ {
+ if (is_null($keys)) {
+ return false;
+ }
+
+ $keys = (array) $keys;
+
+ if (! $array) {
+ return false;
+ }
+
+ if ($keys === []) {
+ return false;
+ }
+
+ foreach ($keys as $key) {
+ if (static::has($array, $key)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine if all items pass the given truth test.
+ *
+ * @param iterable $array
+ * @param (callable(mixed, array-key): bool) $callback
+ * @return bool
+ */
+ public static function every($array, callable $callback)
+ {
+ return array_all($array, $callback);
+ }
+
+ /**
+ * Determine if some items pass the given truth test.
+ *
+ * @param iterable $array
+ * @param (callable(mixed, array-key): bool) $callback
+ * @return bool
+ */
+ public static function some($array, callable $callback)
+ {
+ return array_any($array, $callback);
+ }
+
+ /**
+ * Get an integer item from an array using "dot" notation.
+ */
+ public static function integer(ArrayAccess|array $array, string|int|null $key, ?int $default = null): int
+ {
+ $value = Arr::get($array, $key, $default);
+
+ if (! is_int($value)) {
+ throw new InvalidArgumentException(
+ sprintf('Array value for key [%s] must be an integer, %s found.', $key, gettype($value))
+ );
+ }
+
+ return $value;
+ }
+
+ /**
+ * Determines if an array is associative.
+ *
+ * An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
+ *
+ * @param array $array
+ * @return bool
+ */
+ public static function isAssoc(array $array)
+ {
+ return ! array_is_list($array);
+ }
+
+ /**
+ * Determines if an array is a list.
+ *
+ * An array is a "list" if all array keys are sequential integers starting from 0 with no gaps in between.
+ *
+ * @param array $array
+ * @return bool
+ */
+ public static function isList($array)
+ {
+ return array_is_list($array);
+ }
+
+ /**
+ * Join all items using a string. The final items can use a separate glue string.
+ *
+ * @param array $array
+ * @param string $glue
+ * @param string $finalGlue
+ * @return string
+ */
+ public static function join($array, $glue, $finalGlue = '')
+ {
+ if ($finalGlue === '') {
+ return implode($glue, $array);
+ }
+
+ if (count($array) === 0) {
+ return '';
+ }
+
+ if (count($array) === 1) {
+ return array_last($array);
+ }
+
+ $finalItem = array_pop($array);
+
+ return implode($glue, $array).$finalGlue.$finalItem;
+ }
+
+ /**
+ * Key an associative array by a field or using a callback.
+ *
+ * @param array $array
+ * @param callable|array|string $keyBy
+ * @return array
+ */
+ public static function keyBy($array, $keyBy)
+ {
+ return (new Collection($array))->keyBy($keyBy)->all();
+ }
+
+ /**
+ * Prepend the key names of an associative array.
+ *
+ * @param array $array
+ * @param string $prependWith
+ * @return array
+ */
+ public static function prependKeysWith($array, $prependWith)
+ {
+ return static::mapWithKeys($array, fn ($item, $key) => [$prependWith.$key => $item]);
+ }
+
+ /**
+ * Get a subset of the items from the given array.
+ *
+ * @param array $array
+ * @param array|string $keys
+ * @return array
+ */
+ public static function only($array, $keys)
+ {
+ return array_intersect_key($array, array_flip((array) $keys));
+ }
+
+ /**
+ * Select an array of values from an array.
+ *
+ * @param array $array
+ * @param array|string $keys
+ * @return array
+ */
+ public static function select($array, $keys)
+ {
+ $keys = static::wrap($keys);
+
+ return static::map($array, function ($item) use ($keys) {
+ $result = [];
+
+ foreach ($keys as $key) {
+ if (Arr::accessible($item) && Arr::exists($item, $key)) {
+ $result[$key] = $item[$key];
+ } elseif (is_object($item) && isset($item->{$key})) {
+ $result[$key] = $item->{$key};
+ }
+ }
+
+ return $result;
+ });
+ }
+
+ /**
+ * Pluck an array of values from an array.
+ *
+ * @param iterable $array
+ * @param string|array|int|Closure|null $value
+ * @param string|array|Closure|null $key
+ * @return array
+ */
+ public static function pluck($array, $value, $key = null)
+ {
+ $results = [];
+
+ [$value, $key] = static::explodePluckParameters($value, $key);
+
+ foreach ($array as $item) {
+ $itemValue = $value instanceof Closure
+ ? $value($item)
+ : data_get($item, $value);
+
+ // If the key is "null", we will just append the value to the array and keep
+ // looping. Otherwise we will key the array using the value of the key we
+ // received from the developer. Then we'll return the final array form.
+ if (is_null($key)) {
+ $results[] = $itemValue;
+ } else {
+ $itemKey = $key instanceof Closure
+ ? $key($item)
+ : data_get($item, $key);
+
+ if (is_object($itemKey) && method_exists($itemKey, '__toString')) {
+ $itemKey = (string) $itemKey;
+ }
+
+ $results[$itemKey] = $itemValue;
+ }
+ }
+
+ return $results;
+ }
+
+ /**
+ * Explode the "value" and "key" arguments passed to "pluck".
+ *
+ * @param string|array|Closure $value
+ * @param string|array|Closure|null $key
+ * @return array
+ */
+ protected static function explodePluckParameters($value, $key)
+ {
+ $value = is_string($value) ? explode('.', $value) : $value;
+
+ $key = is_null($key) || is_array($key) || $key instanceof Closure ? $key : explode('.', $key);
+
+ return [$value, $key];
+ }
+
+ /**
+ * Run a map over each of the items in the array.
+ *
+ * @param array $array
+ * @param callable $callback
+ * @return array
+ */
+ public static function map(array $array, callable $callback)
+ {
+ $keys = array_keys($array);
+
+ try {
+ $items = array_map($callback, $array, $keys);
+ } catch (ArgumentCountError) {
+ $items = array_map($callback, $array);
+ }
+
+ return array_combine($keys, $items);
+ }
+
+ /**
+ * Run an associative map over each of the items.
+ *
+ * The callback should return an associative array with a single key/value pair.
+ *
+ * @template TKey
+ * @template TValue
+ * @template TMapWithKeysKey of array-key
+ * @template TMapWithKeysValue
+ *
+ * @param array $array
+ * @param callable(TValue, TKey): array $callback
+ * @return array
+ */
+ public static function mapWithKeys(array $array, callable $callback)
+ {
+ $result = [];
+
+ foreach ($array as $key => $value) {
+ $assoc = $callback($value, $key);
+
+ foreach ($assoc as $mapKey => $mapValue) {
+ $result[$mapKey] = $mapValue;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Run a map over each nested chunk of items.
+ *
+ * @template TKey
+ * @template TValue
+ *
+ * @param array $array
+ * @param callable(mixed...): TValue $callback
+ * @return array
+ */
+ public static function mapSpread(array $array, callable $callback)
+ {
+ return static::map($array, function ($chunk, $key) use ($callback) {
+ $chunk[] = $key;
+
+ return $callback(...$chunk);
+ });
+ }
+
+ /**
+ * Push an item onto the beginning of an array.
+ *
+ * @param array $array
+ * @param mixed $value
+ * @param mixed $key
+ * @return array
+ */
+ public static function prepend($array, $value, $key = null)
+ {
+ if (func_num_args() == 2) {
+ array_unshift($array, $value);
+ } else {
+ $array = [$key => $value] + $array;
+ }
+
+ return $array;
+ }
+
+ /**
+ * Get a value from the array, and remove it.
+ *
+ * @param array $array
+ * @param string|int $key
+ * @param mixed $default
+ * @return mixed
+ */
+ public static function pull(&$array, $key, $default = null)
+ {
+ $value = static::get($array, $key, $default);
+
+ static::forget($array, $key);
+
+ return $value;
+ }
+
+ /**
+ * Convert the array into a query string.
+ *
+ * @param array $array
+ * @return string
+ */
+ public static function query($array)
+ {
+ return http_build_query($array, '', '&', PHP_QUERY_RFC3986);
+ }
+
+ /**
+ * Get one or a specified number of random values from an array.
+ *
+ * @param array $array
+ * @param int|null $number
+ * @param bool $preserveKeys
+ * @return mixed
+ *
+ * @throws \InvalidArgumentException
+ */
+ public static function random($array, $number = null, $preserveKeys = false)
+ {
+ $requested = is_null($number) ? 1 : $number;
+
+ $count = count($array);
+
+ if ($requested > $count) {
+ throw new InvalidArgumentException(
+ "You requested {$requested} items, but there are only {$count} items available."
+ );
+ }
+
+ if (empty($array) || (! is_null($number) && $number <= 0)) {
+ return is_null($number) ? null : [];
+ }
+
+ $keys = (new Randomizer)->pickArrayKeys($array, $requested);
+
+ if (is_null($number)) {
+ return $array[$keys[0]];
+ }
+
+ $results = [];
+
+ if ($preserveKeys) {
+ foreach ($keys as $key) {
+ $results[$key] = $array[$key];
+ }
+ } else {
+ foreach ($keys as $key) {
+ $results[] = $array[$key];
+ }
+ }
+
+ return $results;
+ }
+
+ /**
+ * Set an array item to a given value using "dot" notation.
+ *
+ * If no key is given to the method, the entire array will be replaced.
+ *
+ * @param array $array
+ * @param string|int|null $key
+ * @param mixed $value
+ * @return array
+ */
+ public static function set(&$array, $key, $value)
+ {
+ if (is_null($key)) {
+ return $array = $value;
+ }
+
+ $keys = explode('.', $key);
+
+ foreach ($keys as $i => $key) {
+ if (count($keys) === 1) {
+ break;
+ }
+
+ unset($keys[$i]);
+
+ // If the key doesn't exist at this depth, we will just create an empty array
+ // to hold the next value, allowing us to create the arrays to hold final
+ // values at the correct depth. Then we'll keep digging into the array.
+ if (! isset($array[$key]) || ! is_array($array[$key])) {
+ $array[$key] = [];
+ }
+
+ $array = &$array[$key];
+ }
+
+ $array[array_shift($keys)] = $value;
+
+ return $array;
+ }
+
+ /**
+ * Push an item into an array using "dot" notation.
+ *
+ * @param \ArrayAccess|array $array
+ * @param string|int|null $key
+ * @param mixed $values
+ * @return array
+ */
+ public static function push(ArrayAccess|array &$array, string|int|null $key, mixed ...$values): array
+ {
+ $target = static::array($array, $key, []);
+
+ array_push($target, ...$values);
+
+ return static::set($array, $key, $target);
+ }
+
+ /**
+ * Shuffle the given array and return the result.
+ *
+ * @param array $array
+ * @return array
+ */
+ public static function shuffle($array)
+ {
+ return (new Randomizer)->shuffleArray($array);
+ }
+
+ /**
+ * Get the first item in the array, but only if exactly one item exists. Otherwise, throw an exception.
+ *
+ * @param array $array
+ * @param (callable(mixed, array-key): array)|null $callback
+ *
+ * @throws \Illuminate\Support\ItemNotFoundException
+ * @throws \Illuminate\Support\MultipleItemsFoundException
+ */
+ public static function sole($array, ?callable $callback = null)
+ {
+ if ($callback) {
+ $array = static::where($array, $callback);
+ }
+
+ $count = count($array);
+
+ if ($count === 0) {
+ throw new ItemNotFoundException;
+ }
+
+ if ($count > 1) {
+ throw new MultipleItemsFoundException($count);
+ }
+
+ return static::first($array);
+ }
+
+ /**
+ * Sort the array using the given callback or "dot" notation.
+ *
+ * @param array $array
+ * @param callable|array|string|null $callback
+ * @return array
+ */
+ public static function sort($array, $callback = null)
+ {
+ return (new Collection($array))->sortBy($callback)->all();
+ }
+
+ /**
+ * Sort the array in descending order using the given callback or "dot" notation.
+ *
+ * @param array $array
+ * @param callable|array|string|null $callback
+ * @return array
+ */
+ public static function sortDesc($array, $callback = null)
+ {
+ return (new Collection($array))->sortByDesc($callback)->all();
+ }
+
+ /**
+ * Recursively sort an array by keys and values.
+ *
+ * @param array $array
+ * @param int $options
+ * @param bool $descending
+ * @return array
+ */
+ public static function sortRecursive($array, $options = SORT_REGULAR, $descending = false)
+ {
+ foreach ($array as &$value) {
+ if (is_array($value)) {
+ $value = static::sortRecursive($value, $options, $descending);
+ }
+ }
+
+ if (! array_is_list($array)) {
+ $descending
+ ? krsort($array, $options)
+ : ksort($array, $options);
+ } else {
+ $descending
+ ? rsort($array, $options)
+ : sort($array, $options);
+ }
+
+ return $array;
+ }
+
+ /**
+ * Recursively sort an array by keys and values in descending order.
+ *
+ * @param array $array
+ * @param int $options
+ * @return array
+ */
+ public static function sortRecursiveDesc($array, $options = SORT_REGULAR)
+ {
+ return static::sortRecursive($array, $options, true);
+ }
+
+ /**
+ * Get a string item from an array using "dot" notation.
+ */
+ public static function string(ArrayAccess|array $array, string|int|null $key, ?string $default = null): string
+ {
+ $value = Arr::get($array, $key, $default);
+
+ if (! is_string($value)) {
+ throw new InvalidArgumentException(
+ sprintf('Array value for key [%s] must be a string, %s found.', $key, gettype($value))
+ );
+ }
+
+ return $value;
+ }
+
+ /**
+ * Conditionally compile classes from an array into a CSS class list.
+ *
+ * @param array|string $array
+ * @return string
+ */
+ public static function toCssClasses($array)
+ {
+ $classList = static::wrap($array);
+
+ $classes = [];
+
+ foreach ($classList as $class => $constraint) {
+ if (is_numeric($class)) {
+ $classes[] = $constraint;
+ } elseif ($constraint) {
+ $classes[] = $class;
+ }
+ }
+
+ return implode(' ', $classes);
+ }
+
+ /**
+ * Conditionally compile styles from an array into a style list.
+ *
+ * @param array|string $array
+ * @return string
+ */
+ public static function toCssStyles($array)
+ {
+ $styleList = static::wrap($array);
+
+ $styles = [];
+
+ foreach ($styleList as $class => $constraint) {
+ if (is_numeric($class)) {
+ $styles[] = Str::finish($constraint, ';');
+ } elseif ($constraint) {
+ $styles[] = Str::finish($class, ';');
+ }
+ }
+
+ return implode(' ', $styles);
+ }
+
+ /**
+ * Filter the array using the given callback.
+ *
+ * @param array $array
+ * @param callable $callback
+ * @return array
+ */
+ public static function where($array, callable $callback)
+ {
+ return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
+ }
+
+ /**
+ * Filter the array using the negation of the given callback.
+ *
+ * @param array $array
+ * @param callable $callback
+ * @return array
+ */
+ public static function reject($array, callable $callback)
+ {
+ return static::where($array, fn ($value, $key) => ! $callback($value, $key));
+ }
+
+ /**
+ * Partition the array into two arrays using the given callback.
+ *
+ * @template TKey of array-key
+ * @template TValue of mixed
+ *
+ * @param iterable $array
+ * @param callable(TValue, TKey): bool $callback
+ * @return array, array>
+ */
+ public static function partition($array, callable $callback)
+ {
+ $passed = [];
+ $failed = [];
+
+ foreach ($array as $key => $item) {
+ if ($callback($item, $key)) {
+ $passed[$key] = $item;
+ } else {
+ $failed[$key] = $item;
+ }
+ }
+
+ return [$passed, $failed];
+ }
+
+ /**
+ * Filter items where the value is not null.
+ *
+ * @param array $array
+ * @return array
+ */
+ public static function whereNotNull($array)
+ {
+ return static::where($array, fn ($value) => ! is_null($value));
+ }
+
+ /**
+ * If the given value is not an array and not null, wrap it in one.
+ *
+ * @param mixed $value
+ * @return array
+ */
+ public static function wrap($value)
+ {
+ if (is_null($value)) {
+ return [];
+ }
+
+ return is_array($value) ? $value : [$value];
+ }
+}
diff --git a/plugins/vendor/illuminate/collections/Collection.php b/plugins/vendor/illuminate/collections/Collection.php
new file mode 100644
index 00000000..b01db682
--- /dev/null
+++ b/plugins/vendor/illuminate/collections/Collection.php
@@ -0,0 +1,1934 @@
+
+ * @implements \Illuminate\Support\Enumerable
+ */
+class Collection implements ArrayAccess, CanBeEscapedWhenCastToString, Enumerable
+{
+ /**
+ * @use \Illuminate\Support\Traits\EnumeratesValues
+ */
+ use EnumeratesValues, Macroable, TransformsToResourceCollection;
+
+ /**
+ * The items contained in the collection.
+ *
+ * @var array
+ */
+ protected $items = [];
+
+ /**
+ * Create a new collection.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items
+ */
+ public function __construct($items = [])
+ {
+ $this->items = $this->getArrayableItems($items);
+ }
+
+ /**
+ * Create a collection with the given range.
+ *
+ * @param int $from
+ * @param int $to
+ * @param int $step
+ * @return static
+ */
+ public static function range($from, $to, $step = 1)
+ {
+ return new static(range($from, $to, $step));
+ }
+
+ /**
+ * Get all of the items in the collection.
+ *
+ * @return array
+ */
+ public function all()
+ {
+ return $this->items;
+ }
+
+ /**
+ * Get a lazy collection for the items in this collection.
+ *
+ * @return \Illuminate\Support\LazyCollection
+ */
+ public function lazy()
+ {
+ return new LazyCollection($this->items);
+ }
+
+ /**
+ * Get the median of a given key.
+ *
+ * @param string|array|null $key
+ * @return float|int|null
+ */
+ public function median($key = null)
+ {
+ $values = (isset($key) ? $this->pluck($key) : $this)
+ ->reject(fn ($item) => is_null($item))
+ ->sort()->values();
+
+ $count = $values->count();
+
+ if ($count === 0) {
+ return;
+ }
+
+ $middle = (int) ($count / 2);
+
+ if ($count % 2) {
+ return $values->get($middle);
+ }
+
+ return (new static([
+ $values->get($middle - 1), $values->get($middle),
+ ]))->average();
+ }
+
+ /**
+ * Get the mode of a given key.
+ *
+ * @param string|array|null $key
+ * @return array|null
+ */
+ public function mode($key = null)
+ {
+ if ($this->count() === 0) {
+ return;
+ }
+
+ $collection = isset($key) ? $this->pluck($key) : $this;
+
+ $counts = new static;
+
+ $collection->each(fn ($value) => $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1);
+
+ $sorted = $counts->sort();
+
+ $highestValue = $sorted->last();
+
+ return $sorted->filter(fn ($value) => $value == $highestValue)
+ ->sort()->keys()->all();
+ }
+
+ /**
+ * Collapse the collection of items into a single array.
+ *
+ * @return static
+ */
+ public function collapse()
+ {
+ return new static(Arr::collapse($this->items));
+ }
+
+ /**
+ * Collapse the collection of items into a single array while preserving its keys.
+ *
+ * @return static
+ */
+ public function collapseWithKeys()
+ {
+ if (! $this->items) {
+ return new static;
+ }
+
+ $results = [];
+
+ foreach ($this->items as $key => $values) {
+ if ($values instanceof Collection) {
+ $values = $values->all();
+ } elseif (! is_array($values)) {
+ continue;
+ }
+
+ $results[$key] = $values;
+ }
+
+ if (! $results) {
+ return new static;
+ }
+
+ return new static(array_replace(...$results));
+ }
+
+ /**
+ * Determine if an item exists in the collection.
+ *
+ * @param (callable(TValue, TKey): bool)|TValue|string $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return bool
+ */
+ public function contains($key, $operator = null, $value = null)
+ {
+ if (func_num_args() === 1) {
+ if ($this->useAsCallable($key)) {
+ return array_any($this->items, $key);
+ }
+
+ return in_array($key, $this->items);
+ }
+
+ return $this->contains($this->operatorForWhere(...func_get_args()));
+ }
+
+ /**
+ * Determine if an item exists, using strict comparison.
+ *
+ * @param (callable(TValue): bool)|TValue|array-key $key
+ * @param TValue|null $value
+ * @return bool
+ */
+ public function containsStrict($key, $value = null)
+ {
+ if (func_num_args() === 2) {
+ return $this->contains(fn ($item) => data_get($item, $key) === $value);
+ }
+
+ if ($this->useAsCallable($key)) {
+ return ! is_null($this->first($key));
+ }
+
+ return in_array($key, $this->items, true);
+ }
+
+ /**
+ * Determine if an item is not contained in the collection.
+ *
+ * @param mixed $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return bool
+ */
+ public function doesntContain($key, $operator = null, $value = null)
+ {
+ return ! $this->contains(...func_get_args());
+ }
+
+ /**
+ * Determine if an item is not contained in the enumerable, using strict comparison.
+ *
+ * @param mixed $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return bool
+ */
+ public function doesntContainStrict($key, $operator = null, $value = null)
+ {
+ return ! $this->containsStrict(...func_get_args());
+ }
+
+ /**
+ * Cross join with the given lists, returning all possible permutations.
+ *
+ * @template TCrossJoinKey
+ * @template TCrossJoinValue
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$lists
+ * @return static>
+ */
+ public function crossJoin(...$lists)
+ {
+ return new static(Arr::crossJoin(
+ $this->items, ...array_map($this->getArrayableItems(...), $lists)
+ ));
+ }
+
+ /**
+ * Get the items in the collection that are not present in the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function diff($items)
+ {
+ return new static(array_diff($this->items, $this->getArrayableItems($items)));
+ }
+
+ /**
+ * Get the items in the collection that are not present in the given items, using the callback.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @param callable(TValue, TValue): int $callback
+ * @return static
+ */
+ public function diffUsing($items, callable $callback)
+ {
+ return new static(array_udiff($this->items, $this->getArrayableItems($items), $callback));
+ }
+
+ /**
+ * Get the items in the collection whose keys and values are not present in the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function diffAssoc($items)
+ {
+ return new static(array_diff_assoc($this->items, $this->getArrayableItems($items)));
+ }
+
+ /**
+ * Get the items in the collection whose keys and values are not present in the given items, using the callback.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @param callable(TKey, TKey): int $callback
+ * @return static
+ */
+ public function diffAssocUsing($items, callable $callback)
+ {
+ return new static(array_diff_uassoc($this->items, $this->getArrayableItems($items), $callback));
+ }
+
+ /**
+ * Get the items in the collection whose keys are not present in the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function diffKeys($items)
+ {
+ return new static(array_diff_key($this->items, $this->getArrayableItems($items)));
+ }
+
+ /**
+ * Get the items in the collection whose keys are not present in the given items, using the callback.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @param callable(TKey, TKey): int $callback
+ * @return static
+ */
+ public function diffKeysUsing($items, callable $callback)
+ {
+ return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback));
+ }
+
+ /**
+ * Retrieve duplicate items from the collection.
+ *
+ * @template TMapValue
+ *
+ * @param (callable(TValue): TMapValue)|string|null $callback
+ * @param bool $strict
+ * @return static
+ */
+ public function duplicates($callback = null, $strict = false)
+ {
+ $items = $this->map($this->valueRetriever($callback));
+
+ $uniqueItems = $items->unique(null, $strict);
+
+ $compare = $this->duplicateComparator($strict);
+
+ $duplicates = new static;
+
+ foreach ($items as $key => $value) {
+ if ($uniqueItems->isNotEmpty() && $compare($value, $uniqueItems->first())) {
+ $uniqueItems->shift();
+ } else {
+ $duplicates[$key] = $value;
+ }
+ }
+
+ return $duplicates;
+ }
+
+ /**
+ * Retrieve duplicate items from the collection using strict comparison.
+ *
+ * @template TMapValue
+ *
+ * @param (callable(TValue): TMapValue)|string|null $callback
+ * @return static
+ */
+ public function duplicatesStrict($callback = null)
+ {
+ return $this->duplicates($callback, true);
+ }
+
+ /**
+ * Get the comparison function to detect duplicates.
+ *
+ * @param bool $strict
+ * @return callable(TValue, TValue): bool
+ */
+ protected function duplicateComparator($strict)
+ {
+ if ($strict) {
+ return fn ($a, $b) => $a === $b;
+ }
+
+ return fn ($a, $b) => $a == $b;
+ }
+
+ /**
+ * Get all items except for those with the specified keys.
+ *
+ * @param \Illuminate\Support\Enumerable|array|string $keys
+ * @return static
+ */
+ public function except($keys)
+ {
+ if (is_null($keys)) {
+ return new static($this->items);
+ }
+
+ if ($keys instanceof Enumerable) {
+ $keys = $keys->all();
+ } elseif (! is_array($keys)) {
+ $keys = func_get_args();
+ }
+
+ return new static(Arr::except($this->items, $keys));
+ }
+
+ /**
+ * Run a filter over each of the items.
+ *
+ * @param (callable(TValue, TKey): bool)|null $callback
+ * @return static
+ */
+ public function filter(?callable $callback = null)
+ {
+ if ($callback) {
+ return new static(Arr::where($this->items, $callback));
+ }
+
+ return new static(array_filter($this->items));
+ }
+
+ /**
+ * Get the first item from the collection passing the given truth test.
+ *
+ * @template TFirstDefault
+ *
+ * @param (callable(TValue, TKey): bool)|null $callback
+ * @param TFirstDefault|(\Closure(): TFirstDefault) $default
+ * @return TValue|TFirstDefault
+ */
+ public function first(?callable $callback = null, $default = null)
+ {
+ return Arr::first($this->items, $callback, $default);
+ }
+
+ /**
+ * Get a flattened array of the items in the collection.
+ *
+ * @param int $depth
+ * @return static
+ */
+ public function flatten($depth = INF)
+ {
+ return new static(Arr::flatten($this->items, $depth));
+ }
+
+ /**
+ * Flip the items in the collection.
+ *
+ * @return static
+ */
+ public function flip()
+ {
+ return new static(array_flip($this->items));
+ }
+
+ /**
+ * Remove an item from the collection by key.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable|TKey $keys
+ * @return $this
+ */
+ public function forget($keys)
+ {
+ foreach ($this->getArrayableItems($keys) as $key) {
+ $this->offsetUnset($key);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get an item from the collection by key.
+ *
+ * @template TGetDefault
+ *
+ * @param TKey $key
+ * @param TGetDefault|(\Closure(): TGetDefault) $default
+ * @return TValue|TGetDefault
+ */
+ public function get($key, $default = null)
+ {
+ if (array_key_exists($key, $this->items)) {
+ return $this->items[$key];
+ }
+
+ return value($default);
+ }
+
+ /**
+ * Get an item from the collection by key or add it to collection if it does not exist.
+ *
+ * @template TGetOrPutValue
+ *
+ * @param mixed $key
+ * @param TGetOrPutValue|(\Closure(): TGetOrPutValue) $value
+ * @return TValue|TGetOrPutValue
+ */
+ public function getOrPut($key, $value)
+ {
+ if (array_key_exists($key, $this->items)) {
+ return $this->items[$key];
+ }
+
+ $this->offsetSet($key, $value = value($value));
+
+ return $value;
+ }
+
+ /**
+ * Group an associative array by a field or using a callback.
+ *
+ * @template TGroupKey of array-key
+ *
+ * @param (callable(TValue, TKey): TGroupKey)|array|string $groupBy
+ * @param bool $preserveKeys
+ * @return static<($groupBy is string ? array-key : ($groupBy is array ? array-key : TGroupKey)), static<($preserveKeys is true ? TKey : int), ($groupBy is array ? mixed : TValue)>>
+ */
+ public function groupBy($groupBy, $preserveKeys = false)
+ {
+ if (! $this->useAsCallable($groupBy) && is_array($groupBy)) {
+ $nextGroups = $groupBy;
+
+ $groupBy = array_shift($nextGroups);
+ }
+
+ $groupBy = $this->valueRetriever($groupBy);
+
+ $results = [];
+
+ foreach ($this->items as $key => $value) {
+ $groupKeys = $groupBy($value, $key);
+
+ if (! is_array($groupKeys)) {
+ $groupKeys = [$groupKeys];
+ }
+
+ foreach ($groupKeys as $groupKey) {
+ $groupKey = match (true) {
+ is_bool($groupKey) => (int) $groupKey,
+ $groupKey instanceof \UnitEnum => enum_value($groupKey),
+ $groupKey instanceof \Stringable => (string) $groupKey,
+ default => $groupKey,
+ };
+
+ if (! array_key_exists($groupKey, $results)) {
+ $results[$groupKey] = new static;
+ }
+
+ $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
+ }
+ }
+
+ $result = new static($results);
+
+ if (! empty($nextGroups)) {
+ return $result->map->groupBy($nextGroups, $preserveKeys);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Key an associative array by a field or using a callback.
+ *
+ * @template TNewKey of array-key
+ *
+ * @param (callable(TValue, TKey): TNewKey)|array|string $keyBy
+ * @return static<($keyBy is string ? array-key : ($keyBy is array ? array-key : TNewKey)), TValue>
+ */
+ public function keyBy($keyBy)
+ {
+ $keyBy = $this->valueRetriever($keyBy);
+
+ $results = [];
+
+ foreach ($this->items as $key => $item) {
+ $resolvedKey = $keyBy($item, $key);
+
+ if ($resolvedKey instanceof \UnitEnum) {
+ $resolvedKey = enum_value($resolvedKey);
+ }
+
+ if (is_object($resolvedKey)) {
+ $resolvedKey = (string) $resolvedKey;
+ }
+
+ $results[$resolvedKey] = $item;
+ }
+
+ return new static($results);
+ }
+
+ /**
+ * Determine if an item exists in the collection by key.
+ *
+ * @param TKey|array $key
+ * @return bool
+ */
+ public function has($key)
+ {
+ $keys = is_array($key) ? $key : func_get_args();
+
+ return array_all($keys, fn ($key) => array_key_exists($key, $this->items));
+ }
+
+ /**
+ * Determine if any of the keys exist in the collection.
+ *
+ * @param TKey|array $key
+ * @return bool
+ */
+ public function hasAny($key)
+ {
+ if ($this->isEmpty()) {
+ return false;
+ }
+
+ $keys = is_array($key) ? $key : func_get_args();
+
+ return array_any($keys, fn ($key) => array_key_exists($key, $this->items));
+ }
+
+ /**
+ * Concatenate values of a given key as a string.
+ *
+ * @param (callable(TValue, TKey): mixed)|string|null $value
+ * @param string|null $glue
+ * @return string
+ */
+ public function implode($value, $glue = null)
+ {
+ if ($this->useAsCallable($value)) {
+ return implode($glue ?? '', $this->map($value)->all());
+ }
+
+ $first = $this->first();
+
+ if (is_array($first) || (is_object($first) && ! $first instanceof Stringable)) {
+ return implode($glue ?? '', $this->pluck($value)->all());
+ }
+
+ return implode($value ?? '', $this->items);
+ }
+
+ /**
+ * Intersect the collection with the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function intersect($items)
+ {
+ return new static(array_intersect($this->items, $this->getArrayableItems($items)));
+ }
+
+ /**
+ * Intersect the collection with the given items, using the callback.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @param callable(TValue, TValue): int $callback
+ * @return static
+ */
+ public function intersectUsing($items, callable $callback)
+ {
+ return new static(array_uintersect($this->items, $this->getArrayableItems($items), $callback));
+ }
+
+ /**
+ * Intersect the collection with the given items with additional index check.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function intersectAssoc($items)
+ {
+ return new static(array_intersect_assoc($this->items, $this->getArrayableItems($items)));
+ }
+
+ /**
+ * Intersect the collection with the given items with additional index check, using the callback.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @param callable(TValue, TValue): int $callback
+ * @return static
+ */
+ public function intersectAssocUsing($items, callable $callback)
+ {
+ return new static(array_intersect_uassoc($this->items, $this->getArrayableItems($items), $callback));
+ }
+
+ /**
+ * Intersect the collection with the given items by key.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function intersectByKeys($items)
+ {
+ return new static(array_intersect_key(
+ $this->items, $this->getArrayableItems($items)
+ ));
+ }
+
+ /**
+ * Determine if the collection is empty or not.
+ *
+ * @phpstan-assert-if-true null $this->first()
+ * @phpstan-assert-if-true null $this->last()
+ *
+ * @phpstan-assert-if-false TValue $this->first()
+ * @phpstan-assert-if-false TValue $this->last()
+ *
+ * @return bool
+ */
+ public function isEmpty()
+ {
+ return empty($this->items);
+ }
+
+ /**
+ * Determine if the collection contains exactly one item. If a callback is provided, determine if exactly one item matches the condition.
+ *
+ * @param (callable(TValue, TKey): bool)|null $callback
+ * @return bool
+ */
+ public function containsOneItem(?callable $callback = null): bool
+ {
+ if ($callback) {
+ return $this->filter($callback)->count() === 1;
+ }
+
+ return $this->count() === 1;
+ }
+
+ /**
+ * Join all items from the collection using a string. The final items can use a separate glue string.
+ *
+ * @param string $glue
+ * @param string $finalGlue
+ * @return string
+ */
+ public function join($glue, $finalGlue = '')
+ {
+ if ($finalGlue === '') {
+ return $this->implode($glue);
+ }
+
+ $count = $this->count();
+
+ if ($count === 0) {
+ return '';
+ }
+
+ if ($count === 1) {
+ return $this->last();
+ }
+
+ $collection = new static($this->items);
+
+ $finalItem = $collection->pop();
+
+ return $collection->implode($glue).$finalGlue.$finalItem;
+ }
+
+ /**
+ * Get the keys of the collection items.
+ *
+ * @return static
+ */
+ public function keys()
+ {
+ return new static(array_keys($this->items));
+ }
+
+ /**
+ * Get the last item from the collection.
+ *
+ * @template TLastDefault
+ *
+ * @param (callable(TValue, TKey): bool)|null $callback
+ * @param TLastDefault|(\Closure(): TLastDefault) $default
+ * @return TValue|TLastDefault
+ */
+ public function last(?callable $callback = null, $default = null)
+ {
+ return Arr::last($this->items, $callback, $default);
+ }
+
+ /**
+ * Get the values of a given key.
+ *
+ * @param string|int|array|null $value
+ * @param string|null $key
+ * @return static
+ */
+ public function pluck($value, $key = null)
+ {
+ return new static(Arr::pluck($this->items, $value, $key));
+ }
+
+ /**
+ * Run a map over each of the items.
+ *
+ * @template TMapValue
+ *
+ * @param callable(TValue, TKey): TMapValue $callback
+ * @return static
+ */
+ public function map(callable $callback)
+ {
+ return new static(Arr::map($this->items, $callback));
+ }
+
+ /**
+ * Run a dictionary map over the items.
+ *
+ * The callback should return an associative array with a single key/value pair.
+ *
+ * @template TMapToDictionaryKey of array-key
+ * @template TMapToDictionaryValue
+ *
+ * @param callable(TValue, TKey): array $callback
+ * @return static>
+ */
+ public function mapToDictionary(callable $callback)
+ {
+ $dictionary = [];
+
+ foreach ($this->items as $key => $item) {
+ $pair = $callback($item, $key);
+
+ $key = key($pair);
+
+ $value = reset($pair);
+
+ if (! isset($dictionary[$key])) {
+ $dictionary[$key] = [];
+ }
+
+ $dictionary[$key][] = $value;
+ }
+
+ return new static($dictionary);
+ }
+
+ /**
+ * Run an associative map over each of the items.
+ *
+ * The callback should return an associative array with a single key/value pair.
+ *
+ * @template TMapWithKeysKey of array-key
+ * @template TMapWithKeysValue
+ *
+ * @param callable(TValue, TKey): array $callback
+ * @return static
+ */
+ public function mapWithKeys(callable $callback)
+ {
+ return new static(Arr::mapWithKeys($this->items, $callback));
+ }
+
+ /**
+ * Merge the collection with the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function merge($items)
+ {
+ return new static(array_merge($this->items, $this->getArrayableItems($items)));
+ }
+
+ /**
+ * Recursively merge the collection with the given items.
+ *
+ * @template TMergeRecursiveValue
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function mergeRecursive($items)
+ {
+ return new static(array_merge_recursive($this->items, $this->getArrayableItems($items)));
+ }
+
+ /**
+ * Multiply the items in the collection by the multiplier.
+ *
+ * @param int $multiplier
+ * @return static
+ */
+ public function multiply(int $multiplier)
+ {
+ $new = new static;
+
+ for ($i = 0; $i < $multiplier; $i++) {
+ $new->push(...$this->items);
+ }
+
+ return $new;
+ }
+
+ /**
+ * Create a collection by using this collection for keys and another for its values.
+ *
+ * @template TCombineValue
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $values
+ * @return static
+ */
+ public function combine($values)
+ {
+ return new static(array_combine($this->all(), $this->getArrayableItems($values)));
+ }
+
+ /**
+ * Union the collection with the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function union($items)
+ {
+ return new static($this->items + $this->getArrayableItems($items));
+ }
+
+ /**
+ * Create a new collection consisting of every n-th element.
+ *
+ * @param int $step
+ * @param int $offset
+ * @return static
+ */
+ public function nth($step, $offset = 0)
+ {
+ $new = [];
+
+ $position = 0;
+
+ foreach ($this->slice($offset)->items as $item) {
+ if ($position % $step === 0) {
+ $new[] = $item;
+ }
+
+ $position++;
+ }
+
+ return new static($new);
+ }
+
+ /**
+ * Get the items with the specified keys.
+ *
+ * @param \Illuminate\Support\Enumerable|array|string|null $keys
+ * @return static
+ */
+ public function only($keys)
+ {
+ if (is_null($keys)) {
+ return new static($this->items);
+ }
+
+ if ($keys instanceof Enumerable) {
+ $keys = $keys->all();
+ }
+
+ $keys = is_array($keys) ? $keys : func_get_args();
+
+ return new static(Arr::only($this->items, $keys));
+ }
+
+ /**
+ * Select specific values from the items within the collection.
+ *
+ * @param \Illuminate\Support\Enumerable|array|string|null $keys
+ * @return static
+ */
+ public function select($keys)
+ {
+ if (is_null($keys)) {
+ return new static($this->items);
+ }
+
+ if ($keys instanceof Enumerable) {
+ $keys = $keys->all();
+ }
+
+ $keys = is_array($keys) ? $keys : func_get_args();
+
+ return new static(Arr::select($this->items, $keys));
+ }
+
+ /**
+ * Get and remove the last N items from the collection.
+ *
+ * @param int $count
+ * @return ($count is 1 ? TValue|null : static)
+ */
+ public function pop($count = 1)
+ {
+ if ($count < 1) {
+ return new static;
+ }
+
+ if ($count === 1) {
+ return array_pop($this->items);
+ }
+
+ if ($this->isEmpty()) {
+ return new static;
+ }
+
+ $results = [];
+
+ $collectionCount = $this->count();
+
+ foreach (range(1, min($count, $collectionCount)) as $item) {
+ $results[] = array_pop($this->items);
+ }
+
+ return new static($results);
+ }
+
+ /**
+ * Push an item onto the beginning of the collection.
+ *
+ * @param TValue $value
+ * @param TKey $key
+ * @return $this
+ */
+ public function prepend($value, $key = null)
+ {
+ $this->items = Arr::prepend($this->items, ...func_get_args());
+
+ return $this;
+ }
+
+ /**
+ * Push one or more items onto the end of the collection.
+ *
+ * @param TValue ...$values
+ * @return $this
+ */
+ public function push(...$values)
+ {
+ foreach ($values as $value) {
+ $this->items[] = $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Prepend one or more items to the beginning of the collection.
+ *
+ * @param TValue ...$values
+ * @return $this
+ */
+ public function unshift(...$values)
+ {
+ array_unshift($this->items, ...$values);
+
+ return $this;
+ }
+
+ /**
+ * Push all of the given items onto the collection.
+ *
+ * @template TConcatKey of array-key
+ * @template TConcatValue
+ *
+ * @param iterable $source
+ * @return static
+ */
+ public function concat($source)
+ {
+ $result = new static($this);
+
+ foreach ($source as $item) {
+ $result->push($item);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get and remove an item from the collection.
+ *
+ * @template TPullDefault
+ *
+ * @param TKey $key
+ * @param TPullDefault|(\Closure(): TPullDefault) $default
+ * @return TValue|TPullDefault
+ */
+ public function pull($key, $default = null)
+ {
+ return Arr::pull($this->items, $key, $default);
+ }
+
+ /**
+ * Put an item in the collection by key.
+ *
+ * @param TKey $key
+ * @param TValue $value
+ * @return $this
+ */
+ public function put($key, $value)
+ {
+ $this->offsetSet($key, $value);
+
+ return $this;
+ }
+
+ /**
+ * Get one or a specified number of items randomly from the collection.
+ *
+ * @param (callable(self): int)|int|null $number
+ * @param bool $preserveKeys
+ * @return ($number is null ? TValue : static)
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function random($number = null, $preserveKeys = false)
+ {
+ if (is_null($number)) {
+ return Arr::random($this->items);
+ }
+
+ if (is_callable($number)) {
+ return new static(Arr::random($this->items, $number($this), $preserveKeys));
+ }
+
+ return new static(Arr::random($this->items, $number, $preserveKeys));
+ }
+
+ /**
+ * Replace the collection items with the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function replace($items)
+ {
+ return new static(array_replace($this->items, $this->getArrayableItems($items)));
+ }
+
+ /**
+ * Recursively replace the collection items with the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function replaceRecursive($items)
+ {
+ return new static(array_replace_recursive($this->items, $this->getArrayableItems($items)));
+ }
+
+ /**
+ * Reverse items order.
+ *
+ * @return static
+ */
+ public function reverse()
+ {
+ return new static(array_reverse($this->items, true));
+ }
+
+ /**
+ * Search the collection for a given value and return the corresponding key if successful.
+ *
+ * @param TValue|(callable(TValue,TKey): bool) $value
+ * @param bool $strict
+ * @return TKey|false
+ */
+ public function search($value, $strict = false)
+ {
+ if (! $this->useAsCallable($value)) {
+ return array_search($value, $this->items, $strict);
+ }
+
+ return array_find_key($this->items, $value) ?? false;
+ }
+
+ /**
+ * Get the item before the given item.
+ *
+ * @param TValue|(callable(TValue,TKey): bool) $value
+ * @param bool $strict
+ * @return TValue|null
+ */
+ public function before($value, $strict = false)
+ {
+ $key = $this->search($value, $strict);
+
+ if ($key === false) {
+ return null;
+ }
+
+ $position = ($keys = $this->keys())->search($key);
+
+ if ($position === 0) {
+ return null;
+ }
+
+ return $this->get($keys->get($position - 1));
+ }
+
+ /**
+ * Get the item after the given item.
+ *
+ * @param TValue|(callable(TValue,TKey): bool) $value
+ * @param bool $strict
+ * @return TValue|null
+ */
+ public function after($value, $strict = false)
+ {
+ $key = $this->search($value, $strict);
+
+ if ($key === false) {
+ return null;
+ }
+
+ $position = ($keys = $this->keys())->search($key);
+
+ if ($position === $keys->count() - 1) {
+ return null;
+ }
+
+ return $this->get($keys->get($position + 1));
+ }
+
+ /**
+ * Get and remove the first N items from the collection.
+ *
+ * @param int<0, max> $count
+ * @return ($count is 1 ? TValue|null : static)
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function shift($count = 1)
+ {
+ if ($count < 0) {
+ throw new InvalidArgumentException('Number of shifted items may not be less than zero.');
+ }
+
+ if ($this->isEmpty()) {
+ return null;
+ }
+
+ if ($count === 0) {
+ return new static;
+ }
+
+ if ($count === 1) {
+ return array_shift($this->items);
+ }
+
+ $results = [];
+
+ $collectionCount = $this->count();
+
+ foreach (range(1, min($count, $collectionCount)) as $item) {
+ $results[] = array_shift($this->items);
+ }
+
+ return new static($results);
+ }
+
+ /**
+ * Shuffle the items in the collection.
+ *
+ * @return static
+ */
+ public function shuffle()
+ {
+ return new static(Arr::shuffle($this->items));
+ }
+
+ /**
+ * Create chunks representing a "sliding window" view of the items in the collection.
+ *
+ * @param int $size
+ * @param int $step
+ * @return static
+ */
+ public function sliding($size = 2, $step = 1)
+ {
+ $chunks = floor(($this->count() - $size) / $step) + 1;
+
+ return static::times($chunks, fn ($number) => $this->slice(($number - 1) * $step, $size));
+ }
+
+ /**
+ * Skip the first {$count} items.
+ *
+ * @param int $count
+ * @return static
+ */
+ public function skip($count)
+ {
+ return $this->slice($count);
+ }
+
+ /**
+ * Skip items in the collection until the given condition is met.
+ *
+ * @param TValue|callable(TValue,TKey): bool $value
+ * @return static
+ */
+ public function skipUntil($value)
+ {
+ return new static($this->lazy()->skipUntil($value)->all());
+ }
+
+ /**
+ * Skip items in the collection while the given condition is met.
+ *
+ * @param TValue|callable(TValue,TKey): bool $value
+ * @return static
+ */
+ public function skipWhile($value)
+ {
+ return new static($this->lazy()->skipWhile($value)->all());
+ }
+
+ /**
+ * Slice the underlying collection array.
+ *
+ * @param int $offset
+ * @param int|null $length
+ * @return static
+ */
+ public function slice($offset, $length = null)
+ {
+ return new static(array_slice($this->items, $offset, $length, true));
+ }
+
+ /**
+ * Split a collection into a certain number of groups.
+ *
+ * @param int $numberOfGroups
+ * @return static
+ */
+ public function split($numberOfGroups)
+ {
+ if ($this->isEmpty()) {
+ return new static;
+ }
+
+ $groups = new static;
+
+ $groupSize = floor($this->count() / $numberOfGroups);
+
+ $remain = $this->count() % $numberOfGroups;
+
+ $start = 0;
+
+ for ($i = 0; $i < $numberOfGroups; $i++) {
+ $size = $groupSize;
+
+ if ($i < $remain) {
+ $size++;
+ }
+
+ if ($size) {
+ $groups->push(new static(array_slice($this->items, $start, $size)));
+
+ $start += $size;
+ }
+ }
+
+ return $groups;
+ }
+
+ /**
+ * Split a collection into a certain number of groups, and fill the first groups completely.
+ *
+ * @param int $numberOfGroups
+ * @return static
+ */
+ public function splitIn($numberOfGroups)
+ {
+ return $this->chunk((int) ceil($this->count() / $numberOfGroups));
+ }
+
+ /**
+ * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception.
+ *
+ * @param (callable(TValue, TKey): bool)|string $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return TValue
+ *
+ * @throws \Illuminate\Support\ItemNotFoundException
+ * @throws \Illuminate\Support\MultipleItemsFoundException
+ */
+ public function sole($key = null, $operator = null, $value = null)
+ {
+ $filter = func_num_args() > 1
+ ? $this->operatorForWhere(...func_get_args())
+ : $key;
+
+ $items = $this->unless($filter == null)->filter($filter);
+
+ $count = $items->count();
+
+ if ($count === 0) {
+ throw new ItemNotFoundException;
+ }
+
+ if ($count > 1) {
+ throw new MultipleItemsFoundException($count);
+ }
+
+ return $items->first();
+ }
+
+ /**
+ * Get the first item in the collection but throw an exception if no matching items exist.
+ *
+ * @param (callable(TValue, TKey): bool)|string $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return TValue
+ *
+ * @throws \Illuminate\Support\ItemNotFoundException
+ */
+ public function firstOrFail($key = null, $operator = null, $value = null)
+ {
+ $filter = func_num_args() > 1
+ ? $this->operatorForWhere(...func_get_args())
+ : $key;
+
+ $placeholder = new stdClass();
+
+ $item = $this->first($filter, $placeholder);
+
+ if ($item === $placeholder) {
+ throw new ItemNotFoundException;
+ }
+
+ return $item;
+ }
+
+ /**
+ * Chunk the collection into chunks of the given size.
+ *
+ * @param int $size
+ * @param bool $preserveKeys
+ * @return ($preserveKeys is true ? static : static>)
+ */
+ public function chunk($size, $preserveKeys = true)
+ {
+ if ($size <= 0) {
+ return new static;
+ }
+
+ $chunks = [];
+
+ foreach (array_chunk($this->items, $size, $preserveKeys) as $chunk) {
+ $chunks[] = new static($chunk);
+ }
+
+ return new static($chunks);
+ }
+
+ /**
+ * Chunk the collection into chunks with a callback.
+ *
+ * @param callable(TValue, TKey, static): bool $callback
+ * @return static>
+ */
+ public function chunkWhile(callable $callback)
+ {
+ return new static(
+ $this->lazy()->chunkWhile($callback)->mapInto(static::class)
+ );
+ }
+
+ /**
+ * Sort through each item with a callback.
+ *
+ * @param (callable(TValue, TValue): int)|null|int $callback
+ * @return static
+ */
+ public function sort($callback = null)
+ {
+ $items = $this->items;
+
+ $callback && is_callable($callback)
+ ? uasort($items, $callback)
+ : asort($items, $callback ?? SORT_REGULAR);
+
+ return new static($items);
+ }
+
+ /**
+ * Sort items in descending order.
+ *
+ * @param int $options
+ * @return static
+ */
+ public function sortDesc($options = SORT_REGULAR)
+ {
+ $items = $this->items;
+
+ arsort($items, $options);
+
+ return new static($items);
+ }
+
+ /**
+ * Sort the collection using the given callback.
+ *
+ * @param array|(callable(TValue, TKey): mixed)|string $callback
+ * @param int $options
+ * @param bool $descending
+ * @return static
+ */
+ public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
+ {
+ if (is_array($callback) && ! is_callable($callback)) {
+ return $this->sortByMany($callback, $options);
+ }
+
+ $results = [];
+
+ $callback = $this->valueRetriever($callback);
+
+ // First we will loop through the items and get the comparator from a callback
+ // function which we were given. Then, we will sort the returned values and
+ // grab all the corresponding values for the sorted keys from this array.
+ foreach ($this->items as $key => $value) {
+ $results[$key] = $callback($value, $key);
+ }
+
+ $descending ? arsort($results, $options)
+ : asort($results, $options);
+
+ // Once we have sorted all of the keys in the array, we will loop through them
+ // and grab the corresponding model so we can set the underlying items list
+ // to the sorted version. Then we'll just return the collection instance.
+ foreach (array_keys($results) as $key) {
+ $results[$key] = $this->items[$key];
+ }
+
+ return new static($results);
+ }
+
+ /**
+ * Sort the collection using multiple comparisons.
+ *
+ * @param array $comparisons
+ * @param int $options
+ * @return static
+ */
+ protected function sortByMany(array $comparisons = [], int $options = SORT_REGULAR)
+ {
+ $items = $this->items;
+
+ uasort($items, function ($a, $b) use ($comparisons, $options) {
+ foreach ($comparisons as $comparison) {
+ $comparison = Arr::wrap($comparison);
+
+ $prop = $comparison[0];
+
+ $ascending = Arr::get($comparison, 1, true) === true ||
+ Arr::get($comparison, 1, true) === 'asc';
+
+ if (! is_string($prop) && is_callable($prop)) {
+ $result = $prop($a, $b);
+ } else {
+ $values = [data_get($a, $prop), data_get($b, $prop)];
+
+ if (! $ascending) {
+ $values = array_reverse($values);
+ }
+
+ if (($options & SORT_FLAG_CASE) === SORT_FLAG_CASE) {
+ if (($options & SORT_NATURAL) === SORT_NATURAL) {
+ $result = strnatcasecmp($values[0], $values[1]);
+ } else {
+ $result = strcasecmp($values[0], $values[1]);
+ }
+ } else {
+ $result = match ($options) {
+ SORT_NUMERIC => intval($values[0]) <=> intval($values[1]),
+ SORT_STRING => strcmp($values[0], $values[1]),
+ SORT_NATURAL => strnatcmp((string) $values[0], (string) $values[1]),
+ SORT_LOCALE_STRING => strcoll($values[0], $values[1]),
+ default => $values[0] <=> $values[1],
+ };
+ }
+ }
+
+ if ($result === 0) {
+ continue;
+ }
+
+ return $result;
+ }
+ });
+
+ return new static($items);
+ }
+
+ /**
+ * Sort the collection in descending order using the given callback.
+ *
+ * @param array|(callable(TValue, TKey): mixed)|string $callback
+ * @param int $options
+ * @return static
+ */
+ public function sortByDesc($callback, $options = SORT_REGULAR)
+ {
+ if (is_array($callback) && ! is_callable($callback)) {
+ foreach ($callback as $index => $key) {
+ $comparison = Arr::wrap($key);
+
+ $comparison[1] = 'desc';
+
+ $callback[$index] = $comparison;
+ }
+ }
+
+ return $this->sortBy($callback, $options, true);
+ }
+
+ /**
+ * Sort the collection keys.
+ *
+ * @param int $options
+ * @param bool $descending
+ * @return static
+ */
+ public function sortKeys($options = SORT_REGULAR, $descending = false)
+ {
+ $items = $this->items;
+
+ $descending ? krsort($items, $options) : ksort($items, $options);
+
+ return new static($items);
+ }
+
+ /**
+ * Sort the collection keys in descending order.
+ *
+ * @param int $options
+ * @return static
+ */
+ public function sortKeysDesc($options = SORT_REGULAR)
+ {
+ return $this->sortKeys($options, true);
+ }
+
+ /**
+ * Sort the collection keys using a callback.
+ *
+ * @param callable(TKey, TKey): int $callback
+ * @return static
+ */
+ public function sortKeysUsing(callable $callback)
+ {
+ $items = $this->items;
+
+ uksort($items, $callback);
+
+ return new static($items);
+ }
+
+ /**
+ * Splice a portion of the underlying collection array.
+ *
+ * @param int $offset
+ * @param int|null $length
+ * @param array $replacement
+ * @return static
+ */
+ public function splice($offset, $length = null, $replacement = [])
+ {
+ if (func_num_args() === 1) {
+ return new static(array_splice($this->items, $offset));
+ }
+
+ return new static(array_splice($this->items, $offset, $length, $this->getArrayableItems($replacement)));
+ }
+
+ /**
+ * Take the first or last {$limit} items.
+ *
+ * @param int $limit
+ * @return static
+ */
+ public function take($limit)
+ {
+ if ($limit < 0) {
+ return $this->slice($limit, abs($limit));
+ }
+
+ return $this->slice(0, $limit);
+ }
+
+ /**
+ * Take items in the collection until the given condition is met.
+ *
+ * @param TValue|callable(TValue,TKey): bool $value
+ * @return static
+ */
+ public function takeUntil($value)
+ {
+ return new static($this->lazy()->takeUntil($value)->all());
+ }
+
+ /**
+ * Take items in the collection while the given condition is met.
+ *
+ * @param TValue|callable(TValue,TKey): bool $value
+ * @return static
+ */
+ public function takeWhile($value)
+ {
+ return new static($this->lazy()->takeWhile($value)->all());
+ }
+
+ /**
+ * Transform each item in the collection using a callback.
+ *
+ * @template TMapValue
+ *
+ * @param callable(TValue, TKey): TMapValue $callback
+ * @return $this
+ *
+ * @phpstan-this-out static
+ */
+ public function transform(callable $callback)
+ {
+ $this->items = $this->map($callback)->all();
+
+ return $this;
+ }
+
+ /**
+ * Flatten a multi-dimensional associative array with dots.
+ *
+ * @return static
+ */
+ public function dot()
+ {
+ return new static(Arr::dot($this->all()));
+ }
+
+ /**
+ * Convert a flatten "dot" notation array into an expanded array.
+ *
+ * @return static
+ */
+ public function undot()
+ {
+ return new static(Arr::undot($this->all()));
+ }
+
+ /**
+ * Return only unique items from the collection array.
+ *
+ * @param (callable(TValue, TKey): mixed)|string|null $key
+ * @param bool $strict
+ * @return static
+ */
+ public function unique($key = null, $strict = false)
+ {
+ if (is_null($key) && $strict === false) {
+ return new static(array_unique($this->items, SORT_REGULAR));
+ }
+
+ $callback = $this->valueRetriever($key);
+
+ $exists = [];
+
+ return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) {
+ if (in_array($id = $callback($item, $key), $exists, $strict)) {
+ return true;
+ }
+
+ $exists[] = $id;
+ });
+ }
+
+ /**
+ * Reset the keys on the underlying array.
+ *
+ * @return static
+ */
+ public function values()
+ {
+ return new static(array_values($this->items));
+ }
+
+ /**
+ * Zip the collection together with one or more arrays.
+ *
+ * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
+ * => [[1, 4], [2, 5], [3, 6]]
+ *
+ * @template TZipValue
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$items
+ * @return static>
+ */
+ public function zip($items)
+ {
+ $arrayableItems = array_map(fn ($items) => $this->getArrayableItems($items), func_get_args());
+
+ $params = array_merge([fn () => new static(func_get_args()), $this->items], $arrayableItems);
+
+ return new static(array_map(...$params));
+ }
+
+ /**
+ * Pad collection to the specified length with a value.
+ *
+ * @template TPadValue
+ *
+ * @param int $size
+ * @param TPadValue $value
+ * @return static
+ */
+ public function pad($size, $value)
+ {
+ return new static(array_pad($this->items, $size, $value));
+ }
+
+ /**
+ * Get an iterator for the items.
+ *
+ * @return \ArrayIterator
+ */
+ public function getIterator(): Traversable
+ {
+ return new ArrayIterator($this->items);
+ }
+
+ /**
+ * Count the number of items in the collection.
+ *
+ * @return int<0, max>
+ */
+ public function count(): int
+ {
+ return count($this->items);
+ }
+
+ /**
+ * Count the number of items in the collection by a field or using a callback.
+ *
+ * @param (callable(TValue, TKey): array-key|\UnitEnum)|string|null $countBy
+ * @return static
+ */
+ public function countBy($countBy = null)
+ {
+ return new static($this->lazy()->countBy($countBy)->all());
+ }
+
+ /**
+ * Add an item to the collection.
+ *
+ * @param TValue $item
+ * @return $this
+ */
+ public function add($item)
+ {
+ $this->items[] = $item;
+
+ return $this;
+ }
+
+ /**
+ * Get a base Support collection instance from this collection.
+ *
+ * @return \Illuminate\Support\Collection
+ */
+ public function toBase()
+ {
+ return new self($this);
+ }
+
+ /**
+ * Determine if an item exists at an offset.
+ *
+ * @param TKey $key
+ * @return bool
+ */
+ public function offsetExists($key): bool
+ {
+ return isset($this->items[$key]);
+ }
+
+ /**
+ * Get an item at a given offset.
+ *
+ * @param TKey $key
+ * @return TValue
+ */
+ public function offsetGet($key): mixed
+ {
+ return $this->items[$key];
+ }
+
+ /**
+ * Set the item at a given offset.
+ *
+ * @param TKey|null $key
+ * @param TValue $value
+ * @return void
+ */
+ public function offsetSet($key, $value): void
+ {
+ if (is_null($key)) {
+ $this->items[] = $value;
+ } else {
+ $this->items[$key] = $value;
+ }
+ }
+
+ /**
+ * Unset the item at a given offset.
+ *
+ * @param TKey $key
+ * @return void
+ */
+ public function offsetUnset($key): void
+ {
+ unset($this->items[$key]);
+ }
+}
diff --git a/plugins/vendor/illuminate/collections/Enumerable.php b/plugins/vendor/illuminate/collections/Enumerable.php
new file mode 100644
index 00000000..0b434804
--- /dev/null
+++ b/plugins/vendor/illuminate/collections/Enumerable.php
@@ -0,0 +1,1321 @@
+
+ * @extends \IteratorAggregate
+ */
+interface Enumerable extends Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable
+{
+ /**
+ * Create a new collection instance if the value isn't one already.
+ *
+ * @template TMakeKey of array-key
+ * @template TMakeValue
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items
+ * @return static
+ */
+ public static function make($items = []);
+
+ /**
+ * Create a new instance by invoking the callback a given amount of times.
+ *
+ * @param int $number
+ * @param callable|null $callback
+ * @return static
+ */
+ public static function times($number, ?callable $callback = null);
+
+ /**
+ * Create a collection with the given range.
+ *
+ * @param int $from
+ * @param int $to
+ * @param int $step
+ * @return static
+ */
+ public static function range($from, $to, $step = 1);
+
+ /**
+ * Wrap the given value in a collection if applicable.
+ *
+ * @template TWrapValue
+ *
+ * @param iterable|TWrapValue $value
+ * @return static
+ */
+ public static function wrap($value);
+
+ /**
+ * Get the underlying items from the given collection if applicable.
+ *
+ * @template TUnwrapKey of array-key
+ * @template TUnwrapValue
+ *
+ * @param array|static $value
+ * @return array
+ */
+ public static function unwrap($value);
+
+ /**
+ * Create a new instance with no items.
+ *
+ * @return static
+ */
+ public static function empty();
+
+ /**
+ * Get all items in the enumerable.
+ *
+ * @return array
+ */
+ public function all();
+
+ /**
+ * Alias for the "avg" method.
+ *
+ * @param (callable(TValue): float|int)|string|null $callback
+ * @return float|int|null
+ */
+ public function average($callback = null);
+
+ /**
+ * Get the median of a given key.
+ *
+ * @param string|array|null $key
+ * @return float|int|null
+ */
+ public function median($key = null);
+
+ /**
+ * Get the mode of a given key.
+ *
+ * @param string|array|null $key
+ * @return array|null
+ */
+ public function mode($key = null);
+
+ /**
+ * Collapse the items into a single enumerable.
+ *
+ * @return static
+ */
+ public function collapse();
+
+ /**
+ * Alias for the "contains" method.
+ *
+ * @param (callable(TValue, TKey): bool)|TValue|string $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return bool
+ */
+ public function some($key, $operator = null, $value = null);
+
+ /**
+ * Determine if an item exists, using strict comparison.
+ *
+ * @param (callable(TValue): bool)|TValue|array-key $key
+ * @param TValue|null $value
+ * @return bool
+ */
+ public function containsStrict($key, $value = null);
+
+ /**
+ * Get the average value of a given key.
+ *
+ * @param (callable(TValue): float|int)|string|null $callback
+ * @return float|int|null
+ */
+ public function avg($callback = null);
+
+ /**
+ * Determine if an item exists in the enumerable.
+ *
+ * @param (callable(TValue, TKey): bool)|TValue|string $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return bool
+ */
+ public function contains($key, $operator = null, $value = null);
+
+ /**
+ * Determine if an item is not contained in the collection.
+ *
+ * @param mixed $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return bool
+ */
+ public function doesntContain($key, $operator = null, $value = null);
+
+ /**
+ * Cross join with the given lists, returning all possible permutations.
+ *
+ * @template TCrossJoinKey
+ * @template TCrossJoinValue
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$lists
+ * @return static>
+ */
+ public function crossJoin(...$lists);
+
+ /**
+ * Dump the collection and end the script.
+ *
+ * @param mixed ...$args
+ * @return never
+ */
+ public function dd(...$args);
+
+ /**
+ * Dump the collection.
+ *
+ * @param mixed ...$args
+ * @return $this
+ */
+ public function dump(...$args);
+
+ /**
+ * Get the items that are not present in the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function diff($items);
+
+ /**
+ * Get the items that are not present in the given items, using the callback.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @param callable(TValue, TValue): int $callback
+ * @return static
+ */
+ public function diffUsing($items, callable $callback);
+
+ /**
+ * Get the items whose keys and values are not present in the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function diffAssoc($items);
+
+ /**
+ * Get the items whose keys and values are not present in the given items, using the callback.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @param callable(TKey, TKey): int $callback
+ * @return static
+ */
+ public function diffAssocUsing($items, callable $callback);
+
+ /**
+ * Get the items whose keys are not present in the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function diffKeys($items);
+
+ /**
+ * Get the items whose keys are not present in the given items, using the callback.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @param callable(TKey, TKey): int $callback
+ * @return static
+ */
+ public function diffKeysUsing($items, callable $callback);
+
+ /**
+ * Retrieve duplicate items.
+ *
+ * @param (callable(TValue): bool)|string|null $callback
+ * @param bool $strict
+ * @return static
+ */
+ public function duplicates($callback = null, $strict = false);
+
+ /**
+ * Retrieve duplicate items using strict comparison.
+ *
+ * @param (callable(TValue): bool)|string|null $callback
+ * @return static
+ */
+ public function duplicatesStrict($callback = null);
+
+ /**
+ * Execute a callback over each item.
+ *
+ * @param callable(TValue, TKey): mixed $callback
+ * @return $this
+ */
+ public function each(callable $callback);
+
+ /**
+ * Execute a callback over each nested chunk of items.
+ *
+ * @param callable $callback
+ * @return static
+ */
+ public function eachSpread(callable $callback);
+
+ /**
+ * Determine if all items pass the given truth test.
+ *
+ * @param (callable(TValue, TKey): bool)|TValue|string $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return bool
+ */
+ public function every($key, $operator = null, $value = null);
+
+ /**
+ * Get all items except for those with the specified keys.
+ *
+ * @param \Illuminate\Support\Enumerable|array $keys
+ * @return static
+ */
+ public function except($keys);
+
+ /**
+ * Run a filter over each of the items.
+ *
+ * @param (callable(TValue): bool)|null $callback
+ * @return static
+ */
+ public function filter(?callable $callback = null);
+
+ /**
+ * Apply the callback if the given "value" is (or resolves to) truthy.
+ *
+ * @template TWhenReturnType as null
+ *
+ * @param bool $value
+ * @param (callable($this): TWhenReturnType)|null $callback
+ * @param (callable($this): TWhenReturnType)|null $default
+ * @return $this|TWhenReturnType
+ */
+ public function when($value, ?callable $callback = null, ?callable $default = null);
+
+ /**
+ * Apply the callback if the collection is empty.
+ *
+ * @template TWhenEmptyReturnType
+ *
+ * @param (callable($this): TWhenEmptyReturnType) $callback
+ * @param (callable($this): TWhenEmptyReturnType)|null $default
+ * @return $this|TWhenEmptyReturnType
+ */
+ public function whenEmpty(callable $callback, ?callable $default = null);
+
+ /**
+ * Apply the callback if the collection is not empty.
+ *
+ * @template TWhenNotEmptyReturnType
+ *
+ * @param callable($this): TWhenNotEmptyReturnType $callback
+ * @param (callable($this): TWhenNotEmptyReturnType)|null $default
+ * @return $this|TWhenNotEmptyReturnType
+ */
+ public function whenNotEmpty(callable $callback, ?callable $default = null);
+
+ /**
+ * Apply the callback if the given "value" is (or resolves to) falsy.
+ *
+ * @template TUnlessReturnType
+ *
+ * @param bool $value
+ * @param (callable($this): TUnlessReturnType) $callback
+ * @param (callable($this): TUnlessReturnType)|null $default
+ * @return $this|TUnlessReturnType
+ */
+ public function unless($value, callable $callback, ?callable $default = null);
+
+ /**
+ * Apply the callback unless the collection is empty.
+ *
+ * @template TUnlessEmptyReturnType
+ *
+ * @param callable($this): TUnlessEmptyReturnType $callback
+ * @param (callable($this): TUnlessEmptyReturnType)|null $default
+ * @return $this|TUnlessEmptyReturnType
+ */
+ public function unlessEmpty(callable $callback, ?callable $default = null);
+
+ /**
+ * Apply the callback unless the collection is not empty.
+ *
+ * @template TUnlessNotEmptyReturnType
+ *
+ * @param callable($this): TUnlessNotEmptyReturnType $callback
+ * @param (callable($this): TUnlessNotEmptyReturnType)|null $default
+ * @return $this|TUnlessNotEmptyReturnType
+ */
+ public function unlessNotEmpty(callable $callback, ?callable $default = null);
+
+ /**
+ * Filter items by the given key value pair.
+ *
+ * @param string $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return static
+ */
+ public function where($key, $operator = null, $value = null);
+
+ /**
+ * Filter items where the value for the given key is null.
+ *
+ * @param string|null $key
+ * @return static
+ */
+ public function whereNull($key = null);
+
+ /**
+ * Filter items where the value for the given key is not null.
+ *
+ * @param string|null $key
+ * @return static
+ */
+ public function whereNotNull($key = null);
+
+ /**
+ * Filter items by the given key value pair using strict comparison.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return static
+ */
+ public function whereStrict($key, $value);
+
+ /**
+ * Filter items by the given key value pair.
+ *
+ * @param string $key
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $values
+ * @param bool $strict
+ * @return static
+ */
+ public function whereIn($key, $values, $strict = false);
+
+ /**
+ * Filter items by the given key value pair using strict comparison.
+ *
+ * @param string $key
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $values
+ * @return static
+ */
+ public function whereInStrict($key, $values);
+
+ /**
+ * Filter items such that the value of the given key is between the given values.
+ *
+ * @param string $key
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $values
+ * @return static
+ */
+ public function whereBetween($key, $values);
+
+ /**
+ * Filter items such that the value of the given key is not between the given values.
+ *
+ * @param string $key
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $values
+ * @return static
+ */
+ public function whereNotBetween($key, $values);
+
+ /**
+ * Filter items by the given key value pair.
+ *
+ * @param string $key
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $values
+ * @param bool $strict
+ * @return static
+ */
+ public function whereNotIn($key, $values, $strict = false);
+
+ /**
+ * Filter items by the given key value pair using strict comparison.
+ *
+ * @param string $key
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $values
+ * @return static
+ */
+ public function whereNotInStrict($key, $values);
+
+ /**
+ * Filter the items, removing any items that don't match the given type(s).
+ *
+ * @template TWhereInstanceOf
+ *
+ * @param class-string|array> $type
+ * @return static
+ */
+ public function whereInstanceOf($type);
+
+ /**
+ * Get the first item from the enumerable passing the given truth test.
+ *
+ * @template TFirstDefault
+ *
+ * @param (callable(TValue,TKey): bool)|null $callback
+ * @param TFirstDefault|(\Closure(): TFirstDefault) $default
+ * @return TValue|TFirstDefault
+ */
+ public function first(?callable $callback = null, $default = null);
+
+ /**
+ * Get the first item by the given key value pair.
+ *
+ * @param string $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return TValue|null
+ */
+ public function firstWhere($key, $operator = null, $value = null);
+
+ /**
+ * Get a flattened array of the items in the collection.
+ *
+ * @param int $depth
+ * @return static
+ */
+ public function flatten($depth = INF);
+
+ /**
+ * Flip the values with their keys.
+ *
+ * @return static
+ */
+ public function flip();
+
+ /**
+ * Get an item from the collection by key.
+ *
+ * @template TGetDefault
+ *
+ * @param TKey $key
+ * @param TGetDefault|(\Closure(): TGetDefault) $default
+ * @return TValue|TGetDefault
+ */
+ public function get($key, $default = null);
+
+ /**
+ * Group an associative array by a field or using a callback.
+ *
+ * @template TGroupKey of array-key
+ *
+ * @param (callable(TValue, TKey): TGroupKey)|array|string $groupBy
+ * @param bool $preserveKeys
+ * @return static<($groupBy is string ? array-key : ($groupBy is array ? array-key : TGroupKey)), static<($preserveKeys is true ? TKey : int), ($groupBy is array ? mixed : TValue)>>
+ */
+ public function groupBy($groupBy, $preserveKeys = false);
+
+ /**
+ * Key an associative array by a field or using a callback.
+ *
+ * @template TNewKey of array-key
+ *
+ * @param (callable(TValue, TKey): TNewKey)|array|string $keyBy
+ * @return static<($keyBy is string ? array-key : ($keyBy is array ? array-key : TNewKey)), TValue>
+ */
+ public function keyBy($keyBy);
+
+ /**
+ * Determine if an item exists in the collection by key.
+ *
+ * @param TKey|array $key
+ * @return bool
+ */
+ public function has($key);
+
+ /**
+ * Determine if any of the keys exist in the collection.
+ *
+ * @param mixed $key
+ * @return bool
+ */
+ public function hasAny($key);
+
+ /**
+ * Concatenate values of a given key as a string.
+ *
+ * @param (callable(TValue, TKey): mixed)|string $value
+ * @param string|null $glue
+ * @return string
+ */
+ public function implode($value, $glue = null);
+
+ /**
+ * Intersect the collection with the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function intersect($items);
+
+ /**
+ * Intersect the collection with the given items, using the callback.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @param callable(TValue, TValue): int $callback
+ * @return static
+ */
+ public function intersectUsing($items, callable $callback);
+
+ /**
+ * Intersect the collection with the given items with additional index check.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function intersectAssoc($items);
+
+ /**
+ * Intersect the collection with the given items with additional index check, using the callback.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @param callable(TValue, TValue): int $callback
+ * @return static
+ */
+ public function intersectAssocUsing($items, callable $callback);
+
+ /**
+ * Intersect the collection with the given items by key.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function intersectByKeys($items);
+
+ /**
+ * Determine if the collection is empty or not.
+ *
+ * @return bool
+ */
+ public function isEmpty();
+
+ /**
+ * Determine if the collection is not empty.
+ *
+ * @return bool
+ */
+ public function isNotEmpty();
+
+ /**
+ * Determine if the collection contains a single item.
+ *
+ * @return bool
+ */
+ public function containsOneItem();
+
+ /**
+ * Join all items from the collection using a string. The final items can use a separate glue string.
+ *
+ * @param string $glue
+ * @param string $finalGlue
+ * @return string
+ */
+ public function join($glue, $finalGlue = '');
+
+ /**
+ * Get the keys of the collection items.
+ *
+ * @return static
+ */
+ public function keys();
+
+ /**
+ * Get the last item from the collection.
+ *
+ * @template TLastDefault
+ *
+ * @param (callable(TValue, TKey): bool)|null $callback
+ * @param TLastDefault|(\Closure(): TLastDefault) $default
+ * @return TValue|TLastDefault
+ */
+ public function last(?callable $callback = null, $default = null);
+
+ /**
+ * Run a map over each of the items.
+ *
+ * @template TMapValue
+ *
+ * @param callable(TValue, TKey): TMapValue $callback
+ * @return static
+ */
+ public function map(callable $callback);
+
+ /**
+ * Run a map over each nested chunk of items.
+ *
+ * @param callable $callback
+ * @return static
+ */
+ public function mapSpread(callable $callback);
+
+ /**
+ * Run a dictionary map over the items.
+ *
+ * The callback should return an associative array with a single key/value pair.
+ *
+ * @template TMapToDictionaryKey of array-key
+ * @template TMapToDictionaryValue
+ *
+ * @param callable(TValue, TKey): array $callback
+ * @return static>
+ */
+ public function mapToDictionary(callable $callback);
+
+ /**
+ * Run a grouping map over the items.
+ *
+ * The callback should return an associative array with a single key/value pair.
+ *
+ * @template TMapToGroupsKey of array-key
+ * @template TMapToGroupsValue
+ *
+ * @param callable(TValue, TKey): array $callback
+ * @return static>
+ */
+ public function mapToGroups(callable $callback);
+
+ /**
+ * Run an associative map over each of the items.
+ *
+ * The callback should return an associative array with a single key/value pair.
+ *
+ * @template TMapWithKeysKey of array-key
+ * @template TMapWithKeysValue
+ *
+ * @param callable(TValue, TKey): array $callback
+ * @return static
+ */
+ public function mapWithKeys(callable $callback);
+
+ /**
+ * Map a collection and flatten the result by a single level.
+ *
+ * @template TFlatMapKey of array-key
+ * @template TFlatMapValue
+ *
+ * @param callable(TValue, TKey): (\Illuminate\Support\Collection|array) $callback
+ * @return static
+ */
+ public function flatMap(callable $callback);
+
+ /**
+ * Map the values into a new class.
+ *
+ * @template TMapIntoValue
+ *
+ * @param class-string $class
+ * @return static
+ */
+ public function mapInto($class);
+
+ /**
+ * Merge the collection with the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function merge($items);
+
+ /**
+ * Recursively merge the collection with the given items.
+ *
+ * @template TMergeRecursiveValue
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function mergeRecursive($items);
+
+ /**
+ * Create a collection by using this collection for keys and another for its values.
+ *
+ * @template TCombineValue
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $values
+ * @return static
+ */
+ public function combine($values);
+
+ /**
+ * Union the collection with the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function union($items);
+
+ /**
+ * Get the min value of a given key.
+ *
+ * @param (callable(TValue):mixed)|string|null $callback
+ * @return mixed
+ */
+ public function min($callback = null);
+
+ /**
+ * Get the max value of a given key.
+ *
+ * @param (callable(TValue):mixed)|string|null $callback
+ * @return mixed
+ */
+ public function max($callback = null);
+
+ /**
+ * Create a new collection consisting of every n-th element.
+ *
+ * @param int $step
+ * @param int $offset
+ * @return static
+ */
+ public function nth($step, $offset = 0);
+
+ /**
+ * Get the items with the specified keys.
+ *
+ * @param \Illuminate\Support\Enumerable|array|string $keys
+ * @return static
+ */
+ public function only($keys);
+
+ /**
+ * "Paginate" the collection by slicing it into a smaller collection.
+ *
+ * @param int $page
+ * @param int $perPage
+ * @return static
+ */
+ public function forPage($page, $perPage);
+
+ /**
+ * Partition the collection into two arrays using the given callback or key.
+ *
+ * @param (callable(TValue, TKey): bool)|TValue|string $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return static, static>
+ */
+ public function partition($key, $operator = null, $value = null);
+
+ /**
+ * Push all of the given items onto the collection.
+ *
+ * @template TConcatKey of array-key
+ * @template TConcatValue
+ *
+ * @param iterable $source
+ * @return static
+ */
+ public function concat($source);
+
+ /**
+ * Get one or a specified number of items randomly from the collection.
+ *
+ * @param int|null $number
+ * @return static|TValue
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function random($number = null);
+
+ /**
+ * Reduce the collection to a single value.
+ *
+ * @template TReduceInitial
+ * @template TReduceReturnType
+ *
+ * @param callable(TReduceInitial|TReduceReturnType, TValue, TKey): TReduceReturnType $callback
+ * @param TReduceInitial $initial
+ * @return TReduceInitial|TReduceReturnType
+ */
+ public function reduce(callable $callback, $initial = null);
+
+ /**
+ * Reduce the collection to multiple aggregate values.
+ *
+ * @param callable $callback
+ * @param mixed ...$initial
+ * @return array
+ *
+ * @throws \UnexpectedValueException
+ */
+ public function reduceSpread(callable $callback, ...$initial);
+
+ /**
+ * Replace the collection items with the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function replace($items);
+
+ /**
+ * Recursively replace the collection items with the given items.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable $items
+ * @return static
+ */
+ public function replaceRecursive($items);
+
+ /**
+ * Reverse items order.
+ *
+ * @return static
+ */
+ public function reverse();
+
+ /**
+ * Search the collection for a given value and return the corresponding key if successful.
+ *
+ * @param TValue|callable(TValue,TKey): bool $value
+ * @param bool $strict
+ * @return TKey|bool
+ */
+ public function search($value, $strict = false);
+
+ /**
+ * Get the item before the given item.
+ *
+ * @param TValue|(callable(TValue,TKey): bool) $value
+ * @param bool $strict
+ * @return TValue|null
+ */
+ public function before($value, $strict = false);
+
+ /**
+ * Get the item after the given item.
+ *
+ * @param TValue|(callable(TValue,TKey): bool) $value
+ * @param bool $strict
+ * @return TValue|null
+ */
+ public function after($value, $strict = false);
+
+ /**
+ * Shuffle the items in the collection.
+ *
+ * @return static
+ */
+ public function shuffle();
+
+ /**
+ * Create chunks representing a "sliding window" view of the items in the collection.
+ *
+ * @param int $size
+ * @param int $step
+ * @return static
+ */
+ public function sliding($size = 2, $step = 1);
+
+ /**
+ * Skip the first {$count} items.
+ *
+ * @param int $count
+ * @return static
+ */
+ public function skip($count);
+
+ /**
+ * Skip items in the collection until the given condition is met.
+ *
+ * @param TValue|callable(TValue,TKey): bool $value
+ * @return static
+ */
+ public function skipUntil($value);
+
+ /**
+ * Skip items in the collection while the given condition is met.
+ *
+ * @param TValue|callable(TValue,TKey): bool $value
+ * @return static
+ */
+ public function skipWhile($value);
+
+ /**
+ * Get a slice of items from the enumerable.
+ *
+ * @param int $offset
+ * @param int|null $length
+ * @return static
+ */
+ public function slice($offset, $length = null);
+
+ /**
+ * Split a collection into a certain number of groups.
+ *
+ * @param int $numberOfGroups
+ * @return static
+ */
+ public function split($numberOfGroups);
+
+ /**
+ * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception.
+ *
+ * @param (callable(TValue, TKey): bool)|string $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return TValue
+ *
+ * @throws \Illuminate\Support\ItemNotFoundException
+ * @throws \Illuminate\Support\MultipleItemsFoundException
+ */
+ public function sole($key = null, $operator = null, $value = null);
+
+ /**
+ * Get the first item in the collection but throw an exception if no matching items exist.
+ *
+ * @param (callable(TValue, TKey): bool)|string $key
+ * @param mixed $operator
+ * @param mixed $value
+ * @return TValue
+ *
+ * @throws \Illuminate\Support\ItemNotFoundException
+ */
+ public function firstOrFail($key = null, $operator = null, $value = null);
+
+ /**
+ * Chunk the collection into chunks of the given size.
+ *
+ * @param int $size
+ * @return static
+ */
+ public function chunk($size);
+
+ /**
+ * Chunk the collection into chunks with a callback.
+ *
+ * @param callable(TValue, TKey, static): bool $callback
+ * @return static>
+ */
+ public function chunkWhile(callable $callback);
+
+ /**
+ * Split a collection into a certain number of groups, and fill the first groups completely.
+ *
+ * @param int $numberOfGroups
+ * @return static
+ */
+ public function splitIn($numberOfGroups);
+
+ /**
+ * Sort through each item with a callback.
+ *
+ * @param (callable(TValue, TValue): int)|null|int $callback
+ * @return static
+ */
+ public function sort($callback = null);
+
+ /**
+ * Sort items in descending order.
+ *
+ * @param int $options
+ * @return static
+ */
+ public function sortDesc($options = SORT_REGULAR);
+
+ /**
+ * Sort the collection using the given callback.
+ *
+ * @param array|(callable(TValue, TKey): mixed)|string $callback
+ * @param int $options
+ * @param bool $descending
+ * @return static
+ */
+ public function sortBy($callback, $options = SORT_REGULAR, $descending = false);
+
+ /**
+ * Sort the collection in descending order using the given callback.
+ *
+ * @param array|(callable(TValue, TKey): mixed)|string $callback
+ * @param int $options
+ * @return static
+ */
+ public function sortByDesc($callback, $options = SORT_REGULAR);
+
+ /**
+ * Sort the collection keys.
+ *
+ * @param int $options
+ * @param bool $descending
+ * @return static
+ */
+ public function sortKeys($options = SORT_REGULAR, $descending = false);
+
+ /**
+ * Sort the collection keys in descending order.
+ *
+ * @param int $options
+ * @return static
+ */
+ public function sortKeysDesc($options = SORT_REGULAR);
+
+ /**
+ * Sort the collection keys using a callback.
+ *
+ * @param callable(TKey, TKey): int $callback
+ * @return static
+ */
+ public function sortKeysUsing(callable $callback);
+
+ /**
+ * Get the sum of the given values.
+ *
+ * @param (callable(TValue): mixed)|string|null $callback
+ * @return mixed
+ */
+ public function sum($callback = null);
+
+ /**
+ * Take the first or last {$limit} items.
+ *
+ * @param int $limit
+ * @return static
+ */
+ public function take($limit);
+
+ /**
+ * Take items in the collection until the given condition is met.
+ *
+ * @param TValue|callable(TValue,TKey): bool $value
+ * @return static
+ */
+ public function takeUntil($value);
+
+ /**
+ * Take items in the collection while the given condition is met.
+ *
+ * @param TValue|callable(TValue,TKey): bool $value
+ * @return static
+ */
+ public function takeWhile($value);
+
+ /**
+ * Pass the collection to the given callback and then return it.
+ *
+ * @param callable(TValue): mixed $callback
+ * @return $this
+ */
+ public function tap(callable $callback);
+
+ /**
+ * Pass the enumerable to the given callback and return the result.
+ *
+ * @template TPipeReturnType
+ *
+ * @param callable($this): TPipeReturnType $callback
+ * @return TPipeReturnType
+ */
+ public function pipe(callable $callback);
+
+ /**
+ * Pass the collection into a new class.
+ *
+ * @template TPipeIntoValue
+ *
+ * @param class-string $class
+ * @return TPipeIntoValue
+ */
+ public function pipeInto($class);
+
+ /**
+ * Pass the collection through a series of callable pipes and return the result.
+ *
+ * @param array $pipes
+ * @return mixed
+ */
+ public function pipeThrough($pipes);
+
+ /**
+ * Get the values of a given key.
+ *
+ * @param string|array $value
+ * @param string|null $key
+ * @return static
+ */
+ public function pluck($value, $key = null);
+
+ /**
+ * Create a collection of all elements that do not pass a given truth test.
+ *
+ * @param (callable(TValue, TKey): bool)|bool|TValue $callback
+ * @return static
+ */
+ public function reject($callback = true);
+
+ /**
+ * Convert a flatten "dot" notation array into an expanded array.
+ *
+ * @return static
+ */
+ public function undot();
+
+ /**
+ * Return only unique items from the collection array.
+ *
+ * @param (callable(TValue, TKey): mixed)|string|null $key
+ * @param bool $strict
+ * @return static
+ */
+ public function unique($key = null, $strict = false);
+
+ /**
+ * Return only unique items from the collection array using strict comparison.
+ *
+ * @param (callable(TValue, TKey): mixed)|string|null $key
+ * @return static
+ */
+ public function uniqueStrict($key = null);
+
+ /**
+ * Reset the keys on the underlying array.
+ *
+ * @return static
+ */
+ public function values();
+
+ /**
+ * Pad collection to the specified length with a value.
+ *
+ * @template TPadValue
+ *
+ * @param int $size
+ * @param TPadValue $value
+ * @return static
+ */
+ public function pad($size, $value);
+
+ /**
+ * Get the values iterator.
+ *
+ * @return \Traversable
+ */
+ public function getIterator(): Traversable;
+
+ /**
+ * Count the number of items in the collection.
+ *
+ * @return int
+ */
+ public function count(): int;
+
+ /**
+ * Count the number of items in the collection by a field or using a callback.
+ *
+ * @param (callable(TValue, TKey): array-key)|string|null $countBy
+ * @return static
+ */
+ public function countBy($countBy = null);
+
+ /**
+ * Zip the collection together with one or more arrays.
+ *
+ * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
+ * => [[1, 4], [2, 5], [3, 6]]
+ *
+ * @template TZipValue
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$items
+ * @return static>
+ */
+ public function zip($items);
+
+ /**
+ * Collect the values into a collection.
+ *
+ * @return \Illuminate\Support\Collection
+ */
+ public function collect();
+
+ /**
+ * Get the collection of items as a plain array.
+ *
+ * @return array
+ */
+ public function toArray();
+
+ /**
+ * Convert the object into something JSON serializable.
+ *
+ * @return mixed
+ */
+ public function jsonSerialize(): mixed;
+
+ /**
+ * Get the collection of items as JSON.
+ *
+ * @param int $options
+ * @return string
+ */
+ public function toJson($options = 0);
+
+ /**
+ * Get the collection of items as pretty print formatted JSON.
+ *
+ *
+ * @param int $options
+ * @return string
+ */
+ public function toPrettyJson(int $options = 0);
+
+ /**
+ * Get a CachingIterator instance.
+ *
+ * @param int $flags
+ * @return \CachingIterator
+ */
+ public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING);
+
+ /**
+ * Convert the collection to its string representation.
+ *
+ * @return string
+ */
+ public function __toString();
+
+ /**
+ * Indicate that the model's string representation should be escaped when __toString is invoked.
+ *
+ * @param bool $escape
+ * @return $this
+ */
+ public function escapeWhenCastingToString($escape = true);
+
+ /**
+ * Add a method to the list of proxied methods.
+ *
+ * @param string $method
+ * @return void
+ */
+ public static function proxy($method);
+
+ /**
+ * Dynamically access collection proxies.
+ *
+ * @param string $key
+ * @return mixed
+ *
+ * @throws \Exception
+ */
+ public function __get($key);
+}
diff --git a/plugins/vendor/illuminate/collections/HigherOrderCollectionProxy.php b/plugins/vendor/illuminate/collections/HigherOrderCollectionProxy.php
new file mode 100644
index 00000000..035d0fda
--- /dev/null
+++ b/plugins/vendor/illuminate/collections/HigherOrderCollectionProxy.php
@@ -0,0 +1,69 @@
+
+ * @mixin TValue
+ */
+class HigherOrderCollectionProxy
+{
+ /**
+ * The collection being operated on.
+ *
+ * @var \Illuminate\Support\Enumerable
+ */
+ protected $collection;
+
+ /**
+ * The method being proxied.
+ *
+ * @var string
+ */
+ protected $method;
+
+ /**
+ * Create a new proxy instance.
+ *
+ * @param \Illuminate\Support\Enumerable $collection
+ * @param string $method
+ */
+ public function __construct(Enumerable $collection, $method)
+ {
+ $this->method = $method;
+ $this->collection = $collection;
+ }
+
+ /**
+ * Proxy accessing an attribute onto the collection items.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function __get($key)
+ {
+ return $this->collection->{$this->method}(function ($value) use ($key) {
+ return is_array($value) ? $value[$key] : $value->{$key};
+ });
+ }
+
+ /**
+ * Proxy a method call onto the collection items.
+ *
+ * @param string $method
+ * @param array $parameters
+ * @return mixed
+ */
+ public function __call($method, $parameters)
+ {
+ return $this->collection->{$this->method}(function ($value) use ($method, $parameters) {
+ return is_string($value)
+ ? $value::{$method}(...$parameters)
+ : $value->{$method}(...$parameters);
+ });
+ }
+}
diff --git a/plugins/vendor/illuminate/collections/ItemNotFoundException.php b/plugins/vendor/illuminate/collections/ItemNotFoundException.php
new file mode 100644
index 00000000..05a51d95
--- /dev/null
+++ b/plugins/vendor/illuminate/collections/ItemNotFoundException.php
@@ -0,0 +1,9 @@
+
+ */
+class LazyCollection implements CanBeEscapedWhenCastToString, Enumerable
+{
+ /**
+ * @use \Illuminate\Support\Traits\EnumeratesValues
+ */
+ use EnumeratesValues, Macroable;
+
+ /**
+ * The source from which to generate items.
+ *
+ * @var (Closure(): \Generator)|static|array
+ */
+ public $source;
+
+ /**
+ * Create a new lazy collection instance.
+ *
+ * @param \Illuminate\Contracts\Support\Arrayable|iterable