From 9e931229e24061657b873f468e71fe0b13e04385 Mon Sep 17 00:00:00 2001 From: Dan Orlando Date: Thu, 13 Jul 2023 18:35:15 -0700 Subject: [PATCH] feat: claude integration (#552) * feat: bare bones implementation of claude client (WIP) * feat: client implementation of Claude (WIP) * fix: add claude to store * feat: bare bones implementation of claude client (WIP) * switch eventsource * Try new method of calling claude with anthropic sdk * (WIP) Finish initial claude client implementation and api * debugging update * fix(ClaudeClient.js): fix prompt prefixes for HUMAN_PROMPT and AI_PROMPT fix(ClaudeClient.js): refactor buildMessages logic for correct handling of messages refactor(ClaudeClient.js): refactor buildPrompt method to buildMessages for use in BaseClient sendMessage method refactor(ClaudeClient.js): refactor getCompletion method to sendCompletion for use in BaseClient sendMessage method refactor(ClaudeClient.js): omit getMessageMapMethod method for future refactoring refactor(ClaudeClient.js): remove unused sendMessage method to prefer BaseClient message fix(askClaude.js): error in getIds method was causing a frontend crash, userMessage was not defined fix(askClaude.js): import abortMessage function from utils module feat(askClaude.js): add /abort route to handle message abort requests feat(askClaude.js): create abortControllers map to store abort controllers feat(askClaude.js): implement abortAsk function to handle message abort logic feat(askClaude.js): add onStart callback to handle message start logic feat(HoverButtons.jsx): add 'claude' as a supported endpoint for branching * fix(ClaudeClient.js): update defaultPrefix and promptPrefix messages includes 'Remember your instructions' as Claude is trained to recognize labels preceding colons as participants of a conversation * Change name from claude to anthropic * add settings to handleSubmit and models to endpoints * Implement Claude settings * use svg for anthropic icon * Implement abort * Implement reverse proxy * remove png icons * replace web browser plugin * remove default prefix * fix styling of claude icon * fix console error from svg properties * remove single quote requirement from eslintrc * fix(AnthropicClient.js): fix labels for HUMAN_PROMPT and AI_PROMPT feat(AnthropicClient.js): add support for custom userLabel and modelLabel options feat(AnthropicClient.js): add user_id metadata to requestOptions in getCompletion method feat(anthropic, AnthropicClient.js): add debug logging * refactor(AnthropicClient.js): change promptSuffix variable declaration from let to const * fix(EndpointOptionsDialog.jsx): remove unnecessary code that changes endpointName from 'anthropic' to 'Claude' fix(utils/index.jsx): fix alternateName value for 'anthropic' from 'Claude' to 'Anthropic' * fix(AnthropicIcon): fix sizing/rendering/name of anthropic icon * fix(AnthropicClient.js): change maxContextTokens default value to 99999 fix(AnthropicClient.js): change maxResponseTokens default value to 1500 fix(AnthropicClient.js): remove unnecessary code for setting maxContextTokens and maxResponseTokens based on modelOptions fix(AnthropicClient.js): change max_tokens_to_sample default value to 1500 fix(anthropic.js): pass endpointOption.token to AnthropicClient constructor * Update .env.example * fix(AnthropicClient.js): remove exceeding message when it puts us over the token limit fix(AnthropicClient.js): handle case when the first message exceeds the token limit fix(AnthropicClient.js): throw error when prompt is too long fix(AnthropicClient.js): adjust max tokens calculation to use maxOutputTokens fix(anthropic.js): remove console.log statement in ask route * feat(server/index): increase incoming json payload allowed size --------- Co-authored-by: Danny Avila --- .env.example | 10 + .eslintrc.js | 1 - README.md | 2 +- api/app/clients/AnthropicClient.js | 319 ++++++++++++++++++ api/app/clients/BaseClient.js | 2 +- api/app/clients/index.js | 2 + api/app/clients/tools/manifest.json | 2 +- api/models/schema/defaults.js | 4 +- api/package.json | 2 + api/server/index.js | 4 +- api/server/routes/ask/anthropic.js | 186 ++++++++++ api/server/routes/ask/index.js | 2 + api/server/routes/endpoints.js | 16 +- client/public/assets/web-browser.png | Bin 101756 -> 0 bytes client/public/assets/web-browser.svg | 86 +++++ client/src/components/Auth/Registration.tsx | 1 - .../Endpoints/Anthropic/OptionHover.jsx | 27 ++ .../Endpoints/Anthropic/Settings.jsx | 251 ++++++++++++++ .../Endpoints/OpenAI/OptionHover.jsx | 5 - .../Endpoints/SaveAsPresetDialog.jsx | 2 +- client/src/components/Endpoints/Settings.jsx | 16 +- .../Input/AnthropicOptions/index.jsx | 107 ++++++ client/src/components/Input/index.jsx | 2 + .../src/components/Messages/HoverButtons.jsx | 2 +- .../src/components/Messages/MessageHeader.jsx | 2 + client/src/components/svg/AnthropicIcon.jsx | 37 ++ client/src/components/svg/index.ts | 3 +- client/src/store/endpoints.js | 5 +- client/src/utils/cleanupPreset.js | 13 + client/src/utils/getDefaultConversation.js | 19 +- client/src/utils/getIcon.jsx | 19 +- client/src/utils/handleSubmit.js | 16 + client/src/utils/index.jsx | 3 +- package-lock.json | 313 +++++++++++++++++ packages/data-provider/src/createPayload.ts | 3 +- packages/data-provider/src/types.ts | 1 + 36 files changed, 1455 insertions(+), 30 deletions(-) create mode 100644 api/app/clients/AnthropicClient.js create mode 100644 api/server/routes/ask/anthropic.js delete mode 100644 client/public/assets/web-browser.png create mode 100644 client/public/assets/web-browser.svg create mode 100644 client/src/components/Endpoints/Anthropic/OptionHover.jsx create mode 100644 client/src/components/Endpoints/Anthropic/Settings.jsx create mode 100644 client/src/components/Input/AnthropicOptions/index.jsx create mode 100644 client/src/components/svg/AnthropicIcon.jsx diff --git a/.env.example b/.env.example index c43cf05837..074253d727 100644 --- a/.env.example +++ b/.env.example @@ -107,6 +107,16 @@ CHATGPT_MODELS=text-davinci-002-render-sha,gpt-4 # By default it will use the node-chatgpt-api recommended proxy, (it's a third party server) # CHATGPT_REVERSE_PROXY= +########################## +# Anthropic Endpoint: +########################## +# Access key from https://console.anthropic.com/ +# Leave it blank to disable this feature. +# Set to "user_provided" to allow the user to provide their API key from the UI. +# Note that access to claude-1 may potentially become unavailable with the release of claude-2. +ANTHROPIC_API_KEY="user_provided" +ANTHROPIC_MODELS=claude-1,claude-instant-1,claude-2 + ############################# # Plugins: ############################# diff --git a/.eslintrc.js b/.eslintrc.js index 72ed417d5f..e3dc8484bd 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -52,7 +52,6 @@ module.exports = { 'no-restricted-syntax': 'off', 'react/prop-types': ['off'], 'react/display-name': ['off'], - 'quotes': ['error', 'single'], }, overrides: [ { diff --git a/README.md b/README.md index 02496521bf..6b3b89d53c 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ https://github.com/danny-avila/LibreChat/assets/110412045/c1eb0c0f-41f6-4335-b98 # Features - Response streaming identical to ChatGPT through server-sent events - UI from original ChatGPT, including Dark mode -- AI model selection (through 5 endpoints: OpenAI API, BingAI, ChatGPT Browser, PaLM2, Plugins) +- AI model selection (through 6 endpoints: OpenAI API, BingAI, ChatGPT Browser, PaLM2, Claude, Plugins) - Create, Save, & Share custom presets - [More info on prompt presets here](https://github.com/danny-avila/LibreChat/releases/tag/v0.3.0) - Edit and Resubmit messages with conversation branching - Search all messages/conversations - [More info here](https://github.com/danny-avila/LibreChat/releases/tag/v0.1.0) diff --git a/api/app/clients/AnthropicClient.js b/api/app/clients/AnthropicClient.js new file mode 100644 index 0000000000..cbaff39ee4 --- /dev/null +++ b/api/app/clients/AnthropicClient.js @@ -0,0 +1,319 @@ +const Keyv = require('keyv'); +// const { Agent, ProxyAgent } = require('undici'); +const BaseClient = require('./BaseClient'); +const { + encoding_for_model: encodingForModel, + get_encoding: getEncoding +} = require('@dqbd/tiktoken'); +const Anthropic = require('@anthropic-ai/sdk'); + +const HUMAN_PROMPT = '\n\nHuman:'; +const AI_PROMPT = '\n\nAssistant:'; + +const tokenizersCache = {}; + +class AnthropicClient extends BaseClient { + + constructor(apiKey, options = {}, cacheOptions = {}) { + super(apiKey, options, cacheOptions) + cacheOptions.namespace = cacheOptions.namespace || 'anthropic'; + this.conversationsCache = new Keyv(cacheOptions); + this.apiKey = apiKey || process.env.ANTHROPIC_API_KEY; + this.sender = 'Anthropic'; + this.userLabel = HUMAN_PROMPT; + this.assistantLabel = AI_PROMPT; + this.setOptions(options); + } + + setOptions(options) { + if (this.options && !this.options.replaceOptions) { + // nested options aren't spread properly, so we need to do this manually + this.options.modelOptions = { + ...this.options.modelOptions, + ...options.modelOptions + }; + delete options.modelOptions; + // now we can merge options + this.options = { + ...this.options, + ...options, + }; + } else { + this.options = options; + } + + const modelOptions = this.options.modelOptions || {}; + this.modelOptions = { + ...modelOptions, + // set some good defaults (check for undefined in some cases because they may be 0) + model: modelOptions.model || 'claude-1', + temperature: typeof modelOptions.temperature === 'undefined' ? 0.7 : modelOptions.temperature, // 0 - 1, 0.7 is recommended + topP: typeof modelOptions.topP === 'undefined' ? 0.7 : modelOptions.topP, // 0 - 1, default: 0.7 + topK: typeof modelOptions.topK === 'undefined' ? 40 : modelOptions.topK, // 1-40, default: 40 + stop: modelOptions.stop // no stop method for now + }; + + this.maxContextTokens = this.options.maxContextTokens || 99999; + this.maxResponseTokens = this.modelOptions.maxOutputTokens || 1500; + this.maxPromptTokens = + this.options.maxPromptTokens || this.maxContextTokens - this.maxResponseTokens; + + if (this.maxPromptTokens + this.maxResponseTokens > this.maxContextTokens) { + throw new Error( + `maxPromptTokens + maxOutputTokens (${this.maxPromptTokens} + ${this.maxResponseTokens} = ${ + this.maxPromptTokens + this.maxResponseTokens + }) must be less than or equal to maxContextTokens (${this.maxContextTokens})` + ); + } + + this.startToken = '||>'; + this.endToken = ''; + this.gptEncoder = this.constructor.getTokenizer('cl100k_base'); + + if (!this.modelOptions.stop) { + const stopTokens = [this.startToken]; + if (this.endToken && this.endToken !== this.startToken) { + stopTokens.push(this.endToken); + } + stopTokens.push(`${this.userLabel}`); + stopTokens.push('<|diff_marker|>'); + + this.modelOptions.stop = stopTokens; + } + + return this; + } + + getClient() { + if(this.options.reverseProxyUrl) { + return new Anthropic({ + apiKey: this.apiKey, + baseURL: this.options.reverseProxyUrl + }); + } + else { + return new Anthropic({ + apiKey: this.apiKey, + }); + } + }; + + async buildMessages(messages, parentMessageId) { + const orderedMessages = this.constructor.getMessagesForConversation(messages, parentMessageId); + if (this.options.debug) { + console.debug('AnthropicClient: orderedMessages', orderedMessages, parentMessageId); + } + + const formattedMessages = orderedMessages.map((message) => ({ + author: message.isCreatedByUser ? this.userLabel : this.assistantLabel, + content: message?.content ?? message.text + })); + + let identityPrefix = ''; + if (this.options.userLabel) { + identityPrefix = `\nHuman's name: ${this.options.userLabel}`; + } + + if (this.options.modelLabel) { + identityPrefix = `${identityPrefix}\nYou are ${this.options.modelLabel}`; + } + + let promptPrefix = (this.options.promptPrefix || '').trim(); + if (promptPrefix) { + // If the prompt prefix doesn't end with the end token, add it. + if (!promptPrefix.endsWith(`${this.endToken}`)) { + promptPrefix = `${promptPrefix.trim()}${this.endToken}\n\n`; + } + promptPrefix = `\nContext:\n${promptPrefix}`; + } + + if (identityPrefix) { + promptPrefix = `${identityPrefix}${promptPrefix}`; + } + + const promptSuffix = `${promptPrefix}${this.assistantLabel}\n`; // Prompt AI to respond. + let currentTokenCount = this.getTokenCount(promptSuffix); + + let promptBody = ''; + const maxTokenCount = this.maxPromptTokens; + + const context = []; + + // Iterate backwards through the messages, adding them to the prompt until we reach the max token count. + // Do this within a recursive async function so that it doesn't block the event loop for too long. + // Also, remove the next message when the message that puts us over the token limit is created by the user. + // Otherwise, remove only the exceeding message. This is due to Anthropic's strict payload rule to start with "Human:". + const nextMessage = { + remove: false, + tokenCount: 0, + messageString: '', + }; + + const buildPromptBody = async () => { + if (currentTokenCount < maxTokenCount && formattedMessages.length > 0) { + const message = formattedMessages.pop(); + const isCreatedByUser = message.author === this.userLabel; + const messageString = `${message.author}\n${message.content}${this.endToken}\n`; + let newPromptBody = `${messageString}${promptBody}`; + + context.unshift(message); + + const tokenCountForMessage = this.getTokenCount(messageString); + const newTokenCount = currentTokenCount + tokenCountForMessage; + + if (!isCreatedByUser) { + nextMessage.messageString = messageString; + nextMessage.tokenCount = tokenCountForMessage; + } + + if (newTokenCount > maxTokenCount) { + if (!promptBody) { + // This is the first message, so we can't add it. Just throw an error. + throw new Error(`Prompt is too long. Max token count is ${maxTokenCount}, but prompt is ${newTokenCount} tokens long.`); + } + + // Otherwise, ths message would put us over the token limit, so don't add it. + // if created by user, remove next message, otherwise remove only this message + if (isCreatedByUser) { + nextMessage.remove = true; + } + + return false; + } + promptBody = newPromptBody; + currentTokenCount = newTokenCount; + // wait for next tick to avoid blocking the event loop + await new Promise(resolve => setImmediate(resolve)); + return buildPromptBody(); + } + return true; + }; + + await buildPromptBody(); + + if (nextMessage.remove) { + promptBody = promptBody.replace(nextMessage.messageString, ''); + currentTokenCount -= nextMessage.tokenCount; + context.shift(); + } + + const prompt = `${promptBody}${promptSuffix}`; + // Add 2 tokens for metadata after all messages have been counted. + currentTokenCount += 2; + + // Use up to `this.maxContextTokens` tokens (prompt + response), but try to leave `this.maxTokens` tokens for the response. + this.modelOptions.maxOutputTokens = Math.min(this.maxContextTokens - currentTokenCount, this.maxResponseTokens); + + return { prompt, context }; + } + + getCompletion() { + console.log('AnthropicClient doesn\'t use getCompletion (all handled in sendCompletion)'); + } + + // TODO: implement abortController usage + async sendCompletion(payload, { onProgress, abortController }) { + if (!abortController) { + abortController = new AbortController(); + } + + const { signal } = abortController; + + const modelOptions = { ...this.modelOptions }; + if (typeof onProgress === 'function') { + modelOptions.stream = true; + } + + const { debug } = this.options; + if (debug) { + console.debug(); + console.debug(modelOptions); + console.debug(); + } + + const client = this.getClient(); + const metadata = { + user_id: this.user, + }; + + let text = ''; + const requestOptions = { + prompt: payload, + model: this.modelOptions.model, + stream: this.modelOptions.stream || true, + max_tokens_to_sample: this.modelOptions.maxOutputTokens || 1500, + metadata, + ...modelOptions + }; + if (this.options.debug) { + console.log('AnthropicClient: requestOptions'); + console.dir(requestOptions, { depth: null }); + } + const response = await client.completions.create(requestOptions); + + signal.addEventListener('abort', () => { + if (this.options.debug) { + console.log('AnthropicClient: message aborted!'); + } + response.controller.abort(); + }); + + for await (const completion of response) { + if (this.options.debug) { + // Uncomment to debug message stream + // console.debug(completion); + } + text += completion.completion; + onProgress(completion.completion); + } + + signal.removeEventListener('abort', () => { + if (this.options.debug) { + console.log('AnthropicClient: message aborted!'); + } + response.controller.abort(); + }); + + return text.trim(); + } + + // I commented this out because I will need to refactor this for the BaseClient/all clients + // getMessageMapMethod() { + // return ((message) => ({ + // author: message.isCreatedByUser ? this.userLabel : this.assistantLabel, + // content: message?.content ?? message.text + // })).bind(this); + // } + + getSaveOptions() { + return { + ...this.modelOptions + }; + } + + getBuildMessagesOptions() { + if (this.options.debug) { + console.log('AnthropicClient doesn\'t use getBuildMessagesOptions'); + } + } + + static getTokenizer(encoding, isModelName = false, extendSpecialTokens = {}) { + if (tokenizersCache[encoding]) { + return tokenizersCache[encoding]; + } + let tokenizer; + if (isModelName) { + tokenizer = encodingForModel(encoding, extendSpecialTokens); + } else { + tokenizer = getEncoding(encoding, extendSpecialTokens); + } + tokenizersCache[encoding] = tokenizer; + return tokenizer; + } + + getTokenCount(text) { + return this.gptEncoder.encode(text, 'all').length; + } +} + +module.exports = AnthropicClient; diff --git a/api/app/clients/BaseClient.js b/api/app/clients/BaseClient.js index 3ecd7f45a1..291753666f 100644 --- a/api/app/clients/BaseClient.js +++ b/api/app/clients/BaseClient.js @@ -370,7 +370,6 @@ class BaseClient { } async sendMessage(message, opts = {}) { - console.log('BaseClient: sendMessage', message, opts); const { user, conversationId, @@ -379,6 +378,7 @@ class BaseClient { userMessage, } = await this.handleStartMethods(message, opts); + this.user = user; // It's not necessary to push to currentMessages // depending on subclass implementation of handling messages this.currentMessages.push(userMessage); diff --git a/api/app/clients/index.js b/api/app/clients/index.js index 698a47a75c..6007e0f8ae 100644 --- a/api/app/clients/index.js +++ b/api/app/clients/index.js @@ -3,6 +3,7 @@ const OpenAIClient = require('./OpenAIClient'); const PluginsClient = require('./PluginsClient'); const GoogleClient = require('./GoogleClient'); const TextStream = require('./TextStream'); +const AnthropicClient = require('./AnthropicClient'); const toolUtils = require('./tools/util'); module.exports = { @@ -11,5 +12,6 @@ module.exports = { PluginsClient, GoogleClient, TextStream, + AnthropicClient, ...toolUtils }; \ No newline at end of file diff --git a/api/app/clients/tools/manifest.json b/api/app/clients/tools/manifest.json index e0924383d4..70fcd76c34 100644 --- a/api/app/clients/tools/manifest.json +++ b/api/app/clients/tools/manifest.json @@ -34,7 +34,7 @@ "name": "Browser", "pluginKey": "browser", "description": "Scrape and summarize webpage data", - "icon": "/assets/web-browser.png", + "icon": "/assets/web-browser.svg", "authConfig": [ { "authField": "OPENAI_API_KEY", diff --git a/api/models/schema/defaults.js b/api/models/schema/defaults.js index f790a1af38..5fbecc3a5d 100644 --- a/api/models/schema/defaults.js +++ b/api/models/schema/defaults.js @@ -1,5 +1,5 @@ const conversationPreset = { - // endpoint: [azureOpenAI, openAI, bingAI, chatGPTBrowser] + // endpoint: [azureOpenAI, openAI, bingAI, anthropic, chatGPTBrowser] endpoint: { type: String, default: null, @@ -151,7 +151,7 @@ const agentOptions = { default: null } }; - + module.exports = { conversationPreset, agentOptions diff --git a/api/package.json b/api/package.json index e562573fad..1fe132bfdd 100644 --- a/api/package.json +++ b/api/package.json @@ -20,7 +20,9 @@ }, "homepage": "https://github.com/danny-avila/LibreChat#readme", "dependencies": { + "@anthropic-ai/sdk": "^0.5.0", "@dqbd/tiktoken": "^1.0.2", + "@fortaine/fetch-event-source": "^3.0.6", "@keyv/mongo": "^2.1.8", "@waylaidwanderer/chatgpt-api": "^1.37.0", "axios": "^1.3.4", diff --git a/api/server/index.js b/api/server/index.js index eeb762dd9b..7a06ca243d 100644 --- a/api/server/index.js +++ b/api/server/index.js @@ -24,8 +24,8 @@ config.validate(); // Validate the config const app = express(); app.use(errorController); - app.use(express.json()); - app.use(express.urlencoded({ extended: true })); + app.use(express.json({ limit: '3mb' })); + app.use(express.urlencoded({ extended: true, limit: '3mb' })); app.use(express.static(path.join(projectPath, 'dist'))); app.use(express.static(path.join(projectPath, 'public'))); diff --git a/api/server/routes/ask/anthropic.js b/api/server/routes/ask/anthropic.js new file mode 100644 index 0000000000..39d0318bff --- /dev/null +++ b/api/server/routes/ask/anthropic.js @@ -0,0 +1,186 @@ +const express = require('express'); +const router = express.Router(); +const crypto = require('crypto'); +const { titleConvo, AnthropicClient } = require('../../../app'); +const requireJwtAuth = require('../../../middleware/requireJwtAuth'); +const { abortMessage } = require('../../../utils'); +const { saveMessage, getConvoTitle, saveConvo, getConvo } = require('../../../models'); +const { handleError, sendMessage, createOnProgress } = require('./handlers'); + +const abortControllers = new Map(); + +router.post('/abort', requireJwtAuth, async (req, res) => { + return await abortMessage(req, res, abortControllers); +}); + +router.post('/', requireJwtAuth, async (req, res) => { + const { endpoint, text, parentMessageId, conversationId: oldConversationId } = req.body; + if (text.length === 0) return handleError(res, { text: 'Prompt empty or too short' }); + if (endpoint !== 'anthropic') return handleError(res, { text: 'Illegal request' }); + + const endpointOption = { + promptPrefix: req.body?.promptPrefix ?? null, + modelLabel: req.body?.modelLabel ?? null, + token: req.body?.token ?? null, + modelOptions: { + model: req.body?.model ?? 'claude-1', + temperature: req.body?.temperature ?? 0.7, + maxOutputTokens: req.body?.maxOutputTokens ?? 1024, + topP: req.body?.topP ?? 0.7, + topK: req.body?.topK ?? 40 + } + }; + + const conversationId = oldConversationId || crypto.randomUUID(); + + return await ask({ + text, + endpointOption, + conversationId, + parentMessageId, + req, + res + }); +}); + +const ask = async ({ text, endpointOption, parentMessageId = null, conversationId, req, res }) => { + res.writeHead(200, { + Connection: 'keep-alive', + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache, no-transform', + 'Access-Control-Allow-Origin': '*', + 'X-Accel-Buffering': 'no' + }); + + let userMessage; + let userMessageId; + let responseMessageId; + let lastSavedTimestamp = 0; + const { overrideParentMessageId = null } = req.body; + + try { + const getIds = (data) => { + userMessage = data.userMessage; + userMessageId = data.userMessage.messageId; + responseMessageId = data.responseMessageId; + if (!conversationId) { + conversationId = data.conversationId; + } + }; + + const { onProgress: progressCallback, getPartialText } = createOnProgress({ + onProgress: ({ text: partialText }) => { + const currentTimestamp = Date.now(); + if (currentTimestamp - lastSavedTimestamp > 500) { + lastSavedTimestamp = currentTimestamp; + saveMessage({ + messageId: responseMessageId, + sender: 'Anthropic', + conversationId, + parentMessageId: overrideParentMessageId || userMessageId, + text: partialText, + unfinished: true, + cancelled: false, + error: false + }); + } + } + }); + + const abortController = new AbortController(); + abortController.abortAsk = async function () { + this.abort(); + + const responseMessage = { + messageId: responseMessageId, + sender: 'Anthropic', + conversationId, + parentMessageId: overrideParentMessageId || userMessageId, + text: getPartialText(), + model: endpointOption.modelOptions.model, + unfinished: false, + cancelled: true, + error: false, + }; + + saveMessage(responseMessage); + + return { + title: await getConvoTitle(req.user.id, conversationId), + final: true, + conversation: await getConvo(req.user.id, conversationId), + requestMessage: userMessage, + responseMessage: responseMessage + }; + }; + + const onStart = (userMessage) => { + sendMessage(res, { message: userMessage, created: true }); + abortControllers.set(userMessage.conversationId, { abortController, ...endpointOption }); + } + + const client = new AnthropicClient(endpointOption.token); + + let response = await client.sendMessage(text, { + getIds, + debug: false, + user: req.user.id, + conversationId, + parentMessageId, + overrideParentMessageId, + ...endpointOption, + onProgress: progressCallback.call(null, { + res, + text, + parentMessageId: overrideParentMessageId || userMessageId + }), + onStart, + abortController + }); + + if (overrideParentMessageId) { + response.parentMessageId = overrideParentMessageId; + } + + await saveConvo(req.user.id, { + ...endpointOption, + ...endpointOption.modelOptions, + conversationId, + endpoint: 'anthropic' + }); + + await saveMessage(response); + sendMessage(res, { + title: await getConvoTitle(req.user.id, conversationId), + final: true, + conversation: await getConvo(req.user.id, conversationId), + requestMessage: userMessage, + responseMessage: response + }); + res.end(); + + if (parentMessageId == '00000000-0000-0000-0000-000000000000') { + const title = await titleConvo({ text, response }); + await saveConvo(req.user.id, { + conversationId, + title + }); + } + } catch (error) { + console.error(error); + const errorMessage = { + messageId: responseMessageId, + sender: 'Anthropic', + conversationId, + parentMessageId, + unfinished: false, + cancelled: false, + error: true, + text: error.message + }; + await saveMessage(errorMessage); + handleError(res, errorMessage); + } +}; + +module.exports = router; diff --git a/api/server/routes/ask/index.js b/api/server/routes/ask/index.js index 9ba81b8a12..696cad5244 100644 --- a/api/server/routes/ask/index.js +++ b/api/server/routes/ask/index.js @@ -7,6 +7,7 @@ const google = require('./google'); const askBingAI = require('./askBingAI'); const gptPlugins = require('./gptPlugins'); const askChatGPTBrowser = require('./askChatGPTBrowser'); +const anthropic = require('./anthropic'); // router.use('/azureOpenAI', askAzureOpenAI); router.use(['/azureOpenAI', '/openAI'], openAI); @@ -14,5 +15,6 @@ router.use('/google', google); router.use('/bingAI', askBingAI); router.use('/chatGPTBrowser', askChatGPTBrowser); router.use('/gptPlugins', gptPlugins); +router.use('/anthropic', anthropic); module.exports = router; diff --git a/api/server/routes/endpoints.js b/api/server/routes/endpoints.js index 33be7f95ad..bcd3c36dd4 100644 --- a/api/server/routes/endpoints.js +++ b/api/server/routes/endpoints.js @@ -16,6 +16,12 @@ const getChatGPTBrowserModels = () => { return models; }; +const getAnthropicModels = () => { + let models = ['claude-1', 'claude-1-100k', 'claude-instant-1', 'claude-instant-1-100k', 'claude-2']; + if (process.env.ANTHROPIC_MODELS) models = String(process.env.ANTHROPIC_MODELS).split(','); + + return models; +}; const getPluginModels = () => { let models = ['gpt-4', 'gpt-4-0613', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k', 'gpt-3.5-turbo-0613', 'gpt-3.5-turbo-0301']; @@ -55,7 +61,7 @@ router.get('/', async function (req, res) { ? { availableModels: getOpenAIModels(), userProvide: openAIApiKey === 'user_provided' } : false; const azureOpenAI = azureOpenAIApiKey - ? { availableModels: getOpenAIModels({ azure: true}), userProvide: azureOpenAIApiKey === 'user_provided' } + ? { availableModels: getOpenAIModels({ azure: true }), userProvide: azureOpenAIApiKey === 'user_provided' } : false; const gptPlugins = openAIApiKey || azureOpenAIApiKey ? { availableModels: getPluginModels(), availableTools, availableAgents: ['classic', 'functions'], userProvide: userProvidedOpenAI } @@ -69,8 +75,14 @@ router.get('/', async function (req, res) { availableModels: getChatGPTBrowserModels() } : false; + const anthropic = process.env.ANTHROPIC_API_KEY + ? { + userProvide: process.env.ANTHROPIC_API_KEY == 'user_provided', + availableModels: getAnthropicModels() + } + : false; - res.send(JSON.stringify({ azureOpenAI, openAI, google, bingAI, chatGPTBrowser, gptPlugins })); + res.send(JSON.stringify({ azureOpenAI, openAI, google, bingAI, chatGPTBrowser, gptPlugins, anthropic })); }); module.exports = { router, getOpenAIModels, getChatGPTBrowserModels }; diff --git a/client/public/assets/web-browser.png b/client/public/assets/web-browser.png deleted file mode 100644 index 315140b71fe7402fb29ff3a66cbde1a98ee9e1b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101756 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ⓈMJ0B4xi5`LnL|p8+YfED`XMM8wB#C{=MSfnbL`l9ppVuyx zEp(qLW1D$Mtrb1c1CeEFD=1F?RnL;bl)#|9bV!O?Cs~FYU&_7@^~qMYs4T`*z~_Ys zE?Qh+KRqWXaxKXH}95rDd&A;PM~RvQ+I? zro_liVC%RWg5JJrbkp$N{WIxCj#4CFc%;@=C8;R+#WK9?w4(^!3Cwzdr5aW&5wTEhsFB36jT{zbYFnjhnd@~%{bQ%)y@1}P#}vE-mS=m+TW>8iKx!?f z?{|5`cnWWNXbPW8g`|3-YUNJlUv|F{dRr8+j)0E%c7U$^H+^r_QYg zQ|&FL(}oaV`hvK4u|jVNOo+Mi5vab$9^AzeLA@fuc)ZF zAojS*pXC$7aI4NmQE(V?BavzaVMOo=fQaaoyLTB$GiWpX!mjSTYSU!F3bvcbkgu($ zO>fIvTqfs+22?oJrM;9wrSWGETkS*`p)mo{exrQXDrdxmO>BbTE*MKbbw1S7`=Ujd z2*9XsP)Q=VgvHDj9F;G`OobTSh05*QaV;K_Z3?JJt{?d66g7c~z}6S(%nuRmJl_@* zdv1o^>{E)>L$3pOdEt{eK4M!^L)oZ_;Pc|y_zL*u4s$-%$Y=D9*XRH(R{>$_gOUbn zB=!0LQq_n4;BVznxl8g6tNtGVU-K!usiRG!F?DjpjxnX8-LTe~;J6WX1cNXSu@i^i3 zGG6Y7iVDjp-VpRR_^lOR7n3FO%X%1o-oCU-!j_xN#7xXov7^q5f+qIYaxV8-^@3dh z4?Q_C9iq1>h#~>DJ7GXJkxtOHpBh%37r>OFY~qL~%@H@!o25sT@kLmh0%7E!)%LX8 zE!g{c1BHmfFjnyhOcmE2@HYg;u=RyilEI*$y;In6H3l%V?Fkaa(t1ETp9vGPsGF6Q zkf;CtCb#3JNCjwio|w85)dX#}$R=O@+TiY#-emTbk;;-ioye!N?uhsRFD&O9Ij5;X z6j>q9IBwGn`Rk7b%%ZzS%Zvm}**rL#Wy|k90#818Nx%BV%X*eG6q*%z+&0%wLO;Z4 zQf;R?!ap2P_YNPz*qPtr$;9a}d1OO zV*P7#b|JlNKhsm8gmKuq82KN_T(K`Oy~$kBx2(LK332>G+ycW7)-Rufxmb3raj zWf0|6yd?^vx_j=}TLG1oPywnCagm3tPQJCTTv3=ny915IYOlA>*vMNgY#4q{7wxya zb@+ajl-tWZG?XBF87K2zJngqnh4J0!Jtg%1VuI|LTz@M3rt{#h)UpP#7!#}_PaIfK zj%*=M2=A88GMD#}US@Fx@&Ll8EJM3I4deY%TbS|a!w=!`80K-UOy^0H) z2pIRit`4f|0Le$w;He}6t|(gmQ6**xE{)_o>PkaAV{nRCt^KysSJI31i9|jk83ATK z}=udfi*U*l2>l}!2$0Da6aCK1!Al?R%|(w`1*R&FuB9c>w#j&9rgY)`7Qg$a2m zBjTJ8)zG*Xq<=pVsf zbKN8t6n1!S9;L+^LLo|Lf~7p%Z^AP)knofq5N{|)v3n4wew%3G;$#~NLVNG!P}V@8 z+hrD6h}LH;N_v72fJ4hyiJjhh=GHv5=TP|^6T#fy98jcX$(E552&U#Q201Bb4`pUgeY+Od1i|M0VGTtpkT5C8oBJGckYnpg$QnWlEU>UPrk+Mb`_K*xno zygA|Cp_0dnLie7Pn3<3yQ^em^(SPi`xwUmqxb}J`FhH!~?#_aRvEuO43@T*Z)nSu_ zyyi?%Y(ckAT0XunEJE8Fw%G>&S6%19n<4b)13POx3WT)c*h?rX6FNo|c_B6M(LdkM zpg#?E90VG1wjGI4K5sT!pZU7nH|x07r=^;B+1`g$W;UHoO|k&9Tdts|b0?X_AIw=} zLRE2=%gpHlG0~jtF%#H@-JGrBuFnec(#}qtw6BL&r#+ZO`RmyPsQh1Z8#gOk0&}xI zt8rpHy|LTov(oEdSCe;m{8B-KC9m73Pmce4rP%VoU&-zKmszw)pU`X7fTKr;GItu&U-C_O0}78g+4w0yDsgHea?KcYh`d%)XpkbK;w_29KXuE%-M_PMf*d>z?WrNn9P{ zvhcM(5%@08Jd7P3yP|=<3{DwEvbBN9NJJah&w#T;7;6WqL0h5e7bJ8=`lCjynjtyi z9jbm`FCEXxth!-yCg67?kL*=?b!r9T$K9UZm=~>UAuYPc;ynM~b?~eC^ zB`#%78lkefKL07`n@Jn!&_~=}Jn$;~=ksp7iI2^5!vxvWvc**bna`}tg$71~X#M&A z-1xX#1Z0)pW$Ah2WN9h=Pti+##S|jjKk38C8=5!wDaqL5{%+^}6O$efEq%5SolPdVyXTF0W7- zMk=cv;Pt{@nDr#NhI0<3IlybLBM0L&`*9#JOU(IFNNf?>ePH*V+w+2-_J$on;z+-Q zzC1vk@@eBTh-1wE=`luy@{ru{Y#*ymBvWJ_%jD)XsuZG={%3zSxJZKT8M;7Ud-Die zoCF&jmEN$!wFe)AQ}2pJ`L8B#f!?K5?~npfwKNH@OD07g!@&o`{b?P}#~5pwPmsyg z93Ah<7o!uDx&hCRjGdjewNIOq_7!BU=QSHwLN$g3z~nuOqStbX6Xcy7RIjOQdd;rq zh7I)9z z+(lbb4{S4b_s-Vy1)bgO0I!W4BHsw>qs5!JBa()~+PyzXEUN;ZCo(5Wjwj5ASqpPs zMRhn}$IEc5>*xMSF+25<${cuwg11&d|7`Jc1KXjwFpiisoi_GWv!B$-Ha_h zzFKo>Y2O)1a+A@xDXjJKI-rywE4{0m$MDvluO5DD9~5%WnxS6OfcSz8x%-e7w>CL)PrYDW;~U!Z zHM+|6ojKm|GuPu0b~!dK0lsi*QI)4K1d<6nnlyfx;ONYKQB>anJhjJ2Kc)C=Ma3B~ zrQjjcgYEM$I0)M;NO_UK_Ixhy@3&&n91d^$54gQEI3sSq44%^^B~hJ6U94o*#0g5> zoM(W4CjxEF125Z1RHndnR?ii*%=I*mJ>J%i|NdPN76MTd0xu5T>li~p*SRoSz{-1< zmA!cXomx5A`wlzVyx&qR9OU}m2kEu5I`Lo+U%=54e0}tJqdael&;|#29}o}T^Ew*} zjM1EGae)pfmFIl@)-q3kb{o7q^7JW?M^-Pw@l#ud+UxBvHL8fC>``eei1tgFUAaHT zzf2|zDHP(^#(S^7-R{A)s@y@Gg2Yb4rN1G2skQUvgWlnMan<%+-beYDnsf zy%YJ6Tjy77xlUOrv3@*e1(i3J1p^bIIR=9jkG**lm{gPS4p^|~$w7}1!?cm3>Jcm|zG zQUTjTNEvI0k(zU`%E-9HbX#c5dp(|slg^Y+dTowAB#JGma~3xd))BYO8= z_WBC`)_)O|HmT;(HY}GxC>Y@RLOe*X12E^LioW}iM$M(iC%X9oE7`J*duWGD8%%P^ z99^o`E6=7^2~9RY-(*RF8XBP=_$qE#3m+NBe{SEU4)dK@R-W@JnIKDl&)QYr`Cxe2 zZR+MH4rTDh`@@zOS}{k2eRA(kEOapf^=D=e@P-_nku8DCL?I4m3)vGQu4~6cyIWJ2 zU2%P4DfRgt+IwX}gHC>DcX2$y=(z{{%-q4tA;!3ri`$yjW&iN* zD4P3N;WQd2UwFcFF|lllQ|K3VFFw!9zV7(*i(qP%@+wfjv(U9KQXkMjH05#;LBieF z{;}~57`oY|zD{x2tM)ur-Fdeb4~-Zk0yhKckzrUFE%S~Qf zY~3oVZ)aIkpO$-?qQl)CmSUlEOd@zIeb)Dx9aFSO2rPs>Gvj=T;9zDwFj!%?ySc@`@6L`(!|y?bXeBK z<=Ry&0nE2J%-)8FlGm^N^UmI9kLcrm<^<^xG*S~KL3fm*1%;3IYf49!Hq1Ibr=cTciamFsZ zOvZ8Xt~@EwI0Z9eG64wN_P{41IAmqPa(gv#E8qMYC;D|3f<7(sq{xa=tDu2XcGH7B zBgNC^#e`_}`Tlp4g-89xPrgei4a+QFEa9<-6x_{o7r>7#{qTU9WF6~&@i z^aFZ*w6ayj*V%$)&i;_CsbD#(6YVTesI}-)U*P&H>oVOIrw1HORju zwYX+eDb|W_weg~GeB3$rydRwHeT#F&b6e20^DPOlVYX#=52!o7D(r4eX{D_o_Q7Ls z9?%Kt8HqU}kJAAxEiJL{XTcyBOHL$zW(hSTOa4e%u@@6Fh3m=~BpFe6-D21cwfFk& z^1()6TffDOY&HXR%;0{a<@tCm1W&;ga4=(IZSEJ3ZGDzT3dK~%0Uf{UjLRjYBYwk6 ze4m$oR^0u$I1?3yEr0->0q~@p!^!XF1A%^W4!#=WtWczEFYTsJcNL;E)m<)qTlCiV zE3K-m>itSZBIDnv9Nd@5*y|=~=7LSBWNINFw*$h-8p#lr>3&4YhjR5ZD5s&k4bs$j ztx6&(g~3b1Ga7WXuGnZyhuG{dpl%mqDk!^Tjkz90G7X23+Guq2l$u1tB{2jCi)0dM_0MFCE5-+O z6-6+`BOhEa=f16?7~jg7-0i-y85C1{F#uv^Kfu_YFC1*wupDUTL6(wVdk1}b)7 zr{=-QWu(G!gg}b#`my~F9#9GWsMS{Sj3p6OfwrJMgcVdvy7I!x!DnOrl@nh$TAz4v z<+a(j^|CfuP3~&%eD~yAFYIhOuf4O2WkoNV9#!m3$cYk9u;+M<3&+U-fuF9ihO}k* zS0`?KeCdgY7uNW4)5c!O8VB%Kw7tU@d}8OX&a_9P?UzjxIrzCRCZwmGQn0!jz;O=| zV*9n!XF9pD`3h-k@1o(eFC5-`>BzZHExq{76JP(~{3C}~UQ2N{*+N|W*4%e6_nohu z_Y>0dLkN~=$D!bzu_cD>t3_te3!7VUNqzIN-TG+*Li%7 z{0$W}V_#W3N(U3go8fMQl1KvLbtpjnQVMgvDjCNM5}v;fIsL#efZGy`%TrhLuWd+O zqI~3M%(VZVM72h>qmtj-^1=Vhf%zwwo_ziKwSld10Dl$R+}{4tZNGfZ&{p+gM_Yb8n74pB zLk}gPNeYIjATc{z@Z9W^l?4SGx_eh^v@I*?U^$gSq#>aLy`ONmm}|Kn;-Dbn z8TY^}LKe{|pz&>lL&=^Y$4^=6rhsm;8$B$^<+{vtIq)+KMY8t;IlNWIlEkw|iNL$4 zK{5bdBz32d;GmZqVjCZC{O zx}6GOH5(1(=txEk+_D|*LU8| zT2_2bj&~!&rSyqK$ty(w2upEk3BBWW^%ryB{mSvrwL}irbH`tcZ6$-PE$xvoe9QRl z@1MAKTQxQ%LoL)%B*}vm!umJqF&izXjzdxS>GC0;h0iJ9A>p$}fpGiKu7@V>_%}!X zU9&svr?tib{B$Oeo2K6SzL|Rk{9Y2`5i9@l$|cXC6b*72d)?`O`aOjTCLCzr>PX8* zQ?@aPZfQ-mSv$P*$; z7rU;`DleISDQcN0L4ib``TlecgvED-mX{lo(cZELb{!?`YvDy)4zhtufnrK;=(0j3 zoQUz+<>waS;)}8V(ups9Z~h?#qQ;*A0#*`cS~HW?^gWYz-aB^bI994u%dasa;FO(x zJOzpwkaFvW@ZtI9zT#6h(4}Um?wXa6rbK8!{N&`#FRVQG#o4bmKH#Ua#sU0vcJ9c< zAKUf|orFexNKe@|e_d*xh+_3E#YX)!f2jw6vNM>&1OUdpj1KIknlBrsEB(lpyWh9@ z9S_Vs^1YJ}|6u<6hn8QOtLI*im;lyYt+lREf9}YC`rMKK1Yoi?ef9V)Gp%kwJZJdg zbGy4bh(jVHt&xBvcBmkx!cdCUQc_xmNs@J8c;G|c08=6jr}dSlsZ>iz5~koTA+G_4KuV+3aF`4z}K}hxU`phaZ^x+H1HwcTKCL8V_SttIX0bJ!3c zI2%;>r0y#eU@T+^{j{2fR#0{yK`?|W|L@ZfL0Y;2V^4&bM-P8fRU=J#%E z4@Z!Ol*NUfuPO=$6Z%A(sN&KkwU3%d$+1hl+*xM~DIS5|HuKmXdX{m-r3 z@%-Y856wUR==^t&tQ;MD_|I!)$9qRVfAmk&&tui+&g$;&3dXDPt0r#S(Vpx|55U&e z%tUKcph07jjL4T=>>+4oWMxK0vXr0SF3y^Za02-VQW)BpfUtfENK*w(YJ=yKxy4UC zF`V8D-+cfJTlghn{taKmcYCIhF$5){lrV`ZK_N9{1(=N|Usyg6rM-aGgY!>5vG8Dx z`eckhTzu@+pB(km+P3!gscPi1k!x=l*|V>`XR@lg=+#(RL6tpU>SDio<+EP29731a z6rB8E(n#R$L!Ij+4{sr}t9j)T5sARLA$(}+-v9okr<&bi>$k=Mtk(qc?kyj>dGhi| zIhrMS83*7~9dOadFwOM>#{Mjbo!EacA7q$(g$!n=ph{mJzE{za1vShqC}V7+$D#O)uLdAFc;IobqUWRcQQ zi&~D&!zdE0C=s6NimJh;zlf=~QvMH04?|w%l@s=QUQiH01R^RCtq^D0qgRh#^s^tO z(pGf&c+WJ7Z_j?^+p}LuKTou#_KjS+sT%DF1hEsQE*-smPiOmh)#`{=h?S3{r8+gF zFK2g&AggW$v*Le(y+i3qoPlS&9%v~tDb;+h_42A959ruPevXlYQsZ_tL=_Q;QY}R} zQLj9`{L;5ieh2YnEv*IB=avsVvGDN9oAQ+7i@H0uh9N<%2(^Ty>2c`!kUTUcE_0c1 zSGVMcL#ChJ&EI{OM1J@zEwd%XgT`%WMe|KXp;1GS_}3=i^26nyd}HpupY0%>uGTn! zb=i0|^`WgFYDtU;xq`b8J1x3(h@lW9R3Q8t0$3#~rUpn>Dx6aG;d>6LbAYY9x63Df z{Ujp*@f#-|{#gyrPiH53$G&yqE9GB4fBXwmt*NfGE5wNEoZ*Wv9oauwjSL0pKm%eB zjD@N3)@WrTVviw}mA543@ne~wm(8;n*L?Nb?ehv&d!nX2h!S-K0z{Q4u3ebKkwm(q zD~IRff=a6gS=2BedoQdUdGO@7W>*eG2~lNHdq;c6j=VYg;9)U)uTGdxkc}0-sA}!um(Rr@TPRF9c+ThgWh-xd6PPrPx$N ziATKPy9f-7RKb;o0{zpXn2#%ee&kOF_iMD8XiNK8?~VVi?ISA(j}&`TAD#cfmyV6K zq*X~s4pV@s*37vhm(H}tho#*T1ZWVg5PMNaTGP8aJGZu{JJJpSEOl!-nQ;G5721`A z!7ZtzszRqm&_cvZq%@_YBlK8r_J!p`hgV*NE~$j5p@!7Jvc}oC{M_;jKVEorNf**X zjfxs^DK5PUkF4oPXV1|2hgV)aIxtuCCr3Z^u8|AILR%Q_DB(A&^_07Ko|FBFQERGj za5uq;Y9gLJ4 zZP$%o>fwKMH0HGDSJK*oFyzS_o6_eDy6rQp3v!2&Q^Yy>TO9snQj!K0_&dapeoUH& z@v?w8Usnrj9VGXbse9fwee*L5k00qR-*@6GKVE!7RbRjIq4irtJe9s3SULQ}!ViN~ z;S?4hq&3~%GTquV8b;dE3W5qDBwc}_RDhg}^GADYu)?Fg6aSwB|G$xHwB`ucsu3E2 zsOV|Eq{}Dj6Gv7KEyP*hua+!{*tOPgW&t`Nh~V0>o39!pOy9mv^EBwX1a5bKE|JhyDvRfFmx~Ga#1ZOhD|6+*Kyt7@?*(tL3oH(_#3h# zQ6PxiHFVB>qc?nc?#r*!Fm4!Y9Kag3d+7Z4&b+T1?A&ZpY^D_Zwk>%8%p{=0dCnE8 zIR^DwIGfu|=21-jue&NKI*WC2KqqF(^?&kBlTWVByOkF!$ z&px+2_a}$`@TKMFmbLdYJBW1s77^piekZstzp(Vo3ro+u`dci-#V^l(^VMJHO=SWZ ztHxU**N@%swuxJ(MYpy#jfHj_bwF>XH9q*`hkJ+q?8G;IWAb_zT=Ey*n2~-s^`~Cx zUc$hzS43e!TS5YdMq~&Kd_W z$O6J$o8P^6Xd80XUfzp>Qgkj^X{t^1vNx{^ai&ycbZsk{vVOz`AZJ>zPbmxPxUzU7 zTUcVkDWpdD@#2pL*9&g#>^ysD51@(=P;YLHZfcF5-NnsgzrT$3qYFR&+|fTh)|)-n zn|prg$BEd!#)I3~>t+HG$Z$2Xx4U;pu%o^EUDIzrzdhX2p2eO}Kx;^Vp5HxdYkS9m zl^0&=YEkPSE&X^|ZmJlf0%R&gU*Y~WpXe6pS^-cFT2ZK|g?X~ZFDrd-q9&RhN)EbH zBRs)ieCyKA)O#oI`Ns$T=Ql%8`=+(V0SvNhCT_ca@^XkqtHnuXGptm2_zI(3FNMpq zxezS-3L0~XbWuanA8Uw|rwjpQ@U7+SPoF-pGJkM+jT5BL89I0W@ZP93@(BYLLUgcv zQL|GeaFAj!_vW(`R~ttYcbCEv>yE3GL5}aHeOA%fUTYF7Y<)CExNmV z_6=iK4q>UIJppR;IJNSets$2W?Y>~>oB<91z`>OxFV(%XLaGAt!jb)~6XCzPW2+)|mNF{N9fa^zcO#?~2q=T55Y2Y3s z1=69C5D7UICu+$F5hxx$`N-g-;si3$p6-MgH2@KwTQ;7BS|q5prMIiy`Oua-SG0;E zKbpVsL_K>V>NjVN=5~dx}(a7u(LC*+{9u65Kx>|?@WdThj~wXb^{={r-YPJ1*Y8iRjKIP zB8UQqi zwo&gNIjaW|m7B-+&DIO^ipS@ld}85yiq^5-{DX7fTpIXoi;cZjwx@gE1;cxX5l5@Z zD@U*1(Hb2=oNA2)1OP46z;cw(L&e!)8xXm{0hzl9pm_V_?cbXF_5hSz(dFa1(37gt zIskIvtAtaqTN@{{F*Up@A@x%&8P@*o;ZcJ9!= z8^*8OTy=&d>>b*-x4or<*g`KstSZuhOEK*Nk&siW$qb%3zg)+JMuZDH)1zT@a0Bj} zd+6S=D>sL>u@i<7#NC{pf~RklAaAd6A^4Uts*cq24e32GTzj2z5r z%BWR}_l;fq)%ou|aPnKP^)uNB);NHdv8nc!_iTNCyOOA^^C=1w(!X3=nfn7kv9hw4 zu(zS_4;~aSHlV|xD8!96F7Wp$O|Vb+vAJ9o;dnj!cTC>2gykNpgT00OkAMEh3r|3#R?OD3 zC+pc)^Jq4_jaQT7)kuI=(!O}~+FQo18kM?*IN6$(R8p|JW{ zBRZh!>BawQG=~W?UcuL*-M%Quvu~F6mZd=uiICCI`=#l7ezNrR;n(xaa86Te9KdQ5 z$jy^??H@UpG+6UFoh0|d(tYlQrxL>zn3+(a7x{9@^u3tPyk2=~P2T6l^}~fMcD{|@ zH!Zmcyts0r#-NIw(Q53@O>b4nTCGty0DX0>E<_Ygz*Hz}VSsj_dxy7qX70w( zvzF@RTEcQ{J-2e;+b6y>9~UC3#n^js`M`5aPoBy3MZ;nAg5mv>t&t7@)MKr!H;>)0 zy))K9uTmWgLoKON0!pB&#`kL#O946D3&}Q*-YM7$H5>n`HoG}>bpV2QPTuyw$#2fR za(Z7;zfdop*PaqU)lW7mnGcgx#R0dJW1y}TafR^1p8itwoeyV?^bIrqA5W4of`CO0 zdGjy>2D_8o(Aj?5_-+63=zn-KZ_#)|tZ@LV?X02m-n#it@eGx%695IbN~=tByedpx z5gQXSlU-9|PcK6ei|@AZx$YS-r{&@>&Baonvu~>R`vAaaj{f;#J!sQuCGF|Z6;(yB zb!E{t;Bk(Biw8lzhz5u#E_8)DogfE#XLS_DA!N zEyj}()e2;`UV7x@BTvkK&toh=YmGf!IUUz+Kxl<_K>E%cQD{rr7mQrCZ|J{^SCwO+_b9u*im0>%{#Mw`5=6a2nUy67_9$XFmmbU_GVj(+_for z7a2g7$f_p_K738NPr*Mx4T~WYzyl(Un8A0y1!*fJKoG}TBWF!s4LcWFRCRIs)+4>c zwbng^6_tg!a=179!}&)Zn}4tuSJWJXMmmP2xU~4jWu9Bo8V)1v(5VnA329K$H$9G4 zQ~O3P-#>ir=4z}Pq^lYvwx!zCo*9x#G>V9*R;VF8sHjK+^jMI0+c2ADMtcP6m}i8; zV2%+Z`iMS&qVCv_A92?aAr*9{J$b?K{%_BIeSiw|!t!%HRBh>jU+l~FWUk=*QVfeF za|iWlo9B~I^8}k@Efx2F9yY+PEX5l=Y=&ij!AWQfFa512;k;_(gHvz+M=$-8W?MjM zjRWYjt0r!~W%4>s}Ac~(XA6*=H=8Q<#Ke~S?wB6NMC%lk?m(0oUBIVZKywqYr5v1E#sqa~HX}CP< z8tTWp^Akw~7^|w$u#H1uO}KmFV&H=jqL3bBIqH)3PS%UZ>JvX%dg1AX$L8z9VqZ&Q z4?^wm2CWfmjXmu}#D#j{xuvIj15ey+N$c#P^GCvn2r5*Sga8SGbc9ea)Kx_cGPJXE z?)k%eH@7!WgrSkp?nr0@0Wly75|_6_`VtHV6F7QK-fOMED6)XXz9&Xhm-5vTrVCy` zP)wviP=v9?I|_Q9W=@2RhR&747kzi`{sD^IVqAQxck-fEx8{>(bSS)qlxVM{0ma14 zo(MjvY$Z9Vv9}w~w^+w3=8`7Mz$f>tZ=X!Myb9%8KoQO*8p1!kzkYX7Rp0o}oh?xWSrWTN6t`a1g$+w7i&|t>eSQO3D z$7R}>ze6RBmpP1^xxl7GkiyA?dv}r1oFQ4unXQnwQ2zG5`|C zsPHIhgyzZOMF8p-D{(gcClm=%jm|~NT$4$bzLU!XPylG79u1v!zRE(w>M#BDAPShS;~=rm)<=%il(q;khmP2-egCnImbY zPR3$fFD2(rCyc_+SSRpHOl#fBs_mOjR3L~wt&Xf57#!iAJ$(MfBl`)*juEW6P|)Y) z4QNh4Va;bpUD*LNc>7_bzsO6b0pT8=;tP`DD3IKpt8HLuQ&C86_qXIkqzm-#1QF3d zvC0n-6?d_Mb+Nf_^?>)Ra93x(RCha&70Cs-lnTYif4!MOpWiqfr=R{#_U zDheLXs4C%tYUJLDd;jCHKOQ^{&Kz6gblfw?c69gNF?~l%D&r$*a*1U~bI7b*jVTRE zP=h!YQQrXZLw!BK^lku#q6D%W1ElO~iQ+~ZJp-NEp-}t!So@zG?adwT9UI)uZJiyP z+mjKH^hK3w0)0_6E{V9&J-K(YuQah(rzjI*7?Fc<82)CGruHunX?9+#yhU2uLWr^) zaw78XKr%~Y_ia2iRi#K!fr>;45h1EXgc_kn=pihxL;a1=6_p;+3C~hPB0@w^1SR$K zXGPUH_1=O$y2y}OZu+8t6qLXNE2XP6RD&Qof7R>}jE9IoC5q346qpG849T$A3{?qs zf1wv8D^Ki!4$i!9)Uc}>-__YZczh1@PP`Zw1DSy}owLP8#*r97J$`l%2F z_JGKr3a-y&h=&IDMM_29S<>3^V8cdO7!3l@cEI~5uHV%;d##CZrdZuYiJkbAc%w0>B1{ z0C;Hbp(p1b8Qjxu7-~zM7DSd(c^zeWg%fo9%}NWcRi3Hizf2?`f2L@&EB%IPbcO;T zI)*}Q#7ORJ8B5_uVLl*ogw$gsyFqHZaQVB7a=N_b0{)_T5Fh(bAwNSm~3sjefqAlRjge~ zT`$(FmMw=RFB!{21grxu;4&#=(g%$G@%~=;7z$-GP(A^(+v1fic_c}F6D6c#k|6=2 z*{$ZQ_H}0cCWNTeuw24|f(P(fOW8v21VfbkPIG9QIdB1KfXibXUgjUtMayAlpU5q8 zP6a~JZP!SH&Pc@^jO6L8MhWhoynU)QJzz+Bx-uUZR?woCW(Z@=vy0_nC}xAA_$f~< zczA6wp^dFKzZlfMShGl#P;koEfk{#VUt8%4QUQ05UA%8-|A20uIo3D;RMNU}>W-QA zCZ`Div}E}u&@yYPxiTjc=d{4GhaiM2gHy)?F@dR%5!njS08%qvhpf|D5|AZTO~2QI zmzIwX?&(k%+TGdQ2OqX#lQ$Bt-AkOy`LDoBHQ;2@#jLE)J8I<>UVyQ)P%hdi-29Ki z_rTUTrH_mnjQ!ap+yCa6Kov&a+2m+S`*2{86)}b6i>n%_v(rq&^o2h5DS857)Po`k z>V5RV>KB)c!iqP6v(Ggq0Nh5xOOZ1a6BYTf@PFR zEB4j)r#KkT_-Y}9!aX26lOKeA(o(p2-0IHvz?o8Hw99cNie{Y98a_39+e7?O-% zPwc~D&d3&jZV5vQzN8E=#DEK);qx(c_W*Npo=#^cBjpwwG8YOUNZ*oaNa*fIGlcs) z*B1f6w5;SH9phjSqwW&ea`na(vb%ZelwB8U<%wE|cgOuFa&2!+#Kr}en0MH4odnfN1JUWYUem*Wo19?7bK0(#sF$GIeB{DZ<#nQd<+TpHJ%9L|tS6J-s^s7!|J~37MQCDT7hQm}PRCZ^{-)w`bT*{yyi32N zZZVDeeRGWwW!>DQT##kh;uPPCQY?VT!=DFyefBbrBGJb(hnbxmn8wHhVn1g;%BQcT z{;xKq5X6LIo)1ktBiESrjb-Y6cE)U>hm7_*b?j)im6Q^_8$E;0%9&t3vytevyMc67F;4ZKIk6`Yo7Hz zDCGSUS6(o5;o#10csrvVKwCPuProx*C8W`CP_BhTy=R-8Q!u8_zCaRBp$h@ZS(pV8 zzZ_GaeY%8~>*dcX*!vWxNcGopdqh=p4=Tw?7v9Z) ziImyLe+?_1wqs}NVoouqr&DGa`ogm8AmQIwr4l?ENE66n9k0RVeDi41BPWGIBoe*_ zV3CZHUfXcG6yxA)ZAv_v-jl;uIvDG12X#vZZ4X+Ei(jAn&dIn4K`bs_6uFl55%~w< z9tLqmiwnUAhM(|s2zk4?yCRgav2Z4l22i}~>RvAgYLs0SQKXCIcTe5fku?gRHnyG7 z4&Z{(%deiiMirX25Lt2+j%;c1E3rdKU!rNKCOf9}O$jpj20yFNwx=3iYx;{VX=O4m zWrmf3W6Zv=^JXA0pFhGV`phhIV2}#00h$n+Q{fdAw2pWee34an?}_tJ1KTUx7pmafA^7$2X6u3H>4k1f)B- zLpG9YuFC+r?@=hy*0AJ!`n0=OG<8t3At8x$L5C5Kg-&AGb8~!*)fmLsGq&NCOp86v zGlfu)*}SPhCaL>l0i{ZhJ$&eRJ@FWXP)~#uNe2{pJO|0)6`41NL;HrYO9l_oiq;F- z665kHu2`t~NxaXD!29i~CXQ8h94_ft63*9?h?dsl|0ftVUXMa-b!EVV?(`+R z_E)9{Y~4mr?!nvO%`&D*0Cc$u56(XD%;HmP^;rC-pjg9hY5%JnlhhP(t(_r3F+`x7 zwD%VLK)>)SO--5grG@h=1x7B@xDFxnb(?NbxNJJ+tvnRp8Lb z*eXp>sesm61NEb&AAMu~VQX2U`R)jcUYR2jSg>IJ3}2nTRNAIU(=~VF?o%Un}`Sy$V&NGbIBda zhw&38@KDsI7i%HY3_f!TQo!y6YGItj)HCw0nTdLX<=bqVJ8cZpN*OLuK)NS~Qsu0FYg-a$mB$|jn zstmxXBfN)o({qCy^P=$s%rEVXRq1Z+G#?ufqEC)U1k`r=aSBZSd)5Fb-;kvwA0m3M zJdHHZ5<=lBM*;w$;2(@TvWxOywh+YWJ3-MYhG;UXhny^SuyM@i6})6boo?7Na|IueoVR573T}=v zr$R!Rn(EigdxBO}dKiTM0QQewvZK4*y+^XV<0%%t!>3 zsUkwo?ryzoXwgyXwCO;O?<2FFaE-0cWBEsHAoC^xN72mT2{Q9SPt*FW6kBI?gE^K|v#( zKS?;|`gaCOHkZ$8v5Dx(Rf2)57G9rWS~kN0%JhJzLjiCfmL6I;^4Q6T2Y0z8RaNxE zmsPq#%v{U-UB>YubDHIFYpnYqE_wBJs7zd^n~ICLM&De2Kp%rM$DtZMMxdYYbKJ7W z1k4SjlqsxLMJ$pUZBf=ba{zRb?1@8mx~pa5jcx)^2~Y>+?7wYqh_ZW<)uI$7_}t+c zI3+}tS(bD!>Sr8GMew|M@|E=H3P}3y0_ANi4a=*0@r-A^?174iNLRGGmMs4Lg&)4S za$K0IN&SiR@679#{yp#P0~_W{2Nb=0UKY&Cui#Tc9LIfp{8TFsz+H_6eXKwK((^@x zajEYfzvax#1e}QuU|V z`|-+)dE_;K6=LSUQl~h%ZTX~-mu*msaZ{YbbP;m49Lyq_!%(l0a9^NI78DU1g9cmH zR*ELZFjy4E2MvhaF?R8e_OA6#j}2sJq64^n)4RLUQI?$*a=ihSuQwpoZYNDaoMiwY zf#N3aQtnZ|&^7V*IKEsU(3K zpT9mqV#`&(|mh#p;>6gD!V~?yK!V;_?Q`g zYJ<2+0)E8+H#~bBl>J;lZkC!9XBEBXkd>i;YBBLs6VupA5Rt1#FWuJOF?gUNl*h8B z&Ia`yjn4|}L+SW!zFWzx#|NniJ{vjU_I`$pw#Xz00p@8rralMFm8PkxettPsTn0t} zqRNEe?NfIR?(c@QGtL2QYHz)4>?+pQffJ6pfsr^RlYyiocWgqkf&QQoJt^Xytjs$FR3`+cuHSj5yV9JlJLaSz%q@tu{oZMT^wMZ0IXiVKFi-t;c zN}G3F7nxI=$<|(Gwr#)**R?LoFl62vId4z=Wtih6z};IxV*T-{aH9o*DHZvsO&aB zY_zXH7H1~uSrB6Tk4Q11FQnkb4A0!i;!)ugf-Crvmx0C5<~vNT_1>{HY=dzZWwybT zRED5XkqY6q(f!k{&Fh>Y8^+E!2XNEWJyY$;L`WSGBD_4s$}poXpTrzORwtc)isZ%a z(<&iFR(@R(ChaxpJVeiYF|Kf4oXn~!#A{*%@Qs&tWrd!MC%<&`&j)uo0s+xnPEH<6 zw4k3iG_qf+L!{wp&8TlxOR)(Vze)ireQ}a0?}CT`EDIDK){prcVWXI{>Ov=H5gkf1@ycB6qZE zWJ<|3Mgu`*@cLAp=SUR=vx{>8D+ z&(;feRhvRZ#wc~c>VmDraDo{M?wi9lxrQmcd^U0XTulk~E;@7BJXM z^&&DrBDtF-oP^0V0L~vxd{jH&N#S}OiSI{aGDErUg?R}T-=i1U<9)u z92V}R>7xE1l(g34hujz?7eO)C7#1WaL8Uy6cXB$)84%4e82;PSH=n6Weakf=6>Mrv zT(DMQ%rlEmoYdv)kHPKlsa<8{VJi!^cTp(++3JxzJnAu!MLk+PV!AsH5Z97DXGz_$ z21JgaEk1vj%a0@zDX~8kaO23uTiRRKHA^;%ommcG-{=)*51;G5I!3^QLt~DT*SqmP zAZhD{H!EWZ+N6qhWr8wsnmf{+$cC;GbH+o?u ztqhJ7LCuHt6K7-$_4tO4vH(zS(KMn7H!OpM{IkEdrkT6p_}iuU|JglyH=UVV3sV!c96DsFCXIhAnqv_H7^(0H zDe>6ul1IX260!+qI7w3Ayh1IXVNO=O!hpeuHNL+)m4r)2&L6MVP=OZh%jnZ2XSC&m zAgpKQ-O3oO5Hv09({k(pumq3&1zctI?z=+;gLt7gN}6QRN1vGjfCrIg1_HUXyZy4^ zi`O$pHjJG?4q&`Bef7j`L4vJFTYiS!1%OE=44Hd~$BP9#`)5FA=ZXX;qPK1xVLJC0&$a{FRkFy^XIg_n@ zgCZG{?G`C;5T!uScc1L-Rvmy5xX8sA9sIu~#wG?>P-r%o4`p3egb}lW?D0cxY0P9HJnFksK3|;wtG81iq9t^z2vi ztuO?sWDR`y!NRky)VuXfnmobnUTRJ)_lpEwb8EB0Q@+Py0AC{>2PE}X=rZ{^_9PFq zN4L41#f;S<(c8yw82p`R8_doi2e6}i_MYK$NaV_CDf#4(^nzwR2R>h^87dI{)bf5$ zAifZ@4xTa5*Q@pwinu>08=EeYcTw8kiWQos`j?J=dT_5>(j5vz!FLpwAe*nP=yMTe zb4=?{=ez>#dqdxca(t0mOe*J{%F#DLDqqb>se3*SVOscE*`TJ($Ut&y%N_w`Zb0$~ z4m5Qxu7w_GWr|9$grzk6DT}(0CVfJd{l!M0FMZiJ)bw0Te%mn7wG{)Ef3-w{^ig7t zd7hl=gWosrGgI+OTYE=^*bSX(t&=kU;@Dp#|EPSFMK|*yP5{TPm>juX{wOox=Y7Q< z5tX zvuhm!dco+WyM}fvqB76n$u&)x$xQty3ug(NV+RNj!S3XRKcH4zuMh-qYqa}7wJ(B)HBu!f ztDt}eLNMq!MFo4iJN6B)u^;$&@6d{q1Djm%!U1<$5U>=~93&j($xE1ZN$yj8FEsM# zrAg~E$g(W{q)Ok+k>|J5_})%>;QVkiKY&7Js?n=PE?IBB==8TU#Q|*T?A$+k1u~34 z{UBTuB>Mb;s#0giGbh8Rb+L@<{mu(w~UAZtIdUSQt=QxEwV3$J7Tq1=?df(Stqd)0Gk>t3aA`X7GYW)zv6S95c6TNN_*yhZk12?%Y}H;i1c zwY_aU^JD|qnc@J>9l3b-@LrHa_Ps_4(qT@GCi`;Ynib+yx(Joath(AXN>?@bV4y(W zYCghiLJU@zDo!=ss;M~Al>{Y&Hdqu0ezN$?Y<*%tuN7Lyl^{_S>R%S<6|4kUwvHRa zj5MiaB|F_*=(Zf(ZJ{fZ<7&T>?h^hqr)V|i0#`>m+pekPsvHxNStrQq5TR^Oekuak zv6o_wO@vR*Mt>a>Jv-Z}?34rm!=@0dzw5oRNK%1hqX%&QHyX94{COC|u9BX_yN@%R+49AB=)6 zbD&-rF&zOpV)l@ zEFryBg(3jKXi+W`biil!u)lP~hpwRi{ugVo4|o)+WB?F^FVnrLFHU3DDn^jSoL{bP zS2o97l;zu_c>|}I;&mWvn$o2~5Jl~KNI-@w=zF5dz=|G52(N5bdYAaa%e0rzR_Wri zn6FR=b3qjQ8X|uKBn6$us2P8VlX`VupYP^TLQX^Qk$U)NpRXjgLpKbBh}qupFCPDr z(*k!qxnJsk&w+srp!%Hfwct+9-CugYWbdNPWYCjwl%*V7Q)zt*fxm~^l+gJU)y#lM zjW8nh1>L=8$Tx+Z5e{H$XZN*}cl2qm0Dp4k1PhJ*MJM>h`}vo|MLqrp(&pHb`j#^o zd9`OEnWiGsT~gu#nVJDK!0ob{Z>KWXJ2sf0?HW4gs`2Xp;Ww5P8^1Dvg#gjA3+A+n zCKG|!G3E*A^SC_iBO<=LnD2KISPqSUL|`WhWXhVmZw|CX+e8n25c8GI-?)_Q$eOPx zi(4suB8RLF2PUvECuNd?i8IXLrKLh~ z*s}&j=|fCBeW1;>w@$UDc|wbbP)=5hW+Z1#l?cq@YsvxYL646pEJv!Ducgmh`^fzz z5;Yy;ob?LFAOV@WQ&b^P!eJF`vxi2S66}I#;y{X|7*3@GfYs$B#YQ4`JPkC1rb5lO z{2>F8G%)EKdZ|H?%-Wzb4m1v7gg4mH-$b9J`H^@#Cvb+J!Y{rjGkKf3HV(dLjdKq? zS;X4K$IdG#P!eNOW`11g@}po!XVZ?gHbyC`6{)~RA_tp5R$zSUF@&;dp5~ivgK&pr zSrhVln;UAXoO`PjBc(NJ`l)rK7$xS)>1u@S;=H96fG0#K4ENH3_;Shh$t+NBe-0pSOZD=RwMu|QG)T-Ev}OvKS{q%VlHi3m#wcyyf`OL#EsjgMeN^)W&CfB; zcA6<%-tIC{oHS5kkdGL5M4Lyxk-I1k37o= zlAjsRvGEV7P+lYGTKtyBFg;eQlV>izysi-rUeg{tgu*=vZzlAo;5eK%?h4m zKS58%$DI3Tt~5=cXrEGdC+>)0tJT9kepd0}P4^6k;Wavc`rF2L09)ESr#sUCxtNj} z73v9(C@A2u{Ew~d0uB3KDn4WE-hkf_+;8D=y7pZi1vIPuEWRqW?-uTIS2sxZoBd@6lI%5;h?04c^Q^<_^r zvh@r&7GmQ&fVa>5qGMLc$(_t{7TV(n*#i0z;}k7h%lFVN$#{nfiQyWzsUsE<|`@u#zHKB%TM%vDWjk zLQ0EbbRFUU7#if)G8lWzM7P3(b{2EtC}vcy&(p8PX7iYMg8{IBH(wz$ z01s|*DN;!vq`0Q?&BQz(WiJv<8KDC6bIyksBMABst6e_#P0IgT6ybl8JghlDSv4|- z-2zcuK6*tr3=J5qrMPf#F1KL*;niQTSXFK!Xvd-f@6CS{# znUpgL4}l=&+;{1Ha};AAC(vh@Rt7X2eUGT3bMHQ4{qmMX^V0FBAES>Jkh38GC=jI< z`S?a36LlwA3{QT=M=N(Uky)l5oL8hC1$TSt15uKOnTAmubnW`ZMm(n|T1;Ob&J4(G zg#uCJ`mrk~tH}W)CXf(Xk$#5GxOgZD^fLn&34#4hEfFtHu;7ot9Kkd2()Dr%K=>^9 zi>Yutay9plRb;x#cWCBh4hYFXsz4Bc^E#V`!^nWXZvfli4&cg(w`}U}P-PVj6N&1p z%+j7>5v-BDpcGGGbc?ylr1fivp5R47OoItf98hw5wHwpHkmg1}?GR0h&LXy?HNjAM zUM>N^|Q-Er!f|Uf01un3dIywnuLYh?CTardd>^NUnEwbl8 z6peJ90&aI;4qTxCzcG!_;9MSAF$gYmQ1voDA?a(yxRD^CYl;HIhS`Bn2ob50^;8+> zK+;_u`njzDNZ&wb{WiX7sI7g2To!k#c%mTr zbN3&1AKL&y^^TJ*jSW)_+`p!rqW1V~{A^&=VHq;r>b8my;#7;!xmX)p;r=&zUtxxx z+{H8MaNPz9L@~n82vRtOkiKTlR#Q^0oI%+nEO|}J)td{kzNnQ5D6`^9t&o0N6zNOZ zgz_x_-PzuB{rC;*nKh@cZEy#$tGl-=oiytVPvFZUWN1e!CP@$87HR_9n7LJ&QJM2& zbtcm&sDFE{^6!2HgIMD=-6n!2OZU1EBVMRj83I~n5wU4PD78V|6k z=NA+;zG*U+>mUkAr*zPJ*wkZimcG0*4VGP>`UtZK#TXbh&T&H`Iuys11L`6SGT&~Y zt_KcQt-VL)A6rB(kqTn2$G5@_?&j>1FCx)*2bs>}VhwQ)Pm@!%N34oyU))Wh&#o-R zB`t=_Zp-I`rd!*@w4pPnn%P=vb%czE_66MyUJSaC9l(z6-hE?N*c8fa-PlLeoNwdd zF5sHry68L2Pxj99b zlpeI8i%^S5ydAA=SjCR+aO{85(uEoNMD zv%=rm_r4uXyjT8=_9bu1clwl5Z$S}Mflug^`DxA!f;dr44;V0oKDqGt;gzF#_m-M? zubg_y0E#>HY^;lY5`7{f+vpzDJ)rmwdUq+g9rJhx!K#_~SeKV9(#*4|Aks4E8yO6h0CUFEN**5*Iu%o6des<7V1S2OKCZ zHliE0Ad#;-_G|8`8^^13cA8sdSIeDq3Xwsa{he29xq?aH$QgGF45=6?Po>K z`?%*5xpnd_Eg4)3)LYTIX3j%B8B590Ga01cxf6b~!U3j9UgoH69i>>4S@ga!fgit3 z$HVoLS&esJ?4>kxCTWtvz?0Al+1r`kzM*S@Hmm~(QtcnTx?Oc4LSc`*RAAy{A$I@( z)k>3$MNA5S>(^Y4jB_b2Q*~8%dEFY7eFLjV~W}gWf*@Y6yg|Td!$jZI1q7dcDhKBX2Gv168O_B2i zc1QJaEr&PEf=J;lZSph2z~!ZuY&It&mMk0zxOC*=!RKL|*0y0gHdakuG=2^IgchdI zOw(}Svjt|FvaOhc%ebE7xS0b+DLjIqj*#Cw=$D+=q*b=jlu8G+BrY5Lc-A2I$#zmI z^kiJ92Sxyb&ZKaejYR}-b$~iNZ&%tcZ<`&H6s9%TYMa-7>Y+B=(~z{ zSowg&pRtook>aUyy7)MyX(DtXsX~TlUOJ##ErH>6EHealG@Ze=XS~J0)DjXZ&|rSR z9*PK5BO3ww59=|P$4IDT;K0=ykJihMw2IOxQl3(dzbLHG4w*=Kn>eB9xyvxXa&mT2 z1{F4fglzK?HfQaqJLQPe#W9Q%I770>p^O`hF;usXT|Uv8SZm&#uC`$vz(i}hBONez zlolh;3jjFX;ger|sUZE;e#&W~^qbQhl;Cbeg0XwnIDDb!3p=|@zmtzMd63>pyzEP8 zrYQ}TCr&=RP@f#o{fL-Q*QG7~-7cpNW}N*-xD3I(Q}BTTkCE`tIg82?6-~*r=yCW6 zz!pe;tGe4PNUskIG7%I$6C;*|2X%yTG~s6`3au*wuqGvj;Gt5{D_&U{7o?E^7*P?A zymKDN6fOkiJmYBRKcvx6DPFfJs)VysKasAQhe%1jEyT6NKIfiIYh+5Ee&^VEJ$|Jz zBI1?pWPS3H`5)4O!F%p&2LxpP*~Z1i9H$JHInX@jng<+te$X+e2V!wSetPK*RCTzf z@>p>vojsbY`M`*dDyu_uEQHBwYC!i-Yum66;Kr$Y$J?9W86#Uf;#jUyOdp>j#jFAV zNTw>pq?}Rc6B&@NK+VZQ2NFV`?Io@8)m!)-&swKjPzTqHoOD`TnAsBQ3?eY}21(?oW1X?o9LVriW2?g%q$V#q}VCWAa8T_(h&x zFm9jB{?&X^zNWn;W@K1L1mL|D0QPn2eA3jZe7+QH*GIJMi?s>>>)7EwonZ|T7%2X6 zeWZ}H-H%BAi|`3@ROzF1ng$yI(K~kiIUVxs9-B zEn$KPAe&p`Z=HPWfbO5xwqYH>w(cHSmAzwhC?SPK(B|}gy}5#D$8cq$8%QnH<$k9P zW*QuWtXMD$=!93NTDD4k7CM%h5^v6cOBg&ME2=66*XH5kv1_I~TXLsTy*Y8&V|gZ6=3L);(eo@Qm$*I$0J-6DcsUuAUI4$qVTHj zE0p`cG{f?G(ckVz;NYyW`QT4eq6UW~K2vyPC6cS`sVT4$ihLgFkmszK_`t&9J4^Od zJ?vSiQmJ>>XLAfhe*VCzZp{;aFC+n|WdPuxQKYv;U~_BJWn)(j9yCF1b@Uljq2`2w zN+1%83$3PSnrtMQsY}QKkC0eUOx2LC?qZxWyFfW7Wu8nCB8f?_+0;}2CA$O$D1Cdc zfhf{aoZH#3dEnL?-GJA{ws-eTwl|aIE0{WBr6af!$rD(j4geBtBY+|bf{_K`{wIlC z%uF}sJb()2azGGxB3W9l;)GQk6D3FA;LFegu~@v9WX%K~^`LOvZ1?cFA#DMZge7E| z^d*^U3PkNJYr~AR_&iGp2Ztbe$b|h*%CynD;tBvDs?qypSF_=Xwzny>H4%x<5lfz* zmN^6o*3)9AuAcMNg-LG(bp-QGia?Fo7Z6h0In;Z%uOS;^PgSLPH=t|oz z=nW{yeRhPo{esj;L!R`1{o}*Lf#!}9ecXBQUkh|Rx5j0ezSzV|cTiAfbFkcv?Jj`M zHMPsfP0PpU?_pcS(YJ7y>j(kTPT=g`GWzEa+n_n=W?c=6XK7ax`Yj{YQlOfTSe{a9 zv(!7K4wJ%7tpNRiJv$XD^f{yw?QaGrRPr(6OMx*5JzDO8x%hOGk%3h}09G`f)Ls_( z@H+Hqb8IUG1`HU~% zG95=E=Y{RcuS;ZTUa&n_oNm_Jdpzb9dlNy1aEJX@ut&>S1@5vZ#Ram@#fA7I{uX*9nAqb0Sw7tJgk zp($=Cie1R-%dp>|#tGi4PP?Gzbtsy3V*oh)SJ2*6(`e&MP@5rrtc-mK4+(j^=C+tl_1vb(Wzva3HQDcU2&yNe;`%r7q> zfL=Lr(XP(!!Gmx*+6Ht0Tf4h=bk5G6-FRccr+fltvE7TFQ@Sj17dTSe+Rd{=vXZZ9 zBB}_YN+d%A&p}H-#r@@Mgp(Sk2<%S|5|(jv3JhB;st1>!*J25sYU8b`ZJpijv7$@B z5LNMBI0+JR-mItl!ay1m`XqI^Llhc0tUk6*qfqEftrUit^|Fn8U^B>>5G2iqLOU zA`umi3E>+AbW&h*jDqyVKAPCE2vfMEC;*RAQ!;29AI1qn5Y*xu>Zy|hz_!k|v1(8) zeAN2D(vQ;W9|8Ky4ePF07GFo1^}ARBDP(rg_3T2PbA}-6OB|{ zp?P8^po(d|mFz(zI`G&^=I+{b3UQ{VOyc_2MtU&_B$^9>A|*zJ*9S<)NXif)LDqO` zyNAx-J$#N50Lnv{VcgaoysbK3yMF%QX=0dMW_TwiR}$>g5B%yki{etqqUPL$ zL5_iUnzqrt(GwBaH+0U~L+7k9auRs-EV&98hASUvaz-#UOz7v3syUr*ndh;`8ifyr z4k7z;tFNVR6EFurkI((m?)+VzluT%R4%*sC_a$2t6|~T6%Le>{u#M&b##&RCkKbbP zJ8WhUk&T8VI4Z!PSg!y)!c4Cb7L5(6(RQDPJim}Kull|#iIl(d{;3>O*b32%E18v> z9S@nm=d1W+G-<7+p(-IZ%F2uL;#xKrN@rbfdlQ&J1PFO?)Ji zn8tN&Zwvg97i4q$5($L+EF*9v^RWfqbAjZRspmx9O${EmVwi;vTC6cXn7Mq=p~RV} zHO2a3(5C(uLvx!G=_8t5yr?#Zs}{LZ)s^p(od2@?9A` z6~hSl^5X2aw~+^Bk1GmAfLu3r^;k7Nco0rI+h`78yqelNwAZNz=TNcB4pu=hKWNX_eypA?c%(Dm6co1D+8@Pxf- zgwp{w8C{jJT@IprVXH)MTEcJ@ut+8r9UW+aV-77jzF#DPHlrj*fAyovn6=68JO2Lp=sZ1X#oHq(V zY_An}F2y=(aQfiX$&a$&A=x<@ZqGh%s!6!dz}5Tb`_fgDG^aw%M&R|T03d}`w_|hyAh_fzL zFoWmsq%JSMSv)%lH8qD`g?UK+O{l7-J5x^3%ugiHdH9U9be8Q<_cWeFwLbXbTh`^d z-tobMkY=|^;3@!!hZ$VO8ZU-uMYc{Pss_GbYJ-Lp9$R*V<>>-M)7O|g$uGiFqrxFE zRPoAqHR3E>uZ~%!X6HeN4}6L^cx1nInqD?FI2Gcv)9@XCYnwWH6zxTx3GnGdz0X4n z`<(YMgQ!is{2avQSK7-a^c_qZp@3(L27>ZZrdsB^+S^h5$3I89Y)_U98CGj+h4MCq zJ-A3vP5zFcTCFvBC+fK+)E#D_?LqamPECGdI1)v(1ZL$Dyb&aDf?Mt^ zO?k=N&mf+$P4=W9_+=>+WQdUYgadeaRFm#`_xx#bv8 z{#yjm=_BcFB!!yC92`6jGo774`r;%f{TX>Z zng;sS?b6MuFSYbGlEj3>l1Gtl%-LwaT0!|C!F<#V!9rHvH;n2bmA#WflhCOvBdq+I zZ%?Do*1mQaBS&u78s@^W_I*METk2OgMWyIg(KRv#Cz@q@Qis(UZFVkw^rFvii8*P{ z>SvPf&6QR6NUxT`NN%N1ZsaEb7jUwx5CmYlwQcaI9a?_rx#bsNTt53AMwP7a0#oU$ z#@7&-Oy7q(cR~CI?=>&rKbkC;=U@@Vl|AQwxu!`?L_#rI0J9*fXou?3k#mQ_(BN@6 zy=+4{fFROBWim=RyKM#9vraKVLN>Yqd+1*Gk3N92p9q;g)uen!k+bw)6LRIxIP>zK z*gQj35a*107}oG!f+%YcvEgcT-{=*b$KD6YE8PCXiJw7OoM<60PFss&c+Ow5djkm{ zF)J@!R%JMf6-!I)|8lyI*DGQa1JhFHv9&HG$xYM{&g#g`;h~Qdk6ZknH z3#Ig*nV)+P)41rTB~NB8MA%#~+t+x|rK*Yq)NNF^Ilc^eL6o7>y{vfg&d9t*_}1@&Y9h4-|EamD)DReCg~@6tTJ{;6VcxUS*AXTnAK zC%_@w7H-~AU^wN_Yzc(2f85E;e%auQ3(g|hI}b7s{?wl_MU|pMxvxa?f-NEG}Ls=bS>)@h>4stUei_ zJPW!HqwIPSjQpwRnqrfgf1#7G0sVoA#ll|Ek>IzGnn^zl_|}DA?a(T|zexZ@ej^pJ zf(xF1%F>WSZGo($K;Dv)!vmI#^;`&}tCB>6nu!!Y*z!z^ob*k64W^s28HMBnqhM*U z;D|%_$;WFwMRr&Hiq0#Wto|u~E)#-`z1fMgC9o-xy}lGz5vpkNq?i?P#Ym7wu{R_3D)}pBfmUMwqpkbilI=oWsRDVo;}^@V^U)IDrVtX zkjyYR!on&Ab|sgLxfUeKe_%-qj(4GRN`6^OaY@BhMn&cg?lIjxSSM`q%l7uBi--3O z9)#1&HjV=@p+$mF2h2bZP{8KeVIs~d?xf5D6Uw0EP69f`x<^Tw)&dP969&`pSpLb9*kYv;n%5THLyEadkEXmUJ(==xSgipUSLAzqR6Sn}YG&zrmBdz7 zKR1GH90vekIE)bBa@2|J_E7}Yd0i1B#C|kZVvn8JnMyU3NJKJ~msW^Sn}xJgIIq_ngX=gml;!ZNW?oUl&NO#^N2Aw5j1?e);ap0+01D2nvG zk_NH@1XX^+;<`+de^$njnTitu`{V>7KLN)PA0=D$uLY)JW;2s%f15}-I!icco>+vH zvrZadhZyG4ovfm`M`5ueOPGYUH`ygdk#s5HGg4^Y(?EV4^6Yp;o2}>UE9a6%XS$1; zOH+G(bS=Vl$>6Uf3hDe>pP2$~Jb}H*=mJZJVYNMsa=fQ`dM1b`_Pbx{5Nx61=3dv+vW;;2ui6sIYhrG zA7!FxR55b-ymiF5B|EBRrgSY+k(iO%)sP$*d5n@~SL&<_`RVJ4G{7|ryORomFc6WwQXhwx5BzxH zvBBd|p>oy<537kMAb5d30GZbntI2@H;S=nnha-}2fvja^RoS>3X__&-^n9Ee^TwK1 zCCg(HpsPD!tKC*6KYf26iU$Wz0OUTTO`VjC)_|}4u$XM<9}Y3}Cjl3RE_yp5yg z4kk27dJo5}c$GNl!=`k3=6ijX^0$H-JG~{50fj`^^RbXDMNfqT=Dn4P7s;*l`#T;2 zYi)yia^dlVD@Uy*IoM9>4M~Z4OjrMS^+YZ>kdE4EeW*8(geCJ6BLJL%#Y3Z?W{>O# zr&>0Qs-6ZgBrt~nkTvF znbg+NZxA4b*)(#pITzf~st3gNQK%!?u~j4~7HqOmR8o~w>= z*+HpGvGBXwun^iQ8JV+Ds1$y^z+)9Zft5+sRc>eCY_dIR_T1fjTPrj7SGql855h1q z2SeV+=sX|(7B2?@uchfEB8Vz&sn=gPrMmthxFV|gSa#)8vz$i*1$7tJduA2G@?t{^A&OIqjj5M=2| z(^zBjoilP#yXxlKOYtwEgeXg_%s7?*H7P7hIyRQMQwn%pY@%Xhuj(UX8UlQrqhlbC zJ}?fbV(LDj)ElP+bX)&?dTO8VJ9NR&S^TjYPj*#dO^bw6gTCT}=0u%j5~pIxGkri^ zNy7wX)&VXKrUg@o zC@LH`!BFV#AH8Vs(DD0vIb0@onM052f44!Y#GWp;K^#COtvw?bnesqaZc~kmlrzsCZ-KnFMx7e_47F*beM^stqmooA z@;k`MiVNmhSiIT1jZ!yf(n1t{2c!6nW3h+ymCUwlsy7pkew6i*DL?r&=~Kc=DNxB? zb0@dTvO6izLhKd^jYu>7Uw+gxZ_fAN5Lk@1=Aq8uYOJ4Xx>fuLohZZ+Qwy9~uc^h5 zU80G?AYceQ%pDa1M;QWkvu> zN7*&;HP&XQ`18yY z!37|Fv%mbXlKA!M`|wHSSjpK3IBijN^iJ%Ln3PdN^DORLGTHaAd9s>szJdj*vNKZe zr2C#?L9rDjnw0o<$`BfR<=b2=E)@?Hl(eX%NZioyG}1q0%qikFDr(L{Og# z;)&D*2`sp4M(ut+ifrG!hN6;s!dy;M~XZsMZ8fG)N<4^a+xGp%=_Df01g1 z;Zf$hMq`suOGp;Jrpkq%c$@;%haxWyRr{*N^xzP^fKSgZ0C3QclnPlfO_9MW z8l<}B1x>O!*@ zn|4QKohcJY3NA$(#&l+_6wgEa6Fymx9))Gs{V}UcbD*{=0*&mf7}F5VPt;~oOLSS+ z_)d<~#Wsio*wNivNhht|G-EAfQ(q}eG5RXW=^}s95Ov5=K~R3BfG38$U=9?Rtq=nM z;43ZFAw(EeGY3S<5h1~5oi$bjir{ewtJ^Z9rPZ?%m+G~40w;QB%RxbuvI85^GGgFi z>nblG(D(3j4tS13Tx6oGb25bV+ox+M-y(r)C#|cr=)62BVVGgPg#fmRDObSTC^{$# z8}78yhYCh89ke~JDB1cN14#TXAu{X0P7w>Ymwi$$@J%DDd9pAIEaVdGl=x*IH*DQOd{rjYNFI`d3hF=HM+y?|QsDM~rSGxuDXBwq zAy~0oMwDOv!Ms^R5Ko= zS+a+qYud6dA6Yq?AG2@;5Vccnw!2Nw36n^0tqI*t@idX=0sAh1hCV^eR*KOkUzO=e zMSFZK66<$A){^uD8EP>ax3(m*(hk+FlXt9VK;Hbe5gb5}YFl?N=ef;$hvX7>JRzA8 zM?KJ$T#)0_(bir@LP8+vN}e_%_Vw;WJu81kv9wmvP-2pnQ#G$!zhnB#imp7n_*7i$ zdpT5n0w+&YwAOp%B&~omV_r^dlY*>$mo>a29aVnLzA~jq5?Fa?LG9ABqKA{*{oG#x z(6`h9DGyP|ViOTCwMr~ZDD#$Vv_Jp;vfM$&+gKYV51{ltm{q9gzTD?sjuzDaZa>8S ziIBaQT}u7acK|w2ce}}LtBCT;KJ7+KftDnHb-%-jrv^p<0d!4O^B{`f{!HVRJcPWRxXk=eAH8;V6+M=~;e!yabT%YAm z$Q-k0=6#li^N04VH5jLdZ3G7ZNC?9Pnj}jKMh@zC<~g9oB5ohnr7^^~qp zku>#jpM=`}#?`x83z*Ge56$8lum;oCBKfAf7b1}PR!?#|E>H(H{wMI12gpP@mZZZ( zI2-Mfo+pS9_tV_>;9XgVWrCksDhJ9RI@^?7tU)PVjt?oxbY|p665SM^56t~;E zH&*Ieo+1MGUctg~`0!f<%or{mGLbd=#R@Fat^fnD}6DD~0uU`1#`*I?6L zxN!0^!g#eo#Pf~d0F2rAtTFIR5Ma+W7Qw8oQKcdc$9jtfEO#V{N+*C}5-I8FnsG{P zegh`3a2ip2F&&p6tCnbBBw-s4glp2Kwi+WhR8t^oTv;piw0&sLa2QMScj`_oR(Dz= z5lFHuLvA4!FhbB^>))V_KcxRFc3P#alBojIP^K?h=djQ#sNVzX_)?&iyKT*@ln5lA zbWyTPTg<*`+3=8YmnADoFS4%bMDLjRHg^w7I-blMoOBqAF@#~HQ)WR_$5A2tgp?V| z^rG}7q{H+f+2;|PREux~?gf*V@(E7r;8&o!q~PQ?sfW>^S{Z`rjcQ2?2GTYL(yfNq zJPp6rg&K8C$6n+K;O<8}vi5)}ik-WjpA_7K7VZh|N8LM;3D`4G2B}WbxY%7wBrz&4 zsP2B4_p+I0^~5%g$`An1sxOu}jcp@1fR1$A(sp{NlIIb#tSA;INx#n$@rau|&Ub;S zM6s6(#>y-f{9^Dp)?f=6zf{Xb>(@YT1*r}ZEv;eF5Fw)Q-vPF{y}cVo6%d4?pHx4* zSUzWi#YZ5m4^>kqOcgeK6DB*<27`qYzRbve^O(5sjqD?>^9u2yQa01OXwJbqD^42i z|LJ`#l9KWPSs7SEU$l5w(V#;Z?SQi-LlxB+ z*0UE4>HCQe2mM36dW417E?i$BySYS4H^Z?ci+1Ix?Bi7;X|Qd6hGeBG9%t0GYLNdN@)@Cdl@WkOvf%bQ!|(%7lZJ zL6-2sb`_hcHp5E1;UNl=+o@VyZh%d;Hg`hDfW4&RWLqF|xl6Gok&_aFLCnhILP=Dz z7M{~C1}f$T)3pzg$_3=8kh=0}s%9y>7;(sKS9^L1DJ38n7ug|g|kl8T- z(e)WVS*5%PZsN_{BKI4bpL@>Y8d=vQQ7SXZ{DAmO&goS3Brt$dq4Lh!xSK;Mk{>Au z6FSqfZI)Pw&Wwx#8%nF9E8Wd&9fZji79QN2ZMSo<78^bP6tr*9O7h(|8}id}l2Ld< z#xvOi_%s%uI|Z32_?*X!YTA>DLwPc!7RpR(`n;hFH-Hb=2o7L-_neN50pQ{+tGNKR zbKgiN`XRy~orE3s2QYHh5-0%_u0owdQS{HWAx}xM^^~Wqy&U0!CMTOOW1=h3p$|s} z*l;ykNz2)4UPyggKQ*m$hsz8&5^{{b+T9e}PeIweZ(WrGidbqvd9jKDF|%WbhV+s2 zhLD@tmwd~nD27EdQh=H=<$K4CJ~?;|gE1g5>Lc8Qsj>N3?Uy; zPDsaLcMC;a#i6q}hyQ|cTj5bwg@$58+#Rm#?+hn3C>IO)KOI6Ec@cj3sJJ_8NqaPm zuQhn!hL@b2ux6wVl|f_inwG!iNr)V=8db8WFGtaEA_tqLDO8111oqMA2_I0pn>&X7 z^gwdYnh7LS}tDLcj<)o-w`Ga9`C&k2lX~nJO_I2-X<8+!;p@DbO%Ytyltkq2U;T=Jp~33xlSV ziRTb-7C=#8i@7f=sAcYl6N*#T+M*&7Db)D1D%^%xdu%VGp*la~WV$58f{=thn5M=V z3eC5`aJ9zQp{V(ODd&t)DUqlWNN&I;x*H2=M+ldkFSlS*OC)d1;mowz&25e5mL)3u zp}~Q`7g9d8oZiM7D}3DkRDwc-Nc0CPNO`?Y?THO=AjE0k0RWYB?DYH`>v9{3O(vq4 z1T~N+^WqXviaRkwjUkqSC)ZI?)~$JMh%GyCb`n$rU(Z^oGaTZk(~e+e;#_n@FJ%z3 z28gxNZn*3ytSiJ~TMV}PN~UF_Ar95ahgn^agEx6>w69Dc26_h0?m~1+->N7u-|Lc^ zsPEb=+=yYR^gT)l5Cugl)$r338@Z$EsFu3J?rHYMYnw4eX9_5vMXs6T$Yxf6%mu75 z&~pD#YD^C2oc>b`Pd7aBJXoTex&LnL@&l>r3v7f z8h1PZ6y4AsJa`H(wk8Vz=Nh*f=E2RA&!)Hj|JnP`aNDlyIuIOlpL5fT$cY3A0t85c zBq&BvqA1#mrDQo(Io0QKSN|#3*WLc%ZdZTZU9RfScDcIBu6C)b%Ry4LWXqDQEHQ{V z2ap6wBqHaG_wdqvH=ncD>>q26G1tBT&b<^t;=PNzL_OSl?mm03IOdpR&b4-MEo&A@ zP%FgPau-)XdbI$e3V_Fys~v8fhe&sai!^yddQdTf){wrsqZ45L-4qrw(JE7 zsGgw9X%rvT3GDLbaxc6xH{wdNH)c+Vur~_}878o1oggOKKslwR8cAo2gFloeo zg%Ay%!NJTKJ!@t$8@X@4$ip^zQ-}C`pl=9MxZ0D{16&M#XyY1d)iCfao z_)8p&JnRpzCZg^bi1sAX5fTGu05thm5u`BZ-_ZQHtK!hMhU9}lI8N4iI953T zn3(vk=5!;H2$mwm5adOVtMk=(x=Jv?wmCE+Y>9jEopym$>J+U@nwQIx+%ORUK}uuW z8caqG5M?90GC?*zV~5ozXDYW&QYn_b5mZY>0$4SX+37|-t_5vHH8iGZ#A_jE#tpM3 z5#JWH?OfXDR{lx5=z}X_M#+lGHPq0_YatkhWiYfIXkZkIK_JA4z!Uz|agx*WO2oKR z(AeGx%eiOmzp7f?LH(Cj7hwGiKH8}do!*vfUPM2*W|zXk$iAVmsiEii`T3*49rfxH zk%?`zhnuqN1f$VyzS2ZuXcFnIvA_y}kUmn2NX@@QqL|^bD~&x2AYvo(r6`agj+mWXk7kSv@iKZYMQfp! z78e}JM)uX81b;Mb(3s1>i%7cKvSSel)*fh9e6@$oopsRzHg# z3<2B2g0`9r$0GM&G>p~QKZ^9I`CVJRTEh@AS}<)IEGJC^7(<=a*J&C%9SBNqI20LY zG^ZL!_gGa3YiI_(X|8op!;}s^7~0`Fi;_`su^>&0E0NTUR=AoK^U6!)iBu@mk~Y=deR4@DFd{8D)O&9_88HOLPK!^NSx;An zo|jBmH9H(ccFYdsHHuF7iNIhry&2%K$`7a$vwve}U&qf|=I)U}AY%Y+0~Abqslyic z2_dV5`;z-GK!!l0;_NzOGpVE#8e<;So;M=81~mKG89{0Ib<{a#b+=O=78H;1iI`7` z?IXdixsil8PFm(hO)MQp52-)Dk`#f{oSj{t;(^yyaf@}v>0P5C2x3G_V_}CZrWUA} z>KRoAFgHV2mo^Ne_aAxZ|L*d?xvMF44wt=P0G7rViMHh21wU%`Te{jy-WZfNB;z`9 zEJ>j0a)>A;ql^z}2f_kDbH?C1f2%Yr|WBWGiSj;a+1 z%&qLFrLwsrdO)Aa$J}9cqa2r^o*J$2uzw9lB_VISjR5Y0&se?q8qs#3@>yUjzhZH4 zP%P;t{*Qe0j-~Y_81hm3hMnoquRa{KItAK9TY(xIrH9n7)Xpz#nC{6*&7F6_d_`;M zJjHbqA_bSKHaOp!F&J1y&6YY8Mw_k6b~d5C_wh>Jyer-EAO~7{%{6pnqAT=Mcvp39 z%2SEIn%WpPqV=@W_h^=b21yCV(I2wMBxc%P&K092$`7xYyWqWt-@Idooa1FL7=X%4 z>8B-x8L?OqTWA?;mWWJMqza7U@@#{oLiq&Eb_NUTD}j)LVj)L3*Ajs+W@6qa?-r91 zRzf7NtKFw%Yj+(|LkpR%!u4Ej(efWhRRSj|i6MlwsBr6mY{z+Yo8(OlKGRsTuIg?fM$iThZ4 zvllH>pO!&>Ry|*$i9!q?EMDPAbkaN832?LNzju{)|wBV8!X2;yhAVIsT<&FnXGMvW?L!OYh z&`dv7gQlp!6684z2O(%@W1o3d5oDN~|8C3@f2d23953ZBEy#v2a&W5-Q*C5@ z-F(ImD+Bj-n40F!>_i_lw`xA{64JA(fDCv>ZCwH98e-CoB1Op9MNUyGYi4;OjoMg~ zXhWA9w%-zu)3u4t09{%%;fK^cnmDS_RA>MjRh>#*{3-@Bv-CbK-iPh5h=jQoSq7!j z1MtY-XM_Nuype;89$6?m1OE>I3i4Go92kmq5(W*Z=c5QC>YUVp7qx-asjb6mG!PLT z^wv`Dl2V-GWiRXl0EEto*OpLi)VI-baYr(@R~6ix>H0CMq32t>EW&&B0M4StKp@Y@ z!o5DqNXA5T>B2 z*+4n7jaX2xt#7lDX<%Y}bc~Eoyc^ac`#UbP*hv+r7+vNOCiK|l1BcaD<^Vuf;*Su0 z&OHHSb>{SJ_=mwRwh)(hwOqr9wkk04T~i@S6F!|*Ct?n@BaC#B&W*#nfEew6Ya|a! z%_RB6%RoZyTJkWZ)v9TehNnd!xuNErl-Vsv2?3DLZk$(Hf_gtWG{U;}t1n!7FHqMbgqnqBBebs$||;tUFkAQKbt z;WU@A1+5N-I+{bMZ=T0xFBpJEp_UMc5@%X6!~`>V@lKn)>$ox%ND3suPOxF}+&K;E zVFsEKCPZtT1Tt`t?TDp8>GXs_=aW6F5D4MSz6Y#wt6g=7H8VMkS+0sota4jUT&q>5 zMU`Eum8^R=)Rk=p0k~a~Ze}P1`?M=fXhzi5)WHF9GAk5Kh(RvoW9IoXrZz$8#v}9U|0go&E(Uf4{ADAun^%0CrIL5rNME7M&SwT7w(S!MPuUH`IS}= zUYZlo8*|yrb$z3m=jmc`T=MHXIRORz6ophw8mgs5$a;nuRgI$aT62WtNAa2B$j~mi zAO*Fvy=jMtOgsJg7;Z_7h%fCBbGR&{FXL!&~hOHjp`sZVx%A0#`2 z=$BeoWZWZ~ad)9WR5 z&d2q2u650tXYPBRDYVtgMBN2&e{;Ao-PfE>w6ZZ`%y4?!Ea3Y&nac{0*(=90uepa1 zk&kIKW8IZtl<_j|yPf z2&XB~p&n1A4C~^Q9$V&oJQY8W;mB@vWCbqIn-%aqtUguh7P)h@Qdd}+#J{rv&g4cY znEsH5DrhZ2{1SX^M#RhjqBlXBR1fa`i>QkA|5NJAd1;M_I@lS-eD!_f59bKZMY%Tb zj@#{Aa^OBeQcp!oWh7;_jzz@%%rS1$v|07RK#k$CqB!&<>cw|gXgGYm8->Xgnnvl9 z-2e*#>HkD^k;6<_knK^=ARY=NE~h`wQGTJQ3nuJf=h8*LG$1*7AZC&=RbS%G<`+*q zgD{j_zt@E3U*ug{YeZ}sMof-=&qn}XmaCv(LSi5ee?Od>cdHIX@VTC5&uJvcIP>h+ zvu>+CXpA<>4@H-!#vEg@S}JzT!f>11LoLL(^V}Ln1Bq!5QdYb*2peSQ%70^aVeATY z$igT}{+~6>RayQH3mBJ6UKPnr1hXe@btcoiFvA2hl+h? z3UotEWz1X;fMx*yr0o*}NO6b-jMC06w&Pm341Xhv{3X>cm%Kt5A8bv_U8-#HQtVEMUD@wdLl%a*}PxLT2$& zU`Q#`AJ$jnD`S}*M{`h{5nMwOE?}mf>~&<%A1u-hwSbYFi<7gPDCd0elv!h#yTqW* zO~J3fz&A4dow!2YqSvEojTIKu-OxJshy~!4B*=;@NgvoU3fx>xEDzSnq`cVWZcK4y z%ddGKM}6zlIlr>9BsAY;wHnZx{p3{Hd`oogCCusSo)p>j)Nf_#aV?V8eMh%Y18V&_ zUY{0VyGr}pX!QL5a41Q2Jt+3SZQOFY zBcg~#kaNw1y>lT7uD8$QGdz-kNWrP4QqJ5bLE0W4Z<@6e;`_6o#-jgy{3B)f56*^k z9L@%haF^YtPu_5@=k{|FgJtS->~0}}@YeW&1hQiW3Xc{k$CqmeDJQvLj)+sj>S@J(QAdg>A_FGtV1!7$D`w%H}$*X6HX z-_z1(yUvQ0+wdRek4Z<~`&0jgK%rR)f~{;W4r%L|(_<*=xkCm>FZ|C|3P03S^QwPA zz{>$cqtR4N_MDszecm&OpwZ3I{(q202K6=gEXD=eNHN}4G~9WAmq$O(zcA$ByBmA` z)#vv1^T+)8Ud`ZOcM=&Wn2X?-7;%Kx(Ph}t>%?!Ga95;zLH zLJI|#we-w63kp!hA9Ar~K9$ur^uC4c3l{#k&TIAbB6Nlo$GLS~Na()fBgOz^x3rlUY_R64>yUmc;Q8)J>6x8+n9~p#jYO?=bTr#=kz<+Do8AVvd^tW&w1QQcb;k4E#*X13<*yG` z)@J;!b3`keAa=(c)%?wSN?oEOIZE5OwDik;-Yj8u zAs;Wlb~Z<1!L-Gy*7}SeS0CB`Z0I)E3b?G8bYy;6)Ud@A%|6vGr;=xOd9MEvI8Q~u zh*=M6gIMYInPHp$wwqn|pSUwshj^7sfeaY<$*}%djQ+;EI=-jx{VzfKJV`cQ7VPP| zD7eZ${3OWS(ESY&S@@<9USOOsaQm6Z=67Oec;~!QSp!ZltB8DwP_0SR-eyza7Vc{# zxNR&0G@K7{UDZzgS=inq6Yql9A^{GmSt4uU3!9!>8%>jqQYAK`wmM3xM{#@nlLNK)rA8S%-Kssj60`c(;BgyUM~S~qTZVEwl#2H$&o`Hi zgnY(T_&ej=zT#%jc2^I+&Hjgfjh1KU;NjGLy5sfkp}EtHw-b?w zwK0nOG3V=Bq8k+&weH}`nP(Rn*0_EGKM)mTl4oS5Z}ASoeHhZUa&Zw3`Kbrsx1Cr& zoU_Pyt5a9S9gBmg)02Sx-BtIeh8cl&jJ<<-5m8qFl@WMS9U2@3E(TBByA_en@`+Gx zTTR`-@1xj=F*x01P^RlA(@p`I z(r^xTqo{psthYKH%oKlcz$`SUW9~#G<^HPekD=bTNvGP(&K>XfZbmzZdcxV(y8IW> z&c&fs&w0qTC@2`XJ!v=j91bhrWe*b}X&~`Bq28*};p_C~Mw6DG-9)3lBdD{vLUYkz zM=4s@ds;MUP?Wk%TCgr}5O&V9RC;G+z?6BEaQ$X0C+_Py0dUG#IayKwE+s?n56`=l zrYZC)XJf0)&9E~l;;1%;R*|H6ibz9Na5sJw48pKNm%2%rV{BPZkx>$W=uLr2}QY|j=SzW~kmxsVc z9bPc|#5xda9BQ|5u<7HzSdwwJ2HnFdT0=X;u!sdnWZMVtLrt!YJZuvxqIJK)mr?CL zFW}nMg2$$Rbs!JJeA4EJ?tg5$IZV-0nhsgY10H+m3U9)OhVb>au164CP`sv43_tFxr-@{AFn9+N&3v-?3 zMtJ*ClQwbjGwQP{pBOMX|9-F|g1H4r^GA0&Fy_s2n(rM%;u&(`&D)!ojULxfWbP4Y#eAobSH>tD z&rX1Oq9h1)df#lhwEOv$4Czv}=*>tZK43;X=rDX1Lj<7vfk`aU{AR$M_xo-()_&(_ z74NMEpuNXUB3l&ZJR63IASj-^SsB=#&(K6FdXJ9(C!@S{Zk1jD;6e(I0xvee{Jy<+ zLy>jsk?3#p0FNtQVxvz&%rG-ujY^RnB?lIUIFwpWR|KvP4}TId5MrrNz;#tQAZLRt zwL-A*?Xgj8M~kx4IY2X0Pl7^GbuU_+I@iHS=12DB zT=bZ%J@0yy9*(#TzDRg#7)}GkiTg?nE4)Gt7`n;~MnMCl0XjEwzFu%jKY-a3Ny<+! zwXG5jTB=`giKR%qx+1!?oQw$5N;_K+7LQWG2`-h{2)B%Ahs8%I`Rf7P%780XCf!h{ zqxOg0hSNBvZKoy$ocYw?pEn0=7h9K3CN)FKR^ZMZ$8^*lKv>f`u}GjIge9pCzP~)W zjsl4{x2|gEmh7X|`l)2nlV}prU?djSNSP97EZL+ZjFl$(4AOB@e=E zuTuXC=;lG=Y<-M^8>I*L)Dbb1&+bt5myC39zQ79Sk!+c~?ek`MrxZcCAIYi(Ie52g zBNWk%l@8uCsvP59HMv%$+^EtoJiEM1D0qGm&d837tsb%yZW*aRADc*foaSBHA5`%e zR=YVl=~V!Y__gJfLDY2OnkU9+rw#zxQyFn3)PQ$AiI&IVc)?!)qAwU z5?y1n(cEB;NNUdD5+vdotBxy-=aSzvV6G;X(4X>Zp&wdNyb*F3(tqn=1;k6RV6Ie+leoh{X#9$A-Kf z{8(c=<)qJn-oBd#sMXqXD}y6CSv~QJq%g3B zm*f_hTQI_uHBo%11}(sxKU9Rg?JyEWyEXzv5D$OF#e0MXk?(`?Y<6eMh)z>g{W?ak zXQpS9W!3>mVJ7&q%brXMMq7zL&$UpipNwCz7Yd1kQUVC^Yigaw(9d)@1zbCbNfr?} zj%!#=haG4MCT6l|#DMiJba*CIM<#l zD2P4mE})=)p0ftCZrm}Ni`5Lc+l;Vn46i6#h4zPWb^<&&TG4}FVEV(3NQb&m9UN1$ zTyQH$Oh7w*>@6#ia*A)$qu9VqNx;lMWy@20XEE=T-SvkwtE56rM#7}W>mA#XaF>siVKC1%Bn<%Bl(Mqi- zd7+`Dw|&WGj5ZK1fWSoCnqzHQS|Yk=wzFl0${az%N|1UEU_19`lXC5npA<^_&ps1@ z!Lh@dv@SeXhMlYf#V&cTpNWBcjkoz|R70mJ7=AZfyiy2n_Cwdv+tbUIV^?7+dLNiR zU^tgw`e{Geq61<4NQt{shqbH6IskJHKKp9G3G<$cKw_9yF6w@6cR^g@uAvn63u)H zgIl4sY$45Hs@%2f>n5pie6}A9xw))hL>-I<;FWVb)k3N1{>^YO^9!=ujpPPwu!niD zcND@r?UD&U&dI{fn_I%?$o0zbnwG(R^SnT*T~Nc-2A}mN@hszks2T$*aSIrchjM_HT`Vo3a6$R zp3$WGlOy2o)DI0Ja;>^6MOv_ZCc{qhMYx=3Gn0@?DYn#LxNYgm+-T(37I;Y}9hJ%{ z(W$s~Xlu0Z4hb#m_Z?xGxopHi6!{&al&`46Rj;219#ed64zJp+TB6gL4k!-Hf3-nv zMEeXmWz(cGdUYBXCEX)yA9=|HK=XcU;*YsLhsN?NV1Hr?Ed5Foh(3D16|dp#MVrXH zl)whv4T(cw?Zc~XE|C~gv5X~m`k-ia?=ip#%YlKbWVVZbb$%QFs#GtrORnc6g^;ABm!eg7peh`*w=mh1{cEo4z&0qt<#zayTi&(U7cO^_w~UR#+fSut0;L z=b~aW{2VrxM`lTZF`nx{38*xfdVYmJbVFC3M(lFtZJX%yt*DaeL3{5xVZmwghU(f- z9=WO1R6rm5&aqq=qFHQ105EZ?(`NZb@5^-L^~+fuF7CTQd1$_~z(xCj0I#u^RLn%M zJ-nd3O(kRDCL4-Jx@>i=6*p9GI3g(o*Hd_p+j=6{QZl$H?I&g&iyNIfzHA_zcK52- zPk934=${%EiZ(E8lSKoDg)=|HG9_EtuWf!cOvUAxe4yMCPHot`ELfTGfS6ZMohzc27)5nd$w=n;n zpJzne8Y9pCZNw4qw`wEap|{PZH>jloxWBeEg(QfA3!}!9Q7_bnO$}05pY+AtBaC5D z1{~LcB?OgBj*nN+oXLp#r_d%sdB__!?Bp@+aD;_%bR__EHNzO;I9(xO=Fac{45G^n zTO6M`L=_IL@ZVz0Yx_z_kz32?r&wPqcXgn8&$vxh^mT^g(WTHNiMFnGXQTu_%kC~= z3YVkV6~50;7ousn%k`iOAP-tMgMa#$vOtz5cxk=y@XujcK*7fNQxn%n(nnUKD=$s@ zXeAC9MZ3c;{34DGYit2c0WM`1i!29OpT;NLyu)^EJBeJF2jBUa@Iab1AfGYg5UX{I z5>VR3?S2Q}?G;-_KCg0H(TE7V?Jq<&5LlbTPY&&%lUHNSk>M|2^pGIVe#(z`)LZpS zHMLtkrE)AH~5^T&U#3MYyuD|4j$AGiNhTLBMC>^4eA{HwRnLQ|2hEFw}5&~L(Lmc)}(x_E$^7ysdZTfRSw3r%R5n-oS6IT#1maxukxl|}8 z_mc&pe}@%dX*m@H`@(82EUznnm9n6QRwJ%$-Oj2Hy1e|PR0!a2FriAbgCtruD?N>+55GD>n^&0#y zT2Wu_ufk9qrte!3p)w#)L`w8;%g;`U=Sl%dl=R_LwxoZDXdkf7{9id(i(?5^amr3@ zs5OsP5J~ZAdGUNo?g}m%LB46>@ZELg!@Ts7iBp zGfHfWnzlkrBHD5>Pm?cx5R4=^@t&@ z?*IURY!uZ2Prd9!*ZPNpw-g{#-y#tHLV7d$QPV`ZG)NYP*+X#%dlDp-hFUSu-wYWH zMJ3JL(j5(kAY|Rk?{xmF%F1(SsI9aFB^-9CX0Zc-A7=^I&O|$3RLxQ!H3i;q-IO^e z$9T&kNvBQh@35_QTqVpmo;K+v0y(-pm0_1Mhf7iFYku9j zeL)^3K~%6&=*i43>m5o}|B>k!q{cI(+3{s#HA{0*vMsuPi~d8gZF`jG@!}@STsCA4gqju zd!LWWE)}idi}gxp-VjQ2E7ca^fp>@opKBj|FVz#&zRq@Yc=wTOv_#gsoc)s~y7IpQ z;$KHi7%II969n^Yx_^)zT0{P&smD3%n|pu@`=^$~D$^KfjOxCl0dOGA8)psDMmxLW zI=qj9rRzTngrLakGTrZV7$rMoxG4^DwXQMgLVCBo z>THLbpt`I<4OK=PNx{aE0fYv?T*mhW{ZG6M8;!5)w?j9Y;2EMgqX!fW!tqkkwPwxc z{w6t{d>(kxK%k_Nr@+{vcKn+!WC%`9op#$G=gZ3ESoaD^b05v`F(C%IYj8PE(PXlm zg!6+aEt4B!>U6t1n^ad;#v1WM2V|7dsbqz&Fv^f@!-g^}=cd#ZnZBdr=051BZgMM&TU7kPWJO-#_MRWVKTR zYfd}zWSFi(j(`v3vYb8Xt8qOVQgQ>f%`?$(l6#c^OJ`U`gfo=z`af#w(6BNQYbDm{>bO ziHRK%kY%Ac34N!#GQt&Quq=`Fs-eh=3eUQ+eF-a?Bj+MQ$h3{6V6r{3Wz*8&kLE`c zZ;pQ2-)gSI%4y8LDpvG+FImjX*v2}QUq|=@00{Iv$qWqn#r|sv&c-!FYnA7pwFP_Dv;Sz+nm_B>^2ZU1B*tpoNN*mzDPNl0y`O)D^3I@VNF*OJJl#_D9tq zAJ2h+1|*u+2EQU$Fl{I^tihFH6OY>{e0S851Ja6v+^awfKPgZ}ls43e7=>d_eMB_Y zPN{@mE&ZHt0<@8ao+D>M!-Wzoqs5)0*{C*aeWtSI1`_&%F=V48u*9lKG>%J;Z;7jN z6z`N~Py+>V$9!rW_K#p4RGXF5uHE_APU=J48}Nf`Q$oDG{$QYhQe@CJ8tA`;Wf zYN@_jC)OR?8nW@EW;{w+06GCe-w0-w#o1)U&h_EoxFg4u>usB;aQ=~nlmVfeelUry;} z&4+qq{H&13q$`M~o;uTdZSfls?Na>E(qWW7`k6~jW@H%rjP#Px%86AqYT-GC11=r6 zRpcTmH5MUbdx(Z>T>2M8Q-?jq3P%=oVY36Bn%w?d>eWmN3pWCQ2`gTFR%GaOV^-X3 zTw!|6=6c?_Mgg?_XQ}imy=F~K*+=IUwNw5fz1O ztud?*u^GpJ#?0&dnYm`VK2y`^8#N`g?rb8|$CmX7aZ&NV;%dVocxSgqW$YQ=QsA(p zSfZI(cQc&*U>>D)%L510;ibNwj9?ohosa{LWnx)$Lo_Z+(FV{;lq9u^8Oy136%TVUGg^xa^#S`xjwr00t$+|P))@*UQ*(Oz)N$sr zg)gxc{>5c0iv(@dx2Rs6u7#!wJv($@ES&5I zjcR@9y)$S0dEGUrZJ>lol+6{-L+b=Ql^w;_SpSia3I$}Ygo*p+bLg@M9>er4!k=o{ z9uiE)jcJc#DKa+hfi`tc?sNf;ZOxqX#-`YjBrvcp8wR(%P^3IfQ$8=5i`p(;=^pC> z`jnm0Gs*rXz~Z>dh35v@K~ZK`pt+PdsBs#RY}jdzEfSW-QSw2vkAXx^Dgh;Oxv;aM zue-s#>hHRNd%g(oRpGdGlDDbtMs38IC((CD8|-Vl6H!xNJ$=lA@z4q1u|KU&_eha3 zgRP3z%eFjiM95uMPdDdpKVc=9e1`y!LVq_hgy$8ON#SQI!4u^Z(x6;P50-uo=i3qB zptU+34>57HuA?{TgCahgX&acC&f}<-(Z2d7*!v7UM9pRuaxIt+jEYJD@9lO*;P83M zTYv>bE_w2XG;Yqnoqg>RO-aL)k%SA9Zn$f5wPYB zN;CW|sYB>rViFDk)YUQp`qRZNhUc>S@*WtXysJ}H!9Yt-N~&YRqe@rD*5G4|Vo|i! zEtSel)%wMNtGMc2UOEDMJ+~1h+*G+pqP?BG^c`fm#mcYIq6Qzbh91@shCrr7cU=7cS@KU=2g!mC0T6O|EcTxlf z3UuQA^D(7`k*IPU#V&bCV~{AT-lcNk_Kyp5us|wZ_$V3f8XY*5W51*Y&=vvq-$7(B zq{R7fe8L%sR7ySP#CTl$l$t*)H(LdlrnN0MT&KiKWCNVdt?cBI*!%DS>9P0lD0X|U z>VimrEKRmu;Mjjjcm^LHXdRr0{j^0?xfWVy8Z%$HeCbCMq4ymH0Dz9)rvzYh_o|eP z7?B7RqB;eBp@H^xFWrC%Trh{Q$m-9Yu+pVH3S_In7sM$Q0Kro*1ql=s zf$P0tQL@3JS%>O0k7_a&4ICrc-|)adc6Dr26(zuCfiT#d?>O< zi)dtXK}Cd2*M+7vz9NbX`$>&&LnB2^zPDqqfgv~k+^1(P2XP;PV$D>Ut6JV3xmvK_ zu(}vlR1FN6EmeG%rw^&%Qw#>GqukA7HB{=B6XQjrXQ-ih`w$atcWBaE&`J1~1d2aBw~6Bzf{ zTpjlc?4MBdEMsHk=j*+1iE_-|M!{fd7;AaMaIONCZ{b)q8mJYo!Luxx_R6^@DS!|> zSQ@6he|q!l^4bX}30_!)7^b;OhI*L~kWvH_pddwkHOsdU`a7b;jK%w#3qAbw@BkP1 znP0lqN-kW6cbsEEgF0ZfF`Uj&izh~CGe-Z-G-9V1omn3;Yp_D{nA#zG9Dy|_P4||w z9qvT{nsH%c7}ke_{P$3L#jyS8YJfr4<4DvA%lCh$)+mhBf)r$Y_dyS%HNjHm`3$0c zP*4{VmT&|4X#kgb`N;{L{r9Y?prp0ItlFw5(h=4v9vC#%CYV(c9$sFyE|Qs|Mo+~4 zitz@=IzO$oxJLrsDF}f`yjzE@S0nCv`0$d5DY zh_M%;k}4*S6?JY1xiv~=@wJs8BCFIhi)6AFMYEUX5$(7|8nu ziU+gBV20~!7hCOnyOz%#3H#PoI@w~*BDA6jW$=1-h0pc#cQzD|L*?QUzMkB#DqR!! zyEav)#WbXl2cV(VEfRv`XKZ$5=W4j3HP3LCm=2dxtc^|F*98gSR#!zKu(A~Ar&upG z!KTZci=_^Pn8u(>klXp|IO`D-Z8wmB)Dx2v)d%79S{gQ>uTZmxN-0F#BR~d=!6N-@ zxHzzw43q$KRq4W<|h*lvZ508221FfW8&!u6Y%D#F*K9af(+0l*ZA|fM%&yRe)y5 z&2A>wbgszcBFB1iugdOh9TXdJVF86o1?bH9uIQYY?ZNhG^Ue_^4#egbOOhS0lJo~e zE5eyv6cJ-L7D}RY4x_f~6!dd}thIecwr$kGpKSY7`4-d1XIA0I+PK5?$b31TbqpfZ zcQ>Xn`HUur*I}Xi_bDFG-igg*SCfsitI%|RfFV3VDVV3Q?R+TP(T5nboiNSAI4_Ngl;Ct#V-2I@5Yh!uO$)r~=;g)rA3 z1CKl&MoQIgF$cp+v4svYBbN*~ouLap7C%nh+K|+>1i!#Vr58hY1y!!iZH#wwiDWQg zh^_see&6vX_cpf@{fBz1nCFi+o{kvIznVVIDkh*7Sk#PzfHZ`K7T1b$Qp;0=CP{Wq z2$wwqcDUlaV8RjGI0PvvNHN4i1Ay=lfJ5Gv$)q8`cnDHfyOQo%srLnI zmPLz1L)IK|sf;fm{l$_imhJ)PM%cXJSHutL<$Nh&e3l)k1Tp4uCRg5OOKOs)el9@k zI|1Qkdf3{OR3>LlO?u`1sYSa7MuBw4^Qr$y;hq9Z^67k_-V<3HI4-S7d7Pud!BZgI zPVFdPU741^9H@|nTW4~?kEnC2caybg2|_K2j6OQtyHJCWEq!HZ{~>@=T;+IygM}Tt z5!zs$5RTwYJ@8VEAPf_+wF!Z>t_&+LfeC?A;Tr6x@^qAMt?4oR&jK;)Jt-BsXS&Z5 z^(S?fc^guf8X;tJ&F>$sfePQX2IC_%KK$(jf1XlKb%xqV^%YcNU+KmBaGuTb6Og_Y zXW&!QLbdw2a*y9S4D!u)uCfB=lV;rhaFII?@161!KAwOe7H+C`iI&VRan8<8P({dE zwS5LhIe{#Q(X=50NTW2fJ8eEMu{ln}DS{S&Smj(F50{@7dzs<2P}pme`FIJ-814r` zF*L+|fxbDYFPsgS6mp62ClDiWsAN`ciK8TE$`dx#`?kM`u)yS>i@^D4$z1G}YQEqAF+_+{^E9o@h7R>BoQI zY;CggEBr4hl|sB*pJ6x!BlKViW%| ziJn&OnfrMbk&N1_U#d`QzE7I1{xIvj;DdwHMrsBdgP&}&fmqN^;F|B=N&J5HE(fqe zNH7tNG>-;VV&N5}B{>G-A zN60v!HklevlIsVKouT|(;@WPeEV&3i+HPgAcXc3D?G82w!z8!%;YF1Y7n<45u!~mB5xh5A58;eQvyd+|wvj(GxZpMj^l)+F<3p;%?Deo{=?=jb z_#8B}xiaB+y}s>c6uUl~zfFgC|6g!g{SMbwt_`X6BZHimmmq_AxNb{o=R&p23!bk# zbAG`;;T)I-S$xH9lR`LgY-ierm>TsZ;txN&_K&WaGyC3ub>NIO+fM!-Z>pzXRh#fA zOWQ^jvZ-5kfRkzWXmU_IRoPb)Ur5z3XLok;3c9qD=-M+A(MOfnYhXH}{q7IJsdBu~ zx|+6{)yXeJtmQJQ_FKYTmXQ?@-rs2c@9UqYHeL)AY}1UjCYd6*1EK!XpKQY^$|)9W zxihIK)v2V@_jiHJW%?`XD@*rgp;}oCSU}pz#l@yS*Ntxsb^6`-=JJ|<8$9AIfl^Mk>j8)@598P4{Tzup)Zb`IzJe%yM zZo(d_uIM0Cx_=s9XEFSRi(i6lEr5>4g@ISO1;LQ_8-0_^|LR47SByq3YT^E-OMLvJ z^Yeq-z$;P6@^-#_>2!r8o4CEpciN#8`8HwP>22%j%Z>a|mYaUr-Hwg zhc#;Pnm&H0TV_o;W0QuqEXeR5(ru!|bU#=gUM9N;8i9~uVI37bY>$2CQ*$aQB}2N- zqb^_`0`A--RN|;&P=mZj&4QdPeNJwc`8@^DZa?UKX%Na&ccRuMBD*jIIV9^2GRx@k zm*$gyZyt?l0IU58O^J$xd zI8!&ls`>FqD=cr8_cHWoRK|>II~OGINuJHkh{(N`{;zs{nA+KC=s#O7l6E?D)Vzv- zgfiM)kp9LD3i4D7VC{v60cA0stZqc%^ERKgC#Y}yi-Rf1sn8j3r~a0rQ!zl7%y%Pb zJsyN57N;;JcjSm5yJVt~jDlYHk*r5xU-@g$2&765RsyYRi^+G6xi38Q8$)@k~ z+wtDnT{{79M6-{ufG%Gu@A4j%z}8*pYl*gGp%PbCb*ZXb!^{v#@QbReJT&x@=u~g< zqW%8&06Lo!qMpC+e)g>X!A37VrJu%e-T;8sySf$43-=Tzp`YZ5Df5WJ@_V_1tzQ8; z)qB{xy!h6c05la+`61p*AngW$NZVm!U36S;;Hx)ZC0i50%B6o1$JF#qaG>mTYZ0&L z9qSxqs4GLBK%_cPoDc0HS8^jO$`<{Uk`s_-U#f~b7cX1!Px?Jw#CG@^Pq=F&vNVyd zJ*5URH$!ovME3g_tFT)0LuC$vC!Oa2@lts69byb*&3q*>>P+|T608WC&H$r(?;YfBE6k{Qki47 zj}LTDptZJq>c%GU(BRw}KhPyptx)Hc-;h1p@5hUfFyCd1#Q4k1LcfJjgAvX)Hyz^E zDa}nRB*@F#g)!6B_=4Df-t|pbxxbi0$s>0aZ!Fbx;qEZK9oN`hgirDZ8E2@-Hx>t8 z73zQ`nBP9CQp=+oC_|T#=?R)7%f4Q zUNhDh^h2;Cqcmxxvj%JKdAOy@>GlwikO|02Ol6Omsh+9H8@*^*f26n`;^akRF%-t-$ZLxYPMyh_s# zOaj;p!r~*h+j9IaM9OG0T?835fYx=xaFrG^#vML3^HfO; z!E^rlEPf-y+1W~JXPS_}qffZkW7q5wW#$H0H_G4fi{HfntB#7OLVD!BGIBCoQgm9M zT=8Q9E|p-Jp?vb+Fk(Uua|87FXCP9gShkYxM!jh&d`iJMHMi%k+5WEXb3Pakm-o@s zV{W8MvLS?V(jox$o*D|_y_6RdjN;TWe=ps9Rm2|XaxUkWBcE@ocM%1u0#ITUKPY-a zXq-HZYi@Mf-9&;l`55x@3w}4f=Q+soBR^$t!cXqSBR%32hINzQQ+GUnBv{zuyS&=pV99C>h1;oSz-wX>S=FEVe6o{(ysyZV7CgG{? zyJzr~3gYU*D5b)Xsh|;IU?P#w4!LxtaRKryw^sZhCoM8WEVxEZ*5l^qYHqh4B_TJ9 zWas=Iy79I@lc2EZQpM5IEy_Y8z=g=>W{hOmtukk=tGKS5i5Sz`IS!MWxMXnOQr%T? zOWTdaaAG5MeIjGjKo~)&IiFx@qd7C#5T$w->3)?oK*=R{2j5_hs%uzqn+)!D{*mIy z%>t7`?{evJa0-*}^<6PK|{S2YRUKK)5J-QV9S_x%EEjF1; zo|SOfSIgn2%|pX_j+0QTAP4}kOW`1*hSjAP7Cb9*MN(s;ViRq$HSgzh4TU;~EwsV3 zY&qh|D+!_zjOtv@N>_e9_gfCgi4DGFB#`GR+TM3vRxrOLeP<+A zijLAclLIGTKnDUT&U{Sq!X*?|rW^|f&f3MN7cjIPn)(&Pz{(>ex!#pXiaI@Zel$h2 zPcfT-vXsgwHSPVBg04Di_YvWIl{)7$$&PonC7^H-WZ8_s7E8?JM?#4!V)R3AuzJ7xWAyqoG#a%sd9_Ltp4% zfT?iXc9!JWuM*|~?d(u--j(C+7aX(09$5()_^$(nlqYvM0lS8Ox9%V3)ylOXkc91) zrfCf%J5Vvj5Uo{zqLwvk>!jvM68B;M*&~H7tU-8puS$=6da-x03}R`3#0}*ltS5>K zesI6EGgcA1D=DX}lGcd4^$y{%`JyJuu4^${{6gsFdAmWN1qIr2SkRugI4{+dfioZk z+qVDKJn&aq8m{z{$c2=o8-d0jN%@<1=2#S|$`h26<46v-J&ug0xhFu8+l68f>#T zfY6rz!1Zd{lHzfxrg{__z;ng~!CBUhMIKx5s&Eo}KfJctmdaB-9guT!$_R6{utcGO z@#KJc3N-yb;-2xd@Ic8fvv9=!Z`DZeIu0sRRG+pqg8=g%dU^q~9K|rKd_R+FjFjb!?_-f1-?y-~^IS%{xrAT)*lZcRYCdf{E zKeNqn(A{k~`x)EGjSzc+069%5Um#;562@lZs<4~_%A)K9*=yTIBTk*Vt~5Tdx_Ftv zHkr;tW7+T^T0A%0c;BVJhbM)>iaRk9TCrdh&pM}>@GbcavP!REs%B}hBx76q56w;& z_??%NY7z60EPglfqV(!**0#kJY5{#dDZRbA=7}6C!U~ruiksD1bhhw?Nod+7xea#f zNsweR|99v{@5+96fov0W>OPkZRwYfwTe!81^9rlhXJY`scNqZS;r~8Y4buro0r$V1 zaA5~hUldI5lZrb*B?<^vLl(>|t%SfBhul{!O9-Z=>mG*(=aI8BAmc2~(Z#hNL^p~x z8$ccYR?>gYUDivb8GZep1XRiPDyWzpGf*jYi^)iuQ9{k4=}JUBDOcrJ2_qwyV)v-Q zFrYzMEPzhTbPfR4Li6H#e@`I$HpEIA^NQ6kLJ}ke<R zA*%oy-2j4~SVfp~m5K6(H!3R@{K1~_dh zp3#s;LD$BRARVx%H@n^Aa(Shcb$LRLTr8eOw_mYuf+ZeRliH-QtI1}Ts>~+)Rqpbzo`jl%Re@M97kd0cGQe7kcJcR zld&@BmBmZS(_E~st3J|1gr?vvrL`X;xIWrDyevOJr&#klkOuHj3|=R<5GJ;(-AJUP zt^%C*s{4W8U7y*UT(>`B!gf@f=z~X$wVt>KOW`S^2)20ccc zjy4cYXnggGj9pSB7#>wh9=)5nk-T%lCKuI>1fDAJriJS!bGZOtMrktj7J@C8Oe_?cLQF^O0b;ntfzTn_WvIJ$`-N{+b@xeK6BG=5vf zfhzCj3g>~Fy1~*27QS^Gw6zEAh%c=v-DmhCq3I(bOJ`#49-F`U_V!|Fq)Wdfyg;2T zb*i*5BE1d)K|TF@e<^pHbtudK0H8o$zf=^1H-=MAtg7bVK_aNT_+|mcf$rezmfobk zYUY!snKH{%ZGINMNH&eysdEz#!_nJUg@#4F*LJwt)AodvIt*4rtZo-Pv}Nj()6>1S z0a#_v8i3XQ)WaK}>j`koAQb&^&O(SGhSmsr%G6G@vRXbHj znpj#r>Y+BoNV{}jM90P<0L8o^we`VqPaO{lg#(aE6^s#)z+BxmI;B&&8ai{1|Im93q;t?oP(`3SBTVjOkmg9=8 z9yv1{wROv~2nGjKW^&5sX~426xXQzB<{{gZf3^~=LKmR4#W zTOARRGw}*ai(udi2F9G)?qo0}pW5-pGNp1cg^@Ml< zu2yoL?=?H#zS1d111RCF3Y@V zQS8ww9&P)cWwI%&S{n;`g`lV?W=eICT!AK^EVx>c=r@>0$1+r-;nTn&4IWKwgf*jP z(TFexB)`VVX&$+w%${oIMnnh%nvZYX-|uh`kikbzPf=2m>RikEkvEU`pN6LHCIZh*( zZ6Dss#mvLs@ab~pOFBvxrC=e6|2$uxppzcy#V!wC0?Pph{9j z%b_+TojfkW?IUAOV#bDx54nkjc@r0r2jDq+C7vgf0C$iP(lny!t+-FTx!xW3uHNzV z<`XlTf4-N!Yybe9n%-Z0wRq>%H?5P;8548o58-i2ATY}Jq>hR36pN20nitcd0fdYZeEER8JB(pQ5O z>ms0&rmSt(4khu?Y2X`aXYhRo+>0S6gLR;SQ;gcOx+(@)$6e601#a^10hQt??l5is zV!AqFpGi_&L&zA`SjHv>V;tWmIKiif@vP@+hdM;Zqf;*Ciwrj1%8_fud~qGiJb?%}R2^!&5wz zBO6Dpk!vGRHztmk3RoR$5}PUr)3q@*07^?zH$6lpqocHmfqcfoLURbnd%|9LZhbHs zb1Sfo{%o0f`mC9CwjlehKtlavG{T3h2wa3p8?~DB3@#**t2{h4$eYZ67>O?CQaJJM zb(@%r_9$@xa-qc1M0Sz_hWhUgJGu4jH<$P324IyvZUEN$m5uTk>Z=MNZBc|VCTF9E zBt>lrt0Hk;culYIX(KPGYG!)jJ~b1A7BH)l~K@7+p0-1o)HYJd9S z)vs{vLGCufJ_S?+4Kh^@h@204A*6P+ObVbkC3s$4gKam^_Ek=5qFzqoPMaYvXWO1? zrlctZrzdc-#*ITTkRYnL%2cl1mePnM(E<&%cw?ApkYKu8xw@<<38ohTOXCz=Ufsk5 zsz%zeMxV((_8OOFHbG1b*Fui=GSn5+HZiq1fKS7keh+!E^99Ryp8d+%*>3}O6z^kz z!bC>aT5~#d^v=KrGfYBr-Ixvfj`|wdi8KT48dOEVH~&?##0l)p1ZZwm>*GzW>Yg&` zoX0kwTrX?0+J63*J#GL1eD?JJ59kMxv|8wvYLYdx(+KXO%}Qjh7kGm}^#+=~bU7Q! z53Wdv9Rn2w10>VL#NEZ#9Pqr*gu1Ax&XbqqVe#HKh(V2r0L=%&0!s$15^Y@gP-@ z=wZgn)ze&;#=$anwWK@*Qh#rA zArV28XfH7mHJBY4qH!xS3Yj{jb*KqF?Tn4C;zVi@6#QmaCQU%3tJgaO|81aV8F1*AONZ~<@_cxU<|+XhHrz&h2- zPH*k;{GVF(z5&=QYhOG2?^4SbkF9^EO4w$X$M&e0D}x2hoVn1{Np9f)g>t5hkjqz@ zsaP&S(%Od0@OJvBiN;FNG*+tS(<~hvUpBk#X8pM9>&Aje#CCen!MQ=ZVsQzYIGs}x zjSHKF+JI2<|4N-a!o^N}5+jTCX%Vaw-3xS!ZmjEB@_I`ZX&?gW(vX{{S4I13QO6iq z0pkwEp%;wQks=-v+K{)kwp+sUW5nY5_9j&CI=M(PR3`>C>i;_3(-`59lTrK54M3N8 zCh6SF2DOXX6?d=s|D-`BEwcJ8DpJfll!EE(?m9HSpu-%LhE#`?V_$;6DB_juN89~8 zO@nh~nADtFdvBI3T6nJ$R$hRq17*3%>_Ev=T4*YV;FJ!l<%W+R|HIh_VC;>u_YHu< zAKkdK^Hb9RZ4kK?C_}Sch`=?hq|Lak(;Z2MOy2fTFlie+-B@P(*P`QW=$snoB1oDd zSQj(6O2vGZ1=R`jGxgDQ2Xclplc!du&nQ+<>7?dKG7nSLD;jb5)b@fkTV9+;t)~AjilHpAHlh~fT0V8kr81jz9~8YEoKqNfkrwE zaBWKmgY&3rRV^}R2+9bFMe<$u+~nyKTTjpKtR8@k5X>2n&5pb|s)@CM^ky0#E6_Sx z!x(b$oDnn-RC_|)Lr7knoGzD?tgE)yXca4jZk~wT+y87_?eY<1~=XKfp z1^~eEtw$f&_y`EQk=7BQXpK)A|E>Ndr=$d-ps^%lb^0|PK>cPok@W&2x1sSF2#x?5 ztC0@1L=I_>2%D}?yf34pb4O=y1$c7v;rrIU&^$CMrsl9@I5G`lilhNy0n-WRNMvjX zuMA=?Drxgvx%!NmA3}W|52;}05WBr?uWV0EB#fTV$V6j}Ya4g9o&$2LkKsmc3k=#~ zo&vpb!0L<ot*A4;#Nezl1hw=-5$8j6hMBRs~y zx6RDjb$73P?WxU2XY^HP-38+d`;hw$s+ibR5Q0d~QY@OYFcmy~7zD?j-|+0XXhM1g z9ngi0=3J$WLBweC4%E@oNPsS}df@A4KC_2U0By@F!T?Ns>*=j;k4KxObO;?p`~UzW zg;M9GV8miq9*W)x6-$vGs8IzVa2S)c;i!90Kmc|gnCn3!(U34vFq)9~NU=rW6pv3@YT1A=F+Fh!Wv^&?jPrDKTzAF#FWzUTvhX&Ri&BWl2A*ibK z5L(ip-ia^`FphLt!LGxiOq$?bHuw2J?jZ_yU+? zQnt#>7{HOy1@FD!C+d`GC#w*b`MyMJQyLluK0wfRIA7swnw?x&(Fk-A6ba3yrUr8@ zQ3OM90(e|%O%`~xJ7NOJq$77LZlz2gS$|;STf3Pp=X-fY7ytl|Y}|Qr>mJgPAb60| z7_8mtud)oo#gc6+w;(1apOxENk&db8MlKRFjS2W@urmbrWJ44RR8td03~#`X&b@xI zJ36D)1{>RGWPNdNZiH$P)ZQJIPd7#L=-UL|@ds))6?tl}ID}FlG}XTFtg|8ZQV`&* zq3t4xY57clNQ>pp{61H$3Mr+lMS-MFmmr3GcMd>w9I1iP-p1|C#dFivh&n(C_%Ui8 zHK9Y}1RH7?p4uL=wP9xHs8ZeVNbu)Wq9{k8W7tFUl-)=-1iZY7K_iT2t%jC?btof@ zX1kb6qr(@?zq+x{Y$K(Z=!>w;$@giSjdaQ**sUtEi#@uVmVmrp;cK=%?2d7tiouFb zl#7L(ar**EU>e@~1U$L%@Pli2?|QDB-{qBJ08UJvdS>fuBP)G<;X@tjIxjOfC1yhW z(me7#1Y@kV&Bp*;0gHF~A>bimtU*vBJQ27Vs~%Yshnp7%%*=eN z%$1p^bUFOFt^1~BJ&=a09DK7N0D1!oVR%TTPAsd(Fo?`jszy{bXg!dtl*+6TRHCB{ zUIsfeP3^6Vw}M>lG7qhTmJeMO*$YPpM4iTgYd!heX<^&q9=j;fD4IjBTaBW%IzElp z3U;A^L)yHG{!(GWDj2hIOlVeRMX6(OYu<&TG)IG{lS8Z7MWgG?3we^KcUJpXzYg;_ zo54z0rb^GdT8mQo3R%l~S$SgP-q|{M@6+DtO<2y`VvGiJqi;1VViplqlDP|Qkc@;L zwJbt#0(aD{;NcpE;ixM@5f+&=i`Tb>NEnM9v^8#C52^#0iEHM#Z}rw!LjF%JuM`8| z@P{_OI`QXp=2}1@IjwkUC2{l!l9=U6XxMzp1tB6@!VGB(96$#yGr8VzSsaU8MH7WG z5mVnN4uHgyXyT4(>5h&soZaw;)^C4q`hd&-4R62ROM8M?+lH7WIUA5sl2r31!mTW& zRFtaM!|k0k2C`(NhG7g03@|9XOm{xkrw7bC3|;g&+Fb3Nk#MJ)H8t$;qqsKFg2q} zR=BKaYXh>KBrALJ!C-~|SL^m5=Cb6ep5=&Q)3uLjV zQ1{-Wzc{?>uh$`~7EoG?z%A?n4i%{jjLHB)1i2bndeCICJWd1dnD zY+PVR#mNTEGUUMe>kk|*iU&DT*~#Fj?yl4q3WlVd#}(8rNt42vqB+AJaZRqUO{$M; z{!p#~EJH+Wo|E|s1G7~@@cHfJ8S!lqk+|5@e3|FAQy5}rl4*?_pfm4%Yo}A7@qvqe zzH9R=^TuXraiuFl)30?I*)aB18vbx>EEkQ&kjB&DgBM6}#GN-Z+9sO6b~Vd5DjNLc z`h!nxJ~q46d#SvF48Ym`)IDpT>M*IIfhFO3p(5VuT8%N^h7+;19>Pb07`&bKOo^jg z5sQ+b5I1FDxqe{uOORKAzceBBR0_B>VmK4S~9Mp}#y2U^kB2J*s zc~u9ug00?n*aUFp;`M^;#?&Rx2~mhLd{wuieYvG0h!1T!Bf#MuWQKmT2GprBIEss? z4RRNvqntN4M&0UPYiGd$D_*{N=1a@7kG|MjfG=K?Aiz>8b}w+ zaUDsVsim24`l5prR=0ALCeB2`1OVd*`RICEV-^hs6Z!G=%8nKHNttyT1c254%#$16 z@-lTnY&B1=#1Ga=3pg2H4P>Y zO-o*oJwVeEnPL&lp~@7nDbJD-6xAz&DJkQ*dGYB(tGBK8XJ_|S!93#<9F2ig3i?CN z>^GWHaey$~1EPgGGc4+zv(hEWAv-8T-<}gV=e429l>+GN=o-rrd}96ndsc6q-Q+!1 zUReg<x3BSNe86h}DsGQ5HS^NP8Ap|Hc8+X#(B(RFQI*du<1~7a|f@YE~ zWf&ku$#O|mHYD7E!7*nCu3o%ucB>!UxO1(XLPZGIt0}3TfU$>=Q5%?RXk+~&v$=`m zq~;M{tG6wb8caqnTrOi$AnzOj1NL9zV6m%O1tciG+#^^L-H6fhoADMZk8agXc54hG zX|kFUqPY{Hqb)`;I)ac?b*O$w3C~nWseo*6bhig_urxL_*A>uRJr-lfr-RnONM<=A z8ddfcf^x9?qcYpWR|dyQf9j#NduI31HA~meb&DcNvb_xOT3rfG?i0-_Icou+lGB)5gNPi^^4ttgk-5c+G5Q*) zbt5ZG|CbA$w0a&#-gV^XXE)i=jq6bq6|@)xW;DRLps1fzljTYCLGVlN#{8%FRy}XE z=JZ%+tzQ+SP3AJ1+?Yv-1GC`~tbmk_1W<86qbFtRPB`4S-?cU(Tz<KoQjP#rM zVuUmXA+QjF(pTvK!)SItz3;-GS?mroUIY26@+u3>b;*JDYyn`_0iC8cQ;@XE09Y|p zQx=oaec%(s|7F^!EN4tv`n$5rbXa0qmT=AN?DW(ZPk&

9M!UE6xC%njU|8@`0=?bnH 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

}B5o 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 diff --git a/client/public/assets/web-browser.svg b/client/public/assets/web-browser.svg new file mode 100644 index 0000000000..3f9c85d14b --- /dev/null +++ b/client/public/assets/web-browser.svg @@ -0,0 +1,86 @@ + + + + diff --git a/client/src/components/Auth/Registration.tsx b/client/src/components/Auth/Registration.tsx index 83ef456330..3e3e8512e2 100644 --- a/client/src/components/Auth/Registration.tsx +++ b/client/src/components/Auth/Registration.tsx @@ -305,7 +305,6 @@ function Registration() { )} {startupConfig?.openidLoginEnabled && startupConfig?.socialLoginEnabled && ( <> -
+ +
+

{types[type]}

+
+
+ + ); +} + +export default OptionHover; diff --git a/client/src/components/Endpoints/Anthropic/Settings.jsx b/client/src/components/Endpoints/Anthropic/Settings.jsx new file mode 100644 index 0000000000..2b40dfa412 --- /dev/null +++ b/client/src/components/Endpoints/Anthropic/Settings.jsx @@ -0,0 +1,251 @@ +import React from 'react'; +import { useRecoilValue } from 'recoil'; +import TextareaAutosize from 'react-textarea-autosize'; +import SelectDropDown from '../../ui/SelectDropDown'; +import { Input } from '~/components/ui/Input.tsx'; +import { Label } from '~/components/ui/Label.tsx'; +import { Slider } from '~/components/ui/Slider.tsx'; +import { InputNumber } from '~/components/ui/InputNumber.tsx'; +import OptionHover from './OptionHover'; +import { HoverCard, HoverCardTrigger } from '~/components/ui/HoverCard.tsx'; +import { cn } from '~/utils/'; +const defaultTextProps = + 'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0'; + +const optionText = + 'p-0 shadow-none text-right pr-1 h-8 border-transparent focus:ring-[#10a37f] focus:ring-offset-0 focus:ring-opacity-100 hover:bg-gray-800/10 dark:hover:bg-white/10 focus:bg-gray-800/10 dark:focus:bg-white/10 transition-colors'; + +import store from '~/store'; + +function Settings(props) { + const { + readonly, + model, + modelLabel, + promptPrefix, + temperature, + topP, + topK, + maxOutputTokens, + setOption + } = props; + + const endpointsConfig = useRecoilValue(store.endpointsConfig); + + const setModel = setOption('model'); + const setModelLabel = setOption('modelLabel'); + const setPromptPrefix = setOption('promptPrefix'); + const setTemperature = setOption('temperature'); + const setTopP = setOption('topP'); + const setTopK = setOption('topK'); + const setMaxOutputTokens = setOption('maxOutputTokens'); + + const models = endpointsConfig?.['anthropic']?.['availableModels'] || []; + + return ( +
+
+
+
+ +
+
+ + setModelLabel(e.target.value || null)} + placeholder="Set a custom name for Claude" + className={cn( + defaultTextProps, + 'flex h-10 max-h-10 w-full resize-none px-3 py-2 focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0' + )} + /> +
+
+ + setPromptPrefix(e.target.value || null)} + placeholder="Set custom instructions or context. Ignored if empty." + className={cn( + defaultTextProps, + 'flex max-h-[300px] min-h-[100px] w-full resize-none px-3 py-2 ' + )} + /> +
+
+
+ + +
+ + setTemperature(value)} + max={1} + min={0} + step={0.01} + controls={false} + className={cn( + defaultTextProps, + cn( + optionText, + 'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 group-hover/temp:border-gray-200' + ) + )} + /> +
+ setTemperature(value[0])} + doubleClickHandler={() => setTemperature(1)} + max={1} + min={0} + step={0.01} + className="flex h-4 w-full" + /> +
+ +
+ + +
+ + setTopP(value)} + max={1} + min={0} + step={0.01} + controls={false} + className={cn( + defaultTextProps, + cn( + optionText, + 'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 group-hover/temp:border-gray-200' + ) + )} + /> +
+ setTopP(value[0])} + doubleClickHandler={() => setTopP(1)} + max={1} + min={0} + step={0.01} + className="flex h-4 w-full" + /> +
+ +
+ + + +
+ + setTopK(value)} + max={40} + min={1} + step={0.01} + controls={false} + className={cn( + defaultTextProps, + cn( + optionText, + 'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 group-hover/temp:border-gray-200' + ) + )} + /> +
+ setTopK(value[0])} + doubleClickHandler={() => setTopK(0)} + max={40} + min={1} + step={0.01} + className="flex h-4 w-full" + /> +
+ +
+ + +
+ + setMaxOutputTokens(value)} + max={1024} + min={1} + step={1} + controls={false} + className={cn( + defaultTextProps, + cn( + optionText, + 'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 group-hover/temp:border-gray-200' + ) + )} + /> +
+ setMaxOutputTokens(value[0])} + doubleClickHandler={() => setMaxOutputTokens(0)} + max={1024} + min={1} + step={1} + className="flex h-4 w-full" + /> +
+ +
+
+
+
+ ); +} + +export default Settings; diff --git a/client/src/components/Endpoints/OpenAI/OptionHover.jsx b/client/src/components/Endpoints/OpenAI/OptionHover.jsx index 035d90cc08..76a84e231b 100644 --- a/client/src/components/Endpoints/OpenAI/OptionHover.jsx +++ b/client/src/components/Endpoints/OpenAI/OptionHover.jsx @@ -10,17 +10,12 @@ const types = { }; function OptionHover({ type, side }) { - // const options = {}; - // if (type === 'pres') { - // options.sideOffset = 45; - // } return (

{types[type]}

diff --git a/client/src/components/Endpoints/SaveAsPresetDialog.jsx b/client/src/components/Endpoints/SaveAsPresetDialog.jsx index a371ff080b..794d7c56d1 100644 --- a/client/src/components/Endpoints/SaveAsPresetDialog.jsx +++ b/client/src/components/Endpoints/SaveAsPresetDialog.jsx @@ -43,7 +43,7 @@ const SaveAsPresetDialog = ({ open, onOpenChange, preset }) => { id="chatGptLabel" value={title || ''} onChange={(e) => setTitle(e.target.value || '')} - placeholder="Set a custom name, in case you can find this preset" + placeholder="Set a custom name for this preset" className={cn( defaultTextProps, 'flex h-10 max-h-10 w-full resize-none px-3 py-2 focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0' diff --git a/client/src/components/Endpoints/Settings.jsx b/client/src/components/Endpoints/Settings.jsx index 1e3c4c7bb6..4a9a6d8f0d 100644 --- a/client/src/components/Endpoints/Settings.jsx +++ b/client/src/components/Endpoints/Settings.jsx @@ -2,12 +2,12 @@ import OpenAISettings from './OpenAI/Settings.jsx'; import BingAISettings from './BingAI/Settings.jsx'; import GoogleSettings from './Google/Settings.jsx'; import PluginsSettings from './Plugins/Settings.jsx'; +import AnthropicSettings from './Anthropic/Settings.jsx'; // A preset dialog to show readonly preset values. const Settings = ({ preset, ...props }) => { const renderSettings = () => { const { endpoint } = preset || {}; - console.log('endpoint', endpoint); if (endpoint === 'openAI' || endpoint === 'azureOpenAI') { return ( @@ -47,6 +47,20 @@ const Settings = ({ preset, ...props }) => { {...props} /> ); + } else if (endpoint === 'anthropic') { + return ( + + ); } else if (endpoint === 'gptPlugins') { return ( setAdvancedMode((prev) => !prev); + + const switchToSimpleMode = () => { + setAdvancedMode(false); + }; + + const saveAsPreset = () => { + setSaveAsDialogShow(true); + }; + + const setOption = (param) => (newValue) => { + let update = {}; + update[param] = newValue; + setConversation((prevState) => ({ + ...prevState, + ...update + })); + }; + + const cardStyle = + 'transition-colors shadow-md rounded-md min-w-[75px] font-normal bg-white border-black/10 hover:border-black/10 focus:border-black/10 dark:border-black/10 dark:hover:border-black/10 dark:focus:border-black/10 border dark:bg-gray-700 text-black dark:text-white'; + + return ( + <> +
+ + +
+ + +
+ } + visible={advancedMode} + saveAsPreset={saveAsPreset} + switchToSimpleMode={switchToSimpleMode} + /> + + + ); +} + +export default AnthropicOptions; diff --git a/client/src/components/Input/index.jsx b/client/src/components/Input/index.jsx index d46807cf0a..716141ac38 100644 --- a/client/src/components/Input/index.jsx +++ b/client/src/components/Input/index.jsx @@ -6,6 +6,7 @@ import PluginsOptions from './PluginsOptions'; import ChatGPTOptions from './ChatGPTOptions'; import BingAIOptions from './BingAIOptions'; import GoogleOptions from './GoogleOptions'; +import AnthropicOptions from './AnthropicOptions'; import NewConversationMenu from './NewConversationMenu'; import AdjustToneButton from './AdjustToneButton'; import Footer from './Footer'; @@ -130,6 +131,7 @@ export default function TextChat({ isSearchView = false }) { +
diff --git a/client/src/components/Messages/HoverButtons.jsx b/client/src/components/Messages/HoverButtons.jsx index 16c81412ca..ab2d06a155 100644 --- a/client/src/components/Messages/HoverButtons.jsx +++ b/client/src/components/Messages/HoverButtons.jsx @@ -19,7 +19,7 @@ export default function HoverButtons({ const branchingSupported = // azureOpenAI, openAI, chatGPTBrowser support branching, so edit enabled // 5/21/23: Bing is allowing editing and Message regenerating - !!['azureOpenAI', 'openAI', 'chatGPTBrowser', 'google', 'bingAI', 'gptPlugins'].find( + !!['azureOpenAI', 'openAI', 'chatGPTBrowser', 'google', 'bingAI', 'gptPlugins', 'anthropic'].find( (e) => e === endpoint ); // Sydney in bingAI supports branching, so edit enabled diff --git a/client/src/components/Messages/MessageHeader.jsx b/client/src/components/Messages/MessageHeader.jsx index e06b3b1924..11b1db59f9 100644 --- a/client/src/components/Messages/MessageHeader.jsx +++ b/client/src/components/Messages/MessageHeader.jsx @@ -47,6 +47,8 @@ const MessageHeader = ({ isSearchView = false }) => { if (model) _title += `: ${model}`; } else if (endpoint === 'gptPlugins') { return plugins; + } else if (endpoint === 'anthropic') { + _title = 'Claude'; } else if (endpoint === null) { null; } else { diff --git a/client/src/components/svg/AnthropicIcon.jsx b/client/src/components/svg/AnthropicIcon.jsx new file mode 100644 index 0000000000..2bd75324d6 --- /dev/null +++ b/client/src/components/svg/AnthropicIcon.jsx @@ -0,0 +1,37 @@ +export default function AnthropicIcon({ size = 25 }) { + return ( + + + + + + + + + ); +} diff --git a/client/src/components/svg/index.ts b/client/src/components/svg/index.ts index 1d6c9ca174..e65812132d 100644 --- a/client/src/components/svg/index.ts +++ b/client/src/components/svg/index.ts @@ -8,4 +8,5 @@ export { default as StopGeneratingIcon } from './StopGeneratingIcon'; export { default as GoogleIcon } from './GoogleIcon'; export { default as OpenIDIcon } from './OpenIDIcon'; export { default as GithubIcon } from './GithubIcon'; -export { default as DiscordIcon } from './DiscordIcon'; \ No newline at end of file +export { default as DiscordIcon } from './DiscordIcon'; +export { default as AnthropicIcon } from './AnthropicIcon'; diff --git a/client/src/store/endpoints.js b/client/src/store/endpoints.js index e08dfe1bd4..0ec70afbbc 100644 --- a/client/src/store/endpoints.js +++ b/client/src/store/endpoints.js @@ -8,7 +8,8 @@ const endpointsConfig = atom({ bingAI: null, chatGPTBrowser: null, gptPlugins: null, - google: null + google: null, + anthropic: null } }); @@ -26,7 +27,7 @@ const endpointsFilter = selector({ const availableEndpoints = selector({ key: 'availableEndpoints', get: ({ get }) => { - const endpoints = ['azureOpenAI', 'openAI', 'chatGPTBrowser', 'gptPlugins', 'bingAI', 'google']; + const endpoints = ['azureOpenAI', 'openAI', 'chatGPTBrowser', 'gptPlugins', 'bingAI', 'google', 'anthropic']; const f = get(endpointsFilter); return endpoints.filter((endpoint) => f[endpoint]); } diff --git a/client/src/utils/cleanupPreset.js b/client/src/utils/cleanupPreset.js index ff01b5b8b2..7c03a154b5 100644 --- a/client/src/utils/cleanupPreset.js +++ b/client/src/utils/cleanupPreset.js @@ -29,6 +29,19 @@ const cleanupPreset = ({ preset: _preset, endpointsConfig = {} }) => { topK: _preset?.topK ?? 40, title: _preset?.title ?? 'New Preset' }; + } else if (endpoint === 'anthropic') { + preset = { + endpoint, + presetId: _preset?.presetId ?? null, + model: _preset?.model ?? endpointsConfig[endpoint]?.availableModels?.[0] ?? 'claude-1', + modelLabel: _preset?.modelLabel ?? null, + promptPrefix: _preset?.promptPrefix ?? null, + temperature: _preset?.temperature ?? 0.7, + maxOutputTokens: _preset?.maxOutputTokens ?? 1024, + topP: _preset?.topP ?? 0.7, + topK: _preset?.topK ?? 40, + title: _preset?.title ?? 'New Preset' + }; } else if (endpoint === 'bingAI') { preset = { endpoint, diff --git a/client/src/utils/getDefaultConversation.js b/client/src/utils/getDefaultConversation.js index 34badbf42a..ba1f06222b 100644 --- a/client/src/utils/getDefaultConversation.js +++ b/client/src/utils/getDefaultConversation.js @@ -57,6 +57,22 @@ const buildDefaultConversation = ({ clientId: null, invocationId: 1 }; + } else if (endpoint === 'anthropic') { + conversation = { + ...conversation, + endpoint, + model: + lastConversationSetup?.model ?? + lastSelectedModel[endpoint] ?? + endpointsConfig[endpoint]?.availableModels?.[0] ?? + 'claude-1', + modelLabel: lastConversationSetup?.modelLabel ?? null, + promptPrefix: lastConversationSetup?.promptPrefix ?? null, + temperature: lastConversationSetup?.temperature ?? 0.7, + maxOutputTokens: lastConversationSetup?.maxOutputTokens ?? 1024, + topP: lastConversationSetup?.topP ?? 0.7, + topK: lastConversationSetup?.topK ?? 40 + }; } else if (endpoint === 'chatGPTBrowser') { conversation = { ...conversation, @@ -165,7 +181,8 @@ const getDefaultConversation = ({ conversation, endpointsConfig, preset }) => { 'bingAI', 'chatGPTBrowser', 'gptPlugins', - 'google' + 'google', + 'anthropic' ].find((e) => endpointsConfig?.[e]); if (endpoint) { conversation = buildDefaultConversation({ conversation, endpoint, endpointsConfig }); diff --git a/client/src/utils/getIcon.jsx b/client/src/utils/getIcon.jsx index d0a435f44f..f3d6d0a745 100644 --- a/client/src/utils/getIcon.jsx +++ b/client/src/utils/getIcon.jsx @@ -1,5 +1,6 @@ -import { Plugin, GPTIcon, BingIcon } from '~/components/svg'; +import { Plugin, GPTIcon, BingIcon, AnthropicIcon } from '~/components/svg'; import { useAuthContext } from '~/hooks/AuthContext'; +import { cn } from '~/utils' const getIcon = (props) => { const { size = 30, isCreatedByUser, button, model, message = true } = props; @@ -20,7 +21,9 @@ const getIcon = (props) => { className="rounded-sm" src={ user?.avatar || - `https://api.dicebear.com/6.x/initials/svg?seed=${user?.name || 'User'}&fontFamily=Verdana&fontSize=36` + `https://api.dicebear.com/6.x/initials/svg?seed=${ + user?.name || 'User' + }&fontFamily=Verdana&fontSize=36` } alt="avatar" /> @@ -53,6 +56,11 @@ const getIcon = (props) => { const { modelLabel } = props; icon = Palm Icon; name = modelLabel || 'PaLM2'; + } else if (endpoint === 'anthropic') { + const { modelLabel } = props; + icon = ; + bg = '#d09a74'; + name = modelLabel || 'Claude'; } else if (endpoint === 'bingAI') { const { jailbreak } = props; icon = ; @@ -83,9 +91,10 @@ const getIcon = (props) => { width: size, height: size }} - className={ - 'relative flex items-center justify-center rounded-sm text-white ' + props?.className - } + className={cn( + 'relative flex items-center justify-center rounded-sm text-white ', + props?.className ?? '', + )} > {icon} {error && ( diff --git a/client/src/utils/handleSubmit.js b/client/src/utils/handleSubmit.js index 342d79039e..4860ba4089 100644 --- a/client/src/utils/handleSubmit.js +++ b/client/src/utils/handleSubmit.js @@ -76,6 +76,22 @@ const useMessageHandler = () => { token: endpointsConfig[endpoint]?.userProvide ? getToken() : null }; responseSender = endpointOption.jailbreak ? 'Sydney' : 'BingAI'; + } else if (endpoint === 'anthropic') { + endpointOption = { + endpoint, + model: + currentConversation?.model ?? + endpointsConfig[endpoint]?.availableModels?.[0] ?? + 'claude-1', + modelLabel: currentConversation?.modelLabel ?? null, + promptPrefix: currentConversation?.promptPrefix ?? null, + temperature: currentConversation?.temperature ?? 0.7, + maxOutputTokens: currentConversation?.maxOutputTokens ?? 1024, + topP: currentConversation?.topP ?? 0.7, + topK: currentConversation?.topK ?? 40, + token: endpointsConfig[endpoint]?.userProvide ? getToken() : null + }; + responseSender = 'Anthropic'; } else if (endpoint === 'chatGPTBrowser') { endpointOption = { endpoint, diff --git a/client/src/utils/index.jsx b/client/src/utils/index.jsx index 6233e2a4bc..85286033bd 100644 --- a/client/src/utils/index.jsx +++ b/client/src/utils/index.jsx @@ -41,6 +41,7 @@ export const alternateName = { bingAI: 'Bing', chatGPTBrowser: 'ChatGPT', gptPlugins: 'Plugins', - google: 'PaLM' + google: 'PaLM', + anthropic: 'Anthropic', }; diff --git a/package-lock.json b/package-lock.json index 209faa2056..e2a3111a23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,9 @@ "version": "0.5.3", "license": "ISC", "dependencies": { + "@anthropic-ai/sdk": "^0.5.0", "@dqbd/tiktoken": "^1.0.2", + "@fortaine/fetch-event-source": "^3.0.6", "@keyv/mongo": "^2.1.8", "@waylaidwanderer/chatgpt-api": "^1.37.0", "axios": "^1.3.4", @@ -91,6 +93,28 @@ "supertest": "^6.3.3" } }, + "api/node_modules/@anthropic-ai/sdk": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.5.0.tgz", + "integrity": "sha512-7T/oK6CtheVkdRZmIO9FSdHtKyUU92F6JHRz7RY99gzcm6DM5rYTNORvwVHWTe0nr9lsZuso8GpoXZsUG7Zypg==", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "@types/qs": "^6.9.7", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "digest-fetch": "^1.3.0", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7", + "qs": "^6.10.3" + } + }, + "api/node_modules/@types/node": { + "version": "18.16.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.19.tgz", + "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==" + }, "api/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -371,6 +395,15 @@ } } }, + "api/node_modules/langchain/node_modules/@anthropic-ai/sdk": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.4.4.tgz", + "integrity": "sha512-Z/39nQi1sSUCeLII3lsAbL1u+0JF6cR2XmUEX9sLH0VtxmIjY6cjOUYjCkYh4oapTxOkhAFnVSAFJ6cxml2qXg==", + "dependencies": { + "@fortaine/fetch-event-source": "^3.0.6", + "cross-fetch": "^3.1.5" + } + }, "client": { "name": "@librechat/frontend", "version": "0.5.3", @@ -7560,6 +7593,28 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz", "integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==" }, + "node_modules/@types/node-fetch": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz", + "integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==", + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@types/parse5": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", @@ -7576,6 +7631,11 @@ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, "node_modules/@types/react": { "version": "18.2.11", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.11.tgz", @@ -8320,6 +8380,19 @@ "node": ">= 14" } }, + "node_modules/agentkeepalive": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "dependencies": { + "debug": "^4.1.0", + "depd": "^2.0.0", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -9213,6 +9286,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + }, "node_modules/base64-arraybuffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", @@ -9754,6 +9832,14 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "engines": { + "node": "*" + } + }, "node_modules/cheerio": { "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", @@ -10519,6 +10605,14 @@ "node": ">= 8" } }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "engines": { + "node": "*" + } + }, "node_modules/crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -11022,6 +11116,15 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, + "node_modules/digest-fetch": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", + "integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", + "dependencies": { + "base-64": "^0.1.0", + "md5": "^2.3.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -12898,6 +13001,11 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + }, "node_modules/format": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", @@ -12906,6 +13014,18 @@ "node": ">=0.4.x" } }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, "node_modules/formidable": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", @@ -13894,6 +14014,14 @@ "node": ">=10.17.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/husky": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", @@ -18228,6 +18356,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -18238,6 +18376,11 @@ "safe-buffer": "^5.1.2" } }, + "node_modules/md5/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "node_modules/mdast-util-definitions": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", @@ -19544,6 +19687,24 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.6.11", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", @@ -25895,6 +26056,14 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "engines": { + "node": ">= 14" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -30217,7 +30386,9 @@ "@librechat/backend": { "version": "file:api", "requires": { + "@anthropic-ai/sdk": "^0.5.0", "@dqbd/tiktoken": "^1.0.2", + "@fortaine/fetch-event-source": "^3.0.6", "@keyv/mongo": "^2.1.8", "@waylaidwanderer/chatgpt-api": "^1.37.0", "axios": "^1.3.4", @@ -30259,6 +30430,28 @@ "supertest": "^6.3.3" }, "dependencies": { + "@anthropic-ai/sdk": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.5.0.tgz", + "integrity": "sha512-7T/oK6CtheVkdRZmIO9FSdHtKyUU92F6JHRz7RY99gzcm6DM5rYTNORvwVHWTe0nr9lsZuso8GpoXZsUG7Zypg==", + "requires": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "@types/qs": "^6.9.7", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "digest-fetch": "^1.3.0", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7", + "qs": "^6.10.3" + } + }, + "@types/node": { + "version": "18.16.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.19.tgz", + "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==" + }, "ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -30303,6 +30496,17 @@ "yaml": "^2.2.1", "zod": "^3.21.4", "zod-to-json-schema": "^3.20.4" + }, + "dependencies": { + "@anthropic-ai/sdk": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.4.4.tgz", + "integrity": "sha512-Z/39nQi1sSUCeLII3lsAbL1u+0JF6cR2XmUEX9sLH0VtxmIjY6cjOUYjCkYh4oapTxOkhAFnVSAFJ6cxml2qXg==", + "requires": { + "@fortaine/fetch-event-source": "^3.0.6", + "cross-fetch": "^3.1.5" + } + } } } } @@ -31631,6 +31835,27 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz", "integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==" }, + "@types/node-fetch": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz", + "integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==", + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + }, + "dependencies": { + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, "@types/parse5": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", @@ -31647,6 +31872,11 @@ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, "@types/react": { "version": "18.2.11", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.11.tgz", @@ -32239,6 +32469,16 @@ "debug": "^4.3.4" } }, + "agentkeepalive": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "requires": { + "debug": "^4.1.0", + "depd": "^2.0.0", + "humanize-ms": "^1.2.1" + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -32943,6 +33183,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + }, "base64-arraybuffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", @@ -33329,6 +33574,11 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==" + }, "cheerio": { "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", @@ -33917,6 +34167,11 @@ "which": "^2.0.1" } }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==" + }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -34280,6 +34535,15 @@ } } }, + "digest-fetch": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", + "integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", + "requires": { + "base-64": "^0.1.0", + "md5": "^2.3.0" + } + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -35709,11 +35973,25 @@ "mime-types": "^2.1.12" } }, + "form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + }, "format": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==" }, + "formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "requires": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + } + }, "formidable": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", @@ -36444,6 +36722,14 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "requires": { + "ms": "^2.0.0" + } + }, "husky": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", @@ -39607,6 +39893,23 @@ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==" }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + } + } + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -40486,6 +40789,11 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + }, "node-fetch": { "version": "2.6.11", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", @@ -44889,6 +45197,11 @@ "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==" }, + "web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==" + }, "webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/packages/data-provider/src/createPayload.ts b/packages/data-provider/src/createPayload.ts index 4fc95d9c3b..6808e9e14f 100644 --- a/packages/data-provider/src/createPayload.ts +++ b/packages/data-provider/src/createPayload.ts @@ -12,7 +12,8 @@ export default function createPayload(submission: TSubmission) { bingAI: '/api/ask/bingAI', chatGPT: '/api/ask/chatGPT', chatGPTBrowser: '/api/ask/chatGPTBrowser', - gptPlugins: '/api/ask/gptPlugins' + gptPlugins: '/api/ask/gptPlugins', + anthropic: '/api/ask/anthropic', }; const server = endpointUrlMap[endpoint]; diff --git a/packages/data-provider/src/types.ts b/packages/data-provider/src/types.ts index be2abe9f32..f937f95481 100644 --- a/packages/data-provider/src/types.ts +++ b/packages/data-provider/src/types.ts @@ -24,6 +24,7 @@ export enum EModelEndpoint { chatGPTBrowser = 'chatGPTBrowser', google = 'google', gptPlugins = 'gptPlugins', + anthropic = 'anthropic', } export type TSubmission = {