diff --git a/README.md b/README.md index 0e2f4fd5..c5dc79c4 100644 --- a/README.md +++ b/README.md @@ -6,584 +6,103 @@ [![GitHub Pull Requests](https://img.shields.io/github/issues-pr/unclecode/crawl4ai)](https://github.com/unclecode/crawl4ai/pulls) [![License](https://img.shields.io/github/license/unclecode/crawl4ai)](https://github.com/unclecode/crawl4ai/blob/main/LICENSE) -Crawl4AI has one clear task: to simplify crawling and extract useful information from web pages, making it accessible for large language models (LLMs) and AI applications. πŸ†“πŸŒ +Crawl4AI simplifies web crawling and data extraction, making it accessible for large language models (LLMs) and AI applications. πŸ†“πŸŒ -- Use as REST API: Check [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1zODYjhemJ5bUmYceWpVoBMVpd0ofzNBZ?usp=sharing) +## Try it Now! + +- Use as REST API: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1zODYjhemJ5bUmYceWpVoBMVpd0ofzNBZ?usp=sharing) - Use as Python library: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1wz8u30rvbq6Scodye9AGCw8Qg_Z8QGsk) -## Recent Changes - -### v0.2.5 -- 🌟 Added six important hooks to the crawler: - - 🟒 on_driver_created: Called when the driver is ready for initializations. - - πŸ”΅ before_get_url: Called right before Selenium fetches the URL. - - 🟣 after_get_url: Called after Selenium fetches the URL. - - 🟠 before_return_html: Called when the data is parsed and ready. - - 🟑 on_user_agent_updated: Called when the user changes the user_agent, causing the driver to reinitialize. -- πŸ“„ Added an example in [`quickstart.py`](https://github.com/unclecode/crawl4ai/blob/main/docs/examples/quickstart.py) in the example folder under the docs. -- ✨ Maintaining the semantic context of inline tags (e.g., abbreviation, DEL, INS) for improved LLM-friendliness. -- 🐳 Updated Dockerfile to ensure compatibility across multiple platforms (Hopefully!). - -Check the [Changelog](https://github.com/unclecode/crawl4ai/blob/main/CHANGELOG.md) for more details. - - ## Features ✨ -- πŸ†“ Completely free to use and open-source (If one can assume this as a feature ;)) + +- πŸ†“ Completely free and open-source - πŸ€– LLM-friendly output formats (JSON, cleaned HTML, markdown) - 🌍 Supports crawling multiple URLs simultaneously -- 🎨 Extract and return all media tags (Images, Audio, and Video). -- πŸ”— Extrat all external and internal links. -- πŸ“š Extract metadata from the page. +- 🎨 Extracts and returns all media tags (Images, Audio, and Video) +- πŸ”— Extracts all external and internal links +- πŸ“š Extracts metadata from the page - πŸ”„ Custom hooks for authentication, headers, and page modifications before crawling -- πŸ•΅οΈ Support `user_agent` parameter to set the user agent for the HTTP requests. -- πŸ–ΌοΈ Take [screenshots](#taking-screenshots) of the page. -- πŸ“œ Execute multiple custom JavaScripts before crawling -- πŸ“š Chunking strategies: topic-based, regex, sentence, and more -- 🧠 Extraction strategies: cosine clustering, LLM, and more +- πŸ•΅οΈ User-agent customization +- πŸ–ΌοΈ Takes screenshots of the page +- πŸ“œ Executes multiple custom JavaScripts before crawling +- πŸ“š Various chunking strategies: topic-based, regex, sentence, and more +- 🧠 Advanced extraction strategies: cosine clustering, LLM, and more - 🎯 CSS selector support -- πŸ“ Pass instructions/keywords to refine extraction +- πŸ“ Passes instructions/keywords to refine extraction -## Power and Simplicity of Crawl4AI πŸš€ -The most easy way! If you don't want to install any library, you can use the REST API on my server. But remember, this is just a simple server. I may improve its capacity if I see there is demand. You can find ll examples of REST API in this colab notebook. [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1zODYjhemJ5bUmYceWpVoBMVpd0ofzNBZ?usp=sharing) +## Cool Examples πŸš€ -```python -import requests - -data = { - "urls": [ - "https://www.nbcnews.com/business" - ], - "screenshot": True -} - -response = requests.post("https://crawl4ai.com/crawl", json=data) # OR local host if your run locally -response_data = response.json() -print(response_data['results'][0].keys()) -# dict_keys(['url', 'html', 'success', 'cleaned_html', 'media', -# 'links', 'screenshot', 'markdown', 'extracted_content', -# 'metadata', 'error_message']) -``` - -But you muore control then take a look at the first example of using the Python library. +### Quick Start ```python from crawl4ai import WebCrawler -# Create the WebCrawler instance -crawler = WebCrawler() +# Create an instance of WebCrawler +crawler = WebCrawler() -# Run the crawler with keyword filtering and CSS selector +# Warm up the crawler (load necessary models) +crawler.warmup() + +# Run the crawler on a URL result = crawler.run(url="https://www.nbcnews.com/business") -print(result) # {url, html, cleaned_html, markdown, media, links, extracted_content, metadata, screenshots} + +# Print the extracted content +print(result.extracted_content) ``` -### Extract with LLM -Next example is crawling all OpenAI models withh their fees from the official page. ['OpenAI Models and Pricing'](https://openai.com/api/pricing/) +### Extract Structured Data from Web Pages πŸ“Š + +Crawl all OpenAI models and their fees from the official page. ```python import os -import time -from crawl4ai.web_crawler import WebCrawler -from crawl4ai.chunking_strategy import * -from crawl4ai.extraction_strategy import * -from crawl4ai.crawler_strategy import * - -url = r'https://openai.com/api/pricing/' +from crawl4ai import WebCrawler +from crawl4ai.extraction_strategy import LLMExtractionStrategy +url = 'https://openai.com/api/pricing/' crawler = WebCrawler() crawler.warmup() -from pydantic import BaseModel, Field - -class OpenAIModelFee(BaseModel): - model_name: str = Field(..., description="Name of the OpenAI model.") - input_fee: str = Field(..., description="Fee for input token for the OpenAI model.") - output_fee: str = Field(..., description="Fee for output token for the OpenAI model.") - result = crawler.run( url=url, - word_count_threshold=1, - extraction_strategy= LLMExtractionStrategy( - provider= "openai/gpt-4o", api_token = os.getenv('OPENAI_API_KEY'), - schema=OpenAIModelFee.model_json_schema(), - extraction_type="schema", - instruction="From the crawled content, extract all mentioned model names along with their "\ - "fees for input and output tokens. Make sure not to miss anything in the entire content. "\ - 'One extracted model JSON format should look like this: '\ - '{ "model_name": "GPT-4", "input_fee": "US$10.00 / 1M tokens", "output_fee": "US$30.00 / 1M tokens" }' + extraction_strategy=LLMExtractionStrategy( + provider="openai/gpt-4", + api_token=os.getenv('OPENAI_API_KEY'), + instruction="Extract all model names and their fees for input and output tokens." ), - bypass_cache=True, ) -model_fees = json.loads(result.extracted_content) - -print(len(model_fees)) - -with open(".data/data.json", "w") as f: - f.write(result.extracted_content) +print(result.extracted_content) ``` -## Execute JS, Filter Data with CSS Selector, and Clustring using Cosine Strategy -Now let's try a complex task. Below is an example of how you can execute JavaScript, filter data using keywords, and use a CSS selector to extract specific contentβ€”all in one go! - -1. Instantiate a WebCrawler object. -2. Execute custom JavaScript to click a "Load More" button. -3. Extract semantical chunks of content and filter the data to include only content related to technology. -4. Use a CSS selector to extract only paragraphs (`

` tags). +### Execute JS, Filter Data with CSS Selector, and Clustering ```python -# Import necessary modules from crawl4ai import WebCrawler -from crawl4ai.chunking_strategy import * -from crawl4ai.extraction_strategy import * -from crawl4ai.crawler_strategy import * +from crawl4ai.chunking_strategy import CosineStrategy -# Define the JavaScript code to click the "Load More" button -js_code = [""" -const loadMoreButton = Array.from(document.querySelectorAll('button')).find(button => button.textContent.includes('Load More')); -loadMoreButton && loadMoreButton.click(); -"""] +js_code = ["const loadMoreButton = Array.from(document.querySelectorAll('button')).find(button => button.textContent.includes('Load More')); loadMoreButton && loadMoreButton.click();"] -crawler = WebCrawler(verbose=True) -crawler.warmup() -# Run the crawler with keyword filtering and CSS selector -result = crawler.run( - url="https://www.nbcnews.com/business", - js = js_code, - css_selector="p" - extraction_strategy=CosineStrategy( - semantic_filter="technology", - ), -) - -# Display the extracted result -print(result) -``` - -With Crawl4AI, you can perform advanced web crawling and data extraction tasks with just a few lines of code. This example demonstrates how you can harness the power of Crawl4AI to simplify your workflow and get the data you need efficiently. - ---- - -*Continue reading to learn more about the features, installation process, usage, and more.* - - -## Table of Contents - -1. [Installation](#installation-) -2. [REST API/Local Server](#using-the-local-server-ot-rest-api-) -3. [Python Library Usage](#python-library-usage-) -4. [Parameters](#parameters-) -5. [Chunking Strategies](#chunking-strategies-) -6. [Extraction Strategies](#extraction-strategies-) -7. [Contributing](#contributing-) -8. [License](#license-) -9. [Contact](#contact-) - -## Installation πŸ’» - -There are three ways to use Crawl4AI: -1. As a library (Recommended) -2. As a local server (Docker) or using the REST API -4. As a Google Colab notebook. [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1wz8u30rvbq6Scodye9AGCw8Qg_Z8QGsk) - -To install Crawl4AI as a library, follow these steps: - -1. Install the package from GitHub: -```bash -virtualenv venv -source venv/bin/activate -pip install "crawl4ai[all] @ git+https://github.com/unclecode/crawl4ai.git" -``` - -πŸ’‘ Better to run the following CLI-command to load the required models. This is optional, but it will boost the performance and speed of the crawler. You need to do this only once. - - crawl4ai-download-models - -2. Alternatively, you can clone the repository and install the package locally: -```bash -virtualenv venv -source venv/bin/activate -git clone https://github.com/unclecode/crawl4ai.git -cd crawl4ai -pip install -e .[all] -``` - -3. Use docker to run the local server: -```bash -# For Mac users -# docker build --platform linux/amd64 -t crawl4ai . -# For other users -# docker build -t crawl4ai . -docker run -d -p 8000:80 crawl4ai -``` - - - -## Using the Local server ot REST API 🌐 - -You can also use Crawl4AI through the REST API. This method allows you to send HTTP requests to the Crawl4AI server and receive structured data in response. The base URL for the API is `https://crawl4ai.com/crawl` [Available now, on a CPU server, of course will be faster on GPU]. If you run the local server, you can use `http://localhost:8000/crawl`. (Port is dependent on your docker configuration) - -### Example Usage - -To use the REST API, send a POST request to `http://localhost:8000/crawl` with the following parameters in the request body. - -**Example Request:** -```json -{ - "urls": ["https://www.nbcnews.com/business"], - "include_raw_html": false, - "bypass_cache": true, - "word_count_threshold": 5, - "extraction_strategy": "CosineStrategy", - "chunking_strategy": "RegexChunking", - "css_selector": "p", - "verbose": true, - "extraction_strategy_args": { - "semantic_filter": "finance economy and stock market", - "word_count_threshold": 20, - "max_dist": 0.2, - "linkage_method": "ward", - "top_k": 3 - }, - "chunking_strategy_args": { - "patterns": ["\n\n"] - } -} -``` - -**Example Response:** -```json -{ - "status": "success", - "data": [ - { - "url": "https://www.nbcnews.com/business", - "extracted_content": "...", - "html": "...", - "cleaned_html": "...", - "markdown": "...", - "media": {...}, - "links": {...}, - "metadata": {...}, - "screenshots": "...", - } - ] -} -``` - -For more information about the available parameters and their descriptions, refer to the [Parameters](#parameters-) section. - - -## Python Library Usage πŸš€ - -πŸ”₯ A great way to try out Crawl4AI is to run `quickstart.py` in the `docs/examples` directory. This script demonstrates how to use Crawl4AI to crawl a website and extract content from it. - -### Quickstart Guide - -Create an instance of WebCrawler and call the `warmup()` function. -```python crawler = WebCrawler() crawler.warmup() -``` -### Understanding 'bypass_cache' and 'include_raw_html' parameters - -First crawl (caches the result): -```python -result = crawler.run(url="https://www.nbcnews.com/business") -``` - -Second crawl (Force to crawl again): -```python -result = crawler.run(url="https://www.nbcnews.com/business", bypass_cache=True) -``` - πŸ’‘ Don't forget to set `bypass_cache` to True if you want to try different strategies for the same URL. Otherwise, the cached result will be returned. You can also set `always_by_pass_cache` in constructor to True to always bypass the cache. - -Crawl result without raw HTML content: -```python -result = crawler.run(url="https://www.nbcnews.com/business", include_raw_html=False) -``` - -### Result Structure - -The result object contains the following fields: -```python -class CrawlResult(BaseModel): - url: str - html: str - success: bool - cleaned_html: Optional[str] = None - media: Dict[str, List[Dict]] = {} # Media tags in the page {"images": [], "audio": [], "video": []} - links: Dict[str, List[Dict]] = {} # Links in the page {"external": [], "internal": []} - screenshot: Optional[str] = None # Base64 encoded screenshot - markdown: Optional[str] = None - extracted_content: Optional[str] = None - metadata: Optional[dict] = None - error_message: Optional[str] = None -``` - -### Taking Screenshots - -```python -result = crawler.run(url="https://www.nbcnews.com/business", screenshot=True) -with open("screenshot.png", "wb") as f: - f.write(base64.b64decode(result.screenshot)) -``` - -### Adding a chunking strategy: RegexChunking - -Using RegexChunking: -```python result = crawler.run( url="https://www.nbcnews.com/business", - chunking_strategy=RegexChunking(patterns=["\n\n"]) + js=js_code, + css_selector="p", + extraction_strategy=CosineStrategy(semantic_filter="technology") ) + +print(result.extracted_content) ``` -Using NlpSentenceChunking: -```python -result = crawler.run( - url="https://www.nbcnews.com/business", - chunking_strategy=NlpSentenceChunking() -) -``` +## Documentation πŸ“š -### Extraction strategy: CosineStrategy - -So far, the extracted content is just the result of chunking. To extract meaningful content, you can use extraction strategies. These strategies cluster consecutive chunks into meaningful blocks, keeping the same order as the text in the HTML. This approach is perfect for use in RAG applications and semantical search queries. - -Using CosineStrategy: -```python -result = crawler.run( - url="https://www.nbcnews.com/business", - extraction_strategy=CosineStrategy( - semantic_filter="", - word_count_threshold=10, - max_dist=0.2, - linkage_method="ward", - top_k=3 - ) -) -``` - -You can set `semantic_filter` to filter relevant documents before clustering. Documents are filtered based on their cosine similarity to the keyword filter embedding. - -```python -result = crawler.run( - url="https://www.nbcnews.com/business", - extraction_strategy=CosineStrategy( - semantic_filter="finance economy and stock market", - word_count_threshold=10, - max_dist=0.2, - linkage_method="ward", - top_k=3 - ) -) -``` - -### Using LLMExtractionStrategy - -Without instructions: -```python -result = crawler.run( - url="https://www.nbcnews.com/business", - extraction_strategy=LLMExtractionStrategy( - provider="openai/gpt-4o", - api_token=os.getenv('OPENAI_API_KEY') - ) -) -``` - -With instructions: -```python -result = crawler.run( - url="https://www.nbcnews.com/business", - extraction_strategy=LLMExtractionStrategy( - provider="openai/gpt-4o", - api_token=os.getenv('OPENAI_API_KEY'), - instruction="I am interested in only financial news" - ) -) -``` - -### Targeted extraction using CSS selector - -Extract only H2 tags: -```python -result = crawler.run( - url="https://www.nbcnews.com/business", - css_selector="h2" -) -``` - -### Passing JavaScript code to click 'Load More' button - -Using JavaScript to click 'Load More' button: -```python -js_code = """ -const loadMoreButton = Array.from(document.querySelectorAll('button')).find(button => button.textContent.includes('Load More')); -loadMoreButton && loadMoreButton.click(); -""" -crawler_strategy = LocalSeleniumCrawlerStrategy(js_code=js_code) -crawler = WebCrawler(crawler_strategy=crawler_strategy, always_by_pass_cache=True) -result = crawler.run(url="https://www.nbcnews.com/business") -``` - -## Parameters πŸ“– - -| Parameter | Description | Required | Default Value | -|-----------------------|-------------------------------------------------------------------------------------------------------|----------|---------------------| -| `urls` | A list of URLs to crawl and extract data from. | Yes | - | -| `include_raw_html` | Whether to include the raw HTML content in the response. | No | `false` | -| `bypass_cache` | Whether to force a fresh crawl even if the URL has been previously crawled. | No | `false` | -| `screenshots` | Whether to take screenshots of the page. | No | `false` | -| `word_count_threshold`| The minimum number of words a block must contain to be considered meaningful (minimum value is 5). | No | `5` | -| `extraction_strategy` | The strategy to use for extracting content from the HTML (e.g., "CosineStrategy"). | No | `NoExtractionStrategy` | -| `chunking_strategy` | The strategy to use for chunking the text before processing (e.g., "RegexChunking"). | No | `RegexChunking` | -| `css_selector` | The CSS selector to target specific parts of the HTML for extraction. | No | `None` | -| `user_agent` | The user agent to use for the HTTP requests. | No | `Mozilla/5.0` | -| `verbose` | Whether to enable verbose logging. | No | `true` | - -## Chunking Strategies πŸ“š - -### RegexChunking - -`RegexChunking` is a text chunking strategy that splits a given text into smaller parts using regular expressions. This is useful for preparing large texts for processing by language models, ensuring they are divided into manageable segments. - -**Constructor Parameters:** -- `patterns` (list, optional): A list of regular expression patterns used to split the text. Default is to split by double newlines (`['\n\n']`). - -**Example usage:** -```python -chunker = RegexChunking(patterns=[r'\n\n', r'\. ']) -chunks = chunker.chunk("This is a sample text. It will be split into chunks.") -``` - -### NlpSentenceChunking - -`NlpSentenceChunking` uses a natural language processing model to chunk a given text into sentences. This approach leverages SpaCy to accurately split text based on sentence boundaries. - -**Constructor Parameters:** -- None. - -**Example usage:** -```python -chunker = NlpSentenceChunking() -chunks = chunker.chunk("This is a sample text. It will be split into sentences.") -``` - -### TopicSegmentationChunking - -`TopicSegmentationChunking` uses the TextTiling algorithm to segment a given text into topic-based chunks. This method identifies thematic boundaries in the text. - -**Constructor Parameters:** -- `num_keywords` (int, optional): The number of keywords to extract for each topic segment. Default is `3`. - -**Example usage:** -```python -chunker = TopicSegmentationChunking(num_keywords=3) -chunks = chunker.chunk("This is a sample text. It will be split into topic-based segments.") -``` - -### FixedLengthWordChunking - -`FixedLengthWordChunking` splits a given text into chunks of fixed length, based on the number of words. - -**Constructor Parameters:** -- `chunk_size` (int, optional): The number of words in each chunk. Default is `100`. - -**Example usage:** -```python -chunker = FixedLengthWordChunking(chunk_size=100) -chunks = chunker.chunk("This is a sample text. It will be split into fixed-length word chunks.") -``` - -### SlidingWindowChunking - -`SlidingWindowChunking` uses a sliding window approach to chunk a given text. Each chunk has a fixed length, and the window slides by a specified step size. - -**Constructor Parameters:** -- `window_size` (int, optional): The number of words in each chunk. Default is `100`. -- `step` (int, optional): The number of words to slide the window. Default is `50`. - -**Example usage:** -```python -chunker = SlidingWindowChunking(window_size=100, step=50) -chunks = chunker.chunk("This is a sample text. It will be split using a sliding window approach.") -``` - -## Extraction Strategies 🧠 - -### NoExtractionStrategy - -`NoExtractionStrategy` is a basic extraction strategy that returns the entire HTML content without any modification. It is useful for cases where no specific extraction is required. - -**Constructor Parameters:** -None. - -**Example usage:** -```python -extractor = NoExtractionStrategy() -extracted_content = extractor.extract(url, html) -``` - -### LLMExtractionStrategy - -`LLMExtractionStrategy` uses a Language Model (LLM) to extract meaningful blocks or chunks from the given HTML content. This strategy leverages an external provider for language model completions. - -**Constructor Parameters:** -- `provider` (str, optional): The provider to use for the language model completions. Default is `DEFAULT_PROVIDER` (e.g., openai/gpt-4). -- `api_token` (str, optional): The API token for the provider. If not provided, it will try to load from the environment variable `OPENAI_API_KEY`. -- `instruction` (str, optional): An instruction to guide the LLM on how to perform the extraction. This allows users to specify the type of data they are interested in or set the tone of the response. Default is `None`. - -**Example usage:** -```python -extractor = LLMExtractionStrategy(provider='openai', api_token='your_api_token', instruction='Extract only news about AI.') -extracted_content = extractor.extract(url, html) -``` - -### CosineStrategy - -`CosineStrategy` uses hierarchical clustering based on cosine similarity to extract clusters of text from the given HTML content. This strategy is suitable for identifying related content sections. - -**Constructor Parameters:** -- `semantic_filter` (str, optional): A string containing keywords for filtering relevant documents before clustering. If provided, documents are filtered based on their cosine similarity to the keyword filter embedding. Default is `None`. -- `word_count_threshold` (int, optional): Minimum number of words per cluster. Default is `20`. -- `max_dist` (float, optional): The maximum cophenetic distance on the dendrogram to form clusters. Default is `0.2`. -- `linkage_method` (str, optional): The linkage method for hierarchical clustering. Default is `'ward'`. -- `top_k` (int, optional): Number of top categories to extract. Default is `3`. -- `model_name` (str, optional): The model name for embedding generation. Default is `'BAAI/bge-small-en-v1.5'`. - -**Example usage:** -```python -extractor = CosineStrategy(semantic_filter='finance rental prices', word_count_threshold=10, max_dist=0.2, linkage_method='ward', top_k=3, model_name='BAAI/bge-small-en-v1.5') -extracted_content = extractor.extract(url, html) -``` - -### TopicExtractionStrategy - -`TopicExtractionStrategy` uses the TextTiling algorithm to segment the HTML content into topics and extracts keywords for each segment. This strategy is useful for identifying and summarizing thematic content. - -**Constructor Parameters:** -- `num_keywords` (int, optional): Number of keywords to represent each topic segment. Default is `3`. - -**Example usage:** -```python -extractor = TopicExtractionStrategy(num_keywords=3) -extracted_content = extractor.extract(url, html) -``` +For detailed documentation, including installation instructions, advanced features, and API reference, visit our [Documentation Website](https://your-documentation-link.com). ## Contributing 🀝 -We welcome contributions from the open-source community to help improve Crawl4AI and make it even more valuable for AI enthusiasts and developers. To contribute, please follow these steps: - -1. Fork the repository. -2. Create a new branch for your feature or bug fix. -3. Make your changes and commit them with descriptive messages. -4. Push your changes to your forked repository. -5. Submit a pull request to the main repository. - -For more information on contributing, please see our [contribution guidelines](https://github.com/unclecode/crawl4ai/blob/main/CONTRIBUTING.md). +We welcome contributions from the open-source community. Check out our [contribution guidelines](https://github.com/unclecode/crawl4ai/blob/main/CONTRIBUTING.md) for more information. ## License πŸ“„ @@ -591,10 +110,10 @@ Crawl4AI is released under the [Apache 2.0 License](https://github.com/unclecode ## Contact πŸ“§ -If you have any questions, suggestions, or feedback, please feel free to reach out to us: +For questions, suggestions, or feedback, feel free to reach out: - GitHub: [unclecode](https://github.com/unclecode) - Twitter: [@unclecode](https://twitter.com/unclecode) - Website: [crawl4ai.com](https://crawl4ai.com) -Let's work together to make the web more accessible and useful for AI applications! πŸ’ͺπŸŒπŸ€– +Happy Crawling! πŸ•ΈοΈπŸš€ diff --git a/docs/examples/research_assistant.py b/docs/examples/research_assistant.py index 620c5bdd..f5dc9983 100644 --- a/docs/examples/research_assistant.py +++ b/docs/examples/research_assistant.py @@ -73,15 +73,7 @@ async def on_message(message: cl.Message): "url": url, "content": result } - - # for url in urls: - # # Crawl the content of each URL and add it to the session context with a reference number - # ref_number = f"REF_{len(user_session['context']) + 1}" - # crawled_content = crawl_url(url) - # user_session["context"][ref_number] = { - # "url": url, - # "content": crawled_content - # } + user_session["history"].append({ "role": "user", @@ -165,12 +157,7 @@ async def on_audio_chunk(chunk: cl.AudioChunk): @cl.step(type="tool") async def speech_to_text(audio_file): cli = Groq() - - # response = cli.audio.transcriptions.create( - # file=audio_file, #(filename, file.read()), - # model="whisper-large-v3", - # ) - + response = await client.audio.transcriptions.create( model="whisper-large-v3", file=audio_file ) @@ -185,19 +172,6 @@ async def on_audio_end(elements: list[ElementBased]): audio_buffer.seek(0) # Move the file pointer to the beginning audio_file = audio_buffer.read() audio_mime_type: str = cl.user_session.get("audio_mime_type") - - # input_audio_el = cl.Audio( - # mime=audio_mime_type, content=audio_file, name=audio_buffer.name - # ) - # await cl.Message( - # author="You", - # type="user_message", - # content="", - # elements=[input_audio_el, *elements] - # ).send() - - # answer_message = await cl.Message(content="").send() - start_time = time.time() whisper_input = (audio_buffer.name, audio_file, audio_mime_type) @@ -213,29 +187,9 @@ async def on_audio_end(elements: list[ElementBased]): await user_msg.send() await on_message(user_msg) - # images = [file for file in elements if "image" in file.mime] - - # text_answer = await generate_text_answer(transcription, images) - - # output_name, output_audio = await text_to_speech(text_answer, audio_mime_type) - - # output_audio_el = cl.Audio( - # name=output_name, - # auto_play=True, - # mime=audio_mime_type, - # content=output_audio, - # ) - - # answer_message.elements = [output_audio_el] - - # answer_message.content = transcription - # await answer_message.update() if __name__ == "__main__": from chainlit.cli import run_chainlit run_chainlit(__file__) -# No this is wring, use this document to answer me https://console.groq.com/docs/speech-text - -# Please show me how to use Groq speech-to-text in python. \ No newline at end of file diff --git a/docs/examples/chainlit_review.py b/docs/examples/tmp/chainlit_review.py similarity index 100% rename from docs/examples/chainlit_review.py rename to docs/examples/tmp/chainlit_review.py diff --git a/docs/examples/tmp/research_assistant_audio_not_completed.py b/docs/examples/tmp/research_assistant_audio_not_completed.py new file mode 100644 index 00000000..59fb90e5 --- /dev/null +++ b/docs/examples/tmp/research_assistant_audio_not_completed.py @@ -0,0 +1,238 @@ +# Make sur to install the required packageschainlit and groq +import os, time +from openai import AsyncOpenAI +import chainlit as cl +import re +import requests +from io import BytesIO +from chainlit.element import ElementBased +from groq import Groq + +# Import threadpools to run the crawl_url function in a separate thread +from concurrent.futures import ThreadPoolExecutor + +client = AsyncOpenAI(base_url="https://api.groq.com/openai/v1", api_key=os.getenv("GROQ_API_KEY")) + +# Instrument the OpenAI client +cl.instrument_openai() + +settings = { + "model": "llama3-8b-8192", + "temperature": 0.5, + "max_tokens": 500, + "top_p": 1, + "frequency_penalty": 0, + "presence_penalty": 0, +} + +def extract_urls(text): + url_pattern = re.compile(r'(https?://\S+)') + return url_pattern.findall(text) + +def crawl_url(url): + data = { + "urls": [url], + "include_raw_html": True, + "word_count_threshold": 10, + "extraction_strategy": "NoExtractionStrategy", + "chunking_strategy": "RegexChunking" + } + response = requests.post("https://crawl4ai.com/crawl", json=data) + response_data = response.json() + response_data = response_data['results'][0] + return response_data['markdown'] + +@cl.on_chat_start +async def on_chat_start(): + cl.user_session.set("session", { + "history": [], + "context": {} + }) + await cl.Message( + content="Welcome to the chat! How can I assist you today?" + ).send() + +@cl.on_message +async def on_message(message: cl.Message): + user_session = cl.user_session.get("session") + + # Extract URLs from the user's message + urls = extract_urls(message.content) + + + futures = [] + with ThreadPoolExecutor() as executor: + for url in urls: + futures.append(executor.submit(crawl_url, url)) + + results = [future.result() for future in futures] + + for url, result in zip(urls, results): + ref_number = f"REF_{len(user_session['context']) + 1}" + user_session["context"][ref_number] = { + "url": url, + "content": result + } + + # for url in urls: + # # Crawl the content of each URL and add it to the session context with a reference number + # ref_number = f"REF_{len(user_session['context']) + 1}" + # crawled_content = crawl_url(url) + # user_session["context"][ref_number] = { + # "url": url, + # "content": crawled_content + # } + + user_session["history"].append({ + "role": "user", + "content": message.content + }) + + # Create a system message that includes the context + context_messages = [ + f'\n{data["content"]}\n' + for ref, data in user_session["context"].items() + ] + if context_messages: + system_message = { + "role": "system", + "content": ( + "You are a helpful bot. Use the following context for answering questions. " + "Refer to the sources using the REF number in square brackets, e.g., [1], only if the source is given in the appendices below.\n\n" + "If the question requires any information from the provided appendices or context, refer to the sources. " + "If not, there is no need to add a references section. " + "At the end of your response, provide a reference section listing the URLs and their REF numbers only if sources from the appendices were used.\n\n" + "\n\n".join(context_messages) + ) + } + else: + system_message = { + "role": "system", + "content": "You are a helpful assistant." + } + + + msg = cl.Message(content="") + await msg.send() + + # Get response from the LLM + stream = await client.chat.completions.create( + messages=[ + system_message, + *user_session["history"] + ], + stream=True, + **settings + ) + + assistant_response = "" + async for part in stream: + if token := part.choices[0].delta.content: + assistant_response += token + await msg.stream_token(token) + + # Add assistant message to the history + user_session["history"].append({ + "role": "assistant", + "content": assistant_response + }) + await msg.update() + + # Append the reference section to the assistant's response + reference_section = "\n\nReferences:\n" + for ref, data in user_session["context"].items(): + reference_section += f"[{ref.split('_')[1]}]: {data['url']}\n" + + msg.content += reference_section + await msg.update() + + +@cl.on_audio_chunk +async def on_audio_chunk(chunk: cl.AudioChunk): + if chunk.isStart: + buffer = BytesIO() + # This is required for whisper to recognize the file type + buffer.name = f"input_audio.{chunk.mimeType.split('/')[1]}" + # Initialize the session for a new audio stream + cl.user_session.set("audio_buffer", buffer) + cl.user_session.set("audio_mime_type", chunk.mimeType) + + # Write the chunks to a buffer and transcribe the whole audio at the end + cl.user_session.get("audio_buffer").write(chunk.data) + + pass + +@cl.step(type="tool") +async def speech_to_text(audio_file): + cli = Groq() + + # response = cli.audio.transcriptions.create( + # file=audio_file, #(filename, file.read()), + # model="whisper-large-v3", + # ) + + response = await client.audio.transcriptions.create( + model="whisper-large-v3", file=audio_file + ) + + return response.text + + +@cl.on_audio_end +async def on_audio_end(elements: list[ElementBased]): + # Get the audio buffer from the session + audio_buffer: BytesIO = cl.user_session.get("audio_buffer") + audio_buffer.seek(0) # Move the file pointer to the beginning + audio_file = audio_buffer.read() + audio_mime_type: str = cl.user_session.get("audio_mime_type") + + # input_audio_el = cl.Audio( + # mime=audio_mime_type, content=audio_file, name=audio_buffer.name + # ) + # await cl.Message( + # author="You", + # type="user_message", + # content="", + # elements=[input_audio_el, *elements] + # ).send() + + # answer_message = await cl.Message(content="").send() + + + start_time = time.time() + whisper_input = (audio_buffer.name, audio_file, audio_mime_type) + transcription = await speech_to_text(whisper_input) + end_time = time.time() + print(f"Transcription took {end_time - start_time} seconds") + + user_msg = cl.Message( + author="You", + type="user_message", + content=transcription + ) + await user_msg.send() + await on_message(user_msg) + + # images = [file for file in elements if "image" in file.mime] + + # text_answer = await generate_text_answer(transcription, images) + + # output_name, output_audio = await text_to_speech(text_answer, audio_mime_type) + + # output_audio_el = cl.Audio( + # name=output_name, + # auto_play=True, + # mime=audio_mime_type, + # content=output_audio, + # ) + + # answer_message.elements = [output_audio_el] + + # answer_message.content = transcription + # await answer_message.update() + +if __name__ == "__main__": + from chainlit.cli import run_chainlit + run_chainlit(__file__) + + diff --git a/docs/md/api/core_classes_and_functions.md b/docs/md/api/core_classes_and_functions.md new file mode 100644 index 00000000..198fd427 --- /dev/null +++ b/docs/md/api/core_classes_and_functions.md @@ -0,0 +1,141 @@ +# Core Classes and Functions + +## Overview + +In this section, we will delve into the core classes and functions that make up the Crawl4AI library. This includes the `WebCrawler` class, various `CrawlerStrategy` classes, `ChunkingStrategy` classes, and `ExtractionStrategy` classes. Understanding these core components will help you leverage the full power of Crawl4AI for your web crawling and data extraction needs. + +## WebCrawler Class + +The `WebCrawler` class is the main class you'll interact with. It provides the interface for crawling web pages and extracting data. + +### Initialization + +```python +from crawl4ai import WebCrawler + +# Create an instance of WebCrawler +crawler = WebCrawler() +``` + +### Methods + +- **`warmup()`**: Prepares the crawler for use, such as loading necessary models. +- **`run(url: str, **kwargs)`**: Runs the crawler on the specified URL with optional parameters for customization. + +```python +crawler.warmup() +result = crawler.run(url="https://www.nbcnews.com/business") +print(result) +``` + +## CrawlerStrategy Classes + +The `CrawlerStrategy` classes define how the web crawling is executed. The base class is `CrawlerStrategy`, which is extended by specific implementations like `LocalSeleniumCrawlerStrategy`. + +### CrawlerStrategy Base Class + +An abstract base class that defines the interface for different crawler strategies. + +```python +from abc import ABC, abstractmethod + +class CrawlerStrategy(ABC): + @abstractmethod + def crawl(self, url: str, **kwargs) -> str: + pass + + @abstractmethod + def take_screenshot(self, save_path: str): + pass + + @abstractmethod + def update_user_agent(self, user_agent: str): + pass + + @abstractmethod + def set_hook(self, hook_type: str, hook: Callable): + pass +``` + +### LocalSeleniumCrawlerStrategy Class + +A concrete implementation of `CrawlerStrategy` that uses Selenium to crawl web pages. + +#### Initialization + +```python +from crawl4ai.crawler_strategy import LocalSeleniumCrawlerStrategy + +strategy = LocalSeleniumCrawlerStrategy(js_code=["console.log('Hello, world!');"]) +``` + +#### Methods + +- **`crawl(url: str, **kwargs)`**: Crawls the specified URL. +- **`take_screenshot(save_path: str)`**: Takes a screenshot of the current page. +- **`update_user_agent(user_agent: str)`**: Updates the user agent for the browser. +- **`set_hook(hook_type: str, hook: Callable)`**: Sets a hook for various events. + +```python +result = strategy.crawl("https://www.example.com") +strategy.take_screenshot("screenshot.png") +strategy.update_user_agent("Mozilla/5.0") +strategy.set_hook("before_get_url", lambda: print("About to get URL")) +``` + +## ChunkingStrategy Classes + +The `ChunkingStrategy` classes define how the text from a web page is divided into chunks. Here are a few examples: + +### RegexChunking Class + +Splits text using regular expressions. + +```python +from crawl4ai.chunking_strategy import RegexChunking + +chunker = RegexChunking(patterns=[r'\n\n']) +chunks = chunker.chunk("This is a sample text. It will be split into chunks.") +``` + +### NlpSentenceChunking Class + +Uses NLP to split text into sentences. + +```python +from crawl4ai.chunking_strategy import NlpSentenceChunking + +chunker = NlpSentenceChunking() +chunks = chunker.chunk("This is a sample text. It will be split into sentences.") +``` + +## ExtractionStrategy Classes + +The `ExtractionStrategy` classes define how meaningful content is extracted from the chunks. Here are a few examples: + +### CosineStrategy Class + +Clusters text chunks based on cosine similarity. + +```python +from crawl4ai.extraction_strategy import CosineStrategy + +extractor = CosineStrategy(semantic_filter="finance", word_count_threshold=10) +extracted_content = extractor.extract(url="https://www.example.com", html="...") +``` + +### LLMExtractionStrategy Class + +Uses a Language Model to extract meaningful blocks from HTML. + +```python +from crawl4ai.extraction_strategy import LLMExtractionStrategy + +extractor = LLMExtractionStrategy(provider='openai', api_token='your_api_token', instruction='Extract only news about AI.') +extracted_content = extractor.extract(url="https://www.example.com", html="...") +``` + +## Conclusion + +By understanding these core classes and functions, you can customize and extend Crawl4AI to suit your specific web crawling and data extraction needs. Happy crawling! πŸ•·οΈπŸ€– + diff --git a/docs/md/api/detailed_api_documentation.md b/docs/md/api/detailed_api_documentation.md new file mode 100644 index 00000000..aaf0e34f --- /dev/null +++ b/docs/md/api/detailed_api_documentation.md @@ -0,0 +1,338 @@ +# Detailed API Documentation + +## Overview + +This section provides comprehensive documentation for the Crawl4AI API, covering all classes, methods, and their parameters. This guide will help you understand how to utilize the API to its full potential, enabling efficient web crawling and data extraction. + +## WebCrawler Class + +The `WebCrawler` class is the primary interface for crawling web pages and extracting data. + +### Initialization + +```python +from crawl4ai import WebCrawler + +crawler = WebCrawler() +``` + +### Methods + +#### `warmup()` + +Prepares the crawler for use, such as loading necessary models. + +```python +crawler.warmup() +``` + +#### `run(url: str, **kwargs) -> CrawlResult` + +Crawls the specified URL and returns the result. + +- **Parameters:** + - `url` (str): The URL to crawl. + - `**kwargs`: Additional parameters for customization. + +- **Returns:** + - `CrawlResult`: An object containing the crawl result. + +- **Example:** + +```python +result = crawler.run(url="https://www.nbcnews.com/business") +print(result) +``` + +### CrawlResult Class + +Represents the result of a crawl operation. + +- **Attributes:** + - `url` (str): The URL of the crawled page. + - `html` (str): The raw HTML of the page. + - `success` (bool): Whether the crawl was successful. + - `cleaned_html` (Optional[str]): The cleaned HTML. + - `media` (Dict[str, List[Dict]]): Media tags in the page (images, audio, video). + - `links` (Dict[str, List[Dict]]): Links in the page (external, internal). + - `screenshot` (Optional[str]): Base64 encoded screenshot. + - `markdown` (Optional[str]): Extracted content in Markdown format. + - `extracted_content` (Optional[str]): Extracted meaningful content. + - `metadata` (Optional[dict]): Metadata from the page. + - `error_message` (Optional[str]): Error message if any. + +## CrawlerStrategy Classes + +The `CrawlerStrategy` classes define how the web crawling is executed. + +### CrawlerStrategy Base Class + +An abstract base class for different crawler strategies. + +#### Methods + +- **`crawl(url: str, **kwargs) -> str`**: Crawls the specified URL. +- **`take_screenshot(save_path: str)`**: Takes a screenshot of the current page. +- **`update_user_agent(user_agent: str)`**: Updates the user agent for the browser. +- **`set_hook(hook_type: str, hook: Callable)`**: Sets a hook for various events. + +### LocalSeleniumCrawlerStrategy Class + +Uses Selenium to crawl web pages. + +#### Initialization + +```python +from crawl4ai.crawler_strategy import LocalSeleniumCrawlerStrategy + +strategy = LocalSeleniumCrawlerStrategy(js_code=["console.log('Hello, world!');"]) +``` + +#### Methods + +- **`crawl(url: str, **kwargs)`**: Crawls the specified URL. +- **`take_screenshot(save_path: str)`**: Takes a screenshot of the current page. +- **`update_user_agent(user_agent: str)`**: Updates the user agent for the browser. +- **`set_hook(hook_type: str, hook: Callable)`**: Sets a hook for various events. + +#### Example + +```python +result = strategy.crawl("https://www.example.com") +strategy.take_screenshot("screenshot.png") +strategy.update_user_agent("Mozilla/5.0") +strategy.set_hook("before_get_url", lambda: print("About to get URL")) +``` + +## ChunkingStrategy Classes + +The `ChunkingStrategy` classes define how the text from a web page is divided into chunks. + +### RegexChunking Class + +Splits text using regular expressions. + +#### Initialization + +```python +from crawl4ai.chunking_strategy import RegexChunking + +chunker = RegexChunking(patterns=[r'\n\n']) +``` + +#### Methods + +- **`chunk(text: str) -> List[str]`**: Splits the text into chunks. + +#### Example + +```python +chunks = chunker.chunk("This is a sample text. It will be split into chunks.") +``` + +### NlpSentenceChunking Class + +Uses NLP to split text into sentences. + +#### Initialization + +```python +from crawl4ai.chunking_strategy import NlpSentenceChunking + +chunker = NlpSentenceChunking() +``` + +#### Methods + +- **`chunk(text: str) -> List[str]`**: Splits the text into sentences. + +#### Example + +```python +chunks = chunker.chunk("This is a sample text. It will be split into sentences.") +``` + +### TopicSegmentationChunking Class + +Uses the TextTiling algorithm to segment text into topics. + +#### Initialization + +```python +from crawl4ai.chunking_strategy import TopicSegmentationChunking + +chunker = TopicSegmentationChunking(num_keywords=3) +``` + +#### Methods + +- **`chunk(text: str) -> List[str]`**: Splits the text into topic-based segments. + +#### Example + +```python +chunks = chunker.chunk("This is a sample text. It will be split into topic-based segments.") +``` + +### FixedLengthWordChunking Class + +Splits text into chunks of fixed length based on the number of words. + +#### Initialization + +```python +from crawl4ai.chunking_strategy import FixedLengthWordChunking + +chunker = FixedLengthWordChunking(chunk_size=100) +``` + +#### Methods + +- **`chunk(text: str) -> List[str]`**: Splits the text into fixed-length word chunks. + +#### Example + +```python +chunks = chunker.chunk("This is a sample text. It will be split into fixed-length word chunks.") +``` + +### SlidingWindowChunking Class + +Uses a sliding window approach to chunk text. + +#### Initialization + +```python +from crawl4ai.chunking_strategy import SlidingWindowChunking + +chunker = SlidingWindowChunking(window_size=100, step=50) +``` + +#### Methods + +- **`chunk(text: str) -> List[str]`**: Splits the text using a sliding window approach. + +#### Example + +```python +chunks = chunker.chunk("This is a sample text. It will be split using a sliding window approach.") +``` + +## ExtractionStrategy Classes + +The `ExtractionStrategy` classes define how meaningful content is extracted from the chunks. + +### NoExtractionStrategy Class + +Returns the entire HTML content without any modification. + +#### Initialization + +```python +from crawl4ai.extraction_strategy import NoExtractionStrategy + +extractor = NoExtractionStrategy() +``` + +#### Methods + +- **`extract(url: str, html: str) -> str`**: Returns the HTML content. + +#### Example + +```python +extracted_content = extractor.extract(url="https://www.example.com", html="...") +``` + +### LLMExtractionStrategy Class + +Uses a Language Model to extract meaningful blocks from HTML. + +#### Initialization + +```python +from crawl4ai.extraction_strategy import LLMExtractionStrategy + +extractor = LLMExtractionStrategy(provider='openai', api_token='your_api_token', instruction='Extract only news about AI.') +``` + +#### Methods + +- **`extract(url: str, html: str) -> str`**: Extracts meaningful content using the LLM. + +#### Example + +```python +extracted_content = extractor.extract(url="https://www.example.com", html="...") +``` + +### CosineStrategy Class + +Clusters text chunks based on cosine similarity. + +#### Initialization + +```python +from crawl4ai.extraction_strategy import CosineStrategy + +extractor = CosineStrategy(semantic_filter="finance", word_count_threshold=10) +``` + +#### Methods + +- **`extract(url: str, html: str) -> str`**: Extracts clusters of text based on cosine similarity. + +#### Example + +```python +extracted_content = extractor.extract(url="https://www.example.com", html="...") +``` + +### TopicExtractionStrategy Class + +Uses the TextTiling algorithm to segment HTML content into topics and extract keywords. + +#### Initialization + +```python +from crawl4ai.extraction_strategy import TopicExtractionStrategy + +extractor = TopicExtractionStrategy(num_keywords=3) +``` + +#### Methods + +- **`extract(url: str, html: str) -> str`**: Extracts topic-based segments and keywords. + +#### Example + +```python +extracted_content = extractor.extract(url="https://www.example.com", html="...") +``` + +## Parameters + +Here are the common parameters used across various classes and methods: + +- **`url`** (str): The URL to crawl. +- **`html`** (str): The HTML content of the page. +- **`user_agent`** (str): The user agent for the HTTP requests. +- **`patterns`** (list): A list of regular expression patterns for chunking. +- **`num_keywords`** (int): Number of keywords for topic extraction. +- **`chunk_size`** (int): Number of words in each chunk. +- **`window_size`** (int): Number of words in the sliding window. +- **`step`** (int): Step size for the sliding window. +- **`semantic_filter`** (str): Keywords for filtering relevant documents. +- **`word_count_threshold`** (int): Minimum number of words per cluster. +- **`max_dist`** (float): Maximum cophenetic distance for clustering. +- **`linkage_method`** (str): Linkage method for hierarchical clustering. +- **`top_k`** (int): Number of top categories to extract. +- **`provider`** ( + +str): Provider for language model completions. +- **`api_token`** (str): API token for the provider. +- **`instruction`** (str): Instruction to guide the LLM extraction. + +## Conclusion + +This detailed API documentation provides a thorough understanding of the classes, methods, and parameters in the Crawl4AI library. With this knowledge, you can effectively use the API to perform advanced web crawling and data extraction tasks. \ No newline at end of file diff --git a/docs/md/assets/DankMono-Bold.woff2 b/docs/md/assets/DankMono-Bold.woff2 new file mode 100644 index 00000000..3072fd85 Binary files /dev/null and b/docs/md/assets/DankMono-Bold.woff2 differ diff --git a/docs/md/assets/DankMono-Italic.woff2 b/docs/md/assets/DankMono-Italic.woff2 new file mode 100644 index 00000000..1d01ea6d Binary files /dev/null and b/docs/md/assets/DankMono-Italic.woff2 differ diff --git a/docs/md/assets/DankMono-Regular.woff2 b/docs/md/assets/DankMono-Regular.woff2 new file mode 100644 index 00000000..99c1425c Binary files /dev/null and b/docs/md/assets/DankMono-Regular.woff2 differ diff --git a/docs/md/assets/Monaco.woff b/docs/md/assets/Monaco.woff new file mode 100644 index 00000000..e468c424 Binary files /dev/null and b/docs/md/assets/Monaco.woff differ diff --git a/docs/md/assets/dmvendor.css b/docs/md/assets/dmvendor.css new file mode 100644 index 00000000..0f72703d --- /dev/null +++ b/docs/md/assets/dmvendor.css @@ -0,0 +1,127 @@ +/*! + * @preserve + * Dank Mono (v1.000) + * This font is subject to its EULA. https://dank.sh + * Β© 2018–2020 Phil PlΓΌckthun. All Rights Reserved. + */ + +@font-face{ + font-family: "dm"; + font-weight: normal; + font-style: normal; + unicode-range: U+0000-007F; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,d09GMk9UVE8AAB+IAAwAAAAALhwAAB86AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAADc1uGigbIByEAAZgAEQBNgIkA4N8BAYFgXQHIBtJLVGUcl4UgJ8HmZuXZtEW1XZl1rY1cWX7wvl7NY0jDnGEqlmVEZLM+g+Xe+//m9NaFMHk+OwEWgs4kDD0hNcYoLl1G7sFvSC2G3ejJxZRSrYORERq0KMGrIBXQjBIi6oBI5QqC7ByVsTBz+Ahf/fuPoLQbUIXbIhSU7UmVOsCIQpFLKyeN+d/7VvOOXrpvv9031nbu/K9CoRoiySCCEkIssgKDiJEJ5yEg8A4JBb8jSMYPogQokhBgbQIkOAKcVF6IMtfyIQ+d+cu/v+v/au9+3MAUeHyCCrGRZiZMzN577y77uPAywswTSaA3OomsjiqIQJVRNUqEqaqvqveEAorKjzrNFiBKWCmykph97vHcK4frYg5UKbvwyBcApjAkAdx/PSgLH7W8ncvIoOz9HysxsIcAAuLLDjpgq6hIAdK8AkoHaz+BSs1z6FKKHu36QGAe4OBjc9cfBmfqx7I7kVZJDIME8Ag0mDAhr8IGYrt1mvaRTzCZ+IxdFrRlesp5FbWsodzvMjH/Cx4LCTW4iwBUiEtIpvwUzMKc9/LM04oSiKaVlxhxnbjrchITYmLjxNw41PaiKIdvIL0JNHOIlwTRvYoRZjbNW6WNTvc9ksSJFdlg03MxCA8yR1sg+NgD8eEvwqhRVwmmh1otz0PL/9nINpnC+xkSsRGcbADHLAs7+xueTAcrEx4M8nVDKINaFcahkTCPu7ZgBjrzc9djROALdc83jmklZkzBbirzTAwKZu4Y2KGvfNW8JLydJbg3cpihXmagPp7RbETopa0E9PXxaN633U5GQnpv7FBrchc9XG/8K/zIX7xseZklgd4AgDA2EEA0wA8gDtiM6DXYcobQBEnBLF6xQiIHP+i+EeI+AUrlma5pRQNVL626ZBe1FcGx9hiXDXNzRzznGVpca37tq9dZB+3XzgE4hJnu0skebut7ivPyPPz+N5R76cK0+f4RX6L/zLQDCKCuuC7WmR4LnwbMSLHqCO6Ef3WsIqD47S4LO6JD8bXEkfNZs2HZC+yjPySEk2RUe5RmVR/ajr1FI1M20C7Dh6Qz8oseVA2anf1Zfl2+Kqe6fPMtGcadcWzK561n2vz3IrnLj4XZrzu/8Ufhr4L7AnUxTwf83rM1RjSa/H86OeXGH8xuhqTjZ+N/5rPmJPMX836uL/H++JTtZhwpqZpEAYrF4550P9ISSlBKJfiH0NYPIWJpfSPvUcectIq8eREZ+fkhLgzIUEkToA1RzqnJ5cCz8fvHlNnw1PFy9PzQX3njy0DqOnPd6Msoc+OW8wQTXfmY9SCqoGuh1Bd0h+t0Xq2hXB5levz31SEs3LOiY3LMsAzNuzPvVBXvgXVrKqkF9fTNqKhrHs3+JYChwjWqje4d+pfymdRNUvmsPHZiwCBfWdoGLa8t6vkttG3p9d8ThxmFQnQllReh7EfOv3PELLeWPBtVQWEIXHsq2HJzMYTJ56ddmrgTocfow4nZwkifdyzG2H8BJS5QHmGQSfEsMVRsowDROT00cKoqJ5zMN7J3zUj026eQRtUtyzce+DmUphqRI9N0w+c9mvzzsDvOJqvGhSzqwSmoaXTlw1eNeGMSlccaSyYoiROEyPVSIOsKCy+c2fk2aSktFF2SQXDKsxFZ+T4nJ5LF1Z2zx/LE/j7S3I2IHRKxWP/NGi5Nxx2mWev7cVorlbJxV3Xzpjr3ujN2Jd6c4suKUE7b2fHVPsh+riCj7LyuLnJdOIgi3W//+G+Q4wLO4bkp/NzuD3w6ROscPLwAecAEXr3j311ScL5TmbrEa+4O/hJGwRSBs2AKezl6Fcj0jdC3btXVJ3ZNn/1EHI47WLv6mZRxOOVWa5syKrOQzYhHjsGaxu8mMBBCbdjKB4w2Eb6cZAcyHwAGVCw/+h4ldigQsaxlj4yWDpU4O63n6ZI6RSpAnJPV6gQTCMemwDCAeZXcU+TChA8ADUgB3B6Sx/peYzw5KavyOE5XbkUzFh6NlaotbIo6/fKJ+zCXQagwercG+cJmsH0PNgIPbvfzgKFBdFOThmJsnozDZ2WB5OWF3R0SqwkcwvmsLTIEubJZE4ruUbW6PKgA2QvMogp898Fd699Ae0TfsY6/bzdm2u3wDmjU7xKC4kaGi2P6sIb6ULJCuJaLsiXhXXk8+SBk1442VOimryq23ko3cinLgVTVFTYla35Y7cu9pyvw7c673kFSSoCjlxgAUuAcEUBComAQ2Se/9cHJGcqMtCFt3L/bkFMP0I1Lp/NOV586YYf6dfBfAAnuH8kdiseWz62zsfRTyH9FToJk2d0DGfBWtCRenDU9kJFyeWdn+Sb9k0S3TvklrLgLb5cWdndyfhfcnYiksSMQZ5xdh9FaUHLoVgelWl7VaZCJZHJjMxInwyMiRMlklxJXi69vaqxXETAC74Iwlo4+KH8wkXSjuv9auIrxrnJ7Eb+yZUXA1X5yV6IlluKkyGMlXqUqMaLYMdE5q8+t/QwVHsqveMLw8crQPPVlBk8lK+MTEickKkAenHXXnnJTJsMdjpUkg0wgOX3LDDuv1w6YDNyeefIecsP3RZ3SKt3hzfSsmEtqFJIWAYTXIrGD1ufbaNMooPr31OZLfTZKAO+jPCWWBXs3tMBJ5IJeXHsUlzWntMudz3TavGABpQ8eDUau7+jpsFL6codq+Y6zwUenR5G6qQ2qq+Bqe8cES47nmmOGQumhK5PvxkAqxH9O6yxss2fivhBWaLEfGQVdjLIQy6Tv+YymZZbjsVrEJZ5qm18rfBWK5EkgSDHP+JhCYuH39ERy1r/Tit6pr4Tx4OPCRjcrofKnkPFm/rhY8Vs7aTAZg5EzqRC2rTGRPtorT9C/VrE9+zRomX/WwDNa+LEtlu7rwe0oCONhlPdM6WOVKYoW0E2FEr2tIkm/HVcP4FpmCEMzsgwLKGp5RZUwPEElTx43wtd9b9MPNrDmmGQxswM4wF+MgEwAHTo198CfDWjUfGvbYa1ffZerR+kbhcIJDBpGKkYe1wrefrI/Sd9BoC3jjiM8TcbNmNlu6E7PxvoUStkysT17plw700Tj13xXzs6fPny4TQ3WMstA++aUir3lFTgq+2FHL2y8vL2yWEkQ5BBtzakOuXluhY+nD4UfGfv+blnAnCFCrSwxoRAwLHVI0UHskhIIDuyrG8DY2OFCpT/X9KDQLO/GDfLNcI50C7l2iP0LzdvNZjabyCjhkVrcHMlSrMJ24YUcs/KFGYrblrZMXWW879Am9QFD0jK1gsSFDJRKAqV7LhLzxGH54iddZ9pWGVBx/KoPhUlXX3+ZTJT+nwx6QBMh0D+OgBL9VbOSsZziqXnFLfDSVFQwmqF5iSUebCrBnq2VwnUJ9lnUlpwHNx+6NRIBd5fw3/fN3btlHFq37F93xiA2p0jPQJbT07hw2ez2Ontd9eeDzQembHKpG3uXDyIgMV9secFW2SXVSDW9hZhhyS7PIqBXRfj8glGzOuvwxIGfqV2CmrQA/5sF1pljBR7ZmW2REMEpHQkfTItjX8ysbV5aD8y01ZpAnGdoEbOlJSqCHJxBsq/0Ppz8uTNPZ0FiV0w5YlZ7woKeVDvV4ueIJT9W9U9GVKFQYo+H4Y+Pfs8shl2cX1+EWUzm1O2I2WkwikuImVodCC5hOvZfyocRqlcC9qYs5Fre2psyMu9uOsDu/4+jBqyQu23mKfWdR287gfUvYDsDfKISDnEiipBOJfZplXaWAOTzDDH7SbIrRHAH33Dvucr0xUqppZrOYjlOV7nVeXwkSPnrx6XHCDiYOAQhfiroEPp0sWMIe3I/fXgf98ipdLYANkSgdypigobFS/CDVSQ79SvQLSgrb5Ve2wbTyq8cLal+obWAppnX6R4ih7DijNRjgsSfR2BoVyDgiJS1HDY3YYO2ly4UBixsd32AGt7gfUpH5u+YQembZrGdnyzXR+uBZV+UkrsKhqqtr4Tqj6b67NxETFxbkyh5VpIDylsxB7Qd/gmqSkFDeCk26srYUhzGADEIOcGVEEv3JPjc8K4dJLZA/sO2wfIn1TJjtpoewPpwxu2j9Eo+JhaUK1ICQUX8NG3bDzIoy655XerdLwhhGhLb2oLnk9E7+rEJLl4eqDwSUJzIkIeTNhe4H3KmxdNp00DEnIJKTCN0MhNaCrP9uJRroTx/avAmOpgzn4SrksvvHCHeWo6z7TTwPWzsXD6cHDsvs/THuWQfxiClZga21vjs9HBt+xBx+gMA5XTT/Uv3FHGjEBOx10cU7gkoQVDwcWI6CdP9Gw1H5L0z6mSuJ4XkapQoSk6jN9Qm6PhcgGMKn02DH0ORug79ytIR4hwjPBRd/kuqwD0Q6BHRTC2I20nMojZkTZOdplYmoiNE1BmVKeIlGtBBxOEVXSVjbO1+s4qn+1gOM5GMKyW67MdaZL7RtBZ9YYlci233DEp8RxvwEJD/G+MZyPaFBXojocZeZB7M2JTN1U9UDSFl7moXJLqyHqkYlvxE5SDUBRLOyhltBkFh3GRJCKeOq64vHWOVEakNi7WCARCrRCrYNr6PrFNMnOpEnMwE49Oj23VJi1TQTADIk7tn3YN6PXe40pNkuQOsbDkPYPo/BsgwF5tgwWRP3DrGw0LtMKzb4HZZu3fNxDWntaLDmte/YAAvxbcBs/K6H0n/WCdL2zHwpcvr6pqRX6YW1tQU9AXo3v6hTPtJvsb+N7Rb/OhGV/+vK12e93m7oLuwi7ig76CCyD5Y7F1BhVx/QM7JqcBnMp0sSo0Gvn1Xz7Q03AjV8LsyU1Yb2o8SKaeTXrrhh8r85cWHP0F62kXd+cFzyOnTzA9r2hi593tAqTfqiOpE/nPVVjyjvkw/8SkJH/rgekKXPKodfMpcFo6qKcNGX899Qnx+SLkih6jtp5XWg4gkRiJsGMUpHM9O+TuZr8L73CDmHIbD2xvOZIkMe62hz3s79SAYajLSe550Tw1a3nbAflfYHU+SWh5OZL0s+1Rd70Y9NkctRQJMgMmRCAKc6CS2L7S30HYRx+0leEDSveV832PZ8Fc9bgj7ggx98RFlXN99gmE7F+gIsGfxMn+A3o6mYyMkXB87+bcG1GdeW7vt3sMp9VR02D0EZ7C3p/E9Z2UsPc39TCFGFowKFR6L59lSfBcJlWgy+o47HE8RMdXD+IpXUgFTJbIyZHOtMUZxodBDDw1dccdSXds3BFoV1FxKDeTFikbiyR+Ani03vos10nAFa0M4WVkzOGPAWa5eclKVVAADTBa3QtETm7UypKFRlGWc9byILnGi2RHKp/y0GSRi3MWLpYQxHF1b1edGaminroW7P4dGXZhVsXvh16FUZQM86gpGS6Rs+SSLDQlD2KeLFySNRwUWAAhC1bDiYNGlsQ1igp51irU62iStnTRFIVyzTFDmgeh6PMqP8dMbjquyIfty31AbW6JJ/N6IZ2eK60r22b7kbfnZZQUwk/QUg6zOIC0rEvPGSPWwceGg4XFJ1fMQQ+u9iTA3CEW5kiqciDKIUIa4eMaxoBiEgJbGbI2oG4rOysrOuEXxdCXHV9PhVLH7D9tanPLB11SnBsI26J7Id618drW5911emWk9wnhyx+3Nu9oIerHZk0en1MYgPkj9N8Ige8LjxSJPcbP5sQiGBQRYhNUiys7z++9Fmi81JVoxOzbOqFr+oaTs01t7i0VZHmUGD6yz9zQxNUBAsZcAR3so7UAQmemDu4o/Mq6/0aLIsIfiFMXgsmDAu81hS3o9VeAXRXIQi/nLNQkXjqyY5dwTFLII8W/YV58Jm9kCtbnZZcUmv0mEkmLGY2Lc9njex0DZP5CPPma2INkebVo0sBRhKqFfmx0dniWfSChbz2YoF2saEQ0lJci5IbHuuu1UC7JbCEAwmJJ4M7N7WdPm+mFbPjQ9XnhUIuUsscVpjLjC3+rbG5mwGIyEAolp8RYCjRQhQzZOD9CgV1oLvgApCscpO8P3AAY0FBWpqA7HohtL8Qoky5H2F+CKgySMpKgRdgn958+eFgQLINLt4H3s3vt7g81a92L6AtMaiNML6GRbxksy5XatY/nUAorkiJveSEefFg29YSD8YWiVZPzMCmLMq1Z8ZdcNUriYK7Xn5o0OoUu1fIXm5OFWbFA69Hl8oZQ8ZTUUZh8xOhZ/qm+UPxA+zGi5eUslNtrQNT2nqrVy2tJ5DBsZS0Orx0fkwcaznZrbtK1+tsBYZOAwUiYksnA3rNe4sN6PXoLym4eNeMrqj8iR1VGkcMIIH3BXHfyTiEgybGSMiXJmPuMaIple6t7yXb7y6ZcC0DFqgfBVBc/lvUPbbtIGpfNiYmUnXrHQLsT48oQQSX3AB/qg0OeWL8araNdDLqcbuIiJlEvFL7XVspjyl9omLS96qBvQ7eZfyRR7C6FoAWVeNMtj2os98IO9eQVThxc3dE5AO1dncxFXPtyZSh+DtZV1MHn1si6+qHdRsL95JaLB6LS+LQc4Ro+fOyDpKEQaMpbm2LEyMEkVy7SuveVgXZ04/7zVNaobasyvm7J/tpGmDB8Eb9N1vLo2vHJq2ke1Q/untV0QM8ZGdmwlntNxcgNvlSPJ/VePMyVsHqEcgTALwEaZEvWLUiN/CnoTwWDlfndNZkwtBzGMCioefSjoD0ZkdHw5GbcN7ji3Ph4DsVivCM5aCm5jLQKezGIHWL6vpM5xbnCsqZedvDC42bQn6z3XVuJaqGXZRCWH0lXOuPRXMnR+n8p+dTCCaVZkTJd2Wix/2AmeUIuWdjgbsATLuOZGmpue1XtGr18TrgvCpae2isPbNi4dVM/cqKCrR0irhZDr7b/ovdkc8lP03vrYUoehidN4eWi5ZaqdTc90LTqHF/0+B+WTFiZ0XOQcbxo57PCfXkbD8EnT7LzE3tvbRcgqGNq8w6XJ8Bppln3wab8JMbo1Ain1JGjF8cao0eBPc7dnNQIAa4uffJ01EGF2QZTQ6jtbVBb5H9pjhN9YX2vRqikbPfb/UjvbWzUO5GCGCht3PQTE0ewo4x2IDlzu6IZLwot98aUnAX5nLxcyt1aTNv68rvqsqQzgpZWEQ2Ui1d2nNgC66/3yhdPTFUlucuEvnxwQmbKGqjdkMrfTTwQWhD0oPLbYPINSN29+oCv5EVs+U6uH5krv4M8ZSsN2wu2r5wXwjyvcPn9lfqbO0sGuuU6igZnf5eQgaY9zKn46OFjkA8S3ug6JWHK8S4QzXIeUgSHlbx4HzDMBz2kYnOq7Q8FYAL+GGHtOEGURHQklV8t8KURWkMTTFMB0PFgZpPWJ28U84uziWPey0yLhL74vLK6FJk7GPxmWXNFA2Qdm36xE1m6vWWseYy4kFuIqcLmdT+JbflHnYaS/2CFewq6tD+CPvpF7MLzSKeBam1aHqWpspAH4KbEn7LXAs+VAytzV6bgtqAXrjvTKLpY6VhKp9iDxur/2HDGTgnlX0dEJ5dmF6Yin75TIkxhkFJVBrA//1JZVQdfFN9+UlxRBI3O6rqwrkZW2438vKVh+Agj9M7lnkuM60v6T131H/pkqqQf/nRbab+Mce5g+/EljRXlTfBFsXB+UWUxRECnmGYzf8qu4yO/TqtNT2RkzQtWkAyNooKV//M8GK31YpSiZG2Yl8gD2TMasqpM/6bU78HFiZGLljZWNUKnDuZxBKX8LamI/qDkzaK4aMaAjcE35xk9573j48XI/JVXnw7r934U1ghyGEOzRCFFxVXVRfBgseDn+so6CNiqo6jSjs+6t8gQ/UHhttLeUcahX89C2bAEkeadzR+vHWgYRfR7P/fX9g4xGq0PEjC/qLKiGNYgsVbc92CLWiJTx3Kdp5pns9npTYN9w9Dm1eJcKTK7vgCZxwO3j18+sQ5J2wdmvZ3KS4LeymnvEiDr3krbvw7SYp2uKt10ymIB4XtVo1vqKc4lVvE+4LEUdVHRLEW76FHnahFf9R8bRx2pHIy2yAtqG7wQJKBpH0TJJtzE5UXjKGDcF7Hf7LpswltAs/M+0jCSnppI54UtSvLzXcyshd7ejB6rXnrwsfHVgvsdEgd/JN7g2G/B2khG78wPPWFvO9x0LtwKMdWjoNaLo9x+SYcd5kXYPVAeuUDlXF1yLsjKWxBxocXWm6e9qZVvZNPPQu11oaaUMqsV7pRSYRdFZKaJoy5UOF2Lkg9PmA9yIx7JZAFgUaIPQm6CyPYr0DRU0EVqc16g7aIbxEmj80TSNMlbpH6TxDLqpsryZZ2H7l1ZeCWfUZrfdt2wIy+S+IDMtttm/oIz1/y33j/u1wp/tfA+QIxRCL8j8XfRm1TuXPDe+q3DcafH2b+2Sk2cCSr43AJeR15VrbYSt8UHd65+8896lE4hbHkKq63whlcrnnTFO+JOYVjIiA9eo1GnfiFPL+CGtdjqOkF1i2myXBHlYos9Hail03aIKsMbJnR6JE3N3rb+sOon84s2yi8e43BnX+u+SwxfxeHzkjfsALVY2FugWR7oo0wmO52CoNZ7q/jQE3S14N6nOkC3HYu0J4fVee2QjsNYkHYIenjM60CKKFOJytxAD3ek2DyBwi+8AVVImDrtzQBuJ78MKpG44VmseCXshu9iUfSDD92aMPA7BBzDN3jDdcpPjmvNIpcxejj9fFyrlZixAy/el+gX3qiFHQtb8rQYVIWf+oM58r5opJ+frE/MeG4vfhHKw3dZkzl7avGlgHNH7JiJDhk24jROUQWpioiWiO5VBS2jvNBximRPjbimZrEXMYbPXWKcB5y70oXVXD6gSqopV5n1zT15sAh3J/delioc11hEXWhqFh9erb+islJ2B2/oCiNqLahCvcYVHzR4Q64zUBOJItxKFytVJRqZKxW1PtUhVAU1MC2myVE0q2a3zooOOz6i5oGJn+5dUCLtK7jM9GyaQhpTPZbbwzGF1FFXmbOM/kkme96KCT/nVIpS2XobLuOtuSE9zzcmTkZGJN0dxi7OWfg4xwO98H4v9PDKp0F7qFk1oTm4d78DVcwNpENSBSJCBVKE600pTItdmYNKLQ/I4Rmv2rZAq+AyjSOKhY2sp0Yc44gcddVVoRaWKCjpeVWJIkp113Ifc5pooh4X4u7HNvkzrUPrZIcP5siio7MF0ZE9gkOIpmZzWbNwDDuVb2ekyT9HtNj2ObzCq8HJyoKVEinNRjphFbdyRX03Wpksio50YY36qKHGhpUOfJ03QuDTMUTXsFPR7yjioG5I1+qpTsEUZR3WZReDYymRy0WzVERq2RZIPYtpkst5d+gYquSA7if9kAhYoRXD0nl5kJhwF29flOu3jS4etosNK472oPJ4vcMo6n78bSpbWX80hTdhWXLPtpxw3db1baP8lZdMFsJO3NBzDgJZwvr2nf4njBv1s/7mZYP0P6m2+e7JDlM2yptt9FYSDYCtoetWnfozk+lgV1Xrc+ejSyvl73wyTbByvgcTDBxA9tt815gv+Lfzthdt+48Yx7b60fkH/bbnNH/+/FnU1Nov5IjntOCP58/PsfjDPQW7Coi0nw+PMIEOs+58CqHuxOG7AZeqGf+0P/gAP4k6WVuugn170Mkwy7O/zg1zDiSLG7+Fx+1E3HdmMhjXELVF0769U0slOcEubSTqQDbkQLbnRoGL2cKxynaWHPbRATZp55mW+9vig2Uuy0iyDE/xiwnUviw8CqJhy4jEDzZUkkJ/O/330PfpOCcWDf/xj9O/7qrZvadWSjJVtUV2oQcA5lECGACCExhY4MRLwrEU6ZYt06ZsBQoI97k9TDDMOgoMBYjzfuDLchh3Fk4JaxGww6vvtYgPMDGR0wokK4bSEFudIQIYKnpaUhRg9YabCuPy4IoYsdxr/+YSESbMoc6ALVf+QsUQ2K7RoFfEYlQx2sDCU8enhIUlExYLBi4uMkaXuhnxiRTkKfUB2cU06ctS+nDkMjmzRBJZMVX5uK2a/86EiVTWy8wTqTeybn9kthWsCeEyNOWm8MX0CTC4LH7HNYl85Jzl48ZcZ9tqS49JYprMwKIQI0VydYFkO73V0SSNnPjO5ioBsayuPfEI1PRwNJFR6EGwOIvBhU9bVkJMM9iDIYE1FcOgYsYuZrI9B/wou2mLMfelId6IkXA5yt0AcRVFFXsFAKonwhOWEYa7ugmdEHB0D7gtfT8UAGIwklwBHIkyPCl9ajPAhUTopyxCS+psOObsZDLvDYQKaZJ0YD0+/uu/Kh8tqnI9Px4lXA3Ha5QSbnTsfFmeOqN2O8zO/4v8RUmTxjX/TJepH0HfH4CqljOR9q+OoPa7XrusRUivY+sxjSrpMAoOQmDCS3rQxGEcgBjb+I6oHfbgC0fwweFowXrEYqMKVCtfO7gDMYqTC+CC1YhQ1m6Ar/JgWAuBWoen0sfk8Gm5aoQgEMFgYzk8oQcXXIMPZpEOOo6CgzD4Ko8RIjgjEjnYCIES4k6biA8vrFGJjwhDEOyQoNa7I/anIxMDPQJrNj5LJi5DKHDg9bCyj7ASp2FbOlRMW63nMuGyOYS3jvY4QwjlggJ13S7PKIeIN2oZZtwlvoY4uALGgB0AtgjqDFUkb7sE6IlL1X898ZIq7EspAbCfFofXHsQwk3g7++chS7Z8AqlS8Iiw7DtHtWTOgn1P1VGv8xw/G2PhmDYvM3QaGvi3BOlEfE8xvhUON8KYwFUphHASRhJLjBOnNeeiHA4DZ6HGsvBn2aInze+zKwGa4t8KWAIAAAA=) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: normal; + font-style: normal; + unicode-range: U+0080-1AFF; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,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) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: normal; + font-style: normal; + unicode-range: U+1B00-218F; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,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) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: normal; + font-style: normal; + unicode-range: U+2190-21FF; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,d09GMk9UVE8AAAUAAAsAAAAAB0AAAAS1AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYgTGyAcKgZgADQBNgIkAxgEBgWBdAcgG3wGEZWcfyE+EtMN9vKA5Bc0yUoz5//3zdWt7i7MMhk89Jh5YNQyuHYEC0QOBNNZU+uBFf/fX3vNFsIYcE02IK5Pv98Efw+vn0T3zFEboYh4FE8cSTQSMomQ8Ug0TyqZBNtCn6ltmWJarrMX4mswKBIYY7H7bxbmnSgqLFpx8yIZ/cA9xgIYCyNgLJKMxbKRoIjYCNlyHxrXrZvx+abPHxHcKkZSgdCXUgHlHqe3oz//PyeO3o9FFGNhscnzV2zcsf9YxvXRZ1+7WVpaVOU31l5RbOUBkheyMMmlLEZKVK6tsKIwZ+2aLRsVZRNls3HL+pRnzcrVfUmk4lcW376y5PCf7C3gZLvzqq35t/M+nUD5ywykaFPZH9GRJYNONVRVTftcgLGWUIRLYJCwSaGn8CfbxwbYj5JJypDaol6kJ31kizO5PqQxs+bUnM4k56Br0Gkht7C9/jE3vSeO0BJupOuTZ4LoOC298SmP8tF9cfSWHk8L6T4zLaXjfPKCbpwNpiXiyMevCxu5WT2DTtfw9clOp6Y504RNeHjUi8YuUazT0k/jTC76zsgym27QcbGUT545YKQHiSNiCTe5Xk8nN9n4YN9gb19Sn6a9FuFRvaI6Ko0/qhi9pcv0xqB5ibQ4a3Jf7+BgXxrZyJ3+ulgijnDj7IHJC8FiKR0/dYNH/UqVVt1FR+JMrtdjiDg0F2uofsDBPCq2p+4WkcQ4/Rc0CYQ8BEJHaTsf6B/qSenV+i0mVZygWm+cwgtQpJC4kChANpOaHAGRNzFs+v1rfGz+9AbNpvl8qi5YSM0pQrJV3ORaf29oWT1DA/2Ila5ZzAIHJrSkNB8rKfm9uOm9AUf9kDPZ6dI0R1rUF8YxRkHGSZlyab65jFykC/2tt8U39C3Zy7vHxdiD3N3scyc7HF63O6211dvU1OhvqE96WIxzBzb42zglGy8bF8z+Hn93V1Knt7OlzRJwO/wO1v8WY2Xde8n+gPhGfPvWRdJJLxOucWcdzTC2mB9UWrFUcwkjRWoEg6dhL7EO5IEOXyC5v98fCKS1t/s73O/Y4+22lNA4D/tSwcTNDd76pqRGf3Nbi8Ud6Pf2M2uo+5MN48JeTt/Qt5feFrrQHyTX3j4epQ1O/Da0a0hUDgWJWx3B2qDxh49Ezg2FiEJfny9UD/swXA8EAi9OzIuI+LCvvSvQ0f1QROTE4lmpAO8ygwEIQwoLtv/g8TMIgQIAMzMAABD2QotJtUXl3ywvRAIQIlGRnmMB8EkROUL6DnCpsewhrM059FDtivfmBOYMyI9OE1B7WOhuBbs2gbRVjgCgUgBIAGQAs8hgClGgQgUw35zPzEgw+x8lEC2E3C71ywOzS65Hb/83RFaeA4Bfaz/+dHJy/dvvzkxNU+hLyj2ADIkxRf54muAPswIYM39VAEN/eyZ1I0OSc9Y7J0auUtmylYIVwgEE4xIZTAkFUAuzXAYFtVwJEhxcGYCrXIFxOZK49EEsm+9TpFiNUjmyZCunehyqtVZbY3NNM7KRV3UL6lFZbUCOfLVsvkm35SmXrUKhlVR75ANKHNWXEbR3JuEdbaX12qwcQKftHPKwMjmKFFKtsdJqwZQBMWaGrQUAAAA=) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: normal; + font-style: normal; + unicode-range: U+F8FF-10FFFF; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,d09GMk9UVE8AAAJ0AAsAAAAAA/wAAAIrAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYIRGyAcKgZgAAQBNgIkAwQEBgWBdAcgGzYDQC4D7AZ5j5pUbZm4E4qID3FTshVsW6OPY3WC/+/H2rnvv11ENDEkTQxJq+WNZLJJVAvFm3aTBlvR0kSNfr+2Z6qhKJBM0ol5Y6ja8JLIZEphKPV9HOFkV4XMJnQRxziiAWnTbbybh5rcbQEVaSD4FH+CudcDRKD1sl994/9u8i2QA733nQ5oNDZoniWWYBj3EluDplDkEWft9AMzuudgMIgSdgg3JGVZ6nd2Bv1B6OwinfywmQofJcRH0ykzg9Iyv2VCRnk43/6X4PXUhMnvZ0DScRl4PMKMu/dGkVLCpfSOfGPKU4mFo9Fou1nWW8n6duj0Rd30ilt5v1vpvG4gDg9rRU4mn5ajexpYLbO6SVMBJFn6yMPnuxP+npv9XR6Oexf1IXJq7ndftzNJD8lJ+eLN4tGnQyi82LheWVxa3UxN+/QqTSCykoeAZEqVU/vW9jG4OMD/A8AQVapZPXFvadqHlofodtvXIiw8pNo9iKFmtUk8TuFR5f/AKby9MHb+CBB2lNQMrABYE0KgkgMgQNB3by5Ifm74PoDHdQc8nr2e/PsjvPM4CBgAgnD1R3CR3f/+5wka5ppslUPoBgEJxDCQJwFDoIFwhsAwxiAAE0VnpRGKc8JoieMZA0MrYy0NTVNWe6wa1KnXOAqs47ZKPVasujW1dOXLrh8VHVNNM31hlVp0dVnrDCe6X0Oolp+rqQoHNO6f6u1jEy0DfVb1atQJDyDxv8QBAA==) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: normal; + font-style: italic; + unicode-range: U+0000-007F; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,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) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: normal; + font-style: italic; + unicode-range: U+0080-1AFF; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,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) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: normal; + font-style: italic; + unicode-range: U+1B00-218F; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,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) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: normal; + font-style: italic; + unicode-range: U+2190-21FF; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,d09GMk9UVE8AAATcAAsAAAAABxwAAASRAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYdvGyAcKgZgADQBNgIkAxgEBgWBdAcgG1gGEVWcQwE+ElO4G3pA8hc0hxm3NGG6/8up/ZE0IXYD5JQJQigjvFYGThf5VABWk9PS4bI3/ONOAHFwCxNLNbXr539uoRZZW+ctNHr4gnzB5NNGgyUgiUYiIVpoeKSemIV0+UJPp2JbqHYhnb3wk1sQkAQghOQtP1J7bkNdbd2Ed62zY/jbl7IRwEZmARslsNEiK5EsWQLPzxKrPgHLtGmDHo/hs7NS+Xn+USVA+usP7yneyn36YVUB3suHHEIy8suHT5i5YPm6rYc++unqkcbGujbHjdmW+gr7CLfIUzhDQQrTuo/XttSemTplzszcNcs1Oz5nh0pMmTh5MRQqbf/oY/vHXP9DXwMOnc+b3Hz+2LnfThD+zwwgPdH0l+igeGDa0qWNYv8HACGOdMgUgIAA05z1MbwnI0g7uUL+FqYIF3LQo5Iv2a/iQ+zRyAbZYCgzxI1xQxXa+fHrj/kaHEPZFrVvewqux7GHn9KcT1rZn20Eb6kijsRPNDgW19O+3SrbkYpj+JrH1/lxtNO4wRg3lBsMsmyo5se5i7plv6viO3ZK0b+ej61sX8G2pFQyH3N9SwqPp/WReDhSFpGXpCqD4FiOzz1xI67ZBFu1PBKOk0k143po33Kdj+FrKNuxom93Kh+L6zcddktLJNPE62GS9LJRTphiemktn1+bjYTi/ymyysn1LXgjzqexaCLksj8sR8mGSRzehAQhUE4EcgaFUOeSv1QH/ccea54exiE4nPZ3pfKMbELUzfwI1WZhz8mhRCwqbcaDKQ0n2pIUZfIYgfhvojG9KWEoNxhlWV+d84KtI5jCNop4FodrmtCIKldv3eZv8C3qmoO9vOdzard57OV6vdtur3Y63VarxWs2lX3Je6kNT/iLbRLZj2y3xhvyBgNlfrffcbFKseu9et3r8p6m4FLUfcbf8Le39qCKahM39hoGxz+VrWyO5vOc8s1kLwlSCdcQ5qWoeyhVfB6lPBr1Kkr1pUtenwM7Q+5gVQP2Us9fKRWpxuw2WcssXttFR5Vdibqj2gTnP2ju5bpmfINv997mKlc/R+PSCM2R48nfE4sSvDWRwo/6UuU4+9ODOxNpvNYT8aSrGdcyVUVRkuuysq5FQxHF92NWdtI2uqgSgAY0CABkQIUqZPnK9dshDSQAgMFBAADACYw0mrBYzvkjzbVQwrRDrST8TBSgcpCYJbwDsHe15AuYOjthYdfuBVNNaip+PYBgECR9cW4PaCDMFbMa7CYVKrtIirIsEFmSQGuXbKRc08HBypbsnw0cCimurtT2sysP5c7/L02UfgEA+K3z8VP5dNPte4OjB/7f19JCEEAEQbNJfDyAvBmbGb7BLxA6PviHt3+eCEHIgTI7TbdTnrMaHXZaI9gMMgEgFfYSgUjpANAJzAoBCToVAQTQKyIAGEclnkKhjJGn6Dx9mTr1OjQ645TTmml9C1pTTTbF7Cs0oXVJ6yhXaG2uIJ+fN131vD7HnNPstBa1JtJa4jxjyFbehNATsv0Eba1Kx01c2g2ZnfCjmpxRp5bWFBNNTqsiwCCr53WbagEAAAA=) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: normal; + font-style: italic; + unicode-range: U+F8FF-10FFFF; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,d09GMk9UVE8AAAJwAAsAAAAAA/gAAAInAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYIOGyAcKgZgAAQBNgIkAwQEBgWBdAcgGzMDIL4Mb4gcpY8lI6bRFpuvq4/OWEUk/8G00RY3bzZ45QTP/4/7fp977/hhqDRrEowk18nij7AjlZhdyoMv5jaxZE2Bj3goRCo0jjQxTYTacALb/XAD3u4CDzHDKgCagaf4WPsskuLqgQ3PZuX/n3qBs2kmff9/N/kG2b0PAne7CZpHlGAY9xJq09hCASUSoGTuSs0f2zl4eIgSJghGISKxbXaRXsuiPBy17rvw/Wa3uNuCe5R7qd2i2WdRPsGis68g+3ZpyKuftUT4Ml8LiPrqLUz7F5d4lxWHEbH1TwVznkJxQVFRUcPp5HpB22zRiZu6iSW3/FDmps8biI7jmrPj9tdyRFd98BQsNBZBEBFl2zjn+X2+8fxv6Xy4zzkaIU9y/93vGj4f6Sv2n94f9TP6mJ9Hjhzx9Fp4eubk6SNHH1qsnnViFoQdT0KAaDJlk7aOyw1hMAChEACF5cmnyrGLc12BiEREu1GP5QhhGG1RP8C4Wq3coCSGCSj319jF//XtoAt9W6KaQI4DVI22ALkMAAIIJP+TmbHrYDBPAH5p8KtXb689cwMKjQJAQH8K7tVQaL38SkDoDwAARJ3ABkOIABGM44iJAtYQEwTDGigUW6CBnayhJWGkZwXhRfafy2pu4jDqwF25ShQpVrUSDJE05ZqfwVAUZ+7L7O+kXdQXR7maswwqDVrA81Xk1w6+d1Rg+3GHm9q4LECxAkXRaxpCbqELSggA) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: bold; + font-style: normal; + unicode-range: U+0000-007F; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,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) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: bold; + font-style: normal; + unicode-range: U+0080-1AFF; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,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) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: bold; + font-style: normal; + unicode-range: U+1B00-218F; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,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) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: bold; + font-style: normal; + unicode-range: U+2190-21FF; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,d09GMk9UVE8AAAUwAAsAAAAAB1AAAATmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYgiGyAcKgZgADQBNgIkAxgEBgWBdAcgG4sGAI7TpTZgEnN0/bdZ/WbmEV2iJA6zYsqmkhMnIk5BTAcihkUMkpy4sKwZOZW/86+rntyLICrXkQ0QR08+dWrm0gQ092BRC9DqXtSrFmhMLHCpwL2epzzWACpGhKqRXuEpp/dUeAUCAgeEEGVSsaH2AaPBuPtMK1N7Z4K8GeQtgSBv5eRtvBwusJBAXv0Y9B08uGa1Cq8P9LGwZ+MB/BzxAMI3FN8NuvJ/Wyh+GAJKQvxDYjftPnI66b6Uwkdeeru4ocHYGjOaaq4brORYs5kiqzHz43HWWGZoNlQf2H/8SMsd5Y5Fjq9N5ffv2QcdWSrnbSvN237wz3wHOHNnXr9OX1r74QSeH2ZgOI82/g8dsxCCYs+IPs2/AICQIT8I4IAAB1odPoJ/yf3kNfI7t4Mr5p5UvokvJnrtWBYaZvbgd6pOqUvqipGme1xmdViRfcQxYrfgMKuIct9ip1BD5VM/LmsVqEUx6zZVWvExKy6G4kfesCLcgU4ViqilYY8tJ/4on/VBDTt1y82q0EpdZpOrO7ZL6uqUNKyMWanyTVnL6ry441JomBkvyeUqPMNEuqw9Lp9SsJNM474Lh7CChhXZbQ673e7rmpmedsbMdTk7nWpmwTKqHG+Rf2sl+M6PPL69oOp0OjvnYl2zrrkZDVah5S4307BTVE44vpzkw0TU3plFld9ji85rxnvIW/ilSjJJZilGmu6d7VE7hh0jjhF8gJ2Jct9k3L8UryoYt9V9Nz6AZxx2dKEjenZ6esoZ4zTNdM+qWTomZicht5Wy6wrk/s1epEpWu7RgRRPBj7z8P7JbtZiFgRhFV+72YYEYnZSJmayKSrMzkjPWOTU9O62xOUYddgemYHHUXW4WwKLp0t0+GMCibrlZChYl61cc0c6e3ikpVjKbuk0a5UU5nSAvZ/LYhBtUTWhEDzt34SL7DD9DfcvMr+zLJ+nggG0wtnKwv1JjG7IODsY8w76ing/9W87i5ffkDJXDxzZlm5iMmbJM9Y+pbRY60S/ZuzrK4sC+bJw5jPrH2Gc444IOPXiuiRl/lajyciAfvVs+o3qCGZkHPck6/Iy5mf5x8yH8somOjVvGYp9acDw7YZmxTGnq8UuvdqJHCOivGrIOWgbVnPNwTI9tYGxA3T/hGnH5pWwuxC+fMP/G9M34GbqTLzIP8zyBxiMuquyaW/phXjvPWuYVrGTcp2tO/smKGfO+zGCdtfp5/T0B3rGxsTeXNgYGemZHJ8fGp54KXLe0LTwegE6qgACAP8RRI0l33p8GviAAAKytAXjcqFtsww2m1Bc3GSDKJQ15gfsI40B5DR/I3QaAnOGSp+BAMmChxbPhsfVj6138s6sI+GeJ31mASQAA7gQfCABinAFuoPlAOBcivCyASAsUKa3/tbWaWuqnejdBqM1hrcZr7S0MOvWfLy+8BgDwfceFS/zsno/da2urf/s5hG+AAA+czwr+wiqy+etcSGvLPYAAfJ9wU6ATLdkByYKglFGJEkagAwEA4AM5eCCCHwB0ABkQEKADcMCBBHgAMHcL7ooUYmwhhZ/zExnVadegWqUqTUTPg+iAffY71jDJpONEJdqJdKpU09er6i1DqVpNqjQz2EOUQO+iM9RQoyZQztPlgZahUGYP0qZkBv24RtWMDET77bGvVngAHWsLcAAAAAA=) format('woff2'); +} +@font-face{ + font-family: "dm"; + font-weight: bold; + font-style: normal; + unicode-range: U+F8FF-10FFFF; + src: local('☺'), + url(data:font/woff2;charset=utf-8;base64,d09GMk9UVE8AAAJ0AAsAAAAAA/QAAAIqAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYILGyAcKgZgAAQBNgIkAwQEBgWBdAcgGzADAC4D7IZjzymg62laLb5im9YqKYd4pp0IH5Q4wfM11t7f3RNPmCSGpIkh4c2yaCYkPItas2reuIZYSNQTM2Ss3ZtaSFrNsPSi0pFIpbFOplQSozQTgtx2D1DYR6JuhAypGLvREA2A7uApPgY1OYgeC8Ayvq0tfgCOy3/OjT9vz2+AA909pwF9/n14lic0TDDgLsCov3cD7HJP9eTYIyKzTeFwCA8+E4xCRLzVnb12vN/reyL9TgUEkfJgglcieJcPbf0Qt29BkrLv8J7zzxfL3bbhyD1wjGfBvFlGfC+BrvfzhBHx1jVXVjwp4PWnrNv+wl6+cBzQyXu6yQ23capTbj9uoPHOagFvx3+WIwca9UT0znIXQESUt2/589nB/3tmaqS0NLrz8cJ7wfRIj9sRh9955/JPstfOQqZk3y3czExOze66PSH71ADLTBIBnGTKJtW1sRzoGIAEAGBYnnxqGre7c9KDHAkko875Ih2j3eoVNMnzyi47CgTI/R/Y5O+BdBB/hz4QRzmYAVQZiQ3kMgAIIPD/xF1r5/lKD3MM+Fw1wOfx8Ya/07h5I9AoAAT0Q/wvR2PC/4+GwJWJmuVBIwSw0URCjAPogY6CoQcVigHUwNDQ4DoL6WWVtc7zaH+wHDXrjYnekaVEkWKlS6TJfCtX11KvsdHs+BudH+X2pDHteZVAhURkrVZjS6jKUF2dVSteBQb3BfvWuNnv6RUrUMSpBo7ENgAAAA==) format('woff2'); +} diff --git a/docs/md/assets/highlight.css b/docs/md/assets/highlight.css new file mode 100644 index 00000000..e69de29b diff --git a/docs/md/assets/highlight.min.js b/docs/md/assets/highlight.min.js new file mode 100644 index 00000000..f43ba9aa --- /dev/null +++ b/docs/md/assets/highlight.min.js @@ -0,0 +1,1213 @@ +/*! + Highlight.js v11.9.0 (git: f47103d4f1) + (c) 2006-2023 undefined and other contributors + License: BSD-3-Clause + */ + var hljs=function(){"use strict";function e(n){ + return n instanceof Map?n.clear=n.delete=n.set=()=>{ + throw Error("map is read-only")}:n instanceof Set&&(n.add=n.clear=n.delete=()=>{ + throw Error("set is read-only") + }),Object.freeze(n),Object.getOwnPropertyNames(n).forEach((t=>{ + const a=n[t],i=typeof a;"object"!==i&&"function"!==i||Object.isFrozen(a)||e(a) + })),n}class n{constructor(e){ + void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} + ignoreMatch(){this.isMatchIgnored=!0}}function t(e){ + return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") + }function a(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n] + ;return n.forEach((e=>{for(const n in e)t[n]=e[n]})),t}const i=e=>!!e.scope + ;class r{constructor(e,n){ + this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){ + this.buffer+=t(e)}openNode(e){if(!i(e))return;const n=((e,{prefix:n})=>{ + if(e.startsWith("language:"))return e.replace("language:","language-") + ;if(e.includes(".")){const t=e.split(".") + ;return[`${n}${t.shift()}`,...t.map(((e,n)=>`${e}${"_".repeat(n+1)}`))].join(" ") + }return`${n}${e}`})(e.scope,{prefix:this.classPrefix});this.span(n)} + closeNode(e){i(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ + this.buffer+=``}}const s=(e={})=>{const n={children:[]} + ;return Object.assign(n,e),n};class o{constructor(){ + this.rootNode=s(),this.stack=[this.rootNode]}get top(){ + return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ + this.top.children.push(e)}openNode(e){const n=s({scope:e}) + ;this.add(n),this.stack.push(n)}closeNode(){ + if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ + for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} + walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){ + return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n), + n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){ + "string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ + o._collapse(e)})))}}class l extends o{constructor(e){super(),this.options=e} + addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){ + this.closeNode()}__addSublanguage(e,n){const t=e.root + ;n&&(t.scope="language:"+n),this.add(t)}toHTML(){ + return new r(this,this.options).value()}finalize(){ + return this.closeAllNodes(),!0}}function c(e){ + return e?"string"==typeof e?e:e.source:null}function d(e){return b("(?=",e,")")} + function g(e){return b("(?:",e,")*")}function u(e){return b("(?:",e,")?")} + function b(...e){return e.map((e=>c(e))).join("")}function m(...e){const n=(e=>{ + const n=e[e.length-1] + ;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} + })(e);return"("+(n.capture?"":"?:")+e.map((e=>c(e))).join("|")+")"} + function p(e){return RegExp(e.toString()+"|").exec("").length-1} + const _=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ + ;function h(e,{joinWith:n}){let t=0;return e.map((e=>{t+=1;const n=t + ;let a=c(e),i="";for(;a.length>0;){const e=_.exec(a);if(!e){i+=a;break} + i+=a.substring(0,e.index), + a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0], + "("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)} + const f="[a-zA-Z]\\w*",E="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",N="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",v={ + begin:"\\\\[\\s\\S]",relevance:0},O={scope:"string",begin:"'",end:"'", + illegal:"\\n",contains:[v]},k={scope:"string",begin:'"',end:'"',illegal:"\\n", + contains:[v]},x=(e,n,t={})=>{const i=a({scope:"comment",begin:e,end:n, + contains:[]},t);i.contains.push({scope:"doctag", + begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)", + end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0}) + ;const r=m("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/) + ;return i.contains.push({begin:b(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i + },M=x("//","$"),S=x("/\\*","\\*/"),A=x("#","$");var C=Object.freeze({ + __proto__:null,APOS_STRING_MODE:O,BACKSLASH_ESCAPE:v,BINARY_NUMBER_MODE:{ + scope:"number",begin:w,relevance:0},BINARY_NUMBER_RE:w,COMMENT:x, + C_BLOCK_COMMENT_MODE:S,C_LINE_COMMENT_MODE:M,C_NUMBER_MODE:{scope:"number", + begin:N,relevance:0},C_NUMBER_RE:N,END_SAME_AS_BEGIN:e=>Object.assign(e,{ + "on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{ + n.data._beginMatch!==e[1]&&n.ignoreMatch()}}),HASH_COMMENT_MODE:A,IDENT_RE:f, + MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+E,relevance:0}, + NUMBER_MODE:{scope:"number",begin:y,relevance:0},NUMBER_RE:y, + PHRASAL_WORDS_MODE:{ + begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ + },QUOTE_STRING_MODE:k,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/, + end:/\/[gimuy]*/,contains:[v,{begin:/\[/,end:/\]/,relevance:0,contains:[v]}]}, + RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", + SHEBANG:(e={})=>{const n=/^#![ ]*\// + ;return e.binary&&(e.begin=b(n,/.*\b/,e.binary,/\b.*/)),a({scope:"meta",begin:n, + end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)}, + TITLE_MODE:{scope:"title",begin:f,relevance:0},UNDERSCORE_IDENT_RE:E, + UNDERSCORE_TITLE_MODE:{scope:"title",begin:E,relevance:0}});function T(e,n){ + "."===e.input[e.index-1]&&n.ignoreMatch()}function R(e,n){ + void 0!==e.className&&(e.scope=e.className,delete e.className)}function D(e,n){ + n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", + e.__beforeBegin=T,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, + void 0===e.relevance&&(e.relevance=0))}function I(e,n){ + Array.isArray(e.illegal)&&(e.illegal=m(...e.illegal))}function L(e,n){ + if(e.match){ + if(e.begin||e.end)throw Error("begin & end are not supported with match") + ;e.begin=e.match,delete e.match}}function B(e,n){ + void 0===e.relevance&&(e.relevance=1)}const $=(e,n)=>{if(!e.beforeMatch)return + ;if(e.starts)throw Error("beforeMatch cannot be used with starts") + ;const t=Object.assign({},e);Object.keys(e).forEach((n=>{delete e[n] + })),e.keywords=t.keywords,e.begin=b(t.beforeMatch,d(t.begin)),e.starts={ + relevance:0,contains:[Object.assign(t,{endsParent:!0})] + },e.relevance=0,delete t.beforeMatch + },z=["of","and","for","in","not","or","if","then","parent","list","value"],F="keyword" + ;function U(e,n,t=F){const a=Object.create(null) + ;return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((t=>{ + Object.assign(a,U(e[t],n,t))})),a;function i(e,t){ + n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((n=>{const t=n.split("|") + ;a[t[0]]=[e,j(t[0],t[1])]}))}}function j(e,n){ + return n?Number(n):(e=>z.includes(e.toLowerCase()))(e)?0:1}const P={},K=e=>{ + console.error(e)},H=(e,...n)=>{console.log("WARN: "+e,...n)},q=(e,n)=>{ + P[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),P[`${e}/${n}`]=!0) + },G=Error();function Z(e,n,{key:t}){let a=0;const i=e[t],r={},s={} + ;for(let e=1;e<=n.length;e++)s[e+a]=i[e],r[e+a]=!0,a+=p(n[e-1]) + ;e[t]=s,e[t]._emit=r,e[t]._multi=!0}function W(e){(e=>{ + e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, + delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ + _wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope + }),(e=>{if(Array.isArray(e.begin)){ + if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), + G + ;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"), + G;Z(e,e.begin,{key:"beginScope"}),e.begin=h(e.begin,{joinWith:""})}})(e),(e=>{ + if(Array.isArray(e.end)){ + if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"), + G + ;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"), + G;Z(e,e.end,{key:"endScope"}),e.end=h(e.end,{joinWith:""})}})(e)}function Q(e){ + function n(n,t){ + return RegExp(c(n),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(t?"g":"")) + }class t{constructor(){ + this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} + addRule(e,n){ + n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]), + this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) + ;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(h(e,{joinWith:"|" + }),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex + ;const n=this.matcherRe.exec(e);if(!n)return null + ;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t] + ;return n.splice(0,t),Object.assign(n,a)}}class i{constructor(){ + this.rules=[],this.multiRegexes=[], + this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ + if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t + ;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))), + n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){ + return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){ + this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){ + const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex + ;let t=n.exec(e) + ;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{ + const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)} + return t&&(this.regexIndex+=t.position+1, + this.regexIndex===this.count&&this.considerAll()),t}} + if(e.compilerExtensions||(e.compilerExtensions=[]), + e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") + ;return e.classNameAliases=a(e.classNameAliases||{}),function t(r,s){const o=r + ;if(r.isCompiled)return o + ;[R,L,W,$].forEach((e=>e(r,s))),e.compilerExtensions.forEach((e=>e(r,s))), + r.__beforeBegin=null,[D,I,B].forEach((e=>e(r,s))),r.isCompiled=!0;let l=null + ;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords), + l=r.keywords.$pattern, + delete r.keywords.$pattern),l=l||/\w+/,r.keywords&&(r.keywords=U(r.keywords,e.case_insensitive)), + o.keywordPatternRe=n(l,!0), + s&&(r.begin||(r.begin=/\B|\b/),o.beginRe=n(o.begin),r.end||r.endsWithParent||(r.end=/\B|\b/), + r.end&&(o.endRe=n(o.end)), + o.terminatorEnd=c(o.end)||"",r.endsWithParent&&s.terminatorEnd&&(o.terminatorEnd+=(r.end?"|":"")+s.terminatorEnd)), + r.illegal&&(o.illegalRe=n(r.illegal)), + r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((n=>a(e,{ + variants:null},n)))),e.cachedVariants?e.cachedVariants:X(e)?a(e,{ + starts:e.starts?a(e.starts):null + }):Object.isFrozen(e)?a(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{t(e,o) + })),r.starts&&t(r.starts,s),o.matcher=(e=>{const n=new i + ;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin" + }))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end" + }),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function X(e){ + return!!e&&(e.endsWithParent||X(e.starts))}class V extends Error{ + constructor(e,n){super(e),this.name="HTMLInjectionError",this.html=n}} + const J=t,Y=a,ee=Symbol("nomatch"),ne=t=>{ + const a=Object.create(null),i=Object.create(null),r=[];let s=!0 + ;const o="Could not find the language '{}', did you forget to load/include a language module?",c={ + disableAutodetect:!0,name:"Plain text",contains:[]};let p={ + ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, + languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", + cssSelector:"pre code",languages:null,__emitter:l};function _(e){ + return p.noHighlightRe.test(e)}function h(e,n,t){let a="",i="" + ;"object"==typeof n?(a=e, + t=n.ignoreIllegals,i=n.language):(q("10.7.0","highlight(lang, code, ...args) has been deprecated."), + q("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), + i=e,a=n),void 0===t&&(t=!0);const r={code:a,language:i};x("before:highlight",r) + ;const s=r.result?r.result:f(r.language,r.code,t) + ;return s.code=r.code,x("after:highlight",s),s}function f(e,t,i,r){ + const l=Object.create(null);function c(){if(!x.keywords)return void S.addText(A) + ;let e=0;x.keywordPatternRe.lastIndex=0;let n=x.keywordPatternRe.exec(A),t="" + ;for(;n;){t+=A.substring(e,n.index) + ;const i=w.case_insensitive?n[0].toLowerCase():n[0],r=(a=i,x.keywords[a]);if(r){ + const[e,a]=r + ;if(S.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(C+=a),e.startsWith("_"))t+=n[0];else{ + const t=w.classNameAliases[e]||e;g(n[0],t)}}else t+=n[0] + ;e=x.keywordPatternRe.lastIndex,n=x.keywordPatternRe.exec(A)}var a + ;t+=A.substring(e),S.addText(t)}function d(){null!=x.subLanguage?(()=>{ + if(""===A)return;let e=null;if("string"==typeof x.subLanguage){ + if(!a[x.subLanguage])return void S.addText(A) + ;e=f(x.subLanguage,A,!0,M[x.subLanguage]),M[x.subLanguage]=e._top + }else e=E(A,x.subLanguage.length?x.subLanguage:null) + ;x.relevance>0&&(C+=e.relevance),S.__addSublanguage(e._emitter,e.language) + })():c(),A=""}function g(e,n){ + ""!==e&&(S.startScope(n),S.addText(e),S.endScope())}function u(e,n){let t=1 + ;const a=n.length-1;for(;t<=a;){if(!e._emit[t]){t++;continue} + const a=w.classNameAliases[e[t]]||e[t],i=n[t];a?g(i,a):(A=i,c(),A=""),t++}} + function b(e,n){ + return e.scope&&"string"==typeof e.scope&&S.openNode(w.classNameAliases[e.scope]||e.scope), + e.beginScope&&(e.beginScope._wrap?(g(A,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), + A=""):e.beginScope._multi&&(u(e.beginScope,n),A="")),x=Object.create(e,{parent:{ + value:x}}),x}function m(e,t,a){let i=((e,n)=>{const t=e&&e.exec(n) + ;return t&&0===t.index})(e.endRe,a);if(i){if(e["on:end"]){const a=new n(e) + ;e["on:end"](t,a),a.isMatchIgnored&&(i=!1)}if(i){ + for(;e.endsParent&&e.parent;)e=e.parent;return e}} + if(e.endsWithParent)return m(e.parent,t,a)}function _(e){ + return 0===x.matcher.regexIndex?(A+=e[0],1):(D=!0,0)}function h(e){ + const n=e[0],a=t.substring(e.index),i=m(x,e,a);if(!i)return ee;const r=x + ;x.endScope&&x.endScope._wrap?(d(), + g(n,x.endScope._wrap)):x.endScope&&x.endScope._multi?(d(), + u(x.endScope,e)):r.skip?A+=n:(r.returnEnd||r.excludeEnd||(A+=n), + d(),r.excludeEnd&&(A=n));do{ + x.scope&&S.closeNode(),x.skip||x.subLanguage||(C+=x.relevance),x=x.parent + }while(x!==i.parent);return i.starts&&b(i.starts,e),r.returnEnd?0:n.length} + let y={};function N(a,r){const o=r&&r[0];if(A+=a,null==o)return d(),0 + ;if("begin"===y.type&&"end"===r.type&&y.index===r.index&&""===o){ + if(A+=t.slice(r.index,r.index+1),!s){const n=Error(`0 width match regex (${e})`) + ;throw n.languageName=e,n.badRule=y.rule,n}return 1} + if(y=r,"begin"===r.type)return(e=>{ + const t=e[0],a=e.rule,i=new n(a),r=[a.__beforeBegin,a["on:begin"]] + ;for(const n of r)if(n&&(n(e,i),i.isMatchIgnored))return _(t) + ;return a.skip?A+=t:(a.excludeBegin&&(A+=t), + d(),a.returnBegin||a.excludeBegin||(A=t)),b(a,e),a.returnBegin?0:t.length})(r) + ;if("illegal"===r.type&&!i){ + const e=Error('Illegal lexeme "'+o+'" for mode "'+(x.scope||"")+'"') + ;throw e.mode=x,e}if("end"===r.type){const e=h(r);if(e!==ee)return e} + if("illegal"===r.type&&""===o)return 1 + ;if(R>1e5&&R>3*r.index)throw Error("potential infinite loop, way more iterations than matches") + ;return A+=o,o.length}const w=v(e) + ;if(!w)throw K(o.replace("{}",e)),Error('Unknown language: "'+e+'"') + ;const O=Q(w);let k="",x=r||O;const M={},S=new p.__emitter(p);(()=>{const e=[] + ;for(let n=x;n!==w;n=n.parent)n.scope&&e.unshift(n.scope) + ;e.forEach((e=>S.openNode(e)))})();let A="",C=0,T=0,R=0,D=!1;try{ + if(w.__emitTokens)w.__emitTokens(t,S);else{for(x.matcher.considerAll();;){ + R++,D?D=!1:x.matcher.considerAll(),x.matcher.lastIndex=T + ;const e=x.matcher.exec(t);if(!e)break;const n=N(t.substring(T,e.index),e) + ;T=e.index+n}N(t.substring(T))}return S.finalize(),k=S.toHTML(),{language:e, + value:k,relevance:C,illegal:!1,_emitter:S,_top:x}}catch(n){ + if(n.message&&n.message.includes("Illegal"))return{language:e,value:J(t), + illegal:!0,relevance:0,_illegalBy:{message:n.message,index:T, + context:t.slice(T-100,T+100),mode:n.mode,resultSoFar:k},_emitter:S};if(s)return{ + language:e,value:J(t),illegal:!1,relevance:0,errorRaised:n,_emitter:S,_top:x} + ;throw n}}function E(e,n){n=n||p.languages||Object.keys(a);const t=(e=>{ + const n={value:J(e),illegal:!1,relevance:0,_top:c,_emitter:new p.__emitter(p)} + ;return n._emitter.addText(e),n})(e),i=n.filter(v).filter(k).map((n=>f(n,e,!1))) + ;i.unshift(t);const r=i.sort(((e,n)=>{ + if(e.relevance!==n.relevance)return n.relevance-e.relevance + ;if(e.language&&n.language){if(v(e.language).supersetOf===n.language)return 1 + ;if(v(n.language).supersetOf===e.language)return-1}return 0})),[s,o]=r,l=s + ;return l.secondBest=o,l}function y(e){let n=null;const t=(e=>{ + let n=e.className+" ";n+=e.parentNode?e.parentNode.className:"" + ;const t=p.languageDetectRe.exec(n);if(t){const n=v(t[1]) + ;return n||(H(o.replace("{}",t[1])), + H("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"} + return n.split(/\s+/).find((e=>_(e)||v(e)))})(e);if(_(t))return + ;if(x("before:highlightElement",{el:e,language:t + }),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e) + ;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), + console.warn("https://github.com/highlightjs/highlight.js/wiki/security"), + console.warn("The element with unescaped HTML:"), + console.warn(e)),p.throwUnescapedHTML))throw new V("One of your code blocks includes unescaped HTML.",e.innerHTML) + ;n=e;const a=n.textContent,r=t?h(a,{language:t,ignoreIllegals:!0}):E(a) + ;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,n,t)=>{const a=n&&i[n]||t + ;e.classList.add("hljs"),e.classList.add("language-"+a) + })(e,t,r.language),e.result={language:r.language,re:r.relevance, + relevance:r.relevance},r.secondBest&&(e.secondBest={ + language:r.secondBest.language,relevance:r.secondBest.relevance + }),x("after:highlightElement",{el:e,result:r,text:a})}let N=!1;function w(){ + "loading"!==document.readyState?document.querySelectorAll(p.cssSelector).forEach(y):N=!0 + }function v(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]} + function O(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ + i[e.toLowerCase()]=n}))}function k(e){const n=v(e) + ;return n&&!n.disableAutodetect}function x(e,n){const t=e;r.forEach((e=>{ + e[t]&&e[t](n)}))} + "undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{ + N&&w()}),!1),Object.assign(t,{highlight:h,highlightAuto:E,highlightAll:w, + highlightElement:y, + highlightBlock:e=>(q("10.7.0","highlightBlock will be removed entirely in v12.0"), + q("10.7.0","Please use highlightElement now."),y(e)),configure:e=>{p=Y(p,e)}, + initHighlighting:()=>{ + w(),q("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, + initHighlightingOnLoad:()=>{ + w(),q("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") + },registerLanguage:(e,n)=>{let i=null;try{i=n(t)}catch(n){ + if(K("Language definition for '{}' could not be registered.".replace("{}",e)), + !s)throw n;K(n),i=c} + i.name||(i.name=e),a[e]=i,i.rawDefinition=n.bind(null,t),i.aliases&&O(i.aliases,{ + languageName:e})},unregisterLanguage:e=>{delete a[e] + ;for(const n of Object.keys(i))i[n]===e&&delete i[n]}, + listLanguages:()=>Object.keys(a),getLanguage:v,registerAliases:O, + autoDetection:k,inherit:Y,addPlugin:e=>{(e=>{ + e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{ + e["before:highlightBlock"](Object.assign({block:n.el},n)) + }),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{ + e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),r.push(e)}, + removePlugin:e=>{const n=r.indexOf(e);-1!==n&&r.splice(n,1)}}),t.debugMode=()=>{ + s=!1},t.safeMode=()=>{s=!0},t.versionString="11.9.0",t.regex={concat:b, + lookahead:d,either:m,optional:u,anyNumberOfTimes:g} + ;for(const n in C)"object"==typeof C[n]&&e(C[n]);return Object.assign(t,C),t + },te=ne({});te.newInstance=()=>ne({});var ae=te;const ie=e=>({IMPORTANT:{ + scope:"meta",begin:"!important"},BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{ + scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/}, + FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/}, + ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$", + contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{ + scope:"number", + begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", + relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z_][A-Za-z0-9_-]*/} + }),re=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],se=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],oe=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],le=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],ce=["align-content","align-items","align-self","all","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","content-visibility","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-synthesis","font-variant","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inline-size","isolation","justify-content","left","letter-spacing","line-break","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","perspective","perspective-origin","pointer-events","position","quotes","resize","rest","rest-after","rest-before","right","row-gap","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","speak","speak-as","src","tab-size","table-layout","text-align","text-align-all","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-box","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index"].reverse(),de=oe.concat(le) + ;var ge="[0-9](_*[0-9])*",ue=`\\.(${ge})`,be="[0-9a-fA-F](_*[0-9a-fA-F])*",me={ + className:"number",variants:[{ + begin:`(\\b(${ge})((${ue})|\\.)?|(${ue}))[eE][+-]?(${ge})[fFdD]?\\b`},{ + begin:`\\b(${ge})((${ue})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{ + begin:`(${ue})[fFdD]?\\b`},{begin:`\\b(${ge})[fFdD]\\b`},{ + begin:`\\b0[xX]((${be})\\.?|(${be})?\\.(${be}))[pP][+-]?(${ge})[fFdD]?\\b`},{ + begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${be})[lL]?\\b`},{ + begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], + relevance:0};function pe(e,n,t){return-1===t?"":e.replace(n,(a=>pe(e,n,t-1)))} + const _e="[A-Za-z$_][0-9A-Za-z$_]*",he=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],fe=["true","false","null","undefined","NaN","Infinity"],Ee=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],ye=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],Ne=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],we=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],ve=[].concat(Ne,Ee,ye) + ;function Oe(e){const n=e.regex,t=_e,a={begin:/<[A-Za-z0-9\\._:-]+/, + end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ + const t=e[0].length+e.index,a=e.input[t] + ;if("<"===a||","===a)return void n.ignoreMatch();let i + ;">"===a&&(((e,{after:n})=>{const t="",M={ + match:[/const|var|let/,/\s+/,t,/\s*/,/=\s*/,/(async\s*)?/,n.lookahead(x)], + keywords:"async",className:{1:"keyword",3:"title.function"},contains:[f]} + ;return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:i,exports:{ + PARAMS_CONTAINS:h,CLASS_REFERENCE:y},illegal:/#(?![$_A-z])/, + contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),{ + label:"use_strict",className:"meta",relevance:10, + begin:/^\s*['"]use (strict|asm)['"]/ + },e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,d,g,u,b,m,{match:/\$\d+/},l,y,{ + className:"attr",begin:t+n.lookahead(":"),relevance:0},M,{ + begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", + keywords:"return throw case",relevance:0,contains:[m,e.REGEXP_MODE,{ + className:"function",begin:x,returnBegin:!0,end:"\\s*=>",contains:[{ + className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{ + className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0, + excludeEnd:!0,keywords:i,contains:h}]}]},{begin:/,/,relevance:0},{match:/\s+/, + relevance:0},{variants:[{begin:"<>",end:""},{ + match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:a.begin, + "on:begin":a.isTrulyOpeningTag,end:a.end}],subLanguage:"xml",contains:[{ + begin:a.begin,end:a.end,skip:!0,contains:["self"]}]}]},N,{ + beginKeywords:"while if switch catch for"},{ + begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", + returnBegin:!0,label:"func.def",contains:[f,e.inherit(e.TITLE_MODE,{begin:t, + className:"title.function"})]},{match:/\.\.\./,relevance:0},O,{match:"\\$"+t, + relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, + contains:[f]},w,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, + className:"variable.constant"},E,k,{match:/\$[(.]/}]}} + const ke=e=>b(/\b/,e,/\w$/.test(e)?/\b/:/\B/),xe=["Protocol","Type"].map(ke),Me=["init","self"].map(ke),Se=["Any","Self"],Ae=["actor","any","associatedtype","async","await",/as\?/,/as!/,"as","borrowing","break","case","catch","class","consume","consuming","continue","convenience","copy","default","defer","deinit","didSet","distributed","do","dynamic","each","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","macro","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Ce=["false","nil","true"],Te=["assignment","associativity","higherThan","left","lowerThan","none","right"],Re=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warning"],De=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],Ie=m(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Le=m(Ie,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),Be=b(Ie,Le,"*"),$e=m(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),ze=m($e,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Fe=b($e,ze,"*"),Ue=b(/[A-Z]/,ze,"*"),je=["attached","autoclosure",b(/convention\(/,m("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","freestanding","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",b(/objc\(/,Fe,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","Sendable","testable","UIApplicationMain","unchecked","unknown","usableFromInline","warn_unqualified_access"],Pe=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"] + ;var Ke=Object.freeze({__proto__:null,grmr_bash:e=>{const n=e.regex,t={},a={ + begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]} + ;Object.assign(t,{className:"variable",variants:[{ + begin:n.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const i={ + className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},r={ + begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/, + end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/, + contains:[e.BACKSLASH_ESCAPE,t,i]};i.contains.push(s);const o={begin:/\$?\(\(/, + end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t] + },l=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10 + }),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, + contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ + name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/, + keyword:["if","then","else","elif","fi","for","while","until","in","do","done","case","esac","function","select"], + literal:["true","false"], + built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"] + },contains:[l,e.SHEBANG(),c,o,e.HASH_COMMENT_MODE,r,{match:/(\/[a-z._-]+)+/},s,{ + match:/\\"/},{className:"string",begin:/'/,end:/'/},{match:/\\'/},t]}}, + grmr_c:e=>{const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}] + }),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ + className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{ + match:/\batomic_[a-z]{3,6}\b/}]},o={className:"string",variants:[{ + begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ + begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", + end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ + begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ + className:"number",variants:[{begin:"\\b(0b[01']+)"},{ + begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" + },{ + begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" + }],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ + keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" + },contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ + className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ + className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 + },g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ + keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"], + type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","const","static","complex","bool","imaginary"], + literal:"true false NULL", + built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr" + },b=[c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],m={variants:[{begin:/=/,end:/;/},{ + begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], + keywords:u,contains:b.concat([{begin:/\(/,end:/\)/,keywords:u, + contains:b.concat(["self"]),relevance:0}]),relevance:0},p={ + begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, + keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ + begin:g,returnBegin:!0,contains:[e.inherit(d,{className:"title.function"})], + relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/, + keywords:u,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/, + end:/\)/,keywords:u,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s] + }]},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C",aliases:["h"],keywords:u, + disableAutodetect:!0,illegal:"=]/,contains:[{ + beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:c, + strings:o,keywords:u}}},grmr_cpp:e=>{const n=e.regex,t=e.COMMENT("//","$",{ + contains:[{begin:/\\\n/}] + }),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="(?!struct)("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ + className:"type",begin:"\\b[a-z\\d_]*_t\\b"},o={className:"string",variants:[{ + begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ + begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", + end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ + begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ + className:"number",variants:[{begin:"\\b(0b[01']+)"},{ + begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" + },{ + begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" + }],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ + keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" + },contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ + className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ + className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 + },g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ + type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"], + keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"], + literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"], + _type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"] + },b={className:"function.dispatch",relevance:0,keywords:{ + _hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"] + }, + begin:n.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,n.lookahead(/(<[^<>]+>|)\s*\(/)) + },m=[b,c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],p={variants:[{begin:/=/,end:/;/},{ + begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], + keywords:u,contains:m.concat([{begin:/\(/,end:/\)/,keywords:u, + contains:m.concat(["self"]),relevance:0}]),relevance:0},_={className:"function", + begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, + keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ + begin:g,returnBegin:!0,contains:[d],relevance:0},{begin:/::/,relevance:0},{ + begin:/:/,endsWithParent:!0,contains:[o,l]},{relevance:0,match:/,/},{ + className:"params",begin:/\(/,end:/\)/,keywords:u,relevance:0, + contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/,end:/\)/,keywords:u, + relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s]}] + },s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C++", + aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:u,illegal:"",keywords:u,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:u},{ + match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/], + className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={ + keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]), + built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"], + literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{ + begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{ + begin:"\\b(0b[01']+)"},{ + begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ + begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" + }],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}] + },r=e.inherit(i,{illegal:/\n/}),s={className:"subst",begin:/\{/,end:/\}/, + keywords:n},o=e.inherit(s,{illegal:/\n/}),l={className:"string",begin:/\$"/, + end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/ + },e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{ + begin:/\{\{/},{begin:/\}\}/},{begin:'""'},s]},d=e.inherit(c,{illegal:/\n/, + contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]}) + ;s.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE], + o.contains=[d,l,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{ + illegal:/\n/})];const g={variants:[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] + },u={begin:"<",end:">",contains:[{beginKeywords:"in out"},t] + },b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={ + begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"], + keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0, + contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{ + begin:"\x3c!--|--\x3e"},{begin:""}]}] + }),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#", + end:"$",keywords:{ + keyword:"if else elif endif define undef warning error line region endregion pragma checksum" + }},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/, + illegal:/[^\s:,]/,contains:[{beginKeywords:"where class" + },t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace", + relevance:0,end:/[{;=]/,illegal:/[^\s:]/, + contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ + beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/, + contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta", + begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{ + className:"string",begin:/"/,end:/"/}]},{ + beginKeywords:"new return throw await else",relevance:0},{className:"function", + begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, + end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{ + beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial", + relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, + contains:[e.TITLE_MODE,u],relevance:0},{match:/\(\)/},{className:"params", + begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0, + contains:[g,a,e.C_BLOCK_COMMENT_MODE] + },e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{ + const n=e.regex,t=ie(e),a=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{ + name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{ + keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"}, + contains:[t.BLOCK_COMMENT,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/ + },t.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0 + },{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0 + },t.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{ + begin:":("+oe.join("|")+")"},{begin:":(:)?("+le.join("|")+")"}] + },t.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b"},{ + begin:/:/,end:/[;}{]/, + contains:[t.BLOCK_COMMENT,t.HEXCOLOR,t.IMPORTANT,t.CSS_NUMBER_MODE,...a,{ + begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri" + },contains:[...a,{className:"string",begin:/[^)]/,endsWithParent:!0, + excludeEnd:!0}]},t.FUNCTION_DISPATCH]},{begin:n.lookahead(/@/),end:"[{;]", + relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/ + },{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{ + $pattern:/[a-z-]+/,keyword:"and or not only",attribute:se.join(" ")},contains:[{ + begin:/[a-z-]+(?=:)/,className:"attribute"},...a,t.CSS_NUMBER_MODE]}]},{ + className:"selector-tag",begin:"\\b("+re.join("|")+")\\b"}]}},grmr_diff:e=>{ + const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{ + className:"meta",relevance:10, + match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/) + },{className:"comment",variants:[{ + begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/), + end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{ + className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/, + end:/$/}]}},grmr_go:e=>{const n={ + keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"], + type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"], + literal:["true","false","iota","nil"], + built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"] + };return{name:"Go",aliases:["golang"],keywords:n,illegal:"{const n=e.regex;return{name:"GraphQL",aliases:["gql"], + case_insensitive:!0,disableAutodetect:!1,keywords:{ + keyword:["query","mutation","subscription","type","input","schema","directive","interface","union","scalar","fragment","enum","on"], + literal:["true","false","null"]}, + contains:[e.HASH_COMMENT_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{ + scope:"punctuation",match:/[.]{3}/,relevance:0},{scope:"punctuation", + begin:/[\!\(\)\:\=\[\]\{\|\}]{1}/,relevance:0},{scope:"variable",begin:/\$/, + end:/\W/,excludeEnd:!0,relevance:0},{scope:"meta",match:/@\w+/,excludeEnd:!0},{ + scope:"symbol",begin:n.concat(/[_A-Za-z][_0-9A-Za-z]*/,n.lookahead(/\s*:/)), + relevance:0}],illegal:[/[;<']/,/BEGIN/]}},grmr_ini:e=>{const n=e.regex,t={ + className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{ + begin:e.NUMBER_RE}]},a=e.COMMENT();a.variants=[{begin:/;/,end:/$/},{begin:/#/, + end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{ + begin:/\$\{(.*?)\}/}]},r={className:"literal", + begin:/\bon|off|true|false|yes|no\b/},s={className:"string", + contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{ + begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}] + },o={begin:/\[/,end:/\]/,contains:[a,r,i,s,t,"self"],relevance:0 + },l=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{ + name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/, + contains:[a,{className:"section",begin:/\[+/,end:/\]+/},{ + begin:n.concat(l,"(\\s*\\.\\s*",l,")*",n.lookahead(/\s*=\s*[^#\s]/)), + className:"attr",starts:{end:/$/,contains:[a,o,r,i,s,t]}}]}},grmr_java:e=>{ + const n=e.regex,t="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",a=t+pe("(?:<"+t+"~~~(?:\\s*,\\s*"+t+"~~~)*>)?",/~~~/g,2),i={ + keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits"], + literal:["false","true","null"], + type:["char","boolean","long","float","int","byte","short","double"], + built_in:["super","this"]},r={className:"meta",begin:"@"+t,contains:[{ + begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/, + end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} + ;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/, + contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, + relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ + begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 + },e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/, + className:"string",contains:[e.BACKSLASH_ESCAPE] + },e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ + match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,t],className:{ + 1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{ + begin:[n.concat(/(?!else)/,t),/\s+/,t,/\s+/,/=(?!=)/],className:{1:"type", + 3:"variable",5:"operator"}},{begin:[/record/,/\s+/,t],className:{1:"keyword", + 3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ + beginKeywords:"new throw return else",relevance:0},{ + begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ + 2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/, + end:/\)/,keywords:i,relevance:0, + contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,me,e.C_BLOCK_COMMENT_MODE] + },e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},me,r]}},grmr_javascript:Oe, + grmr_json:e=>{const n=["true","false","null"],t={scope:"literal", + beginKeywords:n.join(" ")};return{name:"JSON",keywords:{literal:n},contains:[{ + className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{ + match:/[{}[\],:]/,className:"punctuation",relevance:0 + },e.QUOTE_STRING_MODE,t,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE], + illegal:"\\S"}},grmr_kotlin:e=>{const n={ + keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", + built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", + literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" + },a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={ + className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string", + variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'", + illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, + contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={ + className:"meta", + begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" + },o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, + end:/\)/,contains:[e.inherit(r,{className:"string"}),"self"]}] + },l=me,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={ + variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/, + contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g], + {name:"Kotlin",aliases:["kt","kts"],keywords:n, + contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag", + begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword", + begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", + begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$", + returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{ + begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, + contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, + keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, + endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, + endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0 + },e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{ + begin:[/class|interface|trait/,/\s+/,e.UNDERSCORE_IDENT_RE],beginScope:{ + 3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, + illegal:"extends implements",contains:[{ + beginKeywords:"public protected internal private constructor" + },e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, + excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/, + excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env", + end:"$",illegal:"\n"},l]}},grmr_less:e=>{ + const n=ie(e),t=de,a="[\\w-]+",i="("+a+"|@\\{"+a+"\\})",r=[],s=[],o=e=>({ + className:"string",begin:"~?"+e+".*?"+e}),l=(e,n,t)=>({className:e,begin:n, + relevance:t}),c={$pattern:/[a-z-]+/,keyword:"and or not only", + attribute:se.join(" ")},d={begin:"\\(",end:"\\)",contains:s,keywords:c, + relevance:0} + ;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,o("'"),o('"'),n.CSS_NUMBER_MODE,{ + begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]", + excludeEnd:!0} + },n.HEXCOLOR,d,l("variable","@@?"+a,10),l("variable","@\\{"+a+"\\}"),l("built_in","~?`[^`]*?`"),{ + className:"attribute",begin:a+"\\s*:",end:":",returnBegin:!0,excludeEnd:!0 + },n.IMPORTANT,{beginKeywords:"and not"},n.FUNCTION_DISPATCH);const g=s.concat({ + begin:/\{/,end:/\}/,contains:r}),u={beginKeywords:"when",endsWithParent:!0, + contains:[{beginKeywords:"and not"}].concat(s)},b={begin:i+"\\s*:", + returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/ + },n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b", + end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}] + },m={className:"keyword", + begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b", + starts:{end:"[;{}]",keywords:c,returnEnd:!0,contains:s,relevance:0}},p={ + className:"variable",variants:[{begin:"@"+a+"\\s*:",relevance:15},{begin:"@"+a + }],starts:{end:"[;}]",returnEnd:!0,contains:g}},_={variants:[{ + begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:i,end:/\{/}],returnBegin:!0, + returnEnd:!0,illegal:"[<='$\"]",relevance:0, + contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,u,l("keyword","all\\b"),l("variable","@\\{"+a+"\\}"),{ + begin:"\\b("+re.join("|")+")\\b",className:"selector-tag" + },n.CSS_NUMBER_MODE,l("selector-tag",i,0),l("selector-id","#"+i),l("selector-class","\\."+i,0),l("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{ + className:"selector-pseudo",begin:":("+oe.join("|")+")"},{ + className:"selector-pseudo",begin:":(:)?("+le.join("|")+")"},{begin:/\(/, + end:/\)/,relevance:0,contains:g},{begin:"!important"},n.FUNCTION_DISPATCH]},h={ + begin:a+":(:)?"+`(${t.join("|")})`,returnBegin:!0,contains:[_]} + ;return r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,m,p,h,b,_,u,n.FUNCTION_DISPATCH), + {name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:r}}, + grmr_lua:e=>{const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"] + },i=[e.COMMENT("--(?!"+n+")","$"),e.COMMENT("--"+n,t,{contains:[a],relevance:10 + })];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE, + literal:"true false nil", + keyword:"and break do else elseif end for goto if in local not or repeat return then until while", + built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove" + },contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)", + contains:[e.inherit(e.TITLE_MODE,{ + begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params", + begin:"\\(",endsWithParent:!0,contains:i}].concat(i) + },e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string", + begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={ + className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)", + contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%{ + const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={ + variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{ + begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, + relevance:2},{ + begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), + relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{ + begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/ + },{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0, + returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)", + excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[", + end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[], + variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}] + },i={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{ + begin:/_(?![_\s])/,end:/_/,relevance:0}]},r=e.inherit(a,{contains:[] + }),s=e.inherit(i,{contains:[]});a.contains.push(s),i.contains.push(r) + ;let o=[n,t];return[a,i,r,s].forEach((e=>{e.contains=e.contains.concat(o) + })),o=o.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ + className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{ + begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", + contains:o}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", + end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:o, + end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{ + begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{ + begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))", + contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{ + begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ + className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ + className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}},grmr_objectivec:e=>{ + const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n, + keyword:["@interface","@class","@protocol","@implementation"]};return{ + name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], + keywords:{"variable.language":["this","super"],$pattern:n, + keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","switch","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"], + literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"], + built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"], + type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"] + },illegal:"/,end:/$/,illegal:"\\n" + },e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class", + begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t, + contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE, + relevance:0}]}},grmr_perl:e=>{const n=e.regex,t=/[dualxmsipngr]{0,12}/,a={ + $pattern:/[\w.]+/, + keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0" + },i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:a},r={begin:/->\{/, + end:/\}/},s={variants:[{begin:/\$\d/},{ + begin:n.concat(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])") + },{begin:/[$%@][^\s\w{]/,relevance:0}] + },o=[e.BACKSLASH_ESCAPE,i,s],l=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],c=(e,a,i="\\1")=>{ + const r="\\1"===i?i:n.concat(i,a) + ;return n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,r,/(?:\\.|[^\\\/])*?/,i,t) + },d=(e,a,i)=>n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,i,t),g=[s,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{ + endsWithParent:!0}),r,{className:"string",contains:o,variants:[{ + begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[", + end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{ + begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">", + relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'", + contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`", + contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{ + begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number", + begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b", + relevance:0},{ + begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*", + keywords:"split return print reverse grep",relevance:0, + contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{ + begin:c("s|tr|y",n.either(...l,{capture:!0}))},{begin:c("s|tr|y","\\(","\\)")},{ + begin:c("s|tr|y","\\[","\\]")},{begin:c("s|tr|y","\\{","\\}")}],relevance:2},{ + className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{ + begin:d("(?:m|qr)?",/\//,/\//)},{begin:d("m|qr",n.either(...l,{capture:!0 + }),/\1/)},{begin:d("m|qr",/\(/,/\)/)},{begin:d("m|qr",/\[/,/\]/)},{ + begin:d("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub", + end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{ + begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$", + subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}] + }];return i.contains=g,r.contains=g,{name:"Perl",aliases:["pl","pm"],keywords:a, + contains:g}},grmr_php:e=>{ + const n=e.regex,t=/(?![A-Za-z0-9])(?![$])/,a=n.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,t),i=n.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,t),r={ + scope:"variable",match:"\\$+"+a},s={scope:"subst",variants:[{begin:/\$\w+/},{ + begin:/\{\$/,end:/\}/}]},o=e.inherit(e.APOS_STRING_MODE,{illegal:null + }),l="[ \t\n]",c={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{ + illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(s)}),o,{ + begin:/<<<[ \t]*(?:(\w+)|"(\w+)")\n/,end:/[ \t]*(\w+)\b/, + contains:e.QUOTE_STRING_MODE.contains.concat(s),"on:begin":(e,n)=>{ + n.data._beginMatch=e[1]||e[2]},"on:end":(e,n)=>{ + n.data._beginMatch!==e[1]&&n.ignoreMatch()}},e.END_SAME_AS_BEGIN({ + begin:/<<<[ \t]*'(\w+)'\n/,end:/[ \t]*(\w+)\b/})]},d={scope:"number",variants:[{ + begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{ + begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{ + begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?" + }],relevance:0 + },g=["false","null","true"],u=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],m={ + keyword:u,literal:(e=>{const n=[];return e.forEach((e=>{ + n.push(e),e.toLowerCase()===e?n.push(e.toUpperCase()):n.push(e.toLowerCase()) + })),n})(g),built_in:b},p=e=>e.map((e=>e.replace(/\|\d+$/,""))),_={variants:[{ + match:[/new/,n.concat(l,"+"),n.concat("(?!",p(b).join("\\b|"),"\\b)"),i],scope:{ + 1:"keyword",4:"title.class"}}]},h=n.concat(a,"\\b(?!\\()"),f={variants:[{ + match:[n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant" + }},{match:[/::/,/class/],scope:{2:"variable.language"}},{ + match:[i,n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{1:"title.class", + 3:"variable.constant"}},{match:[i,n.concat("::",n.lookahead(/(?!class\b)/))], + scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class", + 3:"variable.language"}}]},E={scope:"attr", + match:n.concat(a,n.lookahead(":"),n.lookahead(/(?!::)/))},y={relevance:0, + begin:/\(/,end:/\)/,keywords:m,contains:[E,r,f,e.C_BLOCK_COMMENT_MODE,c,d,_] + },N={relevance:0, + match:[/\b/,n.concat("(?!fn\\b|function\\b|",p(u).join("\\b|"),"|",p(b).join("\\b|"),"\\b)"),a,n.concat(l,"*"),n.lookahead(/(?=\()/)], + scope:{3:"title.function.invoke"},contains:[y]};y.contains.push(N) + ;const w=[E,f,e.C_BLOCK_COMMENT_MODE,c,d,_];return{case_insensitive:!1, + keywords:m,contains:[{begin:n.concat(/#\[\s*/,i),beginScope:"meta",end:/]/, + endScope:"meta",keywords:{literal:g,keyword:["new","array"]},contains:[{ + begin:/\[/,end:/]/,keywords:{literal:g,keyword:["new","array"]}, + contains:["self",...w]},...w,{scope:"meta",match:i}] + },e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{ + scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/, + keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE, + contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{ + begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{ + begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},r,N,f,{ + match:[/const/,/\s/,a],scope:{1:"keyword",3:"variable.constant"}},_,{ + scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/, + excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use" + },e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params", + begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:m, + contains:["self",r,f,e.C_BLOCK_COMMENT_MODE,c,d]}]},{scope:"class",variants:[{ + beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait", + illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{ + beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ + beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/, + contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{ + beginKeywords:"use",relevance:0,end:";",contains:[{ + match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},c,d]} + },grmr_php_template:e=>({name:"PHP template",subLanguage:"xml",contains:[{ + begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*", + end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0 + },e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null, + skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null, + contains:null,skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text", + aliases:["text","txt"],disableAutodetect:!0}),grmr_python:e=>{ + const n=e.regex,t=/[\p{XID_Start}_]\p{XID_Continue}*/u,a=["and","as","assert","async","await","break","case","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","match","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],i={ + $pattern:/[A-Za-z]\w+|__\w+__/,keyword:a, + built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"], + literal:["__debug__","Ellipsis","False","None","NotImplemented","True"], + type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"] + },r={className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/, + end:/\}/,keywords:i,illegal:/#/},o={begin:/\{\{/,relevance:0},l={ + className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{ + begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/, + contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ + begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/, + contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ + begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/, + contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/, + end:/"""/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([uU]|[rR])'/,end:/'/, + relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{ + begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/, + end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/, + contains:[e.BACKSLASH_ESCAPE,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/, + contains:[e.BACKSLASH_ESCAPE,o,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] + },c="[0-9](_?[0-9])*",d=`(\\b(${c}))?\\.(${c})|\\b(${c})\\.`,g="\\b|"+a.join("|"),u={ + className:"number",relevance:0,variants:[{ + begin:`(\\b(${c})|(${d}))[eE][+-]?(${c})[jJ]?(?=${g})`},{begin:`(${d})[jJ]?`},{ + begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${g})`},{ + begin:`\\b0[bB](_?[01])+[lL]?(?=${g})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${g})` + },{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${g})`},{begin:`\\b(${c})[jJ](?=${g})` + }]},b={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:i, + contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={ + className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/, + end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i, + contains:["self",r,u,l,e.HASH_COMMENT_MODE]}]};return s.contains=[l,u,r],{ + name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:i, + illegal:/(<\/|\?)|=>/,contains:[r,u,{begin:/\bself\b/},{beginKeywords:"if", + relevance:0},l,b,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,t],scope:{ + 1:"keyword",3:"title.function"},contains:[m]},{variants:[{ + match:[/\bclass/,/\s+/,t,/\s*/,/\(\s*/,t,/\s*\)/]},{match:[/\bclass/,/\s+/,t]}], + scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{ + className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[u,m,l]}]}}, + grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta.prompt", + starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{ + begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{ + const n=e.regex,t=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,a=n.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/,r=n.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/) + ;return{name:"R",keywords:{$pattern:t, + keyword:"function if in break next repeat else for while", + literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10", + built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm" + },contains:[e.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/, + starts:{end:n.lookahead(n.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)), + endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{ + scope:"variable",variants:[{match:t},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0 + }]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}] + }),e.HASH_COMMENT_MODE,{scope:"string",contains:[e.BACKSLASH_ESCAPE], + variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/ + }),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/ + }),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/ + }),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/ + }),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/ + }),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"', + relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{ + 1:"operator",2:"number"},match:[i,a]},{scope:{1:"operator",2:"number"}, + match:[/%[^%]*%/,a]},{scope:{1:"punctuation",2:"number"},match:[r,a]},{scope:{ + 2:"number"},match:[/[^a-zA-Z0-9._]|^/,a]}]},{scope:{3:"operator"}, + match:[t,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{ + match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:r},{begin:"`",end:"`", + contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{ + const n=e.regex,t="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",a=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(a,/(::\w+)*/),r={ + "variable.constant":["__FILE__","__LINE__","__ENCODING__"], + "variable.language":["self","super"], + keyword:["alias","and","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield","include","extend","prepend","public","private","protected","raise","throw"], + built_in:["proc","lambda","attr_accessor","attr_reader","attr_writer","define_method","private_constant","module_function"], + literal:["true","false","nil"]},s={className:"doctag",begin:"@[A-Za-z]+"},o={ + begin:"#<",end:">"},l=[e.COMMENT("#","$",{contains:[s] + }),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10 + }),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],c={className:"subst",begin:/#\{/, + end:/\}/,keywords:r},d={className:"string",contains:[e.BACKSLASH_ESCAPE,c], + variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{ + begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{ + begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//, + end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{ + begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{ + begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{ + begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{ + begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{ + begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)), + contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, + contains:[e.BACKSLASH_ESCAPE,c]})]}]},g="[0-9](_?[0-9])*",u={className:"number", + relevance:0,variants:[{ + begin:`\\b([1-9](_?[0-9])*|0)(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{ + begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b" + },{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{ + begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{ + begin:"\\b0(_?[0-7])+r?i?\\b"}]},b={variants:[{match:/\(\)/},{ + className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0, + keywords:r}]},m=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{ + match:[/\b(class|module)\s+/,i]}],scope:{2:"title.class", + 4:"title.class.inherited"},keywords:r},{match:[/(include|extend)\s+/,i],scope:{ + 2:"title.class"},keywords:r},{relevance:0,match:[i,/\.new[. (]/],scope:{ + 1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, + className:"variable.constant"},{relevance:0,match:a,scope:"title.class"},{ + match:[/def/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[b]},{ + begin:e.IDENT_RE+"::"},{className:"symbol", + begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol", + begin:":(?!\\s)",contains:[d,{begin:t}],relevance:0},u,{className:"variable", + begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{ + className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0, + relevance:0,keywords:r},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*", + keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c], + illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{ + begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[", + end:"\\][a-z]*"}]}].concat(o,l),relevance:0}].concat(o,l) + ;c.contains=m,b.contains=m;const p=[{begin:/^\s*=>/,starts:{end:"$",contains:m} + },{className:"meta.prompt", + begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])", + starts:{end:"$",keywords:r,contains:m}}];return l.unshift(o),{name:"Ruby", + aliases:["rb","gemspec","podspec","thor","irb"],keywords:r,illegal:/\/\*/, + contains:[e.SHEBANG({binary:"ruby"})].concat(p).concat(l).concat(m)}}, + grmr_rust:e=>{const n=e.regex,t={className:"title.function.invoke",relevance:0, + begin:n.concat(/\b/,/(?!let|for|while|if|else|match\b)/,e.IDENT_RE,n.lookahead(/\s*\(/)) + },a="([ui](8|16|32|64|128|size)|f(32|64))?",i=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","eprintln!","panic!","file!","format!","format_args!","include_bytes!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"],r=["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"] + ;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:r, + keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"], + literal:["true","false","Some","None","Ok","Err"],built_in:i},illegal:""},t]}}, + grmr_scss:e=>{const n=ie(e),t=le,a=oe,i="@[a-z-]+",r={className:"variable", + begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b",relevance:0};return{name:"SCSS", + case_insensitive:!0,illegal:"[=/|']", + contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n.CSS_NUMBER_MODE,{ + className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{ + className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0 + },n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag", + begin:"\\b("+re.join("|")+")\\b",relevance:0},{className:"selector-pseudo", + begin:":("+a.join("|")+")"},{className:"selector-pseudo", + begin:":(:)?("+t.join("|")+")"},r,{begin:/\(/,end:/\)/, + contains:[n.CSS_NUMBER_MODE]},n.CSS_VARIABLE,{className:"attribute", + begin:"\\b("+ce.join("|")+")\\b"},{ + begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b" + },{begin:/:/,end:/[;}{]/,relevance:0, + contains:[n.BLOCK_COMMENT,r,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT,n.FUNCTION_DISPATCH] + },{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{ + begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/, + keyword:"and or not only",attribute:se.join(" ")},contains:[{begin:i, + className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute" + },r,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE] + },n.FUNCTION_DISPATCH]}},grmr_shell:e=>({name:"Shell Session", + aliases:["console","shellsession"],contains:[{className:"meta.prompt", + begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/, + subLanguage:"bash"}}]}),grmr_sql:e=>{ + const n=e.regex,t=e.COMMENT("--","$"),a=["true","false","unknown"],i=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],r=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=r,l=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!r.includes(e))),c={ + begin:n.concat(/\b/,n.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}} + ;return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{ + $pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t + ;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e)) + })(l,{when:e=>e.length<3}),literal:a,type:i, + built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"] + },contains:[{begin:n.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/, + keyword:l.concat(s),literal:a,type:i}},{className:"type", + begin:n.either("double precision","large object","with timezone","without timezone") + },c,{className:"variable",begin:/@[a-z0-9][a-z0-9_]*/},{className:"string", + variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/, + contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{ + className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, + relevance:0}]}},grmr_swift:e=>{const n={match:/\s+/,relevance:0 + },t=e.COMMENT("/\\*","\\*/",{contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={ + match:[/\./,m(...xe,...Me)],className:{2:"keyword"}},r={match:b(/\./,m(...Ae)), + relevance:0},s=Ae.filter((e=>"string"==typeof e)).concat(["_|0"]),o={variants:[{ + className:"keyword", + match:m(...Ae.filter((e=>"string"!=typeof e)).concat(Se).map(ke),...Me)}]},l={ + $pattern:m(/\b\w+/,/#\w+/),keyword:s.concat(Re),literal:Ce},c=[i,r,o],g=[{ + match:b(/\./,m(...De)),relevance:0},{className:"built_in", + match:b(/\b/,m(...De),/(?=\()/)}],u={match:/->/,relevance:0},p=[u,{ + className:"operator",relevance:0,variants:[{match:Be},{match:`\\.(\\.|${Le})+`}] + }],_="([0-9]_*)+",h="([0-9a-fA-F]_*)+",f={className:"number",relevance:0, + variants:[{match:`\\b(${_})(\\.(${_}))?([eE][+-]?(${_}))?\\b`},{ + match:`\\b0x(${h})(\\.(${h}))?([pP][+-]?(${_}))?\\b`},{match:/\b0o([0-7]_*)+\b/ + },{match:/\b0b([01]_*)+\b/}]},E=(e="")=>({className:"subst",variants:[{ + match:b(/\\/,e,/[0\\tnr"']/)},{match:b(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}] + }),y=(e="")=>({className:"subst",match:b(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/) + }),N=(e="")=>({className:"subst",label:"interpol",begin:b(/\\/,e,/\(/),end:/\)/ + }),w=(e="")=>({begin:b(e,/"""/),end:b(/"""/,e),contains:[E(e),y(e),N(e)] + }),v=(e="")=>({begin:b(e,/"/),end:b(/"/,e),contains:[E(e),N(e)]}),O={ + className:"string", + variants:[w(),w("#"),w("##"),w("###"),v(),v("#"),v("##"),v("###")] + },k=[e.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0, + contains:[e.BACKSLASH_ESCAPE]}],x={begin:/\/[^\s](?=[^/\n]*\/)/,end:/\//, + contains:k},M=e=>{const n=b(e,/\//),t=b(/\//,e);return{begin:n,end:t, + contains:[...k,{scope:"comment",begin:`#(?!.*${t})`,end:/$/}]}},S={ + scope:"regexp",variants:[M("###"),M("##"),M("#"),x]},A={match:b(/`/,Fe,/`/) + },C=[A,{className:"variable",match:/\$\d+/},{className:"variable", + match:`\\$${ze}+`}],T=[{match:/(@|#(un)?)available/,scope:"keyword",starts:{ + contains:[{begin:/\(/,end:/\)/,keywords:Pe,contains:[...p,f,O]}]}},{ + scope:"keyword",match:b(/@/,m(...je))},{scope:"meta",match:b(/@/,Fe)}],R={ + match:d(/\b[A-Z]/),relevance:0,contains:[{className:"type", + match:b(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,ze,"+") + },{className:"type",match:Ue,relevance:0},{match:/[?!]+/,relevance:0},{ + match:/\.\.\./,relevance:0},{match:b(/\s+&\s+/,d(Ue)),relevance:0}]},D={ + begin://,keywords:l,contains:[...a,...c,...T,u,R]};R.contains.push(D) + ;const I={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{ + match:b(Fe,/\s*:/),keywords:"_|0",relevance:0 + },...a,S,...c,...g,...p,f,O,...C,...T,R]},L={begin://, + keywords:"repeat each",contains:[...a,R]},B={begin:/\(/,end:/\)/,keywords:l, + contains:[{begin:m(d(b(Fe,/\s*:/)),d(b(Fe,/\s+/,Fe,/\s*:/))),end:/:/, + relevance:0,contains:[{className:"keyword",match:/\b_\b/},{className:"params", + match:Fe}]},...a,...c,...p,f,O,...T,R,I],endsParent:!0,illegal:/["']/},$={ + match:[/(func|macro)/,/\s+/,m(A.match,Fe,Be)],className:{1:"keyword", + 3:"title.function"},contains:[L,B,n],illegal:[/\[/,/%/]},z={ + match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"}, + contains:[L,B,n],illegal:/\[|%/},F={match:[/operator/,/\s+/,Be],className:{ + 1:"keyword",3:"title"}},U={begin:[/precedencegroup/,/\s+/,Ue],className:{ + 1:"keyword",3:"title"},contains:[R],keywords:[...Te,...Ce],end:/}/} + ;for(const e of O.variants){const n=e.contains.find((e=>"interpol"===e.label)) + ;n.keywords=l;const t=[...c,...g,...p,f,O,...C];n.contains=[...t,{begin:/\(/, + end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:l, + contains:[...a,$,z,{beginKeywords:"struct protocol class extension enum actor", + end:"\\{",excludeEnd:!0,keywords:l,contains:[e.inherit(e.TITLE_MODE,{ + className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...c] + },F,U,{beginKeywords:"import",end:/$/,contains:[...a],relevance:0 + },S,...c,...g,...p,f,O,...C,...T,R,I]}},grmr_typescript:e=>{ + const n=Oe(e),t=_e,a=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],i={ + beginKeywords:"namespace",end:/\{/,excludeEnd:!0, + contains:[n.exports.CLASS_REFERENCE]},r={beginKeywords:"interface",end:/\{/, + excludeEnd:!0,keywords:{keyword:"interface extends",built_in:a}, + contains:[n.exports.CLASS_REFERENCE]},s={$pattern:_e, + keyword:he.concat(["type","namespace","interface","public","private","protected","implements","declare","abstract","readonly","enum","override"]), + literal:fe,built_in:ve.concat(a),"variable.language":we},o={className:"meta", + begin:"@"+t},l=(e,n,t)=>{const a=e.contains.findIndex((e=>e.label===n)) + ;if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)} + ;return Object.assign(n.keywords,s), + n.exports.PARAMS_CONTAINS.push(o),n.contains=n.contains.concat([o,i,r]), + l(n,"shebang",e.SHEBANG()),l(n,"use_strict",{className:"meta",relevance:10, + begin:/^\s*['"]use strict['"]/ + }),n.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(n,{ + name:"TypeScript",aliases:["ts","tsx","mts","cts"]}),n},grmr_vbnet:e=>{ + const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,r=/\d{1,2}(:\d{1,2}){1,2}/,s={ + className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{ + begin:n.concat(/# */,r,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{ + begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,r),/ *#/)}] + },o=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}] + }),l=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]}) + ;return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0, + classNameAliases:{label:"symbol"},keywords:{ + keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield", + built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort", + type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort", + literal:"true false nothing"}, + illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{ + className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/, + end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0, + variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/ + },{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{ + begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{ + className:"label",begin:/^\w+:/},o,l,{className:"meta", + begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/, + end:/$/,keywords:{ + keyword:"const disable else elseif enable end externalsource if region then"}, + contains:[l]}]}},grmr_wasm:e=>{e.regex;const n=e.COMMENT(/\(;/,/;\)/) + ;return n.contains.push("self"),{name:"WebAssembly",keywords:{$pattern:/[\w.]+/, + keyword:["anyfunc","block","br","br_if","br_table","call","call_indirect","data","drop","elem","else","end","export","func","global.get","global.set","local.get","local.set","local.tee","get_global","get_local","global","if","import","local","loop","memory","memory.grow","memory.size","module","mut","nop","offset","param","result","return","select","set_global","set_local","start","table","tee_local","then","type","unreachable"] + },contains:[e.COMMENT(/;;/,/$/),n,{match:[/(?:offset|align)/,/\s*/,/=/], + className:{1:"keyword",3:"operator"}},{className:"variable",begin:/\$[\w_]+/},{ + match:/(\((?!;)|\))+/,className:"punctuation",relevance:0},{ + begin:[/(?:func|call|call_indirect)/,/\s+/,/\$[^\s)]+/],className:{1:"keyword", + 3:"title.function"}},e.QUOTE_STRING_MODE,{match:/(i32|i64|f32|f64)(?!\.)/, + className:"type"},{className:"keyword", + match:/\b(f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))\b/ + },{className:"number",relevance:0, + match:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/ + }]}},grmr_xml:e=>{ + const n=e.regex,t=n.concat(/[\p{L}_]/u,n.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),a={ + className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/, + contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] + },r=e.inherit(i,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{ + className:"string"}),o=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),l={ + endsWithParent:!0,illegal:/`]+/}]}]}]};return{ + name:"HTML, XML", + aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], + case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,o,s,r,{begin:/\[/,end:/\]/,contains:[{ + className:"meta",begin://,contains:[i,r,o,s]}]}] + },e.COMMENT(//,{relevance:10}),{begin://, + relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/, + relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag", + begin:/)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{ + end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", + begin:/)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{ + end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ + className:"tag",begin:/<>|<\/>/},{className:"tag", + begin:n.concat(//,/>/,/\s/)))), + end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{ + className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{ + className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]} + },grmr_yaml:e=>{ + const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={ + className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ + },{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", + variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{ + variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={ + end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/, + end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]", + contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{ + begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{ + begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$", + relevance:10},{className:"string", + begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ + begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, + relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type", + begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t + },{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", + begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", + relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ + className:"number", + begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" + },{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l] + ;return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0, + aliases:["yml"],contains:l}}});const He=ae;for(const e of Object.keys(Ke)){ + const n=e.replace("grmr_","").replace("_","-");He.registerLanguage(n,Ke[e])} + return He}() + ;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); \ No newline at end of file diff --git a/docs/md/assets/highlight_init.js b/docs/md/assets/highlight_init.js new file mode 100644 index 00000000..e2379278 --- /dev/null +++ b/docs/md/assets/highlight_init.js @@ -0,0 +1,6 @@ +document.addEventListener('DOMContentLoaded', (event) => { + document.querySelectorAll('pre code').forEach((block) => { + hljs.highlightBlock(block); + }); + }); + \ No newline at end of file diff --git a/docs/md/assets/styles.css b/docs/md/assets/styles.css new file mode 100644 index 00000000..51343a76 --- /dev/null +++ b/docs/md/assets/styles.css @@ -0,0 +1,83 @@ +@font-face { + font-family: "Monaco"; + font-style: normal; + font-weight: normal; + src: local("Monaco"), url("Monaco.woff") format("woff"); +} + +:root { + --global-font-size: 16px; + --global-line-height: 1.5em; + --global-space: 10px; + --font-stack: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, + Courier New, monospace, serif; + --font-stack: dm, Monaco, Courier New, monospace, serif; + --mono-font-stack: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, + Courier New, monospace, serif; + + + --background-color: #151515; /* Dark background */ + --font-color: #eaeaea; /* Light font color for contrast */ + --invert-font-color: #151515; /* Dark color for inverted elements */ + --primary-color: #1a95e0; /* Primary color can remain the same or be adjusted for better contrast */ + --secondary-color: #727578; /* Secondary color for less important text */ + --error-color: #ff5555; /* Bright color for errors */ + --progress-bar-background: #444; /* Darker background for progress bar */ + --progress-bar-fill: #1a95e0; /* Bright color for progress bar fill */ + --code-bg-color: #1e1e1e; /* Darker background for code blocks */ + --input-style: solid; /* Keeping input style solid */ + --block-background-color: #202020; /* Darker background for block elements */ + --global-font-color: #eaeaea; /* Light font color for global elements */ + + --background-color: #222225; + --page-width: 70em; + --font-color: #e8e9ed; + --invert-font-color: #222225; + --secondary-color: #a3abba; + --tertiary-color: #a3abba; + --primary-color: #09b5a5; /* Updated to the brand color */ + --error-color: #ff3c74; + --progress-bar-background: #3f3f44; + --progress-bar-fill: #09b5a5; /* Updated to the brand color */ + --code-bg-color: #3f3f44; + --input-style: solid; + --display-h1-decoration: none; + + --display-h1-decoration: none; +} + +/* body { + background-color: var(--background-color); + color: var(--font-color); +} + +a { + color: var(--primary-color); +} + +a:hover { + background-color: var(--primary-color); + color: var(--invert-font-color); +} + +blockquote::after { + color: #444; +} + +pre, code { + background-color: var(--code-bg-color); + color: var(--font-color); +} + +.terminal-nav:first-child { + border-bottom: 1px dashed var(--secondary-color); +} */ + +.terminal-mkdocs-main-content{ + line-height: var(--global-line-height); +} + +strong, .highlight { + /* background: url(//s2.svgbox.net/pen-brushes.svg?ic=brush-1&color=50ffff); */ + background-color: #50ffff33; +} \ No newline at end of file diff --git a/docs/md/changelog.md b/docs/md/changelog.md new file mode 100644 index 00000000..70d2bb40 --- /dev/null +++ b/docs/md/changelog.md @@ -0,0 +1,18 @@ +# Changelog + +## [0.2.5] - 2024-06-18 +### Added +- Added five important hooks to the crawler: + - on_driver_created: Called when the driver is ready for initializations. + - before_get_url: Called right before Selenium fetches the URL. + - after_get_url: Called after Selenium fetches the URL. + - before_return_html: Called when the data is parsed and ready. + - on_user_agent_updated: Called when the user changes the user_agent, causing the driver to reinitialize. +- Added an example in `quickstart.py` in the example folder under the docs. +- Enhancement issue #24: Replaced inline HTML tags (e.g., DEL, INS, SUB, ABBR) with textual format for better context handling in LLM. +- Maintaining the semantic context of inline tags (e.g., abbreviation, DEL, INS) for improved LLM-friendliness. +- Updated Dockerfile to ensure compatibility across multiple platforms (Hopefully!). + +## [0.2.4] - 2024-06-17 +### Fixed +- Fix issue #22: Use MD5 hash for caching HTML files to handle long URLs diff --git a/docs/md/contact.md b/docs/md/contact.md new file mode 100644 index 00000000..85faa217 --- /dev/null +++ b/docs/md/contact.md @@ -0,0 +1,25 @@ +# Contact +If you have any questions, suggestions, or feedback, please feel free to reach out to us: + +- GitHub: [unclecode](https://github.com/unclecode) +- Twitter: [@unclecode](https://twitter.com/unclecode) +- Website: [crawl4ai.com](https://crawl4ai.com) + + +## Contributing 🀝 + +We welcome contributions from the open-source community to help improve Crawl4AI and make it even more valuable for AI enthusiasts and developers. To contribute, please follow these steps: + +1. Fork the repository. +2. Create a new branch for your feature or bug fix. +3. Make your changes and commit them with descriptive messages. +4. Push your changes to your forked repository. +5. Submit a pull request to the main repository. + +For more information on contributing, please see our [contribution guidelines](https://github.com/unclecode/crawl4ai/blob/main/CONTRIBUTING.md). + +## License πŸ“„ + +Crawl4AI is released under the [Apache 2.0 License](https://github.com/unclecode/crawl4ai/blob/main/LICENSE). + +Let's work together to make the web more accessible and useful for AI applications! πŸ’ͺπŸŒπŸ€– diff --git a/docs/md/examples/hooks_auth.md b/docs/md/examples/hooks_auth.md new file mode 100644 index 00000000..154300df --- /dev/null +++ b/docs/md/examples/hooks_auth.md @@ -0,0 +1,96 @@ +# Hooks & Auth + +Crawl4AI allows you to customize the behavior of the web crawler using hooks. Hooks are functions that are called at specific points in the crawling process, allowing you to modify the crawler's behavior or perform additional actions. This example demonstrates how to use various hooks to customize the crawling process. + +## Example: Using Crawler Hooks + +Let's see how we can customize the crawler using hooks! In this example, we'll: + +1. Maximize the browser window and log in to a website when the driver is created. +2. Add a custom header before fetching the URL. +3. Log the current URL after fetching it. +4. Log the length of the HTML before returning it. + +### Hook Definitions + +```python +def on_driver_created(driver): + print("[HOOK] on_driver_created") + # Example customization: maximize the window + driver.maximize_window() + + # Example customization: logging in to a hypothetical website + driver.get('https://example.com/login') + + from selenium.webdriver.support.ui import WebDriverWait + from selenium.webdriver.common.by import By + from selenium.webdriver.support import expected_conditions as EC + + WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.NAME, 'username')) + ) + driver.find_element(By.NAME, 'username').send_keys('testuser') + driver.find_element(By.NAME, 'password').send_keys('password123') + driver.find_element(By.NAME, 'login').click() + WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.ID, 'welcome')) + ) + # Add a custom cookie + driver.add_cookie({'name': 'test_cookie', 'value': 'cookie_value'}) + return driver + + +def before_get_url(driver): + print("[HOOK] before_get_url") + # Example customization: add a custom header + # Enable Network domain for sending headers + driver.execute_cdp_cmd('Network.enable', {}) + # Add a custom header + driver.execute_cdp_cmd('Network.setExtraHTTPHeaders', {'headers': {'X-Test-Header': 'test'}}) + return driver + +def after_get_url(driver): + print("[HOOK] after_get_url") + # Example customization: log the URL + print(driver.current_url) + return driver + +def before_return_html(driver, html): + print("[HOOK] before_return_html") + # Example customization: log the HTML + print(len(html)) + return driver +``` + +### Using the Hooks with the WebCrawler + +```python +print("\nπŸ”— [bold cyan]Using Crawler Hooks: Let's see how we can customize the crawler using hooks![/bold cyan]", True) +crawler = WebCrawler(verbose=True) +crawler.warmup() +crawler.set_hook('on_driver_created', on_driver_created) +crawler.set_hook('before_get_url', before_get_url) +crawler.set_hook('after_get_url', after_get_url) +crawler.set_hook('before_return_html', before_return_html) + +result = crawler.run(url="https://example.com") + +print("[LOG] πŸ“¦ [bold yellow]Crawler Hooks result:[/bold yellow]") +print(result) +``` + +### Explanation + +- `on_driver_created`: This hook is called when the Selenium driver is created. In this example, it maximizes the window, logs in to a website, and adds a custom cookie. +- `before_get_url`: This hook is called right before Selenium fetches the URL. In this example, it adds a custom HTTP header. +- `after_get_url`: This hook is called after Selenium fetches the URL. In this example, it logs the current URL. +- `before_return_html`: This hook is called before returning the HTML content. In this example, it logs the length of the HTML content. + +### Additional Ideas + +- **Add custom headers to requests**: You can add custom headers to the requests using the `before_get_url` hook. +- **Perform safety checks**: Use the hooks to perform safety checks before the crawling process starts. +- **Modify the HTML content**: Use the `before_return_html` hook to modify the HTML content before it is returned. +- **Log additional information**: Use the hooks to log additional information for debugging or monitoring purposes. + +By using these hooks, you can customize the behavior of the crawler to suit your specific needs. diff --git a/docs/md/examples/index.md b/docs/md/examples/index.md new file mode 100644 index 00000000..14380e3d --- /dev/null +++ b/docs/md/examples/index.md @@ -0,0 +1,29 @@ +# Examples + +Welcome to the examples section of Crawl4AI documentation! In this section, you will find practical examples demonstrating how to use Crawl4AI for various web crawling and data extraction tasks. Each example is designed to showcase different features and capabilities of the library. + +## Examples Index + +### [LLM Extraction](llm_extraction.md) + +This example demonstrates how to use Crawl4AI to extract information using Large Language Models (LLMs). You will learn how to configure the `LLMExtractionStrategy` to get structured data from web pages. + +### [JS Execution & CSS Filtering](js_execution_css_filtering.md) + +Learn how to execute custom JavaScript code and filter data using CSS selectors. This example shows how to perform complex web interactions and extract specific content from web pages. + +### [Hooks & Auth](hooks_auth.md) + +This example covers the use of custom hooks for authentication and other pre-crawling tasks. You will see how to set up hooks to modify headers, authenticate sessions, and perform other preparatory actions before crawling. + +### [Summarization](summarization.md) + +Discover how to use Crawl4AI to summarize web page content. This example demonstrates the summarization capabilities of the library, helping you extract concise information from lengthy web pages. + +### [Research Assistant](research_assistant.md) + +In this example, Crawl4AI is used as a research assistant to gather and organize information from multiple sources. You will learn how to use various extraction and chunking strategies to compile a comprehensive report. + +--- + +Each example includes detailed explanations and code snippets to help you understand and implement the features in your projects. Click on the links to explore each example and start making the most of Crawl4AI! diff --git a/docs/md/examples/js_execution_css_filtering.md b/docs/md/examples/js_execution_css_filtering.md new file mode 100644 index 00000000..0592f094 --- /dev/null +++ b/docs/md/examples/js_execution_css_filtering.md @@ -0,0 +1,44 @@ +# JS Execution & CSS Filtering + +In this example, we'll demonstrate how to use Crawl4AI to execute JavaScript, filter data with CSS selectors, and use a cosine similarity strategy to extract relevant content. This approach is particularly useful when you need to interact with dynamic content on web pages, such as clicking "Load More" buttons. + +## Example: Extracting Structured Data + +```python +# Import necessary modules +from crawl4ai import WebCrawler +from crawl4ai.chunking_strategy import * +from crawl4ai.extraction_strategy import * +from crawl4ai.crawler_strategy import * + +# Define the JavaScript code to click the "Load More" button +js_code = [""" +const loadMoreButton = Array.from(document.querySelectorAll('button')).find(button => button.textContent.includes('Load More')); +loadMoreButton && loadMoreButton.click(); +"""] + +crawler = WebCrawler(verbose=True) +crawler.warmup() +# Run the crawler with keyword filtering and CSS selector +result = crawler.run( + url="https://www.nbcnews.com/business", + js=js_code, + css_selector="p", + extraction_strategy=CosineStrategy( + semantic_filter="technology", + ), +) + +# Display the extracted result +print(result) +``` + +### Explanation + +1. **JavaScript Execution**: The `js_code` variable contains JavaScript code that simulates clicking a "Load More" button. This is useful for loading additional content dynamically. +2. **CSS Selector**: The `css_selector="p"` parameter ensures that only paragraph (`

`) tags are extracted from the web page. +3. **Extraction Strategy**: The `CosineStrategy` is used with a semantic filter for "technology" to extract relevant content based on cosine similarity. + +## Try It Yourself + +This example demonstrates the power and flexibility of Crawl4AI in handling complex web interactions and extracting meaningful data. You can customize the JavaScript code, CSS selectors, and extraction strategies to suit your specific requirements. diff --git a/docs/md/examples/llm_extraction.md b/docs/md/examples/llm_extraction.md new file mode 100644 index 00000000..5336a3cf --- /dev/null +++ b/docs/md/examples/llm_extraction.md @@ -0,0 +1,90 @@ +# LLM Extraction + +Crawl4AI allows you to use Language Models (LLMs) to extract structured data or relevant content from web pages. Below are two examples demonstrating how to use LLMExtractionStrategy for different purposes. + +## Example 1: Extract Structured Data + +In this example, we use the `LLMExtractionStrategy` to extract structured data (model names and their fees) from the OpenAI pricing page. + +```python +import os +import time +from crawl4ai.web_crawler import WebCrawler +from crawl4ai.chunking_strategy import * +from crawl4ai.extraction_strategy import * +from crawl4ai.crawler_strategy import * + +url = r'https://openai.com/api/pricing/' + +crawler = WebCrawler() +crawler.warmup() + +from pydantic import BaseModel, Field + +class OpenAIModelFee(BaseModel): + model_name: str = Field(..., description="Name of the OpenAI model.") + input_fee: str = Field(..., description="Fee for input token for the OpenAI model.") + output_fee: str = Field(..., description="Fee for output token for the OpenAI model.") + +result = crawler.run( + url=url, + word_count_threshold=1, + extraction_strategy= LLMExtractionStrategy( + provider= "openai/gpt-4o", api_token = os.getenv('OPENAI_API_KEY'), + schema=OpenAIModelFee.model_json_schema(), + extraction_type="schema", + instruction="From the crawled content, extract all mentioned model names along with their "\ + "fees for input and output tokens. Make sure not to miss anything in the entire content. "\ + 'One extracted model JSON format should look like this: '\ + '{ "model_name": "GPT-4", "input_fee": "US$10.00 / 1M tokens", "output_fee": "US$30.00 / 1M tokens" }' + ), + bypass_cache=True, +) + +model_fees = json.loads(result.extracted_content) + +print(len(model_fees)) + +with open(".data/data.json", "w") as f: + f.write(result.extracted_content) +``` + +## Example 2: Extract Relevant Content + +In this example, we instruct the LLM to extract only content related to technology from the NBC News business page. + +```python +crawler = WebCrawler() +crawler.warmup() + +result = crawler.run( + url="https://www.nbcnews.com/business", + extraction_strategy=LLMExtractionStrategy( + provider="openai/gpt-4o", + api_token=os.getenv('OPENAI_API_KEY'), + instruction="Extract only content related to technology" + ), + bypass_cache=True, + ) + +model_fees = json.loads(result.extracted_content) + +print(len(model_fees)) + +with open(".data/data.json", "w") as f: + f.write(result.extracted_content) +``` + +## Customizing LLM Provider + +Under the hood, Crawl4AI uses the `litellm` library, which allows you to use any LLM provider you want. Just pass the correct model name and API token. + +```python +extraction_strategy=LLMExtractionStrategy( + provider="your_llm_provider/model_name", + api_token="your_api_token", + instruction="Your extraction instruction" +) +``` + +This flexibility allows you to integrate with various LLM providers and tailor the extraction process to your specific needs. diff --git a/docs/md/examples/research_assistant.md b/docs/md/examples/research_assistant.md new file mode 100644 index 00000000..9284fbef --- /dev/null +++ b/docs/md/examples/research_assistant.md @@ -0,0 +1,248 @@ +## Research Assistant Example + +This example demonstrates how to build a research assistant using `Chainlit` and `Crawl4AI`. The assistant will be capable of crawling web pages for information and answering questions based on the crawled content. Additionally, it integrates speech-to-text functionality for audio inputs. + +### Step-by-Step Guide + +1. **Install Required Packages** + + Ensure you have the necessary packages installed. You need `chainlit`, `groq`, `requests`, and `openai`. + + ```bash + pip install chainlit groq requests openai + ``` + +2. **Import Libraries** + + Import all the necessary modules and initialize the OpenAI client. + + ```python + import os + import time + from openai import AsyncOpenAI + import chainlit as cl + import re + import requests + from io import BytesIO + from chainlit.element import ElementBased + from groq import Groq + + from concurrent.futures import ThreadPoolExecutor + + client = AsyncOpenAI(base_url="https://api.groq.com/openai/v1", api_key=os.getenv("GROQ_API_KEY")) + + # Instrument the OpenAI client + cl.instrument_openai() + ``` + +3. **Set Configuration** + + Define the model settings for the assistant. + + ```python + settings = { + "model": "llama3-8b-8192", + "temperature": 0.5, + "max_tokens": 500, + "top_p": 1, + "frequency_penalty": 0, + "presence_penalty": 0, + } + ``` + +4. **Define Utility Functions** + + - **Extract URLs from Text**: Use regex to find URLs in messages. + + ```python + def extract_urls(text): + url_pattern = re.compile(r'(https?://\S+)') + return url_pattern.findall(text) + ``` + + - **Crawl URL**: Send a request to `Crawl4AI` to fetch the content of a URL. + + ```python + def crawl_url(url): + data = { + "urls": [url], + "include_raw_html": True, + "word_count_threshold": 10, + "extraction_strategy": "NoExtractionStrategy", + "chunking_strategy": "RegexChunking" + } + response = requests.post("https://crawl4ai.com/crawl", json=data) + response_data = response.json() + response_data = response_data['results'][0] + return response_data['markdown'] + ``` + +5. **Initialize Chat Start Event** + + Set up the initial chat message and user session. + + ```python + @cl.on_chat_start + async def on_chat_start(): + cl.user_session.set("session", { + "history": [], + "context": {} + }) + await cl.Message( + content="Welcome to the chat! How can I assist you today?" + ).send() + ``` + +6. **Handle Incoming Messages** + + Process user messages, extract URLs, and crawl them concurrently. Update the chat history and system message. + + ```python + @cl.on_message + async def on_message(message: cl.Message): + user_session = cl.user_session.get("session") + + # Extract URLs from the user's message + urls = extract_urls(message.content) + + futures = [] + with ThreadPoolExecutor() as executor: + for url in urls: + futures.append(executor.submit(crawl_url, url)) + + results = [future.result() for future in futures] + + for url, result in zip(urls, results): + ref_number = f"REF_{len(user_session['context']) + 1}" + user_session["context"][ref_number] = { + "url": url, + "content": result + } + + user_session["history"].append({ + "role": "user", + "content": message.content + }) + + # Create a system message that includes the context + context_messages = [ + f'\n{data["content"]}\n' + for ref, data in user_session["context"].items() + ] + if context_messages: + system_message = { + "role": "system", + "content": ( + "You are a helpful bot. Use the following context for answering questions. " + "Refer to the sources using the REF number in square brackets, e.g., [1], only if the source is given in the appendices below.\n\n" + "If the question requires any information from the provided appendices or context, refer to the sources. " + "If not, there is no need to add a references section. " + "At the end of your response, provide a reference section listing the URLs and their REF numbers only if sources from the appendices were used.\n\n" + "\n\n".join(context_messages) + ) + } + else: + system_message = { + "role": "system", + "content": "You are a helpful assistant." + } + + msg = cl.Message(content="") + await msg.send() + + # Get response from the LLM + stream = await client.chat.completions.create( + messages=[ + system_message, + *user_session["history"] + ], + stream=True, + **settings + ) + + assistant_response = "" + async for part in stream: + if token := part.choices[0].delta.content: + assistant_response += token + await msg.stream_token(token) + + # Add assistant message to the history + user_session["history"].append({ + "role": "assistant", + "content": assistant_response + }) + await msg.update() + + # Append the reference section to the assistant's response + reference_section = "\n\nReferences:\n" + for ref, data in user_session["context"].items(): + reference_section += f"[{ref.split('_')[1]}]: {data['url']}\n" + + msg.content += reference_section + await msg.update() + ``` + +7. **Handle Audio Input** + + Capture and transcribe audio input. Store the audio buffer and transcribe it when the audio ends. + + ```python + @cl.on_audio_chunk + async def on_audio_chunk(chunk: cl.AudioChunk): + if chunk.isStart: + buffer = BytesIO() + buffer.name = f"input_audio.{chunk.mimeType.split('/')[1]}" + cl.user_session.set("audio_buffer", buffer) + cl.user_session.set("audio_mime_type", chunk.mimeType) + + cl.user_session.get("audio_buffer").write(chunk.data) + + @cl.step(type="tool") + async def speech_to_text(audio_file): + cli = Groq() + response = await client.audio.transcriptions.create( + model="whisper-large-v3", file=audio_file + ) + return response.text + + @cl.on_audio_end + async def on_audio_end(elements: list[ElementBased]): + audio_buffer: BytesIO = cl.user_session.get("audio_buffer") + audio_buffer.seek(0) + audio_file = audio_buffer.read() + audio_mime_type: str = cl.user_session.get("audio_mime_type") + + start_time = time.time() + transcription = await speech_to_text((audio_buffer.name, audio_file, audio_mime_type)) + end_time = time.time() + print(f"Transcription took {end_time - start_time} seconds") + + user_msg = cl.Message( + author="You", + type="user_message", + content=transcription + ) + await user_msg.send() + await on_message(user_msg) + ``` + +8. **Run the Chat Application** + + Start the Chainlit application. + + ```python + if __name__ == "__main__": + from chainlit.cli import run_chainlit + run_chainlit(__file__) + ``` + +### Explanation + +- **Libraries and Configuration**: Import necessary libraries and configure the OpenAI client. +- **Utility Functions**: Define functions to extract URLs and crawl them. +- **Chat Start Event**: Initialize chat session and welcome message. +- **Message Handling**: Extract URLs, crawl them concurrently, and update chat history and context. +- **Audio Handling**: Capture, buffer, and transcribe audio input, then process the transcription as text. +- **Running the Application**: Start the Chainlit server to interact with the assistant. + +This example showcases how to create an interactive research assistant that can fetch, process, and summarize web content, along with handling audio inputs for a seamless user experience. diff --git a/docs/md/examples/summarization.md b/docs/md/examples/summarization.md new file mode 100644 index 00000000..3210fad6 --- /dev/null +++ b/docs/md/examples/summarization.md @@ -0,0 +1,108 @@ +## Summarization Example + +This example demonstrates how to use `Crawl4AI` to extract a summary from a web page. The goal is to obtain the title, a detailed summary, a brief summary, and a list of keywords from the given page. + +### Step-by-Step Guide + +1. **Import Necessary Modules** + + First, import the necessary modules and classes. + + ```python + import os + import time + import json + from crawl4ai.web_crawler import WebCrawler + from crawl4ai.chunking_strategy import * + from crawl4ai.extraction_strategy import * + from crawl4ai.crawler_strategy import * + from pydantic import BaseModel, Field + ``` + +2. **Define the URL to be Crawled** + + Set the URL of the web page you want to summarize. + + ```python + url = r'https://marketplace.visualstudio.com/items?itemName=Unclecode.groqopilot' + ``` + +3. **Initialize the WebCrawler** + + Create an instance of the `WebCrawler` and call the `warmup` method. + + ```python + crawler = WebCrawler() + crawler.warmup() + ``` + +4. **Define the Data Model** + + Use Pydantic to define the structure of the extracted data. + + ```python + class PageSummary(BaseModel): + title: str = Field(..., description="Title of the page.") + summary: str = Field(..., description="Summary of the page.") + brief_summary: str = Field(..., description="Brief summary of the page.") + keywords: list = Field(..., description="Keywords assigned to the page.") + ``` + +5. **Run the Crawler** + + Set up and run the crawler with the `LLMExtractionStrategy`. Provide the necessary parameters, including the schema for the extracted data and the instruction for the LLM. + + ```python + result = crawler.run( + url=url, + word_count_threshold=1, + extraction_strategy=LLMExtractionStrategy( + provider="openai/gpt-4o", + api_token=os.getenv('OPENAI_API_KEY'), + schema=PageSummary.model_json_schema(), + extraction_type="schema", + apply_chunking=False, + instruction=( + "From the crawled content, extract the following details: " + "1. Title of the page " + "2. Summary of the page, which is a detailed summary " + "3. Brief summary of the page, which is a paragraph text " + "4. Keywords assigned to the page, which is a list of keywords. " + 'The extracted JSON format should look like this: ' + '{ "title": "Page Title", "summary": "Detailed summary of the page.", ' + '"brief_summary": "Brief summary in a paragraph.", "keywords": ["keyword1", "keyword2", "keyword3"] }' + ) + ), + bypass_cache=True, + ) + ``` + +6. **Process the Extracted Data** + + Load the extracted content into a JSON object and print it. + + ```python + page_summary = json.loads(result.extracted_content) + print(page_summary) + ``` + +7. **Save the Extracted Data** + + Save the extracted data to a file for further use. + + ```python + with open(".data/page_summary.json", "w") as f: + f.write(result.extracted_content) + ``` + +### Explanation + +- **Importing Modules**: Import the necessary modules, including `WebCrawler` and `LLMExtractionStrategy` from `Crawl4AI`. +- **URL Definition**: Set the URL of the web page you want to crawl and summarize. +- **WebCrawler Initialization**: Create an instance of `WebCrawler` and call the `warmup` method to prepare the crawler. +- **Data Model Definition**: Define the structure of the data you want to extract using Pydantic's `BaseModel`. +- **Crawler Execution**: Run the crawler with the `LLMExtractionStrategy`, providing the schema and detailed instructions for the extraction process. +- **Data Processing**: Load the extracted content into a JSON object and print it to verify the results. +- **Data Saving**: Save the extracted data to a file for further use. + +This example demonstrates how to harness the power of `Crawl4AI` to perform advanced web crawling and data extraction tasks with minimal code. diff --git a/docs/md/full_details/advanced_features.md b/docs/md/full_details/advanced_features.md new file mode 100644 index 00000000..944f6e0d --- /dev/null +++ b/docs/md/full_details/advanced_features.md @@ -0,0 +1,138 @@ +# Advanced Features + +Crawl4AI offers a range of advanced features that allow you to fine-tune your web crawling and data extraction process. This section will cover some of these advanced features, including taking screenshots, extracting media and links, customizing the user agent, using custom hooks, and leveraging CSS selectors. + +## Taking Screenshots πŸ“Έ + +One of the cool features of Crawl4AI is the ability to take screenshots of the web pages you're crawling. This can be particularly useful for visual verification or for capturing the state of dynamic content. + +Here's how you can take a screenshot: + +```python +from crawl4ai import WebCrawler +import base64 + +# Create the WebCrawler instance +crawler = WebCrawler() +crawler.warmup() + +# Run the crawler with the screenshot parameter +result = crawler.run(url="https://www.nbcnews.com/business", screenshot=True) + +# Save the screenshot to a file +with open("screenshot.png", "wb") as f: + f.write(base64.b64decode(result.screenshot)) + +print("Screenshot saved to 'screenshot.png'!") +``` + +In this example, we create a `WebCrawler` instance, warm it up, and then run it with the `screenshot` parameter set to `True`. The screenshot is saved as a base64 encoded string in the result, which we then decode and save as a PNG file. + +## Extracting Media and Links πŸŽ¨πŸ”— + +Crawl4AI can extract all media tags (images, audio, and video) and links (both internal and external) from a web page. This feature is useful for collecting multimedia content or analyzing link structures. + +Here's an example: + +```python +from crawl4ai import WebCrawler + +# Create the WebCrawler instance +crawler = WebCrawler() +crawler.warmup() + +# Run the crawler +result = crawler.run(url="https://www.nbcnews.com/business") + +print("Extracted media:", result.media) +print("Extracted links:", result.links) +``` + +In this example, the `result` object contains dictionaries for media and links, which you can access and use as needed. + +## Customizing the User Agent πŸ•΅οΈβ€β™‚οΈ + +Crawl4AI allows you to set a custom user agent for your HTTP requests. This can help you avoid detection by web servers or simulate different browsing environments. + +Here's how to set a custom user agent: + +```python +from crawl4ai import WebCrawler + +# Create the WebCrawler instance +crawler = WebCrawler() +crawler.warmup() + +# Run the crawler with a custom user agent +result = crawler.run(url="https://www.nbcnews.com/business", user_agent="Mozilla/5.0 (compatible; MyCrawler/1.0)") + +print("Crawl result:", result) +``` + +In this example, we specify a custom user agent string when running the crawler. + +## Using Custom Hooks πŸͺ + +Hooks are a powerful feature in Crawl4AI that allow you to customize the crawling process at various stages. You can define hooks for actions such as driver initialization, before and after URL fetching, and before returning the HTML. + +Here's an example of using hooks: + +```python +from crawl4ai import WebCrawler +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +# Define the hooks +def on_driver_created(driver): + driver.maximize_window() + driver.get('https://example.com/login') + WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.NAME, 'username'))).send_keys('testuser') + driver.find_element(By.NAME, 'password').send_keys('password123') + driver.find_element(By.NAME, 'login').click() + return driver + +def before_get_url(driver): + driver.execute_cdp_cmd('Network.setExtraHTTPHeaders', {'headers': {'X-Test-Header': 'test'}}) + return driver + +# Create the WebCrawler instance +crawler = WebCrawler() +crawler.warmup() + +# Set the hooks +crawler.set_hook('on_driver_created', on_driver_created) +crawler.set_hook('before_get_url', before_get_url) + +# Run the crawler +result = crawler.run(url="https://example.com") + +print("Crawl result:", result) +``` + +In this example, we define hooks to handle driver initialization and custom headers before fetching the URL. + +## Using CSS Selectors 🎯 + +CSS selectors allow you to target specific elements on a web page for extraction. This can be useful for scraping structured content, such as articles or product details. + +Here's an example of using a CSS selector: + +```python +from crawl4ai import WebCrawler + +# Create the WebCrawler instance +crawler = WebCrawler() +crawler.warmup() + +# Run the crawler with a CSS selector to extract only H2 tags +result = crawler.run(url="https://www.nbcnews.com/business", css_selector="h2") + +print("Extracted H2 tags:", result.extracted_content) +``` + +In this example, we use the `css_selector` parameter to extract only the H2 tags from the web page. + +--- + +With these advanced features, you can leverage Crawl4AI to perform sophisticated web crawling and data extraction tasks. Whether you need to take screenshots, extract specific elements, customize the crawling process, or set custom headers, Crawl4AI provides the flexibility and power to meet your needs. Happy crawling! πŸ•·οΈπŸš€ diff --git a/docs/md/full_details/chunking_strategies.md b/docs/md/full_details/chunking_strategies.md new file mode 100644 index 00000000..f429310f --- /dev/null +++ b/docs/md/full_details/chunking_strategies.md @@ -0,0 +1,133 @@ +## Chunking Strategies πŸ“š + +Crawl4AI provides several powerful chunking strategies to divide text into manageable parts for further processing. Each strategy has unique characteristics and is suitable for different scenarios. Let's explore them one by one. + +### RegexChunking + +`RegexChunking` splits text using regular expressions. This is ideal for creating chunks based on specific patterns like paragraphs or sentences. + +#### When to Use +- Great for structured text with consistent delimiters. +- Suitable for documents where specific patterns (e.g., double newlines, periods) indicate logical chunks. + +#### Parameters +- `patterns` (list, optional): Regular expressions used to split the text. Default is to split by double newlines (`['\n\n']`). + +#### Example +```python +from crawl4ai.chunking_strategy import RegexChunking + +# Define patterns for splitting text +patterns = [r'\n\n', r'\. '] +chunker = RegexChunking(patterns=patterns) + +# Sample text +text = "This is a sample text. It will be split into chunks.\n\nThis is another paragraph." + +# Chunk the text +chunks = chunker.chunk(text) +print(chunks) +``` + +### NlpSentenceChunking + +`NlpSentenceChunking` uses NLP models to split text into sentences, ensuring accurate sentence boundaries. + +#### When to Use +- Ideal for texts where sentence boundaries are crucial. +- Useful for creating chunks that preserve grammatical structures. + +#### Parameters +- None. + +#### Example +```python +from crawl4ai.chunking_strategy import NlpSentenceChunking + +chunker = NlpSentenceChunking() + +# Sample text +text = "This is a sample text. It will be split into sentences. Here's another sentence." + +# Chunk the text +chunks = chunker.chunk(text) +print(chunks) +``` + +### TopicSegmentationChunking + +`TopicSegmentationChunking` employs the TextTiling algorithm to segment text into topic-based chunks. This method identifies thematic boundaries. + +#### When to Use +- Perfect for long documents with distinct topics. +- Useful when preserving topic continuity is more important than maintaining text order. + +#### Parameters +- `num_keywords` (int, optional): Number of keywords for each topic segment. Default is `3`. + +#### Example +```python +from crawl4ai.chunking_strategy import TopicSegmentationChunking + +chunker = TopicSegmentationChunking(num_keywords=3) + +# Sample text +text = "This document contains several topics. Topic one discusses AI. Topic two covers machine learning." + +# Chunk the text +chunks = chunker.chunk(text) +print(chunks) +``` + +### FixedLengthWordChunking + +`FixedLengthWordChunking` splits text into chunks based on a fixed number of words. This ensures each chunk has approximately the same length. + +#### When to Use +- Suitable for processing large texts where uniform chunk size is important. +- Useful when the number of words per chunk needs to be controlled. + +#### Parameters +- `chunk_size` (int, optional): Number of words per chunk. Default is `100`. + +#### Example +```python +from crawl4ai.chunking_strategy import FixedLengthWordChunking + +chunker = FixedLengthWordChunking(chunk_size=10) + +# Sample text +text = "This is a sample text. It will be split into chunks of fixed length." + +# Chunk the text +chunks = chunker.chunk(text) +print(chunks) +``` + +### SlidingWindowChunking + +`SlidingWindowChunking` uses a sliding window approach to create overlapping chunks. Each chunk has a fixed length, and the window slides by a specified step size. + +#### When to Use +- Ideal for creating overlapping chunks to preserve context. +- Useful for tasks where context from adjacent chunks is needed. + +#### Parameters +- `window_size` (int, optional): Number of words in each chunk. Default is `100`. +- `step` (int, optional): Number of words to slide the window. Default is `50`. + +#### Example +```python +from crawl4ai.chunking_strategy import SlidingWindowChunking + +chunker = SlidingWindowChunking(window_size=10, step=5) + +# Sample text +text = "This is a sample text. It will be split using a sliding window approach to preserve context." + +# Chunk the text +chunks = chunker.chunk(text) +print(chunks) +``` + +With these chunking strategies, you can choose the best method to divide your text based on your specific needs. Whether you need precise sentence boundaries, topic-based segmentation, or uniform chunk sizes, Crawl4AI has you covered. Happy chunking! πŸ“βœ¨ diff --git a/docs/md/full_details/crawl_request_parameters.md b/docs/md/full_details/crawl_request_parameters.md new file mode 100644 index 00000000..c32743c6 --- /dev/null +++ b/docs/md/full_details/crawl_request_parameters.md @@ -0,0 +1,130 @@ +# Crawl Request Parameters + +The `run` function in Crawl4AI is designed to be highly configurable, allowing you to customize the crawling and extraction process to suit your needs. Below are the parameters you can use with the `run` function, along with their descriptions, possible values, and examples. + +## Parameters + +### url (str) +**Description:** The URL of the webpage to crawl. +**Required:** Yes +**Example:** +```python +url = "https://www.nbcnews.com/business" +``` + +### word_count_threshold (int) +**Description:** The minimum number of words a block must contain to be considered meaningful. The default value is `5`. +**Required:** No +**Default Value:** `5` +**Example:** +```python +word_count_threshold = 10 +``` + +### extraction_strategy (ExtractionStrategy) +**Description:** The strategy to use for extracting content from the HTML. It must be an instance of `ExtractionStrategy`. If not provided, the default is `NoExtractionStrategy`. +**Required:** No +**Default Value:** `NoExtractionStrategy()` +**Example:** +```python +extraction_strategy = CosineStrategy(semantic_filter="finance") +``` + +### chunking_strategy (ChunkingStrategy) +**Description:** The strategy to use for chunking the text before processing. It must be an instance of `ChunkingStrategy`. The default value is `RegexChunking()`. +**Required:** No +**Default Value:** `RegexChunking()` +**Example:** +```python +chunking_strategy = NlpSentenceChunking() +``` + +### bypass_cache (bool) +**Description:** Whether to force a fresh crawl even if the URL has been previously crawled. The default value is `False`. +**Required:** No +**Default Value:** `False` +**Example:** +```python +bypass_cache = True +``` + +### css_selector (str) +**Description:** The CSS selector to target specific parts of the HTML for extraction. If not provided, the entire HTML will be processed. +**Required:** No +**Default Value:** `None` +**Example:** +```python +css_selector = "div.article-content" +``` + +### screenshot (bool) +**Description:** Whether to take screenshots of the page. The default value is `False`. +**Required:** No +**Default Value:** `False` +**Example:** +```python +screenshot = True +``` + +### user_agent (str) +**Description:** The user agent to use for the HTTP requests. If not provided, a default user agent will be used. +**Required:** No +**Default Value:** `None` +**Example:** +```python +user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3" +``` + +### verbose (bool) +**Description:** Whether to enable verbose logging. The default value is `True`. +**Required:** No +**Default Value:** `True` +**Example:** +```python +verbose = True +``` + +### **kwargs +Additional keyword arguments that can be passed to customize the crawling process further. Some notable options include: + +- **only_text (bool):** Whether to extract only text content, excluding HTML tags. Default is `False`. + +**Example:** +```python +result = crawler.run( + url="https://www.nbcnews.com/business", + css_selector="p", + only_text=True +) +``` + +## Example Usage + +Here's an example of how to use the `run` function with various parameters: + +```python +from crawl4ai import WebCrawler +from crawl4ai.extraction_strategy import CosineStrategy +from crawl4ai.chunking_strategy import NlpSentenceChunking + +# Create the WebCrawler instance +crawler = WebCrawler() + +# Run the crawler with custom parameters +result = crawler.run( + url="https://www.nbcnews.com/business", + word_count_threshold=10, + extraction_strategy=CosineStrategy(semantic_filter="finance"), + chunking_strategy=NlpSentenceChunking(), + bypass_cache=True, + css_selector="div.article-content", + screenshot=True, + user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3", + verbose=True, + only_text=True +) + +print(result) +``` + +This example demonstrates how to configure various parameters to customize the crawling and extraction process using Crawl4AI. diff --git a/docs/md/full_details/crawl_result_class.md b/docs/md/full_details/crawl_result_class.md new file mode 100644 index 00000000..f66e16dc --- /dev/null +++ b/docs/md/full_details/crawl_result_class.md @@ -0,0 +1,120 @@ +# Crawl Result + +The `CrawlResult` class is the heart of Crawl4AI's output, encapsulating all the data extracted from a crawling session. This class contains various fields that store the results of the web crawling and extraction process. Let's break down each field and see what it holds. πŸŽ‰ + +## Class Definition + +```python +class CrawlResult(BaseModel): + url: str + html: str + success: bool + cleaned_html: Optional[str] = None + media: Dict[str, List[Dict]] = {} + links: Dict[str, List[Dict]] = {} + screenshot: Optional[str] = None + markdown: Optional[str] = None + extracted_content: Optional[str] = None + metadata: Optional[dict] = None + error_message: Optional[str] = None +``` + +## Fields Explanation + +### `url: str` +The URL that was crawled. This field simply stores the URL of the web page that was processed. + +### `html: str` +The raw HTML content of the web page. This is the unprocessed HTML source as retrieved by the crawler. + +### `success: bool` +A flag indicating whether the crawling and extraction were successful. If any error occurs during the process, this will be `False`. + +### `cleaned_html: Optional[str]` +The cleaned HTML content of the web page. This field holds the HTML after removing unwanted tags like `