From ea0e34ef98b4a1a34a7a5567d909c2a0cf550855 Mon Sep 17 00:00:00 2001 From: Troy Simeon Taylor <44444967+troystaylor@users.noreply.github.com> Date: Thu, 4 Sep 2025 13:41:26 -0400 Subject: [PATCH 1/2] Add files via upload --- .../GitHub Models/apiDefinition.swagger.json | 617 ++++++++++++++++++ .../GitHub Models/apiProperties.json | 67 ++ .../GitHub Models/readme.md | 60 ++ 3 files changed, 744 insertions(+) create mode 100644 independent-publisher-connectors/GitHub Models/apiDefinition.swagger.json create mode 100644 independent-publisher-connectors/GitHub Models/apiProperties.json create mode 100644 independent-publisher-connectors/GitHub Models/readme.md diff --git a/independent-publisher-connectors/GitHub Models/apiDefinition.swagger.json b/independent-publisher-connectors/GitHub Models/apiDefinition.swagger.json new file mode 100644 index 0000000000..1b91a3cdce --- /dev/null +++ b/independent-publisher-connectors/GitHub Models/apiDefinition.swagger.json @@ -0,0 +1,617 @@ +{ + "swagger": "2.0", + "info": { + "title": "GitHub Models", + "description": "Access GitHub Models service for AI inference with various open-source and proprietary models including GPT-4o, DeepSeek-R1, and more. GitHub Models provides OpenAI-compatible REST endpoints for chat completions and embeddings.", + "version": "1.0.0", + "contact": { + "name": "Troy Taylor", + "email": "ttaylor@hitachisolutions.com", + "url": "https://www.hitachisolutions.com" + } + }, + "host": "models.github.ai", + "basePath": "/", + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/inference/chat/completions": { + "post": { + "tags": [ + "Inference" + ], + "summary": "Create chat completion", + "description": "Creates a chat completion using GitHub Models. This endpoint is compatible with OpenAI's chat completions API and supports various models including GPT-4o, DeepSeek-R1, and Llama 3.", + "operationId": "CreateChatCompletion", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ChatCompletionRequest" + }, + "description": "Chat completion request parameters including model, messages, and optional settings.", + "x-ms-summary": "Request Body" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/ChatCompletionResponse" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "429": { + "description": "Rate limit exceeded", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/inference/embeddings": { + "post": { + "tags": [ + "Embeddings" + ], + "summary": "Create embeddings", + "description": "Creates embeddings for the given input text using GitHub Models embedding models. Embeddings are useful for semantic search, text classification, and similarity analysis.", + "operationId": "CreateEmbeddings", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/EmbeddingRequest" + }, + "description": "Embedding request parameters including model and input text.", + "x-ms-summary": "Request Body" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/EmbeddingResponse" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "429": { + "description": "Rate limit exceeded", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/catalog/models": { + "get": { + "tags": [ + "Models" + ], + "summary": "List available models", + "description": "Retrieves a list of all available models in the GitHub Models catalog. Use this to discover available models and their capabilities.", + "operationId": "ListModels", + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/ModelListResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, + "definitions": { + "ChatCompletionRequest": { + "type": "object", + "required": [ + "model", + "messages" + ], + "properties": { + "model": { + "type": "string", + "description": "The model to use for completion. Examples: 'openai/gpt-4o', 'meta-llama/llama-3-8b-instruct', 'deepseek/deepseek-r1'.", + "example": "openai/gpt-4o", + "x-ms-summary": "Model" + }, + "messages": { + "type": "array", + "description": "The messages to generate chat completions for. Each message should have a role (system, user, or assistant) and content.", + "x-ms-summary": "Messages", + "items": { + "$ref": "#/definitions/ChatMessage" + } + }, + "temperature": { + "type": "number", + "format": "float", + "description": "Controls randomness in the output. Higher values make output more random, lower values make it more focused and deterministic.", + "x-ms-summary": "Temperature", + "minimum": 0, + "maximum": 2, + "default": 1 + }, + "max_tokens": { + "type": "integer", + "format": "int32", + "description": "The maximum number of tokens to generate in the completion.", + "x-ms-summary": "Max Tokens", + "minimum": 1, + "default": 1024 + }, + "top_p": { + "type": "number", + "format": "float", + "description": "An alternative to sampling with temperature, called nucleus sampling", + "x-ms-summary": "Top P", + "minimum": 0, + "maximum": 1, + "default": 1 + }, + "frequency_penalty": { + "type": "number", + "format": "float", + "description": "Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far.", + "x-ms-summary": "Frequency Penalty", + "minimum": -2, + "maximum": 2, + "default": 0 + }, + "presence_penalty": { + "type": "number", + "format": "float", + "description": "Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far.", + "x-ms-summary": "Presence Penalty", + "minimum": -2, + "maximum": 2, + "default": 0 + }, + "stop": { + "type": "array", + "description": "Up to 4 sequences where the API will stop generating further tokens.", + "x-ms-summary": "Stop Sequences", + "items": { + "type": "string" + }, + "maxItems": 4 + }, + "stream": { + "type": "boolean", + "description": "Whether to stream back partial progress", + "x-ms-summary": "Stream", + "default": false + } + } + }, + "ChatMessage": { + "type": "object", + "required": [ + "role", + "content" + ], + "properties": { + "role": { + "type": "string", + "enum": [ + "system", + "user", + "assistant" + ], + "description": "The role of the message author.", + "x-ms-summary": "Role" + }, + "content": { + "type": "string", + "description": "The content of the message.", + "x-ms-summary": "Content" + }, + "name": { + "type": "string", + "description": "An optional name for the participant.", + "x-ms-summary": "Name" + } + } + }, + "ChatCompletionResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "A unique identifier for the chat completion", + "x-ms-summary": "ID" + }, + "object": { + "type": "string", + "description": "The object type, which is always 'chat.completion'", + "x-ms-summary": "Object Type" + }, + "created": { + "type": "integer", + "format": "int32", + "description": "The Unix timestamp (in seconds) when the chat completion was created", + "x-ms-summary": "Created" + }, + "model": { + "type": "string", + "description": "The model used for the chat completion", + "x-ms-summary": "Model" + }, + "choices": { + "type": "array", + "description": "A list of chat completion choices", + "x-ms-summary": "Choices", + "items": { + "$ref": "#/definitions/ChatChoice" + } + }, + "usage": { + "$ref": "#/definitions/Usage" + } + } + }, + "ChatChoice": { + "type": "object", + "properties": { + "index": { + "type": "integer", + "format": "int32", + "description": "The index of the choice in the list of choices", + "x-ms-summary": "Index" + }, + "message": { + "$ref": "#/definitions/ChatMessage" + }, + "finish_reason": { + "type": "string", + "enum": [ + "stop", + "length", + "content_filter" + ], + "description": "The reason the model stopped generating tokens", + "x-ms-summary": "Finish Reason" + } + } + }, + "EmbeddingRequest": { + "type": "object", + "required": [ + "model", + "input" + ], + "properties": { + "model": { + "type": "string", + "description": "The model to use for embeddings (e.g., 'text-embedding-3-small', 'text-embedding-3-large')", + "x-ms-summary": "Model", + "example": "text-embedding-3-small" + }, + "input": { + "type": "array", + "description": "Input text to get embeddings for", + "x-ms-summary": "Input", + "items": { + "type": "string" + } + }, + "encoding_format": { + "type": "string", + "enum": [ + "float", + "base64" + ], + "description": "The format to return the embeddings in", + "x-ms-summary": "Encoding Format", + "default": "float" + } + } + }, + "EmbeddingResponse": { + "type": "object", + "properties": { + "object": { + "type": "string", + "description": "The object type, which is always 'list'", + "x-ms-summary": "Object Type" + }, + "data": { + "type": "array", + "description": "A list of embedding objects", + "x-ms-summary": "Data", + "items": { + "$ref": "#/definitions/Embedding" + } + }, + "model": { + "type": "string", + "description": "The model used for the embeddings", + "x-ms-summary": "Model" + }, + "usage": { + "$ref": "#/definitions/Usage" + } + } + }, + "Embedding": { + "type": "object", + "properties": { + "object": { + "type": "string", + "description": "The object type, which is always 'embedding'", + "x-ms-summary": "Object Type" + }, + "embedding": { + "type": "array", + "description": "The embedding vector", + "x-ms-summary": "Embedding", + "items": { + "type": "number", + "format": "float" + } + }, + "index": { + "type": "integer", + "format": "int32", + "description": "The index of the embedding in the list of embeddings", + "x-ms-summary": "Index" + } + } + }, + "ModelListResponse": { + "type": "array", + "description": "A list of model objects", + "x-ms-summary": "Models", + "items": { + "$ref": "#/definitions/ModelResponse" + } + }, + "ModelResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The model identifier", + "x-ms-summary": "ID" + }, + "name": { + "type": "string", + "description": "The human-readable name of the model", + "x-ms-summary": "Name" + }, + "publisher": { + "type": "string", + "description": "The publisher of the model", + "x-ms-summary": "Publisher" + }, + "registry": { + "type": "string", + "description": "The registry where the model is hosted", + "x-ms-summary": "Registry" + }, + "summary": { + "type": "string", + "description": "A summary description of the model", + "x-ms-summary": "Summary" + }, + "html_url": { + "type": "string", + "description": "The URL to the model's marketplace page", + "x-ms-summary": "Marketplace URL" + }, + "version": { + "type": "string", + "description": "The version of the model", + "x-ms-summary": "Version" + }, + "capabilities": { + "type": "array", + "description": "The capabilities of the model", + "x-ms-summary": "Capabilities", + "items": { + "type": "string" + } + }, + "limits": { + "type": "object", + "description": "Token limits for the model", + "x-ms-summary": "Limits", + "properties": { + "max_input_tokens": { + "type": "integer", + "format": "int32", + "description": "Maximum input tokens", + "x-ms-summary": "Max Input Tokens" + }, + "max_output_tokens": { + "type": "integer", + "format": "int32", + "description": "Maximum output tokens", + "x-ms-summary": "Max Output Tokens" + } + } + }, + "rate_limit_tier": { + "type": "string", + "description": "The rate limit tier for this model", + "x-ms-summary": "Rate Limit Tier" + }, + "supported_input_modalities": { + "type": "array", + "description": "Supported input modalities (text, image, audio)", + "x-ms-summary": "Input Modalities", + "items": { + "type": "string" + } + }, + "supported_output_modalities": { + "type": "array", + "description": "Supported output modalities (text, image, audio)", + "x-ms-summary": "Output Modalities", + "items": { + "type": "string" + } + }, + "tags": { + "type": "array", + "description": "Tags describing the model's characteristics", + "x-ms-summary": "Tags", + "items": { + "type": "string" + } + } + } + }, + "Usage": { + "type": "object", + "properties": { + "prompt_tokens": { + "type": "integer", + "format": "int32", + "description": "Number of tokens in the prompt", + "x-ms-summary": "Prompt Tokens" + }, + "completion_tokens": { + "type": "integer", + "format": "int32", + "description": "Number of tokens in the generated completion", + "x-ms-summary": "Completion Tokens" + }, + "total_tokens": { + "type": "integer", + "format": "int32", + "description": "Total number of tokens used in the request (prompt + completion)", + "x-ms-summary": "Total Tokens" + } + } + }, + "ErrorResponse": { + "type": "object", + "properties": { + "error": { + "type": "object", + "x-ms-summary": "Error", + "properties": { + "message": { + "type": "string", + "description": "A human-readable error message", + "x-ms-summary": "Message" + }, + "type": { + "type": "string", + "description": "The type of error", + "x-ms-summary": "Type" + }, + "code": { + "type": "string", + "description": "An error code", + "x-ms-summary": "Code" + } + } + } + } + } + }, + "securityDefinitions": { + "Bearer": { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "description": "GitHub Personal Access Token (PAT) with models:read scope. Format: 'Bearer {your_github_token}'" + } + }, + "security": [ + { + "Bearer": [] + } + ], + "tags": [ + { + "name": "Inference", + "description": "Operations for AI model inference" + }, + { + "name": "Embeddings", + "description": "Operations for creating text embeddings" + }, + { + "name": "Models", + "description": "Operations for retrieving model catalog information" + } + ], + "x-ms-connector-metadata": [ + { + "propertyName": "Website", + "propertyValue": "https://docs.github.com/en/github-models" + }, + { + "propertyName": "Privacy policy", + "propertyValue": "https://docs.github.com/en/site-policy/privacy-policies/github-privacy-statement" + }, + { + "propertyName": "Categories", + "propertyValue": "AI;Data" + } + ] +} \ No newline at end of file diff --git a/independent-publisher-connectors/GitHub Models/apiProperties.json b/independent-publisher-connectors/GitHub Models/apiProperties.json new file mode 100644 index 0000000000..8c4eeb274e --- /dev/null +++ b/independent-publisher-connectors/GitHub Models/apiProperties.json @@ -0,0 +1,67 @@ +{ + "properties": { + "connectionParameters": { + "token": { + "type": "securestring", + "uiDefinition": { + "displayName": "GitHub Personal Access Token", + "description": "Enter your GitHub Personal Access Token (PAT) with 'models:read' scope. You can create a PAT at https://github.com/settings/tokens", + "tooltip": "Required: A GitHub Personal Access Token with models:read scope to access GitHub Models API", + "constraints": { + "tabIndex": 2, + "clearText": false, + "required": "true" + } + } + } + }, + "iconBrandColor": "#da3b01", + "capabilities": [ + "actions" + ], + "policyTemplateInstances": [ + { + "templateId": "setheader", + "title": "Set Authorization Header", + "parameters": { + "x-ms-apimTemplateParameter.name": "Authorization", + "x-ms-apimTemplateParameter.value": "Bearer @connectionParameters('token')", + "x-ms-apimTemplateParameter.existsAction": "override", + "x-ms-apimTemplate-policySection": "Request" + } + }, + { + "templateId": "setheader", + "title": "Set User-Agent Header", + "parameters": { + "x-ms-apimTemplateParameter.name": "User-Agent", + "x-ms-apimTemplateParameter.value": "PowerPlatform-GitHubModels-Connector/1.0", + "x-ms-apimTemplateParameter.existsAction": "override", + "x-ms-apimTemplate-policySection": "Request" + } + }, + { + "templateId": "setheader", + "title": "Set Content-Type Header", + "parameters": { + "x-ms-apimTemplateParameter.name": "Content-Type", + "x-ms-apimTemplateParameter.value": "application/json", + "x-ms-apimTemplateParameter.existsAction": "override", + "x-ms-apimTemplate-policySection": "Request" + } + }, + { + "templateId": "setheader", + "title": "Set Accept Header", + "parameters": { + "x-ms-apimTemplateParameter.name": "Accept", + "x-ms-apimTemplateParameter.value": "application/vnd.github+json", + "x-ms-apimTemplateParameter.existsAction": "override", + "x-ms-apimTemplate-policySection": "Request" + } + } + ], + "publisher": "Troy Taylor", + "stackOwner": "GitHub" + } +} \ No newline at end of file diff --git a/independent-publisher-connectors/GitHub Models/readme.md b/independent-publisher-connectors/GitHub Models/readme.md new file mode 100644 index 0000000000..eef80c7402 --- /dev/null +++ b/independent-publisher-connectors/GitHub Models/readme.md @@ -0,0 +1,60 @@ +# GitHub Models (Independent Publisher) + +GitHub Models provides free AI inference service access to various large language models including GPT-4o, DeepSeek-R1, Llama 3, and more. This connector enables seamless integration with the OpenAI-compatible GitHub Models service. + +## Publisher: Troy Taylor + +## Prerequisites + +You will need the following to proceed: +- A GitHub account +- A GitHub Personal Access Token (PAT) with `models:read` scope + +## Obtaining Credentials + +1. Go to [GitHub Settings > Developer settings > Personal access tokens](https://github.com/settings/tokens) +2. Click "Generate new token" > "Generate new token (classic)" +3. Give your token a descriptive name (e.g., "Power Platform GitHub Models") +4. Select the `models:read` scope under "Select scopes" +5. Click "Generate token" +6. **Important**: Copy the token immediately as it won't be shown again + +## Supported Operations + +### Create Chat Completion +Creates a chat completion using GitHub Models. This endpoint is compatible with OpenAI's chat completions API and supports various models including GPT-4o, DeepSeek-R1, and Llama 3. + +### Create Embeddings +Creates embeddings for the given input text using GitHub Models embedding models. Embeddings are useful for semantic search, text classification, and similarity analysis. + +### List Available Models +Retrieves a list of all available models in the GitHub Models catalog. Use this to discover available models and their capabilities. + +### Get Model Details +Retrieves detailed information about a specific model including capabilities, context length, and ownership details. + +## Available Models + +### Chat Completion Models +- `openai/gpt-4o` - OpenAI's most capable model +- `meta-llama/llama-3-8b-instruct` - Meta's Llama 3 model +- `deepseek/deepseek-r1` - DeepSeek's reasoning model +- And more models available in the catalog + +### Embedding Models +- `text-embedding-3-small` - Smaller, faster embedding model +- `text-embedding-3-large` - Larger, more capable embedding model + +## API Documentation + +For more information about the GitHub Models API, visit: +- [GitHub Models Documentation](https://docs.github.com/en/github-models) +- [GitHub Models API Reference](https://docs.github.com/en/rest/models) + +## Known Issues and Limitations + +- Free tier has usage limits per GitHub account +- Some models may have restricted availability based on region +- Streaming responses are not supported in this connector +- Rate limits apply based on your GitHub account tier +- Model availability may change over time \ No newline at end of file From 2c8810194c44082c4ff879d23e46a2bcbbccac42 Mon Sep 17 00:00:00 2001 From: Troy Simeon Taylor <44444967+troystaylor@users.noreply.github.com> Date: Thu, 23 Oct 2025 16:04:22 -0400 Subject: [PATCH 2/2] Add files via upload --- .../GitHub Models/ConnectorPackage.zip | Bin 0 -> 13362 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 independent-publisher-connectors/GitHub Models/ConnectorPackage.zip diff --git a/independent-publisher-connectors/GitHub Models/ConnectorPackage.zip b/independent-publisher-connectors/GitHub Models/ConnectorPackage.zip new file mode 100644 index 0000000000000000000000000000000000000000..a2d5dff7af0248bce6dd31676ca03b241d7f613b GIT binary patch literal 13362 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%0DDfzEy5X^W& zHU0hOE?8RQ{3#aJ;BZz@zXCR0_1?y{ZeB2{SGWXNP^z@{K={+>6Y9V9L2+@?DvzwNG+Jq8#!inB%zxh85JS52(e?|BCg_N*hV6 z_h^=MkU&4M)E5Q8Y4bFRSYaTsh96^`*yxo;hoIC*b__CxPLi?ts2p>Zq;qf3hOoaXw^bHC#EIHu=ENQlz}L?&ZBxu4V~I$mo;zDP+gJtumq(-#xkd zqw3{>z15_-T7_wj@)-#!G!c%#?8;}lI0Pysqvg{B&mvB~$%xjKt-R5*L5}%v^zXpL z%*!rs*PQD=8#2!_hm(m%_E1cK5=B2}w9polf73t3Ns`39fsfS}i_a3Yi!?18QnYo! zjb2i`=+|_(_Vhe_ft2i1PY5Iq{P5jtl90#!0Rzg}*t?QgLo6>IGi#9BU8uSU3^?CQ z=eZof^z}4~kF>;OaY2PrGsRoKBPXD_@7*e!-HyR4sTdoZ4mzlz0E7_df4)!Kdm)5@Eae1CKjuO{r!$|Qj?9-d$4nHCQ)g3p9IpQ64~HdZ@A34fU(KpJuTM-!0qN9#qep-LD8 zkgr&F2z-_;&3o~^EGXTCMImAvQE96F`u98zC+uT9V7xR-m8GQt!zf!@ zHL%ktohzlSEq#&DlID{WQ`^T0fN8)qw{)n(0wTXXjIC)tBtKaDZA!nH&N^5iPT#VX zXOSjc#1J@Kjv#IU%sr=;JZ?Sa?#i|ec~==~d#8&z*pkA+>=&vOwE?~v<O!60-6#&!D)rVT}wAF z0}|JZ>+1No;15JAKlfI2*6{hq*--Z!K>Ow>yr}(xI+`Vc8cx5ms1gP*?@8Ra7D*2L zVUyUp@WyiM6=D%>RL00uF!^6(?0kQ~$gHG1B)_WVQ}@lk#_d&f(K1cC z>CwNMscX?ywD_no?RdL3>$9@lS;Fnh(@}k@U)qE%v+uPXAR&H1=Efp|>gUG7T3_3x ziufZ>iN(<(uI9oH64;v2r0|U>Iv_-cjxK%TRux!eU`0ft{{ryjj~D}5al`01%4ZJ8 zO>)PzBjOOmaUxfw+8Pv&Sn9Ye!1`BfSS|aBfI0~t(=0Ewd{cdO5giTIjl-@A%VpmQ ztIU&nI$o;GaDBZL^jvg#>fZ2wAW zOB&Z5Ou!`w}1O+bI^nb3# zY3@FtDI!+kjPCXOPbPU0g0>Ok4n$mPFp_E7J{h$Fl=3@X1#bN|WUvcttyb1z!f}B6 zXt-)*p)0mFH_0>)6z6z`mzGkt@W*6pCXX?vtQf zT_sk!J;N5kX9F5pI*Po`PuhH~`vnbWr$_4ADKUkqObESZv?K^Q8tnmY%l7u{Oq{tP zcl`l{*Ftj?WhLjWH~e@8SWv@d{NMpZ7aWRBC*h3uBZ=kpPi0Uf8P#b=>6vg!wmw|V zx<8ErHOD+1V^Xg;aHQe46BN#HPJCB?50Lz*{N=xLYSFfpmlr>qBJ8y`?Ni1$RX~H) zPf6)z;BBA8E{CqBTMxq+3hzwcp@Z92M4VDFx(=2pV%Z~wRWB(E|2*|GK8mAjfnYJ3 zB0PrTwmD)}JbfAh&j(fm^{bn~TaJ_{YywW{4Z^me%i&j@g>n^5oR~Bojs9MEmkp>4 z_IF>SASvu@v-bU`$ zPnLKdiDL_y4KIMPxp4gopq>o)6ove}!FvCRT?Og?xi0ycBl}67`QAf?D*7R+pqUI1 z`&|28^JhI0;>h^!>-+&%k^=?90QvvRb^b$u|DV;J`>|6e^IAgzH7 c|B?RuUkrLBIY_Ag7Qz1G_W!{ew*N-|134(x?f?J) literal 0 HcmV?d00001