deploy: c9b95c7c9f15441738c938bb27cca66eb86990e3
4
.buildinfo
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Sphinx build info version 1
|
||||
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
|
||||
config: 416c1b7f738dbd8ff231cf7246bbbb27
|
||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
||||
1
CNAME
|
|
@ -1 +0,0 @@
|
|||
docs.archgw.com
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
version: "0.1-beta"
|
||||
|
||||
listener:
|
||||
address: 0.0.0.0 # or 127.0.0.1
|
||||
port: 10000
|
||||
# Defines how Arch should parse the content from application/json or text/pain Content-type in the http request
|
||||
message_format: huggingface
|
||||
common_tls_context: # If you configure port 443, you'll need to update the listener with your TLS certificates
|
||||
tls_certificates:
|
||||
- certificate_chain:
|
||||
filename: "/etc/certs/cert.pem"
|
||||
private_key:
|
||||
filename: "/etc/certs/key.pem"
|
||||
|
||||
# Arch creates a round-robin load balancing between different endpoints, managed via the cluster subsystem.
|
||||
endpoints:
|
||||
app_server:
|
||||
# value could be ip address or a hostname with port
|
||||
# this could also be a list of endpoints for load balancing
|
||||
# for example endpoint: [ ip1:port, ip2:port ]
|
||||
endpoint: "127.0.0.1:80"
|
||||
# max time to wait for a connection to be established
|
||||
connect_timeout: 0.005s
|
||||
|
||||
mistral_local:
|
||||
endpoint: "127.0.0.1:8001"
|
||||
|
||||
error_target:
|
||||
endpoint: "error_target_1"
|
||||
|
||||
# Centralized way to manage LLMs, manage keys, retry logic, failover and limits in a central way
|
||||
llm_providers:
|
||||
- name: "OpenAI"
|
||||
provider: "openai"
|
||||
access_key: $OPENAI_API_KEY
|
||||
model: gpt-4o
|
||||
default: true
|
||||
stream: true
|
||||
rate_limits:
|
||||
selector: #optional headers, to add rate limiting based on http headers like JWT tokens or API keys
|
||||
http_header:
|
||||
name: "Authorization"
|
||||
value: "" # Empty value means each separate value has a separate limit
|
||||
limit:
|
||||
tokens: 100000 # Tokens per unit
|
||||
unit: "minute"
|
||||
|
||||
- name: "Mistral8x7b"
|
||||
provider: "mistral"
|
||||
access_key: $MISTRAL_API_KEY
|
||||
model: "mistral-8x7b"
|
||||
|
||||
- name: "MistralLocal7b"
|
||||
provider: "local"
|
||||
model: "mistral-7b-instruct"
|
||||
endpoint: "mistral_local"
|
||||
|
||||
# provides a way to override default settings for the arch system
|
||||
overrides:
|
||||
# By default Arch uses an NLI + embedding approach to match an incomming prompt to a prompt target.
|
||||
# The intent matching threshold is kept at 0.80, you can overide this behavior if you would like
|
||||
prompt_target_intent_matching_threshold: 0.60
|
||||
|
||||
# default system prompt used by all prompt targets
|
||||
system_prompt: |
|
||||
You are a network assistant that just offers facts; not advice on manufacturers or purchasing decisions.
|
||||
|
||||
prompt_guards:
|
||||
input_guards:
|
||||
jailbreak:
|
||||
on_exception:
|
||||
message: "Looks like you're curious about my abilities, but I can only provide assistance within my programmed parameters."
|
||||
|
||||
prompt_targets:
|
||||
- name: "reboot_network_device"
|
||||
description: "Helps network operators perform device operations like rebooting a device."
|
||||
endpoint:
|
||||
name: app_server
|
||||
path: "/agent/action"
|
||||
parameters:
|
||||
- name: "device_id"
|
||||
# additional type options include: int | float | bool | string | list | dict
|
||||
type: "string"
|
||||
description: "Identifier of the network device to reboot."
|
||||
required: true
|
||||
- name: "confirmation"
|
||||
type: "string"
|
||||
description: "Confirmation flag to proceed with reboot."
|
||||
default: "no"
|
||||
enum: [yes, no]
|
||||
|
||||
- name: "information_extraction"
|
||||
default: true
|
||||
description: "This prompt handles all scenarios that are question and answer in nature. Like summarization, information extraction, etc."
|
||||
endpoint:
|
||||
name: app_server
|
||||
path: "/agent/summary"
|
||||
# Arch uses the default LLM and treats the response from the endpoint as the prompt to send to the LLM
|
||||
auto_llm_dispatch_on_response: true
|
||||
# override system prompt for this prompt target
|
||||
system_prompt: |
|
||||
You are a helpful information extraction assistant. Use the information that is provided to you.
|
||||
|
||||
error_target:
|
||||
endpoint:
|
||||
name: error_target_1
|
||||
path: /error
|
||||
|
||||
tracing: 100 #sampling rate. Note by default Arch works on OpenTelemetry compatible tracing.
|
||||
152
_downloads/76c29fa020a722e6be4b991f849978ce/intent_detection.py
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
from flask import Flask, request, jsonify
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
from langchain.memory import ConversationBufferMemory
|
||||
from langchain.schema import AIMessage, HumanMessage
|
||||
from langchain import OpenAI
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# Global dictionary to keep track of user memories
|
||||
user_memories = {}
|
||||
|
||||
def get_user_conversation(user_id):
|
||||
"""
|
||||
Retrieve the user's conversation memory using LangChain.
|
||||
If the user does not exist, initialize their conversation memory.
|
||||
"""
|
||||
if user_id not in user_memories:
|
||||
user_memories[user_id] = ConversationBufferMemory(return_messages=True)
|
||||
return user_memories[user_id]
|
||||
|
||||
def update_user_conversation(user_id, client_messages, intent_changed):
|
||||
"""
|
||||
Update the user's conversation memory with new messages using LangChain.
|
||||
Each message is augmented with a UUID, timestamp, and intent change marker.
|
||||
Only new messages are added to avoid duplication.
|
||||
"""
|
||||
memory = get_user_conversation(user_id)
|
||||
stored_messages = memory.chat_memory.messages
|
||||
|
||||
# Determine the number of stored messages
|
||||
num_stored_messages = len(stored_messages)
|
||||
new_messages = client_messages[num_stored_messages:]
|
||||
|
||||
# Process each new message
|
||||
for index, message in enumerate(new_messages):
|
||||
role = message.get('role')
|
||||
content = message.get('content')
|
||||
metadata = {
|
||||
'uuid': str(uuid.uuid4()),
|
||||
'timestamp': datetime.utcnow().isoformat(),
|
||||
'intent_changed': False # Default value
|
||||
}
|
||||
|
||||
# Mark the intent change on the last message if detected
|
||||
if intent_changed and index == len(new_messages) - 1:
|
||||
metadata['intent_changed'] = True
|
||||
|
||||
# Create a new message with metadata
|
||||
if role == 'user':
|
||||
memory.chat_memory.add_message(
|
||||
HumanMessage(content=content, additional_kwargs={'metadata': metadata})
|
||||
)
|
||||
elif role == 'assistant':
|
||||
memory.chat_memory.add_message(
|
||||
AIMessage(content=content, additional_kwargs={'metadata': metadata})
|
||||
)
|
||||
else:
|
||||
# Handle other roles if necessary
|
||||
pass
|
||||
|
||||
return memory
|
||||
|
||||
def get_messages_since_last_intent(messages):
|
||||
"""
|
||||
Retrieve messages from the last intent change onwards using LangChain.
|
||||
"""
|
||||
messages_since_intent = []
|
||||
for message in reversed(messages):
|
||||
# Insert message at the beginning to maintain correct order
|
||||
messages_since_intent.insert(0, message)
|
||||
metadata = message.additional_kwargs.get('metadata', {})
|
||||
# Break if intent_changed is True
|
||||
if metadata.get('intent_changed', False) == True:
|
||||
break
|
||||
return messages_since_intent
|
||||
|
||||
def forward_to_llm(messages):
|
||||
"""
|
||||
Forward messages to an upstream LLM using LangChain.
|
||||
"""
|
||||
# Convert messages to a conversation string
|
||||
conversation = ""
|
||||
for message in messages:
|
||||
role = 'User' if isinstance(message, HumanMessage) else 'Assistant'
|
||||
content = message.content
|
||||
conversation += f"{role}: {content}\n"
|
||||
# Use LangChain's LLM to get a response. This call is proxied through Arch for end-to-end observability and traffic management
|
||||
llm = OpenAI()
|
||||
# Create a prompt that includes the conversation
|
||||
prompt = f"{conversation}Assistant:"
|
||||
response = llm(prompt)
|
||||
return response
|
||||
|
||||
@app.route('/process_rag', methods=['POST'])
|
||||
def process_rag():
|
||||
# Extract JSON data from the request
|
||||
data = request.get_json()
|
||||
|
||||
user_id = data.get('user_id')
|
||||
if not user_id:
|
||||
return jsonify({'error': 'User ID is required'}), 400
|
||||
|
||||
client_messages = data.get('messages')
|
||||
if not client_messages or not isinstance(client_messages, list):
|
||||
return jsonify({'error': 'Messages array is required'}), 400
|
||||
|
||||
# Extract the intent change marker from Arch's headers if present for the current prompt
|
||||
intent_changed_header = request.headers.get('x-arch-intent-marker', '').lower()
|
||||
if intent_changed_header in ['', 'false']:
|
||||
intent_changed = False
|
||||
elif intent_changed_header == 'true':
|
||||
intent_changed = True
|
||||
else:
|
||||
# Invalid value provided
|
||||
return jsonify({'error': 'Invalid value for x-arch-prompt-intent-change header'}), 400
|
||||
|
||||
# Update user conversation based on intent change
|
||||
memory = update_user_conversation(user_id, client_messages, intent_changed)
|
||||
|
||||
# Retrieve messages since last intent change for LLM
|
||||
messages_for_llm = get_messages_since_last_intent(memory.chat_memory.messages)
|
||||
|
||||
# Forward messages to upstream LLM
|
||||
llm_response = forward_to_llm(messages_for_llm)
|
||||
|
||||
# Prepare the messages to return
|
||||
messages_to_return = []
|
||||
for message in memory.chat_memory.messages:
|
||||
role = 'user' if isinstance(message, HumanMessage) else 'assistant'
|
||||
content = message.content
|
||||
metadata = message.additional_kwargs.get('metadata', {})
|
||||
message_entry = {
|
||||
'uuid': metadata.get('uuid'),
|
||||
'timestamp': metadata.get('timestamp'),
|
||||
'role': role,
|
||||
'content': content,
|
||||
'intent_changed': metadata.get('intent_changed', False)
|
||||
}
|
||||
messages_to_return.append(message_entry)
|
||||
|
||||
# Prepare the response
|
||||
response = {
|
||||
'user_id': user_id,
|
||||
'messages': messages_to_return,
|
||||
'llm_response': llm_response
|
||||
}
|
||||
|
||||
return jsonify(response), 200
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
version: "0.1-beta"
|
||||
listener:
|
||||
address: 127.0.0.1 | 0.0.0.0
|
||||
port_value: 8080 #If you configure port 443, you'll need to update the listener with tls_certificates
|
||||
messages: tuple | hugging-face-messages-api
|
||||
|
||||
system_prompts:
|
||||
- name: network_assistant
|
||||
content: You are a network assistant that just offers facts about the operational health of the network
|
||||
|
||||
llm_providers:
|
||||
- name: "OpenAI"
|
||||
access_key: $OPEN_AI_KEY
|
||||
model: gpt-4o
|
||||
default: true
|
||||
- name: "Mistral"
|
||||
access_key: $MISTRAL_KEY
|
||||
model: mixtral8-7B
|
||||
|
||||
prompt_endpoints:
|
||||
- "http://127.0.0.2"
|
||||
- "http://127.0.0.1"
|
||||
|
||||
prompt_guards:
|
||||
input-guard:
|
||||
- name: #jailbreak
|
||||
on-exception-message: Looks like you are curious about my abilities. But I can only
|
||||
|
||||
prompt_targets:
|
||||
- name: information_extraction
|
||||
type: RAG
|
||||
description: this prompt handles all information extractions scenarios
|
||||
path: /agent/summary
|
||||
|
||||
- name: reboot_network_device
|
||||
path: /agent/action
|
||||
description: used to help network operators with perform device operations like rebooting a device.
|
||||
parameters:
|
||||
error_target: #handle errors from Bolt or upstream LLMs
|
||||
name: “error_handler”
|
||||
path: /errors
|
||||
BIN
_images/arch-logo.png
Normal file
|
After Width: | Height: | Size: 311 KiB |
BIN
_images/arch-system-architecture.jpg
Normal file
|
After Width: | Height: | Size: 389 KiB |
BIN
_images/function-calling-network-flow.jpg
Normal file
|
After Width: | Height: | Size: 297 KiB |
BIN
_images/network-topology-agent.jpg
Normal file
|
After Width: | Height: | Size: 264 KiB |
BIN
_images/network-topology-ingress-egress.jpg
Normal file
|
After Width: | Height: | Size: 281 KiB |
13
_sources/configuration_reference.rst
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Configuration Reference
|
||||
============================
|
||||
|
||||
The following is a complete reference of the ``prompt-conifg.yml`` that controls the behavior of a single instance of
|
||||
the Arch gateway. We've kept things simple (less than 80 lines) and held off on exposing additional functionality (for
|
||||
e.g. suppporting push observability stats, managing prompt-endpoints as virtual cluster, exposing more load balancing
|
||||
options, etc). Our belief that the simple things, should be simple. So we offert good defaults for developers, so
|
||||
that they can spend more of their time in building features unique to their AI experience.
|
||||
|
||||
.. literalinclude:: /_config/prompt-config-full-reference.yml
|
||||
:language: yaml
|
||||
:linenos:
|
||||
:caption: :download:`prompt-config-full-reference-beta-1-0.yml </_config/prompt-config-full-reference.yml>`
|
||||
48
_sources/getting_started/getting_started.rst
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
.. _getting_started:
|
||||
|
||||
Getting Started
|
||||
================
|
||||
|
||||
.. sidebar:: Pre-requisites
|
||||
|
||||
In order for you to get started, please make sure that `Docker <https://www.docker.com/get-started>`_
|
||||
and `Python <https://www.python.org/downloads/>`_ are installed locally.
|
||||
|
||||
As the examples use the pre-built `Arch Docker images <https://hub.docker.com/r/katanemo/arch>`_,
|
||||
they should work on the following architectures:
|
||||
|
||||
- x86_64
|
||||
- ARM 64
|
||||
|
||||
|
||||
This section gets you started with a very simple configuration and provides some example configurations.
|
||||
|
||||
|
||||
The fastest way to get started using Arch is installing `pre-built binaries <https://hub.docker.com/r/katanemo/arch>`_.
|
||||
You can also build it from source.
|
||||
|
||||
Step 1: Install the Arch CLI
|
||||
----------------------------
|
||||
Arch's CLI allows you to manage and interact with the Arch gateway efficiently. To install the CLI, simply
|
||||
run the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install archgw
|
||||
|
||||
This will install the archgw command-line tool globally on your system.
|
||||
|
||||
Step 2: Start Arch Gateway
|
||||
--------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
archgw up --quick-start
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Today, only support a static bootstrap configuration file for simplicity today:
|
||||
|
||||
.. literalinclude:: /_config/getting-started.yml
|
||||
:language: yaml
|
||||
6
_sources/getting_started/use_cases.rst
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Use Cases
|
||||
|
||||
use_cases/rag
|
||||
use_cases/function_calling
|
||||
71
_sources/getting_started/use_cases/function_calling.rst
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
.. _arch_function_calling_agentic_guide:
|
||||
|
||||
Agentic (Text-to-Action) Apps
|
||||
==============================
|
||||
|
||||
Arch helps you easily personalize your applications by calling application-specific (API) functions
|
||||
via user prompts. This involves any predefined functions or APIs you want to expose to users to perform tasks,
|
||||
gather information, or manipulate data. This capability is generally referred to as **function calling**, where
|
||||
you have the flexibility to support “agentic” apps tailored to specific use cases - from updating insurance
|
||||
claims to creating ad campaigns - via prompts.
|
||||
|
||||
Arch analyzes prompts, extracts critical information from prompts, engages in lightweight conversation with
|
||||
the user to gather any missing parameters and makes API calls so that you can focus on writing business logic.
|
||||
Arch does this via its purpose-built :ref:`Arch-FC LLM <llms_in_arch>` - the fastest (200ms p90 - 10x faser than GPT-4o)
|
||||
and cheapest (100x than GPT-40) function-calling LLM that matches performance with frontier models.
|
||||
______________________________________________________________________________________________
|
||||
|
||||
.. image:: /_static/img/function-calling-network-flow.jpg
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
|
||||
Single Function Call
|
||||
--------------------
|
||||
In the most common scenario, users will request a single action via prompts, and Arch efficiently processes the
|
||||
request by extracting relevant parameters, validating the input, and calling the designated function or API. Here
|
||||
is how you would go about enabling this scenario with Arch:
|
||||
|
||||
Step 1: Define prompt targets with functions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. literalinclude:: /_config/function-calling-network-agent.yml
|
||||
:language: yaml
|
||||
:linenos:
|
||||
:emphasize-lines: 16-37
|
||||
:caption: Define prompt targets that can enable users to engage with API and backened functions of an app
|
||||
|
||||
Step 2: Process request parameters in Flask
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Once the prompt targets are configured as above, handling those parameters is
|
||||
|
||||
.. literalinclude:: /_include/parameter_handling_flask.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:caption: Flask API example for parameter extraction via HTTP request parameters
|
||||
|
||||
Parallel/ Multiple Function Calling
|
||||
-----------------------------------
|
||||
In more complex use cases, users may request multiple actions or need multiple APIs/functions to be called
|
||||
simultaneously or sequentially. With Arch, you can handle these scenarios efficiently using parallel or multiple
|
||||
function calling. This allows your application to engage in a broader range of interactions, such as updating
|
||||
different datasets, triggering events across systems, or collecting results from multiple services in one prompt.
|
||||
|
||||
Arch-FC1B is built to manage these parallel tasks efficiently, ensuring low latency and high throughput, even
|
||||
when multiple functions are invoked. It provides two mechanisms to handle these cases:
|
||||
|
||||
Step 1: Define Multiple Function Targets
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When enabling multiple function calling, define the prompt targets in a way that supports multiple functions or
|
||||
API calls based on the user's prompt. These targets can be triggered in parallel or sequentially, depending on
|
||||
the user's intent.
|
||||
|
||||
Example of Multiple Prompt Targets in YAML:
|
||||
|
||||
.. literalinclude:: /_config/function-calling-network-agent.yml
|
||||
:language: yaml
|
||||
:linenos:
|
||||
:emphasize-lines: 16-37
|
||||
:caption: Define prompt targets that can enable users to engage with API and backened functions of an app
|
||||
96
_sources/getting_started/use_cases/rag.rst
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
.. _arch_rag_guide:
|
||||
|
||||
Retrieval-Augmented (RAG)
|
||||
=========================
|
||||
|
||||
The following section describes how Arch can help you build faster, smarter and more accurate
|
||||
Retrieval-Augmented Generation (RAG) applications.
|
||||
|
||||
Intent-drift Detection
|
||||
----------------------
|
||||
|
||||
Developers struggle to handle `follow-up <https://www.reddit.com/r/ChatGPTPromptGenius/comments/17dzmpy/how_to_use_rag_with_conversation_history_for/?>`_
|
||||
or `clarifying <https://www.reddit.com/r/LocalLLaMA/comments/18mqwg6/best_practice_for_rag_with_followup_chat/>`_
|
||||
questions. Specifically, when users ask for changes or additions to previous responses their AI applications often
|
||||
generate entirely new responses instead of adjusting previous ones. Arch offers *intent-drift* tracking as a feature so
|
||||
that developers can know when the user has shifted away from a previous intent so that they can dramatically improve
|
||||
retrieval accuracy, lower overall token cost and improve the speed of their responses back to users.
|
||||
|
||||
Arch uses its built-in lightweight NLI and embedding models to know if the user has steered away from an active intent.
|
||||
Arch's intent-drift detection mechanism is based on its' *prompt_targets* primtive. Arch tries to match an incoming
|
||||
prompt to one of the *prompt_targets* configured in the gateway. Once it detects that the user has moved away from an active
|
||||
active intent, Arch adds the ``x-arch-intent-drift`` headers to the request before sending it your application servers.
|
||||
|
||||
.. literalinclude:: /_include/intent_detection.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:lines: 95-125
|
||||
:emphasize-lines: 14-22
|
||||
:caption: :download:`Intent drift detection in python </_include/intent_detection.py>`
|
||||
|
||||
_____________________________________________________________________________________________________________________
|
||||
|
||||
.. Note::
|
||||
|
||||
Arch is (mostly) stateless so that it can scale in an embarrassingly parrallel fashion. So, while Arch offers
|
||||
intent-drift detetction, you still have to maintain converational state with intent drift as meta-data. The
|
||||
following code snippets show how easily you can build and enrich conversational history with Langchain (in python),
|
||||
so that you can use the most relevant prompts for your retrieval and for prompting upstream LLMs.
|
||||
|
||||
|
||||
Step 1: define ConversationBufferMemory
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. literalinclude:: /_include/intent_detection.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:lines: 1-21
|
||||
|
||||
Step 2: update ConversationBufferMemory w/ intent
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. literalinclude:: /_include/intent_detection.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:lines: 22-62
|
||||
|
||||
Step 3: get Messages based on latest drift
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. literalinclude:: /_include/intent_detection.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:lines: 64-76
|
||||
|
||||
|
||||
You can used the last set of messages that match to an intent to prompt an LLM, use it with an vector-DB for
|
||||
improved retrieval, etc. With Arch and a few lines of code, you can improve the retrieval accuracy, lower overall
|
||||
token cost and dramatically improve the speed of their responses back to users.
|
||||
|
||||
Parameter Extraction for RAG
|
||||
----------------------------
|
||||
|
||||
To build RAG (Retrieval-Augmented Generation) applications, you can configure prompt targets with parameters,
|
||||
enabling Arch to retrieve critical information in a structured way for processing. This approach improves the
|
||||
retrieval quality and speed of your application. By extracting parameters from the conversation, you can pull
|
||||
the appropriate chunks from a vector database or SQL-like data store to enhance accuracy. With Arch, you can
|
||||
streamline data retrieval and processing to build more efficient and precise RAG applications.
|
||||
|
||||
Step 1: Define prompt targets with parameter definitions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. literalinclude:: /_config/rag-prompt-targets.yml
|
||||
:language: yaml
|
||||
:linenos:
|
||||
:emphasize-lines: 16-36
|
||||
:caption: prompt-config.yaml for parameter extraction for RAG scenarios
|
||||
|
||||
Step 2: Process request parameters in Flask
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Once the prompt targets are configured as above, handling those parameters is
|
||||
|
||||
.. literalinclude:: /_include/parameter_handling_flask.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:caption: Flask API example for parameter extraction via HTTP request parameters
|
||||
12
_sources/intro/architecture/architecture.rst
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
Technical Architecture
|
||||
======================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
intro/terminology
|
||||
intro/threading_model
|
||||
listeners/listeners
|
||||
prompt_processing/prompt_processing
|
||||
listeners/llm_provider
|
||||
model_serving/model_serving
|
||||
46
_sources/intro/architecture/intro/terminology.rst
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
.. _arch_terminology:
|
||||
|
||||
Terminology
|
||||
============
|
||||
|
||||
A few definitions before we dive into the main architecture documentation. Arch borrows from Envoy's terminology
|
||||
to keep things consistent in logs, traces and in code.
|
||||
|
||||
**Downstream(Ingress)**: An downstream client (web application, etc.) connects to Arch, sends prompts, and receives responses.
|
||||
|
||||
**Upstream(Egress)**: An upstream host that receives connections and prompts from Arch, and returns context or responses for a prompt
|
||||
|
||||
.. image:: /_static/img/network-topology-ingress-egress.jpg
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
**Listener**: A listener is a named network location (e.g., port, address, path etc.) that Arch listens on to process prompts
|
||||
before forwarding them to your application server endpoints. rch enables you to configure one listener for downstream connections
|
||||
(like port 80, 443) and creates a separate internal listener for calls that initiate from your application code to LLMs.
|
||||
|
||||
.. Note::
|
||||
|
||||
When you start Arch, you specify a listener address/port that you want to bind downstream. But, Arch uses are predefined port
|
||||
that you can use (``127.0.0.1:10000``) to proxy egress calls originating from your application to LLMs (API-based or hosted).
|
||||
For more details, check out :ref:`LLM providers <llm_providers>`
|
||||
|
||||
**Instance**: An instance of the Arch gateway. When you start Arch it creates at most two processes. One to handle Layer 7
|
||||
networking operations (auth, tls, observability, etc) and the second process to serve models that enable it to make smart
|
||||
decisions on how to accept, handle and forward prompts. The second process is optional, as the model serving sevice could be
|
||||
hosted on a different network (an API call). But these two processes are considered a single instance of Arch.
|
||||
|
||||
**Prompt Targets**: Arch offers a primitive called ``prompt_targets`` to help separate business logic from undifferentiated
|
||||
work in building generative AI apps. Prompt targets are endpoints that receive prompts that are processed by Arch.
|
||||
For example, Arch enriches incoming prompts with metadata like knowing when a request is a follow-up or clarifying prompt
|
||||
so that you can build faster, more accurate retrieval (RAG) apps. To support agentic apps, like scheduling travel plans or
|
||||
sharing comments on a document - via prompts, Bolt uses its function calling abilities to extract critical information from
|
||||
the incoming prompt (or a set of prompts) needed by a downstream backend API or function call before calling it directly.
|
||||
|
||||
**Error Targets**: Error targets are those endpoints that receive forwarded errors from Arch when issues arise,
|
||||
such as failing to properly call a function/API, detecting violations of guardrails, or encountering other processing errors.
|
||||
These errors are communicated to the application via headers (X-Arch-[ERROR-TYPE]), allowing it to handle the errors gracefully
|
||||
and take appropriate actions.
|
||||
|
||||
**Model Serving**: Arch is a set of **two** self-contained processes that are designed to run alongside your application servers
|
||||
(or on a separate hostconnected via a network).The **model serving** process helps Arch make intelligent decisions about the
|
||||
incoming prompts. The model server is designed to call the (fast) purpose-built :ref:`LLMs <llms_in_arch>` in Arch.
|
||||
21
_sources/intro/architecture/intro/threading_model.rst
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
.. _arch_overview_threading:
|
||||
|
||||
Threading model
|
||||
===============
|
||||
|
||||
Arch builds on top of Envoy's single process with multiple threads architecture.
|
||||
|
||||
A single *primary* thread controls various sporadic coordination tasks while some number of *worker*
|
||||
threads perform filtering, and forwarding.
|
||||
|
||||
Once a connection is accepted, the connection spends the rest of its lifetime bound to a single worker
|
||||
thread. All the functionality around prompt handling from a downstream client is handled in a separate worker thread.
|
||||
This allows the majority of Arch to be largely single threaded (embarrassingly parallel) with a small amount
|
||||
of more complex code handling coordination between the worker threads.
|
||||
|
||||
Generally Arch is written to be 100% non-blocking.
|
||||
|
||||
.. tip::
|
||||
|
||||
For most workloads we recommend configuring the number of worker threads to be equal to the number of
|
||||
hardware threads on the machine.
|
||||
37
_sources/intro/architecture/listeners/listeners.rst
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
.. _arch_overview_listeners:
|
||||
|
||||
Listener
|
||||
---------
|
||||
Listener is a top level primitive in Arch, which simplifies the configuration required to bind incoming
|
||||
connections from downstream clients, and for egress connections to LLMs (hosted or API)
|
||||
|
||||
Arch builds on Envoy's Listener subsystem to streamline connection managemet for developers. Arch minimizes
|
||||
the complexity of Envoy's listener setup by using best-practices and exposing only essential settings,
|
||||
making it easier for developers to bind connections without deep knowledge of Envoy’s configuration model. This
|
||||
simplification ensures that connections are secure, reliable, and optimized for performance.
|
||||
|
||||
Downstream (Ingress)
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
Developers can configure Arch to accept connections from downstream clients. A downstream listener acts as the
|
||||
primary entry point for incoming traffic, handling initial connection setup, including network filtering, gurdrails,
|
||||
and additional network security checks. For more details on prompt security and safety,
|
||||
see :ref:`here <arch_overview_prompt_handling>`
|
||||
|
||||
Upstream (Egress)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Arch automatically configures a listener to route requests from your application to upstream LLM API providers (or hosts).
|
||||
When you start Arch, it creates a listener for egress traffic based on the presence of the ``llm_providers`` configuration
|
||||
section in the ``prompt_config.yml`` file. Arch binds itself to a local address such as ``127.0.0.1:9000/v1`` or a DNS-based
|
||||
address like ``arch.local:9000/v1`` for outgoing traffic. For more details on LLM providers, read :ref:`here <llm_providers>`
|
||||
|
||||
Configure Listener
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To configure a Downstream (Ingress) Listner, simply add the ``listener`` directive to your ``prompt_config.yml`` file:
|
||||
|
||||
.. literalinclude:: /_config/getting-started.yml
|
||||
:language: yaml
|
||||
:linenos:
|
||||
:lines: 1-18
|
||||
:emphasize-lines: 2-5
|
||||
:caption: :download:`arch-getting-started.yml </_config/getting-started.yml>`
|
||||
52
_sources/intro/architecture/listeners/llm_provider.rst
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
.. _llm_providers:
|
||||
|
||||
LLM Provider
|
||||
------------
|
||||
|
||||
``llm_provider`` is a top-level primitive in Arch, helping developers centrally define, secure, observe,
|
||||
and manage the usage of of their LLMs. Arch builds on Envoy's reliable `cluster subsystem <https://www.envoyproxy.io/docs/envoy/v1.31.2/intro/arch_overview/upstream/cluster_manager>`_
|
||||
to manage egress traffic to LLMs, which includes intelligent routing, retry and fail-over mechanisms,
|
||||
ensuring high availability and fault tolerance. This abstraction also enables developers to seamlessly switching between LLM providers or upgrade LLM versions, simplifying the integration and scaling of LLMs across
|
||||
applications.
|
||||
|
||||
|
||||
Below is an example of how you can configure ``llm_providers`` with an instance of an Arch gateway.
|
||||
|
||||
.. literalinclude:: /_config/getting-started.yml
|
||||
:language: yaml
|
||||
:linenos:
|
||||
:lines: 1-20
|
||||
:emphasize-lines: 11-18
|
||||
:caption: :download:`arch-getting-started.yml </_config/getting-started.yml>`
|
||||
|
||||
.. Note::
|
||||
When you start Arch, it creates a listener port for egress traffic based on the presence of ``llm_providers``
|
||||
configuration section in the ``prompt_config.yml`` file. Arch binds itself to a local address such as
|
||||
``127.0.0.1:9000/v1`` or a DNS-based address like ``arch.local:9000/v1`` for egress traffic.
|
||||
|
||||
Arch also offers vendor-agnostic SDKs and libraries to make LLM calls to API-based LLM providers (like OpenAI,
|
||||
Anthropic, Mistral, Cohere, etc.) and supports calls to OSS LLMs that are hosted on your infrastructure. Arch
|
||||
abstracts the complexities of integrating with different LLM providers, providing a unified interface for making
|
||||
calls, handling retries, managing rate limits, and ensuring seamless integration with cloud-based and on-premise
|
||||
LLMs. Simply configure the details of the LLMs your application will use, and Arch offers a unified interface to
|
||||
make outbound LLM calls.
|
||||
|
||||
Example: Using the Arch Python SDK
|
||||
----------------------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from arch_client import ArchClient
|
||||
|
||||
# Initialize the Arch client
|
||||
client = ArchClient(base_url="http://127.0.0.1:9000/v1")
|
||||
|
||||
# Define your LLM provider and prompt
|
||||
model_id = "openai"
|
||||
prompt = "What is the capital of France?"
|
||||
|
||||
# Send the prompt to the LLM through Arch
|
||||
response = client.completions.create(llm_provider=llm_provider, prompt=prompt)
|
||||
|
||||
# Print the response
|
||||
print("LLM Response:", response)
|
||||
56
_sources/intro/architecture/model_serving/model_serving.rst
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
.. _arch_model_serving:
|
||||
|
||||
Model Serving
|
||||
-------------
|
||||
|
||||
Arch is a set of **two** self-contained processes that are designed to run alongside your application
|
||||
servers (or on a separate host connected via a network). The first process is designated to manage low-level
|
||||
networking and HTTP related comcerns, and the other process is for **model serving**, which helps Arch make
|
||||
intelligent decisions about the incoming prompts. The model server is designed to call the purpose-built
|
||||
:ref:`LLMs <llms_in_arch>` in Arch.
|
||||
|
||||
.. image:: /_static/img/arch-system-architecture.jpg
|
||||
:align: center
|
||||
:width: 50%
|
||||
|
||||
_____________________________________________________________________________________________________________
|
||||
|
||||
Arch' is designed to be deployed in your cloud VPC, on a on-premises host, and can work on devices that don't
|
||||
have a GPU. Note, GPU devices are need for fast and cost-efficient use, so that Arch (model server, specifically)
|
||||
can process prompts quickly and forward control back to the applicaton host. There are three modes in which Arch
|
||||
can be configured to run its **model server** subsystem:
|
||||
|
||||
Local Serving (CPU - Moderate)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The following bash commands enable you to configure the model server subsystem in Arch to run local on device
|
||||
and only use CPU devices. This will be the slowest option but can be useful in dev/test scenarios where GPUs
|
||||
might not be available.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
archgw up --local -cpu
|
||||
|
||||
Local Serving (GPU- Fast)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The following bash commands enable you to configure the model server subsystem in Arch to run locally on the
|
||||
machine and utilize the GPU available for fast inference across all model use cases, including function calling
|
||||
guardails, etc.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
archgw up --local
|
||||
|
||||
Cloud Serving (GPU - Blazing Fast)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The command below instructs Arch to intelligently use GPUs locally for fast intent detection, but default to
|
||||
cloud serving for function calling and guardails scenarios to dramatically improve the speed and overall performance
|
||||
of your applications.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
archgw up
|
||||
|
||||
.. Note::
|
||||
Arch's model serving in the cloud is priced at $0.05M/token (156x cheaper than GPT-4o) with averlage latency
|
||||
of 200ms (10x faster than GPT-4o). Please refer to our :ref:`getting started guide <getting_started>` to know
|
||||
how to generate API keys for model serving
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
.. _arch_overview_prompt_handling:
|
||||
|
||||
Prompts
|
||||
-------
|
||||
|
||||
Arch's primary design point is to securely accept, process and handle prompts. To do that effectively,
|
||||
Arch relies on Envoy's HTTP `connection management <https://www.envoyproxy.io/docs/envoy/v1.31.2/intro/arch_overview/http/http_connection_management>`_,
|
||||
subsystem and its **prompt handler** subsystem engineered with purpose-built :ref:`LLMs <llms_in_arch>` to
|
||||
implement critical functionality on behalf of developers so that you can stay focused on business logic.
|
||||
|
||||
.. Note::
|
||||
Arch's **prompt handler** subsystem interacts with the **model** subsytem through Envoy's cluster manager
|
||||
system to ensure robust, resilient and fault-tolerant experience in managing incoming prompts. Read more
|
||||
about the :ref:`model subsystem <arch_model_serving>` and how the LLMs are hosted in Arch.
|
||||
|
||||
Messages
|
||||
--------
|
||||
|
||||
Arch accepts messages directly from the body of the HTTP request in a format that follows the `Hugging Face Messages API <https://huggingface.co/docs/text-generation-inference/en/messages_api>`_.
|
||||
This design allows developers to pass a list of messages, where each message is represented as a dictionary
|
||||
containing two key-value pairs:
|
||||
|
||||
- **Role**: Defines the role of the message sender, such as "user" or "assistant".
|
||||
- **Content**: Contains the actual text of the message.
|
||||
|
||||
|
||||
Prompt Guardrails
|
||||
-----------------
|
||||
|
||||
Arch is engineered with :ref:`Arch-Guard <llms_in_arch>`, an industry leading safety layer, powered by a
|
||||
compact and high-performimg LLM that monitors incoming prompts to detect and reject jailbreak attempts -
|
||||
ensuring that unauthorized or harmful behaviors are intercepted early in the process.
|
||||
|
||||
To add jailbreak guardrails, see example below:
|
||||
|
||||
.. literalinclude:: /_config/getting-started.yml
|
||||
:language: yaml
|
||||
:linenos:
|
||||
:emphasize-lines: 24-27
|
||||
:caption: :download:`arch-getting-started.yml </_config/getting-started.yml>`
|
||||
|
||||
.. Note::
|
||||
As a roadmap item, Arch will expose the ability for developers to define custom guardrails via Arch-Guard-v2,
|
||||
and add support for additional safety checks defined by developers and hazardous categories like, violent crimes, privacy, hate,
|
||||
etc. To offer feedback on our roadmap, please visit our `github page <https://github.com/orgs/katanemo/projects/1>`_
|
||||
|
||||
|
||||
Prompt Targets
|
||||
--------------
|
||||
|
||||
Once a prompt passes any configured guardrail checks, Arch processes the contents of the incoming conversation
|
||||
and identifies where to forwad the conversation to via its essential ``prompt_targets`` primitve. Prompt targets
|
||||
are endpoints that receive prompts that are processed by Arch. For example, Arch enriches incoming prompts with
|
||||
metadata like knowing when a user's intent has changed so that you can build faster, more accurate RAG apps.
|
||||
|
||||
Configuring ``prompt_targets`` is simple. See example below:
|
||||
|
||||
.. literalinclude:: /_config/getting-started.yml
|
||||
:language: yaml
|
||||
:linenos:
|
||||
:emphasize-lines: 29-38
|
||||
:caption: :download:`arch-getting-started.yml </_config/getting-started.yml>`
|
||||
|
||||
|
||||
Intent Detection and Prompt Matching:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Arch uses fast Natural Language Inference (NLI) and embedding approaches to first detect the intent of each
|
||||
incoming prompt. This intent detection phase analyzes the prompt's content and matches it against predefined
|
||||
prompt targets, ensuring that each prompt is forwarded to the most appropriate endpoint. Arch’s intent
|
||||
detection framework considers both the name and description of each prompt target, and uses a composite matching
|
||||
score between an NLI and cosine similarity to enchance accuracy in forwarding decisions.
|
||||
|
||||
- **Embeddings**: By embedding the prompt and comparing it to known target vectors, Arch effectively identifies
|
||||
the closest match, ensuring that the prompt is handled by the correct downstream service.
|
||||
|
||||
- **NLI**: NLI techniques further refine the matching process by evaluating the semantic alignment between the
|
||||
prompt and potential targets.
|
||||
|
||||
Agentic Apps via Prompt Targets
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To support agentic apps, like scheduling travel plans or sharing comments on a document - via prompts, Arch uses
|
||||
its function calling abilities to extract critical information from the incoming prompt (or a set of prompts)
|
||||
needed by a downstream backend API or function call before calling it directly. For more details on how you can
|
||||
build agentic applications using Arch, see our full guide :ref:`here <arch_function_calling_agentic_guide>`:
|
||||
|
||||
.. Note::
|
||||
Arch :ref:`Arch-FC <llms_in_arch>` is the dedicated agentic model engineered in Arch to extract information from
|
||||
a (set of) prompts and executes necessary backend API calls. This allows for efficient handling of agentic tasks,
|
||||
such as scheduling data retrieval, by dynamically interacting with backend services. Arch-FC is a flagship 1.3
|
||||
billion parameter model that matches performance with frontier models like Claude Sonnet 3.5 ang GPT-4, while
|
||||
being 100x cheaper ($0.05M/token hosted) and 10x faster (p50 latencies of 200ms).
|
||||
|
||||
Prompting LLMs
|
||||
--------------
|
||||
Arch is a single piece of software that is designed to manage both ingress and egress prompt traffic, drawing its
|
||||
distributed proxy nature from the robust `Envoy <https://envoyproxy.io>`_. This makes it extremely efficient and capable
|
||||
of handling upstream connections to LLMs. If your application is originating code to an API-based LLM, simply use
|
||||
Arch's Python or JavaScript client SDK to send traffic to the desired LLM of choice. By sending traffic through Arch,
|
||||
you can propagate traces, manage and monitor traffic, apply rate limits, and utilize a large set of traffic management
|
||||
capabilities in a central place.
|
||||
|
||||
.. Attention::
|
||||
When you start Arch, it automatically creates a listener port for egress calls to upstream LLMs. This is based on the
|
||||
``llm_providers`` configuration section in the ``prompt_config.yml`` file. Arch binds itself to a local address such as
|
||||
127.0.0.1:9000/v1 or a DNS-based address like arch.local:9000/v1 for outgoing traffic.
|
||||
|
||||
Example: Using the Arch Python SDK
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from arch_client import ArchClient
|
||||
|
||||
# Initialize the Arch client
|
||||
client = ArchClient(base_url="http://127.0.0.1:9000/v1")
|
||||
|
||||
# Define your LLM provider and prompt
|
||||
model_id = "openai"
|
||||
prompt = "What is the capital of France?"
|
||||
|
||||
# Send the prompt to the LLM through Arch
|
||||
response = client.completions.create(llm_provider=llm_provider, prompt=prompt)
|
||||
|
||||
# Print the response
|
||||
print("LLM Response:", response)
|
||||
|
||||
Example: Using OpenAI Client with Arch as an Egress Gateway
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import openai
|
||||
|
||||
# Set the OpenAI API base URL to the Arch gateway endpoint
|
||||
openai.api_base = "http://127.0.0.1:9000/v1"
|
||||
|
||||
# No need to set openai.api_key since it's configured in Arch's gateway
|
||||
|
||||
# Use the OpenAI client as usual
|
||||
response = openai.Completion.create(
|
||||
model="text-davinci-003",
|
||||
prompt="What is the capital of France?"
|
||||
)
|
||||
|
||||
print("OpenAI Response:", response.choices[0].text.strip())
|
||||
|
||||
In these examples:
|
||||
|
||||
The ArchClient is used to send traffic directly through the Arch egress proxy to the LLM of your choice, such as OpenAI.
|
||||
The OpenAI client is configured to route traffic via Arch by setting the proxy to 127.0.0.1:9000, assuming Arch is
|
||||
running locally and bound to that address and port.
|
||||
|
||||
This setup allows you to take advantage of Arch's advanced traffic management features while interacting with LLM APIs like OpenAI.
|
||||
15
_sources/intro/getting_help.rst
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
.. _getting_help:
|
||||
|
||||
Getting help
|
||||
============
|
||||
|
||||
We are very interested in building a community around Arch. Please reach out to us if you are
|
||||
interested in using it and need help or want to contribute.
|
||||
|
||||
Please see `contact info <https://github.com/katanemo/arch#contact>`_.
|
||||
|
||||
Reporting security vulnerabilities
|
||||
----------------------------------
|
||||
|
||||
Please see `security contact info
|
||||
<https://github.com/katanemo/arch#reporting-security-vulnerabilities>`_.
|
||||
12
_sources/intro/intro.rst
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
.. _intro:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
what_is_arch
|
||||
architecture/architecture
|
||||
life_of_a_request
|
||||
getting_help
|
||||
176
_sources/intro/life_of_a_request.rst
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
.. _life_of_a_request:
|
||||
|
||||
Life of a Request
|
||||
=================
|
||||
|
||||
Below we describe the events in the life of a request passing through an Arch gateway instance. We first
|
||||
describe how Arch fits into the request path and then the internal events that take place following
|
||||
the arrival of a request at Arch from downtream clients. We follow the request until the corresponding
|
||||
dispatch upstream and the response path.
|
||||
|
||||
.. image:: /_static/img/network-topology-ingress-egress.jpg
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
|
||||
We recommend that you get familiar with some of the :ref:`terminology <arch_terminology>` used in Arch
|
||||
before reading this section.
|
||||
|
||||
Network topology
|
||||
----------------
|
||||
|
||||
How a request flows through the components in a network (including Arch) depends on the network’s topology.
|
||||
Arch can be used in a wide variety of networking topologies. We focus on the inner operation of Arch below,
|
||||
but briefly we address how Arch relates to the rest of the network in this section.
|
||||
|
||||
- **Downstream(Ingress)** listeners take requests from upstream clients like a web UI or clients that forward
|
||||
prompts to you local application responses from the application flow back through Arch to the downstream.
|
||||
|
||||
- **Upstream(Egress)** listeners take requests from the application and forward them to LLMs.
|
||||
|
||||
.. image:: /_static/img/network-topology-ingress-egress.jpg
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
In practice, Arch can be deployed on the edge and as an internal load balancer between AI agents. A request path may
|
||||
traverse multiple Arch gateways:
|
||||
|
||||
.. image:: /_static/img/network-topology-agent.jpg
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
|
||||
High level architecture
|
||||
-----------------------
|
||||
Arch is a set of **two** self-contained processes that are designed to run alongside your application servers
|
||||
(or on a separate server connected to your application servers via a network). The first process is designated
|
||||
to manage HTTP-level networking and connection management concerns (protocol management, request id generation,
|
||||
header sanitization, etc.), and the other process is for **model serving**, which helps Arch make intelligent
|
||||
decisions about the incoming prompts. The model server hosts the purpose-built :ref:`LLMs <llms_in_arch>` to
|
||||
manage several critical, but undifferentiated, prompt related tasks on behalf of developers.
|
||||
|
||||
|
||||
The request processing path in Arch has three main parts:
|
||||
|
||||
* :ref:`Listener subsystem <arch_overview_listeners>` which handles **downstream** and **upstream** request
|
||||
processing. It is responsible for managing the downstream (ingress) and the upstream (egress) request
|
||||
lifecycle. The downstream and upstream HTTP/2 codec lives here.
|
||||
* :ref:`Prompt handler subsystem <arch_overview_prompt_handling>` which is responsible for selecting and
|
||||
forwarding prompts ``prompt_targets`` and establishes the lifecycle of any **upstream** connection to a
|
||||
hosted endpoint that implements domain-specific business logic for incoming promots. This is where knowledge
|
||||
of targets and endpoint health, load balancing and connection pooling exists.
|
||||
* :ref:`Model serving subsystem <arch_model_serving>` which helps Arch make intelligent decisions about the
|
||||
incoming prompts. The model server is designed to call the purpose-built :ref:`LLMs <llms_in_arch>` in Arch.
|
||||
|
||||
The three subsystems are bridged with either the HTTP router filter, and the cluster manager subsystems of Envoy.
|
||||
|
||||
Also, Arch utilizes `Envoy event-based thread model <https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310>`_.
|
||||
A main thread is responsible forthe server lifecycle, configuration processing, stats, etc. and some number of
|
||||
:ref:`worker threads <arch_overview_threading>` process requests. All threads operate around an event loop (`libevent <https://libevent.org/>`_)
|
||||
and any given downstream TCP connection will be handled by exactly one worker thread for its lifetime. Each worker
|
||||
thread maintains its own pool of TCP connections to upstream endpoints.
|
||||
|
||||
Worker threads rarely share state and operate in a trivially parallel fashion. This threading model
|
||||
enables scaling to very high core count CPUs.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Today, only support a static bootstrap configuration file for simplicity today:
|
||||
|
||||
.. literalinclude:: /_config/getting-started.yml
|
||||
:language: yaml
|
||||
|
||||
|
||||
Request Flow (Ingress)
|
||||
----------------------
|
||||
|
||||
Overview
|
||||
^^^^^^^^
|
||||
A brief outline of the life cycle of a request and response using the example configuration above:
|
||||
|
||||
1. **TCP Connection Establishment**:
|
||||
A TCP connection from downstream is accepted by an Arch listener running on a worker thread.
|
||||
The listener filter chain provides SNI and other pre-TLS information. The transport socket, typically TLS,
|
||||
decrypts incoming data for processing.
|
||||
|
||||
2. **Prompt Guardrails Check**:
|
||||
Arch first checks the incoming prompts for guardrails such as jailbreak attempts. This ensures
|
||||
that harmful or unwanted behaviors are detected early in the request processing pipeline.
|
||||
|
||||
3. **Intent Matching**:
|
||||
The decrypted data stream is deframed by the HTTP/2 codec in Arch's HTTP connection manager. Arch performs
|
||||
intent matching via is **prompt-handler** subsystem using the name and description of the defined prompt targets,
|
||||
determining which endpoint should handle the prompt.
|
||||
|
||||
4. **Parameter Gathering with Arch-FC**:
|
||||
If a prompt target requires specific parameters, Arch engages Arch-FC to extract the necessary details
|
||||
from the incoming prompt(s). This process gathers the critical information needed for downstream API calls.
|
||||
|
||||
5. **API Call Execution**:
|
||||
Arch routes the prompt to the appropriate backend API or function call. If an endpoint cluster is identified,
|
||||
load balancing is performed, circuit breakers are checked, and the request is proxied to the upstream endpoint.
|
||||
|
||||
6. **Default Summarization by Upstream LLM**:
|
||||
By default, if no specific endpoint processing is needed, the prompt is sent to an upstream LLM for summarization.
|
||||
This ensures that responses are concise and relevant, enhancing user experience in RAG (Retrieval-Augmented Generation)
|
||||
and agentic applications.
|
||||
|
||||
7. **Error Handling and Forwarding**:
|
||||
Errors encountered during processing, such as failed function calls or guardrail detections, are forwarded to
|
||||
designated error targets. Error details are communicated through specific headers to the application:
|
||||
|
||||
- ``X-Function-Error-Code``: Code indicating the type of function call error.
|
||||
- ``X-Prompt-Guard-Error-Code``: Code specifying violations detected by prompt guardrails.
|
||||
- Additional headers carry messages and timestamps to aid in debugging and logging.
|
||||
|
||||
8. **Response Handling**:
|
||||
The upstream endpoint’s TLS transport socket encrypts the response, which is then proxied back downstream.
|
||||
Responses pass through HTTP filters in reverse order, ensuring any necessary processing or modification before final delivery.
|
||||
|
||||
|
||||
Request Flow (Egress)
|
||||
---------------------
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
A brief outline of the life cycle of a request and response in the context of egress traffic from an application
|
||||
to Large Language Models (LLMs) via Arch:
|
||||
|
||||
1. **HTTP Connection Establishment to LLM**:
|
||||
Arch initiates an HTTP connection to the upstream LLM service. This connection is handled by Arch’s egress listener
|
||||
running on a worker thread. The connection typically uses a secure transport protocol such as HTTPS, ensuring the
|
||||
prompt data is encrypted before being sent to the LLM service.
|
||||
|
||||
2. **Rate Limiting**:
|
||||
Before sending the request to the LLM, Arch applies rate-limiting policies to ensure that the upstream LLM service
|
||||
is not overwhelmed by excessive traffic. Rate limits are enforced per client or service, ensuring fair usage and
|
||||
preventing accidental or malicious overload. If the rate limit is exceeded, Arch may return an appropriate HTTP
|
||||
error (e.g., 429 Too Many Requests) without sending the prompt to the LLM.
|
||||
|
||||
3. **Load Balancing to (hosted) LLM Endpoints**:
|
||||
After passing the rate-limiting checks, Arch routes the prompt to the appropriate LLM endpoint.
|
||||
If multiple LLM providers instances are available, load balancing is performed to distribute traffic evenly
|
||||
across the instances. Arch checks the health of the LLM endpoints using circuit breakers and health checks,
|
||||
ensuring that the prompt is only routed to a healthy, responsive instance.
|
||||
|
||||
4. **Response Reception and Forwarding**:
|
||||
Once the LLM processes the prompt, Arch receives the response from the LLM service. The response is typically a
|
||||
generated text, completion, or summarization. Upon reception, Arch decrypts (if necessary) and handles the response,
|
||||
passing it through any egress processing pipeline defined by the application, such as logging or additional response filtering.
|
||||
|
||||
|
||||
Post-request processing
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Once a request completes, the stream is destroyed. The following also takes places:
|
||||
|
||||
* The post-request :ref:`monitoring <monitoring>` are updated (e.g. timing, active requests, upgrades, health checks).
|
||||
Some statistics are updated earlier however, during request processing. Stats are batchedand written by the main
|
||||
thread periodically.
|
||||
* :ref:`Access logs <arch_access_logging>` are written to the access log
|
||||
* :ref:`Trace <arch_overview_tracing>` spans are finalized. If our example request was traced, a
|
||||
trace span, describing the duration and details of the request would be created by the HCM when
|
||||
processing request headers and then finalized by the HCM during post-request processing.
|
||||
90
_sources/intro/what_is_arch.rst
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
What is Arch
|
||||
============
|
||||
|
||||
Arch is an intelligent `(Layer 7) <https://www.cloudflare.com/learning/ddos/what-is-layer-7/>`_ gateway
|
||||
designed for generative AI apps, AI agents, and Co-pilots that work with prompts. Engineered with purpose-built
|
||||
:ref:`LLMs <llms_in_arch>`, Arch handles all the critical but undifferentiated tasks related to the handling and
|
||||
processing of prompts, including detecting and rejecting `jailbreak <https://github.com/verazuo/jailbreak_llms>`_
|
||||
attempts, intelligently calling “backend” APIs to fulfill the user's request represented in a prompt, routing to
|
||||
and offering disaster recovery between upstream LLMs, and managing the observability of prompts and LLM interactions
|
||||
in a centralized way.
|
||||
|
||||
.. image:: /_static/img/arch-logo.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
**The project was born out of the belief that:**
|
||||
|
||||
*Prompts are nuanced and opaque user requests, which require the same capabilities as traditional HTTP requests
|
||||
including secure handling, intelligent routing, robust observability, and integration with backend (API)
|
||||
systems for personalization - all outside business logic.*
|
||||
|
||||
|
||||
In practice, achieving the above goal is incredibly difficult. Arch attempts to do so by providing the
|
||||
following high level features:
|
||||
|
||||
_____________________________________________________________________________________________________________
|
||||
|
||||
**Out-of-process architecture, built on** `Envoy <http://envoyproxy.io/>`_: Arch is takes a dependency on
|
||||
Envoy and is a self-contained process that is designed to run alongside your application servers. Arch uses
|
||||
Envoy's HTTP connection management subsystem, HTTP L7 filtering and telemetry capabilities to extend the
|
||||
functionality exclusively for prompts and LLMs. This gives Arch several advantages:
|
||||
|
||||
* Arch builds on Envoy's proven success. Envoy is used at masssive sacle by the leading technology companies of
|
||||
our time including `AirBnB <https://www.airbnb.com>`_, `Dropbox <https://www.dropbox.com>`_,
|
||||
`Google <https://www.google.com>`_, `Reddit <https://www.reddit.com>`_, `Stripe <https://www.stripe.com>`_,
|
||||
etc. Its battle tested and scales linearly with usage and enables developers to focus on what really matters:
|
||||
application features and business logic.
|
||||
|
||||
* Arch works with any application language. A single Arch deployment can act as gateway for AI applications
|
||||
written in Python, Java, C++, Go, Php, etc.
|
||||
|
||||
* Arch can be deployed and upgraded quickly across your infrastructure transparently without the horrid pain
|
||||
of deploying library upgrades in your applications.
|
||||
|
||||
**Engineered with Fast LLMs:** Arch is engineered with specialized (sub-billion) LLMs that are desgined for
|
||||
fast, cost-effective and acurrate handling of prompts. These :ref:`LLMs <llms_in_arch>` are designed to be
|
||||
best-in-class for critcal prompt-related tasks like:
|
||||
|
||||
* **Function/API Calling:** Arch helps you easily personalize your applications by enabling calls to
|
||||
application-specific (API) operations via user prompts. This involves any predefined functions or APIs
|
||||
you want to expose to users to perform tasks, gather information, or manipulate data. With function calling,
|
||||
you have flexibility to support "agentic" experiences tailored to specific use cases - from updating insurance
|
||||
claims to creating ad campaigns - via prompts. Arch analyzes prompts, extracts critical information from
|
||||
prompts, engages in lightweight conversation to gather any missing parameters and makes API calls so that you can
|
||||
focus on writing business logic. For more details, read :ref:`prompt processing <arch_overview_prompt_handling>`.
|
||||
|
||||
* **Prompt Guardrails:** Arch helps you improve the safety of your application by applying prompt guardrails in
|
||||
a centralized way for better governance hygiene. With prompt guardrails you can prevent `jailbreak <https://github.com/verazuo/jailbreak_llms>`_
|
||||
attempts or toxicity present in user's prompts without having to write a single line of code. To learn more
|
||||
about how to configure guardrails available in Arch, read :ref:`prompt processing <arch_overview_prompt_handling>`.
|
||||
|
||||
* **Intent-Drift Detection:** Developers struggle to handle `follow-up <https://www.reddit.com/r/ChatGPTPromptGenius/comments/17dzmpy/how_to_use_rag_with_conversation_history_for/?>`_,
|
||||
or `clarifying <https://www.reddit.com/r/LocalLLaMA/comments/18mqwg6/best_practice_for_rag_with_followup_chat/>`_
|
||||
questions. Specifically, when users ask for modifications or additions to previous responses their AI applications
|
||||
often generate entirely new responses instead of adjusting the previous ones. Arch offers intent-drift detection as a
|
||||
feature so that developers know when the user has shifted away from the previous intent so that they can improve
|
||||
their retrieval, lower overall token cost and dramatically improve the speed and accuracy of their responses back
|
||||
to users.
|
||||
|
||||
**Traffic Management:** Arch offers several capabilities for LLM calls originating from your applications, including a
|
||||
vendor-agnostic SDK to make LLM calls, smart retries on errors from upstream LLMs, and automatic cutover to other LLMs
|
||||
configured in Arch for continuous availability and disaster recovery scenarios. Arch extends Envoy's `cluster subsystem
|
||||
<https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/cluster_manager>`_ to manage upstream connections
|
||||
to LLMs so that you can build resilient AI applications.
|
||||
|
||||
**Front/edge Gateway:** There is substantial benefit in using the same software at the edge (observability,
|
||||
traffic shaping alogirithms, applying guardrails, etc.) as for outbound LLM inference use cases. Arch has the feature set
|
||||
that makes it exceptionally well suited as an edge gateway for AI applications. This includes TLS termination, rate limiting,
|
||||
and prompt-based routing.
|
||||
|
||||
**Best-In Class Monitoring:** Arch offers several monitoring metrics that help you understand three
|
||||
critical aspects of your application: latency, token usage, and error rates by an upstream LLM provider. Latency
|
||||
measures the speed at which your application is responding to users, which includes metrics like time to first
|
||||
token (TFT), time per output token (TOT) metrics, and the total latency as perceived by users.
|
||||
|
||||
**End-to-End Tracing:** Arch propagates trace context using the W3C Trace Context standard, specifically through
|
||||
the ``traceparent`` header. This allows each component in the system to record its part of the request flow,
|
||||
enabling **end-to-end tracing** across the entire application. By using OpenTelemetry, Arch ensures that
|
||||
developers can capture this trace data consistently and in a format compatible with various observability tools.
|
||||
For more details, read :ref:`tracing <arch_overview_tracing>`.
|
||||
159
_sources/llms/llms.rst
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
.. _llms_in_arch:
|
||||
|
||||
LLMs
|
||||
====
|
||||
|
||||
Arch utilizes purpose-built, industry leading, LLMs to handle the crufty and undifferentiated work around
|
||||
accepting, handling and processing prompts. The following sections talk about some of the core models that
|
||||
are built-in Arch.
|
||||
|
||||
Arch-Guard-v1
|
||||
-------------
|
||||
LLM-powered applications are susceptible to prompt attacks, which are prompts intentionally designed to
|
||||
subvert the developer’s intended behavior of the LLM. Arch-Guard-v1 is a classifier model trained on a large
|
||||
corpus of attacks, capable of detecting explicitly malicious prompts (and toxicity).
|
||||
|
||||
The model is useful as a starting point for identifying and guardrailing against the most risky realistic
|
||||
inputs to LLM-powered applications. Our goal in embedding Arch-Guard in the Arch gateway is to enable developers
|
||||
to focus on their business logic and factor out security and safety outside application logic. Wth Arch-Guard-v1
|
||||
developers can take to significantly reduce prompt attack risk while maintaining control over the user experience.
|
||||
|
||||
Below is our test results of the strength of our model as compared to Prompt-Guard from `Meta LLama <https://huggingface.co/meta-llama/Prompt-Guard-86M>`_.
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 15 15 10 15 15
|
||||
|
||||
* - Dataset
|
||||
- Jailbreak (Yes/No)
|
||||
- Samples
|
||||
- Prompt-Guard Accuracy
|
||||
- Arch-Guard Accuracy
|
||||
* - casual_conversation
|
||||
- 0
|
||||
- 3725
|
||||
- 1.00
|
||||
- 1.00
|
||||
* - commonqa
|
||||
- 0
|
||||
- 9741
|
||||
- 1.00
|
||||
- 1.00
|
||||
* - financeqa
|
||||
- 0
|
||||
- 1585
|
||||
- 1.00
|
||||
- 1.00
|
||||
* - instruction
|
||||
- 0
|
||||
- 5000
|
||||
- 1.00
|
||||
- 1.00
|
||||
* - jailbreak_behavior_benign
|
||||
- 0
|
||||
- 100
|
||||
- 0.10
|
||||
- 0.20
|
||||
* - jailbreak_behavior_harmful
|
||||
- 1
|
||||
- 100
|
||||
- 0.30
|
||||
- 0.52
|
||||
* - jailbreak_judge
|
||||
- 1
|
||||
- 300
|
||||
- 0.33
|
||||
- 0.49
|
||||
* - jailbreak_prompts
|
||||
- 1
|
||||
- 79
|
||||
- 0.99
|
||||
- 1.00
|
||||
* - jailbreak_tweet
|
||||
- 1
|
||||
- 1282
|
||||
- 0.16
|
||||
- 0.35
|
||||
* - jailbreak_v
|
||||
- 1
|
||||
- 20000
|
||||
- 0.90
|
||||
- 0.93
|
||||
* - jailbreak_vigil
|
||||
- 1
|
||||
- 104
|
||||
- 1.00
|
||||
- 1.00
|
||||
* - mental_health
|
||||
- 0
|
||||
- 3512
|
||||
- 1.00
|
||||
- 1.00
|
||||
* - telecom
|
||||
- 0
|
||||
- 4000
|
||||
- 1.00
|
||||
- 1.00
|
||||
* - truthqa
|
||||
- 0
|
||||
- 817
|
||||
- 1.00
|
||||
- 0.98
|
||||
* - weather
|
||||
- 0
|
||||
- 3121
|
||||
- 1.00
|
||||
- 1.00
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 15 20
|
||||
|
||||
* - Statistics
|
||||
- Overall performance
|
||||
* - Overall Accuracy
|
||||
- 0.93568 (Prompt-Guard), 0.95267 (Arch-Guard)
|
||||
* - True positives rate (TPR)
|
||||
- 0.8468 (Prompt-Guard), 0.8887 (Arch-Guard)
|
||||
* - True negative rate (TNR)
|
||||
- 0.9972 (Prompt-Guard), 0.9970 (Arch-Guard)
|
||||
* - False positive rate (FPR)
|
||||
- 0.0028 (Prompt-Guard), 0.0030 (Arch-Guard)
|
||||
* - False negative rate (FNR)
|
||||
- 0.1532 (Prompt-Guard), 0.1113 (Arch-Guard)
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 15 20
|
||||
|
||||
* - Metrics
|
||||
- Values
|
||||
* - AUC
|
||||
- 0.857 (Prompt-Guard), 0.880 (Arch-Guard)
|
||||
* - Precision
|
||||
- 0.715 (Prompt-Guard), 0.761 (Arch-Guard)
|
||||
* - Recall
|
||||
- 0.999 (Prompt-Guard), 0.999 (Arch-Guard)
|
||||
|
||||
|
||||
|
||||
Arch-FC
|
||||
-------
|
||||
Arch-FC is a lean, powerful and cost-effective agentic model designed for function calling scenarios.
|
||||
You can run Arch-FC locally, or use the cloud-hosted version for as little as $0.05/M token (100x cheaper
|
||||
than GPT-4o), with a p50 latency of 200ms (5x faster than GPT-4o), while meeting frontier model performance.
|
||||
|
||||
.. Note::
|
||||
Function calling helps you personalize the GenAI experience by calling application-specific operations via
|
||||
prompts. This involves any predefined functions or APIs you want to expose to perform tasks, gather
|
||||
information, or manipulate data - via prompts.
|
||||
|
||||
You can get started with function calling simply by configuring a prompt target with a name, description
|
||||
and set of parameters needed by a specific backend function or a hosted API. The name, and description helps
|
||||
Arch-FC match a user prompt to a function or API that can process it.
|
||||
|
||||
By using Arch-FC, Arch enables you to easily build agentic workflows tailored to domain-specific use cases -
|
||||
from updating insurance claims to creating ad campaigns. Arch-FC analyzes prompts, extracts critical information
|
||||
from prompts, engages in lightweight conversations with the user to gather any missing parameters need before
|
||||
handling control back to Arch to make the API call to your hosted backend. Arch-FC handles the muck of information
|
||||
extraction so that you can focus on the business logic of your application.
|
||||
23
_sources/observability/access_logs.rst
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
.. _arch_access_logging:
|
||||
|
||||
Access Logging
|
||||
==============
|
||||
|
||||
Access logging in Arch refers to the logging of detailed information about each request and response that flows through Arch.
|
||||
It provides visibility into the traffic passing through Arch, which is crucial for monitoring, debugging, and analyzing the
|
||||
behavior of AI applications and their interactions.
|
||||
|
||||
Key Features of Access Logging in Arch:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
* **Per-Request Logging**:
|
||||
Each request that passes through Arch is logged. This includes important metadata such as HTTP method,
|
||||
path, response status code, request duration, upstream host, and more.
|
||||
* **Integration with Monitoring Tools**:
|
||||
Access logs can be exported to centralized logging systems (e.g., ELK stack or Fluentd) or used to feed monitoring and alerting systems.
|
||||
* **Structured Logging**: where each request is logged as a object, making it easier to parse and analyze using tools like Elasticsearch and Kibana.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
[2024-09-27T14:52:01.123Z] "ARCH REQUEST" GET /path/to/resource HTTP/1.1 200 512 1024 56 upstream_service.com D
|
||||
X-Arch-Upstream-Service-Time: 25
|
||||
X-Arch-Attempt-Count: 1
|
||||
11
_sources/observability/observability.rst
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
.. _observability:
|
||||
|
||||
Observability
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
tracing
|
||||
stats
|
||||
access_logs
|
||||
9
_sources/observability/stats.rst
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
.. _monitoring:
|
||||
|
||||
Monitoring
|
||||
==========
|
||||
|
||||
Arch offers several monitoring metrics that help you understand three critical aspects of your application:
|
||||
latency, token usage, and error rates by an upstream LLM provider. Latency measures the speed at which your
|
||||
application is responding to users, which includes metrics like time to first token (TFT), time per output
|
||||
token (TOT) metrics, and the total latency as perceived by users.
|
||||
313
_sources/observability/tracing.rst
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
.. _arch_overview_tracing:
|
||||
|
||||
Tracing
|
||||
=======
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
`OpenTelemetry <https://opentelemetry.io/>`_ is an open-source observability framework providing APIs
|
||||
and instrumentation for generating, collecting, processing, and exporting telemetry data, such as traces,
|
||||
metrics, and logs. Its flexible design supports a wide range of backends and seamlessly integrates with
|
||||
modern application tools. A key feature of OpenTelemetry is its commitment to standards like the
|
||||
`W3C Trace Context <https://www.w3.org/TR/trace-context/>`_
|
||||
|
||||
**Tracing** is a critical tool that allows developers to visualize and understand the flow of
|
||||
requests in an AI application. With tracing, you can capture a detailed view of how requests propagate
|
||||
through various services and components, which is crucial for **debugging**, **performance optimization**,
|
||||
and understanding complex AI agent architectures like Co-pilots.
|
||||
|
||||
**Arch** propagates trace context using the W3C Trace Context standard, specifically through the
|
||||
``traceparent`` header. This allows each component in the system to record its part of the request
|
||||
flow, enabling **end-to-end tracing** across the entire application. By using OpenTelemetry, Arch ensures
|
||||
that developers can capture this trace data consistently and in a format compatible with various observability
|
||||
tools.
|
||||
______________________________________________________________________________________________
|
||||
|
||||
Benefits of using ``traceparent`` headers
|
||||
-----------------------------------------
|
||||
|
||||
- **Standardization**: The W3C Trace Context standard ensures compatibility across ecosystem tools, allowing
|
||||
traces to be propagated uniformly through different layers of the system.
|
||||
- **Ease of Integration**: OpenTelemetry's design allows developers to easily integrate tracing with minimal
|
||||
changes to their codebase, enabling quick adoption of end-to-end observability.
|
||||
- **Interoperability**: Works seamlessly with popular tracing tools like AWS X-Ray, Datadog, Jaeger, and many others,
|
||||
making it easy to visualize traces in the tools you're already usi
|
||||
|
||||
How to initiate a trace
|
||||
-----------------------
|
||||
|
||||
1. **Enable Tracing Configuration**: Simply add the ``tracing: 100`` flag to in the :ref:`listener <arch_overview_listeners>` config
|
||||
|
||||
2. **Trace Context Propagation**: Arch automatically propagates the ``traceparent`` header. When a request is received, Arch will:
|
||||
|
||||
- Generate a new ``traceparent`` header if one is not present.
|
||||
- Extract the trace context from the ``traceparent`` header if it exists.
|
||||
- Start a new span representing its processing of the request.
|
||||
- Forward the ``traceparent`` header to downstream services.
|
||||
|
||||
3. **Sampling Policy**: The 100 in ``tracing: 100`` means that all the requests as sampled for tracing.
|
||||
You can adjust this value from 0-100.
|
||||
|
||||
|
||||
Trace Propagation
|
||||
-----------------
|
||||
|
||||
Arch uses the W3C Trace Context standard for trace propagation, which relies on the ``traceparent`` header.
|
||||
This header carries tracing information in a standardized format, enabling interoperability between different
|
||||
tracing systems.
|
||||
|
||||
Header Format
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The ``traceparent`` header has the following format::
|
||||
|
||||
traceparent: {version}-{trace-id}-{parent-id}-{trace-flags}
|
||||
|
||||
- {version}: The version of the Trace Context specification (e.g., ``00``).
|
||||
- {trace-id}: A 16-byte (32-character hexadecimal) unique identifier for the trace.
|
||||
- {parent-id}: An 8-byte (16-character hexadecimal) identifier for the parent span.
|
||||
- {trace-flags}: Flags indicating trace options (e.g., sampling).
|
||||
|
||||
Instrumentation
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
To integrate AI tracing, your application needs to follow a few simple steps. The steps
|
||||
below are very common practice, and not unique to Arch, when you reading tracing headers and export
|
||||
`spans <https://docs.lightstep.com/docs/understand-distributed-tracing>`_ for distributed tracing.
|
||||
|
||||
- Read the ``traceparent`` header from incoming requests.
|
||||
- Start new spans as children of the extracted context.
|
||||
- Include the ``traceparent`` header in outbound requests to propagate trace context.
|
||||
- Send tracing data to a collector or tracing backend to export spans
|
||||
|
||||
Example with OpenTelemetry in Python
|
||||
************************************
|
||||
|
||||
Install OpenTelemetry packages:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp
|
||||
pip install opentelemetry-instrumentation-requests
|
||||
|
||||
Set up the tracer and exporter:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from opentelemetry import trace
|
||||
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
||||
from opentelemetry.instrumentation.requests import RequestsInstrumentor
|
||||
from opentelemetry.sdk.resources import Resource
|
||||
from opentelemetry.sdk.trace import TracerProvider
|
||||
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
||||
|
||||
# Define the service name
|
||||
resource = Resource(attributes={
|
||||
"service.name": "customer-support-agent"
|
||||
})
|
||||
|
||||
# Set up the tracer provider and exporter
|
||||
tracer_provider = TracerProvider(resource=resource)
|
||||
otlp_exporter = OTLPSpanExporter(endpoint="otel-collector:4317", insecure=True)
|
||||
span_processor = BatchSpanProcessor(otlp_exporter)
|
||||
tracer_provider.add_span_processor(span_processor)
|
||||
trace.set_tracer_provider(tracer_provider)
|
||||
|
||||
# Instrument HTTP requests
|
||||
RequestsInstrumentor().instrument()
|
||||
|
||||
Handle incoming requests:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from opentelemetry import trace
|
||||
from opentelemetry.propagate import extract, inject
|
||||
import requests
|
||||
|
||||
def handle_request(request):
|
||||
# Extract the trace context
|
||||
context = extract(request.headers)
|
||||
tracer = trace.get_tracer(__name__)
|
||||
|
||||
with tracer.start_as_current_span("process_customer_request", context=context):
|
||||
# Example of processing a customer request
|
||||
print("Processing customer request...")
|
||||
|
||||
# Prepare headers for outgoing request to payment service
|
||||
headers = {}
|
||||
inject(headers)
|
||||
|
||||
# Make outgoing request to external service (e.g., payment gateway)
|
||||
response = requests.get("http://payment-service/api", headers=headers)
|
||||
|
||||
print(f"Payment service response: {response.content}")
|
||||
|
||||
|
||||
AI Agent Tracing Visualization Example
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The following is an example of tracing for an AI-powered customer support system.
|
||||
A customer interacts with AI agents, which forward their requests through different
|
||||
specialized services and external systems.
|
||||
|
||||
::
|
||||
|
||||
+--------------------------+
|
||||
| Customer Interaction |
|
||||
+--------------------------+
|
||||
|
|
||||
v
|
||||
+--------------------------+ +--------------------------+
|
||||
| Agent 1 (Main - Arch) | ----> | External Payment Service |
|
||||
+--------------------------+ +--------------------------+
|
||||
| |
|
||||
v v
|
||||
+--------------------------+ +--------------------------+
|
||||
| Agent 2 (Support - Arch)| ----> | Internal Tech Support |
|
||||
+--------------------------+ +--------------------------+
|
||||
| |
|
||||
v v
|
||||
+--------------------------+ +--------------------------+
|
||||
| Agent 3 (Orders- Arch) | ----> | Inventory Management |
|
||||
+--------------------------+ +--------------------------+
|
||||
|
||||
Trace Breakdown:
|
||||
****************
|
||||
|
||||
- Customer Interaction:
|
||||
- Span 1: Customer initiates a request via the AI-powered chatbot for billing support (e.g., asking for payment details).
|
||||
|
||||
- AI Agent 1 (Main - Arch):
|
||||
- Span 2: AI Agent 1 (Main) processes the request and identifies it as related to billing, forwarding the request
|
||||
to an external payment service.
|
||||
- Span 3: AI Agent 1 determines that additional technical support is needed for processing and forwards the request
|
||||
to AI Agent 2.
|
||||
|
||||
- External Payment Service:
|
||||
- Span 4: The external payment service processes the payment-related request (e.g., verifying payment status) and sends
|
||||
the response back to AI Agent 1.
|
||||
|
||||
- AI Agent 2 (Tech - Arch):
|
||||
- Span 5: AI Agent 2, responsible for technical queries, processes a request forwarded from AI Agent 1 (e.g., checking for
|
||||
any account issues).
|
||||
- Span 6: AI Agent 2 forwards the query to Internal Tech Support for further investigation.
|
||||
|
||||
- Internal Tech Support:
|
||||
- Span 7: Internal Tech Support processes the request (e.g., resolving account access issues) and responds to AI Agent 2.
|
||||
|
||||
- AI Agent 3 (Orders - Arch):
|
||||
- Span 8: AI Agent 3 handles order-related queries. AI Agent 1 forwards the request to AI Agent 3 after payment verification
|
||||
is completed.
|
||||
- Span 9: AI Agent 3 forwards a request to the Inventory Management system to confirm product availability for a pending order.
|
||||
|
||||
- Inventory Management:
|
||||
- Span 10: The Inventory Management system checks stock and availability and returns the information to AI Agent 3.
|
||||
|
||||
Integrating with Tracing Tools
|
||||
------------------------------
|
||||
|
||||
AWS X-Ray
|
||||
~~~~~~~~~
|
||||
|
||||
To send tracing data to `AWS X-Ray <https://aws.amazon.com/xray/>`_ :
|
||||
|
||||
1. **Configure OpenTelemetry Collector**: Set up the collector to export traces to AWS X-Ray.
|
||||
|
||||
Collector configuration (``otel-collector-config.yaml``):
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
receivers:
|
||||
otlp:
|
||||
protocols:
|
||||
grpc:
|
||||
|
||||
processors:
|
||||
batch:
|
||||
|
||||
exporters:
|
||||
awsxray:
|
||||
region: your-aws-region
|
||||
|
||||
service:
|
||||
pipelines:
|
||||
traces:
|
||||
receivers: [otlp]
|
||||
processors: [batch]
|
||||
exporters: [awsxray]
|
||||
|
||||
2. **Deploy the Collector**: Run the collector as a Docker container, Kubernetes pod, or standalone service.
|
||||
3. **Ensure AWS Credentials**: Provide AWS credentials to the collector, preferably via IAM roles.
|
||||
4. **Verify Traces**: Access the AWS X-Ray console to view your traces.
|
||||
|
||||
Datadog
|
||||
~~~~~~~
|
||||
|
||||
Datadog
|
||||
|
||||
To send tracing data to `Datadog <https://docs.datadoghq.com/getting_started/tracing/>`_:
|
||||
|
||||
1. **Configure OpenTelemetry Collector**: Set up the collector to export traces to Datadog.
|
||||
|
||||
Collector configuration (``otel-collector-config.yaml``):
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
receivers:
|
||||
otlp:
|
||||
protocols:
|
||||
grpc:
|
||||
|
||||
processors:
|
||||
batch:
|
||||
|
||||
exporters:
|
||||
datadog:
|
||||
api:
|
||||
key: "${DD_API_KEY}"
|
||||
site: "${DD_SITE}"
|
||||
|
||||
service:
|
||||
pipelines:
|
||||
traces:
|
||||
receivers: [otlp]
|
||||
processors: [batch]
|
||||
exporters: [datadog]
|
||||
|
||||
2. **Set Environment Variables**: Provide your Datadog API key and site.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export DD_API_KEY=your_datadog_api_key
|
||||
export DD_SITE=datadoghq.com # Or datadoghq.eu
|
||||
|
||||
3. **Deploy the Collector**: Run the collector in your environment.
|
||||
4. **Verify Traces**: Access the Datadog APM dashboard to view your traces.
|
||||
|
||||
|
||||
Best Practices
|
||||
--------------
|
||||
|
||||
- **Consistent Instrumentation**: Ensure all services propagate the ``traceparent`` header.
|
||||
- **Secure Configuration**: Protect sensitive data and secure communication between services.
|
||||
- **Performance Monitoring**: Be mindful of the performance impact and adjust sampling rates accordingly.
|
||||
- **Error Handling**: Implement proper error handling to prevent tracing issues from affecting your application.
|
||||
|
||||
Conclusion
|
||||
----------
|
||||
|
||||
By leveraging the ``traceparent`` header for trace context propagation, Arch enables developers to implement
|
||||
tracing efficiently. This approach simplifies the process of collecting and analyzing tracing data in common
|
||||
tools like AWS X-Ray and Datadog, enhancing observability and facilitating faster debugging and optimization.
|
||||
|
||||
Additional Resources
|
||||
--------------------
|
||||
|
||||
- **OpenTelemetry Documentation**: https://opentelemetry.io/docs/
|
||||
- **W3C Trace Context Specification**: https://www.w3.org/TR/trace-context/
|
||||
- **AWS X-Ray Exporter**: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/awsxrayexporter
|
||||
- **Datadog Exporter**: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/datadogexporter
|
||||
|
||||
.. Note::
|
||||
Replace placeholders like ``your-aws-region``, and ``DD_API_KEY`` with your actual configurations.
|
||||
22
_sources/root.rst
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
Documentation
|
||||
=============
|
||||
|
||||
.. image:: /_static/img/arch-logo.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
**Arch is built on (and by the core contributors of) Envoy proxy with the belief that:**
|
||||
|
||||
*Prompts are nuanced and opaque user requests, which require the same capabilities as traditional HTTP requests
|
||||
including secure handling, intelligent routing, robust observability, and integration with backend (API)
|
||||
systems for personalization - all outside business logic.*
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
intro/intro
|
||||
getting_started/getting_started
|
||||
getting_started/use_cases
|
||||
observability/observability
|
||||
llms/llms
|
||||
configuration_reference
|
||||
BIN
_static/arch-nav-logo.png
Normal file
|
After Width: | Height: | Size: 289 KiB |
925
_static/basic.css
Normal file
|
|
@ -0,0 +1,925 @@
|
|||
/*
|
||||
* basic.css
|
||||
* ~~~~~~~~~
|
||||
*
|
||||
* Sphinx stylesheet -- basic theme.
|
||||
*
|
||||
* :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/* -- main layout ----------------------------------------------------------- */
|
||||
|
||||
div.clearer {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
div.section::after {
|
||||
display: block;
|
||||
content: '';
|
||||
clear: left;
|
||||
}
|
||||
|
||||
/* -- relbar ---------------------------------------------------------------- */
|
||||
|
||||
div.related {
|
||||
width: 100%;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.related h3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.related ul {
|
||||
margin: 0;
|
||||
padding: 0 0 0 10px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.related li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.related li.right {
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* -- sidebar --------------------------------------------------------------- */
|
||||
|
||||
div.sphinxsidebarwrapper {
|
||||
padding: 10px 5px 0 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
float: left;
|
||||
width: 270px;
|
||||
margin-left: -100%;
|
||||
font-size: 90%;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap : break-word;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul,
|
||||
div.sphinxsidebar ul.want-points {
|
||||
margin-left: 20px;
|
||||
list-style: square;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar form {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #98dbcc;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
div.sphinxsidebar #searchbox form.search {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.sphinxsidebar #searchbox input[type="text"] {
|
||||
float: left;
|
||||
width: 80%;
|
||||
padding: 0.25em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
div.sphinxsidebar #searchbox input[type="submit"] {
|
||||
float: left;
|
||||
width: 20%;
|
||||
border-left: none;
|
||||
padding: 0.25em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* -- search page ----------------------------------------------------------- */
|
||||
|
||||
ul.search {
|
||||
margin: 10px 0 0 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.search li {
|
||||
padding: 5px 0 5px 20px;
|
||||
background-image: url(file.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 7px;
|
||||
}
|
||||
|
||||
ul.search li a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul.search li p.context {
|
||||
color: #888;
|
||||
margin: 2px 0 0 30px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
ul.keywordmatches li.goodmatch a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* -- index page ------------------------------------------------------------ */
|
||||
|
||||
table.contentstable {
|
||||
width: 90%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.contentstable p.biglink {
|
||||
line-height: 150%;
|
||||
}
|
||||
|
||||
a.biglink {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
span.linkdescr {
|
||||
font-style: italic;
|
||||
padding-top: 5px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
/* -- general index --------------------------------------------------------- */
|
||||
|
||||
table.indextable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.indextable td {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.indextable ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
table.indextable > tbody > tr > td > ul {
|
||||
padding-left: 0em;
|
||||
}
|
||||
|
||||
table.indextable tr.pcap {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
table.indextable tr.cap {
|
||||
margin-top: 10px;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
img.toggler {
|
||||
margin-right: 3px;
|
||||
margin-top: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.modindex-jumpbox {
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 1em 0 1em 0;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
div.genindex-jumpbox {
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 1em 0 1em 0;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
/* -- domain module index --------------------------------------------------- */
|
||||
|
||||
table.modindextable td {
|
||||
padding: 2px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
/* -- general body styles --------------------------------------------------- */
|
||||
|
||||
div.body {
|
||||
min-width: 360px;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
div.body p, div.body dd, div.body li, div.body blockquote {
|
||||
-moz-hyphens: auto;
|
||||
-ms-hyphens: auto;
|
||||
-webkit-hyphens: auto;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
a.headerlink {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #551A8B;
|
||||
}
|
||||
|
||||
h1:hover > a.headerlink,
|
||||
h2:hover > a.headerlink,
|
||||
h3:hover > a.headerlink,
|
||||
h4:hover > a.headerlink,
|
||||
h5:hover > a.headerlink,
|
||||
h6:hover > a.headerlink,
|
||||
dt:hover > a.headerlink,
|
||||
caption:hover > a.headerlink,
|
||||
p.caption:hover > a.headerlink,
|
||||
div.code-block-caption:hover > a.headerlink {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
div.body p.caption {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
div.body td {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.first {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
p.rubric {
|
||||
margin-top: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
img.align-left, figure.align-left, .figure.align-left, object.align-left {
|
||||
clear: left;
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
img.align-right, figure.align-right, .figure.align-right, object.align-right {
|
||||
clear: right;
|
||||
float: right;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
img.align-center, figure.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
img.align-default, figure.align-default, .figure.align-default {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.align-default {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* -- sidebars -------------------------------------------------------------- */
|
||||
|
||||
div.sidebar,
|
||||
aside.sidebar {
|
||||
margin: 0 0 0.5em 1em;
|
||||
border: 1px solid #ddb;
|
||||
padding: 7px;
|
||||
background-color: #ffe;
|
||||
width: 40%;
|
||||
float: right;
|
||||
clear: right;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
p.sidebar-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
nav.contents,
|
||||
aside.topic,
|
||||
div.admonition, div.topic, blockquote {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
/* -- topics ---------------------------------------------------------------- */
|
||||
|
||||
nav.contents,
|
||||
aside.topic,
|
||||
div.topic {
|
||||
border: 1px solid #ccc;
|
||||
padding: 7px;
|
||||
margin: 10px 0 10px 0;
|
||||
}
|
||||
|
||||
p.topic-title {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* -- admonitions ----------------------------------------------------------- */
|
||||
|
||||
div.admonition {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
div.admonition dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
margin: 0px 10px 5px 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.body p.centered {
|
||||
text-align: center;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
/* -- content of sidebars/topics/admonitions -------------------------------- */
|
||||
|
||||
div.sidebar > :last-child,
|
||||
aside.sidebar > :last-child,
|
||||
nav.contents > :last-child,
|
||||
aside.topic > :last-child,
|
||||
div.topic > :last-child,
|
||||
div.admonition > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.sidebar::after,
|
||||
aside.sidebar::after,
|
||||
nav.contents::after,
|
||||
aside.topic::after,
|
||||
div.topic::after,
|
||||
div.admonition::after,
|
||||
blockquote::after {
|
||||
display: block;
|
||||
content: '';
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* -- tables ---------------------------------------------------------------- */
|
||||
|
||||
table.docutils {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.align-default {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table caption span.caption-number {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
table caption span.caption-text {
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th {
|
||||
padding: 1px 8px 1px 5px;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
table.citation td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
th > :first-child,
|
||||
td > :first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
th > :last-child,
|
||||
td > :last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
/* -- figures --------------------------------------------------------------- */
|
||||
|
||||
div.figure, figure {
|
||||
margin: 0.5em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
div.figure p.caption, figcaption {
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
div.figure p.caption span.caption-number,
|
||||
figcaption span.caption-number {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.figure p.caption span.caption-text,
|
||||
figcaption span.caption-text {
|
||||
}
|
||||
|
||||
/* -- field list styles ----------------------------------------------------- */
|
||||
|
||||
table.field-list td, table.field-list th {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
.field-list ul {
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.field-list p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.field-name {
|
||||
-moz-hyphens: manual;
|
||||
-ms-hyphens: manual;
|
||||
-webkit-hyphens: manual;
|
||||
hyphens: manual;
|
||||
}
|
||||
|
||||
/* -- hlist styles ---------------------------------------------------------- */
|
||||
|
||||
table.hlist {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
table.hlist td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* -- object description styles --------------------------------------------- */
|
||||
|
||||
.sig {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
}
|
||||
|
||||
.sig-name, code.descname {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sig-name {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
code.descname {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.sig-prename, code.descclassname {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.optional {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.sig-paren {
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.sig-param.n {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* C++ specific styling */
|
||||
|
||||
.sig-inline.c-texpr,
|
||||
.sig-inline.cpp-texpr {
|
||||
font-family: unset;
|
||||
}
|
||||
|
||||
.sig.c .k, .sig.c .kt,
|
||||
.sig.cpp .k, .sig.cpp .kt {
|
||||
color: #0033B3;
|
||||
}
|
||||
|
||||
.sig.c .m,
|
||||
.sig.cpp .m {
|
||||
color: #1750EB;
|
||||
}
|
||||
|
||||
.sig.c .s, .sig.c .sc,
|
||||
.sig.cpp .s, .sig.cpp .sc {
|
||||
color: #067D17;
|
||||
}
|
||||
|
||||
|
||||
/* -- other body styles ----------------------------------------------------- */
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha;
|
||||
}
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha;
|
||||
}
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman;
|
||||
}
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman;
|
||||
}
|
||||
|
||||
:not(li) > ol > li:first-child > :first-child,
|
||||
:not(li) > ul > li:first-child > :first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
:not(li) > ol > li:last-child > :last-child,
|
||||
:not(li) > ul > li:last-child > :last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
ol.simple ol p,
|
||||
ol.simple ul p,
|
||||
ul.simple ol p,
|
||||
ul.simple ul p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ol.simple > li:not(:first-child) > p,
|
||||
ul.simple > li:not(:first-child) > p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ol.simple p,
|
||||
ul.simple p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
aside.footnote > span,
|
||||
div.citation > span {
|
||||
float: left;
|
||||
}
|
||||
aside.footnote > span:last-of-type,
|
||||
div.citation > span:last-of-type {
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
aside.footnote > p {
|
||||
margin-left: 2em;
|
||||
}
|
||||
div.citation > p {
|
||||
margin-left: 4em;
|
||||
}
|
||||
aside.footnote > p:last-of-type,
|
||||
div.citation > p:last-of-type {
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
aside.footnote > p:last-of-type:after,
|
||||
div.citation > p:last-of-type:after {
|
||||
content: "";
|
||||
clear: both;
|
||||
}
|
||||
|
||||
dl.field-list {
|
||||
display: grid;
|
||||
grid-template-columns: fit-content(30%) auto;
|
||||
}
|
||||
|
||||
dl.field-list > dt {
|
||||
font-weight: bold;
|
||||
word-break: break-word;
|
||||
padding-left: 0.5em;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
dl.field-list > dd {
|
||||
padding-left: 0.5em;
|
||||
margin-top: 0em;
|
||||
margin-left: 0em;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
dd > :first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
dd ul, dd table {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.sig dd {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.sig dl {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
dl > dd:last-child,
|
||||
dl > dd:last-child > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt:target, span.highlighted {
|
||||
background-color: #fbe54e;
|
||||
}
|
||||
|
||||
rect.highlighted {
|
||||
fill: #fbe54e;
|
||||
}
|
||||
|
||||
dl.glossary dt {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.versionmodified {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
background-color: #fda;
|
||||
padding: 5px;
|
||||
border: 3px solid red;
|
||||
}
|
||||
|
||||
.footnote:target {
|
||||
background-color: #ffa;
|
||||
}
|
||||
|
||||
.line-block {
|
||||
display: block;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.line-block .line-block {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
.guilabel, .menuselection {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.accelerator {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.classifier {
|
||||
font-style: oblique;
|
||||
}
|
||||
|
||||
.classifier:before {
|
||||
font-style: normal;
|
||||
margin: 0 0.5em;
|
||||
content: ":";
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
abbr, acronym {
|
||||
border-bottom: dotted 1px;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.translated {
|
||||
background-color: rgba(207, 255, 207, 0.2)
|
||||
}
|
||||
|
||||
.untranslated {
|
||||
background-color: rgba(255, 207, 207, 0.2)
|
||||
}
|
||||
|
||||
/* -- code displays --------------------------------------------------------- */
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
overflow-y: hidden; /* fixes display issues on Chrome browsers */
|
||||
}
|
||||
|
||||
pre, div[class*="highlight-"] {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
span.pre {
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
-webkit-hyphens: none;
|
||||
hyphens: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
div[class*="highlight-"] {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
td.linenos pre {
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
table.highlighttable {
|
||||
display: block;
|
||||
}
|
||||
|
||||
table.highlighttable tbody {
|
||||
display: block;
|
||||
}
|
||||
|
||||
table.highlighttable tr {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
table.highlighttable td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table.highlighttable td.linenos {
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
table.highlighttable td.code {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.highlight .hll {
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.highlight pre,
|
||||
table.highlighttable pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.code-block-caption + div {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
div.code-block-caption {
|
||||
margin-top: 1em;
|
||||
padding: 2px 5px;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
div.code-block-caption code {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
table.highlighttable td.linenos,
|
||||
span.linenos,
|
||||
div.highlight span.gp { /* gp: Generic.Prompt */
|
||||
user-select: none;
|
||||
-webkit-user-select: text; /* Safari fallback only */
|
||||
-webkit-user-select: none; /* Chrome/Safari */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE10+ */
|
||||
}
|
||||
|
||||
div.code-block-caption span.caption-number {
|
||||
padding: 0.1em 0.3em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.code-block-caption span.caption-text {
|
||||
}
|
||||
|
||||
div.literal-block-wrapper {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
code.xref, a code {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.viewcode-link {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.viewcode-back {
|
||||
float: right;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
div.viewcode-block:target {
|
||||
margin: -1px -10px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
/* -- math display ---------------------------------------------------------- */
|
||||
|
||||
img.math {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.body div.math p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span.eqno {
|
||||
float: right;
|
||||
}
|
||||
|
||||
span.eqno a.headerlink {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
div.math:hover a.headerlink {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* -- printout stylesheet --------------------------------------------------- */
|
||||
|
||||
@media print {
|
||||
div.document,
|
||||
div.documentwrapper,
|
||||
div.bodywrapper {
|
||||
margin: 0 !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar,
|
||||
div.related,
|
||||
div.footer,
|
||||
#top-link {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
4
_static/check-solid.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-check" width="44" height="44" viewBox="0 0 24 24" stroke-width="2" stroke="#22863a" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M5 12l5 5l10 -10" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 313 B |
7
_static/clipboard.min.js
vendored
Normal file
5
_static/copy-button.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-copy" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#000000" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<rect x="8" y="8" width="12" height="12" rx="2" />
|
||||
<path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 411 B |
94
_static/copybutton.css
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/* Copy buttons */
|
||||
button.copybtn {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
top: .3em;
|
||||
right: .3em;
|
||||
width: 1.7em;
|
||||
height: 1.7em;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s, border .3s, background-color .3s;
|
||||
user-select: none;
|
||||
padding: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 0.4em;
|
||||
/* The colors that GitHub uses */
|
||||
border: #1b1f2426 1px solid;
|
||||
background-color: #f6f8fa;
|
||||
color: #57606a;
|
||||
}
|
||||
|
||||
button.copybtn.success {
|
||||
border-color: #22863a;
|
||||
color: #22863a;
|
||||
}
|
||||
|
||||
button.copybtn svg {
|
||||
stroke: currentColor;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
padding: 0.1em;
|
||||
}
|
||||
|
||||
div.highlight {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Show the copybutton */
|
||||
.highlight:hover button.copybtn, button.copybtn.success {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.highlight button.copybtn:hover {
|
||||
background-color: rgb(235, 235, 235);
|
||||
}
|
||||
|
||||
.highlight button.copybtn:active {
|
||||
background-color: rgb(187, 187, 187);
|
||||
}
|
||||
|
||||
/**
|
||||
* A minimal CSS-only tooltip copied from:
|
||||
* https://codepen.io/mildrenben/pen/rVBrpK
|
||||
*
|
||||
* To use, write HTML like the following:
|
||||
*
|
||||
* <p class="o-tooltip--left" data-tooltip="Hey">Short</p>
|
||||
*/
|
||||
.o-tooltip--left {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.o-tooltip--left:after {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
content: attr(data-tooltip);
|
||||
padding: .2em;
|
||||
font-size: .8em;
|
||||
left: -.2em;
|
||||
background: grey;
|
||||
color: white;
|
||||
white-space: nowrap;
|
||||
z-index: 2;
|
||||
border-radius: 2px;
|
||||
transform: translateX(-102%) translateY(0);
|
||||
transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1);
|
||||
}
|
||||
|
||||
.o-tooltip--left:hover:after {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translateX(-100%) translateY(0);
|
||||
transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1);
|
||||
transition-delay: .5s;
|
||||
}
|
||||
|
||||
/* By default the copy button shouldn't show up when printing a page */
|
||||
@media print {
|
||||
button.copybtn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
248
_static/copybutton.js
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
// Localization support
|
||||
const messages = {
|
||||
'en': {
|
||||
'copy': 'Copy',
|
||||
'copy_to_clipboard': 'Copy to clipboard',
|
||||
'copy_success': 'Copied!',
|
||||
'copy_failure': 'Failed to copy',
|
||||
},
|
||||
'es' : {
|
||||
'copy': 'Copiar',
|
||||
'copy_to_clipboard': 'Copiar al portapapeles',
|
||||
'copy_success': '¡Copiado!',
|
||||
'copy_failure': 'Error al copiar',
|
||||
},
|
||||
'de' : {
|
||||
'copy': 'Kopieren',
|
||||
'copy_to_clipboard': 'In die Zwischenablage kopieren',
|
||||
'copy_success': 'Kopiert!',
|
||||
'copy_failure': 'Fehler beim Kopieren',
|
||||
},
|
||||
'fr' : {
|
||||
'copy': 'Copier',
|
||||
'copy_to_clipboard': 'Copier dans le presse-papier',
|
||||
'copy_success': 'Copié !',
|
||||
'copy_failure': 'Échec de la copie',
|
||||
},
|
||||
'ru': {
|
||||
'copy': 'Скопировать',
|
||||
'copy_to_clipboard': 'Скопировать в буфер',
|
||||
'copy_success': 'Скопировано!',
|
||||
'copy_failure': 'Не удалось скопировать',
|
||||
},
|
||||
'zh-CN': {
|
||||
'copy': '复制',
|
||||
'copy_to_clipboard': '复制到剪贴板',
|
||||
'copy_success': '复制成功!',
|
||||
'copy_failure': '复制失败',
|
||||
},
|
||||
'it' : {
|
||||
'copy': 'Copiare',
|
||||
'copy_to_clipboard': 'Copiato negli appunti',
|
||||
'copy_success': 'Copiato!',
|
||||
'copy_failure': 'Errore durante la copia',
|
||||
}
|
||||
}
|
||||
|
||||
let locale = 'en'
|
||||
if( document.documentElement.lang !== undefined
|
||||
&& messages[document.documentElement.lang] !== undefined ) {
|
||||
locale = document.documentElement.lang
|
||||
}
|
||||
|
||||
let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT;
|
||||
if (doc_url_root == '#') {
|
||||
doc_url_root = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* SVG files for our copy buttons
|
||||
*/
|
||||
let iconCheck = `<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-check" width="44" height="44" viewBox="0 0 24 24" stroke-width="2" stroke="#22863a" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<title>${messages[locale]['copy_success']}</title>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M5 12l5 5l10 -10" />
|
||||
</svg>`
|
||||
|
||||
// If the user specified their own SVG use that, otherwise use the default
|
||||
let iconCopy = ``;
|
||||
if (!iconCopy) {
|
||||
iconCopy = `<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-copy" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#000000" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<title>${messages[locale]['copy_to_clipboard']}</title>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<rect x="8" y="8" width="12" height="12" rx="2" />
|
||||
<path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2" />
|
||||
</svg>`
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up copy/paste for code blocks
|
||||
*/
|
||||
|
||||
const runWhenDOMLoaded = cb => {
|
||||
if (document.readyState != 'loading') {
|
||||
cb()
|
||||
} else if (document.addEventListener) {
|
||||
document.addEventListener('DOMContentLoaded', cb)
|
||||
} else {
|
||||
document.attachEvent('onreadystatechange', function() {
|
||||
if (document.readyState == 'complete') cb()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const codeCellId = index => `codecell${index}`
|
||||
|
||||
// Clears selected text since ClipboardJS will select the text when copying
|
||||
const clearSelection = () => {
|
||||
if (window.getSelection) {
|
||||
window.getSelection().removeAllRanges()
|
||||
} else if (document.selection) {
|
||||
document.selection.empty()
|
||||
}
|
||||
}
|
||||
|
||||
// Changes tooltip text for a moment, then changes it back
|
||||
// We want the timeout of our `success` class to be a bit shorter than the
|
||||
// tooltip and icon change, so that we can hide the icon before changing back.
|
||||
var timeoutIcon = 2000;
|
||||
var timeoutSuccessClass = 1500;
|
||||
|
||||
const temporarilyChangeTooltip = (el, oldText, newText) => {
|
||||
el.setAttribute('data-tooltip', newText)
|
||||
el.classList.add('success')
|
||||
// Remove success a little bit sooner than we change the tooltip
|
||||
// So that we can use CSS to hide the copybutton first
|
||||
setTimeout(() => el.classList.remove('success'), timeoutSuccessClass)
|
||||
setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon)
|
||||
}
|
||||
|
||||
// Changes the copy button icon for two seconds, then changes it back
|
||||
const temporarilyChangeIcon = (el) => {
|
||||
el.innerHTML = iconCheck;
|
||||
setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon)
|
||||
}
|
||||
|
||||
const addCopyButtonToCodeCells = () => {
|
||||
// If ClipboardJS hasn't loaded, wait a bit and try again. This
|
||||
// happens because we load ClipboardJS asynchronously.
|
||||
if (window.ClipboardJS === undefined) {
|
||||
setTimeout(addCopyButtonToCodeCells, 250)
|
||||
return
|
||||
}
|
||||
|
||||
// Add copybuttons to all of our code cells
|
||||
const COPYBUTTON_SELECTOR = 'div.highlight pre';
|
||||
const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR)
|
||||
codeCells.forEach((codeCell, index) => {
|
||||
const id = codeCellId(index)
|
||||
codeCell.setAttribute('id', id)
|
||||
|
||||
const clipboardButton = id =>
|
||||
`<button class="copybtn o-tooltip--left" data-tooltip="${messages[locale]['copy']}" data-clipboard-target="#${id}">
|
||||
${iconCopy}
|
||||
</button>`
|
||||
codeCell.insertAdjacentHTML('afterend', clipboardButton(id))
|
||||
})
|
||||
|
||||
function escapeRegExp(string) {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes excluded text from a Node.
|
||||
*
|
||||
* @param {Node} target Node to filter.
|
||||
* @param {string} exclude CSS selector of nodes to exclude.
|
||||
* @returns {DOMString} Text from `target` with text removed.
|
||||
*/
|
||||
function filterText(target, exclude) {
|
||||
const clone = target.cloneNode(true); // clone as to not modify the live DOM
|
||||
if (exclude) {
|
||||
// remove excluded nodes
|
||||
clone.querySelectorAll(exclude).forEach(node => node.remove());
|
||||
}
|
||||
return clone.innerText;
|
||||
}
|
||||
|
||||
// Callback when a copy button is clicked. Will be passed the node that was clicked
|
||||
// should then grab the text and replace pieces of text that shouldn't be used in output
|
||||
function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") {
|
||||
var regexp;
|
||||
var match;
|
||||
|
||||
// Do we check for line continuation characters and "HERE-documents"?
|
||||
var useLineCont = !!lineContinuationChar
|
||||
var useHereDoc = !!hereDocDelim
|
||||
|
||||
// create regexp to capture prompt and remaining line
|
||||
if (isRegexp) {
|
||||
regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)')
|
||||
} else {
|
||||
regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)')
|
||||
}
|
||||
|
||||
const outputLines = [];
|
||||
var promptFound = false;
|
||||
var gotLineCont = false;
|
||||
var gotHereDoc = false;
|
||||
const lineGotPrompt = [];
|
||||
for (const line of textContent.split('\n')) {
|
||||
match = line.match(regexp)
|
||||
if (match || gotLineCont || gotHereDoc) {
|
||||
promptFound = regexp.test(line)
|
||||
lineGotPrompt.push(promptFound)
|
||||
if (removePrompts && promptFound) {
|
||||
outputLines.push(match[2])
|
||||
} else {
|
||||
outputLines.push(line)
|
||||
}
|
||||
gotLineCont = line.endsWith(lineContinuationChar) & useLineCont
|
||||
if (line.includes(hereDocDelim) & useHereDoc)
|
||||
gotHereDoc = !gotHereDoc
|
||||
} else if (!onlyCopyPromptLines) {
|
||||
outputLines.push(line)
|
||||
} else if (copyEmptyLines && line.trim() === '') {
|
||||
outputLines.push(line)
|
||||
}
|
||||
}
|
||||
|
||||
// If no lines with the prompt were found then just use original lines
|
||||
if (lineGotPrompt.some(v => v === true)) {
|
||||
textContent = outputLines.join('\n');
|
||||
}
|
||||
|
||||
// Remove a trailing newline to avoid auto-running when pasting
|
||||
if (textContent.endsWith("\n")) {
|
||||
textContent = textContent.slice(0, -1)
|
||||
}
|
||||
return textContent
|
||||
}
|
||||
|
||||
|
||||
var copyTargetText = (trigger) => {
|
||||
var target = document.querySelector(trigger.attributes['data-clipboard-target'].value);
|
||||
|
||||
// get filtered text
|
||||
let exclude = '.linenos';
|
||||
|
||||
let text = filterText(target, exclude);
|
||||
return formatCopyText(text, '', false, true, true, true, '', '')
|
||||
}
|
||||
|
||||
// Initialize with a callback so we can modify the text before copy
|
||||
const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText})
|
||||
|
||||
// Update UI with error/success messages
|
||||
clipboard.on('success', event => {
|
||||
clearSelection()
|
||||
temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success'])
|
||||
temporarilyChangeIcon(event.trigger)
|
||||
})
|
||||
|
||||
clipboard.on('error', event => {
|
||||
temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure'])
|
||||
})
|
||||
}
|
||||
|
||||
runWhenDOMLoaded(addCopyButtonToCodeCells)
|
||||
73
_static/copybutton_funcs.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
function escapeRegExp(string) {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes excluded text from a Node.
|
||||
*
|
||||
* @param {Node} target Node to filter.
|
||||
* @param {string} exclude CSS selector of nodes to exclude.
|
||||
* @returns {DOMString} Text from `target` with text removed.
|
||||
*/
|
||||
export function filterText(target, exclude) {
|
||||
const clone = target.cloneNode(true); // clone as to not modify the live DOM
|
||||
if (exclude) {
|
||||
// remove excluded nodes
|
||||
clone.querySelectorAll(exclude).forEach(node => node.remove());
|
||||
}
|
||||
return clone.innerText;
|
||||
}
|
||||
|
||||
// Callback when a copy button is clicked. Will be passed the node that was clicked
|
||||
// should then grab the text and replace pieces of text that shouldn't be used in output
|
||||
export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") {
|
||||
var regexp;
|
||||
var match;
|
||||
|
||||
// Do we check for line continuation characters and "HERE-documents"?
|
||||
var useLineCont = !!lineContinuationChar
|
||||
var useHereDoc = !!hereDocDelim
|
||||
|
||||
// create regexp to capture prompt and remaining line
|
||||
if (isRegexp) {
|
||||
regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)')
|
||||
} else {
|
||||
regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)')
|
||||
}
|
||||
|
||||
const outputLines = [];
|
||||
var promptFound = false;
|
||||
var gotLineCont = false;
|
||||
var gotHereDoc = false;
|
||||
const lineGotPrompt = [];
|
||||
for (const line of textContent.split('\n')) {
|
||||
match = line.match(regexp)
|
||||
if (match || gotLineCont || gotHereDoc) {
|
||||
promptFound = regexp.test(line)
|
||||
lineGotPrompt.push(promptFound)
|
||||
if (removePrompts && promptFound) {
|
||||
outputLines.push(match[2])
|
||||
} else {
|
||||
outputLines.push(line)
|
||||
}
|
||||
gotLineCont = line.endsWith(lineContinuationChar) & useLineCont
|
||||
if (line.includes(hereDocDelim) & useHereDoc)
|
||||
gotHereDoc = !gotHereDoc
|
||||
} else if (!onlyCopyPromptLines) {
|
||||
outputLines.push(line)
|
||||
} else if (copyEmptyLines && line.trim() === '') {
|
||||
outputLines.push(line)
|
||||
}
|
||||
}
|
||||
|
||||
// If no lines with the prompt were found then just use original lines
|
||||
if (lineGotPrompt.some(v => v === true)) {
|
||||
textContent = outputLines.join('\n');
|
||||
}
|
||||
|
||||
// Remove a trailing newline to avoid auto-running when pasting
|
||||
if (textContent.endsWith("\n")) {
|
||||
textContent = textContent.slice(0, -1)
|
||||
}
|
||||
return textContent
|
||||
}
|
||||
5
_static/css/arch.css
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
@import url("theme.css");
|
||||
|
||||
body {
|
||||
font-size: 1em;
|
||||
}
|
||||
156
_static/doctools.js
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* doctools.js
|
||||
* ~~~~~~~~~~~
|
||||
*
|
||||
* Base JavaScript utilities for all Sphinx HTML documentation.
|
||||
*
|
||||
* :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([
|
||||
"TEXTAREA",
|
||||
"INPUT",
|
||||
"SELECT",
|
||||
"BUTTON",
|
||||
]);
|
||||
|
||||
const _ready = (callback) => {
|
||||
if (document.readyState !== "loading") {
|
||||
callback();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Small JavaScript module for the documentation.
|
||||
*/
|
||||
const Documentation = {
|
||||
init: () => {
|
||||
Documentation.initDomainIndexTable();
|
||||
Documentation.initOnKeyListeners();
|
||||
},
|
||||
|
||||
/**
|
||||
* i18n support
|
||||
*/
|
||||
TRANSLATIONS: {},
|
||||
PLURAL_EXPR: (n) => (n === 1 ? 0 : 1),
|
||||
LOCALE: "unknown",
|
||||
|
||||
// gettext and ngettext don't access this so that the functions
|
||||
// can safely bound to a different name (_ = Documentation.gettext)
|
||||
gettext: (string) => {
|
||||
const translated = Documentation.TRANSLATIONS[string];
|
||||
switch (typeof translated) {
|
||||
case "undefined":
|
||||
return string; // no translation
|
||||
case "string":
|
||||
return translated; // translation exists
|
||||
default:
|
||||
return translated[0]; // (singular, plural) translation tuple exists
|
||||
}
|
||||
},
|
||||
|
||||
ngettext: (singular, plural, n) => {
|
||||
const translated = Documentation.TRANSLATIONS[singular];
|
||||
if (typeof translated !== "undefined")
|
||||
return translated[Documentation.PLURAL_EXPR(n)];
|
||||
return n === 1 ? singular : plural;
|
||||
},
|
||||
|
||||
addTranslations: (catalog) => {
|
||||
Object.assign(Documentation.TRANSLATIONS, catalog.messages);
|
||||
Documentation.PLURAL_EXPR = new Function(
|
||||
"n",
|
||||
`return (${catalog.plural_expr})`
|
||||
);
|
||||
Documentation.LOCALE = catalog.locale;
|
||||
},
|
||||
|
||||
/**
|
||||
* helper function to focus on search bar
|
||||
*/
|
||||
focusSearchBar: () => {
|
||||
document.querySelectorAll("input[name=q]")[0]?.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialise the domain index toggle buttons
|
||||
*/
|
||||
initDomainIndexTable: () => {
|
||||
const toggler = (el) => {
|
||||
const idNumber = el.id.substr(7);
|
||||
const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`);
|
||||
if (el.src.substr(-9) === "minus.png") {
|
||||
el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`;
|
||||
toggledRows.forEach((el) => (el.style.display = "none"));
|
||||
} else {
|
||||
el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`;
|
||||
toggledRows.forEach((el) => (el.style.display = ""));
|
||||
}
|
||||
};
|
||||
|
||||
const togglerElements = document.querySelectorAll("img.toggler");
|
||||
togglerElements.forEach((el) =>
|
||||
el.addEventListener("click", (event) => toggler(event.currentTarget))
|
||||
);
|
||||
togglerElements.forEach((el) => (el.style.display = ""));
|
||||
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler);
|
||||
},
|
||||
|
||||
initOnKeyListeners: () => {
|
||||
// only install a listener if it is really needed
|
||||
if (
|
||||
!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&
|
||||
!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS
|
||||
)
|
||||
return;
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
// bail for input elements
|
||||
if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
|
||||
// bail with special keys
|
||||
if (event.altKey || event.ctrlKey || event.metaKey) return;
|
||||
|
||||
if (!event.shiftKey) {
|
||||
switch (event.key) {
|
||||
case "ArrowLeft":
|
||||
if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
|
||||
|
||||
const prevLink = document.querySelector('link[rel="prev"]');
|
||||
if (prevLink && prevLink.href) {
|
||||
window.location.href = prevLink.href;
|
||||
event.preventDefault();
|
||||
}
|
||||
break;
|
||||
case "ArrowRight":
|
||||
if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
|
||||
|
||||
const nextLink = document.querySelector('link[rel="next"]');
|
||||
if (nextLink && nextLink.href) {
|
||||
window.location.href = nextLink.href;
|
||||
event.preventDefault();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// some keyboard layouts may need Shift to get /
|
||||
switch (event.key) {
|
||||
case "/":
|
||||
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;
|
||||
Documentation.focusSearchBar();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// quick alias for translations
|
||||
const _ = Documentation.gettext;
|
||||
|
||||
_ready(Documentation.init);
|
||||
13
_static/documentation_options.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
const DOCUMENTATION_OPTIONS = {
|
||||
VERSION: '0.1-beta',
|
||||
LANGUAGE: 'en',
|
||||
COLLAPSE_INDEX: false,
|
||||
BUILDER: 'html',
|
||||
FILE_SUFFIX: '.html',
|
||||
LINK_SUFFIX: '.html',
|
||||
HAS_SOURCE: true,
|
||||
SOURCELINK_SUFFIX: '',
|
||||
NAVIGATION_WITH_KEYS: false,
|
||||
SHOW_SEARCH_SUMMARY: true,
|
||||
ENABLE_SEARCH_SHORTCUTS: true,
|
||||
};
|
||||
BIN
_static/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
_static/file.png
Normal file
|
After Width: | Height: | Size: 286 B |
19
_static/images/logo_binder.svg
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 44.4 44.4" style="enable-background:new 0 0 44.4 44.4;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:none;stroke:#F5A252;stroke-width:5;stroke-miterlimit:10;}
|
||||
.st1{fill:none;stroke:#579ACA;stroke-width:5;stroke-miterlimit:10;}
|
||||
.st2{fill:none;stroke:#E66581;stroke-width:5;stroke-miterlimit:10;}
|
||||
</style>
|
||||
<title>logo</title>
|
||||
<g>
|
||||
<path class="st0" d="M33.9,6.4c3.6,3.9,3.4,9.9-0.5,13.5s-9.9,3.4-13.5-0.5s-3.4-9.9,0.5-13.5l0,0C24.2,2.4,30.2,2.6,33.9,6.4z"/>
|
||||
<path class="st1" d="M35.1,27.3c2.6,4.6,1.1,10.4-3.5,13c-4.6,2.6-10.4,1.1-13-3.5s-1.1-10.4,3.5-13l0,0
|
||||
C26.6,21.2,32.4,22.7,35.1,27.3z"/>
|
||||
<path class="st2" d="M25.9,17.8c2.6,4.6,1.1,10.4-3.5,13s-10.4,1.1-13-3.5s-1.1-10.4,3.5-13l0,0C17.5,11.7,23.3,13.2,25.9,17.8z"/>
|
||||
<path class="st1" d="M19.2,26.4c3.1-4.3,9.1-5.2,13.3-2.1c1.1,0.8,2,1.8,2.7,3"/>
|
||||
<path class="st0" d="M19.9,19.4c-3.6-3.9-3.4-9.9,0.5-13.5s9.9-3.4,13.5,0.5"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
BIN
_static/images/logo_colab.png
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
1
_static/images/logo_deepnote.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M0 128h52.512l29.539-11.077-11.077-43.487-34.051 3.693L0 128Z" fill="#0076D4"/><path fill-rule="evenodd" clip-rule="evenodd" d="M52.513 128s16.6-8.759 19.673-24.277c3.072-15.517-12.091-26.594-35.263-26.594 0-.41 20.343-28.718 20.343-28.718l49.4 1.435L95.71 107.7l-20.452 15.978L52.513 128Z" fill="#002868"/><path fill-rule="evenodd" clip-rule="evenodd" d="M0 60.718 41.025.001s1.006.01 3.282 0c16.082-.068 81.23 3.12 81.23 60.368 0 65.352-73.025 67.631-73.025 67.631s30.495-5.839 30.495-34.816c0-28.978-27.541-32.466-45.264-32.466H0Z" fill="#00A9FF"/></svg>
|
||||
|
After Width: | Height: | Size: 681 B |
1
_static/images/logo_jupyterhub.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="38.73" height="50" viewBox="0 0 38.73 50"><defs><style>.cls-1{fill:#767677;}.cls-2{fill:#f37726;}.cls-3{fill:#9e9e9e;}.cls-4{fill:#616262;}.cls-5{font-size:17.07px;fill:#fff;font-family:Roboto-Regular, Roboto;}</style></defs><title>logo_jupyterhub</title><g id="Canvas"><path id="path7_fill" data-name="path7 fill" class="cls-1" d="M39.51,3.53a3,3,0,0,1-1.7,2.9A3,3,0,0,1,34.48,6a3,3,0,0,1-.82-3.26,3,3,0,0,1,1.05-1.41A3,3,0,0,1,37.52.86a2.88,2.88,0,0,1,1,.6,3,3,0,0,1,.7.93,3.18,3.18,0,0,1,.28,1.14Z" transform="translate(-1.87 -0.69)"/><path id="path8_fill" data-name="path8 fill" class="cls-2" d="M21.91,38.39c-8,0-15.06-2.87-18.7-7.12a19.93,19.93,0,0,0,37.39,0C37,35.52,30,38.39,21.91,38.39Z" transform="translate(-1.87 -0.69)"/><path id="path9_fill" data-name="path9 fill" class="cls-2" d="M21.91,10.78c8,0,15.05,2.87,18.69,7.12a19.93,19.93,0,0,0-37.39,0C6.85,13.64,13.86,10.78,21.91,10.78Z" transform="translate(-1.87 -0.69)"/><path id="path10_fill" data-name="path10 fill" class="cls-3" d="M10.88,46.66a3.86,3.86,0,0,1-.52,2.15,3.81,3.81,0,0,1-1.62,1.51,3.93,3.93,0,0,1-2.19.34,3.79,3.79,0,0,1-2-.94,3.73,3.73,0,0,1-1.14-1.9,3.79,3.79,0,0,1,.1-2.21,3.86,3.86,0,0,1,1.33-1.78,3.92,3.92,0,0,1,3.54-.53,3.85,3.85,0,0,1,2.14,1.93,3.74,3.74,0,0,1,.37,1.43Z" transform="translate(-1.87 -0.69)"/><path id="path11_fill" data-name="path11 fill" class="cls-4" d="M4.12,9.81A2.18,2.18,0,0,1,2.9,9.48a2.23,2.23,0,0,1-.84-1A2.26,2.26,0,0,1,1.9,7.26a2.13,2.13,0,0,1,.56-1.13,2.18,2.18,0,0,1,2.36-.56,2.13,2.13,0,0,1,1,.76,2.18,2.18,0,0,1,.42,1.2A2.22,2.22,0,0,1,4.12,9.81Z" transform="translate(-1.87 -0.69)"/></g><text class="cls-5" transform="translate(5.24 30.01)">Hub</text></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
BIN
_static/img/arch-logo.png
Normal file
|
After Width: | Height: | Size: 311 KiB |
BIN
_static/img/arch-nav-logo.png
Normal file
|
After Width: | Height: | Size: 289 KiB |
BIN
_static/img/arch-system-architecture.jpg
Normal file
|
After Width: | Height: | Size: 389 KiB |
BIN
_static/img/function-calling-network-flow.jpg
Normal file
|
After Width: | Height: | Size: 297 KiB |
BIN
_static/img/network-topology-agent.jpg
Normal file
|
After Width: | Height: | Size: 264 KiB |
BIN
_static/img/network-topology-ingress-egress.jpg
Normal file
|
After Width: | Height: | Size: 281 KiB |
199
_static/language_data.js
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* language_data.js
|
||||
* ~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* This script contains the language-specific data used by searchtools.js,
|
||||
* namely the list of stopwords, stemmer, scorer and splitter.
|
||||
*
|
||||
* :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"];
|
||||
|
||||
|
||||
/* Non-minified version is copied as a separate JS file, if available */
|
||||
|
||||
/**
|
||||
* Porter Stemmer
|
||||
*/
|
||||
var Stemmer = function() {
|
||||
|
||||
var step2list = {
|
||||
ational: 'ate',
|
||||
tional: 'tion',
|
||||
enci: 'ence',
|
||||
anci: 'ance',
|
||||
izer: 'ize',
|
||||
bli: 'ble',
|
||||
alli: 'al',
|
||||
entli: 'ent',
|
||||
eli: 'e',
|
||||
ousli: 'ous',
|
||||
ization: 'ize',
|
||||
ation: 'ate',
|
||||
ator: 'ate',
|
||||
alism: 'al',
|
||||
iveness: 'ive',
|
||||
fulness: 'ful',
|
||||
ousness: 'ous',
|
||||
aliti: 'al',
|
||||
iviti: 'ive',
|
||||
biliti: 'ble',
|
||||
logi: 'log'
|
||||
};
|
||||
|
||||
var step3list = {
|
||||
icate: 'ic',
|
||||
ative: '',
|
||||
alize: 'al',
|
||||
iciti: 'ic',
|
||||
ical: 'ic',
|
||||
ful: '',
|
||||
ness: ''
|
||||
};
|
||||
|
||||
var c = "[^aeiou]"; // consonant
|
||||
var v = "[aeiouy]"; // vowel
|
||||
var C = c + "[^aeiouy]*"; // consonant sequence
|
||||
var V = v + "[aeiou]*"; // vowel sequence
|
||||
|
||||
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
|
||||
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
|
||||
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
|
||||
var s_v = "^(" + C + ")?" + v; // vowel in stem
|
||||
|
||||
this.stemWord = function (w) {
|
||||
var stem;
|
||||
var suffix;
|
||||
var firstch;
|
||||
var origword = w;
|
||||
|
||||
if (w.length < 3)
|
||||
return w;
|
||||
|
||||
var re;
|
||||
var re2;
|
||||
var re3;
|
||||
var re4;
|
||||
|
||||
firstch = w.substr(0,1);
|
||||
if (firstch == "y")
|
||||
w = firstch.toUpperCase() + w.substr(1);
|
||||
|
||||
// Step 1a
|
||||
re = /^(.+?)(ss|i)es$/;
|
||||
re2 = /^(.+?)([^s])s$/;
|
||||
|
||||
if (re.test(w))
|
||||
w = w.replace(re,"$1$2");
|
||||
else if (re2.test(w))
|
||||
w = w.replace(re2,"$1$2");
|
||||
|
||||
// Step 1b
|
||||
re = /^(.+?)eed$/;
|
||||
re2 = /^(.+?)(ed|ing)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
re = new RegExp(mgr0);
|
||||
if (re.test(fp[1])) {
|
||||
re = /.$/;
|
||||
w = w.replace(re,"");
|
||||
}
|
||||
}
|
||||
else if (re2.test(w)) {
|
||||
var fp = re2.exec(w);
|
||||
stem = fp[1];
|
||||
re2 = new RegExp(s_v);
|
||||
if (re2.test(stem)) {
|
||||
w = stem;
|
||||
re2 = /(at|bl|iz)$/;
|
||||
re3 = new RegExp("([^aeiouylsz])\\1$");
|
||||
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
|
||||
if (re2.test(w))
|
||||
w = w + "e";
|
||||
else if (re3.test(w)) {
|
||||
re = /.$/;
|
||||
w = w.replace(re,"");
|
||||
}
|
||||
else if (re4.test(w))
|
||||
w = w + "e";
|
||||
}
|
||||
}
|
||||
|
||||
// Step 1c
|
||||
re = /^(.+?)y$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
re = new RegExp(s_v);
|
||||
if (re.test(stem))
|
||||
w = stem + "i";
|
||||
}
|
||||
|
||||
// Step 2
|
||||
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
suffix = fp[2];
|
||||
re = new RegExp(mgr0);
|
||||
if (re.test(stem))
|
||||
w = stem + step2list[suffix];
|
||||
}
|
||||
|
||||
// Step 3
|
||||
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
suffix = fp[2];
|
||||
re = new RegExp(mgr0);
|
||||
if (re.test(stem))
|
||||
w = stem + step3list[suffix];
|
||||
}
|
||||
|
||||
// Step 4
|
||||
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
|
||||
re2 = /^(.+?)(s|t)(ion)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
re = new RegExp(mgr1);
|
||||
if (re.test(stem))
|
||||
w = stem;
|
||||
}
|
||||
else if (re2.test(w)) {
|
||||
var fp = re2.exec(w);
|
||||
stem = fp[1] + fp[2];
|
||||
re2 = new RegExp(mgr1);
|
||||
if (re2.test(stem))
|
||||
w = stem;
|
||||
}
|
||||
|
||||
// Step 5
|
||||
re = /^(.+?)e$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
re = new RegExp(mgr1);
|
||||
re2 = new RegExp(meq1);
|
||||
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
|
||||
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
|
||||
w = stem;
|
||||
}
|
||||
re = /ll$/;
|
||||
re2 = new RegExp(mgr1);
|
||||
if (re.test(w) && re2.test(w)) {
|
||||
re = /.$/;
|
||||
w = w.replace(re,"");
|
||||
}
|
||||
|
||||
// and turn initial Y back to y
|
||||
if (firstch == "y")
|
||||
w = firstch.toLowerCase() + w.substr(1);
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
_static/locales/ar/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/ar/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ar\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "طباعة إلى PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "موضوع بواسطة"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "تنزيل ملف المصدر"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "قضية مفتوحة"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "محتويات"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "الصفحة السابقة"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "تنزيل ملف دفتر الملاحظات"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "حقوق النشر"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "قم بتنزيل هذه الصفحة"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "مستودع المصدر"
|
||||
|
||||
msgid "By"
|
||||
msgstr "بواسطة"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "مخزن"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "آخر تحديث في"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "تبديل التنقل"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "موضوع كتاب أبو الهول"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "أقترح تحرير"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "افتح قضية"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "إطلاق"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "وضع ملء الشاشة"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "قم بتحرير هذه الصفحة"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "بواسطة"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "الصفحة التالية"
|
||||
BIN
_static/locales/bg/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/bg/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: bg\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Печат в PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Тема от"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Изтеглете изходния файл"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "отворен брой"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Съдържание"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "предишна страница"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Изтеглете файла на бележника"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Авторско право"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Изтеглете тази страница"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Хранилище на източника"
|
||||
|
||||
msgid "By"
|
||||
msgstr "От"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "хранилище"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Последна актуализация на"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Превключване на навигацията"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Тема на книгата Sphinx"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "предложи редактиране"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Отворете проблем"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Стартиране"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Режим на цял екран"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Редактирайте тази страница"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "По"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "Следваща страница"
|
||||
BIN
_static/locales/bn/LC_MESSAGES/booktheme.mo
Normal file
63
_static/locales/bn/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: bn\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "পিডিএফ প্রিন্ট করুন"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "থিম দ্বারা"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "উত্স ফাইল ডাউনলোড করুন"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "খোলা সমস্যা"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "আগের পৃষ্ঠা"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "নোটবুক ফাইল ডাউনলোড করুন"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "কপিরাইট"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "এই পৃষ্ঠাটি ডাউনলোড করুন"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "উত্স সংগ্রহস্থল"
|
||||
|
||||
msgid "By"
|
||||
msgstr "দ্বারা"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "সর্বশেষ আপডেট"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "নেভিগেশন টগল করুন"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "স্পিনিক্স বুক থিম"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "একটি সমস্যা খুলুন"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "শুরু করা"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "এই পৃষ্ঠাটি সম্পাদনা করুন"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "দ্বারা"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "পরবর্তী পৃষ্ঠা"
|
||||
BIN
_static/locales/ca/LC_MESSAGES/booktheme.mo
Normal file
66
_static/locales/ca/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ca\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Imprimeix a PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Tema del"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Baixeu el fitxer font"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "número obert"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "Pàgina anterior"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Descarregar fitxer de quadern"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Copyright"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Descarregueu aquesta pàgina"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Dipòsit de fonts"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Per"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Darrera actualització el"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Commuta la navegació"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Tema del llibre Esfinx"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "suggerir edició"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Obriu un número"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Llançament"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Editeu aquesta pàgina"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Per la"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "pàgina següent"
|
||||
BIN
_static/locales/cs/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/cs/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: cs\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Tisk do PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Téma od"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Stáhněte si zdrojový soubor"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "otevřené číslo"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Obsah"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "předchozí stránka"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Stáhnout soubor poznámkového bloku"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "autorská práva"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Stáhněte si tuto stránku"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Zdrojové úložiště"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Podle"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "úložiště"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Naposledy aktualizováno"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Přepnout navigaci"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Téma knihy Sfinga"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "navrhnout úpravy"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Otevřete problém"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Zahájení"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Režim celé obrazovky"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Upravit tuto stránku"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Podle"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "další strana"
|
||||
BIN
_static/locales/da/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/da/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: da\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Udskriv til PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Tema af"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Download kildefil"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "åbent nummer"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Indhold"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "forrige side"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Download notesbog-fil"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "ophavsret"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Download denne side"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Kildelager"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Ved"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "lager"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Sidst opdateret den"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Skift navigation"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Sphinx bogtema"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "foreslå redigering"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Åbn et problem"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Start"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Fuldskærmstilstand"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Rediger denne side"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Ved"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "Næste side"
|
||||
BIN
_static/locales/de/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/de/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: de\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "In PDF drucken"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Thema von der"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Quelldatei herunterladen"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "offenes Thema"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Inhalt"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "vorherige Seite"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Notebook-Datei herunterladen"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Urheberrechte ©"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Laden Sie diese Seite herunter"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Quell-Repository"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Durch"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "Repository"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Zuletzt aktualisiert am"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Navigation umschalten"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Sphinx-Buch-Thema"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "vorschlagen zu bearbeiten"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Öffnen Sie ein Problem"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Starten"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Vollbildmodus"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Bearbeite diese Seite"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Bis zum"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "Nächste Seite"
|
||||
BIN
_static/locales/el/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/el/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: el\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Εκτύπωση σε PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Θέμα από το"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Λήψη αρχείου προέλευσης"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "ανοιχτό ζήτημα"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Περιεχόμενα"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "προηγούμενη σελίδα"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Λήψη αρχείου σημειωματάριου"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Πνευματική ιδιοκτησία"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Λήψη αυτής της σελίδας"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Αποθήκη πηγής"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Με"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "αποθήκη"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Τελευταία ενημέρωση στις"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Εναλλαγή πλοήγησης"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Θέμα βιβλίου Sphinx"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "προτείνω επεξεργασία"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Ανοίξτε ένα ζήτημα"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Εκτόξευση"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "ΛΕΙΤΟΥΡΓΙΑ ΠΛΗΡΟΥΣ ΟΘΟΝΗΣ"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Επεξεργαστείτε αυτήν τη σελίδα"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Από το"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "επόμενη σελίδα"
|
||||
BIN
_static/locales/eo/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/eo/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: eo\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Presi al PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Temo de la"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Elŝutu fontodosieron"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "malferma numero"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Enhavo"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "antaŭa paĝo"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Elŝutu kajeran dosieron"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Kopirajto"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Elŝutu ĉi tiun paĝon"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Fonto-deponejo"
|
||||
|
||||
msgid "By"
|
||||
msgstr "De"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "deponejo"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Laste ĝisdatigita la"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Ŝalti navigadon"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Sfinksa Libro-Temo"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "sugesti redaktadon"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Malfermu numeron"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Lanĉo"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Plenekrana reĝimo"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Redaktu ĉi tiun paĝon"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Per la"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "sekva paĝo"
|
||||
BIN
_static/locales/es/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/es/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Imprimir en PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Tema por el"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Descargar archivo fuente"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "Tema abierto"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Contenido"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "pagina anterior"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Descargar archivo de cuaderno"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Derechos de autor"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Descarga esta pagina"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Repositorio de origen"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Por"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "repositorio"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Ultima actualización en"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Navegación de palanca"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Tema del libro de la esfinge"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "sugerir editar"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Abrir un problema"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Lanzamiento"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Modo de pantalla completa"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Edita esta página"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Por el"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "siguiente página"
|
||||
BIN
_static/locales/et/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/et/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: et\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Prindi PDF-i"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Teema"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Laadige alla lähtefail"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "avatud küsimus"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Sisu"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "eelmine leht"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Laadige sülearvuti fail alla"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Autoriõigus"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Laadige see leht alla"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Allikahoidla"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Kõrval"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "hoidla"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Viimati uuendatud"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Lülita navigeerimine sisse"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Sfinksiraamatu teema"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "soovita muuta"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Avage probleem"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Käivitage"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Täisekraanirežiim"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Muutke seda lehte"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Autor"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "järgmine leht"
|
||||
BIN
_static/locales/fi/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/fi/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fi\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Tulosta PDF-tiedostoon"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Teeman tekijä"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Lataa lähdetiedosto"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "avoin ongelma"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Sisällys"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "Edellinen sivu"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Lataa muistikirjatiedosto"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Tekijänoikeus"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Lataa tämä sivu"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Lähteen arkisto"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Tekijä"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "arkisto"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Viimeksi päivitetty"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Vaihda navigointia"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Sphinx-kirjan teema"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "ehdottaa muokkausta"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Avaa ongelma"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Tuoda markkinoille"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Koko näytön tila"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Muokkaa tätä sivua"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Mukaan"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "seuraava sivu"
|
||||
BIN
_static/locales/fr/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/fr/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Imprimer au format PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Thème par le"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Télécharger le fichier source"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "signaler un problème"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Contenu"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "page précédente"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Télécharger le fichier notebook"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "droits d'auteur"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Téléchargez cette page"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Dépôt source"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Par"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "dépôt"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Dernière mise à jour le"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Basculer la navigation"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Thème du livre Sphinx"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "suggestion de modification"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Ouvrez un problème"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "lancement"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Mode plein écran"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Modifier cette page"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Par le"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "page suivante"
|
||||
BIN
_static/locales/hr/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/hr/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: hr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Ispis u PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Tema autora"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Preuzmi izvornu datoteku"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "otvoreno izdanje"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Sadržaj"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "Prethodna stranica"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Preuzmi datoteku bilježnice"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Autorska prava"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Preuzmite ovu stranicu"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Izvorno spremište"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Po"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "spremište"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Posljednje ažuriranje:"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Uključi / isključi navigaciju"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Tema knjige Sphinx"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "predloži uređivanje"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Otvorite izdanje"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Pokrenite"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Način preko cijelog zaslona"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Uredite ovu stranicu"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Od strane"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "sljedeća stranica"
|
||||
BIN
_static/locales/id/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/id/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: id\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Cetak ke PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Tema oleh"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Unduh file sumber"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "masalah terbuka"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Isi"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "halaman sebelumnya"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Unduh file notebook"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "hak cipta"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Unduh halaman ini"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Repositori sumber"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Oleh"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "gudang"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Terakhir diperbarui saat"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Alihkan navigasi"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Tema Buku Sphinx"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "menyarankan edit"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Buka masalah"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Meluncurkan"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Mode layar penuh"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Edit halaman ini"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Oleh"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "halaman selanjutnya"
|
||||
BIN
_static/locales/it/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/it/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: it\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Stampa in PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Tema di"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Scarica il file sorgente"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "questione aperta"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Contenuti"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "pagina precedente"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Scarica il file del taccuino"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Diritto d'autore"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Scarica questa pagina"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Repository di origine"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Di"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "repository"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Ultimo aggiornamento il"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Attiva / disattiva la navigazione"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Tema del libro della Sfinge"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "suggerisci modifica"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Apri un problema"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Lanciare"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Modalità schermo intero"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Modifica questa pagina"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Dal"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "pagina successiva"
|
||||
BIN
_static/locales/iw/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/iw/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: iw\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "הדפס לקובץ PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "נושא מאת"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "הורד את קובץ המקור"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "בעיה פתוחה"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "תוכן"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "עמוד קודם"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "הורד קובץ מחברת"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "זכויות יוצרים"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "הורד דף זה"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "מאגר המקורות"
|
||||
|
||||
msgid "By"
|
||||
msgstr "על ידי"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "מאגר"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "עודכן לאחרונה ב"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "החלף ניווט"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "נושא ספר ספינקס"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "מציע לערוך"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "פתח גיליון"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "לְהַשִׁיק"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "מצב מסך מלא"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "ערוך דף זה"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "דרך"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "עמוד הבא"
|
||||
BIN
_static/locales/ja/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/ja/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ja\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "PDFに印刷"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "のテーマ"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "ソースファイルをダウンロード"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "未解決の問題"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "目次"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "前のページ"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "ノートブックファイルをダウンロード"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Copyright"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "このページをダウンロード"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "ソースリポジトリ"
|
||||
|
||||
msgid "By"
|
||||
msgstr "著者"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "リポジトリ"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "最終更新日"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "ナビゲーションを切り替え"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "スフィンクスの本のテーマ"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "編集を提案する"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "問題を報告"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "起動"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "全画面モード"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "このページを編集"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "によって"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "次のページ"
|
||||
BIN
_static/locales/ko/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/ko/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ko\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "PDF로 인쇄"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "테마별"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "소스 파일 다운로드"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "열린 문제"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "내용"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "이전 페이지"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "노트북 파일 다운로드"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "저작권"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "이 페이지 다운로드"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "소스 저장소"
|
||||
|
||||
msgid "By"
|
||||
msgstr "으로"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "저장소"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "마지막 업데이트"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "탐색 전환"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "스핑크스 도서 테마"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "편집 제안"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "이슈 열기"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "시작하다"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "전체 화면으로보기"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "이 페이지 편집"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "에 의해"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "다음 페이지"
|
||||
BIN
_static/locales/lt/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/lt/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: lt\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Spausdinti į PDF"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Tema"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Atsisiųsti šaltinio failą"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "atviras klausimas"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Turinys"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "Ankstesnis puslapis"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Atsisiųsti nešiojamojo kompiuterio failą"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Autorių teisės"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Atsisiųskite šį puslapį"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Šaltinio saugykla"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Iki"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "saugykla"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Paskutinį kartą atnaujinta"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Perjungti naršymą"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Sfinkso knygos tema"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "pasiūlyti redaguoti"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Atidarykite problemą"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Paleiskite"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Pilno ekrano režimas"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Redaguoti šį puslapį"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Prie"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "Kitas puslapis"
|
||||
BIN
_static/locales/lv/LC_MESSAGES/booktheme.mo
Normal file
75
_static/locales/lv/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: lv\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "Drukāt PDF formātā"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "Autora tēma"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "Lejupielādēt avota failu"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "atklāts jautājums"
|
||||
|
||||
msgid "Contents"
|
||||
msgstr "Saturs"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "iepriekšējā lapa"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "Lejupielādēt piezīmju grāmatiņu"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "Autortiesības"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "Lejupielādējiet šo lapu"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "Avota krātuve"
|
||||
|
||||
msgid "By"
|
||||
msgstr "Autors"
|
||||
|
||||
msgid "repository"
|
||||
msgstr "krātuve"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "Pēdējoreiz atjaunināts"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Pārslēgt navigāciju"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "Sfinksa grāmatas tēma"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "ieteikt rediģēt"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "Atveriet problēmu"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "Uzsākt"
|
||||
|
||||
msgid "Fullscreen mode"
|
||||
msgstr "Pilnekrāna režīms"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "Rediģēt šo lapu"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "Ar"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "nākamā lapaspuse"
|
||||
BIN
_static/locales/ml/LC_MESSAGES/booktheme.mo
Normal file
66
_static/locales/ml/LC_MESSAGES/booktheme.po
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx-Book-Theme\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ml\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Print to PDF"
|
||||
msgstr "PDF- ലേക്ക് പ്രിന്റുചെയ്യുക"
|
||||
|
||||
msgid "Theme by the"
|
||||
msgstr "പ്രമേയം"
|
||||
|
||||
msgid "Download source file"
|
||||
msgstr "ഉറവിട ഫയൽ ഡൗൺലോഡുചെയ്യുക"
|
||||
|
||||
msgid "open issue"
|
||||
msgstr "തുറന്ന പ്രശ്നം"
|
||||
|
||||
msgid "previous page"
|
||||
msgstr "മുൻപത്തെ താൾ"
|
||||
|
||||
msgid "Download notebook file"
|
||||
msgstr "നോട്ട്ബുക്ക് ഫയൽ ഡൺലോഡ് ചെയ്യുക"
|
||||
|
||||
msgid "Copyright"
|
||||
msgstr "പകർപ്പവകാശം"
|
||||
|
||||
msgid "Download this page"
|
||||
msgstr "ഈ പേജ് ഡൗൺലോഡുചെയ്യുക"
|
||||
|
||||
msgid "Source repository"
|
||||
msgstr "ഉറവിട ശേഖരം"
|
||||
|
||||
msgid "By"
|
||||
msgstr "എഴുതിയത്"
|
||||
|
||||
msgid "Last updated on"
|
||||
msgstr "അവസാനം അപ്ഡേറ്റുചെയ്തത്"
|
||||
|
||||
msgid "Toggle navigation"
|
||||
msgstr "നാവിഗേഷൻ ടോഗിൾ ചെയ്യുക"
|
||||
|
||||
msgid "Sphinx Book Theme"
|
||||
msgstr "സ്ഫിങ്ക്സ് പുസ്തക തീം"
|
||||
|
||||
msgid "suggest edit"
|
||||
msgstr "എഡിറ്റുചെയ്യാൻ നിർദ്ദേശിക്കുക"
|
||||
|
||||
msgid "Open an issue"
|
||||
msgstr "ഒരു പ്രശ്നം തുറക്കുക"
|
||||
|
||||
msgid "Launch"
|
||||
msgstr "സമാരംഭിക്കുക"
|
||||
|
||||
msgid "Edit this page"
|
||||
msgstr "ഈ പേജ് എഡിറ്റുചെയ്യുക"
|
||||
|
||||
msgid "By the"
|
||||
msgstr "എഴുതിയത്"
|
||||
|
||||
msgid "next page"
|
||||
msgstr "അടുത്ത പേജ്"
|
||||