diff --git a/.dev_scripts/test_regression_txt2img_dream_v1_4.sh b/.dev_scripts/test_regression_txt2img_dream_v1_4.sh index 11cbf8f14b..9326d3c311 100644 --- a/.dev_scripts/test_regression_txt2img_dream_v1_4.sh +++ b/.dev_scripts/test_regression_txt2img_dream_v1_4.sh @@ -5,8 +5,7 @@ SAMPLES_DIR=${OUT_DIR} python scripts/dream.py \ --from_file ${PROMPT_FILE} \ --outdir ${OUT_DIR} \ - --sampler plms \ - --full_precision + --sampler plms # original output by CompVis/stable-diffusion IMAGE1=".dev_scripts/images/v1_4_astronaut_rides_horse_plms_step50_seed42.png" diff --git a/.github/workflows/mkdocs-flow.yml b/.github/workflows/mkdocs-flow.yml new file mode 100644 index 0000000000..49a9cbd423 --- /dev/null +++ b/.github/workflows/mkdocs-flow.yml @@ -0,0 +1,28 @@ +name: Deploy +on: + push: + branches: + - main + pull_request: + branches: + - main +jobs: + build: + name: Deploy docs to GitHub Pages + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Build + uses: Tiryoh/actions-mkdocs@v0 + with: + mkdocs_version: 'latest' # option + requirements: '/requirements-mkdocs.txt' # option + configfile: '/mkdocs.yml' # option + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./site diff --git a/.github/workflows/test-dream-conda.yml b/.github/workflows/test-dream-conda.yml index 3bd9b24582..6c51ebe718 100644 --- a/.github/workflows/test-dream-conda.yml +++ b/.github/workflows/test-dream-conda.yml @@ -85,9 +85,9 @@ jobs: fi # Utterly hacky, but I don't know how else to do this if [[ ${{ github.ref }} == 'refs/heads/master' ]]; then - time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/dream.py --from_file tests/preflight_prompts.txt --full_precision + time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/dream.py --from_file tests/preflight_prompts.txt elif [[ ${{ github.ref }} == 'refs/heads/development' ]]; then - time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/dream.py --from_file tests/dev_prompts.txt --full_precision + time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/dream.py --from_file tests/dev_prompts.txt fi mkdir -p outputs/img-samples - name: Archive results diff --git a/.gitignore b/.gitignore index df1e55ee6d..da74df3a1a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ # ignore default image save location and model symbolic link outputs/ models/ldm/stable-diffusion-v1/model.ckpt +ldm/dream/restoration/codeformer/weights + +# ignore the Anaconda/Miniconda installer used while building Docker image +anaconda.sh # ignore a directory which serves as a place for initial images inputs/ @@ -77,9 +81,6 @@ db.sqlite3-journal instance/ .webassets-cache -# WebUI temp files: -img2img-tmp.png - # Scrapy stuff: .scrapy @@ -186,3 +187,12 @@ testtube checkpoints # If it's a Mac .DS_Store + +# Let the frontend manage its own gitignore +!frontend/* + +# Scratch folder +.scratch/ +.vscode/ +gfpgan/ +models/ldm/stable-diffusion-v1/model.sha256 diff --git a/.prettierrc.yaml b/.prettierrc.yaml new file mode 100644 index 0000000000..ce4b99a07b --- /dev/null +++ b/.prettierrc.yaml @@ -0,0 +1,13 @@ +endOfLine: lf +tabWidth: 2 +useTabs: false +singleQuote: true +quoteProps: as-needed +embeddedLanguageFormatting: auto +overrides: + - files: '*.md' + options: + proseWrap: always + printWidth: 80 + parser: markdown + cursorOffset: -1 diff --git a/README.md b/README.md index 4c6681ee59..b61b365774 100644 --- a/README.md +++ b/README.md @@ -1,165 +1,190 @@ -

InvokeAI: A Stable Diffusion Toolkit

+
-

- -

+# InvokeAI: A Stable Diffusion Toolkit -

- last-commit - stars -
- issues - pull-requests -

+![project logo](docs/assets/logo.png) -This is a fork of -[CompVis/stable-diffusion](https://github.com/CompVis/stable-diffusion), -the open source text-to-image generator. It provides a streamlined -process with various new features and options to aid the image -generation process. It runs on Windows, Mac and Linux machines, -and runs on GPU cards with as little as 4 GB or RAM. +[![discord badge]][discord link] + +[![latest release badge]][latest release link] [![github stars badge]][github stars link] [![github forks badge]][github forks link] + +[![CI checks on main badge]][CI checks on main link] [![CI checks on dev badge]][CI checks on dev link] [![latest commit to dev badge]][latest commit to dev link] + +[![github open issues badge]][github open issues link] [![github open prs badge]][github open prs link] + +[CI checks on dev badge]: https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/development?label=CI%20status%20on%20dev&cache=900&icon=github +[CI checks on dev link]: https://github.com/invoke-ai/InvokeAI/actions?query=branch%3Adevelopment +[CI checks on main badge]: https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/main?label=CI%20status%20on%20main&cache=900&icon=github +[CI checks on main link]: https://github.com/invoke-ai/InvokeAI/actions/workflows/test-dream-conda.yml +[discord badge]: https://flat.badgen.net/discord/members/htRgbc7e?icon=discord +[discord link]: https://discord.gg/ZmtBAhwWhy +[github forks badge]: https://flat.badgen.net/github/forks/invoke-ai/InvokeAI?icon=github +[github forks link]: https://useful-forks.github.io/?repo=invoke-ai%2FInvokeAI +[github open issues badge]: https://flat.badgen.net/github/open-issues/invoke-ai/InvokeAI?icon=github +[github open issues link]: https://github.com/invoke-ai/InvokeAI/issues?q=is%3Aissue+is%3Aopen +[github open prs badge]: https://flat.badgen.net/github/open-prs/invoke-ai/InvokeAI?icon=github +[github open prs link]: https://github.com/invoke-ai/InvokeAI/pulls?q=is%3Apr+is%3Aopen +[github stars badge]: https://flat.badgen.net/github/stars/invoke-ai/InvokeAI?icon=github +[github stars link]: https://github.com/invoke-ai/InvokeAI/stargazers +[latest commit to dev badge]: https://flat.badgen.net/github/last-commit/invoke-ai/InvokeAI/development?icon=github&color=yellow&label=last%20dev%20commit&cache=900 +[latest commit to dev link]: https://github.com/invoke-ai/InvokeAI/commits/development +[latest release badge]: https://flat.badgen.net/github/release/invoke-ai/InvokeAI/development?icon=github +[latest release link]: https://github.com/invoke-ai/InvokeAI/releases +
+ +This is a fork of [CompVis/stable-diffusion](https://github.com/CompVis/stable-diffusion), the open +source text-to-image generator. It provides a streamlined process with various new features and +options to aid the image generation process. It runs on Windows, Mac and Linux machines, and runs on +GPU cards with as little as 4 GB or RAM. _Note: This fork is rapidly evolving. Please use the -[Issues](https://github.com/invoke-ai/InvokeAI/issues) tab to -report bugs and make feature requests. Be sure to use the provided -templates. They will help aid diagnose issues faster._ +[Issues](https://github.com/invoke-ai/InvokeAI/issues) tab to report bugs and make feature +requests. Be sure to use the provided templates. They will help aid diagnose issues faster._ -_This repository was formally known as lstein/stable-diffusion_ - -# **Table of Contents** +## Table of Contents 1. [Installation](#installation) -2. [Major Features](#features) -3. [Changelog](#latest-changes) -4. [Troubleshooting](#troubleshooting) -5. [Contributing](#contributing) -6. [Support](#support) +2. [Hardware Requirements](#hardware-requirements) +3. [Features](#features) +4. [Latest Changes](#latest-changes) +5. [Troubleshooting](#troubleshooting) +6. [Contributing](#contributing) +7. [Contributors](#contributors) +8. [Support](#support) +9. [Further Reading](#further-reading) -# Installation +### Installation -This fork is supported across multiple platforms. You can find individual installation instructions below. +This fork is supported across multiple platforms. You can find individual installation instructions +below. -- ## [Linux](docs/installation/INSTALL_LINUX.md) -- ## [Windows](docs/installation/INSTALL_WINDOWS.md) -- ## [Macintosh](docs/installation/INSTALL_MAC.md) +- #### [Linux](docs/installation/INSTALL_LINUX.md) -## **Hardware Requirements** +- #### [Windows](docs/installation/INSTALL_WINDOWS.md) -**System** +- #### [Macintosh](docs/installation/INSTALL_MAC.md) + +### Hardware Requirements + +#### System You wil need one of the following: - An NVIDIA-based graphics card with 4 GB or more VRAM memory. - An Apple computer with an M1 chip. -**Memory** +#### Memory - At least 12 GB Main Memory RAM. -**Disk** +#### Disk - At least 6 GB of free disk space for the machine learning model, Python, and all its dependencies. -**Note** +#### Note -If you are have a Nvidia 10xx series card (e.g. the 1080ti), please -run the dream script in full-precision mode as shown below. +Precision is auto configured based on the device. If however you encounter +errors like 'expected type Float but found Half' or 'not implemented for Half' +you can try starting `dream.py` with the `--precision=float32` flag: -Similarly, specify full-precision mode on Apple M1 hardware. - -To run in full-precision mode, start `dream.py` with the -`--full_precision` flag: - -``` -(ldm) ~/stable-diffusion$ python scripts/dream.py --full_precision +```bash +(ldm) ~/stable-diffusion$ python scripts/dream.py --precision=float32 ``` -# Features +### Features -## **Major Features** +#### Major Features -- ## [Interactive Command Line Interface](docs/features/CLI.md) +- [Interactive Command Line Interface](docs/features/CLI.md) +- [Image To Image](docs/features/IMG2IMG.md) +- [Inpainting Support](docs/features/INPAINTING.md) +- [Outpainting Support](docs/features/OUTPAINTING.md) +- [GFPGAN and Real-ESRGAN Support](docs/features/UPSCALE.md) +- [Seamless Tiling](docs/features/OTHER.md#seamless-tiling) +- [Google Colab](docs/features/OTHER.md#google-colab) +- [Web Server](docs/features/WEB.md) +- [Reading Prompts From File](docs/features/PROMPTS.md#reading-prompts-from-a-file) +- [Shortcut: Reusing Seeds](docs/features/OTHER.md#shortcuts-reusing-seeds) +- [Weighted Prompts](docs/features/PROMPTS.md#weighted-prompts) +- [Negative/Unconditioned Prompts](docs/features/PROMPTS.md#negative-and-unconditioned-prompts) +- [Variations](docs/features/VARIATIONS.md) +- [Personalizing Text-to-Image Generation](docs/features/TEXTUAL_INVERSION.md) +- [Simplified API for text to image generation](docs/features/OTHER.md#simplified-api) -- ## [Image To Image](docs/features/IMG2IMG.md) +#### Other Features -- ## [Inpainting Support](docs/features/INPAINTING.md) +- [Creating Transparent Regions for Inpainting](docs/features/INPAINTING.md#creating-transparent-regions-for-inpainting) +- [Preload Models](docs/features/OTHER.md#preload-models) -- ## [GFPGAN and Real-ESRGAN Support](docs/features/UPSCALE.md) +### Latest Changes -- ## [Seamless Tiling](docs/features/OTHER.md#seamless-tiling) +- vNEXT (TODO 2022) -- ## [Google Colab](docs/features/OTHER.md#google-colab) - -- ## [Web Server](docs/features/WEB.md) - -- ## [Reading Prompts From File](docs/features/OTHER.md#reading-prompts-from-a-file) - -- ## [Shortcut: Reusing Seeds](docs/features/OTHER.md#shortcuts-reusing-seeds) - -- ## [Weighted Prompts](docs/features/OTHER.md#weighted-prompts) - -- ## [Variations](docs/features/VARIATIONS.md) - -- ## [Personalizing Text-to-Image Generation](docs/features/TEXTUAL_INVERSION.md) - -- ## [Simplified API for text to image generation](docs/features/OTHER.md#simplified-api) - -## **Other Features** - -- ### [Creating Transparent Regions for Inpainting](docs/features/INPAINTING.md#creating-transparent-regions-for-inpainting) - -- ### [Preload Models](docs/features/OTHER.md#preload-models) - -# Latest Changes + - Deprecated `--full_precision` / `-F`. Simply omit it and `dream.py` will auto + configure. To switch away from auto use the new flag like `--precision=float32`. - v1.14 (11 September 2022) - Memory optimizations for small-RAM cards. 512x512 now possible on 4 GB GPUs. - Full support for Apple hardware with M1 or M2 chips. - - Add "seamless mode" for circular tiling of image. Generates beautiful effects. ([prixt](https://github.com/prixt)). + - Add "seamless mode" for circular tiling of image. Generates beautiful effects. + ([prixt](https://github.com/prixt)). - Inpainting support. - Improved web server GUI. - Lots of code and documentation cleanups. - v1.13 (3 September 2022 - - Support image variations (see [VARIATIONS](docs/features/VARIATIONS.md) ([Kevin Gibbons](https://github.com/bakkot) and many contributors and reviewers) - - Supports a Google Colab notebook for a standalone server running on Google hardware [Arturo Mendivil](https://github.com/artmen1516) - - WebUI supports GFPGAN/ESRGAN facial reconstruction and upscaling [Kevin Gibbons](https://github.com/bakkot) - - WebUI supports incremental display of in-progress images during generation [Kevin Gibbons](https://github.com/bakkot) - - A new configuration file scheme that allows new models (including upcoming stable-diffusion-v1.5) - to be added without altering the code. ([David Wager](https://github.com/maddavid12)) + - Support image variations (see [VARIATIONS](docs/features/VARIATIONS.md) + ([Kevin Gibbons](https://github.com/bakkot) and many contributors and reviewers) + - Supports a Google Colab notebook for a standalone server running on Google hardware + [Arturo Mendivil](https://github.com/artmen1516) + - WebUI supports GFPGAN/ESRGAN facial reconstruction and upscaling + [Kevin Gibbons](https://github.com/bakkot) + - WebUI supports incremental display of in-progress images during generation + [Kevin Gibbons](https://github.com/bakkot) + - A new configuration file scheme that allows new models (including upcoming + stable-diffusion-v1.5) to be added without altering the code. + ([David Wager](https://github.com/maddavid12)) - Can specify --grid on dream.py command line as the default. - Miscellaneous internal bug and stability fixes. - Works on M1 Apple hardware. - Multiple bug fixes. -For older changelogs, please visit **[CHANGELOGS](docs/CHANGELOG.md)**. +For older changelogs, please visit the **[CHANGELOG](docs/features/CHANGELOG.md)**. -# Troubleshooting +### Troubleshooting -Please check out our **[Q&A](docs/help/TROUBLESHOOT.md)** to get solutions for common installation problems and other issues. +Please check out our **[Q&A](docs/help/TROUBLESHOOT.md)** to get solutions for common installation +problems and other issues. # Contributing -Anyone who wishes to contribute to this project, whether documentation, features, bug fixes, code cleanup, testing, or code reviews, is very much encouraged to do so. If you are unfamiliar with -how to contribute to GitHub projects, here is a [Getting Started Guide](https://opensource.com/article/19/7/create-pull-request-github). +Anyone who wishes to contribute to this project, whether documentation, features, bug fixes, code +cleanup, testing, or code reviews, is very much encouraged to do so. If you are unfamiliar with how +to contribute to GitHub projects, here is a +[Getting Started Guide](https://opensource.com/article/19/7/create-pull-request-github). -A full set of contribution guidelines, along with templates, are in progress, but for now the most important thing is to **make your pull request against the "development" branch**, and not against "main". This will help keep public breakage to a minimum and will allow you to propose more radical changes. +A full set of contribution guidelines, along with templates, are in progress, but for now the most +important thing is to **make your pull request against the "development" branch**, and not against +"main". This will help keep public breakage to a minimum and will allow you to propose more radical +changes. -## **Contributors** +### Contributors -This fork is a combined effort of various people from across the world. [Check out the list of all these amazing people](docs/CONTRIBUTORS.md). We thank them for their time, hard work and effort. +This fork is a combined effort of various people from across the world. +[Check out the list of all these amazing people](docs/other/CONTRIBUTORS.md). We thank them for +their time, hard work and effort. -# Support +### Support -For support, -please use this repository's GitHub Issues tracking service. Feel free -to send me an email if you use and like the script. +For support, please use this repository's GitHub Issues tracking service. Feel free to send me an +email if you use and like the script. -Original portions of the software are Copyright (c) 2020 Lincoln D. Stein (https://github.com/lstein) +Original portions of the software are Copyright (c) 2020 +[Lincoln D. Stein](https://github.com/lstein) -# Further Reading +### Further Reading -Please see the original README for more information on this software -and underlying algorithm, located in the file [README-CompViz.md](docs/README-CompViz.md). +Please see the original README for more information on this software and underlying algorithm, +located in the file [README-CompViz.md](docs/other/README-CompViz.md). diff --git a/backend/modules/create_cmd_parser.py b/backend/modules/create_cmd_parser.py new file mode 100644 index 0000000000..06f2f4025c --- /dev/null +++ b/backend/modules/create_cmd_parser.py @@ -0,0 +1,49 @@ +import argparse +import os +from ldm.dream.args import PRECISION_CHOICES + + +def create_cmd_parser(): + parser = argparse.ArgumentParser(description="InvokeAI web UI") + parser.add_argument( + "--host", + type=str, + help="The host to serve on", + default="localhost", + ) + parser.add_argument("--port", type=int, help="The port to serve on", default=9090) + parser.add_argument( + "--cors", + nargs="*", + type=str, + help="Additional allowed origins, comma-separated", + ) + parser.add_argument( + "--embedding_path", + type=str, + help="Path to a pre-trained embedding manager checkpoint - can only be set on command line", + ) + # TODO: Can't get flask to serve images from any dir (saving to the dir does work when specified) + # parser.add_argument( + # "--output_dir", + # default="outputs/", + # type=str, + # help="Directory for output images", + # ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="Enables verbose logging", + ) + parser.add_argument( + "--precision", + dest="precision", + type=str, + choices=PRECISION_CHOICES, + metavar="PRECISION", + help=f'Set model precision. Defaults to auto selected based on device. Options: {", ".join(PRECISION_CHOICES)}', + default="auto", + ) + + return parser diff --git a/backend/modules/parameters.py b/backend/modules/parameters.py new file mode 100644 index 0000000000..ec0cfe8272 --- /dev/null +++ b/backend/modules/parameters.py @@ -0,0 +1,61 @@ +from modules.parse_seed_weights import parse_seed_weights +import argparse + +SAMPLER_CHOICES = [ + "ddim", + "k_dpm_2_a", + "k_dpm_2", + "k_euler_a", + "k_euler", + "k_heun", + "k_lms", + "plms", +] + + +def parameters_to_command(params): + """ + Converts dict of parameters into a `dream.py` REPL command. + """ + + switches = list() + + if "prompt" in params: + switches.append(f'"{params["prompt"]}"') + if "steps" in params: + switches.append(f'-s {params["steps"]}') + if "seed" in params: + switches.append(f'-S {params["seed"]}') + if "width" in params: + switches.append(f'-W {params["width"]}') + if "height" in params: + switches.append(f'-H {params["height"]}') + if "cfg_scale" in params: + switches.append(f'-C {params["cfg_scale"]}') + if "sampler_name" in params: + switches.append(f'-A {params["sampler_name"]}') + if "seamless" in params and params["seamless"] == True: + switches.append(f"--seamless") + if "init_img" in params and len(params["init_img"]) > 0: + switches.append(f'-I {params["init_img"]}') + if "init_mask" in params and len(params["init_mask"]) > 0: + switches.append(f'-M {params["init_mask"]}') + if "init_color" in params and len(params["init_color"]) > 0: + switches.append(f'--init_color {params["init_color"]}') + if "strength" in params and "init_img" in params: + switches.append(f'-f {params["strength"]}') + if "fit" in params and params["fit"] == True: + switches.append(f"--fit") + if "gfpgan_strength" in params and params["gfpgan_strength"]: + switches.append(f'-G {params["gfpgan_strength"]}') + if "upscale" in params and params["upscale"]: + switches.append(f'-U {params["upscale"][0]} {params["upscale"][1]}') + if "variation_amount" in params and params["variation_amount"] > 0: + switches.append(f'-v {params["variation_amount"]}') + if "with_variations" in params: + seed_weight_pairs = ",".join( + f"{seed}:{weight}" for seed, weight in params["with_variations"] + ) + switches.append(f"-V {seed_weight_pairs}") + + return " ".join(switches) diff --git a/backend/modules/parse_seed_weights.py b/backend/modules/parse_seed_weights.py new file mode 100644 index 0000000000..7e15d4e166 --- /dev/null +++ b/backend/modules/parse_seed_weights.py @@ -0,0 +1,47 @@ +def parse_seed_weights(seed_weights): + """ + Accepts seed weights as string in "12345:0.1,23456:0.2,3456:0.3" format + Validates them + If valid: returns as [[12345, 0.1], [23456, 0.2], [3456, 0.3]] + If invalid: returns False + """ + + # Must be a string + if not isinstance(seed_weights, str): + return False + # String must not be empty + if len(seed_weights) == 0: + return False + + pairs = [] + + for pair in seed_weights.split(","): + split_values = pair.split(":") + + # Seed and weight are required + if len(split_values) != 2: + return False + + if len(split_values[0]) == 0 or len(split_values[1]) == 1: + return False + + # Try casting the seed to int and weight to float + try: + seed = int(split_values[0]) + weight = float(split_values[1]) + except ValueError: + return False + + # Seed must be 0 or above + if not seed >= 0: + return False + + # Weight must be between 0 and 1 + if not (weight >= 0 and weight <= 1): + return False + + # This pair is valid + pairs.append([seed, weight]) + + # All pairs are valid + return pairs diff --git a/backend/server.py b/backend/server.py new file mode 100644 index 0000000000..b5a04a6e9b --- /dev/null +++ b/backend/server.py @@ -0,0 +1,767 @@ +import mimetypes +import transformers +import json +import os +import traceback +import eventlet +import glob +import shlex +import math +import shutil +import sys + +sys.path.append(".") + +from argparse import ArgumentTypeError +from modules.create_cmd_parser import create_cmd_parser + +parser = create_cmd_parser() +opt = parser.parse_args() + + +from flask_socketio import SocketIO +from flask import Flask, send_from_directory, url_for, jsonify +from pathlib import Path +from PIL import Image +from pytorch_lightning import logging +from threading import Event +from uuid import uuid4 +from send2trash import send2trash + + +from ldm.generate import Generate +from ldm.dream.restoration import Restoration +from ldm.dream.pngwriter import PngWriter, retrieve_metadata +from ldm.dream.args import APP_ID, APP_VERSION, calculate_init_img_hash +from ldm.dream.conditioning import split_weighted_subprompts + +from modules.parameters import parameters_to_command + + +""" +USER CONFIG +""" +if opt.cors and "*" in opt.cors: + raise ArgumentTypeError('"*" is not an allowed CORS origin') + + +output_dir = "outputs/" # Base output directory for images +host = opt.host # Web & socket.io host +port = opt.port # Web & socket.io port +verbose = opt.verbose # enables copious socket.io logging +precision = opt.precision +embedding_path = opt.embedding_path +additional_allowed_origins = ( + opt.cors if opt.cors else [] +) # additional CORS allowed origins +model = "stable-diffusion-1.4" + +""" +END USER CONFIG +""" + + +print("* Initializing, be patient...\n") + + +""" +SERVER SETUP +""" + + +# fix missing mimetypes on windows due to registry wonkiness +mimetypes.add_type("application/javascript", ".js") +mimetypes.add_type("text/css", ".css") + +app = Flask(__name__, static_url_path="", static_folder="../frontend/dist/") + + +app.config["OUTPUTS_FOLDER"] = "../outputs" + + +@app.route("/outputs/") +def outputs(filename): + return send_from_directory(app.config["OUTPUTS_FOLDER"], filename) + + +@app.route("/", defaults={"path": ""}) +def serve(path): + return send_from_directory(app.static_folder, "index.html") + + +logger = True if verbose else False +engineio_logger = True if verbose else False + +# default 1,000,000, needs to be higher for socketio to accept larger images +max_http_buffer_size = 10000000 + +cors_allowed_origins = [f"http://{host}:{port}"] + additional_allowed_origins + +socketio = SocketIO( + app, + logger=logger, + engineio_logger=engineio_logger, + max_http_buffer_size=max_http_buffer_size, + cors_allowed_origins=cors_allowed_origins, +) + + +""" +END SERVER SETUP +""" + + +""" +APP SETUP +""" + + +class CanceledException(Exception): + pass + + +try: + gfpgan, codeformer, esrgan = None, None, None + from ldm.dream.restoration.base import Restoration + + restoration = Restoration() + gfpgan, codeformer = restoration.load_face_restore_models() + esrgan = restoration.load_esrgan() + + # coreformer.process(self, image, strength, device, seed=None, fidelity=0.75) + +except (ModuleNotFoundError, ImportError): + print(traceback.format_exc(), file=sys.stderr) + print(">> You may need to install the ESRGAN and/or GFPGAN modules") + +canceled = Event() + +# reduce logging outputs to error +transformers.logging.set_verbosity_error() +logging.getLogger("pytorch_lightning").setLevel(logging.ERROR) + +# Initialize and load model +generate = Generate( + model, + precision=precision, + embedding_path=embedding_path, +) +generate.load_model() + + +# location for "finished" images +result_path = os.path.join(output_dir, "img-samples/") + +# temporary path for intermediates +intermediate_path = os.path.join(result_path, "intermediates/") + +# path for user-uploaded init images and masks +init_image_path = os.path.join(result_path, "init-images/") +mask_image_path = os.path.join(result_path, "mask-images/") + +# txt log +log_path = os.path.join(result_path, "dream_log.txt") + +# make all output paths +[ + os.makedirs(path, exist_ok=True) + for path in [result_path, intermediate_path, init_image_path, mask_image_path] +] + + +""" +END APP SETUP +""" + + +""" +SOCKET.IO LISTENERS +""" + + +@socketio.on("requestSystemConfig") +def handle_request_capabilities(): + print(f">> System config requested") + config = get_system_config() + socketio.emit("systemConfig", config) + + +@socketio.on("requestAllImages") +def handle_request_all_images(): + print(f">> All images requested") + paths = list(filter(os.path.isfile, glob.glob(result_path + "*.png"))) + paths.sort(key=lambda x: os.path.getmtime(x)) + image_array = [] + for path in paths: + metadata = retrieve_metadata(path) + image_array.append({"url": path, "metadata": metadata["sd-metadata"]}) + socketio.emit("galleryImages", {"images": image_array}) + eventlet.sleep(0) + + +@socketio.on("generateImage") +def handle_generate_image_event( + generation_parameters, esrgan_parameters, gfpgan_parameters +): + print( + f">> Image generation requested: {generation_parameters}\nESRGAN parameters: {esrgan_parameters}\nGFPGAN parameters: {gfpgan_parameters}" + ) + generate_images(generation_parameters, esrgan_parameters, gfpgan_parameters) + + +@socketio.on("runESRGAN") +def handle_run_esrgan_event(original_image, esrgan_parameters): + print( + f'>> ESRGAN upscale requested for "{original_image["url"]}": {esrgan_parameters}' + ) + progress = { + "currentStep": 1, + "totalSteps": 1, + "currentIteration": 1, + "totalIterations": 1, + "currentStatus": "Preparing", + "isProcessing": True, + "currentStatusHasSteps": False, + } + + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + image = Image.open(original_image["url"]) + + seed = ( + original_image["metadata"]["seed"] + if "seed" in original_image["metadata"] + else "unknown_seed" + ) + + progress["currentStatus"] = "Upscaling" + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + image = esrgan.process( + image=image, + upsampler_scale=esrgan_parameters["upscale"][0], + strength=esrgan_parameters["upscale"][1], + seed=seed, + ) + + progress["currentStatus"] = "Saving image" + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + esrgan_parameters["seed"] = seed + metadata = parameters_to_post_processed_image_metadata( + parameters=esrgan_parameters, + original_image_path=original_image["url"], + type="esrgan", + ) + command = parameters_to_command(esrgan_parameters) + + path = save_image(image, command, metadata, result_path, postprocessing="esrgan") + + write_log_message(f'[Upscaled] "{original_image["url"]}" > "{path}": {command}') + + progress["currentStatus"] = "Finished" + progress["currentStep"] = 0 + progress["totalSteps"] = 0 + progress["currentIteration"] = 0 + progress["totalIterations"] = 0 + progress["isProcessing"] = False + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + socketio.emit( + "esrganResult", + { + "url": os.path.relpath(path), + "metadata": metadata, + }, + ) + + +@socketio.on("runGFPGAN") +def handle_run_gfpgan_event(original_image, gfpgan_parameters): + print( + f'>> GFPGAN face fix requested for "{original_image["url"]}": {gfpgan_parameters}' + ) + progress = { + "currentStep": 1, + "totalSteps": 1, + "currentIteration": 1, + "totalIterations": 1, + "currentStatus": "Preparing", + "isProcessing": True, + "currentStatusHasSteps": False, + } + + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + image = Image.open(original_image["url"]) + + seed = ( + original_image["metadata"]["seed"] + if "seed" in original_image["metadata"] + else "unknown_seed" + ) + + progress["currentStatus"] = "Fixing faces" + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + image = gfpgan.process( + image=image, strength=gfpgan_parameters["gfpgan_strength"], seed=seed + ) + + progress["currentStatus"] = "Saving image" + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + gfpgan_parameters["seed"] = seed + metadata = parameters_to_post_processed_image_metadata( + parameters=gfpgan_parameters, + original_image_path=original_image["url"], + type="gfpgan", + ) + command = parameters_to_command(gfpgan_parameters) + + path = save_image(image, command, metadata, result_path, postprocessing="gfpgan") + + write_log_message(f'[Fixed faces] "{original_image["url"]}" > "{path}": {command}') + + progress["currentStatus"] = "Finished" + progress["currentStep"] = 0 + progress["totalSteps"] = 0 + progress["currentIteration"] = 0 + progress["totalIterations"] = 0 + progress["isProcessing"] = False + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + socketio.emit( + "gfpganResult", + { + "url": os.path.relpath(path), + "metadata": metadata, + }, + ) + + +@socketio.on("cancel") +def handle_cancel(): + print(f">> Cancel processing requested") + canceled.set() + socketio.emit("processingCanceled") + + +# TODO: I think this needs a safety mechanism. +@socketio.on("deleteImage") +def handle_delete_image(path, uuid): + print(f'>> Delete requested "{path}"') + send2trash(path) + socketio.emit("imageDeleted", {"url": path, "uuid": uuid}) + + +# TODO: I think this needs a safety mechanism. +@socketio.on("uploadInitialImage") +def handle_upload_initial_image(bytes, name): + print(f'>> Init image upload requested "{name}"') + uuid = uuid4().hex + split = os.path.splitext(name) + name = f"{split[0]}.{uuid}{split[1]}" + file_path = os.path.join(init_image_path, name) + os.makedirs(os.path.dirname(file_path), exist_ok=True) + newFile = open(file_path, "wb") + newFile.write(bytes) + socketio.emit("initialImageUploaded", {"url": file_path, "uuid": ""}) + + +# TODO: I think this needs a safety mechanism. +@socketio.on("uploadMaskImage") +def handle_upload_mask_image(bytes, name): + print(f'>> Mask image upload requested "{name}"') + uuid = uuid4().hex + split = os.path.splitext(name) + name = f"{split[0]}.{uuid}{split[1]}" + file_path = os.path.join(mask_image_path, name) + os.makedirs(os.path.dirname(file_path), exist_ok=True) + newFile = open(file_path, "wb") + newFile.write(bytes) + socketio.emit("maskImageUploaded", {"url": file_path, "uuid": ""}) + + +""" +END SOCKET.IO LISTENERS +""" + + +""" +ADDITIONAL FUNCTIONS +""" + + +def get_system_config(): + return { + "model": "stable diffusion", + "model_id": model, + "model_hash": generate.model_hash, + "app_id": APP_ID, + "app_version": APP_VERSION, + } + + +def parameters_to_post_processed_image_metadata(parameters, original_image_path, type): + # top-level metadata minus `image` or `images` + metadata = get_system_config() + + orig_hash = calculate_init_img_hash(original_image_path) + + image = {"orig_path": original_image_path, "orig_hash": orig_hash} + + if type == "esrgan": + image["type"] = "esrgan" + image["scale"] = parameters["upscale"][0] + image["strength"] = parameters["upscale"][1] + elif type == "gfpgan": + image["type"] = "gfpgan" + image["strength"] = parameters["gfpgan_strength"] + else: + raise TypeError(f"Invalid type: {type}") + + metadata["image"] = image + return metadata + + +def parameters_to_generated_image_metadata(parameters): + # top-level metadata minus `image` or `images` + + metadata = get_system_config() + # remove any image keys not mentioned in RFC #266 + rfc266_img_fields = [ + "type", + "postprocessing", + "sampler", + "prompt", + "seed", + "variations", + "steps", + "cfg_scale", + "step_number", + "width", + "height", + "extra", + "seamless", + ] + + rfc_dict = {} + + for item in parameters.items(): + key, value = item + if key in rfc266_img_fields: + rfc_dict[key] = value + + postprocessing = [] + + # 'postprocessing' is either null or an + if "gfpgan_strength" in parameters: + + postprocessing.append( + {"type": "gfpgan", "strength": float(parameters["gfpgan_strength"])} + ) + + if "upscale" in parameters: + postprocessing.append( + { + "type": "esrgan", + "scale": int(parameters["upscale"][0]), + "strength": float(parameters["upscale"][1]), + } + ) + + rfc_dict["postprocessing"] = postprocessing if len(postprocessing) > 0 else None + + # semantic drift + rfc_dict["sampler"] = parameters["sampler_name"] + + # display weighted subprompts (liable to change) + subprompts = split_weighted_subprompts(parameters["prompt"]) + subprompts = [{"prompt": x[0], "weight": x[1]} for x in subprompts] + rfc_dict["prompt"] = subprompts + + # 'variations' should always exist and be an array, empty or consisting of {'seed': seed, 'weight': weight} pairs + variations = [] + + if "with_variations" in parameters: + variations = [ + {"seed": x[0], "weight": x[1]} for x in parameters["with_variations"] + ] + + rfc_dict["variations"] = variations + + if "init_img" in parameters: + rfc_dict["type"] = "img2img" + rfc_dict["strength"] = parameters["strength"] + rfc_dict["fit"] = parameters["fit"] # TODO: Noncompliant + rfc_dict["orig_hash"] = calculate_init_img_hash(parameters["init_img"]) + rfc_dict["init_image_path"] = parameters["init_img"] # TODO: Noncompliant + rfc_dict["sampler"] = "ddim" # TODO: FIX ME WHEN IMG2IMG SUPPORTS ALL SAMPLERS + if "init_mask" in parameters: + rfc_dict["mask_hash"] = calculate_init_img_hash( + parameters["init_mask"] + ) # TODO: Noncompliant + rfc_dict["mask_image_path"] = parameters["init_mask"] # TODO: Noncompliant + else: + rfc_dict["type"] = "txt2img" + + metadata["image"] = rfc_dict + + return metadata + + +def make_unique_init_image_filename(name): + uuid = uuid4().hex + split = os.path.splitext(name) + name = f"{split[0]}.{uuid}{split[1]}" + return name + + +def write_log_message(message, log_path=log_path): + """Logs the filename and parameters used to generate or process that image to log file""" + message = f"{message}\n" + with open(log_path, "a", encoding="utf-8") as file: + file.writelines(message) + + +def save_image( + image, command, metadata, output_dir, step_index=None, postprocessing=False +): + pngwriter = PngWriter(output_dir) + prefix = pngwriter.unique_prefix() + + seed = "unknown_seed" + + if "image" in metadata: + if "seed" in metadata["image"]: + seed = metadata["image"]["seed"] + + filename = f"{prefix}.{seed}" + + if step_index: + filename += f".{step_index}" + if postprocessing: + filename += f".postprocessed" + + filename += ".png" + + path = pngwriter.save_image_and_prompt_to_png( + image=image, dream_prompt=command, metadata=metadata, name=filename + ) + + return path + + +def calculate_real_steps(steps, strength, has_init_image): + return math.floor(strength * steps) if has_init_image else steps + + +def generate_images(generation_parameters, esrgan_parameters, gfpgan_parameters): + canceled.clear() + + step_index = 1 + prior_variations = ( + generation_parameters["with_variations"] + if "with_variations" in generation_parameters + else [] + ) + """ + If a result image is used as an init image, and then deleted, we will want to be + able to use it as an init image in the future. Need to copy it. + + If the init/mask image doesn't exist in the init_image_path/mask_image_path, + make a unique filename for it and copy it there. + """ + if "init_img" in generation_parameters: + filename = os.path.basename(generation_parameters["init_img"]) + if not os.path.exists(os.path.join(init_image_path, filename)): + unique_filename = make_unique_init_image_filename(filename) + new_path = os.path.join(init_image_path, unique_filename) + shutil.copy(generation_parameters["init_img"], new_path) + generation_parameters["init_img"] = new_path + if "init_mask" in generation_parameters: + filename = os.path.basename(generation_parameters["init_mask"]) + if not os.path.exists(os.path.join(mask_image_path, filename)): + unique_filename = make_unique_init_image_filename(filename) + new_path = os.path.join(init_image_path, unique_filename) + shutil.copy(generation_parameters["init_img"], new_path) + generation_parameters["init_mask"] = new_path + + totalSteps = calculate_real_steps( + steps=generation_parameters["steps"], + strength=generation_parameters["strength"] + if "strength" in generation_parameters + else None, + has_init_image="init_img" in generation_parameters, + ) + + progress = { + "currentStep": 1, + "totalSteps": totalSteps, + "currentIteration": 1, + "totalIterations": generation_parameters["iterations"], + "currentStatus": "Preparing", + "isProcessing": True, + "currentStatusHasSteps": False, + } + + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + def image_progress(sample, step): + if canceled.is_set(): + raise CanceledException + + nonlocal step_index + nonlocal generation_parameters + nonlocal progress + + progress["currentStep"] = step + 1 + progress["currentStatus"] = "Generating" + progress["currentStatusHasSteps"] = True + + if ( + generation_parameters["progress_images"] + and step % 5 == 0 + and step < generation_parameters["steps"] - 1 + ): + image = generate.sample_to_image(sample) + path = save_image( + image, generation_parameters, intermediate_path, step_index + ) + + step_index += 1 + socketio.emit( + "intermediateResult", + {"url": os.path.relpath(path), "metadata": generation_parameters}, + ) + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + def image_done(image, seed, first_seed): + nonlocal generation_parameters + nonlocal esrgan_parameters + nonlocal gfpgan_parameters + nonlocal progress + + step_index = 1 + nonlocal prior_variations + + progress["currentStatus"] = "Generation complete" + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + all_parameters = generation_parameters + postprocessing = False + + if ( + "variation_amount" in all_parameters + and all_parameters["variation_amount"] > 0 + ): + first_seed = first_seed or seed + this_variation = [[seed, all_parameters["variation_amount"]]] + all_parameters["with_variations"] = prior_variations + this_variation + + if esrgan_parameters: + progress["currentStatus"] = "Upscaling" + progress["currentStatusHasSteps"] = False + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + image = esrgan.process( + image=image, + upsampler_scale=esrgan_parameters["level"], + strength=esrgan_parameters["strength"], + seed=seed, + ) + + postprocessing = True + all_parameters["upscale"] = [ + esrgan_parameters["level"], + esrgan_parameters["strength"], + ] + + if gfpgan_parameters: + progress["currentStatus"] = "Fixing faces" + progress["currentStatusHasSteps"] = False + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + image = gfpgan.process( + image=image, strength=gfpgan_parameters["strength"], seed=seed + ) + postprocessing = True + all_parameters["gfpgan_strength"] = gfpgan_parameters["strength"] + + all_parameters["seed"] = first_seed + progress["currentStatus"] = "Saving image" + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + metadata = parameters_to_generated_image_metadata(all_parameters) + command = parameters_to_command(all_parameters) + + path = save_image( + image, command, metadata, result_path, postprocessing=postprocessing + ) + + print(f'>> Image generated: "{path}"') + write_log_message(f'[Generated] "{path}": {command}') + + if progress["totalIterations"] > progress["currentIteration"]: + progress["currentStep"] = 1 + progress["currentIteration"] += 1 + progress["currentStatus"] = "Iteration finished" + progress["currentStatusHasSteps"] = False + else: + progress["currentStep"] = 0 + progress["totalSteps"] = 0 + progress["currentIteration"] = 0 + progress["totalIterations"] = 0 + progress["currentStatus"] = "Finished" + progress["isProcessing"] = False + + socketio.emit("progressUpdate", progress) + eventlet.sleep(0) + + socketio.emit( + "generationResult", + {"url": os.path.relpath(path), "metadata": metadata}, + ) + eventlet.sleep(0) + + try: + generate.prompt2image( + **generation_parameters, + step_callback=image_progress, + image_callback=image_done, + ) + + except KeyboardInterrupt: + raise + except CanceledException: + pass + except Exception as e: + socketio.emit("error", {"message": (str(e))}) + print("\n") + traceback.print_exc() + print("\n") + + +""" +END ADDITIONAL FUNCTIONS +""" + + +if __name__ == "__main__": + print(f">> Starting server at http://{host}:{port}") + socketio.run(app, host=host, port=port) diff --git a/docker-build/Dockerfile b/docker-build/Dockerfile new file mode 100644 index 0000000000..f3d6834c93 --- /dev/null +++ b/docker-build/Dockerfile @@ -0,0 +1,57 @@ +FROM debian + +ARG gsd +ENV GITHUB_STABLE_DIFFUSION $gsd + +ARG rsd +ENV REQS $rsd + +ARG cs +ENV CONDA_SUBDIR $cs + +ENV PIP_EXISTS_ACTION="w" + +# TODO: Optimize image size + +SHELL ["/bin/bash", "-c"] + +WORKDIR / +RUN apt update && apt upgrade -y \ + && apt install -y \ + git \ + libgl1-mesa-glx \ + libglib2.0-0 \ + pip \ + python3 \ + && git clone $GITHUB_STABLE_DIFFUSION + +# Install Anaconda or Miniconda +COPY anaconda.sh . +RUN bash anaconda.sh -b -u -p /anaconda && /anaconda/bin/conda init bash + +# SD +WORKDIR /stable-diffusion +RUN source ~/.bashrc \ + && conda create -y --name ldm && conda activate ldm \ + && conda config --env --set subdir $CONDA_SUBDIR \ + && pip3 install -r $REQS \ + && pip3 install basicsr facexlib realesrgan \ + && mkdir models/ldm/stable-diffusion-v1 \ + && ln -s "/data/sd-v1-4.ckpt" models/ldm/stable-diffusion-v1/model.ckpt + +# Face restoreation +# by default expected in a sibling directory to stable-diffusion +WORKDIR / +RUN git clone https://github.com/TencentARC/GFPGAN.git + +WORKDIR /GFPGAN +RUN pip3 install -r requirements.txt \ + && python3 setup.py develop \ + && ln -s "/data/GFPGANv1.4.pth" experiments/pretrained_models/GFPGANv1.4.pth + +WORKDIR /stable-diffusion +RUN python3 scripts/preload_models.py + +WORKDIR / +COPY entrypoint.sh . +ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/docker-build/entrypoint.sh b/docker-build/entrypoint.sh new file mode 100755 index 0000000000..f47e6669e0 --- /dev/null +++ b/docker-build/entrypoint.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +cd /stable-diffusion + +if [ $# -eq 0 ]; then + python3 scripts/dream.py --full_precision -o /data + # bash +else + python3 scripts/dream.py --full_precision -o /data "$@" +fi \ No newline at end of file diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md deleted file mode 100644 index 31dc8e80db..0000000000 --- a/docs/CHANGELOG.md +++ /dev/null @@ -1,137 +0,0 @@ -# **Changelog** - -## v1.13 (in process) - -- Supports a Google Colab notebook for a standalone server running on Google hardware [Arturo Mendivil](https://github.com/artmen1516) -- WebUI supports GFPGAN/ESRGAN facial reconstruction and upscaling [Kevin Gibbons](https://github.com/bakkot) -- WebUI supports incremental display of in-progress images during generation [Kevin Gibbons](https://github.com/bakkot) -- Output directory can be specified on the dream> command line. -- The grid was displaying duplicated images when not enough images to fill the final row [Muhammad Usama](https://github.com/SMUsamaShah) -- Can specify --grid on dream.py command line as the default. -- Miscellaneous internal bug and stability fixes. - ---- - -## v1.12 (28 August 2022) - -- Improved file handling, including ability to read prompts from standard input. - (kudos to [Yunsaki](https://github.com/yunsaki) -- The web server is now integrated with the dream.py script. Invoke by adding --web to - the dream.py command arguments. -- Face restoration and upscaling via GFPGAN and Real-ESGAN are now automatically - enabled if the GFPGAN directory is located as a sibling to Stable Diffusion. - VRAM requirements are modestly reduced. Thanks to both [Blessedcoolant](https://github.com/blessedcoolant) and - [Oceanswave](https://github.com/oceanswave) for their work on this. -- You can now swap samplers on the dream> command line. [Blessedcoolant](https://github.com/blessedcoolant) - ---- - -## v1.11 (26 August 2022) - -- NEW FEATURE: Support upscaling and face enhancement using the GFPGAN module. (kudos to [Oceanswave](https://github.com/Oceanswave) -- You now can specify a seed of -1 to use the previous image's seed, -2 to use the seed for the image generated before that, etc. - Seed memory only extends back to the previous command, but will work on all images generated with the -n# switch. -- Variant generation support temporarily disabled pending more general solution. -- Created a feature branch named **yunsaki-morphing-dream** which adds experimental support for - iteratively modifying the prompt and its parameters. Please see[ Pull Request #86](https://github.com/lstein/stable-diffusion/pull/86) - for a synopsis of how this works. Note that when this feature is eventually added to the main branch, it will may be modified - significantly. - ---- - -## v1.10 (25 August 2022) - -- A barebones but fully functional interactive web server for online generation of txt2img and img2img. - ---- - -## v1.09 (24 August 2022) - -- A new -v option allows you to generate multiple variants of an initial image - in img2img mode. (kudos to [Oceanswave](https://github.com/Oceanswave). [ - See this discussion in the PR for examples and details on use](https://github.com/lstein/stable-diffusion/pull/71#issuecomment-1226700810)) -- Added ability to personalize text to image generation (kudos to [Oceanswave](https://github.com/Oceanswave) and [nicolai256](https://github.com/nicolai256)) -- Enabled all of the samplers from k_diffusion - ---- - -## v1.08 (24 August 2022) - -- Escape single quotes on the dream> command before trying to parse. This avoids - parse errors. -- Removed instruction to get Python3.8 as first step in Windows install. - Anaconda3 does it for you. -- Added bounds checks for numeric arguments that could cause crashes. -- Cleaned up the copyright and license agreement files. - ---- - -## v1.07 (23 August 2022) - -- Image filenames will now never fill gaps in the sequence, but will be assigned the - next higher name in the chosen directory. This ensures that the alphabetic and chronological - sort orders are the same. - ---- - -## v1.06 (23 August 2022) - -- Added weighted prompt support contributed by [xraxra](https://github.com/xraxra) -- Example of using weighted prompts to tweak a demonic figure contributed by [bmaltais](https://github.com/bmaltais) - ---- - -## v1.05 (22 August 2022 - after the drop) - -- Filenames now use the following formats: - 000010.95183149.png -- Two files produced by the same command (e.g. -n2), - 000010.26742632.png -- distinguished by a different seed. - - 000011.455191342.01.png -- Two files produced by the same command using - 000011.455191342.02.png -- a batch size>1 (e.g. -b2). They have the same seed. - - 000011.4160627868.grid#1-4.png -- a grid of four images (-g); the whole grid can - be regenerated with the indicated key - -- It should no longer be possible for one image to overwrite another -- You can use the "cd" and "pwd" commands at the dream> prompt to set and retrieve - the path of the output directory. - ---- - -## v1.04 (22 August 2022 - after the drop) - -- Updated README to reflect installation of the released weights. -- Suppressed very noisy and inconsequential warning when loading the frozen CLIP - tokenizer. - ---- - -## v1.03 (22 August 2022) - -- The original txt2img and img2img scripts from the CompViz repository have been moved into - a subfolder named "orig_scripts", to reduce confusion. - ---- - -## v1.02 (21 August 2022) - -- A copy of the prompt and all of its switches and options is now stored in the corresponding - image in a tEXt metadata field named "Dream". You can read the prompt using scripts/images2prompt.py, - or an image editor that allows you to explore the full metadata. - **Please run "conda env update -f environment.yaml" to load the k_lms dependencies!!** - ---- - -## v1.01 (21 August 2022) - -- added k_lms sampling. - **Please run "conda env update -f environment.yaml" to load the k_lms dependencies!!** -- use half precision arithmetic by default, resulting in faster execution and lower memory requirements - Pass argument --full_precision to dream.py to get slower but more accurate image generation - ---- - -## Links - -- **[Read Me](../readme.md)** diff --git a/docs/assets/join-us-on-discord-image.png b/docs/assets/join-us-on-discord-image.png new file mode 100644 index 0000000000..53e4ee0fe0 Binary files /dev/null and b/docs/assets/join-us-on-discord-image.png differ diff --git a/docs/assets/logo.png b/docs/assets/logo.png index fa0548ff78..b6eb33a6db 100644 Binary files a/docs/assets/logo.png and b/docs/assets/logo.png differ diff --git a/docs/assets/negative_prompt_walkthru/step1.png b/docs/assets/negative_prompt_walkthru/step1.png new file mode 100644 index 0000000000..6f94d7d035 Binary files /dev/null and b/docs/assets/negative_prompt_walkthru/step1.png differ diff --git a/docs/assets/negative_prompt_walkthru/step2.png b/docs/assets/negative_prompt_walkthru/step2.png new file mode 100644 index 0000000000..0ff90eca3c Binary files /dev/null and b/docs/assets/negative_prompt_walkthru/step2.png differ diff --git a/docs/assets/negative_prompt_walkthru/step3.png b/docs/assets/negative_prompt_walkthru/step3.png new file mode 100644 index 0000000000..f6676de386 Binary files /dev/null and b/docs/assets/negative_prompt_walkthru/step3.png differ diff --git a/docs/assets/negative_prompt_walkthru/step4.png b/docs/assets/negative_prompt_walkthru/step4.png new file mode 100644 index 0000000000..2e73532629 Binary files /dev/null and b/docs/assets/negative_prompt_walkthru/step4.png differ diff --git a/docs/assets/outpainting/elven_princess.outpainted.png b/docs/assets/outpainting/elven_princess.outpainted.png new file mode 100644 index 0000000000..98f98564df Binary files /dev/null and b/docs/assets/outpainting/elven_princess.outpainted.png differ diff --git a/docs/assets/outpainting/elven_princess.png b/docs/assets/outpainting/elven_princess.png new file mode 100644 index 0000000000..aa5f00ccf7 Binary files /dev/null and b/docs/assets/outpainting/elven_princess.png differ diff --git a/assets/stable-samples/img2img/mountains-2.png b/docs/assets/stable-samples/img2img/mountains-2.png similarity index 100% rename from assets/stable-samples/img2img/mountains-2.png rename to docs/assets/stable-samples/img2img/mountains-2.png diff --git a/assets/stable-samples/img2img/mountains-3.png b/docs/assets/stable-samples/img2img/mountains-3.png similarity index 100% rename from assets/stable-samples/img2img/mountains-3.png rename to docs/assets/stable-samples/img2img/mountains-3.png diff --git a/assets/stable-samples/img2img/sketch-mountains-input.jpg b/docs/assets/stable-samples/img2img/sketch-mountains-input.jpg similarity index 100% rename from assets/stable-samples/img2img/sketch-mountains-input.jpg rename to docs/assets/stable-samples/img2img/sketch-mountains-input.jpg diff --git a/assets/stable-samples/txt2img/merged-0005.png b/docs/assets/stable-samples/txt2img/merged-0005.png similarity index 100% rename from assets/stable-samples/txt2img/merged-0005.png rename to docs/assets/stable-samples/txt2img/merged-0005.png diff --git a/assets/stable-samples/txt2img/merged-0006.png b/docs/assets/stable-samples/txt2img/merged-0006.png similarity index 100% rename from assets/stable-samples/txt2img/merged-0006.png rename to docs/assets/stable-samples/txt2img/merged-0006.png diff --git a/assets/stable-samples/txt2img/merged-0007.png b/docs/assets/stable-samples/txt2img/merged-0007.png similarity index 100% rename from assets/stable-samples/txt2img/merged-0007.png rename to docs/assets/stable-samples/txt2img/merged-0007.png diff --git a/assets/v1-variants-scores.jpg b/docs/assets/v1-variants-scores.jpg similarity index 100% rename from assets/v1-variants-scores.jpg rename to docs/assets/v1-variants-scores.jpg diff --git a/docs/features/CHANGELOG.md b/docs/features/CHANGELOG.md new file mode 100644 index 0000000000..a6258f6a56 --- /dev/null +++ b/docs/features/CHANGELOG.md @@ -0,0 +1,143 @@ +--- +title: Changelog +--- + +# :octicons-log-16: Changelog + +## v1.13 (in process) + +- Supports a Google Colab notebook for a standalone server running on Google + hardware [Arturo Mendivil](https://github.com/artmen1516) +- WebUI supports GFPGAN/ESRGAN facial reconstruction and upscaling + [Kevin Gibbons](https://github.com/bakkot) +- WebUI supports incremental display of in-progress images during generation + [Kevin Gibbons](https://github.com/bakkot) +- Output directory can be specified on the dream> command line. +- The grid was displaying duplicated images when not enough images to fill the + final row [Muhammad Usama](https://github.com/SMUsamaShah) +- Can specify --grid on dream.py command line as the default. +- Miscellaneous internal bug and stability fixes. + +--- + +## v1.12 (28 August 2022) + +- Improved file handling, including ability to read prompts from standard input. + (kudos to [Yunsaki](https://github.com/yunsaki) +- The web server is now integrated with the dream.py script. Invoke by adding + --web to the dream.py command arguments. +- Face restoration and upscaling via GFPGAN and Real-ESGAN are now automatically + enabled if the GFPGAN directory is located as a sibling to Stable Diffusion. + VRAM requirements are modestly reduced. Thanks to both + [Blessedcoolant](https://github.com/blessedcoolant) and + [Oceanswave](https://github.com/oceanswave) for their work on this. +- You can now swap samplers on the dream> command line. + [Blessedcoolant](https://github.com/blessedcoolant) + +--- + +## v1.11 (26 August 2022) + +- NEW FEATURE: Support upscaling and face enhancement using the GFPGAN module. + (kudos to [Oceanswave](https://github.com/Oceanswave)) +- You now can specify a seed of -1 to use the previous image's seed, -2 to use + the seed for the image generated before that, etc. Seed memory only extends + back to the previous command, but will work on all images generated with the + -n# switch. +- Variant generation support temporarily disabled pending more general solution. +- Created a feature branch named **yunsaki-morphing-dream** which adds + experimental support for iteratively modifying the prompt and its parameters. + Please + see[ Pull Request #86](https://github.com/lstein/stable-diffusion/pull/86) for + a synopsis of how this works. Note that when this feature is eventually added + to the main branch, it will may be modified significantly. + +--- + +## v1.10 (25 August 2022) + +- A barebones but fully functional interactive web server for online generation + of txt2img and img2img. + +--- + +## v1.09 (24 August 2022) + +- A new -v option allows you to generate multiple variants of an initial image + in img2img mode. (kudos to [Oceanswave](https://github.com/Oceanswave). +- [See this discussion in the PR for examples and details on use](https://github.com/lstein/stable-diffusion/pull/71#issuecomment-1226700810)) +- Added ability to personalize text to image generation (kudos to + [Oceanswave](https://github.com/Oceanswave) and + [nicolai256](https://github.com/nicolai256)) +- Enabled all of the samplers from k_diffusion + +--- + +## v1.08 (24 August 2022) + +- Escape single quotes on the dream> command before trying to parse. This avoids + parse errors. +- Removed instruction to get Python3.8 as first step in Windows install. + Anaconda3 does it for you. +- Added bounds checks for numeric arguments that could cause crashes. +- Cleaned up the copyright and license agreement files. + +--- + +## v1.07 (23 August 2022) + +- Image filenames will now never fill gaps in the sequence, but will be assigned + the next higher name in the chosen directory. This ensures that the alphabetic + and chronological sort orders are the same. + +--- + +## v1.06 (23 August 2022) + +- Added weighted prompt support contributed by + [xraxra](https://github.com/xraxra) +- Example of using weighted prompts to tweak a demonic figure contributed by + [bmaltais](https://github.com/bmaltais) + +--- + +## v1.05 (22 August 2022 - after the drop) + +- Filenames now use the following formats: 000010.95183149.png -- Two files + produced by the same command (e.g. -n2), 000010.26742632.png -- distinguished + by a different seed. + 000011.455191342.01.png -- Two files produced by the same command using + 000011.455191342.02.png -- a batch size>1 (e.g. -b2). They have the same seed. + 000011.4160627868.grid#1-4.png -- a grid of four images (-g); the whole grid + can be regenerated with the indicated key + +- It should no longer be possible for one image to overwrite another +- You can use the "cd" and "pwd" commands at the dream> prompt to set and + retrieve the path of the output directory. + +## v1.04 (22 August 2022 - after the drop) + +- Updated README to reflect installation of the released weights. +- Suppressed very noisy and inconsequential warning when loading the frozen CLIP + tokenizer. + +## v1.03 (22 August 2022) + +- The original txt2img and img2img scripts from the CompViz repository have been + moved into a subfolder named "orig_scripts", to reduce confusion. + +## v1.02 (21 August 2022) + +- A copy of the prompt and all of its switches and options is now stored in the + corresponding image in a tEXt metadata field named "Dream". You can read the + prompt using scripts/images2prompt.py, or an image editor that allows you to + explore the full metadata. **Please run "conda env update -f environment.yaml" + to load the k_lms dependencies!!** + +## v1.01 (21 August 2022) + +- added k_lms sampling. **Please run "conda env update -f environment.yaml" to + load the k_lms dependencies!!** +- use half precision arithmetic by default, resulting in faster execution and + lower memory requirements Pass argument --full_precision to dream.py to get + slower but more accurate image generation diff --git a/docs/features/CLI.md b/docs/features/CLI.md index d809d48841..1cbdbf21cb 100644 --- a/docs/features/CLI.md +++ b/docs/features/CLI.md @@ -1,19 +1,39 @@ -# **Interactive Command-Line Interface** +--- +title: CLI +hide: + - toc +--- -The `dream.py` script, located in `scripts/dream.py`, provides an interactive interface to image generation similar to the "dream mothership" bot that Stable AI provided on its Discord server. +# :material-bash: CLI -Unlike the txt2img.py and img2img.py scripts provided in the original CompViz/stable-diffusion source code repository, the time-consuming initialization of the AI model initialization only happens once. After that image generation -from the command-line interface is very fast. +## **Interactive Command Line Interface** -The script uses the readline library to allow for in-line editing, command history (up and down arrows), autocompletion, and more. To help keep track of which prompts generated which images, the script writes a log file of image names and prompts to the selected output directory. +The `dream.py` script, located in `scripts/dream.py`, provides an interactive +interface to image generation similar to the "dream mothership" bot that Stable +AI provided on its Discord server. -In addition, as of version 1.02, it also writes the prompt into the PNG file's metadata where it can be retrieved using scripts/images2prompt.py +Unlike the `txt2img.py` and `img2img.py` scripts provided in the original +[CompVis/stable-diffusion](https://github.com/CompVis/stable-diffusion) source +code repository, the time-consuming initialization of the AI model +initialization only happens once. After that image generation from the +command-line interface is very fast. + +The script uses the readline library to allow for in-line editing, command +history (++up++ and ++down++), autocompletion, and more. To help keep track of +which prompts generated which images, the script writes a log file of image +names and prompts to the selected output directory. + +In addition, as of version 1.02, it also writes the prompt into the PNG file's +metadata where it can be retrieved using `scripts/images2prompt.py` The script is confirmed to work on Linux, Windows and Mac systems. -_Note:_ This script runs from the command-line or can be used as a Web application. The Web GUI is currently rudimentary, but a much better replacement is on its way. +!!! note -``` + This script runs from the command-line or can be used as a Web application. The Web GUI is + currently rudimentary, but a much better replacement is on its way. + +```bash (ldm) ~/stable-diffusion$ python3 ./scripts/dream.py * Initializing, be patient... Loading model from models/ldm/text2img-large/model.ckpt @@ -37,192 +57,207 @@ dream> q 00011.png: "there's a fly in my soup" -n6 -g -S 2685670268 ``` -

- -

+![dream-py-demo](../assets/dream-py-demo.png) -The `dream>` prompt's arguments are pretty much identical to those -used in the Discord bot, except you don't need to type "!dream" (it -doesn't hurt if you do). A significant change is that creation of -individual images is now the default unless --grid (-g) is given. A -full list is given in [List of prompt arguments] -(#list-of-prompt-arguments). +The `dream>` prompt's arguments are pretty much identical to those used in the +Discord bot, except you don't need to type "!dream" (it doesn't hurt if you do). +A significant change is that creation of individual images is now the default +unless `--grid` (`-g`) is given. A full list is given in +[List of prompt arguments](#list-of-prompt-arguments). -# Arguments +## Arguments -The script itself also recognizes a series of command-line switches -that will change important global defaults, such as the directory for -image outputs and the location of the model weight files. +The script itself also recognizes a series of command-line switches that will +change important global defaults, such as the directory for image outputs and +the location of the model weight files. -## List of arguments recognized at the command line: +### List of arguments recognized at the command line -These command-line arguments can be passed to dream.py when you first -run it from the Windows, Mac or Linux command line. Some set defaults -that can be overridden on a per-prompt basis (see [List of prompt -arguments] (#list-of-prompt-arguments). Others +These command-line arguments can be passed to `dream.py` when you first run it +from the Windows, Mac or Linux command line. Some set defaults that can be +overridden on a per-prompt basis (see [List of prompt arguments] +(#list-of-prompt-arguments). Others -| Argument | Shortcut | Default | Description | -|--------------------|------------|---------------------|--------------| -| --help | -h | | Print a concise help message. | -| --outdir | -o | outputs/img_samples | Location for generated images. | -| --prompt_as_dir | -p | False | Name output directories using the prompt text. | -| --from_file | | None | Read list of prompts from a file. Use "-" to read from standard input | -| --model | | stable-diffusion-1.4| Loads model specified in configs/models.yaml. Currently one of "stable-diffusion-1.4" or "laion400m"| -| --full_precision | -F | False | Run in slower full-precision mode. Needed for Macintosh M1/M2 hardware and some older video cards. | -| --web | | False | Start in web server mode | -| --host | | localhost | Which network interface web server should listen on. Set to 0.0.0.0 to listen on any. | -| --port | | 9090 | Which port web server should listen for requests on. | -| --config | | configs/models.yaml | Configuration file for models and their weights. | -| --iterations | -n | 1 | How many images to generate per prompt. | -| --grid | -g | False | Save all image series as a grid rather than individually. | -| --sampler | -A| k_lms | Sampler to use. Use -h to get list of available samplers. | -| --seamless | | False | Create interesting effects by tiling elements of the image. | -| --embedding_path | | None | Path to pre-trained embedding manager checkpoints, for custom models | -| --gfpgan_dir | | src/gfpgan | Path to where GFPGAN is installed. | -| --gfpgan_model_path| | experiments/pretrained_models/GFPGANv1.3.pth| Path to GFPGAN model file, relative to --gfpgan_dir. | -| --device | -d| torch.cuda.current_device() | Device to run SD on, e.g. "cuda:0" | +| Argument | Shortcut | Default | Description | +| ----------------------------------------- | ----------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------- | +| `--help` | `-h` | | Print a concise help message. | +| `--outdir ` | `-o` | `outputs/img_samples` | Location for generated images. | +| `--prompt_as_dir` | `-p` | `False` | Name output directories using the prompt text. | +| `--from_file ` | | `None` | Read list of prompts from a file. Use `-` to read from standard input | +| `--model ` | | `stable-diffusion-1.4` | Loads model specified in configs/models.yaml. Currently one of "stable-diffusion-1.4" or "laion400m" | +| `--full_precision` | `-F` | `False` | Run in slower full-precision mode. Needed for Macintosh M1/M2 hardware and some older video cards. | +| `--web` | | `False` | Start in web server mode | +| `--host ` | | `localhost` | Which network interface web server should listen on. Set to 0.0.0.0 to listen on any. | +| `--port ` | | `9090` | Which port web server should listen for requests on. | +| `--config ` | | `configs/models.yaml` | Configuration file for models and their weights. | +| `--iterations ` | `-n` | `1` | How many images to generate per prompt. | +| `--grid` | `-g` | `False` | Save all image series as a grid rather than individually. | +| `--sampler ` | `-A` | `k_lms` | Sampler to use. Use `-h` to get list of available samplers. | +| `--seamless` | | `False` | Create interesting effects by tiling elements of the image. | +| `--embedding_path ` | | `None` | Path to pre-trained embedding manager checkpoints, for custom models | +| `--gfpgan_dir` | | `src/gfpgan` | Path to where GFPGAN is installed. | +| `--gfpgan_model_path` | | `experiments/pretrained_models/GFPGANv1.4.pth` | Path to GFPGAN model file, relative to `--gfpgan_dir`. | +| `--device ` | `-d` | `torch.cuda.current_device()` | Device to run SD on, e.g. "cuda:0" | + +#### deprecated These arguments are deprecated but still work: -| Argument | Shortcut | Default | Description | -|--------------------|------------|---------------------|--------------| -| --weights | | None | Pth to weights file; use `--model stable-diffusion-1.4` instead | -| --laion400m | -l | False | Use older LAION400m weights; use `--model=laion400m` instead | +
-**A note on path names:** On Windows systems, you may run into - problems when passing the dream script standard backslashed path - names because the Python interpreter treats "\" as an escape. - You can either double your slashes (ick): C:\\\\path\\\\to\\\\my\\\\file, or - use Linux/Mac style forward slashes (better): C:/path/to/my/file. +| Argument | Shortcut | Default | Description | +| ------------------ | -------- | ------- | --------------------------------------------------------------- | +| `--weights ` | | `None` | Pth to weights file; use `--model stable-diffusion-1.4` instead | +| `--laion400m` | `-l` | `False` | Use older LAION400m weights; use `--model=laion400m` instead | -## List of prompt arguments +
-After the dream.py script initializes, it will present you with a -**dream>** prompt. Here you can enter information to generate images -from text (txt2img), to embellish an existing image or sketch -(img2img), or to selectively alter chosen regions of the image -(inpainting). +!!! note -### This is an example of txt2img: + On Windows systems, you may run into problems when passing the dream script standard backslashed + path names because the Python interpreter treats `\` as an escape. You can either double your + slashes (ick): `C:\\path\\to\\my\\file`, or use Linux/Mac style forward slashes (better): + `C:/path/to/my/file`. -~~~~ -dream> waterfall and rainbow -W640 -H480 -~~~~ +### List of prompt arguments -This will create the requested image with the dimensions 640 (width) -and 480 (height). +After the `dream.py` script initializes, it will present you with a **`dream>`** +prompt. Here you can enter information to generate images from text (txt2img), +to embellish an existing image or sketch (img2img), or to selectively alter +chosen regions of the image (inpainting). -Here are the dream> command that apply to txt2img: +#### txt2img -| Argument | Shortcut | Default | Description | -|--------------------|------------|---------------------|--------------| -| "my prompt" | | | Text prompt to use. The quotation marks are optional. | -| --width | -W | 512 | Width of generated image | -| --height | -H | 512 | Height of generated image | -| --iterations | -n | 1 | How many images to generate from this prompt | -| --steps | -s | 50 | How many steps of refinement to apply | -| --cfg_scale | -C | 7.5 | How hard to try to match the prompt to the generated image; any number greater than 0.0 works, but the useful range is roughly 5.0 to 20.0 | -| --seed | -S | None | Set the random seed for the next series of images. This can be used to recreate an image generated previously.| -| --sampler | -A| k_lms | Sampler to use. Use -h to get list of available samplers. | -| --grid | -g | False | Turn on grid mode to return a single image combining all the images generated by this prompt | -| --individual | -i | True | Turn off grid mode (deprecated; leave off --grid instead) | -| --outdir | -o | outputs/img_samples | Temporarily change the location of these images | -| --seamless | | False | Activate seamless tiling for interesting effects | -| --log_tokenization | -t | False | Display a color-coded list of the parsed tokens derived from the prompt | -| --skip_normalization| -x | False | Weighted subprompts will not be normalized. See [Weighted Prompts](./OTHER.md#weighted-prompts) | -| --upscale | -U | -U 1 0.75| Upscale image by magnification factor (2, 4), and set strength of upscaling (0.0-1.0). If strength not set, will default to 0.75. | -| --gfpgan_strength | -G | -G0 | Fix faces using the GFPGAN algorithm; argument indicates how hard the algorithm should try (0.0-1.0) | -| --save_original | -save_orig| False | When upscaling or fixing faces, this will cause the original image to be saved rather than replaced. | -| --variation |-v| 0.0 | Add a bit of noise (0.0=none, 1.0=high) to the image in order to generate a series of variations. Usually used in combination with -S and -n to generate a series a riffs on a starting image. See [Variations](./VARIATIONS.md). | -| --with_variations | -V| None | Combine two or more variations. See [Variations](./VARIATIONS.md) for now to use this. | +!!! example -Note that the width and height of the image must be multiples of -64. You can provide different values, but they will be rounded down to -the nearest multiple of 64. + ```bash + dream> "waterfall and rainbow" -W640 -H480 + ``` + This will create the requested image with the dimensions 640 (width) and 480 (height). -### This is an example of img2img: +Those are the `dream` commands that apply to txt2img: -~~~~ -dream> waterfall and rainbow -I./vacation-photo.png -W640 -H480 --fit -~~~~ +| Argument | Shortcut | Default | Description | +| ----------------------------------------- | ----------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `"my prompt"` | | | Text prompt to use. The quotation marks are optional. | +| `--width ` | `-W` | `512` | Width of generated image | +| `--height ` | `-H` | `512` | Height of generated image | +| `--iterations ` | `-n` | `1` | How many images to generate from this prompt | +| `--steps ` | `-s` | `50` | How many steps of refinement to apply | +| `--cfg_scale ` | `-C` | `7.5` | How hard to try to match the prompt to the generated image; any number greater than 0.0 works, but the useful range is roughly 5.0 to 20.0 | +| `--seed ` | `-S` | `None` | Set the random seed for the next series of images. This can be used to recreate an image generated previously. | +| `--sampler ` | `-A` | `k_lms` | Sampler to use. Use `-h` to get list of available samplers. | +| `--grid` | `-g` | `False` | Turn on grid mode to return a single image combining all the images generated by this prompt | +| `--individual` | `-i` | `True` | Turn off grid mode (deprecated; leave off `--grid` instead) | +| `--outdir ` | `-o` | `outputs/img_samples` | Temporarily change the location of these images | +| `--seamless` | | `False` | Activate seamless tiling for interesting effects | +| `--log_tokenization` | `-t` | `False` | Display a color-coded list of the parsed tokens derived from the prompt | +| `--skip_normalization` | `-x` | `False` | Weighted subprompts will not be normalized. See [Weighted Prompts](./OTHER.md#weighted-prompts) | +| `--upscale ` | `-U ` | `-U 1 0.75` | Upscale image by magnification factor (2, 4), and set strength of upscaling (0.0-1.0). If strength not set, will default to 0.75. | +| `--gfpgan_strength ` | `-G ` | `-G0` | Fix faces using the GFPGAN algorithm; argument indicates how hard the algorithm should try (0.0-1.0) | +| `--save_original` | `-save_orig` | `False` | When upscaling or fixing faces, this will cause the original image to be saved rather than replaced. | +| `--variation ` | `-v` | `0.0` | Add a bit of noise (0.0=none, 1.0=high) to the image in order to generate a series of variations. Usually used in combination with `-S` and `-n` to generate a series a riffs on a starting image. See [Variations](./VARIATIONS.md). | +| `--with_variations ` | `-V` | `None` | Combine two or more variations. See [Variations](./VARIATIONS.md) for now to use this. | -This will modify the indicated vacation photograph by making it more -like the prompt. Results will vary greatly depending on what is in the -image. We also ask to --fit the image into a box no bigger than -640x480. Otherwise the image size will be identical to the provided -photo and you may run out of memory if it is large. +!!! note -In addition to the command-line options recognized by txt2img, img2img -accepts additional options: + The width and height of the image must be multiples of 64. You can provide different + values, but they will be rounded down to the nearest multiple of 64. -| Argument | Shortcut | Default | Description | -|--------------------|------------|---------------------|--------------| -| --init_img | -I | None | Path to the initialization image | -| --fit | -F | False | Scale the image to fit into the specified -H and -W dimensions | -| --strength | -s | 0.75 | How hard to try to match the prompt to the initial image. Ranges from 0.0-0.99, with higher values replacing the initial image completely.| +#### img2img -### This is an example of inpainting: +!!! example -~~~~ -dream> waterfall and rainbow -I./vacation-photo.png -M./vacation-mask.png -W640 -H480 --fit -~~~~ + ```bash + dream> "waterfall and rainbow" -I./vacation-photo.png -W640 -H480 --fit + ``` -This will do the same thing as img2img, but image alterations will -only occur within transparent areas defined by the mask file specified -by -M. You may also supply just a single initial image with the areas -to overpaint made transparent, but you must be careful not to destroy -the pixels underneath when you create the transparent areas. See -[Inpainting](./INPAINTING.md) for details. + This will modify the indicated vacation photograph by making it more like the prompt. Results will + vary greatly depending on what is in the image. We also ask to --fit the image into a box no bigger + than 640x480. Otherwise the image size will be identical to the provided photo and you may run out + of memory if it is large. -inpainting accepts all the arguments used for txt2img and img2img, as -well as the --mask (-M) argument: +Repeated chaining of img2img on an image can result in significant color shifts +in the output, especially if run with lower strength. Color correction can be +run against a reference image to fix this issue. Use the original input image to +the chain as the the reference image for each step in the chain. -| Argument | Shortcut | Default | Description | -|--------------------|------------|---------------------|--------------| -| --init_mask | -M | None |Path to an image the same size as the initial_image, with areas for inpainting made transparent.| +In addition to the command-line options recognized by txt2img, img2img accepts +additional options: +| Argument | Shortcut | Default | Description | +| ----------------------------------------- | ----------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| `--init_img ` | `-I` | `None` | Path to the initialization image | +| `--init_color ` | | `None` | Path to reference image for color correction | +| `--fit` | `-F` | `False` | Scale the image to fit into the specified -H and -W dimensions | +| `--strength ` | `-f` | `0.75` | How hard to try to match the prompt to the initial image. Ranges from 0.0-0.99, with higher values replacing the initial image completely. | -# Command-line editing and completion +#### Inpainting -If you are on a Macintosh or Linux machine, the command-line offers -convenient history tracking, editing, and command completion. +!!! example -- To scroll through previous commands and potentially edit/reuse them, use the up and down cursor keys. -- To edit the current command, use the left and right cursor keys to position the cursor, and then backspace, delete or insert characters. -- To move to the very beginning of the command, type CTRL-A (or command-A on the Mac) -- To move to the end of the command, type CTRL-E. -- To cut a section of the command, position the cursor where you want to start cutting and type CTRL-K. -- To paste a cut section back in, position the cursor where you want to paste, and type CTRL-Y + ```bash + dream> "waterfall and rainbow" -I./vacation-photo.png -M./vacation-mask.png -W640 -H480 --fit + ``` -Windows users can get similar, but more limited, functionality if they -launch dream.py with the "winpty" program: + This will do the same thing as img2img, but image alterations will only occur within transparent + areas defined by the mask file specified by `-M`. You may also supply just a single initial image with + the areas to overpaint made transparent, but you must be careful not to destroy the pixels + underneath when you create the transparent areas. See [Inpainting](./INPAINTING.md) for details. -~~~ -> winpty python scripts\dream.py -~~~ +Inpainting accepts all the arguments used for txt2img and img2img, as well as +the `--mask` (`-M`) argument: -On the Mac and Linux platforms, when you exit dream.py, the last 1000 -lines of your command-line history will be saved. When you restart -dream.py, you can access the saved history using the up-arrow key. +| Argument | Shortcut | Default | Description | +| ----------------------------------------- | ---------- | ------- | ------------------------------------------------------------------------------------------------ | +| `--init_mask ` | `-M` | `None` | Path to an image the same size as the initial_image, with areas for inpainting made transparent. | -In addition, limited command-line completion is installed. In various -contexts, you can start typing your command and press tab. A list of -potential completions will be presented to you. You can then type a -little more, hit tab again, and eventually autocomplete what you want. +## Command-line editing and completion -When specifying file paths using the one-letter shortcuts, the CLI -will attempt to complete pathnames for you. This is most handy for the --I (init image) and -M (init mask) paths. To initiate completion, start -the path with a slash ("/") or "./". For example: +If you are on a Macintosh or Linux machine, the command-line offers convenient +history tracking, editing, and command completion. -~~~ -dream> zebra with a mustache -I./test-pictures +- To scroll through previous commands and potentially edit/reuse them, use the + ++up++ and ++down++ cursor keys. +- To edit the current command, use the ++left++ and ++right++ cursor keys to + position the cursor, and then ++backspace++, ++delete++ or ++insert++ + characters. +- To move to the very beginning of the command, type ++ctrl+a++ (or + ++command+a++ on the Mac) +- To move to the end of the command, type ++ctrl+e++. +- To cut a section of the command, position the cursor where you want to start + cutting and type ++ctrl+k++. +- To paste a cut section back in, position the cursor where you want to paste, + and type ++ctrl+y++ + +Windows users can get similar, but more limited, functionality if they launch +`dream.py` with the "winpty" program: + +```batch +winpty python scripts\dream.py +``` + +On the Mac and Linux platforms, when you exit `dream.py`, the last 1000 lines of +your command-line history will be saved. When you restart `dream.py`, you can +access the saved history using the ++up++ key. + +In addition, limited command-line completion is installed. In various contexts, +you can start typing your command and press tab. A list of potential completions +will be presented to you. You can then type a little more, hit tab again, and +eventually autocomplete what you want. + +When specifying file paths using the one-letter shortcuts, the CLI will attempt +to complete pathnames for you. This is most handy for the `-I` (init image) and +`-M` (init mask) paths. To initiate completion, start the path with a slash `/` +or `./`, for example: + +```bash +dream> "zebra with a mustache" -I./test-pictures -I./test-pictures/Lincoln-and-Parrot.png -I./test-pictures/zebra.jpg -I./test-pictures/madonna.png -I./test-pictures/bad-sketch.png -I./test-pictures/man_with_eagle/ -~~~ +``` -You can then type "z", hit tab again, and it will autofill to "zebra.jpg". +You can then type ++z++, hit ++tab++ again, and it will autofill to `zebra.jpg`. More text completion features (such as autocompleting seeds) are on their way. - diff --git a/docs/features/EMBIGGEN.md b/docs/features/EMBIGGEN.md new file mode 100644 index 0000000000..92b379b64b --- /dev/null +++ b/docs/features/EMBIGGEN.md @@ -0,0 +1,154 @@ +--- +title: Embiggen +--- + +# :material-loupe: Embiggen + +**upscale your images on limited memory machines** + +GFPGAN and Real-ESRGAN are both memory intensive. In order to avoid +crashes and memory overloads during the Stable Diffusion process, +these effects are applied after Stable Diffusion has completed its +work. + +In single image generations, you will see the output right away but +when you are using multiple iterations, the images will first be +generated and then upscaled and face restored after that process is +complete. While the image generation is taking place, you will still +be able to preview the base images. + +If you wish to stop during the image generation but want to upscale or +face restore a particular generated image, pass it again with the same +prompt and generated seed along with the `-U` and `-G` prompt +arguments to perform those actions. + +## Embiggen + +If you wanted to be able to do more (pixels) without running out of VRAM, +or you want to upscale with details that couldn't possibly appear +without the context of a prompt, this is the feature to try out. + +Embiggen automates the process of taking an init image, upscaling it, +cutting it into smaller tiles that slightly overlap, running all the +tiles through img2img to refine details with respect to the prompt, +and "stitching" the tiles back together into a cohesive image. + +It automatically computes how many tiles are needed, and so it can be fed +*ANY* size init image and perform Img2Img on it (though it will be run only +one tile at a time, which can cause problems, see the Note at the end). + +If you're familiar with "GoBig" (ala [progrock-stable](https://github.com/lowfuel/progrock-stable)) +it's similar to that, except it can work up to an arbitrarily large size +(instead of just 2x), with tile overlaps configurable as a ratio, and +has extra logic to re-run any number of the tile sub-sections of the image +if for example a small part of a huge run got messed up. + +## Usage + +`-embiggen ` + +Takes a scaling factor relative to the size of the `--init_img` (`-I`), followed by +ESRGAN upscaling strength (0 - 1.0), followed by minimum amount of overlap +between tiles as a decimal ratio (0 - 1.0) *OR* a number of pixels. + +The scaling factor is how much larger than the `--init_img` the output +should be, and will multiply both x and y axis, so an image that is a +scaling factor of 3.0 has 3*3= 9 times as many pixels, and will take +(at least) 9 times as long (see overlap for why it might be +longer). If the `--init_img` is already the right size `-embiggen 1`, +and it can also be less than one if the init_img is too big. + +Esrgan_strength defaults to 0.75, and the overlap_ratio defaults to +0.25, both are optional. + +Unlike Img2Img, the `--width` (`-W`) and `--height` (`-H`) arguments +do not control the size of the image as a whole, but the size of the +tiles used to Embiggen the image. + +ESRGAN is used to upscale the `--init_img` prior to cutting it into +tiles/pieces to run through img2img and then stitch back +together. Embiggen can be run without ESRGAN; just set the strength to +zero (e.g. `-embiggen 1.75 0`). The output of Embiggen can also be +upscaled after it's finished (`-U`). + +The overlap is the minimum that tiles will overlap with adjacent +tiles, specified as either a ratio or a number of pixels. How much the +tiles overlap determines the likelihood the tiling will be noticable, +really small overlaps (e.g. a couple of pixels) may produce noticeable +grid-like fuzzy distortions in the final stitched image. Though, as +the overlapping space doesn't contribute to making the image bigger, +and the larger the overlap the more tiles (and the more time) it will +take to finish. + +Because the overlapping parts of tiles don't "contribute" to +increasing size, every tile after the first in a row or column +effectively only covers an extra `1 - overlap_ratio` on each axis. If +the input/`--init_img` is same size as a tile, the ideal (for time) +scaling factors with the default overlap (0.25) are 1.75, 2.5, 3.25, +4.0 etc.. + +`-embiggen_tiles ` + +An advanced usage useful if you only want to alter parts of the image +while running Embiggen. It takes a list of tiles by number to run and +replace onto the initial image e.g. `1 3 5`. It's useful for either +fixing problem spots from a previous Embiggen run, or selectively +altering the prompt for sections of an image - for creative or +coherency reasons. + +Tiles are numbered starting with one, and left-to-right, +top-to-bottom. So, if you are generating a 3x3 tiled image, the +middle row would be `4 5 6`. + +## Example Usage + +Running Embiggen with 512x512 tiles on an existing image, scaling up by a factor of 2.5x; +and doing the same again (default ESRGAN strength is 0.75, default overlap between tiles is 0.25): + +```bash +dream > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5 +dream > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5 0.75 0.25 +``` + +If your starting image was also 512x512 this should have taken 9 tiles. + +If there weren't enough clouds in the sky of that forest you just made +(and that image is about 1280 pixels (512*2.5) wide A.K.A. three +512x512 tiles with 0.25 overlaps wide) we can replace that top row of +tiles: + +```bash +dream> a photo of puffy clouds over a forest at sunset -s 100 -W 512 -H 512 -I outputs/000002.seed.png -f 0.5 -embiggen_tiles 1 2 3 +``` + +## Fixing Previously-Generated Images + +It is easy to apply embiggen to any previously-generated file without having to +look up the original prompt and provide an initial image. Just use the +syntax `!fix path/to/file.png `. For example, you can rewrite the +previous command to look like this: + +~~~~ +dream> !fix ./outputs/000002.seed.png -embiggen_tiles 1 2 3 +~~~~ + +A new file named `000002.seed.fixed.png` will be created in the output directory. Note that +the `!fix` command does not replace the original file, unlike the behavior at generate time. +You do not need to provide the prompt, and `!fix` automatically selects a good strength for +embiggen-ing. + + +**Note** +Because the same prompt is used on all the tiled images, and the model +doesn't have the context of anything outside the tile being run - it +can end up creating repeated pattern (also called 'motifs') across all +the tiles based on that prompt. The best way to combat this is +lowering the `--strength` (`-f`) to stay more true to the init image, +and increasing the number of steps so there is more compute-time to +create the detail. Anecdotally `--strength` 0.35-0.45 works pretty +well on most things. It may also work great in some examples even with +the `--strength` set high for patterns, landscapes, or subjects that +are more abstract. Because this is (relatively) fast, you can also +preserve the best parts from each. + +Author: [Travco](https://github.com/travco) diff --git a/docs/features/IMG2IMG.md b/docs/features/IMG2IMG.md index ac560f6984..e61f365c01 100644 --- a/docs/features/IMG2IMG.md +++ b/docs/features/IMG2IMG.md @@ -1,30 +1,30 @@ -# **Image-to-Image** +--- +title: Image-to-Image +--- -This script also provides an img2img feature that lets you seed your -creations with an initial drawing or photo. This is a really cool -feature that tells stable diffusion to build the prompt on top of the -image you provide, preserving the original's basic shape and -layout. To use it, provide the `--init_img` option as shown here: +# :material-image-multiple: **IMG2IMG** -``` +This script also provides an `img2img` feature that lets you seed your creations with an initial +drawing or photo. This is a really cool feature that tells stable diffusion to build the prompt on +top of the image you provide, preserving the original's basic shape and layout. To use it, provide +the `--init_img` option as shown here: + +```bash dream> "waterfall and rainbow" --init_img=./init-images/crude_drawing.png --strength=0.5 -s100 -n4 ``` -The `--init_img (-I)` option gives the path to the seed -picture. `--strength (-f)` controls how much the original will be -modified, ranging from `0.0` (keep the original intact), to `1.0` -(ignore the original completely). The default is `0.75`, and ranges -from `0.25-0.75` give interesting results. +The `--init_img (-I)` option gives the path to the seed picture. `--strength (-f)` controls how much +the original will be modified, ranging from `0.0` (keep the original intact), to `1.0` (ignore the +original completely). The default is `0.75`, and ranges from `0.25-0.75` give interesting results. -You may also pass a `-v` option to generate count variants on +You may also pass a `-v` option to generate `-n` count variants on the original image. This is done by passing the first generated image back into img2img the requested number of times. It generates interesting variants. -If the initial image contains transparent regions, then Stable -Diffusion will only draw within the transparent regions, a process -called "inpainting". However, for this to work correctly, the color -information underneath the transparent needs to be preserved, not -erased. See [Creating Transparent Images For -Inpainting](./INPAINTING.md#creating-transparent-regions-for-inpainting) -for details. +If the initial image contains transparent regions, then Stable Diffusion will only draw within the +transparent regions, a process called "inpainting". However, for this to work correctly, the color +information underneath the transparent needs to be preserved, not erased. + +More Details can be found here: +[Creating Transparent Images For Inpainting](./INPAINTING.md#creating-transparent-regions-for-inpainting) diff --git a/docs/features/INPAINTING.md b/docs/features/INPAINTING.md index bc1c709837..497bbc7a48 100644 --- a/docs/features/INPAINTING.md +++ b/docs/features/INPAINTING.md @@ -1,31 +1,35 @@ -# **Creating Transparent Regions for Inpainting** +--- +title: Inpainting +--- -Inpainting is really cool. To do it, you start with an initial image -and use a photoeditor to make one or more regions transparent -(i.e. they have a "hole" in them). You then provide the path to this -image at the dream> command line using the `-I` switch. Stable -Diffusion will only paint within the transparent region. +# :octicons-paintbrush-16: Inpainting -There's a catch. In the current implementation, you have to prepare -the initial image correctly so that the underlying colors are -preserved under the transparent area. Many imaging editing -applications will by default erase the color information under the -transparent pixels and replace them with white or black, which will -lead to suboptimal inpainting. You also must take care to export the -PNG file in such a way that the color information is preserved. +## **Creating Transparent Regions for Inpainting** -If your photoeditor is erasing the underlying color information, -`dream.py` will give you a big fat warning. If you can't find a way to -coax your photoeditor to retain color values under transparent areas, -then you can combine the `-I` and `-M` switches to provide both the -original unedited image and the masked (partially transparent) image: +Inpainting is really cool. To do it, you start with an initial image and use a photoeditor to make +one or more regions transparent (i.e. they have a "hole" in them). You then provide the path to this +image at the dream> command line using the `-I` switch. Stable Diffusion will only paint within the +transparent region. -``` -dream> man with cat on shoulder -I./images/man.png -M./images/man-transparent.png +There's a catch. In the current implementation, you have to prepare the initial image correctly so +that the underlying colors are preserved under the transparent area. Many imaging editing +applications will by default erase the color information under the transparent pixels and replace +them with white or black, which will lead to suboptimal inpainting. You also must take care to +export the PNG file in such a way that the color information is preserved. + +If your photoeditor is erasing the underlying color information, `dream.py` will give you a big fat +warning. If you can't find a way to coax your photoeditor to retain color values under transparent +areas, then you can combine the `-I` and `-M` switches to provide both the original unedited image +and the masked (partially transparent) image: + +```bash +dream> "man with cat on shoulder" -I./images/man.png -M./images/man-transparent.png ``` We are hoping to get rid of the need for this workaround in an upcoming release. +--- + ## Recipe for GIMP [GIMP](https://www.gimp.org/) is a popular Linux photoediting tool. @@ -34,7 +38,7 @@ We are hoping to get rid of the need for this workaround in an upcoming release. 2. Layer->Transparency->Add Alpha Channel 3. Use lasoo tool to select region to mask 4. Choose Select -> Float to create a floating selection -5. Open the Layers toolbar (^L) and select "Floating Selection" +5. Open the Layers toolbar (++ctrl+l++) and select "Floating Selection" 6. Set opacity to 0% 7. Export as PNG 8. In the export dialogue, Make sure the "Save colour values from @@ -44,35 +48,29 @@ We are hoping to get rid of the need for this workaround in an upcoming release. ## Recipe for Adobe Photoshop 1. Open image in Photoshop -

- -

+ +![step1](../assets/step1.png) 2. Use any of the selection tools (Marquee, Lasso, or Wand) to select the area you desire to inpaint. -

- -

-3. Because we'll be applying a mask over the area we want to preserve, you should now select the inverse by using the Shift + Ctrl + I shortcut, or right clicking and using the "Select Inverse" option. +![step2](../assets/step2.png) -4. You'll now create a mask by selecting the image layer, and Masking the selection. Make sure that you don't delete any of the underlying image, or your inpainting results will be dramatically impacted. -

- -

+3. Because we'll be applying a mask over the area we want to preserve, you should now select the inverse by using the ++shift+ctrl+i++ shortcut, or right clicking and using the "Select Inverse" option. + +4. You'll now create a mask by selecting the image layer, and Masking the selection. Make sure that you don't delete any of the undrlying image, or your inpainting results will be dramatically impacted. + +![step4](../assets/step4.png) 5. Make sure to hide any background layers that are present. You should see the mask applied to your image layer, and the image on your canvas should display the checkered background. -

- -

-

- -

+![step5](../assets/step5.png) -6. Save the image as a transparent PNG by using the "Save a Copy" option in the File menu, or using the Alt + Ctrl + S keyboard shortcut. +6. Save the image as a transparent PNG by using the "Save a Copy" option in the File menu, or using the Alt + Ctrl + S keyboard shortcut + +![step6](../assets/step6.png) 7. After following the inpainting instructions above (either through the CLI or the Web UI), marvel at your newfound ability to selectively dream. Lookin' good! -

- -

+![step7](../assets/step7.png) + +8. In the export dialogue, Make sure the "Save colour values from transparent pixels" checkbox is selected. diff --git a/docs/features/OTHER.md b/docs/features/OTHER.md index 3853b185ed..5faa1d32d0 100644 --- a/docs/features/OTHER.md +++ b/docs/features/OTHER.md @@ -1,65 +1,47 @@ +--- +title: Others +--- + +# :fontawesome-regular-share-from-square: Others + ## **Google Colab** Stable Diffusion AI Notebook: +
Open and follow instructions to use an -isolated environment running Dream.
+alt="Open In Colab"/>
Open and follow instructions to use an isolated environment running +Dream.
-Output Example: -![Colab Notebook](../assets/colab_notebook.png) +Output Example: ![Colab Notebook](../assets/colab_notebook.png) --- ## **Seamless Tiling** -The seamless tiling mode causes generated images to seamlessly tile -with itself. To use it, add the `--seamless` option when starting the -script which will result in all generated images to tile, or for each -`dream>` prompt as shown here: +The seamless tiling mode causes generated images to seamlessly tile with itself. To use it, add the +`--seamless` option when starting the script which will result in all generated images to tile, or +for each `dream>` prompt as shown here: -``` +```python dream> "pond garden with lotus by claude monet" --seamless -s100 -n4 ``` --- -## **Reading Prompts from a File** - -You can automate `dream.py` by providing a text file with the prompts -you want to run, one line per prompt. The text file must be composed -with a text editor (e.g. Notepad) and not a word processor. Each line -should look like what you would type at the dream> prompt: - -``` -a beautiful sunny day in the park, children playing -n4 -C10 -stormy weather on a mountain top, goats grazing -s100 -innovative packaging for a squid's dinner -S137038382 -``` - -Then pass this file's name to `dream.py` when you invoke it: - -``` -(ldm) ~/stable-diffusion$ python3 scripts/dream.py --from_file "path/to/prompts.txt" -``` - -You may read a series of prompts from standard input by providing a filename of `-`: - -``` -(ldm) ~/stable-diffusion$ echo "a beautiful day" | python3 scripts/dream.py --from_file - -``` - ---- - ## **Shortcuts: Reusing Seeds** -Since it is so common to reuse seeds while refining a prompt, there is now a shortcut as of version 1.11. Provide a `**-S**` (or `**--seed**`) -switch of `-1` to use the seed of the most recent image generated. If you produced multiple images with the `**-n**` switch, then you can go back further using -2, -3, etc. up to the first image generated by the previous command. Sorry, but you can't go back further than one command. +Since it is so common to reuse seeds while refining a prompt, there is now a shortcut as of version +1.11. Provide a `**-S**` (or `**--seed**`) switch of `-1` to use the seed of the most recent image +generated. If you produced multiple images with the `**-n**` switch, then you can go back further +using -2, -3, etc. up to the first image generated by the previous command. Sorry, but you can't go +back further than one command. -Here's an example of using this to do a quick refinement. It also illustrates using the new `**-G**` switch to turn on upscaling and face enhancement (see previous section): +Here's an example of using this to do a quick refinement. It also illustrates using the new `**-G**` +switch to turn on upscaling and face enhancement (see previous section): -``` +```bash dream> a cute child playing hopscotch -G0.5 [...] outputs/img-samples/000039.3498014304.png: "a cute child playing hopscotch" -s50 -W512 -H512 -C7.5 -mk_lms -S3498014304 @@ -73,29 +55,13 @@ outputs/img-samples/000040.3498014304.png: "a cute child playing hopscotch" -G1. --- -## **Weighted Prompts** - -You may weight different sections of the prompt to tell the sampler to attach different levels of -priority to them, by adding `:(number)` to the end of the section you wish to up- or downweight. -For example consider this prompt: - -``` - tabby cat:0.25 white duck:0.75 hybrid -``` - -This will tell the sampler to invest 25% of its effort on the tabby -cat aspect of the image and 75% on the white duck aspect -(surprisingly, this example actually works). The prompt weights can -use any combination of integers and floating point numbers, and they -do not need to add up to 1. - ---- - ## **Simplified API** -For programmers who wish to incorporate stable-diffusion into other products, this repository includes a simplified API for text to image generation, which lets you create images from a prompt in just three lines of code: +For programmers who wish to incorporate stable-diffusion into other products, this repository +includes a simplified API for text to image generation, which lets you create images from a prompt +in just three lines of code: -``` +```bash from ldm.generate import Generate g = Generate() outputs = g.txt2img("a unicorn in manhattan") @@ -109,16 +75,14 @@ Please see ldm/generate.py for more information. A set of example scripts is com ## **Preload Models** -In situations where you have limited internet connectivity or are -blocked behind a firewall, you can use the preload script to preload -the required files for Stable Diffusion to run. +In situations where you have limited internet connectivity or are blocked behind a firewall, you can +use the preload script to preload the required files for Stable Diffusion to run. -The preload script `scripts/preload_models.py` needs to be run once at -least while connected to the internet. In the following runs, it will -load up the cached versions of the required files from the `.cache` -directory of the system. +The preload script `scripts/preload_models.py` needs to be run once at least while connected to the +internet. In the following runs, it will load up the cached versions of the required files from the +`.cache` directory of the system. -``` +```bash (ldm) ~/stable-diffusion$ python3 ./scripts/preload_models.py preloading bert tokenizer... Downloading: 100%|██████████████████████████████████| 28.0/28.0 [00:00<00:00, 49.3kB/s] diff --git a/docs/features/OUTPAINTING.md b/docs/features/OUTPAINTING.md new file mode 100644 index 0000000000..9f72a5cb3c --- /dev/null +++ b/docs/features/OUTPAINTING.md @@ -0,0 +1,78 @@ +--- +title: Outpainting +--- + +# :octicons-paintbrush-16: Outpainting + +## Continous outpainting + +This extension uses the inpainting code to extend an existing image to +any direction of "top", "right", "bottom" or "left". To use it you +need to provide an initial image with -I and an extension direction +with -D (direction). When extending using outpainting a higher img2img +strength value of 0.83 is the default. + +The code is not foolproof. Sometimes it will do a good job extending +the image, and other times it will generate ghost images and other +artifacts. In addition, the code works best on images that were +generated by dream.py, because it will be able to recover the original +prompt that generated the file and "understand" what you are trying to +achieve. + +### Basic Usage + +To illustrate, consider this image generated with the prompt "fantasy +portrait of eleven princess." It's nice, but rather annoying that the +top of the head has been cropped off. + +![elven_princess](../assets/outpainting/elven_princess.png) + +We can fix that using the `!fix` command! + +~~~~ +dream> !fix my_images/elven_princess.png -D top 50 +~~~~ + +This is telling dream.py to open up a rectangle 50 pixels high at the +top of the image and outpaint into it. The result is: + +![elven_princess.fixed](../assets/outpainting/elven_princess.outpainted.png) + +Viola! You can similarly specify `bottom`, `left` or `right` to +outpaint into these margins. + +There are some limitations to be aware of: + +1. You cannot change the size of the image rectangle. In the example, + notice that the whole image is shifted downwards by 50 pixels, rather + than the top being extended upwards. + +2. Attempting to outpaint larger areas will frequently give rise to ugly + ghosting effects. + +3. For best results, try increasing the step number. + +4. If you don't specify a pixel value in -D, it will default to half + of the whole image, which is likely not what you want. + +You can do more with `!fix` including upscaling and facial +reconstruction of previously-generated images. See +[./UPSCALE.md#fixing-previously-generated-images] for the details. + +### Advanced Usage + +For more control over the outpaintihg process, you can provide the +`-D` option at image generation time. This allows you to apply all the +controls, including the ability to resize the image and apply face-fixing +and upscaling. For example: + +~~~~ +dream> man with cat on shoulder -I./images/man.png -D bottom 100 -W960 -H960 -fit +~~~~ + +Or even shorter, since the prompt is read from the metadata of the old image: + +~~~~ +dream> -I./images/man.png -D bottom 100 -W960 -H960 -fit -U2 -G1 +~~~~ + diff --git a/docs/features/PROMPTS.md b/docs/features/PROMPTS.md new file mode 100644 index 0000000000..f3bb9cef86 --- /dev/null +++ b/docs/features/PROMPTS.md @@ -0,0 +1,90 @@ +--- +title: Prompting Features +--- + +# :octicons-command-palette-24: Prompting Features + +## **Reading Prompts from a File** + +You can automate `dream.py` by providing a text file with the prompts you want to run, one line per +prompt. The text file must be composed with a text editor (e.g. Notepad) and not a word processor. +Each line should look like what you would type at the dream> prompt: + +```bash +a beautiful sunny day in the park, children playing -n4 -C10 +stormy weather on a mountain top, goats grazing -s100 +innovative packaging for a squid's dinner -S137038382 +``` + +Then pass this file's name to `dream.py` when you invoke it: + +```bash +(ldm) ~/stable-diffusion$ python3 scripts/dream.py --from_file "path/to/prompts.txt" +``` + +You may read a series of prompts from standard input by providing a filename of `-`: + +```bash +(ldm) ~/stable-diffusion$ echo "a beautiful day" | python3 scripts/dream.py --from_file - +``` + +--- + +## **Weighted Prompts** + +You may weight different sections of the prompt to tell the sampler to attach different levels of +priority to them, by adding `:(number)` to the end of the section you wish to up- or downweight. For +example consider this prompt: + +```bash +tabby cat:0.25 white duck:0.75 hybrid +``` + +This will tell the sampler to invest 25% of its effort on the tabby cat aspect of the image and 75% +on the white duck aspect (surprisingly, this example actually works). The prompt weights can use any +combination of integers and floating point numbers, and they do not need to add up to 1. + +--- + +## **Negative and Unconditioned Prompts** + +Any words between a pair of square brackets will try and be ignored by Stable Diffusion's model during generation of images. + +```bash +this is a test prompt [not really] to make you understand [cool] how this works. +``` + +In the above statement, the words 'not really cool` will be ignored by Stable Diffusion. + +Here's a prompt that depicts what it does. + +original prompt: + +`#!bash "A fantastical translucent poney made of water and foam, ethereal, radiant, hyperalism, scottish folklore, digital painting, artstation, concept art, smooth, 8 k frostbite 3 engine, ultra detailed, art by artgerm and greg rutkowski and magali villeneuve" -s 20 -W 512 -H 768 -C 7.5 -A k_euler_a -S 1654590180` + +![step1](../assets/negative_prompt_walkthru/step1.png) + +That image has a woman, so if we want the horse without a rider, we can influence the image not to have a woman by putting [woman] in the prompt, like this: + +`#!bash "A fantastical translucent poney made of water and foam, ethereal, radiant, hyperalism, scottish folklore, digital painting, artstation, concept art, smooth, 8 k frostbite 3 engine, ultra detailed, art by artgerm and greg rutkowski and magali villeneuve [woman]" -s 20 -W 512 -H 768 -C 7.5 -A k_euler_a -S 1654590180` + +![step2](../assets/negative_prompt_walkthru/step2.png) + +That's nice - but say we also don't want the image to be quite so blue. We can add "blue" to the list of negative prompts, so it's now [woman blue]: + +`#!bash "A fantastical translucent poney made of water and foam, ethereal, radiant, hyperalism, scottish folklore, digital painting, artstation, concept art, smooth, 8 k frostbite 3 engine, ultra detailed, art by artgerm and greg rutkowski and magali villeneuve [woman blue]" -s 20 -W 512 -H 768 -C 7.5 -A k_euler_a -S 1654590180` + +![step3](../assets/negative_prompt_walkthru/step3.png) + +Getting close - but there's no sense in having a saddle when our horse doesn't have a rider, so we'll add one more negative prompt: [woman blue saddle]. + +`#!bash "A fantastical translucent poney made of water and foam, ethereal, radiant, hyperalism, scottish folklore, digital painting, artstation, concept art, smooth, 8 k frostbite 3 engine, ultra detailed, art by artgerm and greg rutkowski and magali villeneuve [woman blue saddle]" -s 20 -W 512 -H 768 -C 7.5 -A k_euler_a -S 1654590180` + +![step4](../assets/negative_prompt_walkthru/step4.png) + +!!! notes "Notes about this feature:" + + * The only requirement for words to be ignored is that they are in between a pair of square brackets. + * You can provide multiple words within the same bracket. + * You can provide multiple brackets with multiple words in different places of your prompt. That works just fine. + * To improve typical anatomy problems, you can add negative prompts like `[bad anatomy, extra legs, extra arms, extra fingers, poorly drawn hands, poorly drawn feet, disfigured, out of frame, tiling, bad art, deformed, mutated]`. diff --git a/docs/features/TEXTUAL_INVERSION.md b/docs/features/TEXTUAL_INVERSION.md index 3641732e79..50532968a8 100644 --- a/docs/features/TEXTUAL_INVERSION.md +++ b/docs/features/TEXTUAL_INVERSION.md @@ -1,70 +1,91 @@ -# **Personalizing Text-to-Image Generation** +--- +title: TEXTUAL_INVERSION +--- -You may personalize the generated images to provide your own styles or objects by training a new LDM checkpoint and introducing a new vocabulary to the fixed model as a (.pt) embeddings file. Alternatively, you may use or train HuggingFace Concepts embeddings files (.bin) from https://huggingface.co/sd-concepts-library and its associated notebooks. +# :material-file-document-plus-outline: TEXTUAL_INVERSION -**Training** +## **Personalizing Text-to-Image Generation** -To train, prepare a folder that contains images sized at 512x512 and execute the following: +You may personalize the generated images to provide your own styles or objects +by training a new LDM checkpoint and introducing a new vocabulary to the fixed +model as a (.pt) embeddings file. Alternatively, you may use or train +HuggingFace Concepts embeddings files (.bin) from + and its associated notebooks. -**WINDOWS**: As the default backend is not available on Windows, if you're using that platform, set the environment variable `PL_TORCH_DISTRIBUTED_BACKEND=gloo` +## **Training** -``` -(ldm) ~/stable-diffusion$ python3 ./main.py --base ./configs/stable-diffusion/v1-finetune.yaml \ - -t \ - --actual_resume ./models/ldm/stable-diffusion-v1/model.ckpt \ - -n my_cat \ - --gpus 0, \ - --data_root D:/textual-inversion/my_cat \ - --init_word 'cat' +To train, prepare a folder that contains images sized at 512x512 and execute the +following: + +### WINDOWS + +As the default backend is not available on Windows, if you're using that +platform, set the environment variable `PL_TORCH_DISTRIBUTED_BACKEND` to `gloo` + +```bash +python3 ./main.py --base ./configs/stable-diffusion/v1-finetune.yaml \ + --actual_resume ./models/ldm/stable-diffusion-v1/model.ckpt \ + -t \ + -n my_cat \ + --gpus 0 \ + --data_root D:/textual-inversion/my_cat \ + --init_word 'cat' ``` During the training process, files will be created in -/logs/[project][time][project]/ where you can see the process. +`/logs/[project][time][project]/` where you can see the process. -Conditioning contains the training prompts inputs, reconstruction the -input images for the training epoch samples, samples scaled for a -sample of the prompt and one with the init word provided. +Conditioning contains the training prompts inputs, reconstruction the input +images for the training epoch samples, samples scaled for a sample of the prompt +and one with the init word provided. On a RTX3090, the process for SD will take ~1h @1.6 iterations/sec. -_Note_: According to the associated paper, the optimal number of -images is 3-5. Your model may not converge if you use more images than -that. +!!! note -Training will run indefinitely, but you may wish to stop it (with -ctrl-c) before the heat death of the universe, when you find a low -loss epoch or around ~5000 iterations. Note that you can set a fixed -limit on the number of training steps by decreasing the "max_steps" -option in configs/stable_diffusion/v1-finetune.yaml (currently set to -4000000) + According to the associated paper, the optimal number of + images is 3-5. Your model may not converge if you use more images than + that. -**Running** +Training will run indefinitely, but you may wish to stop it (with ctrl-c) before +the heat death of the universe, when you find a low loss epoch or around ~5000 +iterations. Note that you can set a fixed limit on the number of training steps +by decreasing the "max_steps" option in +configs/stable_diffusion/v1-finetune.yaml (currently set to 4000000) -Once the model is trained, specify the trained .pt or .bin file when -starting dream using +## **Run the Model** -``` -(ldm) ~/stable-diffusion$ python3 ./scripts/dream.py --embedding_path /path/to/embedding.pt --full_precision +Once the model is trained, specify the trained .pt or .bin file when starting +dream using + +```bash +python3 ./scripts/dream.py --embedding_path /path/to/embedding.pt ``` Then, to utilize your subject at the dream prompt -``` +```bash dream> "a photo of *" ``` This also works with image2image -``` +```bash dream> "waterfall and rainbow in the style of *" --init_img=./init-images/crude_drawing.png --strength=0.5 -s100 -n4 ``` -For .pt files it's also possible to train multiple tokens (modify the placeholder string in `configs/stable-diffusion/v1-finetune.yaml`) and combine LDM checkpoints using: +For .pt files it's also possible to train multiple tokens (modify the +placeholder string in `configs/stable-diffusion/v1-finetune.yaml`) and combine +LDM checkpoints using: -``` -(ldm) ~/stable-diffusion$ python3 ./scripts/merge_embeddings.py \ - --manager_ckpts /path/to/first/embedding.pt /path/to/second/embedding.pt [...] \ - --output_path /path/to/output/embedding.pt +```bash +python3 ./scripts/merge_embeddings.py \ + --manager_ckpts /path/to/first/embedding.pt \ + [
,[...]] \ + --output_path /path/to/output/embedding.pt ``` -Credit goes to rinongal and the repository located at https://github.com/rinongal/textual_inversion Please see the repository and associated paper for details and limitations. +Credit goes to rinongal and the repository + +Please see [the repository](https://github.com/rinongal/textual_inversion) and +associated paper for details and limitations. diff --git a/docs/features/UPSCALE.md b/docs/features/UPSCALE.md index 381d2b90ec..f4c06f8b42 100644 --- a/docs/features/UPSCALE.md +++ b/docs/features/UPSCALE.md @@ -1,105 +1,177 @@ -# **GFPGAN and Real-ESRGAN Support** +--- +title: Upscale +--- -The script also provides the ability to do face restoration and -upscaling with the help of GFPGAN and Real-ESRGAN respectively. +## Intro -As of version 1.14, environment.yaml will install the Real-ESRGAN package into the -standard install location for python packages, and will put GFPGAN into a subdirectory of "src" -in the stable-diffusion directory. -(The reason for this is that the standard GFPGAN distribution has a minor bug that adversely affects image -color.) Upscaling with Real-ESRGAN should "just work" without further intervention. Simply pass the --upscale (-U) -option on the dream> command line, or indicate the desired scale on the popup in the Web GUI. +The script provides the ability to restore faces and upscale. You can apply +these operations at the time you generate the images, or at any time to a +previously-generated PNG file, using the +[!fix](#fixing-previously-generated-images) command. -For **GFPGAN** to work, there is one additional step needed. You will need to download and -copy the GFPGAN [models file](https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth) -into **src/gfpgan/experiments/pretrained_models**. On Mac and Linux systems, here's how you'd do it using -**wget**: -~~~~ -> wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth -P src/gfpgan/experiments/pretrained_models/ -~~~~ +## Face Fixing + +The default face restoration module is GFPGAN. The default upscale is +Real-ESRGAN. For an alternative face restoration module, see [CodeFormer +Support] below. + +As of version 1.14, environment.yaml will install the Real-ESRGAN package into +the standard install location for python packages, and will put GFPGAN into a +subdirectory of "src" in the stable-diffusion directory. (The reason for this is +that the standard GFPGAN distribution has a minor bug that adversely affects +image color.) Upscaling with Real-ESRGAN should "just work" without further +intervention. Simply pass the --upscale (-U) option on the dream> command line, +or indicate the desired scale on the popup in the Web GUI. + +For **GFPGAN** to work, there is one additional step needed. You will need to +download and copy the GFPGAN +[models file](https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth) +into **src/gfpgan/experiments/pretrained_models**. On Mac and Linux systems, +here's how you'd do it using **wget**: + +```bash +> wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth src/gfpgan/experiments/pretrained_models/ +``` Make sure that you're in the stable-diffusion directory when you do this. -Alternatively, if you have GFPGAN installed elsewhere, or if you are using -an earlier version of this package which asked you to install GFPGAN in a -sibling directory, you may use the `--gfpgan_dir` argument with `dream.py` to set a -custom path to your GFPGAN directory. _There are other GFPGAN related -boot arguments if you wish to customize further._ +Alternatively, if you have GFPGAN installed elsewhere, or if you are using an +earlier version of this package which asked you to install GFPGAN in a sibling +directory, you may use the `--gfpgan_dir` argument with `dream.py` to set a +custom path to your GFPGAN directory. _There are other GFPGAN related boot +arguments if you wish to customize further._ -**Note: Internet connection needed:** -Users whose GPU machines are isolated from the Internet (e.g. on a -University cluster) should be aware that the first time you run -dream.py with GFPGAN and Real-ESRGAN turned on, it will try to -download model files from the Internet. To rectify this, you may run -`python3 scripts/preload_models.py` after you have installed GFPGAN -and all its dependencies. +!!! warning "Internet connection needed" -**Usage** + Users whose GPU machines are isolated from the Internet (e.g. + on a University cluster) should be aware that the first time you run dream.py with GFPGAN and + Real-ESRGAN turned on, it will try to download model files from the Internet. To rectify this, you + may run `python3 scripts/preload_models.py` after you have installed GFPGAN and all its + dependencies. + +## Usage You will now have access to two new prompt arguments. -**Upscaling** +### Upscaling `-U : ` -The upscaling prompt argument takes two values. The first value is a -scaling factor and should be set to either `2` or `4` only. This will -either scale the image 2x or 4x respectively using different models. +The upscaling prompt argument takes two values. The first value is a scaling +factor and should be set to either `2` or `4` only. This will either scale the +image 2x or 4x respectively using different models. -You can set the scaling stength between `0` and `1.0` to control -intensity of the of the scaling. This is handy because AI upscalers -generally tend to smooth out texture details. If you wish to retain -some of those for natural looking results, we recommend using values -between `0.5 to 0.8`. +You can set the scaling stength between `0` and `1.0` to control intensity of +the of the scaling. This is handy because AI upscalers generally tend to smooth +out texture details. If you wish to retain some of those for natural looking +results, we recommend using values between `0.5 to 0.8`. -If you do not explicitly specify an upscaling_strength, it will -default to 0.75. +If you do not explicitly specify an upscaling_strength, it will default to 0.75. -**Face Restoration** +### Face Restoration `-G : ` -This prompt argument controls the strength of the face restoration -that is being applied. Similar to upscaling, values between `0.5 to 0.8` are recommended. +This prompt argument controls the strength of the face restoration that is being +applied. Similar to upscaling, values between `0.5 to 0.8` are recommended. -You can use either one or both without any conflicts. In cases where -you use both, the image will be first upscaled and then the face -restoration process will be executed to ensure you get the highest -quality facial features. +You can use either one or both without any conflicts. In cases where you use +both, the image will be first upscaled and then the face restoration process +will be executed to ensure you get the highest quality facial features. `--save_orig` -When you use either `-U` or `-G`, the final result you get is upscaled -or face modified. If you want to save the original Stable Diffusion -generation, you can use the `-save_orig` prompt argument to save the -original unaffected version too. +When you use either `-U` or `-G`, the final result you get is upscaled or face +modified. If you want to save the original Stable Diffusion generation, you can +use the `-save_orig` prompt argument to save the original unaffected version +too. -**Example Usage** +### Example Usage -``` -dream > superman dancing with a panda bear -U 2 0.6 -G 0.4 +```bash +dream> superman dancing with a panda bear -U 2 0.6 -G 0.4 ``` This also works with img2img: -``` +```bash dream> a man wearing a pineapple hat -I path/to/your/file.png -U 2 0.5 -G 0.6 ``` -**Note** +!!! note -GFPGAN and Real-ESRGAN are both memory intensive. In order to avoid -crashes and memory overloads during the Stable Diffusion process, -these effects are applied after Stable Diffusion has completed its -work. + GFPGAN and Real-ESRGAN are both memory intensive. In order to avoid crashes and memory overloads + during the Stable Diffusion process, these effects are applied after Stable Diffusion has completed + its work. -In single image generations, you will see the output right away but -when you are using multiple iterations, the images will first be -generated and then upscaled and face restored after that process is -complete. While the image generation is taking place, you will still -be able to preview the base images. + In single image generations, you will see the output right away but when you are using multiple + iterations, the images will first be generated and then upscaled and face restored after that + process is complete. While the image generation is taking place, you will still be able to preview + the base images. -If you wish to stop during the image generation but want to upscale or -face restore a particular generated image, pass it again with the same -prompt and generated seed along with the `-U` and `-G` prompt -arguments to perform those actions. +If you wish to stop during the image generation but want to upscale or face +restore a particular generated image, pass it again with the same prompt and +generated seed along with the `-U` and `-G` prompt arguments to perform those +actions. + +## CodeFormer Support + +This repo also allows you to perform face restoration using +[CodeFormer](https://github.com/sczhou/CodeFormer). + +In order to setup CodeFormer to work, you need to download the models like with +GFPGAN. You can do this either by running `preload_models.py` or by manually +downloading the +[model file](https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/codeformer.pth) +and saving it to `ldm/restoration/codeformer/weights` folder. + +You can use `-ft` prompt argument to swap between CodeFormer and the default +GFPGAN. The above mentioned `-G` prompt argument will allow you to control the +strength of the restoration effect. + +### Usage: + +The following command will perform face restoration with CodeFormer instead of +the default gfpgan. + +` -G 0.8 -ft codeformer` + +### Other Options: + +- `-cf` - cf or CodeFormer Fidelity takes values between `0` and `1`. 0 produces + high quality results but low accuracy and 1 produces lower quality results but + higher accuacy to your original face. + +The following command will perform face restoration with CodeFormer. CodeFormer +will output a result that is closely matching to the input face. + +` -G 1.0 -ft codeformer -cf 0.9` + +The following command will perform face restoration with CodeFormer. CodeFormer +will output a result that is the best restoration possible. This may deviate +slightly from the original face. This is an excellent option to use in +situations when there is very little facial data to work with. + +` -G 1.0 -ft codeformer -cf 0.1` + +## Fixing Previously-Generated Images + +It is easy to apply face restoration and/or upscaling to any +previously-generated file. Just use the syntax +`!fix path/to/file.png `. For example, to apply GFPGAN at strength 0.8 +and upscale 2X for a file named `./outputs/img-samples/000044.2945021133.png`, +just run: + +``` +dream> !fix ./outputs/img-samples/000044.2945021133.png -G 0.8 -U 2 +``` + +A new file named `000044.2945021133.fixed.png` will be created in the output +directory. Note that the `!fix` command does not replace the original file, +unlike the behavior at generate time. + +### Disabling: + +If, for some reason, you do not wish to load the GFPGAN and/or ESRGAN libraries, +you can disable them on the dream.py command line with the `--no_restore` and +`--no_upscale` options, respectively. diff --git a/docs/features/VARIATIONS.md b/docs/features/VARIATIONS.md index a6c5c936c1..e021c300fb 100644 --- a/docs/features/VARIATIONS.md +++ b/docs/features/VARIATIONS.md @@ -1,28 +1,39 @@ -# **Variations** +--- +title: Variations +--- + +# :material-tune-variant: Variations + +## Intro Release 1.13 of SD-Dream adds support for image variations. You are able to do the following: -1. Generate a series of systematic variations of an image, given a prompt. The amount of variation from one image to the next can be controlled. +1. Generate a series of systematic variations of an image, given a prompt. The + amount of variation from one image to the next can be controlled. -2. Given two or more variations that you like, you can combine them in a weighted fashion. +2. Given two or more variations that you like, you can combine them in a + weighted fashion. --- -This cheat sheet provides a quick guide for how this works in practice, using variations to create the desired image of Xena, Warrior Princess. +This cheat sheet provides a quick guide for how this works in practice, using +variations to create the desired image of Xena, Warrior Princess. --- ## Step 1 -- Find a base image that you like -The prompt we will use throughout is `lucy lawless as xena, warrior princess, character portrait, high resolution.` +The prompt we will use throughout is +`lucy lawless as xena, warrior princess, character portrait, high resolution.` This will be indicated as `prompt` in the examples below. -First we let SD create a series of images in the usual way, in this case requesting six iterations: +First we let SD create a series of images in the usual way, in this case +requesting six iterations: -``` +```bash dream> lucy lawless as xena, warrior princess, character portrait, high resolution -n6 ... Outputs: @@ -34,19 +45,18 @@ Outputs: ./outputs/Xena/000001.3357757885.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -S3357757885 ``` -The one with seed 3357757885 looks nice: - - +![var1](../assets/variation_walkthru/000001.3357757885.png) --- ## Step 2 - Generating Variations -Let's try to generate some variations. Using the same seed, we pass the argument `-v0.1` (or --variant_amount), which generates a series of -variations each differing by a variation amount of 0.2. This number ranges from `0` to `1.0`, with higher numbers being larger amounts of -variation. +Let's try to generate some variations. Using the same seed, we pass the argument +`-v0.1` (or --variant_amount), which generates a series of variations each +differing by a variation amount of 0.2. This number ranges from `0` to `1.0`, +with higher numbers being larger amounts of variation. -``` +```bash dream> "prompt" -n6 -S3357757885 -v0.2 ... Outputs: @@ -60,33 +70,42 @@ Outputs: ### **Variation Sub Seeding** -Note that the output for each image has a `-V` option giving the "variant subseed" for that image, consisting of a seed followed by the -variation amount used to generate it. +Note that the output for each image has a `-V` option giving the "variant +subseed" for that image, consisting of a seed followed by the variation amount +used to generate it. -This gives us a series of closely-related variations, including the two shown here. +This gives us a series of closely-related variations, including the two shown +here. - - +![var2](../assets/variation_walkthru/000002.3647897225.png) -I like the expression on Xena's face in the first one (subseed 3647897225), and the armor on her shoulder in the second one (subseed 1614299449). Can we combine them to get the best of both worlds? +![var3](../assets/variation_walkthru/000002.1614299449.png) -We combine the two variations using `-V` (--with_variations). Again, we must provide the seed for the originally-chosen image in order for -this to work. +I like the expression on Xena's face in the first one (subseed 3647897225), and +the armor on her shoulder in the second one (subseed 1614299449). Can we combine +them to get the best of both worlds? -``` -dream> "prompt" -S3357757885 -V3647897225,0.1;1614299449,0.1 +We combine the two variations using `-V` (`--with_variations`). Again, we must +provide the seed for the originally-chosen image in order for this to work. + +```bash +dream> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1 Outputs: ./outputs/Xena/000003.1614299449.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1 -S3357757885 ``` -Here we are providing equal weights (0.1 and 0.1) for both the subseeds. The resulting image is close, but not exactly what I wanted: +Here we are providing equal weights (0.1 and 0.1) for both the subseeds. The +resulting image is close, but not exactly what I wanted: - +![var4](../assets/variation_walkthru/000003.1614299449.png) -We could either try combining the images with different weights, or we can generate more variations around the almost-but-not-quite image. We do the latter, using both the `-V` (combining) and `-v` (variation strength) options. Note that we use `-n6` to generate 6 variations: +We could either try combining the images with different weights, or we can +generate more variations around the almost-but-not-quite image. We do the +latter, using both the `-V` (combining) and `-v` (variation strength) options. +Note that we use `-n6` to generate 6 variations: -``` -dream> "prompt" -S3357757885 -V3647897225,0.1;1614299449,0.1 -v0.05 -n6 +```bash +dream> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1 -v0.05 -n6 Outputs: ./outputs/Xena/000004.3279757577.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,3279757577:0.05 -S3357757885 ./outputs/Xena/000004.2853129515.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,2853129515:0.05 -S3357757885 @@ -96,9 +115,11 @@ Outputs: ./outputs/Xena/000004.2183375608.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,2183375608:0.05 -S3357757885 ``` -This produces six images, all slight variations on the combination of the chosen two images. Here's the one I like best: +This produces six images, all slight variations on the combination of the chosen +two images. Here's the one I like best: - +![var5](../assets/variation_walkthru/000004.3747154981.png) -As you can see, this is a very powerful tool, which when combined with subprompt weighting, gives you great control over the content and -quality of your generated images. +As you can see, this is a very powerful tool, which when combined with subprompt +weighting, gives you great control over the content and quality of your +generated images. diff --git a/docs/features/WEB.md b/docs/features/WEB.md index 9eb6aa5bfc..833b18cdfc 100644 --- a/docs/features/WEB.md +++ b/docs/features/WEB.md @@ -1,13 +1,21 @@ -# Barebones Web Server +--- +title: Barebones Web Server +--- -As of version 1.10, this distribution comes with a bare bones web server (see screenshot). To use it, run the `dream.py` script by adding the `**--web**` option. +# :material-web: Barebones Web Server -``` +As of version 1.10, this distribution comes with a bare bones web server (see +screenshot). To use it, run the `dream.py` script by adding the `--web` +option. + +```bash (ldm) ~/stable-diffusion$ python3 scripts/dream.py --web ``` -You can then connect to the server by pointing your web browser at http://localhost:9090, or to the network name or IP address of the server. +You can then connect to the server by pointing your web browser at +http://localhost:9090, or to the network name or IP address of the server. -Kudos to [Tesseract Cat](https://github.com/TesseractCat) for contributing this code, and to [dagf2101](https://github.com/dagf2101) for refining it. +Kudos to [Tesseract Cat](https://github.com/TesseractCat) for contributing this +code, and to [dagf2101](https://github.com/dagf2101) for refining it. ![Dream Web Server](../assets/dream_web_server.png) diff --git a/docs/help/SAMPLER_CONVERGENCE.md b/docs/help/SAMPLER_CONVERGENCE.md new file mode 100644 index 0000000000..5dfee5dc4e --- /dev/null +++ b/docs/help/SAMPLER_CONVERGENCE.md @@ -0,0 +1,141 @@ +--- +title: SAMPLER CONVERGENCE +--- + +## *Sampler Convergence* + +As features keep increasing, making the right choices for your needs can become increasingly difficult. What sampler to use? And for how many steps? Do you change the CFG value? Do you use prompt weighting? Do you allow variations? + +Even once you have a result, do you blend it with other images? Pass it through `img2img`? With what strength? Do you use inpainting to correct small details? Outpainting to extend cropped sections? + +The purpose of this series of documents is to help you better understand these tools, so you can make the best out of them. Feel free to contribute with your own findings! + +In this document, we will talk about sampler convergence. + +Looking for a short version? Here's a TL;DR in 3 tables. + +| Remember | +|:---| +| Results converge as steps (`-s`) are increased (except for `K_DPM_2_A` and `K_EULER_A`). Often at ≥ `-s100`, but may require ≥ `-s700`). | +| Producing a batch of candidate images at low (`-s8` to `-s30`) step counts can save you hours of computation. | +| `K_HEUN` and `K_DPM_2` converge in less steps (but are slower). | +| `K_DPM_2_A` and `K_EULER_A` incorporate a lot of creativity/variability. | + +| Sampler | (3 sample avg) it/s (M1 Max 64GB, 512x512) | +|---|---| +| `DDIM` | 1.89 | +| `PLMS` | 1.86 | +| `K_EULER` | 1.86 | +| `K_LMS` | 1.91 | +| `K_HEUN` | 0.95 (slower) | +| `K_DPM_2` | 0.95 (slower) | +| `K_DPM_2_A` | 0.95 (slower) | +| `K_EULER_A` | 1.86 | + +| Suggestions | +|:---| +| For most use cases, `K_LMS`, `K_HEUN` and `K_DPM_2` are the best choices (the latter 2 run 0.5x as quick, but tend to converge 2x as quick as `K_LMS`). At very low steps (≤ `-s8`), `K_HEUN` and `K_DPM_2` are not recommended. Use `K_LMS` instead.| +| For variability, use `K_EULER_A` (runs 2x as quick as `K_DPM_2_A`). | + +--- + +### *Sampler results* + +Let's start by choosing a prompt and using it with each of our 8 samplers, running it for 10, 20, 30, 40, 50 and 100 steps. + +Anime. `"an anime girl" -W512 -H512 -C7.5 -S3031912972` + +![191636411-083c8282-6ed1-4f78-9273-ee87c0a0f1b6-min (1)](https://user-images.githubusercontent.com/50542132/191868725-7f7af991-e254-4c1f-83e7-bed8c9b2d34f.png) + +### *Sampler convergence* + +Immediately, you can notice results tend to converge -that is, as `-s` (step) values increase, images look more and more similar until there comes a point where the image no longer changes. + +You can also notice how `DDIM` and `PLMS` eventually tend to converge to K-sampler results as steps are increased. +Among K-samplers, `K_HEUN` and `K_DPM_2` seem to require the fewest steps to converge, and even at low step counts they are good indicators of the final result. And finally, `K_DPM_2_A` and `K_EULER_A` seem to do a bit of their own thing and don't keep much similarity with the rest of the samplers. + +### *Batch generation speedup* + +This realization is very useful because it means you don't need to create a batch of 100 images (`-n100`) at `-s100` to choose your favorite 2 or 3 images. +You can produce the same 100 images at `-s10` to `-s30` using a K-sampler (since they converge faster), get a rough idea of the final result, choose your 2 or 3 favorite ones, and then run `-s100` on those images to polish some details. +The latter technique is 3-8x as quick. + +Example: + +At 60s per 100 steps. + +(Option A) 60s * 100 images = 6000s (100 images at `-s100`, manually picking 3 favorites) + +(Option B) 6s * 100 images + 60s * 3 images = 780s (100 images at `-s10`, manually picking 3 favorites, and running those 3 at `-s100` to polish details) + +The result is 1 hour and 40 minutes (Option A) vs 13 minutes (Option B). + +### *Topic convergance* + +Now, these results seem interesting, but do they hold for other topics? How about nature? Food? People? Animals? Let's try! + +Nature. `"valley landscape wallpaper, d&d art, fantasy, painted, 4k, high detail, sharp focus, washed colors, elaborate excellent painted illustration" -W512 -H512 -C7.5 -S1458228930` + +![191736091-dda76929-00d1-4590-bef4-7314ea4ea419-min (1)](https://user-images.githubusercontent.com/50542132/191868763-b151c69e-0a72-4cf1-a151-5a64edd0c93e.png) + +With nature, you can see how initial results are even more indicative of final result -more so than with characters/people. `K_HEUN` and `K_DPM_2` are again the quickest indicators, almost right from the start. Results also converge faster (e.g. `K_HEUN` converged at `-s21`). + +Food. `"a hamburger with a bowl of french fries" -W512 -H512 -C7.5 -S4053222918` + +![191639011-f81d9d38-0a15-45f0-9442-a5e8d5c25f1f-min (1)](https://user-images.githubusercontent.com/50542132/191868898-98801a62-885f-4ea1-aee8-563503522aa9.png) + +Again, `K_HEUN` and `K_DPM_2` take the fewest number of steps to be good indicators of the final result. `K_DPM_2_A` and `K_EULER_A` seem to incorporate a lot of creativity/variability, capable of producing rotten hamburgers, but also of adding lettuce to the mix. And they're the only samplers that produced an actual 'bowl of fries'! + +Animals. `"grown tiger, full body" -W512 -H512 -C7.5 -S3721629802` + +![191771922-6029a4f5-f707-4684-9011-c6f96e25fe56-min (1)](https://user-images.githubusercontent.com/50542132/191868870-9e3b7d82-b909-429f-893a-13f6ec343454.png) + +`K_HEUN` and `K_DPM_2` once again require the least number of steps to be indicative of the final result (around `-s30`), while other samplers are still struggling with several tails or malformed back legs. + +It also takes longer to converge (for comparison, `K_HEUN` required around 150 steps to converge). This is normal, as producing human/animal faces/bodies is one of the things the model struggles the most with. For these topics, running for more steps will often increase coherence within the composition. + +People. `"Ultra realistic photo, (Miranda Bloom-Kerr), young, stunning model, blue eyes, blond hair, beautiful face, intricate, highly detailed, smooth, art by artgerm and greg rutkowski and alphonse mucha, stained glass" -W512 -H512 -C7.5 -S2131956332`. This time, we will go up to 300 steps. + +![Screenshot 2022-09-23 at 02 05 48-min (1)](https://user-images.githubusercontent.com/50542132/191871743-6802f199-0ffd-4986-98c5-df2d8db30d18.png) + +Observing the results, it again takes longer for all samplers to converge (`K_HEUN` took around 150 steps), but we can observe good indicative results much earlier (see: `K_HEUN`). Conversely, `DDIM` and `PLMS` are still undergoing moderate changes (see: lace around her neck), even at `-s300`. + +In fact, as we can see in this other experiment, some samplers can take 700+ steps to converge when generating people. + +![191988191-c586b75a-2d7f-4351-b705-83cc1149881a-min (1)](https://user-images.githubusercontent.com/50542132/191992123-7e0759d6-6220-42c4-a961-88c7071c5ee6.png) + +Note also the point of convergence may not be the most desirable state (e.g. I prefer an earlier version of the face, more rounded), but it will probably be the most coherent arms/hands/face attributes-wise. You can always merge different images with a photo editing tool and pass it through `img2img` to smoothen the composition. + +### *Sampler generation times* + +Once we understand the concept of sampler convergence, we must look into the performance of each sampler in terms of steps (iterations) per second, as not all samplers run at the same speed. + +On my M1 Max with 64GB of RAM, for a 512x512 image: +| Sampler | (3 sample average) it/s | +|---|---| +| `DDIM` | 1.89 | +| `PLMS` | 1.86 | +| `K_EULER` | 1.86 | +| `K_LMS` | 1.91 | +| `K_HEUN` | 0.95 (slower) | +| `K_DPM_2` | 0.95 (slower) | +| `K_DPM_2_A` | 0.95 (slower) | +| `K_EULER_A` | 1.86 | + +Combining our results with the steps per second of each sampler, three choices come out on top: `K_LMS`, `K_HEUN` and `K_DPM_2` (where the latter two run 0.5x as quick but tend to converge 2x as quick as `K_LMS`). For creativity and a lot of variation between iterations, `K_EULER_A` can be a good choice (which runs 2x as quick as `K_DPM_2_A`). + +Additionally, image generation at very low steps (≤ `-s8`) is not recommended for `K_HEUN` and `K_DPM_2`. Use `K_LMS` instead. + +192044949-67d5d441-a0d5-4d5a-be30-5dda4fc28a00-min + +### *Three key points* + +Finally, it is relevant to mention that, in general, there are 3 important moments in the process of image formation as steps increase: + +* The (earliest) point at which an image becomes a good indicator of the final result (useful for batch generation at low step values, to then improve the quality/coherence of the chosen images via running the same prompt and seed for more steps). + +* The (earliest) point at which an image becomes coherent, even if different from the result if steps are increased (useful for batch generation at low step values, where quality/coherence is improved via techniques other than increasing the steps -e.g. via inpainting). + +* The point at which an image fully converges. + +Hence, remember that your workflow/strategy should define your optimal number of steps, even for the same prompt and seed (for example, if you seek full convergence, you may run `K_LMS` for `-s200` in the case of the red-haired girl, but `K_LMS` and `-s20`-taking one tenth the time- may do as well if your workflow includes adding small details, such as the missing shoulder strap, via `img2img`). diff --git a/docs/help/TROUBLESHOOT.md b/docs/help/TROUBLESHOOT.md index cac5dddf23..f5dcfe2c1c 100644 --- a/docs/help/TROUBLESHOOT.md +++ b/docs/help/TROUBLESHOOT.md @@ -1,68 +1,91 @@ -# **Frequently Asked Questions** +--- +title: F.A.Q. +--- -Here are a few common installation problems and their solutions. Often these are caused by incomplete installations or crashes during the -install process. +# :material-frequently-asked-questions: F.A.Q. + +## **Frequently-Asked-Questions** + +Here are a few common installation problems and their solutions. Often these are caused by +incomplete installations or crashes during the install process. --- -**QUESTION** +### **QUESTION** During `conda env create -f environment.yaml`, conda hangs indefinitely. -**SOLUTION** +### **SOLUTION** -Enter the stable-diffusion directory and completely remove the `src` directory and all its contents. The safest way to do this is to enter the stable-diffusion directory and give the command `git clean -f`. If this still doesn't fix the problem, try "conda clean -all" and then restart at the `conda env create` step. +Enter the stable-diffusion directory and completely remove the `src` directory and all its contents. +The safest way to do this is to enter the stable-diffusion directory and give the command +`git clean -f`. If this still doesn't fix the problem, try "conda clean -all" and then restart at +the `conda env create` step. --- -**QUESTION** +### **QUESTION** -`dream.py` crashes with the complaint that it can't find `ldm.simplet2i.py`. Or it complains that function is being passed incorrect parameters. +`dream.py` crashes with the complaint that it can't find `ldm.simplet2i.py`. Or it complains that +function is being passed incorrect parameters. -**SOLUTION** +### **SOLUTION** -Reinstall the stable diffusion modules. Enter the `stable-diffusion` directory and give the command `pip install -e .` +Reinstall the stable diffusion modules. Enter the `stable-diffusion` directory and give the command +`pip install -e .` --- -**QUESTION** +### **QUESTION** `dream.py` dies, complaining of various missing modules, none of which starts with `ldm``. -**SOLUTION** +### **SOLUTION** -From within the `stable-diffusion` directory, run `conda env update -f environment.yaml` This is also frequently the solution to -complaints about an unknown function in a module. +From within the `stable-diffusion` directory, run `conda env update -f environment.yaml` This is +also frequently the solution to complaints about an unknown function in a module. --- -**QUESTION** +### **QUESTION** There's a feature or bugfix in the Stable Diffusion GitHub that you want to try out. -**SOLUTION** +### **SOLUTION** -**Main Branch** +#### **Main Branch** -If the fix/feature is on the `main` branch, enter the stable-diffusion directory and do a `git pull`. +If the fix/feature is on the `main` branch, enter the stable-diffusion directory and do a +`git pull`. -Usually this will be sufficient, but if you start to see errors about missing or incorrect modules, use the command `pip install -e .` and/or `conda env update -f environment.yaml` (These commands won't break anything.) +Usually this will be sufficient, but if you start to see errors about missing or incorrect modules, +use the command -**Sub Branch** +`pip install -e .` and/or -If the feature/fix is on a branch (e.g. "_foo-bugfix_"), the recipe is similar, but do a `git pull `. +`conda env update -f environment.yaml` -**Not Committed** +(These commands won't break anything.) -If the feature/fix is in a pull request that has not yet been made part of the main branch or a feature/bugfix branch, then from the page for the desired pull request, look for the line at the top that reads "_xxxx wants to merge xx commits into lstein:main from YYYYYY_". Copy the URL in YYYY. It should have the format `https://github.com//stable-diffusion/tree/` +#### **Sub Branch** -Then **go to the directory above stable-diffusion** and rename the directory to "_stable-diffusion.lstein_", "_stable-diffusion.old_", or anything else. You can then git clone the branch that contains the pull request: +If the feature/fix is on a branch (e.g. "_foo-bugfix_"), the recipe is similar, but do a +`git pull `. -``` -git clone https://github.com//stable-diffusion/tree/ -``` +#### **Not Committed** -You will need to go through the install procedure again, but it should be fast because all the dependencies are already loaded. +If the feature/fix is in a pull request that has not yet been made part of the main branch or a +feature/bugfix branch, then from the page for the desired pull request, look for the line at the top +that reads "_xxxx wants to merge xx commits into lstein:main from YYYYYY_". Copy the URL in YYYY. It +should have the format ---- +`https://github.com//stable-diffusion/tree/` + +Then **go to the directory above stable-diffusion** and rename the directory to +"_stable-diffusion.lstein_", "_stable-diffusion.old_", or anything else. You can then git clone the +branch that contains the pull request: + +`git clone https://github.com//stable-diffusion/tree/` + +You will need to go through the install procedure again, but it should be fast because all the +dependencies are already loaded. diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000000..d58b25e628 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,19 @@ + + + + + + Swagger UI + + + + + + + +
+ + + + + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..c356c2cee5 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,168 @@ +--- +title: Home +template: main.html +--- + + +
+ +# :material-script-text-outline: Stable Diffusion Dream Script + +![project logo](assets/logo.png) + +[![discord badge]][discord link] + +[![latest release badge]][latest release link] [![github stars badge]][github stars link] [![github forks badge]][github forks link] + +[![CI checks on main badge]][CI checks on main link] [![CI checks on dev badge]][CI checks on dev link] [![latest commit to dev badge]][latest commit to dev link] + +[![github open issues badge]][github open issues link] [![github open prs badge]][github open prs link] + +[CI checks on dev badge]: https://flat.badgen.net/github/checks/lstein/stable-diffusion/development?label=CI%20status%20on%20dev&cache=900&icon=github +[CI checks on dev link]: https://github.com/lstein/stable-diffusion/actions?query=branch%3Adevelopment +[CI checks on main badge]: https://flat.badgen.net/github/checks/lstein/stable-diffusion/main?label=CI%20status%20on%20main&cache=900&icon=github +[CI checks on main link]: https://github.com/lstein/stable-diffusion/actions/workflows/test-dream-conda.yml +[discord badge]: https://flat.badgen.net/discord/members/htRgbc7e?icon=discord +[discord link]: https://discord.com/invite/htRgbc7e +[github forks badge]: https://flat.badgen.net/github/forks/lstein/stable-diffusion?icon=github +[github forks link]: https://useful-forks.github.io/?repo=lstein%2Fstable-diffusion +[github open issues badge]: https://flat.badgen.net/github/open-issues/lstein/stable-diffusion?icon=github +[github open issues link]: https://github.com/lstein/stable-diffusion/issues?q=is%3Aissue+is%3Aopen +[github open prs badge]: https://flat.badgen.net/github/open-prs/lstein/stable-diffusion?icon=github +[github open prs link]: https://github.com/lstein/stable-diffusion/pulls?q=is%3Apr+is%3Aopen +[github stars badge]: https://flat.badgen.net/github/stars/lstein/stable-diffusion?icon=github +[github stars link]: https://github.com/lstein/stable-diffusion/stargazers +[latest commit to dev badge]: https://flat.badgen.net/github/last-commit/lstein/stable-diffusion/development?icon=github&color=yellow&label=last%20dev%20commit&cache=900 +[latest commit to dev link]: https://github.com/lstein/stable-diffusion/commits/development +[latest release badge]: https://flat.badgen.net/github/release/lstein/stable-diffusion/development?icon=github +[latest release link]: https://github.com/lstein/stable-diffusion/releases + +
+ +This is a fork of [CompVis/stable-diffusion](https://github.com/CompVis/stable-diffusion), the open +source text-to-image generator. It provides a streamlined process with various new features and +options to aid the image generation process. It runs on Windows, Mac and Linux machines, and runs on +GPU cards with as little as 4 GB or RAM. + +!!! note + + This fork is rapidly evolving. Please use the + [Issues](https://github.com/lstein/stable-diffusion/issues) tab to report bugs and make feature + requests. Be sure to use the provided templates. They will help aid diagnose issues faster. + +## :octicons-package-dependencies-24: Installation + +This fork is supported across multiple platforms. You can find individual installation instructions +below. + +- :fontawesome-brands-linux: [Linux](installation/INSTALL_LINUX.md) +- :fontawesome-brands-windows: [Windows](installation/INSTALL_WINDOWS.md) +- :fontawesome-brands-apple: [Macintosh](installation/INSTALL_MAC.md) + +## :fontawesome-solid-computer: Hardware Requirements + +### :octicons-cpu-24: System + +You wil need one of the following: + +- :simple-nvidia: An NVIDIA-based graphics card with 4 GB or more VRAM memory. +- :fontawesome-brands-apple: An Apple computer with an M1 chip. + +### :fontawesome-solid-memory: Memory + +- At least 12 GB Main Memory RAM. + +### :fontawesome-regular-hard-drive: Disk + +- At least 6 GB of free disk space for the machine learning model, Python, and all its dependencies. + +!!! note + + If you are have a Nvidia 10xx series card (e.g. the 1080ti), please run the dream script in + full-precision mode as shown below. + + Similarly, specify full-precision mode on Apple M1 hardware. + + To run in full-precision mode, start `dream.py` with the `--full_precision` flag: + + ```bash + (ldm) ~/stable-diffusion$ python scripts/dream.py --full_precision + ``` +## :octicons-log-16: Latest Changes + +### vNEXT (TODO 2022) + + - Deprecated `--full_precision` / `-F`. Simply omit it and `dream.py` will auto + configure. To switch away from auto use the new flag like `--precision=float32`. + +### v1.14 (11 September 2022) + +- Memory optimizations for small-RAM cards. 512x512 now possible on 4 GB GPUs. +- Full support for Apple hardware with M1 or M2 chips. +- Add "seamless mode" for circular tiling of image. Generates beautiful effects. + ([prixt](https://github.com/prixt)). +- Inpainting support. +- Improved web server GUI. +- Lots of code and documentation cleanups. + +### v1.13 (3 September 2022 + +- Support image variations (see [VARIATIONS](features/VARIATIONS.md) + ([Kevin Gibbons](https://github.com/bakkot) and many contributors and reviewers) +- Supports a Google Colab notebook for a standalone server running on Google hardware + [Arturo Mendivil](https://github.com/artmen1516) +- WebUI supports GFPGAN/ESRGAN facial reconstruction and upscaling + [Kevin Gibbons](https://github.com/bakkot) +- WebUI supports incremental display of in-progress images during generation + [Kevin Gibbons](https://github.com/bakkot) +- A new configuration file scheme that allows new models (including upcoming stable-diffusion-v1.5) + to be added without altering the code. ([David Wager](https://github.com/maddavid12)) +- Can specify --grid on dream.py command line as the default. +- Miscellaneous internal bug and stability fixes. +- Works on M1 Apple hardware. +- Multiple bug fixes. + +For older changelogs, please visit the **[CHANGELOG](features/CHANGELOG.md)**. + +## :material-target: Troubleshooting + +Please check out our **[:material-frequently-asked-questions: Q&A](help/TROUBLESHOOT.md)** to get solutions for common installation +problems and other issues. + +## :octicons-repo-push-24: Contributing + +Anyone who wishes to contribute to this project, whether documentation, features, bug fixes, code +cleanup, testing, or code reviews, is very much encouraged to do so. If you are unfamiliar with how +to contribute to GitHub projects, here is a +[Getting Started Guide](https://opensource.com/article/19/7/create-pull-request-github). + +A full set of contribution guidelines, along with templates, are in progress, but for now the most +important thing is to **make your pull request against the "development" branch**, and not against +"main". This will help keep public breakage to a minimum and will allow you to propose more radical +changes. + +## :octicons-person-24: Contributors + +This fork is a combined effort of various people from across the world. +[Check out the list of all these amazing people](other/CONTRIBUTORS.md). We thank them for their +time, hard work and effort. + +## :octicons-question-24: Support + +For support, please use this repository's GitHub Issues tracking service. Feel free to send me an +email if you use and like the script. + +Original portions of the software are Copyright (c) 2020 +[Lincoln D. Stein](https://github.com/lstein) + +## :octicons-book-24: Further Reading + +Please see the original README for more information on this software and underlying algorithm, +located in the file [README-CompViz.md](other/README-CompViz.md). diff --git a/docs/installation/INSTALL_DOCKER.md b/docs/installation/INSTALL_DOCKER.md new file mode 100644 index 0000000000..c7dd3582d5 --- /dev/null +++ b/docs/installation/INSTALL_DOCKER.md @@ -0,0 +1,255 @@ +# Before you begin + +- For end users: Install Stable Diffusion locally using the instructions for + your OS. +- For developers: For container-related development tasks or for enabling easy + deployment to other environments (on-premises or cloud), follow these + instructions. For general use, install locally to leverage your machine's GPU. + +# Why containers? + +They provide a flexible, reliable way to build and deploy Stable Diffusion. +You'll also use a Docker volume to store the largest model files and image +outputs as a first step in decoupling storage and compute. Future enhancements +can do this for other assets. See [Processes](https://12factor.net/processes) +under the Twelve-Factor App methodology for details on why running applications +in such a stateless fashion is important. + +You can specify the target platform when building the image and running the +container. You'll also need to specify the Stable Diffusion requirements file +that matches the container's OS and the architecture it will run on. + +Developers on Apple silicon (M1/M2): You +[can't access your GPU cores from Docker containers](https://github.com/pytorch/pytorch/issues/81224) +and performance is reduced compared with running it directly on macOS but for +development purposes it's fine. Once you're done with development tasks on your +laptop you can build for the target platform and architecture and deploy to +another environment with NVIDIA GPUs on-premises or in the cloud. + +# Installation on a Linux container + +## Prerequisites + +### Get the data files + +Go to +[Hugging Face](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original), +and click "Access repository" to Download the model file `sd-v1-4.ckpt` (~4 GB) +to `~/Downloads`. You'll need to create an account but it's quick and free. + +Also download the face restoration model. + +```Shell +cd ~/Downloads +wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth +``` + +### Install [Docker](https://github.com/santisbon/guides#docker) + +On the Docker Desktop app, go to Preferences, Resources, Advanced. Increase the +CPUs and Memory to avoid this +[Issue](https://github.com/invoke-ai/InvokeAI/issues/342). You may need to +increase Swap and Disk image size too. + +## Setup + +Set the fork you want to use and other variables. + +```Shell +TAG_STABLE_DIFFUSION="santisbon/stable-diffusion" +PLATFORM="linux/arm64" +GITHUB_STABLE_DIFFUSION="-b orig-gfpgan https://github.com/santisbon/stable-diffusion.git" +REQS_STABLE_DIFFUSION="requirements-linux-arm64.txt" +CONDA_SUBDIR="osx-arm64" + +echo $TAG_STABLE_DIFFUSION +echo $PLATFORM +echo $GITHUB_STABLE_DIFFUSION +echo $REQS_STABLE_DIFFUSION +echo $CONDA_SUBDIR +``` + +Create a Docker volume for the downloaded model files. + +```Shell +docker volume create my-vol +``` + +Copy the data files to the Docker volume using a lightweight Linux container. +We'll need the models at run time. You just need to create the container with +the mountpoint; no need to run this dummy container. + +```Shell +cd ~/Downloads # or wherever you saved the files + +docker create --platform $PLATFORM --name dummy --mount source=my-vol,target=/data alpine + +docker cp sd-v1-4.ckpt dummy:/data +docker cp GFPGANv1.4.pth dummy:/data +``` + +Get the repo and download the Miniconda installer (we'll need it at build time). +Replace the URL with the version matching your container OS and the architecture +it will run on. + +```Shell +cd ~ +git clone $GITHUB_STABLE_DIFFUSION + +cd stable-diffusion/docker-build +chmod +x entrypoint.sh +wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-aarch64.sh -O anaconda.sh && chmod +x anaconda.sh +``` + +Build the Docker image. Give it any tag `-t` that you want. +Choose the Linux container's host platform: x86-64/Intel is `amd64`. Apple +silicon is `arm64`. If deploying the container to the cloud to leverage powerful +GPU instances you'll be on amd64 hardware but if you're just trying this out +locally on Apple silicon choose arm64. +The application uses libraries that need to match the host environment so use +the appropriate requirements file. +Tip: Check that your shell session has the env variables set above. + +```Shell +docker build -t $TAG_STABLE_DIFFUSION \ +--platform $PLATFORM \ +--build-arg gsd=$GITHUB_STABLE_DIFFUSION \ +--build-arg rsd=$REQS_STABLE_DIFFUSION \ +--build-arg cs=$CONDA_SUBDIR \ +. +``` + +Run a container using your built image. +Tip: Make sure you've created and populated the Docker volume (above). + +```Shell +docker run -it \ +--rm \ +--platform $PLATFORM \ +--name stable-diffusion \ +--hostname stable-diffusion \ +--mount source=my-vol,target=/data \ +$TAG_STABLE_DIFFUSION +``` + +# Usage (time to have fun) + +## Startup + +If you're on a **Linux container** the `dream` script is **automatically +started** and the output dir set to the Docker volume you created earlier. + +If you're **directly on macOS follow these startup instructions**. +With the Conda environment activated (`conda activate ldm`), run the interactive +interface that combines the functionality of the original scripts `txt2img` and +`img2img`: +Use the more accurate but VRAM-intensive full precision math because +half-precision requires autocast and won't work. +By default the images are saved in `outputs/img-samples/`. + +```Shell +python3 scripts/dream.py --full_precision +``` + +You'll get the script's prompt. You can see available options or quit. + +```Shell +dream> -h +dream> q +``` + +## Text to Image + +For quick (but bad) image results test with 5 steps (default 50) and 1 sample +image. This will let you know that everything is set up correctly. +Then increase steps to 100 or more for good (but slower) results. +The prompt can be in quotes or not. + +```Shell +dream> The hulk fighting with sheldon cooper -s5 -n1 +dream> "woman closeup highly detailed" -s 150 +# Reuse previous seed and apply face restoration +dream> "woman closeup highly detailed" --steps 150 --seed -1 -G 0.75 +``` + +You'll need to experiment to see if face restoration is making it better or +worse for your specific prompt. + +If you're on a container the output is set to the Docker volume. You can copy it +wherever you want. +You can download it from the Docker Desktop app, Volumes, my-vol, data. +Or you can copy it from your Mac terminal. Keep in mind `docker cp` can't expand +`*.png` so you'll need to specify the image file name. + +On your host Mac (you can use the name of any container that mounted the +volume): + +```Shell +docker cp dummy:/data/000001.928403745.png /Users//Pictures +``` + +## Image to Image + +You can also do text-guided image-to-image translation. For example, turning a +sketch into a detailed drawing. + +`strength` is a value between 0.0 and 1.0 that controls the amount of noise that +is added to the input image. Values that approach 1.0 allow for lots of +variations but will also produce images that are not semantically consistent +with the input. 0.0 preserves image exactly, 1.0 replaces it completely. + +Make sure your input image size dimensions are multiples of 64 e.g. 512x512. +Otherwise you'll get `Error: product of dimension sizes > 2**31'`. If you still +get the error +[try a different size](https://support.apple.com/guide/preview/resize-rotate-or-flip-an-image-prvw2015/mac#:~:text=image's%20file%20size-,In%20the%20Preview%20app%20on%20your%20Mac%2C%20open%20the%20file,is%20shown%20at%20the%20bottom.) +like 512x256. + +If you're on a Docker container, copy your input image into the Docker volume + +```Shell +docker cp /Users//Pictures/sketch-mountains-input.jpg dummy:/data/ +``` + +Try it out generating an image (or more). The `dream` script needs absolute +paths to find the image so don't use `~`. + +If you're on your Mac + +```Shell +dream> "A fantasy landscape, trending on artstation" -I /Users//Pictures/sketch-mountains-input.jpg --strength 0.75 --steps 100 -n4 +``` + +If you're on a Linux container on your Mac + +```Shell +dream> "A fantasy landscape, trending on artstation" -I /data/sketch-mountains-input.jpg --strength 0.75 --steps 50 -n1 +``` + +## Web Interface + +You can use the `dream` script with a graphical web interface. Start the web +server with: + +```Shell +python3 scripts/dream.py --full_precision --web +``` + +If it's running on your Mac point your Mac web browser to http://127.0.0.1:9090 + +Press Control-C at the command line to stop the web server. + +## Notes + +Some text you can add at the end of the prompt to make it very pretty: + +```Shell +cinematic photo, highly detailed, cinematic lighting, ultra-detailed, ultrarealistic, photorealism, Octane Rendering, cyberpunk lights, Hyper Detail, 8K, HD, Unreal Engine, V-Ray, full hd, cyberpunk, abstract, 3d octane render + 4k UHD + immense detail + dramatic lighting + well lit + black, purple, blue, pink, cerulean, teal, metallic colours, + fine details, ultra photoreal, photographic, concept art, cinematic composition, rule of thirds, mysterious, eerie, photorealism, breathtaking detailed, painting art deco pattern, by hsiao, ron cheng, john james audubon, bizarre compositions, exquisite detail, extremely moody lighting, painted by greg rutkowski makoto shinkai takashi takeuchi studio ghibli, akihiko yoshida +``` + +The original scripts should work as well. + +```Shell +python3 scripts/orig_scripts/txt2img.py --help +python3 scripts/orig_scripts/txt2img.py --ddim_steps 100 --n_iter 1 --n_samples 1 --plms --prompt "new born baby kitten. Hyper Detail, Octane Rendering, Unreal Engine, V-Ray" +python3 scripts/orig_scripts/txt2img.py --ddim_steps 5 --n_iter 1 --n_samples 1 --plms --prompt "ocean" # or --klms +``` diff --git a/docs/installation/INSTALL_LINUX.md b/docs/installation/INSTALL_LINUX.md index 2a64f1eb41..a865016bd5 100644 --- a/docs/installation/INSTALL_LINUX.md +++ b/docs/installation/INSTALL_LINUX.md @@ -1,20 +1,28 @@ -# **Linux Installation** +--- +title: Linux +--- -1. You will need to install the following prerequisites if they are not already available. Use your operating system's preferred installer +# :fontawesome-brands-linux: Linux -- Python (version 3.8.5 recommended; higher may work) -- git +## Installation + +1. You will need to install the following prerequisites if they are not already + available. Use your operating system's preferred installer. + + - Python (version 3.8.5 recommended; higher may work) + - git 2. Install the Python Anaconda environment manager. -``` -~$ wget https://repo.anaconda.com/archive/Anaconda3-2022.05-Linux-x86_64.sh -~$ chmod +x Anaconda3-2022.05-Linux-x86_64.sh -~$ ./Anaconda3-2022.05-Linux-x86_64.sh -``` + ```bash + ~$ wget https://repo.anaconda.com/archive/Anaconda3-2022.05-Linux-x86_64.sh + ~$ chmod +x Anaconda3-2022.05-Linux-x86_64.sh + ~$ ./Anaconda3-2022.05-Linux-x86_64.sh + ``` -After installing anaconda, you should log out of your system and log back in. If the installation -worked, your command prompt will be prefixed by the name of the current anaconda environment - `(base)`. + After installing anaconda, you should log out of your system and log back in. If + the installation worked, your command prompt will be prefixed by the name of the + current anaconda environment - `(base)`. 3. Copy the InvokeAI source code from GitHub: @@ -31,7 +39,9 @@ This will create InvokeAI folder where you will follow the rest of the steps. (base) ~/InvokeAI$ ``` -5. Use anaconda to copy necessary python packages, create a new python environment named `ldm` and activate the environment. +5. Use anaconda to copy necessary python packages, create a new python + environment named `ldm` and activate the environment. + ``` (base) ~/InvokeAI$ conda env create -f environment.yaml @@ -39,24 +49,36 @@ This will create InvokeAI folder where you will follow the rest of the steps. (ldm) ~/InvokeAI$ ``` -After these steps, your command prompt will be prefixed by `(ldm)` as shown above. + After these steps, your command prompt will be prefixed by `(ldm)` as shown + above. 6. Load a couple of small machine-learning models required by stable diffusion: + ``` (ldm) ~/InvokeAI$ python3 scripts/preload_models.py ``` -Note that this step is necessary because I modified the original just-in-time model loading scheme to allow the script to work on GPU machines that are not internet connected. See [Preload Models](../features/OTHER.md#preload-models) + !!! note + + This step is necessary because I modified the original just-in-time + model loading scheme to allow the script to work on GPU machines that are not + internet connected. See [Preload Models](../features/OTHER.md#preload-models) 7. Now you need to install the weights for the stable diffusion model. -- For running with the released weights, you will first need to set up an acount with Hugging Face (https://huggingface.co). -- Use your credentials to log in, and then point your browser at https://huggingface.co/CompVis/stable-diffusion-v-1-4-original. -- You may be asked to sign a license agreement at this point. -- Click on "Files and versions" near the top of the page, and then click on the file named "sd-v1-4.ckpt". You'll be taken to a page that prompts you to click the "download" link. Save the file somewhere safe on your local machine. + - For running with the released weights, you will first need to set up an acount + with [Hugging Face](https://huggingface.co). + - Use your credentials to log in, and then point your browser [here](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original.) + - You may be asked to sign a license agreement at this point. + - Click on "Files and versions" near the top of the page, and then click on the + file named "sd-v1-4.ckpt". You'll be taken to a page that prompts you to click + the "download" link. Save the file somewhere safe on your local machine. + + Now run the following commands from within the stable-diffusion directory. + This will create a symbolic link from the stable-diffusion model.ckpt file, to + the true location of the `sd-v1-4.ckpt` file. -Now run the following commands from within the stable-diffusion directory. This will create a symbolic link from the stable-diffusion model.ckpt file, to the true location of the sd-v1-4.ckpt file. ``` (ldm) ~/InvokeAI$ mkdir -p models/ldm/stable-diffusion-v1 @@ -78,7 +100,8 @@ Now run the following commands from within the stable-diffusion directory. This 9. Subsequently, to relaunch the script, be sure to run "conda activate ldm" (step 5, second command), enter the `InvokeAI` directory, and then launch the dream script (step 8). If you forget to activate the ldm environment, the script will fail with multiple `ModuleNotFound` errors. -### Updating to newer versions of the script +## Updating to newer versions of the script + This distribution is changing rapidly. If you used the `git clone` method (step 5) to download the InvokeAI directory, then to update to the latest and greatest version, launch the Anaconda window, enter `InvokeAI` and type: diff --git a/docs/installation/INSTALL_MAC.md b/docs/installation/INSTALL_MAC.md index c000e818bb..8258ff11f4 100644 --- a/docs/installation/INSTALL_MAC.md +++ b/docs/installation/INSTALL_MAC.md @@ -1,206 +1,338 @@ -# **macOS Instructions** +--- +title: macOS +--- -Requirements +# :fontawesome-brands-apple: macOS + +## Requirements - macOS 12.3 Monterey or later - Python - Patience -- Apple Silicon\* +- Apple Silicon or Intel Mac -\*I haven't tested any of this on Intel Macs but I have read that one person got it to work, so Apple Silicon might not be requried. +Things have moved really fast and so these instructions change often which makes +them outdated pretty fast. One of the problems is that there are so many +different ways to run this. -Things have moved really fast and so these instructions change often -and are often out-of-date. One of the problems is that there are so -many different ways to run this. +We are trying to build a testing setup so that when we make changes it doesn't +always break. -We are trying to build a testing setup so that when we make changes it -doesn't always break. +## How to -How to (this hasn't been 100% tested yet): +(this hasn't been 100% tested yet) -First get the weights checkpoint download started - it's big: +First get the weights checkpoint download started since it's big and will take +some time: -1. Sign up at https://huggingface.co -2. Go to the [Stable diffusion diffusion model page](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original) +1. Sign up at [huggingface.co](https://huggingface.co) +2. Go to the + [Stable diffusion diffusion model page](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original) 3. Accept the terms and click Access Repository: -4. Download [sd-v1-4.ckpt (4.27 GB)](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/blob/main/sd-v1-4.ckpt) and note where you have saved it (probably the Downloads folder) +4. Download + [sd-v1-4.ckpt (4.27 GB)](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/blob/main/sd-v1-4.ckpt) + and note where you have saved it (probably the Downloads folder) -While that is downloading, open Terminal and run the following commands one at a time. +While that is downloading, open a Terminal and run the following commands: -```bash -# install brew (and Xcode command line tools): -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +!!! todo "Homebrew" -# -# Now there are two different routes to get the Python (miniconda) environment up and running: -# 1. Alongside pyenv -# 2. No pyenv -# -# If you don't know what we are talking about, choose 2. -# -# NOW EITHER DO -# 1. Installing alongside pyenv + === "no brew installation yet" -brew install pyenv-virtualenv # you might have this from before, no problem -pyenv install anaconda3-2022.05 -pyenv virtualenv anaconda3-2022.05 -eval "$(pyenv init -)" -pyenv activate anaconda3-2022.05 + ```bash title="install brew (and Xcode command line tools)" + /bin/bash -c \ + "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + ``` -# OR, -# 2. Installing standalone -# install python 3, git, cmake, protobuf: -brew install cmake protobuf rust + === "brew is already installed" + + Only if you installed protobuf in a previous version of this tutorial, otherwise skip -# install miniconda (M1 arm64 version): -curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh -o Miniconda3-latest-MacOSX-arm64.sh -/bin/bash Miniconda3-latest-MacOSX-arm64.sh + `#!bash brew uninstall protobuf` +!!! todo "Conda Installation" -# EITHER WAY, -# continue from here + Now there are two different ways to set up the Python (miniconda) environment: + 1. Standalone + 2. with pyenv + If you don't know what we are talking about, choose Standalone + === "Standalone" + + ```bash + # install cmake and rust: + brew install cmake rust + ``` + + === "M1 arm64" + + ```bash title="Install miniconda for M1 arm64" + curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh \ + -o Miniconda3-latest-MacOSX-arm64.sh + /bin/bash Miniconda3-latest-MacOSX-arm64.sh + ``` + + === "Intel x86_64" + + ```bash title="Install miniconda for Intel" + curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh \ + -o Miniconda3-latest-MacOSX-x86_64.sh + /bin/bash Miniconda3-latest-MacOSX-x86_64.sh + ``` + + === "with pyenv" + + ```{.bash .annotate} + brew install rust pyenv-virtualenv # (1)! + pyenv install anaconda3-2022.05 + pyenv virtualenv anaconda3-2022.05 + eval "$(pyenv init -)" + pyenv activate anaconda3-2022.05 + ``` + + 1. You might already have this installed, if that is the case just continue. + +```{.bash .annotate title="local repo setup"} # clone the repo -git clone https://github.com/lstein/stable-diffusion.git +git clone https://github.com/invoke-ai/InvokeAI.git cd stable-diffusion -# # wait until the checkpoint file has downloaded, then proceed -# # create symlink to checkpoint mkdir -p models/ldm/stable-diffusion-v1/ -PATH_TO_CKPT="$HOME/Downloads" # or wherever you saved sd-v1-4.ckpt +PATH_TO_CKPT="$HOME/Downloads" # (1)! -ln -s "$PATH_TO_CKPT/sd-v1-4.ckpt" models/ldm/stable-diffusion-v1/model.ckpt +ln -s "$PATH_TO_CKPT/sd-v1-4.ckpt" \ + models/ldm/stable-diffusion-v1/model.ckpt +``` -# install packages -PIP_EXISTS_ACTION=w CONDA_SUBDIR=osx-arm64 conda env create -f environment-mac.yaml -conda activate ldm +1. or wherever you saved sd-v1-4.ckpt +!!! todo "create Conda Environment" + + === "M1 arm64" + + ```bash + PIP_EXISTS_ACTION=w CONDA_SUBDIR=osx-arm64 \ + conda env create \ + -f environment-mac.yaml \ + && conda activate ldm + ``` + + === "Intel x86_64" + + ```bash + PIP_EXISTS_ACTION=w CONDA_SUBDIR=osx-x86_64 \ + conda env create \ + -f environment-mac.yaml \ + && conda activate ldm + ``` + +```{.bash .annotate title="preload models and run script"} # only need to do this once python scripts/preload_models.py -# run SD! -python scripts/dream.py --full_precision # half-precision requires autocast and won't work +# now you can run SD in CLI mode +python scripts/dream.py --full_precision # (1)! + +# or run the web interface! +python scripts/dream.py --web + +# The original scripts should work as well. +python scripts/orig_scripts/txt2img.py \ + --prompt "a photograph of an astronaut riding a horse" \ + --plms ``` -The original scripts should work as well. +1. half-precision requires autocast which is unfortunatelly incompatible -``` -python scripts/orig_scripts/txt2img.py --prompt "a photograph of an astronaut riding a horse" --plms -``` +!!! note -Note, `export PIP_EXISTS_ACTION=w` is a precaution to fix `conda env -create -f environment-mac.yaml` never finishing in some situations. So -it isn't required but wont hurt. + `#!bash export PIP_EXISTS_ACTION=w` is a precaution to fix a problem where -After you follow all the instructions and run dream.py you might get several errors. Here's the errors I've seen and found solutions for. + ```bash + conda env create \ + -f environment-mac.yaml + ``` + + did never finish in some situations. So it isn't required but wont hurt. + +--- + +## Common problems + +After you followed all the instructions and try to run dream.py, you might +get several errors. Here's the errors I've seen and found solutions for. ### Is it slow? -Be sure to specify 1 sample and 1 iteration. +```bash title="Be sure to specify 1 sample and 1 iteration." +python ./scripts/orig_scripts/txt2img.py \ + --prompt "ocean" \ + --ddim_steps 5 \ + --n_samples 1 \ + --n_iter 1 +``` - python ./scripts/orig_scripts/txt2img.py --prompt "ocean" --ddim_steps 5 --n_samples 1 --n_iter 1 +--- ### Doesn't work anymore? -PyTorch nightly includes support for MPS. Because of this, this setup is inherently unstable. One morning I woke up and it no longer worked no matter what I did until I switched to miniforge. However, I have another Mac that works just fine with Anaconda. If you can't get it to work, please search a little first because many of the errors will get posted and solved. If you can't find a solution please [create an issue](https://github.com/lstein/stable-diffusion/issues). +PyTorch nightly includes support for MPS. Because of this, this setup is +inherently unstable. One morning I woke up and it no longer worked no matter +what I did until I switched to miniforge. However, I have another Mac that works +just fine with Anaconda. If you can't get it to work, please search a little +first because many of the errors will get posted and solved. If you can't find a +solution please +[create an issue](https://github.com/invoke-ai/InvokeAI/issues). One debugging step is to update to the latest version of PyTorch nightly. - conda install pytorch torchvision torchaudio -c pytorch-nightly +```bash +conda install \ + pytorch \ + torchvision \ + -c pytorch-nightly \ + -n ldm +``` -If `conda env create -f environment-mac.yaml` takes forever run this. +If it takes forever to run - git clean -f +```bash +conda env create \ + -f environment-mac.yaml +``` -And run this. +you could try to run: - conda clean --yes --all +```bash +git clean -f +conda clean \ + --yes \ + --all +``` -Or you could reset Anaconda. +Or you could try to completley reset Anaconda: - conda update --force-reinstall -y -n base -c defaults conda +```bash +conda update \ + --force-reinstall \ + -y \ + -n base \ + -c defaults conda +``` -### "No module named cv2", torch, 'ldm', 'transformers', 'taming', etc. +--- -There are several causes of these errors. +### "No module named cv2", torch, 'ldm', 'transformers', 'taming', etc -First, did you remember to `conda activate ldm`? If your terminal prompt -begins with "(ldm)" then you activated it. If it begins with "(base)" -or something else you haven't. +There are several causes of these errors: -Second, you might've run `./scripts/preload_models.py` or `./scripts/dream.py` -instead of `python ./scripts/preload_models.py` or `python ./scripts/dream.py`. -The cause of this error is long so it's below. +1. Did you remember to `conda activate ldm`? If your terminal prompt begins with + "(ldm)" then you activated it. If it begins with "(base)" or something else + you haven't. -Third, if it says you're missing taming you need to rebuild your virtual -environment. +2. You might've run `./scripts/preload_models.py` or `./scripts/dream.py` + instead of `python ./scripts/preload_models.py` or + `python ./scripts/dream.py`. The cause of this error is long so it's below. + + +3. if it says you're missing taming you need to rebuild your virtual + environment. + + ```bash + conda deactivate conda env remove -n ldm - conda env create -f environment-mac.yaml + PIP_EXISTS_ACTION=w CONDA_SUBDIR=osx-arm64 \ + conda env create \ + -f environment-mac.yaml + ``` -Fourth, If you have activated the ldm virtual environment and tried rebuilding it, maybe the problem could be that I have something installed that you don't and you'll just need to manually install it. Make sure you activate the virtual environment so it installs there instead of -globally. +4. If you have activated the ldm virtual environment and tried rebuilding it, + maybe the problem could be that I have something installed that you don't and + you'll just need to manually install it. Make sure you activate the virtual + environment so it installs there instead of globally. + ```bash conda activate ldm - pip install *name* + pip install + ``` You might also need to install Rust (I mention this again below). +--- + ### How many snakes are living in your computer? You might have multiple Python installations on your system, in which case it's -important to be explicit and consistent about which one to use for a given project. -This is because virtual environments are coupled to the Python that created it (and all -the associated 'system-level' modules). +important to be explicit and consistent about which one to use for a given +project. This is because virtual environments are coupled to the Python that +created it (and all the associated 'system-level' modules). -When you run `python` or `python3`, your shell searches the colon-delimited locations -in the `PATH` environment variable (`echo $PATH` to see that list) in that order - first match wins. -You can ask for the location of the first `python3` found in your `PATH` with the `which` command like this: +When you run `python` or `python3`, your shell searches the colon-delimited +locations in the `PATH` environment variable (`echo $PATH` to see that list) in +that order - first match wins. You can ask for the location of the first +`python3` found in your `PATH` with the `which` command like this: - % which python3 - /usr/bin/python3 +```bash +% which python3 +/usr/bin/python3 +``` -Anything in `/usr/bin` is [part of the OS](https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW6). However, `/usr/bin/python3` is not actually python3, but -rather a stub that offers to install Xcode (which includes python 3). If you have Xcode installed already, -`/usr/bin/python3` will execute `/Library/Developer/CommandLineTools/usr/bin/python3` or +Anything in `/usr/bin` is +[part of the OS](https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW6). +However, `/usr/bin/python3` is not actually python3, but rather a stub that +offers to install Xcode (which includes python 3). If you have Xcode installed +already, `/usr/bin/python3` will execute +`/Library/Developer/CommandLineTools/usr/bin/python3` or `/Applications/Xcode.app/Contents/Developer/usr/bin/python3` (depending on which Xcode you've selected with `xcode-select`). -Note that `/usr/bin/python` is an entirely different python - specifically, python 2. Note: starting in -macOS 12.3, `/usr/bin/python` no longer exists. +Note that `/usr/bin/python` is an entirely different python - specifically, +python 2. Note: starting in macOS 12.3, `/usr/bin/python` no longer exists. - % which python3 - /opt/homebrew/bin/python3 +```bash +% which python3 +/opt/homebrew/bin/python3 +``` If you installed python3 with Homebrew and you've modified your path to search for Homebrew binaries before system ones, you'll see the above path. - % which python - /opt/anaconda3/bin/python +```bash +% which python +/opt/anaconda3/bin/python +``` If you have Anaconda installed, you will see the above path. There is a -`/opt/anaconda3/bin/python3` also. We expect that `/opt/anaconda3/bin/python` -and `/opt/anaconda3/bin/python3` should actually be the *same python*, which you can -verify by comparing the output of `python3 -V` and `python -V`. +`/opt/anaconda3/bin/python3` also. - (ldm) % which python - /Users/name/miniforge3/envs/ldm/bin/python +We expect that `/opt/anaconda3/bin/python` and `/opt/anaconda3/bin/python3` +should actually be the _same python_, which you can verify by comparing the +output of `python3 -V` and `python -V`. -The above is what you'll see if you have miniforge and you've correctly activated -the ldm environment, and you used option 2 in the setup instructions above ("no pyenv"). +```bash +(ldm) % which python +/Users/name/miniforge3/envs/ldm/bin/python +``` - (anaconda3-2022.05) % which python - /Users/name/.pyenv/shims/python - -... and the above is what you'll see if you used option 1 ("Alongside pyenv"). +The above is what you'll see if you have miniforge and correctly activated the +ldm environment, while usingd the standalone setup instructions above. -It's all a mess and you should know [how to modify the path environment variable](https://support.apple.com/guide/terminal/use-environment-variables-apd382cc5fa-4f58-4449-b20a-41c53c006f8f/mac) -if you want to fix it. Here's a brief hint of all the ways you can modify it -(don't really have the time to explain it all here). +If you otherwise installed via pyenv, you will get this result: + +```bash +(anaconda3-2022.05) % which python +/Users/name/.pyenv/shims/python +``` + +It's all a mess and you should know +[how to modify the path environment variable](https://support.apple.com/guide/terminal/use-environment-variables-apd382cc5fa-4f58-4449-b20a-41c53c006f8f/mac) +if you want to fix it. Here's a brief hint of the most common ways you can +modify it (don't really have the time to explain it all here). - ~/.zshrc - ~/.bash_profile @@ -208,53 +340,86 @@ if you want to fix it. Here's a brief hint of all the ways you can modify it - /etc/paths.d - /etc/path -Which one you use will depend on what you have installed except putting a file -in /etc/paths.d is what I prefer to do. +Which one you use will depend on what you have installed, except putting a file +in /etc/paths.d - which also is the way I prefer to do. -Finally, to answer the question posed by this section's title, it may help to list -all of the `python` / `python3` things found in `$PATH` instead of just the one that -will be executed by default. To do that, add the `-a` switch to `which`: +Finally, to answer the question posed by this section's title, it may help to +list all of the `python` / `python3` things found in `$PATH` instead of just the +first hit. To do so, add the `-a` switch to `which`: - % which -a python3 - ... +```bash +% which -a python3 +... +``` + +This will show a list of all binaries which are actually available in your PATH. + +--- ### Debugging? -Tired of waiting for your renders to finish before you can see if it -works? Reduce the steps! The image quality will be horrible but at least you'll -get quick feedback. +Tired of waiting for your renders to finish before you can see if it works? +Reduce the steps! The image quality will be horrible but at least you'll get +quick feedback. - python ./scripts/txt2img.py --prompt "ocean" --ddim_steps 5 --n_samples 1 --n_iter 1 +```bash +python ./scripts/txt2img.py \ + --prompt "ocean" \ + --ddim_steps 5 \ + --n_samples 1 \ + --n_iter 1 +``` -### OSError: Can't load tokenizer for 'openai/clip-vit-large-patch14'... +--- - python scripts/preload_models.py +### OSError: Can't load tokenizer for 'openai/clip-vit-large-patch14' + +```bash +python scripts/preload_models.py +``` + +--- ### "The operator [name] is not current implemented for the MPS device." (sic) -Example error. +!!! example "example error" -``` -... -NotImplementedError: The operator 'aten::_index_put_impl_' is not current implemented for the MPS device. If you want this op to be added in priority during the prototype phase of this feature, please comment on [https://github.com/pytorch/pytorch/issues/77764](https://github.com/pytorch/pytorch/issues/77764). As a temporary fix, you can set the environment variable `PYTORCH_ENABLE_MPS_FALLBACK=1` to use the CPU as a fallback for this op. WARNING: this will be slower than running natively on MPS. -``` + ```bash + ... NotImplementedError: The operator 'aten::_index_put_impl_' is not current + implemented for the MPS device. If you want this op to be added in priority + during the prototype phase of this feature, please comment on + https://github.com/pytorch/pytorch/issues/77764. + As a temporary fix, you can set the environment variable + `PYTORCH_ENABLE_MPS_FALLBACK=1` to use the CPU as a fallback for this op. + WARNING: this will be slower than running natively on MPS. + ``` -The lstein branch includes this fix in [environment-mac.yaml](https://github.com/lstein/stable-diffusion/blob/main/environment-mac.yaml). +This fork already includes a fix for this in +[environment-mac.yaml](https://github.com/invoke-ai/InvokeAI/blob/main/environment-mac.yaml). + +--- ### "Could not build wheels for tokenizers" -I have not seen this error because I had Rust installed on my computer before I started playing with Stable Diffusion. The fix is to install Rust. +I have not seen this error because I had Rust installed on my computer before I +started playing with Stable Diffusion. The fix is to install Rust. - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +```bash +curl \ + --proto '=https' \ + --tlsv1.2 \ + -sSf https://sh.rustup.rs | sh +``` + +--- ### How come `--seed` doesn't work? First this: -> Completely reproducible results are not guaranteed across PyTorch -> releases, individual commits, or different platforms. Furthermore, -> results may not be reproducible between CPU and GPU executions, even -> when using identical seeds. +> Completely reproducible results are not guaranteed across PyTorch releases, +> individual commits, or different platforms. Furthermore, results may not be +> reproducible between CPU and GPU executions, even when using identical seeds. [PyTorch docs](https://pytorch.org/docs/stable/notes/randomness.html) @@ -263,55 +428,68 @@ still working on it. ### libiomp5.dylib error? - OMP: Error #15: Initializing libiomp5.dylib, but found libomp.dylib already initialized. +```bash +OMP: Error #15: Initializing libiomp5.dylib, but found libomp.dylib already initialized. +``` -You are likely using an Intel package by mistake. Be sure to run conda with -the environment variable `CONDA_SUBDIR=osx-arm64`, like so: +You are likely using an Intel package by mistake. Be sure to run conda with the +environment variable `CONDA_SUBDIR=osx-arm64`, like so: `CONDA_SUBDIR=osx-arm64 conda install ...` -This error happens with Anaconda on Macs when the Intel-only `mkl` is pulled in by -a dependency. [nomkl](https://stackoverflow.com/questions/66224879/what-is-the-nomkl-python-package-used-for) +This error happens with Anaconda on Macs when the Intel-only `mkl` is pulled in +by a dependency. +[nomkl](https://stackoverflow.com/questions/66224879/what-is-the-nomkl-python-package-used-for) is a metapackage designed to prevent this, by making it impossible to install `mkl`, but if your environment is already broken it may not work. Do _not_ use `os.environ['KMP_DUPLICATE_LIB_OK']='True'` or equivalents as this masks the underlying issue of using Intel packages. -### Not enough memory. +--- -This seems to be a common problem and is probably the underlying -problem for a lot of symptoms (listed below). The fix is to lower your -image size or to add `model.half()` right after the model is loaded. I -should probably test it out. I've read that the reason this fixes -problems is because it converts the model from 32-bit to 16-bit and -that leaves more RAM for other things. I have no idea how that would -affect the quality of the images though. +### Not enough memory + +This seems to be a common problem and is probably the underlying problem for a +lot of symptoms (listed below). The fix is to lower your image size or to add +`model.half()` right after the model is loaded. I should probably test it out. +I've read that the reason this fixes problems is because it converts the model +from 32-bit to 16-bit and that leaves more RAM for other things. I have no idea +how that would affect the quality of the images though. See [this issue](https://github.com/CompVis/stable-diffusion/issues/71). +--- + ### "Error: product of dimension sizes > 2\*\*31'" -This error happens with img2img, which I haven't played with too much -yet. But I know it's because your image is too big or the resolution -isn't a multiple of 32x32. Because the stable-diffusion model was -trained on images that were 512 x 512, it's always best to use that -output size (which is the default). However, if you're using that size -and you get the above error, try 256 x 256 or 512 x 256 or something -as the source image. +This error happens with img2img, which I haven't played with too much yet. But I +know it's because your image is too big or the resolution isn't a multiple of +32x32. Because the stable-diffusion model was trained on images that were 512 x +512, it's always best to use that output size (which is the default). However, +if you're using that size and you get the above error, try 256 x 256 or 512 x +256 or something as the source image. -BTW, 2\*\*31-1 = [2,147,483,647](https://en.wikipedia.org/wiki/2,147,483,647#In_computing), which is also 32-bit signed [LONG_MAX](https://en.wikipedia.org/wiki/C_data_types) in C. +BTW, 2\*\*31-1 = +[2,147,483,647](https://en.wikipedia.org/wiki/2,147,483,647#In_computing), which +is also 32-bit signed [LONG_MAX](https://en.wikipedia.org/wiki/C_data_types) in +C. + +--- ### I just got Rickrolled! Do I have a virus? You don't have a virus. It's part of the project. Here's -[Rick](https://github.com/lstein/stable-diffusion/blob/main/assets/rick.jpeg) -and here's [the -code](https://github.com/lstein/stable-diffusion/blob/69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc/scripts/txt2img.py#L79) -that swaps him in. It's a NSFW filter, which IMO, doesn't work very -good (and we call this "computer vision", sheesh). +[Rick](https://github.com/invoke-ai/InvokeAI/blob/main/assets/rick.jpeg) +and here's +[the code](https://github.com/invoke-ai/InvokeAI/blob/69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc/scripts/txt2img.py#L79) +that swaps him in. It's a NSFW filter, which IMO, doesn't work very good (and we +call this "computer vision", sheesh). -Actually, this could be happening because there's not enough RAM. You could try the `model.half()` suggestion or specify smaller output images. +Actually, this could be happening because there's not enough RAM. You could try +the `model.half()` suggestion or specify smaller output images. + +--- ### My images come out black @@ -319,31 +497,32 @@ We might have this fixed, we are still testing. There's a [similar issue](https://github.com/CompVis/stable-diffusion/issues/69) on CUDA GPU's where the images come out green. Maybe it's the same issue? -Someone in that issue says to use "--precision full", but this fork -actually disables that flag. I don't know why, someone else provided -that code and I don't know what it does. Maybe the `model.half()` -suggestion above would fix this issue too. I should probably test it. +Someone in that issue says to use "--precision full", but this fork actually +disables that flag. I don't know why, someone else provided that code and I +don't know what it does. Maybe the `model.half()` suggestion above would fix +this issue too. I should probably test it. ### "view size is not compatible with input tensor's size and stride" -``` - File "/opt/anaconda3/envs/ldm/lib/python3.10/site-packages/torch/nn/functional.py", line 2511, in layer_norm - return torch.layer_norm(input, normalized_shape, weight, bias, eps, torch.backends.cudnn.enabled) +```bash +File "/opt/anaconda3/envs/ldm/lib/python3.10/site-packages/torch/nn/functional.py", line 2511, in layer_norm +return torch.layer_norm(input, normalized_shape, weight, bias, eps, torch.backends.cudnn.enabled) RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead. ``` -Update to the latest version of lstein/stable-diffusion. We were -patching pytorch but we found a file in stable-diffusion that we could -change instead. This is a 32-bit vs 16-bit problem. +Update to the latest version of invoke-ai/InvokeAI. We were patching +pytorch but we found a file in stable-diffusion that we could change instead. +This is a 32-bit vs 16-bit problem. + +--- ### The processor must support the Intel bla bla bla What? Intel? On an Apple Silicon? - Intel MKL FATAL ERROR: This system does not meet the minimum requirements for use of the Intel(R) Math Kernel Library. - The processor must support the Intel(R) Supplemental Streaming SIMD Extensions 3 (Intel(R) SSSE3) instructions. - The processor must support the Intel(R) Streaming SIMD Extensions 4.2 (Intel(R) SSE4.2) instructions. - The processor must support the Intel(R) Advanced Vector Extensions (Intel(R) AVX) instructions. +```bash +Intel MKL FATAL ERROR: This system does not meet the minimum requirements for use of the Intel(R) Math Kernel Library. The processor must support the Intel(R) Supplemental Streaming SIMD Extensions 3 (Intel(R) SSSE3) instructions. The processor must support the Intel(R) Streaming SIMD Extensions 4.2 (Intel(R) SSE4.2) instructions. The processor must support the Intel(R) Advanced Vector Extensions (Intel(R) AVX) instructions. +``` This is due to the Intel `mkl` package getting picked up when you try to install something that depends on it-- Rosetta can translate some Intel instructions but @@ -351,11 +530,13 @@ not the specialized ones here. To avoid this, make sure to use the environment variable `CONDA_SUBDIR=osx-arm64`, which restricts the Conda environment to only use ARM packages, and use `nomkl` as described above. +--- + ### input types 'tensor<2x1280xf32>' and 'tensor<\*xf16>' are not broadcast compatible May appear when just starting to generate, e.g.: -``` +```bash dream> clouds Generating: 0%| | 0/1 [00:004 GB in size, so - downloading may take a while. + - For running with the released weights, you will first need to set up an + acount with [Hugging Face](https://huggingface.co). + - Use your credentials to log in, and then point your browser at + [https://huggingface.co/CompVis/stable-diffusion-v-1-4-original](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original). + - You may be asked to sign a license agreement at this point. + - Click on "Files and versions" near the top of the page, and then click on + the file named `sd-v1-4.ckpt`. You'll be taken to a page that prompts you + to click the "download" link. Now save the file somewhere safe on your + local machine. + - The weight file is >4 GB in size, so downloading may take a while. -Now run the following commands from **within the stable-diffusion directory** to copy the weights file to the right place: + Now run the following commands from **within the stable-diffusion directory** + to copy the weights file to the right place: -``` -mkdir -p models\ldm\stable-diffusion-v1 -copy C:\path\to\sd-v1-4.ckpt models\ldm\stable-diffusion-v1\model.ckpt -``` + ```batch + mkdir -p models\ldm\stable-diffusion-v1 + copy C:\path\to\sd-v1-4.ckpt models\ldm\stable-diffusion-v1\model.ckpt + ``` -Please replace `C:\path\to\sd-v1.4.ckpt` with the correct path to wherever you stashed this file. If you prefer not to copy or move the .ckpt file, -you may instead create a shortcut to it from within `models\ldm\stable-diffusion-v1\`. + Please replace `C:\path\to\sd-v1.4.ckpt` with the correct path to wherever + you stashed this file. If you prefer not to copy or move the .ckpt file, you + may instead create a shortcut to it from within + `models\ldm\stable-diffusion-v1\`. 9. Start generating images! -``` -# for the pre-release weights -python scripts\dream.py -l + ```batch + # for the pre-release weights + python scripts\dream.py -l -# for the post-release weights -python scripts\dream.py -``` + # for the post-release weights + python scripts\dream.py + ``` -10. Subsequently, to relaunch the script, first activate the Anaconda command window (step 3),enter the stable-diffusion directory (step 5, `cd \path\to\stable-diffusion`), run `conda activate ldm` (step 6b), and then launch the dream script (step 9). +10. Subsequently, to relaunch the script, first activate the Anaconda command + window (step 3),enter the stable-diffusion directory (step 5, + `cd \path\to\stable-diffusion`), run `conda activate ldm` (step 6b), and + then launch the dream script (step 9). -**Note:** Tildebyte has written an alternative ["Easy peasy Windows -install"](https://github.com/lstein/stable-diffusion/wiki/Easy-peasy-Windows-install) -which uses the Windows Powershell and pew. If you are having trouble with Anaconda on Windows, give this a try (or try it first!) + **Note:** Tildebyte has written an alternative + ["Easy peasy Windows install"](https://github.com/invoke-ai/InvokeAI/wiki/Easy-peasy-Windows-install) + which uses the Windows Powershell and pew. If you are having trouble with + Anaconda on Windows, give this a try (or try it first!) -### Updating to newer versions of the script +--- -This distribution is changing rapidly. If you used the `git clone` method (step 5) to download the stable-diffusion directory, then to update to the latest and greatest version, launch the Anaconda window, enter `stable-diffusion`, and type: +## Updating to newer versions of the script -``` +This distribution is changing rapidly. If you used the `git clone` method +(step 5) to download the stable-diffusion directory, then to update to the +latest and greatest version, launch the Anaconda window, enter +`stable-diffusion`, and type: + +```batch git pull conda env update -f environment.yaml ``` diff --git a/docs/openapi3_0.yaml b/docs/openapi3_0.yaml new file mode 100644 index 0000000000..86dfca6783 --- /dev/null +++ b/docs/openapi3_0.yaml @@ -0,0 +1,73 @@ +openapi: 3.0.3 +info: + title: Stable Diffusion + description: |- + TODO: Description Here + + Some useful links: + - [Stable Diffusion Dream Server](https://github.com/lstein/stable-diffusion) + + license: + name: MIT License + url: https://github.com/lstein/stable-diffusion/blob/main/LICENSE + version: 1.0.0 +servers: + - url: http://localhost:9090/api +tags: + - name: images + description: Retrieve and manage generated images +paths: + /images/{imageId}: + get: + tags: + - images + summary: Get image by ID + description: Returns a single image + operationId: getImageById + parameters: + - name: imageId + in: path + description: ID of image to return + required: true + schema: + type: string + responses: + '200': + description: successful operation + content: + image/png: + schema: + type: string + format: binary + '404': + description: Image not found + /intermediates/{intermediateId}/{step}: + get: + tags: + - images + summary: Get intermediate image by ID + description: Returns a single intermediate image + operationId: getIntermediateById + parameters: + - name: intermediateId + in: path + description: ID of intermediate to return + required: true + schema: + type: string + - name: step + in: path + description: The generation step of the intermediate + required: true + schema: + type: string + responses: + '200': + description: successful operation + content: + image/png: + schema: + type: string + format: binary + '404': + description: Intermediate not found diff --git a/docs/CONTRIBUTORS.md b/docs/other/CONTRIBUTORS.md similarity index 76% rename from docs/CONTRIBUTORS.md rename to docs/other/CONTRIBUTORS.md index 57a9d5cd38..8f40419791 100644 --- a/docs/CONTRIBUTORS.md +++ b/docs/other/CONTRIBUTORS.md @@ -1,14 +1,19 @@ -# Contributors +--- +title: Contributors +--- -The list of all the amazing people who have contributed to the various features that you get to experience in this fork. +# :octicons-person-24: Contributors + +The list of all the amazing people who have contributed to the various features that you get to +experience in this fork. We thank them for all of their time and hard work. -_Original Author:_ +## **Original Author:** -- Lincoln D. Stein +- [Lincoln D. Stein](mailto:lincoln.stein@gmail.com) -_Contributions by:_ +## **Contributions by:** - [Sean McLellan](https://github.com/Oceanswave) - [Kevin Gibbons](https://github.com/bakkot) @@ -45,8 +50,15 @@ _Contributions by:_ - [Paul Sajna](https://github.com/sajattack) - [Samuel Husso](https://github.com/shusso) - [nicolai256](https://github.com/nicolai256) +- [Mihai](https://github.com/mh-dm) +- [Any Winter](https://github.com/any-winter-4079) +- [Doggettx](https://github.com/doggettx) +- [Matthias Wild](https://github.com/mauwii) +- [Kyle Schouviller](https://github.com/kyle0654) +- [rabidcopy](https://github.com/rabidcopy) +- [Dominic Letz](https://github.com/dominicletz) -_Original CompVis Authors:_ +## **Original CompVis Authors:** - [Robin Rombach](https://github.com/rromb) - [Patrick von Platen](https://github.com/patrickvonplaten) @@ -58,4 +70,5 @@ _Original CompVis Authors:_ --- -_If you have contributed and don't see your name on the list of contributors, please let one of the collaborators know about the omission, or feel free to make a pull request._ +_If you have contributed and don't see your name on the list of contributors, please let one of the +collaborators know about the omission, or feel free to make a pull request._ diff --git a/docs/README-CompViz.md b/docs/other/README-CompViz.md similarity index 52% rename from docs/README-CompViz.md rename to docs/other/README-CompViz.md index ed7df6a4ea..395612092f 100644 --- a/docs/README-CompViz.md +++ b/docs/other/README-CompViz.md @@ -1,6 +1,12 @@ -# Original README from CompViz/stable-diffusion +--- +title: CompViz-Readme +--- -_Stable Diffusion was made possible thanks to a collaboration with [Stability AI](https://stability.ai/) and [Runway](https://runwayml.com/) and builds upon our previous work:_ +# _README from [CompViz/stable-diffusion](https://github.com/CompVis/stable-diffusion)_ + +_Stable Diffusion was made possible thanks to a collaboration with +[Stability AI](https://stability.ai/) and [Runway](https://runwayml.com/) and +builds upon our previous work:_ [**High-Resolution Image Synthesis with Latent Diffusion Models**](https://ommer-lab.com/research/latent-diffusion-models/)
[Robin Rombach](https://github.com/rromb)\*, @@ -9,32 +15,40 @@ _Stable Diffusion was made possible thanks to a collaboration with [Stability AI [Patrick Esser](https://github.com/pesser), [Björn Ommer](https://hci.iwr.uni-heidelberg.de/Staff/bommer)
-**CVPR '22 Oral** +## **CVPR '22 Oral** -which is available on [GitHub](https://github.com/CompVis/latent-diffusion). PDF at [arXiv](https://arxiv.org/abs/2112.10752). Please also visit our [Project page](https://ommer-lab.com/research/latent-diffusion-models/). +which is available on [GitHub](https://github.com/CompVis/latent-diffusion). PDF +at [arXiv](https://arxiv.org/abs/2112.10752). Please also visit our +[Project page](https://ommer-lab.com/research/latent-diffusion-models/). ![txt2img-stable2](../assets/stable-samples/txt2img/merged-0006.png) [Stable Diffusion](#stable-diffusion-v1) is a latent text-to-image diffusion -model. -Thanks to a generous compute donation from [Stability AI](https://stability.ai/) and support from [LAION](https://laion.ai/), we were able to train a Latent Diffusion Model on 512x512 images from a subset of the [LAION-5B](https://laion.ai/blog/laion-5b/) database. -Similar to Google's [Imagen](https://arxiv.org/abs/2205.11487), -this model uses a frozen CLIP ViT-L/14 text encoder to condition the model on text prompts. -With its 860M UNet and 123M text encoder, the model is relatively lightweight and runs on a GPU with at least 10GB VRAM. -See [this section](#stable-diffusion-v1) below and the [model card](https://huggingface.co/CompVis/stable-diffusion). +model. Thanks to a generous compute donation from +[Stability AI](https://stability.ai/) and support from +[LAION](https://laion.ai/), we were able to train a Latent Diffusion Model on +512x512 images from a subset of the [LAION-5B](https://laion.ai/blog/laion-5b/) +database. Similar to Google's [Imagen](https://arxiv.org/abs/2205.11487), this +model uses a frozen CLIP ViT-L/14 text encoder to condition the model on text +prompts. With its 860M UNet and 123M text encoder, the model is relatively +lightweight and runs on a GPU with at least 10GB VRAM. See +[this section](#stable-diffusion-v1) below and the +[model card](https://huggingface.co/CompVis/stable-diffusion). ## Requirements -A suitable [conda](https://conda.io/) environment named `ldm` can be created -and activated with: +A suitable [conda](https://conda.io/) environment named `ldm` can be created and +activated with: -``` +```bash conda env create -f environment.yaml conda activate ldm ``` -You can also update an existing [latent diffusion](https://github.com/CompVis/latent-diffusion) environment by running +You can also update an existing +[latent diffusion](https://github.com/CompVis/latent-diffusion) environment by +running -``` +```bash conda install pytorch torchvision -c pytorch pip install transformers==4.19.2 pip install -e . @@ -42,42 +56,57 @@ pip install -e . ## Stable Diffusion v1 -Stable Diffusion v1 refers to a specific configuration of the model -architecture that uses a downsampling-factor 8 autoencoder with an 860M UNet -and CLIP ViT-L/14 text encoder for the diffusion model. The model was pretrained on 256x256 images and -then finetuned on 512x512 images. +Stable Diffusion v1 refers to a specific configuration of the model architecture +that uses a downsampling-factor 8 autoencoder with an 860M UNet and CLIP +ViT-L/14 text encoder for the diffusion model. The model was pretrained on +256x256 images and then finetuned on 512x512 images. -\*Note: Stable Diffusion v1 is a general text-to-image diffusion model and therefore mirrors biases and (mis-)conceptions that are present -in its training data. -Details on the training procedure and data, as well as the intended use of the model can be found in the corresponding [model card](https://huggingface.co/CompVis/stable-diffusion). -Research into the safe deployment of general text-to-image models is an ongoing effort. To prevent misuse and harm, we currently provide access to the checkpoints only for [academic research purposes upon request](https://stability.ai/academia-access-form). -**This is an experiment in safe and community-driven publication of a capable and general text-to-image model. We are working on a public release with a more permissive license that also incorporates ethical considerations.\*** +\*Note: Stable Diffusion v1 is a general text-to-image diffusion model and +therefore mirrors biases and (mis-)conceptions that are present in its training +data. Details on the training procedure and data, as well as the intended use of +the model can be found in the corresponding +[model card](https://huggingface.co/CompVis/stable-diffusion). Research into the +safe deployment of general text-to-image models is an ongoing effort. To prevent +misuse and harm, we currently provide access to the checkpoints only for +[academic research purposes upon request](https://stability.ai/academia-access-form). +**This is an experiment in safe and community-driven publication of a capable +and general text-to-image model. We are working on a public release with a more +permissive license that also incorporates ethical considerations.\*** [Request access to Stable Diffusion v1 checkpoints for academic research](https://stability.ai/academia-access-form) ### Weights -We currently provide three checkpoints, `sd-v1-1.ckpt`, `sd-v1-2.ckpt` and `sd-v1-3.ckpt`, -which were trained as follows, +We currently provide three checkpoints, `sd-v1-1.ckpt`, `sd-v1-2.ckpt` and +`sd-v1-3.ckpt`, which were trained as follows, -- `sd-v1-1.ckpt`: 237k steps at resolution `256x256` on [laion2B-en](https://huggingface.co/datasets/laion/laion2B-en). - 194k steps at resolution `512x512` on [laion-high-resolution](https://huggingface.co/datasets/laion/laion-high-resolution) (170M examples from LAION-5B with resolution `>= 1024x1024`). -- `sd-v1-2.ckpt`: Resumed from `sd-v1-1.ckpt`. - 515k steps at resolution `512x512` on "laion-improved-aesthetics" (a subset of laion2B-en, - filtered to images with an original size `>= 512x512`, estimated aesthetics score `> 5.0`, and an estimated watermark probability `< 0.5`. The watermark estimate is from the LAION-5B metadata, the aesthetics score is estimated using an [improved aesthetics estimator](https://github.com/christophschuhmann/improved-aesthetic-predictor)). -- `sd-v1-3.ckpt`: Resumed from `sd-v1-2.ckpt`. 195k steps at resolution `512x512` on "laion-improved-aesthetics" and 10\% dropping of the text-conditioning to improve [classifier-free guidance sampling](https://arxiv.org/abs/2207.12598). +- `sd-v1-1.ckpt`: 237k steps at resolution `256x256` on + [laion2B-en](https://huggingface.co/datasets/laion/laion2B-en). 194k steps at + resolution `512x512` on + [laion-high-resolution](https://huggingface.co/datasets/laion/laion-high-resolution) + (170M examples from LAION-5B with resolution `>= 1024x1024`). +- `sd-v1-2.ckpt`: Resumed from `sd-v1-1.ckpt`. 515k steps at resolution + `512x512` on "laion-improved-aesthetics" (a subset of laion2B-en, filtered to + images with an original size `>= 512x512`, estimated aesthetics score `> 5.0`, + and an estimated watermark probability `< 0.5`. The watermark estimate is from + the LAION-5B metadata, the aesthetics score is estimated using an + [improved aesthetics estimator](https://github.com/christophschuhmann/improved-aesthetic-predictor)). +- `sd-v1-3.ckpt`: Resumed from `sd-v1-2.ckpt`. 195k steps at resolution + `512x512` on "laion-improved-aesthetics" and 10\% dropping of the + text-conditioning to improve + [classifier-free guidance sampling](https://arxiv.org/abs/2207.12598). Evaluations with different classifier-free guidance scales (1.5, 2.0, 3.0, 4.0, -5.0, 6.0, 7.0, 8.0) and 50 PLMS sampling -steps show the relative improvements of the checkpoints: -![sd evaluation results](../assets/v1-variants-scores.jpg) +5.0, 6.0, 7.0, 8.0) and 50 PLMS sampling steps show the relative improvements of +the checkpoints: ![sd evaluation results](../assets/v1-variants-scores.jpg) ### Text-to-Image with Stable Diffusion ![txt2img-stable2](../assets/stable-samples/txt2img/merged-0005.png) ![txt2img-stable2](../assets/stable-samples/txt2img/merged-0007.png) -Stable Diffusion is a latent diffusion model conditioned on the (non-pooled) text embeddings of a CLIP ViT-L/14 text encoder. +Stable Diffusion is a latent diffusion model conditioned on the (non-pooled) +text embeddings of a CLIP ViT-L/14 text encoder. #### Sampling Script @@ -94,8 +123,11 @@ and sample with python scripts/txt2img.py --prompt "a photograph of an astronaut riding a horse" --plms ``` -By default, this uses a guidance scale of `--scale 7.5`, [Katherine Crowson's implementation](https://github.com/CompVis/latent-diffusion/pull/51) of the [PLMS](https://arxiv.org/abs/2202.09778) sampler, -and renders images of size 512x512 (which it was trained on) in 50 steps. All supported arguments are listed below (type `python scripts/txt2img.py --help`). +By default, this uses a guidance scale of `--scale 7.5`, +[Katherine Crowson's implementation](https://github.com/CompVis/latent-diffusion/pull/51) +of the [PLMS](https://arxiv.org/abs/2202.09778) sampler, and renders images of +size 512x512 (which it was trained on) in 50 steps. All supported arguments are +listed below (type `python scripts/txt2img.py --help`). ```commandline usage: txt2img.py [-h] [--prompt [PROMPT]] [--outdir [OUTDIR]] [--skip_grid] [--skip_save] [--ddim_steps DDIM_STEPS] [--plms] [--laion400m] [--fixed_code] [--ddim_eta DDIM_ETA] [--n_iter N_ITER] [--H H] [--W W] [--C C] [--f F] [--n_samples N_SAMPLES] [--n_rows N_ROWS] @@ -133,14 +165,17 @@ optional arguments: ``` -Note: The inference config for all v1 versions is designed to be used with EMA-only checkpoints. -For this reason `use_ema=False` is set in the configuration, otherwise the code will try to switch from -non-EMA to EMA weights. If you want to examine the effect of EMA vs no EMA, we provide "full" checkpoints -which contain both types of weights. For these, `use_ema=False` will load and use the non-EMA weights. +Note: The inference config for all v1 versions is designed to be used with +EMA-only checkpoints. For this reason `use_ema=False` is set in the +configuration, otherwise the code will try to switch from non-EMA to EMA +weights. If you want to examine the effect of EMA vs no EMA, we provide "full" +checkpoints which contain both types of weights. For these, `use_ema=False` will +load and use the non-EMA weights. #### Diffusers Integration -Another way to download and sample Stable Diffusion is by using the [diffusers library](https://github.com/huggingface/diffusers/tree/main#new--stable-diffusion-is-now-fully-compatible-with-diffusers) +Another way to download and sample Stable Diffusion is by using the +[diffusers library](https://github.com/huggingface/diffusers/tree/main#new--stable-diffusion-is-now-fully-compatible-with-diffusers) ```py # make sure you're logged in with `huggingface-cli login` @@ -161,18 +196,23 @@ image.save("astronaut_rides_horse.png") ### Image Modification with Stable Diffusion -By using a diffusion-denoising mechanism as first proposed by [SDEdit](https://arxiv.org/abs/2108.01073), the model can be used for different -tasks such as text-guided image-to-image translation and upscaling. Similar to the txt2img sampling script, -we provide a script to perform image modification with Stable Diffusion. +By using a diffusion-denoising mechanism as first proposed by +[SDEdit](https://arxiv.org/abs/2108.01073), the model can be used for different +tasks such as text-guided image-to-image translation and upscaling. Similar to +the txt2img sampling script, we provide a script to perform image modification +with Stable Diffusion. -The following describes an example where a rough sketch made in [Pinta](https://www.pinta-project.com/) is converted into a detailed artwork. +The following describes an example where a rough sketch made in +[Pinta](https://www.pinta-project.com/) is converted into a detailed artwork. ``` python scripts/img2img.py --prompt "A fantasy landscape, trending on artstation" --init-img --strength 0.8 ``` -Here, strength is a value between 0.0 and 1.0, that controls the amount of noise that is added to the input image. -Values that approach 1.0 allow for lots of variations but will also produce images that are not semantically consistent with the input. See the following example. +Here, strength is a value between 0.0 and 1.0, that controls the amount of noise +that is added to the input image. Values that approach 1.0 allow for lots of +variations but will also produce images that are not semantically consistent +with the input. See the following example. **Input** @@ -183,15 +223,19 @@ Values that approach 1.0 allow for lots of variations but will also produce imag ![out3](../assets/stable-samples/img2img/mountains-3.png) ![out2](../assets/stable-samples/img2img/mountains-2.png) -This procedure can, for example, also be used to upscale samples from the base model. +This procedure can, for example, also be used to upscale samples from the base +model. ## Comments -- Our codebase for the diffusion models builds heavily on [OpenAI's ADM codebase](https://github.com/openai/guided-diffusion) - and [https://github.com/lucidrains/denoising-diffusion-pytorch](https://github.com/lucidrains/denoising-diffusion-pytorch). +- Our codebase for the diffusion models builds heavily on + [OpenAI's ADM codebase](https://github.com/openai/guided-diffusion) and + [https://github.com/lucidrains/denoising-diffusion-pytorch](https://github.com/lucidrains/denoising-diffusion-pytorch). Thanks for open-sourcing! -- The implementation of the transformer encoder is from [x-transformers](https://github.com/lucidrains/x-transformers) by [lucidrains](https://github.com/lucidrains?tab=repositories). +- The implementation of the transformer encoder is from + [x-transformers](https://github.com/lucidrains/x-transformers) by + [lucidrains](https://github.com/lucidrains?tab=repositories). ## BibTeX diff --git a/docs/swagger-ui/favicon-16x16.png b/docs/swagger-ui/favicon-16x16.png new file mode 100644 index 0000000000..8b194e617a Binary files /dev/null and b/docs/swagger-ui/favicon-16x16.png differ diff --git a/docs/swagger-ui/favicon-32x32.png b/docs/swagger-ui/favicon-32x32.png new file mode 100644 index 0000000000..249737fe44 Binary files /dev/null and b/docs/swagger-ui/favicon-32x32.png differ diff --git a/docs/swagger-ui/index.css b/docs/swagger-ui/index.css new file mode 100644 index 0000000000..f2376fdaa8 --- /dev/null +++ b/docs/swagger-ui/index.css @@ -0,0 +1,16 @@ +html { + box-sizing: border-box; + overflow: -moz-scrollbars-vertical; + overflow-y: scroll; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +body { + margin: 0; + background: #fafafa; +} diff --git a/docs/swagger-ui/oauth2-redirect.html b/docs/swagger-ui/oauth2-redirect.html new file mode 100644 index 0000000000..5640917181 --- /dev/null +++ b/docs/swagger-ui/oauth2-redirect.html @@ -0,0 +1,79 @@ + + + + Swagger UI: OAuth2 Redirect + + + + + diff --git a/docs/swagger-ui/swagger-initializer.js b/docs/swagger-ui/swagger-initializer.js new file mode 100644 index 0000000000..5ab64bd9f9 --- /dev/null +++ b/docs/swagger-ui/swagger-initializer.js @@ -0,0 +1,20 @@ +window.onload = function() { + // + + // the following lines will be replaced by docker/configurator, when it runs in a docker-container + window.ui = SwaggerUIBundle({ + url: "openapi3_0.yaml", + dom_id: '#swagger-ui', + deepLinking: true, + presets: [ + SwaggerUIBundle.presets.apis, + SwaggerUIStandalonePreset + ], + plugins: [ + SwaggerUIBundle.plugins.DownloadUrl + ], + layout: "StandaloneLayout" + }); + + // +}; diff --git a/docs/swagger-ui/swagger-ui-bundle.js b/docs/swagger-ui/swagger-ui-bundle.js new file mode 100644 index 0000000000..3d6c34e73a --- /dev/null +++ b/docs/swagger-ui/swagger-ui-bundle.js @@ -0,0 +1,3 @@ +/*! For license information please see swagger-ui-bundle.js.LICENSE.txt */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUIBundle=t():e.SwaggerUIBundle=t()}(this,(function(){return(()=>{var e={17967:(e,t)=>{"use strict";t.N=void 0;var r=/^([^\w]*)(javascript|data|vbscript)/im,n=/&#(\w+)(^\w|;)?/g,o=/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim,a=/^([^:]+):/gm,i=[".","/"];t.N=function(e){var t,s=(t=e||"",t.replace(n,(function(e,t){return String.fromCharCode(t)}))).replace(o,"").trim();if(!s)return"about:blank";if(function(e){return i.indexOf(e[0])>-1}(s))return s;var l=s.match(a);if(!l)return s;var u=l[0];return r.test(u)?"about:blank":s}},53795:(e,t,r)=>{"use strict";r.d(t,{Z:()=>P});var n=r(23101),o=r.n(n),a=r(61125),i=r.n(a),s=r(11882),l=r.n(s),u=r(97606),c=r.n(u),p=r(67294),f=r(43393);function h(e){return h="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},h(e)}function d(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function m(e,t){for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{},r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=k(t,r),o=e||Object.keys(y({},r,{},t));return o.every(n)}function k(e,t){return function(r){if("string"==typeof r)return(0,f.is)(t[r],e[r]);if(Array.isArray(r))return(0,f.is)(S(t,r),S(e,r));throw new TypeError("Invalid key: expected Array or string: "+r)}}var C=function(e){function t(){return d(this,t),E(this,b(t).apply(this,arguments))}var r,n,o;return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&w(e,t)}(t,e),r=t,n=[{key:"shouldComponentUpdate",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return!A(this.updateOnProps,this.props,e,"updateOnProps")||!A(this.updateOnStates,this.state,t,"updateOnStates")}}],n&&m(r.prototype,n),o&&m(r,o),t}(p.Component);const O=C;var j=r(23930),I=r.n(j),N=r(45697),T=r.n(N);class P extends O{constructor(){super(...arguments),i()(this,"getModelName",(e=>-1!==l()(e).call(e,"#/definitions/")?e.replace(/^.*#\/definitions\//,""):-1!==l()(e).call(e,"#/components/schemas/")?e.replace(/^.*#\/components\/schemas\//,""):void 0)),i()(this,"getRefSchema",(e=>{let{specSelectors:t}=this.props;return t.findDefinition(e)}))}render(){let{getComponent:e,getConfigs:t,specSelectors:n,schema:a,required:i,name:s,isRef:l,specPath:u,displayName:c,includeReadOnly:f,includeWriteOnly:h}=this.props;const d=e("ObjectModel"),m=e("ArrayModel"),g=e("PrimitiveModel");let v="object",y=a&&a.get("$$ref");if(!s&&y&&(s=this.getModelName(y)),!a&&y&&(a=this.getRefSchema(s)),!a)return p.createElement("span",{className:"model model-title"},p.createElement("span",{className:"model-title__text"},c||s),p.createElement("img",{src:r(2517),height:"20px",width:"20px"}));const b=n.isOAS3()&&a.get("deprecated");switch(l=void 0!==l?l:!!y,v=a&&a.get("type")||v,v){case"object":return p.createElement(d,o()({className:"object"},this.props,{specPath:u,getConfigs:t,schema:a,name:s,deprecated:b,isRef:l,includeReadOnly:f,includeWriteOnly:h}));case"array":return p.createElement(m,o()({className:"array"},this.props,{getConfigs:t,schema:a,name:s,deprecated:b,required:i,includeReadOnly:f,includeWriteOnly:h}));default:return p.createElement(g,o()({},this.props,{getComponent:e,getConfigs:t,schema:a,name:s,deprecated:b,required:i}))}}}i()(P,"propTypes",{schema:c()(I()).isRequired,getComponent:T().func.isRequired,getConfigs:T().func.isRequired,specSelectors:T().object.isRequired,name:T().string,displayName:T().string,isRef:T().bool,required:T().bool,expandDepth:T().number,depth:T().number,specPath:I().list.isRequired,includeReadOnly:T().bool,includeWriteOnly:T().bool})},5623:(e,t,r)=>{"use strict";r.d(t,{Z:()=>f});var n=r(61125),o=r.n(n),a=r(28222),i=r.n(a),s=r(67294),l=r(84564),u=r.n(l),c=r(90242),p=r(27504);class f extends s.Component{constructor(e,t){super(e,t),o()(this,"getDefinitionUrl",(()=>{let{specSelectors:e}=this.props;return new(u())(e.url(),p.Z.location).toString()}));let{getConfigs:r}=e,{validatorUrl:n}=r();this.state={url:this.getDefinitionUrl(),validatorUrl:void 0===n?"https://validator.swagger.io/validator":n}}UNSAFE_componentWillReceiveProps(e){let{getConfigs:t}=e,{validatorUrl:r}=t();this.setState({url:this.getDefinitionUrl(),validatorUrl:void 0===r?"https://validator.swagger.io/validator":r})}render(){let{getConfigs:e}=this.props,{spec:t}=e(),r=(0,c.Nm)(this.state.validatorUrl);return"object"==typeof t&&i()(t).length?null:this.state.url&&(0,c.hW)(this.state.validatorUrl)&&(0,c.hW)(this.state.url)?s.createElement("span",{className:"float-right"},s.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:`${r}/debug?url=${encodeURIComponent(this.state.url)}`},s.createElement(h,{src:`${r}?url=${encodeURIComponent(this.state.url)}`,alt:"Online validator badge"}))):null}}class h extends s.Component{constructor(e){super(e),this.state={loaded:!1,error:!1}}componentDidMount(){const e=new Image;e.onload=()=>{this.setState({loaded:!0})},e.onerror=()=>{this.setState({error:!0})},e.src=this.props.src}UNSAFE_componentWillReceiveProps(e){if(e.src!==this.props.src){const t=new Image;t.onload=()=>{this.setState({loaded:!0})},t.onerror=()=>{this.setState({error:!0})},t.src=e.src}}render(){return this.state.error?s.createElement("img",{alt:"Error"}):this.state.loaded?s.createElement("img",{src:this.props.src,alt:this.props.alt}):null}}},86019:(e,t,r)=>{"use strict";r.d(t,{Z:()=>me,s:()=>ge});var n=r(67294),o=r(89927);function a(e,t){if(Array.prototype.indexOf)return e.indexOf(t);for(var r=0,n=e.length;r=0;r--)!0===t(e[r])&&e.splice(r,1)}function s(e){throw new Error("Unhandled case for value: '"+e+"'")}var l=function(){function e(e){void 0===e&&(e={}),this.tagName="",this.attrs={},this.innerHTML="",this.whitespaceRegex=/\s+/,this.tagName=e.tagName||"",this.attrs=e.attrs||{},this.innerHTML=e.innerHtml||e.innerHTML||""}return e.prototype.setTagName=function(e){return this.tagName=e,this},e.prototype.getTagName=function(){return this.tagName||""},e.prototype.setAttr=function(e,t){return this.getAttrs()[e]=t,this},e.prototype.getAttr=function(e){return this.getAttrs()[e]},e.prototype.setAttrs=function(e){return Object.assign(this.getAttrs(),e),this},e.prototype.getAttrs=function(){return this.attrs||(this.attrs={})},e.prototype.setClass=function(e){return this.setAttr("class",e)},e.prototype.addClass=function(e){for(var t,r=this.getClass(),n=this.whitespaceRegex,o=r?r.split(n):[],i=e.split(n);t=i.shift();)-1===a(o,t)&&o.push(t);return this.getAttrs().class=o.join(" "),this},e.prototype.removeClass=function(e){for(var t,r=this.getClass(),n=this.whitespaceRegex,o=r?r.split(n):[],i=e.split(n);o.length&&(t=i.shift());){var s=a(o,t);-1!==s&&o.splice(s,1)}return this.getAttrs().class=o.join(" "),this},e.prototype.getClass=function(){return this.getAttrs().class||""},e.prototype.hasClass=function(e){return-1!==(" "+this.getClass()+" ").indexOf(" "+e+" ")},e.prototype.setInnerHTML=function(e){return this.innerHTML=e,this},e.prototype.setInnerHtml=function(e){return this.setInnerHTML(e)},e.prototype.getInnerHTML=function(){return this.innerHTML||""},e.prototype.getInnerHtml=function(){return this.getInnerHTML()},e.prototype.toAnchorString=function(){var e=this.getTagName(),t=this.buildAttrsStr();return["<",e,t=t?" "+t:"",">",this.getInnerHtml(),""].join("")},e.prototype.buildAttrsStr=function(){if(!this.attrs)return"";var e=this.getAttrs(),t=[];for(var r in e)e.hasOwnProperty(r)&&t.push(r+'="'+e[r]+'"');return t.join(" ")},e}();var u=function(){function e(e){void 0===e&&(e={}),this.newWindow=!1,this.truncate={},this.className="",this.newWindow=e.newWindow||!1,this.truncate=e.truncate||{},this.className=e.className||""}return e.prototype.build=function(e){return new l({tagName:"a",attrs:this.createAttrs(e),innerHtml:this.processAnchorText(e.getAnchorText())})},e.prototype.createAttrs=function(e){var t={href:e.getAnchorHref()},r=this.createCssClass(e);return r&&(t.class=r),this.newWindow&&(t.target="_blank",t.rel="noopener noreferrer"),this.truncate&&this.truncate.length&&this.truncate.length=s)return l.host.length==t?(l.host.substr(0,t-o)+r).substr(0,s+n):i(c,s).substr(0,s+n);var p="";if(l.path&&(p+="/"+l.path),l.query&&(p+="?"+l.query),p){if((c+p).length>=s)return(c+p).length==t?(c+p).substr(0,t):(c+i(p,s-c.length)).substr(0,s+n);c+=p}if(l.fragment){var f="#"+l.fragment;if((c+f).length>=s)return(c+f).length==t?(c+f).substr(0,t):(c+i(f,s-c.length)).substr(0,s+n);c+=f}if(l.scheme&&l.host){var h=l.scheme+"://";if((c+h).length0&&(d=c.substr(-1*Math.floor(s/2))),(c.substr(0,Math.ceil(s/2))+r+d).substr(0,s+n)}(e,r):"middle"===n?function(e,t,r){if(e.length<=t)return e;var n,o;null==r?(r="…",n=8,o=3):(n=r.length,o=r.length);var a=t-o,i="";return a>0&&(i=e.substr(-1*Math.floor(a/2))),(e.substr(0,Math.ceil(a/2))+r+i).substr(0,a+n)}(e,r):function(e,t,r){return function(e,t,r){var n;return e.length>t&&(null==r?(r="…",n=3):n=r.length,e=e.substring(0,t-n)+r),e}(e,t,r)}(e,r)},e}(),c=function(){function e(e){this.__jsduckDummyDocProp=null,this.matchedText="",this.offset=0,this.tagBuilder=e.tagBuilder,this.matchedText=e.matchedText,this.offset=e.offset}return e.prototype.getMatchedText=function(){return this.matchedText},e.prototype.setOffset=function(e){this.offset=e},e.prototype.getOffset=function(){return this.offset},e.prototype.getCssClassSuffixes=function(){return[this.getType()]},e.prototype.buildTag=function(){return this.tagBuilder.build(this)},e}(),p=function(e,t){return p=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])},p(e,t)};function f(e,t){function r(){this.constructor=e}p(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}var h=function(){return h=Object.assign||function(e){for(var t,r=1,n=arguments.length;r-1},e.isValidUriScheme=function(e){var t=e.match(this.uriSchemeRegex),r=t&&t[0].toLowerCase();return"javascript:"!==r&&"vbscript:"!==r},e.urlMatchDoesNotHaveProtocolOrDot=function(e,t){return!(!e||t&&this.hasFullProtocolRegex.test(t)||-1!==e.indexOf("."))},e.urlMatchDoesNotHaveAtLeastOneWordChar=function(e,t){return!(!e||!t)&&(!this.hasFullProtocolRegex.test(t)&&!this.hasWordCharAfterProtocolRegex.test(e))},e.hasFullProtocolRegex=/^[A-Za-z][-.+A-Za-z0-9]*:\/\//,e.uriSchemeRegex=/^[A-Za-z][-.+A-Za-z0-9]*:/,e.hasWordCharAfterProtocolRegex=new RegExp(":[^\\s]*?["+C+"]"),e.ipRegex=/[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?(:[0-9]*)?\/?$/,e}(),V=(d=new RegExp("[/?#](?:["+N+"\\-+&@#/%=~_()|'$*\\[\\]{}?!:,.;^✓]*["+N+"\\-+&@#/%=~_()|'$*\\[\\]{}✓])?"),new RegExp(["(?:","(",/(?:[A-Za-z][-.+A-Za-z0-9]{0,63}:(?![A-Za-z][-.+A-Za-z0-9]{0,63}:\/\/)(?!\d+\/?)(?:\/\/)?)/.source,M(2),")","|","(","(//)?",/(?:www\.)/.source,M(6),")","|","(","(//)?",M(10)+"\\.",L.source,"(?![-"+I+"])",")",")","(?::[0-9]+)?","(?:"+d.source+")?"].join(""),"gi")),$=new RegExp("["+N+"]"),W=function(e){function t(t){var r=e.call(this,t)||this;return r.stripPrefix={scheme:!0,www:!0},r.stripTrailingSlash=!0,r.decodePercentEncoding=!0,r.matcherRegex=V,r.wordCharRegExp=$,r.stripPrefix=t.stripPrefix,r.stripTrailingSlash=t.stripTrailingSlash,r.decodePercentEncoding=t.decodePercentEncoding,r}return f(t,e),t.prototype.parseMatches=function(e){for(var t,r=this.matcherRegex,n=this.stripPrefix,o=this.stripTrailingSlash,a=this.decodePercentEncoding,i=this.tagBuilder,s=[],l=function(){var r=t[0],l=t[1],c=t[4],p=t[5],f=t[9],h=t.index,d=p||f,m=e.charAt(h-1);if(!q.isValid(r,l))return"continue";if(h>0&&"@"===m)return"continue";if(h>0&&d&&u.wordCharRegExp.test(m))return"continue";if(/\?$/.test(r)&&(r=r.substr(0,r.length-1)),u.matchHasUnbalancedClosingParen(r))r=r.substr(0,r.length-1);else{var g=u.matchHasInvalidCharAfterTld(r,l);g>-1&&(r=r.substr(0,g))}var v=["http://","https://"].find((function(e){return!!l&&-1!==l.indexOf(e)}));if(v){var y=r.indexOf(v);r=r.substr(y),l=l.substr(y),h+=y}var w=l?"scheme":c?"www":"tld",E=!!l;s.push(new b({tagBuilder:i,matchedText:r,offset:h,urlMatchType:w,url:r,protocolUrlMatch:E,protocolRelativeMatch:!!d,stripPrefix:n,stripTrailingSlash:o,decodePercentEncoding:a}))},u=this;null!==(t=r.exec(e));)l();return s},t.prototype.matchHasUnbalancedClosingParen=function(e){var t,r=e.charAt(e.length-1);if(")"===r)t="(";else if("]"===r)t="[";else{if("}"!==r)return!1;t="{"}for(var n=0,o=0,a=e.length-1;o"===e?(m=new ne(h(h({},m),{name:H()})),W()):E.test(e)||x.test(e)||":"===e||V()}function w(e){">"===e?V():E.test(e)?f=3:V()}function _(e){S.test(e)||("/"===e?f=12:">"===e?W():"<"===e?$():"="===e||A.test(e)||k.test(e)?V():f=5)}function C(e){S.test(e)?f=6:"/"===e?f=12:"="===e?f=7:">"===e?W():"<"===e?$():A.test(e)&&V()}function O(e){S.test(e)||("/"===e?f=12:"="===e?f=7:">"===e?W():"<"===e?$():A.test(e)?V():f=5)}function j(e){S.test(e)||('"'===e?f=8:"'"===e?f=9:/[>=`]/.test(e)?V():"<"===e?$():f=10)}function I(e){'"'===e&&(f=11)}function N(e){"'"===e&&(f=11)}function T(e){S.test(e)?f=4:">"===e?W():"<"===e&&$()}function P(e){S.test(e)?f=4:"/"===e?f=12:">"===e?W():"<"===e?$():(f=4,c--)}function R(e){">"===e?(m=new ne(h(h({},m),{isClosing:!0})),W()):f=4}function M(t){"--"===e.substr(c,2)?(c+=2,m=new ne(h(h({},m),{type:"comment"})),f=14):"DOCTYPE"===e.substr(c,7).toUpperCase()?(c+=7,m=new ne(h(h({},m),{type:"doctype"})),f=20):V()}function D(e){"-"===e?f=15:">"===e?V():f=16}function L(e){"-"===e?f=18:">"===e?V():f=16}function B(e){"-"===e&&(f=17)}function F(e){f="-"===e?18:16}function z(e){">"===e?W():"!"===e?f=19:"-"===e||(f=16)}function U(e){"-"===e?f=17:">"===e?W():f=16}function q(e){">"===e?W():"<"===e&&$()}function V(){f=0,m=u}function $(){f=1,m=new ne({idx:c})}function W(){var t=e.slice(d,m.idx);t&&a(t,d),"comment"===m.type?i(m.idx):"doctype"===m.type?l(m.idx):(m.isOpening&&n(m.name,m.idx),m.isClosing&&o(m.name,m.idx)),V(),d=c+1}function H(){var t=m.idx+(m.isClosing?2:1);return e.slice(t,c).toLowerCase()}d=0&&n++},onText:function(e,r){if(0===n){var a=function(e,t){if(!t.global)throw new Error("`splitRegex` must have the 'g' flag set");for(var r,n=[],o=0;r=t.exec(e);)n.push(e.substring(o,r.index)),n.push(r[0]),o=r.index+r[0].length;return n.push(e.substring(o)),n}(e,/( | |<|<|>|>|"|"|')/gi),i=r;a.forEach((function(e,r){if(r%2==0){var n=t.parseText(e,i);o.push.apply(o,n)}i+=e.length}))}},onCloseTag:function(e){r.indexOf(e)>=0&&(n=Math.max(n-1,0))},onComment:function(e){},onDoctype:function(e){}}),o=this.compactMatches(o),o=this.removeUnwantedMatches(o)},e.prototype.compactMatches=function(e){e.sort((function(e,t){return e.getOffset()-t.getOffset()}));for(var t=0;to?t:t+1;e.splice(i,1);continue}e[t+1].getOffset()/g,">"));for(var t=this.parse(e),r=[],n=0,o=0,a=t.length;o/i.test(e)}function se(){var e=[],t=new oe({stripPrefix:!1,url:!0,email:!0,replaceFn:function(t){switch(t.getType()){case"url":e.push({text:t.matchedText,url:t.getUrl()});break;case"email":e.push({text:t.matchedText,url:"mailto:"+t.getEmail().replace(/^mailto:/i,"")})}return!1}});return{links:e,autolinker:t}}function le(e){var t,r,n,o,a,i,s,l,u,c,p,f,h,d,m=e.tokens,g=null;for(r=0,n=m.length;r=0;t--)if("link_close"!==(a=o[t]).type){if("htmltag"===a.type&&(d=a.content,/^\s]/i.test(d)&&p>0&&p--,ie(a.content)&&p++),!(p>0)&&"text"===a.type&&ae.test(a.content)){if(g||(f=(g=se()).links,h=g.autolinker),i=a.content,f.length=0,h.link(i),!f.length)continue;for(s=[],c=a.level,l=0;l({useUnsafeMarkdown:!1})};const me=de;function ge(e){let{useUnsafeMarkdown:t=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=t,n=t?[]:["style","class"];return t&&!ge.hasWarnedAboutDeprecation&&(console.warn("useUnsafeMarkdown display configuration parameter is deprecated since >3.26.0 and will be removed in v4.0.0."),ge.hasWarnedAboutDeprecation=!0),pe().sanitize(e,{ADD_ATTR:["target"],FORBID_TAGS:["style","form"],ALLOW_DATA_ATTR:r,FORBID_ATTR:n})}ge.hasWarnedAboutDeprecation=!1},45308:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>f});var n,o=r(86),a=r.n(o),i=r(8712),s=r.n(i),l=r(90242),u=r(27621);const c=r(95102),p={},f=p;a()(n=s()(c).call(c)).call(n,(function(e){if("./index.js"===e)return;let t=c(e);p[(0,l.Zl)(e)]=t.default?t.default:t})),p.SafeRender=u.default},55812:(e,t,r)=>{"use strict";r.r(t),r.d(t,{SHOW_AUTH_POPUP:()=>p,AUTHORIZE:()=>f,LOGOUT:()=>h,PRE_AUTHORIZE_OAUTH2:()=>d,AUTHORIZE_OAUTH2:()=>m,VALIDATE:()=>g,CONFIGURE_AUTH:()=>v,RESTORE_AUTHORIZATION:()=>y,showDefinitions:()=>b,authorize:()=>w,authorizeWithPersistOption:()=>E,logout:()=>x,logoutWithPersistOption:()=>_,preAuthorizeImplicit:()=>S,authorizeOauth2:()=>A,authorizeOauth2WithPersistOption:()=>k,authorizePassword:()=>C,authorizeApplication:()=>O,authorizeAccessCodeWithFormParams:()=>j,authorizeAccessCodeWithBasicAuthentication:()=>I,authorizeRequest:()=>N,configureAuth:()=>T,restoreAuthorization:()=>P,persistAuthorizationIfNeeded:()=>R,authPopup:()=>M});var n=r(35627),o=r.n(n),a=r(76986),i=r.n(a),s=r(84564),l=r.n(s),u=r(27504),c=r(90242);const p="show_popup",f="authorize",h="logout",d="pre_authorize_oauth2",m="authorize_oauth2",g="validate",v="configure_auth",y="restore_authorization";function b(e){return{type:p,payload:e}}function w(e){return{type:f,payload:e}}const E=e=>t=>{let{authActions:r}=t;r.authorize(e),r.persistAuthorizationIfNeeded()};function x(e){return{type:h,payload:e}}const _=e=>t=>{let{authActions:r}=t;r.logout(e),r.persistAuthorizationIfNeeded()},S=e=>t=>{let{authActions:r,errActions:n}=t,{auth:a,token:i,isValid:s}=e,{schema:l,name:c}=a,p=l.get("flow");delete u.Z.swaggerUIRedirectOauth2,"accessCode"===p||s||n.newAuthErr({authId:c,source:"auth",level:"warning",message:"Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"}),i.error?n.newAuthErr({authId:c,source:"auth",level:"error",message:o()(i)}):r.authorizeOauth2WithPersistOption({auth:a,token:i})};function A(e){return{type:m,payload:e}}const k=e=>t=>{let{authActions:r}=t;r.authorizeOauth2(e),r.persistAuthorizationIfNeeded()},C=e=>t=>{let{authActions:r}=t,{schema:n,name:o,username:a,password:s,passwordType:l,clientId:u,clientSecret:p}=e,f={grant_type:"password",scope:e.scopes.join(" "),username:a,password:s},h={};switch(l){case"request-body":!function(e,t,r){t&&i()(e,{client_id:t});r&&i()(e,{client_secret:r})}(f,u,p);break;case"basic":h.Authorization="Basic "+(0,c.r3)(u+":"+p);break;default:console.warn(`Warning: invalid passwordType ${l} was passed, not including client id and secret`)}return r.authorizeRequest({body:(0,c.GZ)(f),url:n.get("tokenUrl"),name:o,headers:h,query:{},auth:e})};const O=e=>t=>{let{authActions:r}=t,{schema:n,scopes:o,name:a,clientId:i,clientSecret:s}=e,l={Authorization:"Basic "+(0,c.r3)(i+":"+s)},u={grant_type:"client_credentials",scope:o.join(" ")};return r.authorizeRequest({body:(0,c.GZ)(u),name:a,url:n.get("tokenUrl"),auth:e,headers:l})},j=e=>{let{auth:t,redirectUrl:r}=e;return e=>{let{authActions:n}=e,{schema:o,name:a,clientId:i,clientSecret:s,codeVerifier:l}=t,u={grant_type:"authorization_code",code:t.code,client_id:i,client_secret:s,redirect_uri:r,code_verifier:l};return n.authorizeRequest({body:(0,c.GZ)(u),name:a,url:o.get("tokenUrl"),auth:t})}},I=e=>{let{auth:t,redirectUrl:r}=e;return e=>{let{authActions:n}=e,{schema:o,name:a,clientId:i,clientSecret:s,codeVerifier:l}=t,u={Authorization:"Basic "+(0,c.r3)(i+":"+s)},p={grant_type:"authorization_code",code:t.code,client_id:i,redirect_uri:r,code_verifier:l};return n.authorizeRequest({body:(0,c.GZ)(p),name:a,url:o.get("tokenUrl"),auth:t,headers:u})}},N=e=>t=>{let r,{fn:n,getConfigs:a,authActions:s,errActions:u,oas3Selectors:c,specSelectors:p,authSelectors:f}=t,{body:h,query:d={},headers:m={},name:g,url:v,auth:y}=e,{additionalQueryStringParams:b}=f.getConfigs()||{};if(p.isOAS3()){let e=c.serverEffectiveValue(c.selectedServer());r=l()(v,e,!0)}else r=l()(v,p.url(),!0);"object"==typeof b&&(r.query=i()({},r.query,b));const w=r.toString();let E=i()({Accept:"application/json, text/plain, */*","Content-Type":"application/x-www-form-urlencoded","X-Requested-With":"XMLHttpRequest"},m);n.fetch({url:w,method:"post",headers:E,query:d,body:h,requestInterceptor:a().requestInterceptor,responseInterceptor:a().responseInterceptor}).then((function(e){let t=JSON.parse(e.data),r=t&&(t.error||""),n=t&&(t.parseError||"");e.ok?r||n?u.newAuthErr({authId:g,level:"error",source:"auth",message:o()(t)}):s.authorizeOauth2WithPersistOption({auth:y,token:t}):u.newAuthErr({authId:g,level:"error",source:"auth",message:e.statusText})})).catch((e=>{let t=new Error(e).message;if(e.response&&e.response.data){const r=e.response.data;try{const e="string"==typeof r?JSON.parse(r):r;e.error&&(t+=`, error: ${e.error}`),e.error_description&&(t+=`, description: ${e.error_description}`)}catch(e){}}u.newAuthErr({authId:g,level:"error",source:"auth",message:t})}))};function T(e){return{type:v,payload:e}}function P(e){return{type:y,payload:e}}const R=()=>e=>{let{authSelectors:t,getConfigs:r}=e;if(r().persistAuthorization){const e=t.authorized();localStorage.setItem("authorized",o()(e.toJS()))}},M=(e,t)=>()=>{u.Z.swaggerUIRedirectOauth2=t,u.Z.open(e)}},93705:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>u,preauthorizeBasic:()=>c,preauthorizeApiKey:()=>p});var n=r(11189),o=r.n(n),a=r(43962),i=r(55812),s=r(60035),l=r(48302);function u(){return{afterLoad(e){this.rootInjects=this.rootInjects||{},this.rootInjects.initOAuth=e.authActions.configureAuth,this.rootInjects.preauthorizeApiKey=o()(p).call(p,null,e),this.rootInjects.preauthorizeBasic=o()(c).call(c,null,e)},statePlugins:{auth:{reducers:a.default,actions:i,selectors:s},spec:{wrapActions:l}}}}function c(e,t,r,n){const{authActions:{authorize:o},specSelectors:{specJson:a,isOAS3:i}}=e,s=i()?["components","securitySchemes"]:["securityDefinitions"],l=a().getIn([...s,t]);return l?o({[t]:{value:{username:r,password:n},schema:l.toJS()}}):null}function p(e,t,r){const{authActions:{authorize:n},specSelectors:{specJson:o,isOAS3:a}}=e,i=a()?["components","securitySchemes"]:["securityDefinitions"],s=o().getIn([...i,t]);return s?n({[t]:{value:r,schema:s.toJS()}}):null}},43962:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>c});var n=r(86),o=r.n(n),a=r(76986),i=r.n(a),s=r(43393),l=r(90242),u=r(55812);const c={[u.SHOW_AUTH_POPUP]:(e,t)=>{let{payload:r}=t;return e.set("showDefinitions",r)},[u.AUTHORIZE]:(e,t)=>{var r;let{payload:n}=t,a=(0,s.fromJS)(n),i=e.get("authorized")||(0,s.Map)();return o()(r=a.entrySeq()).call(r,(t=>{let[r,n]=t;if(!(0,l.Wl)(n.getIn))return e.set("authorized",i);let o=n.getIn(["schema","type"]);if("apiKey"===o||"http"===o)i=i.set(r,n);else if("basic"===o){let e=n.getIn(["value","username"]),t=n.getIn(["value","password"]);i=i.setIn([r,"value"],{username:e,header:"Basic "+(0,l.r3)(e+":"+t)}),i=i.setIn([r,"schema"],n.get("schema"))}})),e.set("authorized",i)},[u.AUTHORIZE_OAUTH2]:(e,t)=>{let r,{payload:n}=t,{auth:o,token:a}=n;o.token=i()({},a),r=(0,s.fromJS)(o);let l=e.get("authorized")||(0,s.Map)();return l=l.set(r.get("name"),r),e.set("authorized",l)},[u.LOGOUT]:(e,t)=>{let{payload:r}=t,n=e.get("authorized").withMutations((e=>{o()(r).call(r,(t=>{e.delete(t)}))}));return e.set("authorized",n)},[u.CONFIGURE_AUTH]:(e,t)=>{let{payload:r}=t;return e.set("configs",r)},[u.RESTORE_AUTHORIZATION]:(e,t)=>{let{payload:r}=t;return e.set("authorized",(0,s.fromJS)(r.authorized))}}},60035:(e,t,r)=>{"use strict";r.r(t),r.d(t,{shownDefinitions:()=>y,definitionsToAuthorize:()=>b,getDefinitionsByNames:()=>w,definitionsForRequirements:()=>E,authorized:()=>x,isAuthorized:()=>_,getConfigs:()=>S});var n=r(86),o=r.n(n),a=r(14418),i=r.n(a),s=r(92039),l=r.n(s),u=r(11882),c=r.n(u),p=r(97606),f=r.n(p),h=r(28222),d=r.n(h),m=r(20573),g=r(43393);const v=e=>e,y=(0,m.P1)(v,(e=>e.get("showDefinitions"))),b=(0,m.P1)(v,(()=>e=>{var t;let{specSelectors:r}=e,n=r.securityDefinitions()||(0,g.Map)({}),a=(0,g.List)();return o()(t=n.entrySeq()).call(t,(e=>{let[t,r]=e,n=(0,g.Map)();n=n.set(t,r),a=a.push(n)})),a})),w=(e,t)=>e=>{var r;let{specSelectors:n}=e;console.warn("WARNING: getDefinitionsByNames is deprecated and will be removed in the next major version.");let a=n.securityDefinitions(),i=(0,g.List)();return o()(r=t.valueSeq()).call(r,(e=>{var t;let r=(0,g.Map)();o()(t=e.entrySeq()).call(t,(e=>{let t,[n,i]=e,s=a.get(n);var l;"oauth2"===s.get("type")&&i.size&&(t=s.get("scopes"),o()(l=t.keySeq()).call(l,(e=>{i.contains(e)||(t=t.delete(e))})),s=s.set("allowedScopes",t));r=r.set(n,s)})),i=i.push(r)})),i},E=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:(0,g.List)();return e=>{let{authSelectors:r}=e;const n=r.definitionsToAuthorize()||(0,g.List)();return i()(n).call(n,(e=>l()(t).call(t,(t=>t.get(e.keySeq().first())))))}},x=(0,m.P1)(v,(e=>e.get("authorized")||(0,g.Map)())),_=(e,t)=>e=>{var r;let{authSelectors:n}=e,o=n.authorized();return g.List.isList(t)?!!i()(r=t.toJS()).call(r,(e=>{var t,r;return-1===c()(t=f()(r=d()(e)).call(r,(e=>!!o.get(e)))).call(t,!1)})).length:null},S=(0,m.P1)(v,(e=>e.get("configs")))},48302:(e,t,r)=>{"use strict";r.r(t),r.d(t,{execute:()=>n});const n=(e,t)=>{let{authSelectors:r,specSelectors:n}=t;return t=>{let{path:o,method:a,operation:i,extras:s}=t,l={authorized:r.authorized()&&r.authorized().toJS(),definitions:n.securityDefinitions()&&n.securityDefinitions().toJS(),specSecurity:n.security()&&n.security().toJS()};return e({path:o,method:a,operation:i,securities:l,...s})}}},70714:(e,t,r)=>{"use strict";r.r(t),r.d(t,{UPDATE_CONFIGS:()=>n,TOGGLE_CONFIGS:()=>o,update:()=>a,toggle:()=>i,loaded:()=>s});const n="configs_update",o="configs_toggle";function a(e,t){return{type:n,payload:{[e]:t}}}function i(e){return{type:o,payload:e}}const s=()=>e=>{let{getConfigs:t,authActions:r}=e;if(t().persistAuthorization){const e=localStorage.getItem("authorized");e&&r.restoreAuthorization({authorized:JSON.parse(e)})}}},92256:(e,t,r)=>{"use strict";r.r(t),r.d(t,{parseYamlConfig:()=>o});var n=r(1272);const o=(e,t)=>{try{return n.ZP.load(e)}catch(e){return t&&t.errActions.newThrownErr(new Error(e)),{}}}},1661:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>c});var n=r(15163),o=r(92256),a=r(70714),i=r(22698),s=r(69018),l=r(37743);const u={getLocalConfig:()=>(0,o.parseYamlConfig)(n)};function c(){return{statePlugins:{spec:{actions:i,selectors:u},configs:{reducers:l.default,actions:a,selectors:s}}}}},37743:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>a});var n=r(43393),o=r(70714);const a={[o.UPDATE_CONFIGS]:(e,t)=>e.merge((0,n.fromJS)(t.payload)),[o.TOGGLE_CONFIGS]:(e,t)=>{const r=t.payload,n=e.get(r);return e.set(r,!n)}}},69018:(e,t,r)=>{"use strict";r.r(t),r.d(t,{get:()=>a});var n=r(58309),o=r.n(n);const a=(e,t)=>e.getIn(o()(t)?t:[t])},22698:(e,t,r)=>{"use strict";r.r(t),r.d(t,{downloadConfig:()=>o,getConfigByUrl:()=>a});var n=r(92256);const o=e=>t=>{const{fn:{fetch:r}}=t;return r(e)},a=(e,t)=>r=>{let{specActions:o}=r;if(e)return o.downloadConfig(e).then(a,a);function a(r){r instanceof Error||r.status>=400?(o.updateLoadingStatus("failedConfig"),o.updateLoadingStatus("failedConfig"),o.updateUrl(""),console.error(r.statusText+" "+e.url),t(null)):t((0,n.parseYamlConfig)(r.text))}}},31970:(e,t,r)=>{"use strict";r.r(t),r.d(t,{setHash:()=>n});const n=e=>e?history.pushState(null,null,`#${e}`):window.location.hash=""},34980:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>i});var n=r(41599),o=r(60877),a=r(34584);function i(){return[n.default,{statePlugins:{configs:{wrapActions:{loaded:(e,t)=>function(){e(...arguments);const r=decodeURIComponent(window.location.hash);t.layoutActions.parseDeepLinkHash(r)}}}},wrapComponents:{operation:o.default,OperationTag:a.default}}]}},41599:(e,t,r)=>{"use strict";r.r(t),r.d(t,{show:()=>b,scrollTo:()=>w,parseDeepLinkHash:()=>E,readyToScroll:()=>x,scrollToElement:()=>_,clearScrollTo:()=>S,default:()=>A});var n=r(58309),o=r.n(n),a=r(24278),i=r.n(a),s=r(97606),l=r.n(s),u=r(11882),c=r.n(u),p=r(31970),f=r(45172),h=r.n(f),d=r(90242),m=r(43393),g=r.n(m);const v="layout_scroll_to",y="layout_clear_scroll",b=(e,t)=>{let{getConfigs:r,layoutSelectors:n}=t;return function(){for(var t=arguments.length,a=new Array(t),i=0;i({type:v,payload:o()(e)?e:[e]}),E=e=>t=>{let{layoutActions:r,layoutSelectors:n,getConfigs:o}=t;if(o().deepLinking&&e){var a;let t=i()(e).call(e,1);"!"===t[0]&&(t=i()(t).call(t,1)),"/"===t[0]&&(t=i()(t).call(t,1));const o=l()(a=t.split("/")).call(a,(e=>e||"")),s=n.isShownKeyFromUrlHashArray(o),[u,p="",f=""]=s;if("operations"===u){const e=n.isShownKeyFromUrlHashArray([p]);c()(p).call(p,"_")>-1&&(console.warn("Warning: escaping deep link whitespace with `_` will be unsupported in v4.0, use `%20` instead."),r.show(l()(e).call(e,(e=>e.replace(/_/g," "))),!0)),r.show(e,!0)}(c()(p).call(p,"_")>-1||c()(f).call(f,"_")>-1)&&(console.warn("Warning: escaping deep link whitespace with `_` will be unsupported in v4.0, use `%20` instead."),r.show(l()(s).call(s,(e=>e.replace(/_/g," "))),!0)),r.show(s,!0),r.scrollTo(s)}},x=(e,t)=>r=>{const n=r.layoutSelectors.getScrollToKey();g().is(n,(0,m.fromJS)(e))&&(r.layoutActions.scrollToElement(t),r.layoutActions.clearScrollTo())},_=(e,t)=>r=>{try{t=t||r.fn.getScrollParent(e),h().createScroller(t).to(e)}catch(e){console.error(e)}},S=()=>({type:y});const A={fn:{getScrollParent:function(e,t){const r=document.documentElement;let n=getComputedStyle(e);const o="absolute"===n.position,a=t?/(auto|scroll|hidden)/:/(auto|scroll)/;if("fixed"===n.position)return r;for(let t=e;t=t.parentElement;)if(n=getComputedStyle(t),(!o||"static"!==n.position)&&a.test(n.overflow+n.overflowY+n.overflowX))return t;return r}},statePlugins:{layout:{actions:{scrollToElement:_,scrollTo:w,clearScrollTo:S,readyToScroll:x,parseDeepLinkHash:E},selectors:{getScrollToKey:e=>e.get("scrollToKey"),isShownKeyFromUrlHashArray(e,t){const[r,n]=t;return n?["operations",r,n]:r?["operations-tag",r]:[]},urlHashArrayFromIsShownKey(e,t){let[r,n,o]=t;return"operations"==r?[n,o]:"operations-tag"==r?[n]:[]}},reducers:{[v]:(e,t)=>e.set("scrollToKey",g().fromJS(t.payload)),[y]:e=>e.delete("scrollToKey")},wrapActions:{show:b}}}}},34584:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>i});var n=r(61125),o=r.n(n),a=r(67294);const i=(e,t)=>class extends a.Component{constructor(){super(...arguments),o()(this,"onLoad",(e=>{const{tag:r}=this.props,n=["operations-tag",r];t.layoutActions.readyToScroll(n,e)}))}render(){return a.createElement("span",{ref:this.onLoad},a.createElement(e,this.props))}}},60877:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>i});var n=r(61125),o=r.n(n),a=r(67294);r(23930);const i=(e,t)=>class extends a.Component{constructor(){super(...arguments),o()(this,"onLoad",(e=>{const{operation:r}=this.props,{tag:n,operationId:o}=r.toObject();let{isShownKey:a}=r.toObject();a=a||["operations",n,o],t.layoutActions.readyToScroll(a,e)}))}render(){return a.createElement("span",{ref:this.onLoad},a.createElement(e,this.props))}}},48011:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>d});var n=r(76986),o=r.n(n),a=r(63460),i=r.n(a),s=r(11882),l=r.n(s),u=r(35627),c=r.n(u),p=r(20573),f=r(43393),h=r(27504);function d(e){let{fn:t}=e;return{statePlugins:{spec:{actions:{download:e=>r=>{let{errActions:n,specSelectors:a,specActions:s,getConfigs:l}=r,{fetch:u}=t;const c=l();function p(t){if(t instanceof Error||t.status>=400)return s.updateLoadingStatus("failed"),n.newThrownErr(o()(new Error((t.message||t.statusText)+" "+e),{source:"fetch"})),void(!t.status&&t instanceof Error&&function(){try{let t;if("URL"in h.Z?t=new(i())(e):(t=document.createElement("a"),t.href=e),"https:"!==t.protocol&&"https:"===h.Z.location.protocol){const e=o()(new Error(`Possible mixed-content issue? The page was loaded over https:// but a ${t.protocol}// URL was specified. Check that you are not attempting to load mixed content.`),{source:"fetch"});return void n.newThrownErr(e)}if(t.origin!==h.Z.location.origin){const e=o()(new Error(`Possible cross-origin (CORS) issue? The URL origin (${t.origin}) does not match the page (${h.Z.location.origin}). Check the server returns the correct 'Access-Control-Allow-*' headers.`),{source:"fetch"});n.newThrownErr(e)}}catch(e){return}}());s.updateLoadingStatus("success"),s.updateSpec(t.text),a.url()!==e&&s.updateUrl(e)}e=e||a.url(),s.updateLoadingStatus("loading"),n.clear({source:"fetch"}),u({url:e,loadSpec:!0,requestInterceptor:c.requestInterceptor||(e=>e),responseInterceptor:c.responseInterceptor||(e=>e),credentials:"same-origin",headers:{Accept:"application/json,*/*"}}).then(p,p)},updateLoadingStatus:e=>{let t=[null,"loading","failed","success","failedConfig"];return-1===l()(t).call(t,e)&&console.error(`Error: ${e} is not one of ${c()(t)}`),{type:"spec_update_loading_status",payload:e}}},reducers:{spec_update_loading_status:(e,t)=>"string"==typeof t.payload?e.set("loadingStatus",t.payload):e},selectors:{loadingStatus:(0,p.P1)((e=>e||(0,f.Map)()),(e=>e.get("loadingStatus")||null))}}}}}},34966:(e,t,r)=>{"use strict";r.r(t),r.d(t,{NEW_THROWN_ERR:()=>o,NEW_THROWN_ERR_BATCH:()=>a,NEW_SPEC_ERR:()=>i,NEW_SPEC_ERR_BATCH:()=>s,NEW_AUTH_ERR:()=>l,CLEAR:()=>u,CLEAR_BY:()=>c,newThrownErr:()=>p,newThrownErrBatch:()=>f,newSpecErr:()=>h,newSpecErrBatch:()=>d,newAuthErr:()=>m,clear:()=>g,clearBy:()=>v});var n=r(7710);const o="err_new_thrown_err",a="err_new_thrown_err_batch",i="err_new_spec_err",s="err_new_spec_err_batch",l="err_new_auth_err",u="err_clear",c="err_clear_by";function p(e){return{type:o,payload:(0,n.serializeError)(e)}}function f(e){return{type:a,payload:e}}function h(e){return{type:i,payload:e}}function d(e){return{type:s,payload:e}}function m(e){return{type:l,payload:e}}function g(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{type:u,payload:e}}function v(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:()=>!0;return{type:c,payload:e}}},56982:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>c});var n=r(14418),o=r.n(n),a=r(97606),i=r.n(a),s=r(54061),l=r.n(s);const u=[r(2392),r(21835)];function c(e){var t;let r={jsSpec:{}},n=l()(u,((e,t)=>{try{let n=t.transform(e,r);return o()(n).call(n,(e=>!!e))}catch(t){return console.error("Transformer error:",t),e}}),e);return i()(t=o()(n).call(n,(e=>!!e))).call(t,(e=>(!e.get("line")&&e.get("path"),e)))}},2392:(e,t,r)=>{"use strict";r.r(t),r.d(t,{transform:()=>p});var n=r(97606),o=r.n(n),a=r(11882),i=r.n(a),s=r(24278),l=r.n(s),u=r(24282),c=r.n(u);function p(e){return o()(e).call(e,(e=>{var t;let r="is not of a type(s)",n=i()(t=e.get("message")).call(t,r);if(n>-1){var o,a;let t=l()(o=e.get("message")).call(o,n+r.length).split(",");return e.set("message",l()(a=e.get("message")).call(a,0,n)+function(e){return c()(e).call(e,((e,t,r,n)=>r===n.length-1&&n.length>1?e+"or "+t:n[r+1]&&n.length>2?e+t+", ":n[r+1]?e+t+" ":e+t),"should be a")}(t))}return e}))}},21835:(e,t,r)=>{"use strict";r.r(t),r.d(t,{transform:()=>n});r(97606),r(11882),r(27361),r(43393);function n(e,t){let{jsSpec:r}=t;return e}},77793:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>i});var n=r(93527),o=r(34966),a=r(87667);function i(e){return{statePlugins:{err:{reducers:(0,n.default)(e),actions:o,selectors:a}}}}},93527:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>v});var n=r(76986),o=r.n(n),a=r(97606),i=r.n(a),s=r(39022),l=r.n(s),u=r(14418),c=r.n(u),p=r(2250),f=r.n(p),h=r(34966),d=r(43393),m=r(56982);let g={line:0,level:"error",message:"Unknown error"};function v(){return{[h.NEW_THROWN_ERR]:(e,t)=>{let{payload:r}=t,n=o()(g,r,{type:"thrown"});return e.update("errors",(e=>(e||(0,d.List)()).push((0,d.fromJS)(n)))).update("errors",(e=>(0,m.default)(e)))},[h.NEW_THROWN_ERR_BATCH]:(e,t)=>{let{payload:r}=t;return r=i()(r).call(r,(e=>(0,d.fromJS)(o()(g,e,{type:"thrown"})))),e.update("errors",(e=>{var t;return l()(t=e||(0,d.List)()).call(t,(0,d.fromJS)(r))})).update("errors",(e=>(0,m.default)(e)))},[h.NEW_SPEC_ERR]:(e,t)=>{let{payload:r}=t,n=(0,d.fromJS)(r);return n=n.set("type","spec"),e.update("errors",(e=>(e||(0,d.List)()).push((0,d.fromJS)(n)).sortBy((e=>e.get("line"))))).update("errors",(e=>(0,m.default)(e)))},[h.NEW_SPEC_ERR_BATCH]:(e,t)=>{let{payload:r}=t;return r=i()(r).call(r,(e=>(0,d.fromJS)(o()(g,e,{type:"spec"})))),e.update("errors",(e=>{var t;return l()(t=e||(0,d.List)()).call(t,(0,d.fromJS)(r))})).update("errors",(e=>(0,m.default)(e)))},[h.NEW_AUTH_ERR]:(e,t)=>{let{payload:r}=t,n=(0,d.fromJS)(o()({},r));return n=n.set("type","auth"),e.update("errors",(e=>(e||(0,d.List)()).push((0,d.fromJS)(n)))).update("errors",(e=>(0,m.default)(e)))},[h.CLEAR]:(e,t)=>{var r;let{payload:n}=t;if(!n||!e.get("errors"))return e;let o=c()(r=e.get("errors")).call(r,(e=>{var t;return f()(t=e.keySeq()).call(t,(t=>{const r=e.get(t),o=n[t];return!o||r!==o}))}));return e.merge({errors:o})},[h.CLEAR_BY]:(e,t)=>{var r;let{payload:n}=t;if(!n||"function"!=typeof n)return e;let o=c()(r=e.get("errors")).call(r,(e=>n(e)));return e.merge({errors:o})}}}},87667:(e,t,r)=>{"use strict";r.r(t),r.d(t,{allErrors:()=>a,lastError:()=>i});var n=r(43393),o=r(20573);const a=(0,o.P1)((e=>e),(e=>e.get("errors",(0,n.List)()))),i=(0,o.P1)(a,(e=>e.last()))},49978:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>o});var n=r(4309);function o(){return{fn:{opsFilter:n.default}}}},4309:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>s});var n=r(14418),o=r.n(n),a=r(11882),i=r.n(a);function s(e,t){return o()(e).call(e,((e,r)=>-1!==i()(r).call(r,t)))}},25474:(e,t,r)=>{"use strict";r.r(t),r.d(t,{UPDATE_LAYOUT:()=>o,UPDATE_FILTER:()=>a,UPDATE_MODE:()=>i,SHOW:()=>s,updateLayout:()=>l,updateFilter:()=>u,show:()=>c,changeMode:()=>p});var n=r(90242);const o="layout_update_layout",a="layout_update_filter",i="layout_update_mode",s="layout_show";function l(e){return{type:o,payload:e}}function u(e){return{type:a,payload:e}}function c(e){let t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return e=(0,n.AF)(e),{type:s,payload:{thing:e,shown:t}}}function p(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=(0,n.AF)(e),{type:i,payload:{thing:e,mode:t}}}},26821:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>s});var n=r(5672),o=r(25474),a=r(4400),i=r(28989);function s(){return{statePlugins:{layout:{reducers:n.default,actions:o,selectors:a},spec:{wrapSelectors:i}}}}},5672:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>s});var n=r(39022),o=r.n(n),a=r(43393),i=r(25474);const s={[i.UPDATE_LAYOUT]:(e,t)=>e.set("layout",t.payload),[i.UPDATE_FILTER]:(e,t)=>e.set("filter",t.payload),[i.SHOW]:(e,t)=>{const r=t.payload.shown,n=(0,a.fromJS)(t.payload.thing);return e.update("shown",(0,a.fromJS)({}),(e=>e.set(n,r)))},[i.UPDATE_MODE]:(e,t)=>{var r;let n=t.payload.thing,a=t.payload.mode;return e.setIn(o()(r=["modes"]).call(r,n),(a||"")+"")}}},4400:(e,t,r)=>{"use strict";r.r(t),r.d(t,{current:()=>i,currentFilter:()=>s,isShown:()=>l,whatMode:()=>u,showSummary:()=>c});var n=r(20573),o=r(90242),a=r(43393);const i=e=>e.get("layout"),s=e=>e.get("filter"),l=(e,t,r)=>(t=(0,o.AF)(t),e.get("shown",(0,a.fromJS)({})).get((0,a.fromJS)(t),r)),u=function(e,t){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return t=(0,o.AF)(t),e.getIn(["modes",...t],r)},c=(0,n.P1)((e=>e),(e=>!l(e,"editor")))},28989:(e,t,r)=>{"use strict";r.r(t),r.d(t,{taggedOperations:()=>a});var n=r(24278),o=r.n(n);const a=(e,t)=>function(r){for(var n=arguments.length,a=new Array(n>1?n-1:0),i=1;i=0&&(s=o()(s).call(s,0,f)),s}},9150:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>a});var n=r(11189),o=r.n(n);function a(e){let{configs:t}=e;const r={debug:0,info:1,log:2,warn:3,error:4},n=e=>r[e]||-1;let{logLevel:a}=t,i=n(a);function s(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),o=1;o=i&&console[e](...r)}return s.warn=o()(s).call(s,null,"warn"),s.error=o()(s).call(s,null,"error"),s.info=o()(s).call(s,null,"info"),s.debug=o()(s).call(s,null,"debug"),{rootInjects:{log:s}}}},67002:(e,t,r)=>{"use strict";r.r(t),r.d(t,{UPDATE_SELECTED_SERVER:()=>n,UPDATE_REQUEST_BODY_VALUE:()=>o,UPDATE_REQUEST_BODY_VALUE_RETAIN_FLAG:()=>a,UPDATE_REQUEST_BODY_INCLUSION:()=>i,UPDATE_ACTIVE_EXAMPLES_MEMBER:()=>s,UPDATE_REQUEST_CONTENT_TYPE:()=>l,UPDATE_RESPONSE_CONTENT_TYPE:()=>u,UPDATE_SERVER_VARIABLE_VALUE:()=>c,SET_REQUEST_BODY_VALIDATE_ERROR:()=>p,CLEAR_REQUEST_BODY_VALIDATE_ERROR:()=>f,CLEAR_REQUEST_BODY_VALUE:()=>h,setSelectedServer:()=>d,setRequestBodyValue:()=>m,setRetainRequestBodyValueFlag:()=>g,setRequestBodyInclusion:()=>v,setActiveExamplesMember:()=>y,setRequestContentType:()=>b,setResponseContentType:()=>w,setServerVariableValue:()=>E,setRequestBodyValidateError:()=>x,clearRequestBodyValidateError:()=>_,initRequestBodyValidateError:()=>S,clearRequestBodyValue:()=>A});const n="oas3_set_servers",o="oas3_set_request_body_value",a="oas3_set_request_body_retain_flag",i="oas3_set_request_body_inclusion",s="oas3_set_active_examples_member",l="oas3_set_request_content_type",u="oas3_set_response_content_type",c="oas3_set_server_variable_value",p="oas3_set_request_body_validate_error",f="oas3_clear_request_body_validate_error",h="oas3_clear_request_body_value";function d(e,t){return{type:n,payload:{selectedServerUrl:e,namespace:t}}}function m(e){let{value:t,pathMethod:r}=e;return{type:o,payload:{value:t,pathMethod:r}}}const g=e=>{let{value:t,pathMethod:r}=e;return{type:a,payload:{value:t,pathMethod:r}}};function v(e){let{value:t,pathMethod:r,name:n}=e;return{type:i,payload:{value:t,pathMethod:r,name:n}}}function y(e){let{name:t,pathMethod:r,contextType:n,contextName:o}=e;return{type:s,payload:{name:t,pathMethod:r,contextType:n,contextName:o}}}function b(e){let{value:t,pathMethod:r}=e;return{type:l,payload:{value:t,pathMethod:r}}}function w(e){let{value:t,path:r,method:n}=e;return{type:u,payload:{value:t,path:r,method:n}}}function E(e){let{server:t,namespace:r,key:n,val:o}=e;return{type:c,payload:{server:t,namespace:r,key:n,val:o}}}const x=e=>{let{path:t,method:r,validationErrors:n}=e;return{type:p,payload:{path:t,method:r,validationErrors:n}}},_=e=>{let{path:t,method:r}=e;return{type:f,payload:{path:t,method:r}}},S=e=>{let{pathMethod:t}=e;return{type:f,payload:{path:t[0],method:t[1]}}},A=e=>{let{pathMethod:t}=e;return{type:h,payload:{pathMethod:t}}}},73723:(e,t,r)=>{"use strict";r.r(t),r.d(t,{definitionsToAuthorize:()=>f});var n=r(86),o=r.n(n),a=r(14418),i=r.n(a),s=r(24282),l=r.n(s),u=r(20573),c=r(43393),p=r(7779);const f=(h=(0,u.P1)((e=>e),(e=>{let{specSelectors:t}=e;return t.securityDefinitions()}),((e,t)=>{var r;let n=(0,c.List)();return t?(o()(r=t.entrySeq()).call(r,(e=>{let[t,r]=e;const a=r.get("type");var s;if("oauth2"===a&&o()(s=r.get("flows").entrySeq()).call(s,(e=>{let[o,a]=e,s=(0,c.fromJS)({flow:o,authorizationUrl:a.get("authorizationUrl"),tokenUrl:a.get("tokenUrl"),scopes:a.get("scopes"),type:r.get("type"),description:r.get("description")});n=n.push(new c.Map({[t]:i()(s).call(s,(e=>void 0!==e))}))})),"http"!==a&&"apiKey"!==a||(n=n.push(new c.Map({[t]:r}))),"openIdConnect"===a&&r.get("openIdConnectData")){let e=r.get("openIdConnectData"),a=e.get("grant_types_supported")||["authorization_code","implicit"];o()(a).call(a,(o=>{var a;let s=e.get("scopes_supported")&&l()(a=e.get("scopes_supported")).call(a,((e,t)=>e.set(t,"")),new c.Map),u=(0,c.fromJS)({flow:o,authorizationUrl:e.get("authorization_endpoint"),tokenUrl:e.get("token_endpoint"),scopes:s,type:"oauth2",openIdConnectUrl:r.get("openIdConnectUrl")});n=n.push(new c.Map({[t]:i()(u).call(u,(e=>void 0!==e))}))}))}})),n):n})),(e,t)=>function(){const r=t.getSystem().specSelectors.specJson();for(var n=arguments.length,o=new Array(n),a=0;a{"use strict";r.r(t),r.d(t,{default:()=>u});var n=r(23101),o=r.n(n),a=r(97606),i=r.n(a),s=r(67294),l=(r(23930),r(43393));const u=e=>{var t;let{callbacks:r,getComponent:n,specPath:a}=e;const u=n("OperationContainer",!0);if(!r)return s.createElement("span",null,"No callbacks");let c=i()(t=r.entrySeq()).call(t,(t=>{var r;let[n,c]=t;return s.createElement("div",{key:n},s.createElement("h2",null,n),i()(r=c.entrySeq()).call(r,(t=>{var r;let[c,p]=t;return"$$ref"===c?null:s.createElement("div",{key:c},i()(r=p.entrySeq()).call(r,(t=>{let[r,i]=t;if("$$ref"===r)return null;let p=(0,l.fromJS)({operation:i});return s.createElement(u,o()({},e,{op:p,key:r,tag:"",method:r,path:c,specPath:a.push(n,c,r),allowTryItOut:!1}))})))})))}));return s.createElement("div",null,c)}},86775:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>f});var n=r(61125),o=r.n(n),a=r(76986),i=r.n(a),s=r(14418),l=r.n(s),u=r(97606),c=r.n(u),p=r(67294);class f extends p.Component{constructor(e,t){super(e,t),o()(this,"onChange",(e=>{let{onChange:t}=this.props,{value:r,name:n}=e.target,o=i()({},this.state.value);n?o[n]=r:o=r,this.setState({value:o},(()=>t(this.state)))}));let{name:r,schema:n}=this.props,a=this.getValue();this.state={name:r,schema:n,value:a}}getValue(){let{name:e,authorized:t}=this.props;return t&&t.getIn([e,"value"])}render(){var e;let{schema:t,getComponent:r,errSelectors:n,name:o}=this.props;const a=r("Input"),i=r("Row"),s=r("Col"),u=r("authError"),f=r("Markdown",!0),h=r("JumpToPath",!0),d=(t.get("scheme")||"").toLowerCase();let m=this.getValue(),g=l()(e=n.allErrors()).call(e,(e=>e.get("authId")===o));if("basic"===d){var v;let e=m?m.get("username"):null;return p.createElement("div",null,p.createElement("h4",null,p.createElement("code",null,o||t.get("name")),"  (http, Basic)",p.createElement(h,{path:["securityDefinitions",o]})),e&&p.createElement("h6",null,"Authorized"),p.createElement(i,null,p.createElement(f,{source:t.get("description")})),p.createElement(i,null,p.createElement("label",null,"Username:"),e?p.createElement("code",null," ",e," "):p.createElement(s,null,p.createElement(a,{type:"text",required:"required",name:"username","aria-label":"auth-basic-username",onChange:this.onChange,autoFocus:!0}))),p.createElement(i,null,p.createElement("label",null,"Password:"),e?p.createElement("code",null," ****** "):p.createElement(s,null,p.createElement(a,{autoComplete:"new-password",name:"password",type:"password","aria-label":"auth-basic-password",onChange:this.onChange}))),c()(v=g.valueSeq()).call(v,((e,t)=>p.createElement(u,{error:e,key:t}))))}var y;return"bearer"===d?p.createElement("div",null,p.createElement("h4",null,p.createElement("code",null,o||t.get("name")),"  (http, Bearer)",p.createElement(h,{path:["securityDefinitions",o]})),m&&p.createElement("h6",null,"Authorized"),p.createElement(i,null,p.createElement(f,{source:t.get("description")})),p.createElement(i,null,p.createElement("label",null,"Value:"),m?p.createElement("code",null," ****** "):p.createElement(s,null,p.createElement(a,{type:"text","aria-label":"auth-bearer-value",onChange:this.onChange,autoFocus:!0}))),c()(y=g.valueSeq()).call(y,((e,t)=>p.createElement(u,{error:e,key:t})))):p.createElement("div",null,p.createElement("em",null,p.createElement("b",null,o)," HTTP authentication: unsupported scheme ",`'${d}'`))}}},76467:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>p});var n=r(33427),o=r(42458),a=r(15757),i=r(56617),s=r(9928),l=r(45327),u=r(86775),c=r(96796);const p={Callbacks:n.default,HttpAuth:u.default,RequestBody:o.default,Servers:i.default,ServersContainer:s.default,RequestBodyEditor:l.default,OperationServers:c.default,operationLink:a.default}},15757:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>u});var n=r(35627),o=r.n(n),a=r(97606),i=r.n(a),s=r(67294);r(23930);class l extends s.Component{render(){const{link:e,name:t,getComponent:r}=this.props,n=r("Markdown",!0);let a=e.get("operationId")||e.get("operationRef"),l=e.get("parameters")&&e.get("parameters").toJS(),u=e.get("description");return s.createElement("div",{className:"operation-link"},s.createElement("div",{className:"description"},s.createElement("b",null,s.createElement("code",null,t)),u?s.createElement(n,{source:u}):null),s.createElement("pre",null,"Operation `",a,"`",s.createElement("br",null),s.createElement("br",null),"Parameters ",function(e,t){var r;if("string"!=typeof t)return"";return i()(r=t.split("\n")).call(r,((t,r)=>r>0?Array(e+1).join(" ")+t:t)).join("\n")}(0,o()(l,null,2))||"{}",s.createElement("br",null)))}}const u=l},96796:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>i});var n=r(61125),o=r.n(n),a=r(67294);r(23930);class i extends a.Component{constructor(){super(...arguments),o()(this,"setSelectedServer",(e=>{const{path:t,method:r}=this.props;return this.forceUpdate(),this.props.setSelectedServer(e,`${t}:${r}`)})),o()(this,"setServerVariableValue",(e=>{const{path:t,method:r}=this.props;return this.forceUpdate(),this.props.setServerVariableValue({...e,namespace:`${t}:${r}`})})),o()(this,"getSelectedServer",(()=>{const{path:e,method:t}=this.props;return this.props.getSelectedServer(`${e}:${t}`)})),o()(this,"getServerVariable",((e,t)=>{const{path:r,method:n}=this.props;return this.props.getServerVariable({namespace:`${r}:${n}`,server:e},t)})),o()(this,"getEffectiveServerValue",(e=>{const{path:t,method:r}=this.props;return this.props.getEffectiveServerValue({server:e,namespace:`${t}:${r}`})}))}render(){const{operationServers:e,pathServers:t,getComponent:r}=this.props;if(!e&&!t)return null;const n=r("Servers"),o=e||t,i=e?"operation":"path";return a.createElement("div",{className:"opblock-section operation-servers"},a.createElement("div",{className:"opblock-section-header"},a.createElement("div",{className:"tab-header"},a.createElement("h4",{className:"opblock-title"},"Servers"))),a.createElement("div",{className:"opblock-description-wrapper"},a.createElement("h4",{className:"message"},"These ",i,"-level options override the global server options."),a.createElement(n,{servers:o,currentServer:this.getSelectedServer(),setSelectedServer:this.setSelectedServer,setServerVariableValue:this.setServerVariableValue,getServerVariable:this.getServerVariable,getEffectiveServerValue:this.getEffectiveServerValue})))}}},45327:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>c});var n=r(61125),o=r.n(n),a=r(67294),i=r(94184),s=r.n(i),l=r(90242);const u=Function.prototype;class c extends a.PureComponent{constructor(e,t){super(e,t),o()(this,"applyDefaultValue",(e=>{const{onChange:t,defaultValue:r}=e||this.props;return this.setState({value:r}),t(r)})),o()(this,"onChange",(e=>{this.props.onChange((0,l.Pz)(e))})),o()(this,"onDomChange",(e=>{const t=e.target.value;this.setState({value:t},(()=>this.onChange(t)))})),this.state={value:(0,l.Pz)(e.value)||e.defaultValue},e.onChange(e.value)}UNSAFE_componentWillReceiveProps(e){this.props.value!==e.value&&e.value!==this.state.value&&this.setState({value:(0,l.Pz)(e.value)}),!e.value&&e.defaultValue&&this.state.value&&this.applyDefaultValue(e)}render(){let{getComponent:e,errors:t}=this.props,{value:r}=this.state,n=t.size>0;const o=e("TextArea");return a.createElement("div",{className:"body-param"},a.createElement(o,{className:s()("body-param__text",{invalid:n}),title:t.size?t.join(", "):"",value:r,onChange:this.onDomChange}))}}o()(c,"defaultProps",{onChange:u,userHasEditedBody:!1})},42458:(e,t,r)=>{"use strict";r.r(t),r.d(t,{getDefaultRequestBodyValue:()=>m,default:()=>g});var n=r(97606),o=r.n(n),a=r(11882),i=r.n(a),s=r(58118),l=r.n(s),u=r(58309),c=r.n(u),p=r(67294),f=(r(23930),r(43393)),h=r(90242),d=r(2518);const m=(e,t,r)=>{const n=e.getIn(["content",t]),o=n.get("schema").toJS(),a=void 0!==n.get("examples"),i=n.get("example"),s=a?n.getIn(["examples",r,"value"]):i,l=(0,h.xi)(o,t,{includeWriteOnly:!0},s);return(0,h.Pz)(l)},g=e=>{let{userHasEditedBody:t,requestBody:r,requestBodyValue:n,requestBodyInclusionSetting:a,requestBodyErrors:s,getComponent:u,getConfigs:g,specSelectors:v,fn:y,contentType:b,isExecute:w,specPath:E,onChange:x,onChangeIncludeEmpty:_,activeExamplesKey:S,updateActiveExamplesKey:A,setRetainRequestBodyValueFlag:k}=e;const C=e=>{x(e.target.files[0])},O=e=>{let t={key:e,shouldDispatchInit:!1,defaultValue:!0};return"no value"===a.get(e,"no value")&&(t.shouldDispatchInit=!0),t},j=u("Markdown",!0),I=u("modelExample"),N=u("RequestBodyEditor"),T=u("highlightCode"),P=u("ExamplesSelectValueRetainer"),R=u("Example"),M=u("ParameterIncludeEmpty"),{showCommonExtensions:D}=g(),L=r&&r.get("description")||null,B=r&&r.get("content")||new f.OrderedMap;b=b||B.keySeq().first()||"";const F=B.get(b,(0,f.OrderedMap)()),z=F.get("schema",(0,f.OrderedMap)()),U=F.get("examples",null),q=null==U?void 0:o()(U).call(U,((e,t)=>{var n;const o=null===(n=e)||void 0===n?void 0:n.get("value",null);return o&&(e=e.set("value",m(r,b,t),o)),e}));if(s=f.List.isList(s)?s:(0,f.List)(),!F.size)return null;const V="object"===F.getIn(["schema","type"]),$="binary"===F.getIn(["schema","format"]),W="base64"===F.getIn(["schema","format"]);if("application/octet-stream"===b||0===i()(b).call(b,"image/")||0===i()(b).call(b,"audio/")||0===i()(b).call(b,"video/")||$||W){const e=u("Input");return w?p.createElement(e,{type:"file",onChange:C}):p.createElement("i",null,"Example values are not available for ",p.createElement("code",null,b)," media types.")}if(V&&("application/x-www-form-urlencoded"===b||0===i()(b).call(b,"multipart/"))&&z.get("properties",(0,f.OrderedMap)()).size>0){var H;const e=u("JsonSchemaForm"),t=u("ParameterExt"),r=z.get("properties",(0,f.OrderedMap)());return n=f.Map.isMap(n)?n:(0,f.OrderedMap)(),p.createElement("div",{className:"table-container"},L&&p.createElement(j,{source:L}),p.createElement("table",null,p.createElement("tbody",null,f.Map.isMap(r)&&o()(H=r.entrySeq()).call(H,(r=>{var i,d;let[m,g]=r;if(g.get("readOnly"))return;let v=D?(0,h.po)(g):null;const b=l()(i=z.get("required",(0,f.List)())).call(i,m),E=g.get("type"),S=g.get("format"),A=g.get("description"),k=n.getIn([m,"value"]),C=n.getIn([m,"errors"])||s,I=a.get(m)||!1,N=g.has("default")||g.has("example")||g.hasIn(["items","example"])||g.hasIn(["items","default"]),T=g.has("enum")&&(1===g.get("enum").size||b),P=N||T;let R="";"array"!==E||P||(R=[]),("object"===E||P)&&(R=(0,h.xi)(g,!1,{includeWriteOnly:!0})),"string"!=typeof R&&"object"===E&&(R=(0,h.Pz)(R)),"string"==typeof R&&"array"===E&&(R=JSON.parse(R));const L="string"===E&&("binary"===S||"base64"===S);return p.createElement("tr",{key:m,className:"parameters","data-property-name":m},p.createElement("td",{className:"parameters-col_name"},p.createElement("div",{className:b?"parameter__name required":"parameter__name"},m,b?p.createElement("span",null," *"):null),p.createElement("div",{className:"parameter__type"},E,S&&p.createElement("span",{className:"prop-format"},"($",S,")"),D&&v.size?o()(d=v.entrySeq()).call(d,(e=>{let[r,n]=e;return p.createElement(t,{key:`${r}-${n}`,xKey:r,xVal:n})})):null),p.createElement("div",{className:"parameter__deprecated"},g.get("deprecated")?"deprecated":null)),p.createElement("td",{className:"parameters-col_description"},p.createElement(j,{source:A}),w?p.createElement("div",null,p.createElement(e,{fn:y,dispatchInitialValue:!L,schema:g,description:m,getComponent:u,value:void 0===k?R:k,required:b,errors:C,onChange:e=>{x(e,[m])}}),b?null:p.createElement(M,{onChange:e=>_(m,e),isIncluded:I,isIncludedOptions:O(m),isDisabled:c()(k)?0!==k.length:!(0,h.O2)(k)})):null))})))))}const J=m(r,b,S);let K=null;return(0,d.O)(J)&&(K="json"),p.createElement("div",null,L&&p.createElement(j,{source:L}),q?p.createElement(P,{userHasEditedBody:t,examples:q,currentKey:S,currentUserInputValue:n,onSelect:e=>{A(e)},updateValue:x,defaultToFirstExample:!0,getComponent:u,setRetainRequestBodyValueFlag:k}):null,w?p.createElement("div",null,p.createElement(N,{value:n,errors:s,defaultValue:J,onChange:x,getComponent:u})):p.createElement(I,{getComponent:u,getConfigs:g,specSelectors:v,expandDepth:1,isExecute:w,schema:F.get("schema"),specPath:E.push("content",b),example:p.createElement(T,{className:"body-param__example",getConfigs:g,language:K,value:(0,h.Pz)(n)||J}),includeWriteOnly:!0}),q?p.createElement(R,{example:q.get(S),getComponent:u,getConfigs:g}):null)}},9928:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>o});var n=r(67294);class o extends n.Component{render(){const{specSelectors:e,oas3Selectors:t,oas3Actions:r,getComponent:o}=this.props,a=e.servers(),i=o("Servers");return a&&a.size?n.createElement("div",null,n.createElement("span",{className:"servers-title"},"Servers"),n.createElement(i,{servers:a,currentServer:t.selectedServer(),setSelectedServer:r.setSelectedServer,setServerVariableValue:r.setServerVariableValue,getServerVariable:t.serverVariableValue,getEffectiveServerValue:t.serverEffectiveValue})):null}}},56617:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>p});var n=r(61125),o=r.n(n),a=r(51679),i=r.n(a),s=r(97606),l=r.n(s),u=r(67294),c=r(43393);r(23930);class p extends u.Component{constructor(){super(...arguments),o()(this,"onServerChange",(e=>{this.setServer(e.target.value)})),o()(this,"onServerVariableValueChange",(e=>{let{setServerVariableValue:t,currentServer:r}=this.props,n=e.target.getAttribute("data-variable"),o=e.target.value;"function"==typeof t&&t({server:r,key:n,val:o})})),o()(this,"setServer",(e=>{let{setSelectedServer:t}=this.props;t(e)}))}componentDidMount(){var e;let{servers:t,currentServer:r}=this.props;r||this.setServer(null===(e=t.first())||void 0===e?void 0:e.get("url"))}UNSAFE_componentWillReceiveProps(e){let{servers:t,setServerVariableValue:r,getServerVariable:n}=e;if(this.props.currentServer!==e.currentServer||this.props.servers!==e.servers){var o;let a=i()(t).call(t,(t=>t.get("url")===e.currentServer)),s=i()(o=this.props.servers).call(o,(e=>e.get("url")===this.props.currentServer))||(0,c.OrderedMap)();if(!a)return this.setServer(t.first().get("url"));let u=s.get("variables")||(0,c.OrderedMap)(),p=(i()(u).call(u,(e=>e.get("default")))||(0,c.OrderedMap)()).get("default"),f=a.get("variables")||(0,c.OrderedMap)(),h=(i()(f).call(f,(e=>e.get("default")))||(0,c.OrderedMap)()).get("default");l()(f).call(f,((t,o)=>{n(e.currentServer,o)&&p===h||r({server:e.currentServer,key:o,val:t.get("default")||""})}))}}render(){var e,t;let{servers:r,currentServer:n,getServerVariable:o,getEffectiveServerValue:a}=this.props,s=(i()(r).call(r,(e=>e.get("url")===n))||(0,c.OrderedMap)()).get("variables")||(0,c.OrderedMap)(),p=0!==s.size;return u.createElement("div",{className:"servers"},u.createElement("label",{htmlFor:"servers"},u.createElement("select",{onChange:this.onServerChange,value:n},l()(e=r.valueSeq()).call(e,(e=>u.createElement("option",{value:e.get("url"),key:e.get("url")},e.get("url"),e.get("description")&&` - ${e.get("description")}`))).toArray())),p?u.createElement("div",null,u.createElement("div",{className:"computed-url"},"Computed URL:",u.createElement("code",null,a(n))),u.createElement("h4",null,"Server variables"),u.createElement("table",null,u.createElement("tbody",null,l()(t=s.entrySeq()).call(t,(e=>{var t;let[r,a]=e;return u.createElement("tr",{key:r},u.createElement("td",null,r),u.createElement("td",null,a.get("enum")?u.createElement("select",{"data-variable":r,onChange:this.onServerVariableValueChange},l()(t=a.get("enum")).call(t,(e=>u.createElement("option",{selected:e===o(n,r),key:e,value:e},e)))):u.createElement("input",{type:"text",value:o(n,r)||"",onChange:this.onServerVariableValueChange,"data-variable":r})))}))))):null)}}},7779:(e,t,r)=>{"use strict";r.r(t),r.d(t,{isOAS3:()=>l,isSwagger2:()=>u,OAS3ComponentWrapFactory:()=>c});var n=r(23101),o=r.n(n),a=r(27043),i=r.n(a),s=r(67294);function l(e){const t=e.get("openapi");return"string"==typeof t&&(i()(t).call(t,"3.0.")&&t.length>4)}function u(e){const t=e.get("swagger");return"string"==typeof t&&i()(t).call(t,"2.0")}function c(e){return(t,r)=>n=>{if(r&&r.specSelectors&&r.specSelectors.specJson){return l(r.specSelectors.specJson())?s.createElement(e,o()({},n,r,{Ori:t})):s.createElement(t,n)}return console.warn("OAS3 wrapper: couldn't get spec"),null}}},97451:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>p});var n=r(92044),o=r(73723),a=r(91741),i=r(76467),s=r(37761),l=r(67002),u=r(5065),c=r(62109);function p(){return{components:i.default,wrapComponents:s.default,statePlugins:{spec:{wrapSelectors:n,selectors:a},auth:{wrapSelectors:o},oas3:{actions:l,reducers:c.default,selectors:u}}}}},62109:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>p});var n=r(8712),o=r.n(n),a=r(86),i=r.n(a),s=r(24282),l=r.n(s),u=r(43393),c=r(67002);const p={[c.UPDATE_SELECTED_SERVER]:(e,t)=>{let{payload:{selectedServerUrl:r,namespace:n}}=t;const o=n?[n,"selectedServer"]:["selectedServer"];return e.setIn(o,r)},[c.UPDATE_REQUEST_BODY_VALUE]:(e,t)=>{let{payload:{value:r,pathMethod:n}}=t,[a,s]=n;if(!u.Map.isMap(r))return e.setIn(["requestData",a,s,"bodyValue"],r);let l,c=e.getIn(["requestData",a,s,"bodyValue"])||(0,u.Map)();u.Map.isMap(c)||(c=(0,u.Map)());const[...p]=o()(r).call(r);return i()(p).call(p,(e=>{let t=r.getIn([e]);c.has(e)&&u.Map.isMap(t)||(l=c.setIn([e,"value"],t))})),e.setIn(["requestData",a,s,"bodyValue"],l)},[c.UPDATE_REQUEST_BODY_VALUE_RETAIN_FLAG]:(e,t)=>{let{payload:{value:r,pathMethod:n}}=t,[o,a]=n;return e.setIn(["requestData",o,a,"retainBodyValue"],r)},[c.UPDATE_REQUEST_BODY_INCLUSION]:(e,t)=>{let{payload:{value:r,pathMethod:n,name:o}}=t,[a,i]=n;return e.setIn(["requestData",a,i,"bodyInclusion",o],r)},[c.UPDATE_ACTIVE_EXAMPLES_MEMBER]:(e,t)=>{let{payload:{name:r,pathMethod:n,contextType:o,contextName:a}}=t,[i,s]=n;return e.setIn(["examples",i,s,o,a,"activeExample"],r)},[c.UPDATE_REQUEST_CONTENT_TYPE]:(e,t)=>{let{payload:{value:r,pathMethod:n}}=t,[o,a]=n;return e.setIn(["requestData",o,a,"requestContentType"],r)},[c.UPDATE_RESPONSE_CONTENT_TYPE]:(e,t)=>{let{payload:{value:r,path:n,method:o}}=t;return e.setIn(["requestData",n,o,"responseContentType"],r)},[c.UPDATE_SERVER_VARIABLE_VALUE]:(e,t)=>{let{payload:{server:r,namespace:n,key:o,val:a}}=t;const i=n?[n,"serverVariableValues",r,o]:["serverVariableValues",r,o];return e.setIn(i,a)},[c.SET_REQUEST_BODY_VALIDATE_ERROR]:(e,t)=>{let{payload:{path:r,method:n,validationErrors:o}}=t,a=[];if(a.push("Required field is not provided"),o.missingBodyValue)return e.setIn(["requestData",r,n,"errors"],(0,u.fromJS)(a));if(o.missingRequiredKeys&&o.missingRequiredKeys.length>0){const{missingRequiredKeys:t}=o;return e.updateIn(["requestData",r,n,"bodyValue"],(0,u.fromJS)({}),(e=>l()(t).call(t,((e,t)=>e.setIn([t,"errors"],(0,u.fromJS)(a))),e)))}return console.warn("unexpected result: SET_REQUEST_BODY_VALIDATE_ERROR"),e},[c.CLEAR_REQUEST_BODY_VALIDATE_ERROR]:(e,t)=>{let{payload:{path:r,method:n}}=t;const a=e.getIn(["requestData",r,n,"bodyValue"]);if(!u.Map.isMap(a))return e.setIn(["requestData",r,n,"errors"],(0,u.fromJS)([]));const[...i]=o()(a).call(a);return i?e.updateIn(["requestData",r,n,"bodyValue"],(0,u.fromJS)({}),(e=>l()(i).call(i,((e,t)=>e.setIn([t,"errors"],(0,u.fromJS)([]))),e))):e},[c.CLEAR_REQUEST_BODY_VALUE]:(e,t)=>{let{payload:{pathMethod:r}}=t,[n,o]=r;const a=e.getIn(["requestData",n,o,"bodyValue"]);return a?u.Map.isMap(a)?e.setIn(["requestData",n,o,"bodyValue"],(0,u.Map)()):e.setIn(["requestData",n,o,"bodyValue"],""):e}}},5065:(e,t,r)=>{"use strict";r.r(t),r.d(t,{selectedServer:()=>g,requestBodyValue:()=>v,shouldRetainRequestBodyValue:()=>y,hasUserEditedBody:()=>b,requestBodyInclusionSetting:()=>w,requestBodyErrors:()=>E,activeExamplesMember:()=>x,requestContentType:()=>_,responseContentType:()=>S,serverVariableValue:()=>A,serverVariables:()=>k,serverEffectiveValue:()=>C,validateBeforeExecute:()=>O,validateShallowRequired:()=>I});var n=r(97606),o=r.n(n),a=r(86),i=r.n(a),s=r(28222),l=r.n(s),u=r(11882),c=r.n(u),p=r(43393),f=r(7779),h=r(42458),d=r(90242);function m(e){return function(){for(var t=arguments.length,r=new Array(t),n=0;n{const n=t.getSystem().specSelectors.specJson();return(0,f.isOAS3)(n)?e(...r):null}}}const g=m(((e,t)=>{const r=t?[t,"selectedServer"]:["selectedServer"];return e.getIn(r)||""})),v=m(((e,t,r)=>e.getIn(["requestData",t,r,"bodyValue"])||null)),y=m(((e,t,r)=>e.getIn(["requestData",t,r,"retainBodyValue"])||!1)),b=(e,t,r)=>e=>{const{oas3Selectors:n,specSelectors:o}=e.getSystem(),a=o.specJson();if((0,f.isOAS3)(a)){let e=!1;const a=n.requestContentType(t,r);let i=n.requestBodyValue(t,r);if(p.Map.isMap(i)&&(i=(0,d.Pz)(i.mapEntries((e=>p.Map.isMap(e[1])?[e[0],e[1].get("value")]:e)).toJS())),p.List.isList(i)&&(i=(0,d.Pz)(i)),a){const s=(0,h.getDefaultRequestBodyValue)(o.specResolvedSubtree(["paths",t,r,"requestBody"]),a,n.activeExamplesMember(t,r,"requestBody","requestBody"));e=!!i&&i!==s}return e}return null},w=m(((e,t,r)=>e.getIn(["requestData",t,r,"bodyInclusion"])||(0,p.Map)())),E=m(((e,t,r)=>e.getIn(["requestData",t,r,"errors"])||null)),x=m(((e,t,r,n,o)=>e.getIn(["examples",t,r,n,o,"activeExample"])||null)),_=m(((e,t,r)=>e.getIn(["requestData",t,r,"requestContentType"])||null)),S=m(((e,t,r)=>e.getIn(["requestData",t,r,"responseContentType"])||null)),A=m(((e,t,r)=>{let n;if("string"!=typeof t){const{server:e,namespace:o}=t;n=o?[o,"serverVariableValues",e,r]:["serverVariableValues",e,r]}else{n=["serverVariableValues",t,r]}return e.getIn(n)||null})),k=m(((e,t)=>{let r;if("string"!=typeof t){const{server:e,namespace:n}=t;r=n?[n,"serverVariableValues",e]:["serverVariableValues",e]}else{r=["serverVariableValues",t]}return e.getIn(r)||(0,p.OrderedMap)()})),C=m(((e,t)=>{var r,n;if("string"!=typeof t){const{server:o,namespace:a}=t;n=o,r=a?e.getIn([a,"serverVariableValues",n]):e.getIn(["serverVariableValues",n])}else n=t,r=e.getIn(["serverVariableValues",n]);r=r||(0,p.OrderedMap)();let a=n;return o()(r).call(r,((e,t)=>{a=a.replace(new RegExp(`{${t}}`,"g"),e)})),a})),O=(j=(e,t)=>((e,t)=>(t=t||[],!!e.getIn(["requestData",...t,"bodyValue"])))(e,t),function(){for(var e=arguments.length,t=new Array(e),r=0;r{const r=e.getSystem().specSelectors.specJson();let n=[...t][1]||[];return!r.getIn(["paths",...n,"requestBody","required"])||j(...t)}});var j;const I=(e,t)=>{var r;let{oas3RequiredRequestBodyContentType:n,oas3RequestContentType:o,oas3RequestBodyValue:a}=t,s=[];if(!p.Map.isMap(a))return s;let u=[];return i()(r=l()(n.requestContentType)).call(r,(e=>{if(e===o){let t=n.requestContentType[e];i()(t).call(t,(e=>{c()(u).call(u,e)<0&&u.push(e)}))}})),i()(u).call(u,(e=>{a.getIn([e,"value"])||s.push(e)})),s}},91741:(e,t,r)=>{"use strict";r.r(t),r.d(t,{servers:()=>u,isSwagger2:()=>p});var n=r(20573),o=r(43393),a=r(7779);const i=e=>e||(0,o.Map)(),s=(0,n.P1)(i,(e=>e.get("json",(0,o.Map)()))),l=(0,n.P1)(i,(e=>e.get("resolved",(0,o.Map)()))),u=(c=(0,n.P1)((e=>{let t=l(e);return t.count()<1&&(t=s(e)),t}),(e=>e.getIn(["servers"])||(0,o.Map)())),()=>function(e){const t=e.getSystem().specSelectors.specJson();if((0,a.isOAS3)(t)){for(var r=arguments.length,n=new Array(r>1?r-1:0),o=1;o()=>{const e=t.getSystem().specSelectors.specJson();return(0,a.isSwagger2)(e)}},92044:(e,t,r)=>{"use strict";r.r(t),r.d(t,{definitions:()=>h,hasHost:()=>d,securityDefinitions:()=>m,host:()=>g,basePath:()=>v,consumes:()=>y,produces:()=>b,schemes:()=>w,servers:()=>E,isOAS3:()=>x,isSwagger2:()=>_});var n=r(20573),o=r(33881),a=r(43393),i=r(7779);function s(e){return(t,r)=>function(){const n=r.getSystem().specSelectors.specJson();return(0,i.isOAS3)(n)?e(...arguments):t(...arguments)}}const l=e=>e||(0,a.Map)(),u=s((0,n.P1)((()=>null))),c=(0,n.P1)(l,(e=>e.get("json",(0,a.Map)()))),p=(0,n.P1)(l,(e=>e.get("resolved",(0,a.Map)()))),f=e=>{let t=p(e);return t.count()<1&&(t=c(e)),t},h=s((0,n.P1)(f,(e=>{const t=e.getIn(["components","schemas"]);return a.Map.isMap(t)?t:(0,a.Map)()}))),d=s((e=>f(e).hasIn(["servers",0]))),m=s((0,n.P1)(o.specJsonWithResolvedSubtrees,(e=>e.getIn(["components","securitySchemes"])||null))),g=u,v=u,y=u,b=u,w=u,E=s((0,n.P1)(f,(e=>e.getIn(["servers"])||(0,a.Map)()))),x=(e,t)=>()=>{const e=t.getSystem().specSelectors.specJson();return(0,i.isOAS3)(a.Map.isMap(e)?e:(0,a.Map)())},_=(e,t)=>()=>{const e=t.getSystem().specSelectors.specJson();return(0,i.isSwagger2)(a.Map.isMap(e)?e:(0,a.Map)())}},70356:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>o});var n=r(67294);const o=(0,r(7779).OAS3ComponentWrapFactory)((e=>{let{Ori:t,...r}=e;const{schema:o,getComponent:a,errSelectors:i,authorized:s,onAuthChange:l,name:u}=r,c=a("HttpAuth");return"http"===o.get("type")?n.createElement(c,{key:u,schema:o,name:u,errSelectors:i,authorized:s,getComponent:a,onChange:l}):n.createElement(t,r)}))},37761:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>u});var n=r(22460),o=r(70356),a=r(69487),i=r(50058),s=r(53499),l=r(90287);const u={Markdown:n.default,AuthItem:o.default,JsonSchema_string:l.default,VersionStamp:a.default,model:s.default,onlineValidatorBadge:i.default}},90287:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>o});var n=r(67294);const o=(0,r(7779).OAS3ComponentWrapFactory)((e=>{let{Ori:t,...r}=e;const{schema:o,getComponent:a,errors:i,onChange:s}=r,l=o&&o.get?o.get("format"):null,u=o&&o.get?o.get("type"):null,c=a("Input");return u&&"string"===u&&l&&("binary"===l||"base64"===l)?n.createElement(c,{type:"file",className:i.length?"invalid":"",title:i.length?i:"",onChange:e=>{s(e.target.files[0])},disabled:t.isDisabled}):n.createElement(t,r)}))},22460:(e,t,r)=>{"use strict";r.r(t),r.d(t,{Markdown:()=>f,default:()=>h});var n=r(81607),o=r.n(n),a=r(67294),i=r(94184),s=r.n(i),l=r(89927),u=r(7779),c=r(86019);const p=new l._("commonmark");p.block.ruler.enable(["table"]),p.set({linkTarget:"_blank"});const f=e=>{let{source:t,className:r="",getConfigs:n}=e;if("string"!=typeof t)return null;if(t){const{useUnsafeMarkdown:e}=n(),i=p.render(t),l=(0,c.s)(i,{useUnsafeMarkdown:e});let u;return"string"==typeof l&&(u=o()(l).call(l)),a.createElement("div",{dangerouslySetInnerHTML:{__html:u},className:s()(r,"renderedMarkdown")})}return null};f.defaultProps={getConfigs:()=>({useUnsafeMarkdown:!1})};const h=(0,u.OAS3ComponentWrapFactory)(f)},53499:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>u});var n=r(23101),o=r.n(n),a=r(67294),i=r(7779),s=r(53795);class l extends a.Component{render(){let{getConfigs:e,schema:t}=this.props,r=["model-box"],n=null;return!0===t.get("deprecated")&&(r.push("deprecated"),n=a.createElement("span",{className:"model-deprecated-warning"},"Deprecated:")),a.createElement("div",{className:r.join(" ")},n,a.createElement(s.Z,o()({},this.props,{getConfigs:e,depth:1,expandDepth:this.props.expandDepth||0})))}}const u=(0,i.OAS3ComponentWrapFactory)(l)},50058:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>a});var n=r(7779),o=r(5623);const a=(0,n.OAS3ComponentWrapFactory)(o.Z)},69487:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>o});var n=r(67294);const o=(0,r(7779).OAS3ComponentWrapFactory)((e=>{const{Ori:t}=e;return n.createElement("span",null,n.createElement(t,e),n.createElement("small",{className:"version-stamp"},n.createElement("pre",{className:"version"},"OAS3")))}))},28560:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>i});var n=r(87198),o=r.n(n);let a=!1;function i(){return{statePlugins:{spec:{wrapActions:{updateSpec:e=>function(){return a=!0,e(...arguments)},updateJsonSpec:(e,t)=>function(){const r=t.getConfigs().onComplete;return a&&"function"==typeof r&&(o()(r,0),a=!1),e(...arguments)}}}}}}},92135:(e,t,r)=>{"use strict";r.r(t),r.d(t,{requestSnippetGenerator_curl_powershell:()=>A,requestSnippetGenerator_curl_bash:()=>k,requestSnippetGenerator_curl_cmd:()=>C});var n=r(11882),o=r.n(n),a=r(81607),i=r.n(a),s=r(35627),l=r.n(s),u=r(97606),c=r.n(u),p=r(12196),f=r.n(p),h=r(74386),d=r.n(h),m=r(58118),g=r.n(m),v=r(27504),y=r(43393);const b=e=>{var t;const r="_**[]";return o()(e).call(e,r)<0?e:i()(t=e.split(r)[0]).call(t)},w=e=>"-d "===e||/^[_\/-]/g.test(e)?e:"'"+e.replace(/'/g,"'\\''")+"'",E=e=>"-d "===(e=e.replace(/\^/g,"^^").replace(/\\"/g,'\\\\"').replace(/"/g,'""').replace(/\n/g,"^\n"))?e.replace(/-d /g,"-d ^\n"):/^[_\/-]/g.test(e)?e:'"'+e+'"',x=e=>"-d "===e?e:/\n/.test(e)?'@"\n'+e.replace(/"/g,'\\"').replace(/`/g,"``").replace(/\$/,"`$")+'\n"@':/^[_\/-]/g.test(e)?e:"'"+e.replace(/"/g,'""').replace(/'/g,"''")+"'";function _(e){let t=[];for(let[r,n]of e.get("body").entrySeq()){let e=b(r);n instanceof v.Z.File?t.push(` "${e}": {\n "name": "${n.name}"${n.type?`,\n "type": "${n.type}"`:""}\n }`):t.push(` "${e}": ${l()(n,null,2).replace(/(\r\n|\r|\n)/g,"\n ")}`)}return`{\n${t.join(",\n")}\n}`}const S=function(e,t,r){let n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"",o=!1,a="";const i=function(){for(var e=arguments.length,r=new Array(e),n=0;na+=` ${r}`,p=function(){var e;let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1;return a+=f()(e=" ").call(e,t)};let h=e.get("headers");if(a+="curl"+n,e.has("curlOptions")&&i(...e.get("curlOptions")),i("-X",e.get("method")),u(),p(),s(`${e.get("url")}`),h&&h.size)for(let t of d()(m=e.get("headers")).call(m)){var m;u(),p();let[e,r]=t;s("-H",`${e}: ${r}`),o=o||/^content-type$/i.test(e)&&/^multipart\/form-data$/i.test(r)}const w=e.get("body");var E;if(w)if(o&&g()(E=["POST","PUT","PATCH"]).call(E,e.get("method")))for(let[e,t]of w.entrySeq()){let r=b(e);u(),p(),s("-F"),t instanceof v.Z.File?i(`${r}=@${t.name}${t.type?`;type=${t.type}`:""}`):i(`${r}=${t}`)}else if(w instanceof v.Z.File)u(),p(),s(`--data-binary '@${w.name}'`);else{u(),p(),s("-d ");let t=w;y.Map.isMap(t)?s(_(e)):("string"!=typeof t&&(t=l()(t)),s(t))}else w||"POST"!==e.get("method")||(u(),p(),s("-d ''"));return a},A=e=>S(e,x,"`\n",".exe"),k=e=>S(e,w,"\\\n"),C=e=>S(e,E,"^\n")},86575:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>i});var n=r(92135),o=r(4669),a=r(84206);const i=()=>({components:{RequestSnippets:a.default},fn:n,statePlugins:{requestSnippets:{selectors:o}}})},84206:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>w});var n=r(14418),o=r.n(n),a=r(25110),i=r.n(a),s=r(86),l=r.n(s),u=r(97606),c=r.n(u),p=r(67294),f=r(27361),h=r.n(f),d=r(23560),m=r.n(d),g=r(74855),v=r(36581);const y={cursor:"pointer",lineHeight:1,display:"inline-flex",backgroundColor:"rgb(250, 250, 250)",paddingBottom:"0",paddingTop:"0",border:"1px solid rgb(51, 51, 51)",borderRadius:"4px 4px 0 0",boxShadow:"none",borderBottom:"none"},b={cursor:"pointer",lineHeight:1,display:"inline-flex",backgroundColor:"rgb(51, 51, 51)",boxShadow:"none",border:"1px solid rgb(51, 51, 51)",paddingBottom:"0",paddingTop:"0",borderRadius:"4px 4px 0 0",marginTop:"-5px",marginRight:"-5px",marginLeft:"-5px",zIndex:"9999",borderBottom:"none"},w=e=>{var t,r;let{request:n,requestSnippetsSelectors:a,getConfigs:s}=e;const u=m()(s)?s():null,f=!1!==h()(u,"syntaxHighlight")&&h()(u,"syntaxHighlight.activated",!0),d=(0,p.useRef)(null),[w,E]=(0,p.useState)(null===(t=a.getSnippetGenerators())||void 0===t?void 0:t.keySeq().first()),[x,_]=(0,p.useState)(null==a?void 0:a.getDefaultExpanded());(0,p.useEffect)((()=>{}),[]),(0,p.useEffect)((()=>{var e;const t=o()(e=i()(d.current.childNodes)).call(e,(e=>{var t;return!!e.nodeType&&(null===(t=e.classList)||void 0===t?void 0:t.contains("curl-command"))}));return l()(t).call(t,(e=>e.addEventListener("mousewheel",j,{passive:!1}))),()=>{l()(t).call(t,(e=>e.removeEventListener("mousewheel",j)))}}),[n]);const S=a.getSnippetGenerators(),A=S.get(w),k=A.get("fn")(n),C=()=>{_(!x)},O=e=>e===w?b:y,j=e=>{const{target:t,deltaY:r}=e,{scrollHeight:n,offsetHeight:o,scrollTop:a}=t;n>o&&(0===a&&r<0||o+a>=n&&r>0)&&e.preventDefault()},I=f?p.createElement(v.d3,{language:A.get("syntax"),className:"curl microlight",style:(0,v.C2)(h()(u,"syntaxHighlight.theme"))},k):p.createElement("textarea",{readOnly:!0,className:"curl",value:k});return p.createElement("div",{className:"request-snippets",ref:d},p.createElement("div",{style:{width:"100%",display:"flex",justifyContent:"flex-start",alignItems:"center",marginBottom:"15px"}},p.createElement("h4",{onClick:()=>C(),style:{cursor:"pointer"}},"Snippets"),p.createElement("button",{onClick:()=>C(),style:{border:"none",background:"none"},title:x?"Collapse operation":"Expand operation"},p.createElement("svg",{className:"arrow",width:"10",height:"10"},p.createElement("use",{href:x?"#large-arrow-down":"#large-arrow",xlinkHref:x?"#large-arrow-down":"#large-arrow"})))),x&&p.createElement("div",{className:"curl-command"},p.createElement("div",{style:{paddingLeft:"15px",paddingRight:"10px",width:"100%",display:"flex"}},c()(r=S.entrySeq()).call(r,(e=>{let[t,r]=e;return p.createElement("div",{style:O(t),className:"btn",key:t,onClick:()=>(e=>{w!==e&&E(e)})(t)},p.createElement("h4",{style:t===w?{color:"white"}:{}},r.get("title")))}))),p.createElement("div",{className:"copy-to-clipboard"},p.createElement(g.CopyToClipboard,{text:k},p.createElement("button",null))),p.createElement("div",null,I)))}},4669:(e,t,r)=>{"use strict";r.r(t),r.d(t,{getGenerators:()=>f,getSnippetGenerators:()=>h,getActiveLanguage:()=>d,getDefaultExpanded:()=>m});var n=r(14418),o=r.n(n),a=r(58118),i=r.n(a),s=r(97606),l=r.n(s),u=r(20573),c=r(43393);const p=e=>e||(0,c.Map)(),f=(0,u.P1)(p,(e=>{const t=e.get("languages"),r=e.get("generators",(0,c.Map)());return!t||t.isEmpty()?r:o()(r).call(r,((e,r)=>i()(t).call(t,r)))})),h=e=>t=>{var r,n;let{fn:a}=t;return o()(r=l()(n=f(e)).call(n,((e,t)=>{const r=(e=>a[`requestSnippetGenerator_${e}`])(t);return"function"!=typeof r?null:e.set("fn",r)}))).call(r,(e=>e))},d=(0,u.P1)(p,(e=>e.get("activeLanguage"))),m=(0,u.P1)(p,(e=>e.get("defaultExpanded")))},36195:(e,t,r)=>{"use strict";r.r(t),r.d(t,{ErrorBoundary:()=>i,default:()=>s});var n=r(67294),o=r(56189),a=r(29403);class i extends n.Component{static getDerivedStateFromError(e){return{hasError:!0,error:e}}constructor(){super(...arguments),this.state={hasError:!1,error:null}}componentDidCatch(e,t){this.props.fn.componentDidCatch(e,t)}render(){const{getComponent:e,targetName:t,children:r}=this.props;if(this.state.hasError){const r=e("Fallback");return n.createElement(r,{name:t})}return r}}i.defaultProps={targetName:"this component",getComponent:()=>a.default,fn:{componentDidCatch:o.componentDidCatch},children:null};const s=i},29403:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>o});var n=r(67294);const o=e=>{let{name:t}=e;return n.createElement("div",{className:"fallback"},"😱 ",n.createElement("i",null,"Could not render ","t"===t?"this component":t,", see the console."))}},56189:(e,t,r)=>{"use strict";r.r(t),r.d(t,{componentDidCatch:()=>i,withErrorBoundary:()=>s});var n=r(23101),o=r.n(n),a=r(67294);const i=console.error,s=e=>t=>{const{getComponent:r,fn:n}=e(),i=r("ErrorBoundary"),s=n.getDisplayName(t);class l extends a.Component{render(){return a.createElement(i,{targetName:s,getComponent:r,fn:n},a.createElement(t,o()({},this.props,this.context)))}}var u;return l.displayName=`WithErrorBoundary(${s})`,(u=t).prototype&&u.prototype.isReactComponent&&(l.prototype.mapStateToProps=t.prototype.mapStateToProps),l}},27621:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>c});var n=r(47475),o=r.n(n),a=r(7287),i=r.n(a),s=r(36195),l=r(29403),u=r(56189);const c=function(){let{componentList:e=[],fullOverride:t=!1}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return r=>{var n;let{getSystem:a}=r;const c=t?e:["App","BaseLayout","VersionPragmaFilter","InfoContainer","ServersContainer","SchemesContainer","AuthorizeBtnContainer","FilterContainer","Operations","OperationContainer","parameters","responses","OperationServers","Models","ModelWrapper",...e],p=i()(c,o()(n=Array(c.length)).call(n,((e,t)=>{let{fn:r}=t;return r.withErrorBoundary(e)})));return{fn:{componentDidCatch:u.componentDidCatch,withErrorBoundary:(0,u.withErrorBoundary)(a)},components:{ErrorBoundary:s.default,Fallback:l.default},wrapComponents:p}}}},57050:(e,t,r)=>{"use strict";r.r(t),r.d(t,{sampleFromSchemaGeneric:()=>F,inferSchema:()=>z,createXMLExample:()=>U,sampleFromSchema:()=>q,memoizedCreateXMLExample:()=>$,memoizedSampleFromSchema:()=>W});var n=r(11882),o=r.n(n),a=r(86),i=r.n(a),s=r(58309),l=r.n(s),u=r(58118),c=r.n(u),p=r(92039),f=r.n(p),h=r(24278),d=r.n(h),m=r(51679),g=r.n(m),v=r(39022),y=r.n(v),b=r(97606),w=r.n(b),E=r(35627),x=r.n(E),_=r(53479),S=r.n(_),A=r(14419),k=r.n(A),C=r(41609),O=r.n(C),j=r(90242),I=r(60314);const N={string:e=>e.pattern?(e=>{try{return new(k())(e).gen()}catch(e){return"string"}})(e.pattern):"string",string_email:()=>"user@example.com","string_date-time":()=>(new Date).toISOString(),string_date:()=>(new Date).toISOString().substring(0,10),string_uuid:()=>"3fa85f64-5717-4562-b3fc-2c963f66afa6",string_hostname:()=>"example.com",string_ipv4:()=>"198.51.100.42",string_ipv6:()=>"2001:0db8:5b96:0000:0000:426f:8e17:642a",number:()=>0,number_float:()=>0,integer:()=>0,boolean:e=>"boolean"!=typeof e.default||e.default},T=e=>{e=(0,j.mz)(e);let{type:t,format:r}=e,n=N[`${t}_${r}`]||N[t];return(0,j.Wl)(n)?n(e):"Unknown Type: "+e.type},P=e=>(0,j.XV)(e,"$$ref",(e=>"string"==typeof e&&o()(e).call(e,"#")>-1)),R=["maxProperties","minProperties"],M=["minItems","maxItems"],D=["minimum","maximum","exclusiveMinimum","exclusiveMaximum"],L=["minLength","maxLength"],B=function(e,t){var r;let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const a=r=>{void 0===t[r]&&void 0!==e[r]&&(t[r]=e[r])};var s;(i()(r=["example","default","enum","xml","type",...R,...M,...D,...L]).call(r,(e=>a(e))),void 0!==e.required&&l()(e.required))&&(void 0!==t.required&&t.required.length||(t.required=[]),i()(s=e.required).call(s,(e=>{var r;c()(r=t.required).call(r,e)||t.required.push(e)})));if(e.properties){t.properties||(t.properties={});let r=(0,j.mz)(e.properties);for(let a in r){var u;if(Object.prototype.hasOwnProperty.call(r,a))if(!r[a]||!r[a].deprecated)if(!r[a]||!r[a].readOnly||n.includeReadOnly)if(!r[a]||!r[a].writeOnly||n.includeWriteOnly)if(!t.properties[a])t.properties[a]=r[a],!e.required&&l()(e.required)&&-1!==o()(u=e.required).call(u,a)&&(t.required?t.required.push(a):t.required=[a])}}return e.items&&(t.items||(t.items={}),t.items=B(e.items,t.items,n)),t},F=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0,n=arguments.length>3&&void 0!==arguments[3]&&arguments[3];e&&(0,j.Wl)(e.toJS)&&(e=e.toJS());let a=void 0!==r||e&&void 0!==e.example||e&&void 0!==e.default;const s=!a&&e&&e.oneOf&&e.oneOf.length>0,u=!a&&e&&e.anyOf&&e.anyOf.length>0;if(!a&&(s||u)){const r=(0,j.mz)(s?e.oneOf[0]:e.anyOf[0]);if(B(r,e,t),!e.xml&&r.xml&&(e.xml=r.xml),void 0!==e.example&&void 0!==r.example)a=!0;else if(r.properties){e.properties||(e.properties={});let n=(0,j.mz)(r.properties);for(let a in n){var p;if(Object.prototype.hasOwnProperty.call(n,a))if(!n[a]||!n[a].deprecated)if(!n[a]||!n[a].readOnly||t.includeReadOnly)if(!n[a]||!n[a].writeOnly||t.includeWriteOnly)if(!e.properties[a])e.properties[a]=n[a],!r.required&&l()(r.required)&&-1!==o()(p=r.required).call(p,a)&&(e.required?e.required.push(a):e.required=[a])}}}const h={};let{xml:m,type:v,example:b,properties:E,additionalProperties:x,items:_}=e||{},{includeReadOnly:S,includeWriteOnly:A}=t;m=m||{};let k,{name:C,prefix:I,namespace:N}=m,L={};if(n&&(C=C||"notagname",k=(I?I+":":"")+C,N)){h[I?"xmlns:"+I:"xmlns"]=N}n&&(L[k]=[]);const z=t=>f()(t).call(t,(t=>Object.prototype.hasOwnProperty.call(e,t)));e&&!v&&(E||x||z(R)?v="object":_||z(M)?v="array":z(D)?(v="number",e.type="number"):a||e.enum||(v="string",e.type="string"));const U=t=>{var r,n,o,a,i;null!==(null===(r=e)||void 0===r?void 0:r.maxItems)&&void 0!==(null===(n=e)||void 0===n?void 0:n.maxItems)&&(t=d()(t).call(t,0,null===(i=e)||void 0===i?void 0:i.maxItems));if(null!==(null===(o=e)||void 0===o?void 0:o.minItems)&&void 0!==(null===(a=e)||void 0===a?void 0:a.minItems)){let r=0;for(;t.length<(null===(s=e)||void 0===s?void 0:s.minItems);){var s;t.push(t[r++%t.length])}}return t},q=(0,j.mz)(E);let V,$=0;const W=()=>e&&null!==e.maxProperties&&void 0!==e.maxProperties&&$>=e.maxProperties,H=()=>{if(!e||!e.required)return 0;let t=0;var r,o;n?i()(r=e.required).call(r,(e=>t+=void 0===L[e]?0:1)):i()(o=e.required).call(o,(e=>{var r;return t+=void 0===(null===(r=L[k])||void 0===r?void 0:g()(r).call(r,(t=>void 0!==t[e])))?0:1}));return e.required.length-t},J=t=>{var r;return!(e&&e.required&&e.required.length)||!c()(r=e.required).call(r,t)},K=t=>!e||null===e.maxProperties||void 0===e.maxProperties||!W()&&(!J(t)||e.maxProperties-$-H()>0);if(V=n?function(r){let o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:void 0;if(e&&q[r]){if(q[r].xml=q[r].xml||{},q[r].xml.attribute){const e=l()(q[r].enum)?q[r].enum[0]:void 0,t=q[r].example,n=q[r].default;return void(h[q[r].xml.name||r]=void 0!==t?t:void 0!==n?n:void 0!==e?e:T(q[r]))}q[r].xml.name=q[r].xml.name||r}else q[r]||!1===x||(q[r]={xml:{name:r}});let a=F(e&&q[r]||void 0,t,o,n);var i;K(r)&&($++,l()(a)?L[k]=y()(i=L[k]).call(i,a):L[k].push(a))}:(e,r)=>{K(e)&&(L[e]=F(q[e],t,r,n),$++)},a){let o;if(o=P(void 0!==r?r:void 0!==b?b:e.default),!n){if("number"==typeof o&&"string"===v)return`${o}`;if("string"!=typeof o||"string"===v)return o;try{return JSON.parse(o)}catch(e){return o}}if(e||(v=l()(o)?"array":typeof o),"array"===v){if(!l()(o)){if("string"==typeof o)return o;o=[o]}const r=e?e.items:void 0;r&&(r.xml=r.xml||m||{},r.xml.name=r.xml.name||m.name);let a=w()(o).call(o,(e=>F(r,t,e,n)));return a=U(a),m.wrapped?(L[k]=a,O()(h)||L[k].push({_attr:h})):L=a,L}if("object"===v){if("string"==typeof o)return o;for(let t in o)Object.prototype.hasOwnProperty.call(o,t)&&(e&&q[t]&&q[t].readOnly&&!S||e&&q[t]&&q[t].writeOnly&&!A||(e&&q[t]&&q[t].xml&&q[t].xml.attribute?h[q[t].xml.name||t]=o[t]:V(t,o[t])));return O()(h)||L[k].push({_attr:h}),L}return L[k]=O()(h)?o:[{_attr:h},o],L}if("object"===v){for(let e in q)Object.prototype.hasOwnProperty.call(q,e)&&(q[e]&&q[e].deprecated||q[e]&&q[e].readOnly&&!S||q[e]&&q[e].writeOnly&&!A||V(e));if(n&&h&&L[k].push({_attr:h}),W())return L;if(!0===x)n?L[k].push({additionalProp:"Anything can be here"}):L.additionalProp1={},$++;else if(x){const r=(0,j.mz)(x),o=F(r,t,void 0,n);if(n&&r.xml&&r.xml.name&&"notagname"!==r.xml.name)L[k].push(o);else{const t=null!==e.minProperties&&void 0!==e.minProperties&&$F(B(_,e,t),t,void 0,n)));else if(l()(_.oneOf)){var Y;r=w()(Y=_.oneOf).call(Y,(e=>F(B(_,e,t),t,void 0,n)))}else{if(!(!n||n&&m.wrapped))return F(_,t,void 0,n);r=[F(_,t,void 0,n)]}return r=U(r),n&&m.wrapped?(L[k]=r,O()(h)||L[k].push({_attr:h}),L):r}let Q;if(e&&l()(e.enum))Q=(0,j.AF)(e.enum)[0];else{if(!e)return;if(Q=T(e),"number"==typeof Q){let t=e.minimum;null!=t&&(e.exclusiveMinimum&&t++,Q=t);let r=e.maximum;null!=r&&(e.exclusiveMaximum&&r--,Q=r)}if("string"==typeof Q&&(null!==e.maxLength&&void 0!==e.maxLength&&(Q=d()(Q).call(Q,0,e.maxLength)),null!==e.minLength&&void 0!==e.minLength)){let t=0;for(;Q.length(e.schema&&(e=e.schema),e.properties&&(e.type="object"),e),U=(e,t,r)=>{const n=F(e,t,r,!0);if(n)return"string"==typeof n?n:S()(n,{declaration:!0,indent:"\t"})},q=(e,t,r)=>F(e,t,r,!1),V=(e,t,r)=>[e,x()(t),x()(r)],$=(0,I.Z)(U,V),W=(0,I.Z)(q,V)},8883:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>o});var n=r(57050);function o(){return{fn:n}}},51228:(e,t,r)=>{"use strict";r.r(t),r.d(t,{UPDATE_SPEC:()=>U,UPDATE_URL:()=>q,UPDATE_JSON:()=>V,UPDATE_PARAM:()=>$,UPDATE_EMPTY_PARAM_INCLUSION:()=>W,VALIDATE_PARAMS:()=>H,SET_RESPONSE:()=>J,SET_REQUEST:()=>K,SET_MUTATED_REQUEST:()=>G,LOG_REQUEST:()=>Z,CLEAR_RESPONSE:()=>Y,CLEAR_REQUEST:()=>Q,CLEAR_VALIDATE_PARAMS:()=>X,UPDATE_OPERATION_META_VALUE:()=>ee,UPDATE_RESOLVED:()=>te,UPDATE_RESOLVED_SUBTREE:()=>re,SET_SCHEME:()=>ne,updateSpec:()=>oe,updateResolved:()=>ae,updateUrl:()=>ie,updateJsonSpec:()=>se,parseToJson:()=>le,resolveSpec:()=>ce,requestResolvedSubtree:()=>he,changeParam:()=>de,changeParamByIdentity:()=>me,updateResolvedSubtree:()=>ge,invalidateResolvedSubtreeCache:()=>ve,validateParams:()=>ye,updateEmptyParamInclusion:()=>be,clearValidateParams:()=>we,changeConsumesValue:()=>Ee,changeProducesValue:()=>xe,setResponse:()=>_e,setRequest:()=>Se,setMutatedRequest:()=>Ae,logRequest:()=>ke,executeRequest:()=>Ce,execute:()=>Oe,clearResponse:()=>je,clearRequest:()=>Ie,setScheme:()=>Ne});var n=r(58309),o=r.n(n),a=r(97606),i=r.n(a),s=r(96718),l=r.n(s),u=r(24282),c=r.n(u),p=r(2250),f=r.n(p),h=r(6226),d=r.n(h),m=r(14418),g=r.n(m),v=r(3665),y=r.n(v),b=r(11882),w=r.n(b),E=r(86),x=r.n(E),_=r(28222),S=r.n(_),A=r(76986),k=r.n(A),C=r(70586),O=r.n(C),j=r(1272),I=r(43393),N=r(84564),T=r.n(N),P=r(7710),R=r(47037),M=r.n(R),D=r(23279),L=r.n(D),B=r(36968),F=r.n(B),z=r(90242);const U="spec_update_spec",q="spec_update_url",V="spec_update_json",$="spec_update_param",W="spec_update_empty_param_inclusion",H="spec_validate_param",J="spec_set_response",K="spec_set_request",G="spec_set_mutated_request",Z="spec_log_request",Y="spec_clear_response",Q="spec_clear_request",X="spec_clear_validate_param",ee="spec_update_operation_meta_value",te="spec_update_resolved",re="spec_update_resolved_subtree",ne="set_scheme";function oe(e){const t=(r=e,M()(r)?r:"").replace(/\t/g," ");var r;if("string"==typeof e)return{type:U,payload:t}}function ae(e){return{type:te,payload:e}}function ie(e){return{type:q,payload:e}}function se(e){return{type:V,payload:e}}const le=e=>t=>{let{specActions:r,specSelectors:n,errActions:o}=t,{specStr:a}=n,i=null;try{e=e||a(),o.clear({source:"parser"}),i=j.ZP.load(e,{schema:j.A8})}catch(e){return console.error(e),o.newSpecErr({source:"parser",level:"error",message:e.reason,line:e.mark&&e.mark.line?e.mark.line+1:void 0})}return i&&"object"==typeof i?r.updateJsonSpec(i):{}};let ue=!1;const ce=(e,t)=>r=>{let{specActions:n,specSelectors:a,errActions:s,fn:{fetch:u,resolve:c,AST:p={}},getConfigs:f}=r;ue||(console.warn("specActions.resolveSpec is deprecated since v3.10.0 and will be removed in v4.0.0; use requestResolvedSubtree instead!"),ue=!0);const{modelPropertyMacro:h,parameterMacro:d,requestInterceptor:m,responseInterceptor:g}=f();void 0===e&&(e=a.specJson()),void 0===t&&(t=a.url());let v=p.getLineNumberForPath?p.getLineNumberForPath:()=>{},y=a.specStr();return c({fetch:u,spec:e,baseDoc:t,modelPropertyMacro:h,parameterMacro:d,requestInterceptor:m,responseInterceptor:g}).then((e=>{let{spec:t,errors:r}=e;if(s.clear({type:"thrown"}),o()(r)&&r.length>0){let e=i()(r).call(r,(e=>(console.error(e),e.line=e.fullPath?v(y,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",l()(e,"message",{enumerable:!0,value:e.message}),e)));s.newThrownErrBatch(e)}return n.updateResolved(t)}))};let pe=[];const fe=L()((async()=>{const e=pe.system;if(!e)return void console.error("debResolveSubtrees: don't have a system to operate on, aborting.");const{errActions:t,errSelectors:r,fn:{resolveSubtree:n,fetch:a,AST:s={}},specSelectors:u,specActions:p}=e;if(!n)return void console.error("Error: Swagger-Client did not provide a `resolveSubtree` method, doing nothing.");let h=s.getLineNumberForPath?s.getLineNumberForPath:()=>{};const m=u.specStr(),{modelPropertyMacro:v,parameterMacro:b,requestInterceptor:w,responseInterceptor:E}=e.getConfigs();try{var x=await c()(pe).call(pe,(async(e,s)=>{const{resultMap:c,specWithCurrentSubtrees:p}=await e,{errors:x,spec:_}=await n(p,s,{baseDoc:u.url(),modelPropertyMacro:v,parameterMacro:b,requestInterceptor:w,responseInterceptor:E});if(r.allErrors().size&&t.clearBy((e=>{var t;return"thrown"!==e.get("type")||"resolver"!==e.get("source")||!f()(t=e.get("fullPath")).call(t,((e,t)=>e===s[t]||void 0===s[t]))})),o()(x)&&x.length>0){let e=i()(x).call(x,(e=>(e.line=e.fullPath?h(m,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",l()(e,"message",{enumerable:!0,value:e.message}),e)));t.newThrownErrBatch(e)}var S,A;_&&u.isOAS3()&&"components"===s[0]&&"securitySchemes"===s[1]&&await d().all(i()(S=g()(A=y()(_)).call(A,(e=>"openIdConnect"===e.type))).call(S,(async e=>{const t={url:e.openIdConnectUrl,requestInterceptor:w,responseInterceptor:E};try{const r=await a(t);r instanceof Error||r.status>=400?console.error(r.statusText+" "+t.url):e.openIdConnectData=JSON.parse(r.text)}catch(e){console.error(e)}})));return F()(c,s,_),F()(p,s,_),{resultMap:c,specWithCurrentSubtrees:p}}),d().resolve({resultMap:(u.specResolvedSubtree([])||(0,I.Map)()).toJS(),specWithCurrentSubtrees:u.specJson().toJS()}));delete pe.system,pe=[]}catch(e){console.error(e)}p.updateResolvedSubtree([],x.resultMap)}),35),he=e=>t=>{var r;w()(r=i()(pe).call(pe,(e=>e.join("@@")))).call(r,e.join("@@"))>-1||(pe.push(e),pe.system=t,fe())};function de(e,t,r,n,o){return{type:$,payload:{path:e,value:n,paramName:t,paramIn:r,isXml:o}}}function me(e,t,r,n){return{type:$,payload:{path:e,param:t,value:r,isXml:n}}}const ge=(e,t)=>({type:re,payload:{path:e,value:t}}),ve=()=>({type:re,payload:{path:[],value:(0,I.Map)()}}),ye=(e,t)=>({type:H,payload:{pathMethod:e,isOAS3:t}}),be=(e,t,r,n)=>({type:W,payload:{pathMethod:e,paramName:t,paramIn:r,includeEmptyValue:n}});function we(e){return{type:X,payload:{pathMethod:e}}}function Ee(e,t){return{type:ee,payload:{path:e,value:t,key:"consumes_value"}}}function xe(e,t){return{type:ee,payload:{path:e,value:t,key:"produces_value"}}}const _e=(e,t,r)=>({payload:{path:e,method:t,res:r},type:J}),Se=(e,t,r)=>({payload:{path:e,method:t,req:r},type:K}),Ae=(e,t,r)=>({payload:{path:e,method:t,req:r},type:G}),ke=e=>({payload:e,type:Z}),Ce=e=>t=>{let{fn:r,specActions:n,specSelectors:a,getConfigs:s,oas3Selectors:l}=t,{pathName:u,method:c,operation:p}=e,{requestInterceptor:f,responseInterceptor:h}=s(),d=p.toJS();var m,v;p&&p.get("parameters")&&x()(m=g()(v=p.get("parameters")).call(v,(e=>e&&!0===e.get("allowEmptyValue")))).call(m,(t=>{if(a.parameterInclusionSettingFor([u,c],t.get("name"),t.get("in"))){e.parameters=e.parameters||{};const r=(0,z.cz)(t,e.parameters);(!r||r&&0===r.size)&&(e.parameters[t.get("name")]="")}}));if(e.contextUrl=T()(a.url()).toString(),d&&d.operationId?e.operationId=d.operationId:d&&u&&c&&(e.operationId=r.opId(d,u,c)),a.isOAS3()){const t=`${u}:${c}`;e.server=l.selectedServer(t)||l.selectedServer();const r=l.serverVariables({server:e.server,namespace:t}).toJS(),n=l.serverVariables({server:e.server}).toJS();e.serverVariables=S()(r).length?r:n,e.requestContentType=l.requestContentType(u,c),e.responseContentType=l.responseContentType(u,c)||"*/*";const a=l.requestBodyValue(u,c),s=l.requestBodyInclusionSetting(u,c);var y;if(a&&a.toJS)e.requestBody=g()(y=i()(a).call(a,(e=>I.Map.isMap(e)?e.get("value"):e))).call(y,((e,t)=>(o()(e)?0!==e.length:!(0,z.O2)(e))||s.get(t))).toJS();else e.requestBody=a}let b=k()({},e);b=r.buildRequest(b),n.setRequest(e.pathName,e.method,b);e.requestInterceptor=async t=>{let r=await f.apply(void 0,[t]),o=k()({},r);return n.setMutatedRequest(e.pathName,e.method,o),r},e.responseInterceptor=h;const w=O()();return r.execute(e).then((t=>{t.duration=O()()-w,n.setResponse(e.pathName,e.method,t)})).catch((t=>{"Failed to fetch"===t.message&&(t.name="",t.message='**Failed to fetch.** \n**Possible Reasons:** \n - CORS \n - Network Failure \n - URL scheme must be "http" or "https" for CORS request.'),n.setResponse(e.pathName,e.method,{error:!0,err:(0,P.serializeError)(t)})}))},Oe=function(){let{path:e,method:t,...r}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return n=>{let{fn:{fetch:o},specSelectors:a,specActions:i}=n,s=a.specJsonWithResolvedSubtrees().toJS(),l=a.operationScheme(e,t),{requestContentType:u,responseContentType:c}=a.contentTypeValues([e,t]).toJS(),p=/xml/i.test(u),f=a.parameterValues([e,t],p).toJS();return i.executeRequest({...r,fetch:o,spec:s,pathName:e,method:t,parameters:f,requestContentType:u,scheme:l,responseContentType:c})}};function je(e,t){return{type:Y,payload:{path:e,method:t}}}function Ie(e,t){return{type:Q,payload:{path:e,method:t}}}function Ne(e,t,r){return{type:ne,payload:{scheme:e,path:t,method:r}}}},37038:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>s});var n=r(20032),o=r(51228),a=r(33881),i=r(77508);function s(){return{statePlugins:{spec:{wrapActions:i,reducers:n.default,actions:o,selectors:a}}}}},20032:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>d});var n=r(24282),o=r.n(n),a=r(97606),i=r.n(a),s=r(76986),l=r.n(s),u=r(43393),c=r(90242),p=r(27504),f=r(33881),h=r(51228);const d={[h.UPDATE_SPEC]:(e,t)=>"string"==typeof t.payload?e.set("spec",t.payload):e,[h.UPDATE_URL]:(e,t)=>e.set("url",t.payload+""),[h.UPDATE_JSON]:(e,t)=>e.set("json",(0,c.oG)(t.payload)),[h.UPDATE_RESOLVED]:(e,t)=>e.setIn(["resolved"],(0,c.oG)(t.payload)),[h.UPDATE_RESOLVED_SUBTREE]:(e,t)=>{const{value:r,path:n}=t.payload;return e.setIn(["resolvedSubtrees",...n],(0,c.oG)(r))},[h.UPDATE_PARAM]:(e,t)=>{let{payload:r}=t,{path:n,paramName:o,paramIn:a,param:i,value:s,isXml:l}=r,u=i?(0,c.V9)(i):`${a}.${o}`;const p=l?"value_xml":"value";return e.setIn(["meta","paths",...n,"parameters",u,p],s)},[h.UPDATE_EMPTY_PARAM_INCLUSION]:(e,t)=>{let{payload:r}=t,{pathMethod:n,paramName:o,paramIn:a,includeEmptyValue:i}=r;if(!o||!a)return console.warn("Warning: UPDATE_EMPTY_PARAM_INCLUSION could not generate a paramKey."),e;const s=`${a}.${o}`;return e.setIn(["meta","paths",...n,"parameter_inclusions",s],i)},[h.VALIDATE_PARAMS]:(e,t)=>{let{payload:{pathMethod:r,isOAS3:n}}=t;const a=(0,f.specJsonWithResolvedSubtrees)(e).getIn(["paths",...r]),i=(0,f.parameterValues)(e,r).toJS();return e.updateIn(["meta","paths",...r,"parameters"],(0,u.fromJS)({}),(t=>{var s;return o()(s=a.get("parameters",(0,u.List)())).call(s,((t,o)=>{const a=(0,c.cz)(o,i),s=(0,f.parameterInclusionSettingFor)(e,r,o.get("name"),o.get("in")),l=(0,c.Ik)(o,a,{bypassRequiredCheck:s,isOAS3:n});return t.setIn([(0,c.V9)(o),"errors"],(0,u.fromJS)(l))}),t)}))},[h.CLEAR_VALIDATE_PARAMS]:(e,t)=>{let{payload:{pathMethod:r}}=t;return e.updateIn(["meta","paths",...r,"parameters"],(0,u.fromJS)([]),(e=>i()(e).call(e,(e=>e.set("errors",(0,u.fromJS)([]))))))},[h.SET_RESPONSE]:(e,t)=>{let r,{payload:{res:n,path:o,method:a}}=t;r=n.error?l()({error:!0,name:n.err.name,message:n.err.message,statusCode:n.err.statusCode},n.err.response):n,r.headers=r.headers||{};let i=e.setIn(["responses",o,a],(0,c.oG)(r));return p.Z.Blob&&n.data instanceof p.Z.Blob&&(i=i.setIn(["responses",o,a,"text"],n.data)),i},[h.SET_REQUEST]:(e,t)=>{let{payload:{req:r,path:n,method:o}}=t;return e.setIn(["requests",n,o],(0,c.oG)(r))},[h.SET_MUTATED_REQUEST]:(e,t)=>{let{payload:{req:r,path:n,method:o}}=t;return e.setIn(["mutatedRequests",n,o],(0,c.oG)(r))},[h.UPDATE_OPERATION_META_VALUE]:(e,t)=>{let{payload:{path:r,value:n,key:o}}=t,a=["paths",...r],i=["meta","paths",...r];return e.getIn(["json",...a])||e.getIn(["resolved",...a])||e.getIn(["resolvedSubtrees",...a])?e.setIn([...i,o],(0,u.fromJS)(n)):e},[h.CLEAR_RESPONSE]:(e,t)=>{let{payload:{path:r,method:n}}=t;return e.deleteIn(["responses",r,n])},[h.CLEAR_REQUEST]:(e,t)=>{let{payload:{path:r,method:n}}=t;return e.deleteIn(["requests",r,n])},[h.SET_SCHEME]:(e,t)=>{let{payload:{scheme:r,path:n,method:o}}=t;return n&&o?e.setIn(["scheme",n,o],r):n||o?void 0:e.setIn(["scheme","_defaultScheme"],r)}}},33881:(e,t,r)=>{"use strict";r.r(t),r.d(t,{lastError:()=>O,url:()=>j,specStr:()=>I,specSource:()=>N,specJson:()=>T,specResolved:()=>P,specResolvedSubtree:()=>R,specJsonWithResolvedSubtrees:()=>D,spec:()=>L,isOAS3:()=>B,info:()=>F,externalDocs:()=>z,version:()=>U,semver:()=>q,paths:()=>V,operations:()=>$,consumes:()=>W,produces:()=>H,security:()=>J,securityDefinitions:()=>K,findDefinition:()=>G,definitions:()=>Z,basePath:()=>Y,host:()=>Q,schemes:()=>X,operationsWithRootInherited:()=>ee,tags:()=>te,tagDetails:()=>re,operationsWithTags:()=>ne,taggedOperations:()=>oe,responses:()=>ae,requests:()=>ie,mutatedRequests:()=>se,responseFor:()=>le,requestFor:()=>ue,mutatedRequestFor:()=>ce,allowTryItOutFor:()=>pe,parameterWithMetaByIdentity:()=>fe,parameterInclusionSettingFor:()=>he,parameterWithMeta:()=>de,operationWithMeta:()=>me,getParameter:()=>ge,hasHost:()=>ve,parameterValues:()=>ye,parametersIncludeIn:()=>be,parametersIncludeType:()=>we,contentTypeValues:()=>Ee,currentProducesFor:()=>xe,producesOptionsFor:()=>_e,consumesOptionsFor:()=>Se,operationScheme:()=>Ae,canExecuteScheme:()=>ke,validateBeforeExecute:()=>Ce,getOAS3RequiredRequestBodyContentType:()=>Oe,isMediaTypeSchemaPropertiesEqual:()=>je});var n=r(24278),o=r.n(n),a=r(86),i=r.n(a),s=r(11882),l=r.n(s),u=r(97606),c=r.n(u),p=r(14418),f=r.n(p),h=r(51679),d=r.n(h),m=r(24282),g=r.n(m),v=r(2578),y=r.n(v),b=r(92039),w=r.n(b),E=r(58309),x=r.n(E),_=r(20573),S=r(90242),A=r(43393);const k=["get","put","post","delete","options","head","patch","trace"],C=e=>e||(0,A.Map)(),O=(0,_.P1)(C,(e=>e.get("lastError"))),j=(0,_.P1)(C,(e=>e.get("url"))),I=(0,_.P1)(C,(e=>e.get("spec")||"")),N=(0,_.P1)(C,(e=>e.get("specSource")||"not-editor")),T=(0,_.P1)(C,(e=>e.get("json",(0,A.Map)()))),P=(0,_.P1)(C,(e=>e.get("resolved",(0,A.Map)()))),R=(e,t)=>e.getIn(["resolvedSubtrees",...t],void 0),M=(e,t)=>A.Map.isMap(e)&&A.Map.isMap(t)?t.get("$$ref")?t:(0,A.OrderedMap)().mergeWith(M,e,t):t,D=(0,_.P1)(C,(e=>(0,A.OrderedMap)().mergeWith(M,e.get("json"),e.get("resolvedSubtrees")))),L=e=>T(e),B=(0,_.P1)(L,(()=>!1)),F=(0,_.P1)(L,(e=>Ie(e&&e.get("info")))),z=(0,_.P1)(L,(e=>Ie(e&&e.get("externalDocs")))),U=(0,_.P1)(F,(e=>e&&e.get("version"))),q=(0,_.P1)(U,(e=>{var t;return o()(t=/v?([0-9]*)\.([0-9]*)\.([0-9]*)/i.exec(e)).call(t,1)})),V=(0,_.P1)(D,(e=>e.get("paths"))),$=(0,_.P1)(V,(e=>{if(!e||e.size<1)return(0,A.List)();let t=(0,A.List)();return e&&i()(e)?(i()(e).call(e,((e,r)=>{if(!e||!i()(e))return{};i()(e).call(e,((e,n)=>{l()(k).call(k,n)<0||(t=t.push((0,A.fromJS)({path:r,method:n,operation:e,id:`${n}-${r}`})))}))})),t):(0,A.List)()})),W=(0,_.P1)(L,(e=>(0,A.Set)(e.get("consumes")))),H=(0,_.P1)(L,(e=>(0,A.Set)(e.get("produces")))),J=(0,_.P1)(L,(e=>e.get("security",(0,A.List)()))),K=(0,_.P1)(L,(e=>e.get("securityDefinitions"))),G=(e,t)=>{const r=e.getIn(["resolvedSubtrees","definitions",t],null),n=e.getIn(["json","definitions",t],null);return r||n||null},Z=(0,_.P1)(L,(e=>{const t=e.get("definitions");return A.Map.isMap(t)?t:(0,A.Map)()})),Y=(0,_.P1)(L,(e=>e.get("basePath"))),Q=(0,_.P1)(L,(e=>e.get("host"))),X=(0,_.P1)(L,(e=>e.get("schemes",(0,A.Map)()))),ee=(0,_.P1)($,W,H,((e,t,r)=>c()(e).call(e,(e=>e.update("operation",(e=>{if(e){if(!A.Map.isMap(e))return;return e.withMutations((e=>(e.get("consumes")||e.update("consumes",(e=>(0,A.Set)(e).merge(t))),e.get("produces")||e.update("produces",(e=>(0,A.Set)(e).merge(r))),e)))}return(0,A.Map)()})))))),te=(0,_.P1)(L,(e=>{const t=e.get("tags",(0,A.List)());return A.List.isList(t)?f()(t).call(t,(e=>A.Map.isMap(e))):(0,A.List)()})),re=(e,t)=>{var r;let n=te(e)||(0,A.List)();return d()(r=f()(n).call(n,A.Map.isMap)).call(r,(e=>e.get("name")===t),(0,A.Map)())},ne=(0,_.P1)(ee,te,((e,t)=>g()(e).call(e,((e,t)=>{let r=(0,A.Set)(t.getIn(["operation","tags"]));return r.count()<1?e.update("default",(0,A.List)(),(e=>e.push(t))):g()(r).call(r,((e,r)=>e.update(r,(0,A.List)(),(e=>e.push(t)))),e)}),g()(t).call(t,((e,t)=>e.set(t.get("name"),(0,A.List)())),(0,A.OrderedMap)())))),oe=e=>t=>{var r;let{getConfigs:n}=t,{tagsSorter:o,operationsSorter:a}=n();return c()(r=ne(e).sortBy(((e,t)=>t),((e,t)=>{let r="function"==typeof o?o:S.wh.tagsSorter[o];return r?r(e,t):null}))).call(r,((t,r)=>{let n="function"==typeof a?a:S.wh.operationsSorter[a],o=n?y()(t).call(t,n):t;return(0,A.Map)({tagDetails:re(e,r),operations:o})}))},ae=(0,_.P1)(C,(e=>e.get("responses",(0,A.Map)()))),ie=(0,_.P1)(C,(e=>e.get("requests",(0,A.Map)()))),se=(0,_.P1)(C,(e=>e.get("mutatedRequests",(0,A.Map)()))),le=(e,t,r)=>ae(e).getIn([t,r],null),ue=(e,t,r)=>ie(e).getIn([t,r],null),ce=(e,t,r)=>se(e).getIn([t,r],null),pe=()=>!0,fe=(e,t,r)=>{const n=D(e).getIn(["paths",...t,"parameters"],(0,A.OrderedMap)()),o=e.getIn(["meta","paths",...t,"parameters"],(0,A.OrderedMap)()),a=c()(n).call(n,(e=>{const t=o.get(`${r.get("in")}.${r.get("name")}`),n=o.get(`${r.get("in")}.${r.get("name")}.hash-${r.hashCode()}`);return(0,A.OrderedMap)().merge(e,t,n)}));return d()(a).call(a,(e=>e.get("in")===r.get("in")&&e.get("name")===r.get("name")),(0,A.OrderedMap)())},he=(e,t,r,n)=>{const o=`${n}.${r}`;return e.getIn(["meta","paths",...t,"parameter_inclusions",o],!1)},de=(e,t,r,n)=>{const o=D(e).getIn(["paths",...t,"parameters"],(0,A.OrderedMap)()),a=d()(o).call(o,(e=>e.get("in")===n&&e.get("name")===r),(0,A.OrderedMap)());return fe(e,t,a)},me=(e,t,r)=>{var n;const o=D(e).getIn(["paths",t,r],(0,A.OrderedMap)()),a=e.getIn(["meta","paths",t,r],(0,A.OrderedMap)()),i=c()(n=o.get("parameters",(0,A.List)())).call(n,(n=>fe(e,[t,r],n)));return(0,A.OrderedMap)().merge(o,a).set("parameters",i)};function ge(e,t,r,n){t=t||[];let o=e.getIn(["meta","paths",...t,"parameters"],(0,A.fromJS)([]));return d()(o).call(o,(e=>A.Map.isMap(e)&&e.get("name")===r&&e.get("in")===n))||(0,A.Map)()}const ve=(0,_.P1)(L,(e=>{const t=e.get("host");return"string"==typeof t&&t.length>0&&"/"!==t[0]}));function ye(e,t,r){t=t||[];let n=me(e,...t).get("parameters",(0,A.List)());return g()(n).call(n,((e,t)=>{let n=r&&"body"===t.get("in")?t.get("value_xml"):t.get("value");return e.set((0,S.V9)(t,{allowHashes:!1}),n)}),(0,A.fromJS)({}))}function be(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(A.List.isList(e))return w()(e).call(e,(e=>A.Map.isMap(e)&&e.get("in")===t))}function we(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(A.List.isList(e))return w()(e).call(e,(e=>A.Map.isMap(e)&&e.get("type")===t))}function Ee(e,t){t=t||[];let r=D(e).getIn(["paths",...t],(0,A.fromJS)({})),n=e.getIn(["meta","paths",...t],(0,A.fromJS)({})),o=xe(e,t);const a=r.get("parameters")||new A.List,i=n.get("consumes_value")?n.get("consumes_value"):we(a,"file")?"multipart/form-data":we(a,"formData")?"application/x-www-form-urlencoded":void 0;return(0,A.fromJS)({requestContentType:i,responseContentType:o})}function xe(e,t){t=t||[];const r=D(e).getIn(["paths",...t],null);if(null===r)return;const n=e.getIn(["meta","paths",...t,"produces_value"],null),o=r.getIn(["produces",0],null);return n||o||"application/json"}function _e(e,t){t=t||[];const r=D(e),n=r.getIn(["paths",...t],null);if(null===n)return;const[o]=t,a=n.get("produces",null),i=r.getIn(["paths",o,"produces"],null),s=r.getIn(["produces"],null);return a||i||s}function Se(e,t){t=t||[];const r=D(e),n=r.getIn(["paths",...t],null);if(null===n)return;const[o]=t,a=n.get("consumes",null),i=r.getIn(["paths",o,"consumes"],null),s=r.getIn(["consumes"],null);return a||i||s}const Ae=(e,t,r)=>{let n=e.get("url").match(/^([a-z][a-z0-9+\-.]*):/),o=x()(n)?n[1]:null;return e.getIn(["scheme",t,r])||e.getIn(["scheme","_defaultScheme"])||o||""},ke=(e,t,r)=>{var n;return l()(n=["http","https"]).call(n,Ae(e,t,r))>-1},Ce=(e,t)=>{t=t||[];let r=e.getIn(["meta","paths",...t,"parameters"],(0,A.fromJS)([])),n=!0;return i()(r).call(r,(e=>{let t=e.get("errors");t&&t.count()&&(n=!1)})),n},Oe=(e,t)=>{var r;let n={requestBody:!1,requestContentType:{}},o=e.getIn(["resolvedSubtrees","paths",...t,"requestBody"],(0,A.fromJS)([]));return o.size<1||(o.getIn(["required"])&&(n.requestBody=o.getIn(["required"])),i()(r=o.getIn(["content"]).entrySeq()).call(r,(e=>{const t=e[0];if(e[1].getIn(["schema","required"])){const r=e[1].getIn(["schema","required"]).toJS();n.requestContentType[t]=r}}))),n},je=(e,t,r,n)=>{if((r||n)&&r===n)return!0;let o=e.getIn(["resolvedSubtrees","paths",...t,"requestBody","content"],(0,A.fromJS)([]));if(o.size<2||!r||!n)return!1;let a=o.getIn([r,"schema","properties"],(0,A.fromJS)([])),i=o.getIn([n,"schema","properties"],(0,A.fromJS)([]));return!!a.equals(i)};function Ie(e){return A.Map.isMap(e)?e:new A.Map}},77508:(e,t,r)=>{"use strict";r.r(t),r.d(t,{updateSpec:()=>u,updateJsonSpec:()=>c,executeRequest:()=>p,validateParams:()=>f});var n=r(28222),o=r.n(n),a=r(86),i=r.n(a),s=r(27361),l=r.n(s);const u=(e,t)=>{let{specActions:r}=t;return function(){e(...arguments),r.parseToJson(...arguments)}},c=(e,t)=>{let{specActions:r}=t;return function(){for(var t=arguments.length,n=new Array(t),a=0;a{l()(u,[e]).$ref&&r.requestResolvedSubtree(["paths",e])})),r.requestResolvedSubtree(["components","securitySchemes"])}},p=(e,t)=>{let{specActions:r}=t;return t=>(r.logRequest(t),e(t))},f=(e,t)=>{let{specSelectors:r}=t;return t=>e(t,r.isOAS3())}},34852:(e,t,r)=>{"use strict";r.r(t),r.d(t,{loaded:()=>n});const n=(e,t)=>function(){e(...arguments);const r=t.getConfigs().withCredentials;void 0!==r&&(t.fn.fetch.withCredentials="string"==typeof r?"true"===r:!!r)}},48792:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>qr});var n={};r.r(n),r.d(n,{JsonPatchError:()=>Fe,_areEquals:()=>Ge,applyOperation:()=>$e,applyPatch:()=>We,applyReducer:()=>He,deepClone:()=>ze,getValueByPointer:()=>Ve,validate:()=>Ke,validator:()=>Je});var o={};r.r(o),r.d(o,{compare:()=>nt,generate:()=>tt,observe:()=>et,unobserve:()=>Xe});var a={};r.r(a),r.d(a,{cookie:()=>kr,header:()=>Ar,path:()=>xr,query:()=>_r});var i=r(80093),s=r.n(i),l=r(30222),u=r.n(l),c=r(36594),p=r.n(c),f=r(20474),h=r.n(f),d=r(67375),m=r.n(d),g=r(58118),v=r.n(g),y=r(74386),b=r.n(y),w=r(25110),E=r.n(w),x=r(35627),_=r.n(x),S=r(97606),A=r.n(S),k=r(28222),C=r.n(k),O=r(39022),j=r.n(O),I=r(2018),N=r.n(I),T=r(14418),P=r.n(T),R=(r(31905),r(92495)),M=r.n(R),D=r(1272);const L="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:window,{FormData:B,Blob:F,File:z}=L;var U=r(15687),q=r.n(U),V=r(24278),$=r.n(V),W=function(e){return":/?#[]@!$&'()*+,;=".indexOf(e)>-1},H=function(e){return/^[a-z0-9\-._~]+$/i.test(e)};function J(e){var t,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=r.escape,o=arguments.length>2?arguments[2]:void 0;return"number"==typeof e&&(e=e.toString()),"string"==typeof e&&e.length&&n?o?JSON.parse(e):A()(t=q()(e)).call(t,(function(e){var t,r;if(H(e))return e;if(W(e)&&"unsafe"===n)return e;var o=new TextEncoder;return A()(t=A()(r=E()(o.encode(e))).call(r,(function(e){var t;return $()(t="0".concat(e.toString(16).toUpperCase())).call(t,-2)}))).call(t,(function(e){return"%".concat(e)})).join("")})).join(""):e}function K(e){var t=e.value;return Array.isArray(t)?function(e){var t=e.key,r=e.value,n=e.style,o=e.explode,a=e.escape,i=function(e){return J(e,{escape:a})};if("simple"===n)return A()(r).call(r,(function(e){return i(e)})).join(",");if("label"===n)return".".concat(A()(r).call(r,(function(e){return i(e)})).join("."));if("matrix"===n)return A()(r).call(r,(function(e){return i(e)})).reduce((function(e,r){var n,a,i;return!e||o?j()(a=j()(i="".concat(e||"",";")).call(i,t,"=")).call(a,r):j()(n="".concat(e,",")).call(n,r)}),"");if("form"===n){var s=o?"&".concat(t,"="):",";return A()(r).call(r,(function(e){return i(e)})).join(s)}if("spaceDelimited"===n){var l=o?"".concat(t,"="):"";return A()(r).call(r,(function(e){return i(e)})).join(" ".concat(l))}if("pipeDelimited"===n){var u=o?"".concat(t,"="):"";return A()(r).call(r,(function(e){return i(e)})).join("|".concat(u))}return}(e):"object"===h()(t)?function(e){var t=e.key,r=e.value,n=e.style,o=e.explode,a=e.escape,i=function(e){return J(e,{escape:a})},s=C()(r);if("simple"===n)return s.reduce((function(e,t){var n,a,s,l=i(r[t]),u=o?"=":",",c=e?"".concat(e,","):"";return j()(n=j()(a=j()(s="".concat(c)).call(s,t)).call(a,u)).call(n,l)}),"");if("label"===n)return s.reduce((function(e,t){var n,a,s,l=i(r[t]),u=o?"=":".",c=e?"".concat(e,"."):".";return j()(n=j()(a=j()(s="".concat(c)).call(s,t)).call(a,u)).call(n,l)}),"");if("matrix"===n&&o)return s.reduce((function(e,t){var n,o,a=i(r[t]),s=e?"".concat(e,";"):";";return j()(n=j()(o="".concat(s)).call(o,t,"=")).call(n,a)}),"");if("matrix"===n)return s.reduce((function(e,n){var o,a,s=i(r[n]),l=e?"".concat(e,","):";".concat(t,"=");return j()(o=j()(a="".concat(l)).call(a,n,",")).call(o,s)}),"");if("form"===n)return s.reduce((function(e,t){var n,a,s,l,u=i(r[t]),c=e?j()(n="".concat(e)).call(n,o?"&":","):"",p=o?"=":",";return j()(a=j()(s=j()(l="".concat(c)).call(l,t)).call(s,p)).call(a,u)}),"");return}(e):function(e){var t,r=e.key,n=e.value,o=e.style,a=e.escape,i=function(e){return J(e,{escape:a})};if("simple"===o)return i(n);if("label"===o)return".".concat(i(n));if("matrix"===o)return j()(t=";".concat(r,"=")).call(t,i(n));if("form"===o)return i(n);if("deepObject"===o)return i(n,{},!0);return}(e)}const G=function(e,t){t.body=e};var Z={serializeRes:te,mergeInQueryOrForm:fe};function Y(e){return Q.apply(this,arguments)}function Q(){return Q=s()(u().mark((function e(t){var r,n,o,a,i,s=arguments;return u().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(r=s.length>1&&void 0!==s[1]?s[1]:{},"object"===h()(t)&&(t=(r=t).url),r.headers=r.headers||{},Z.mergeInQueryOrForm(r),r.headers&&C()(r.headers).forEach((function(e){var t=r.headers[e];"string"==typeof t&&(r.headers[e]=t.replace(/\n+/g," "))})),!r.requestInterceptor){e.next=12;break}return e.next=8,r.requestInterceptor(r);case 8:if(e.t0=e.sent,e.t0){e.next=11;break}e.t0=r;case 11:r=e.t0;case 12:return n=r.headers["content-type"]||r.headers["Content-Type"],/multipart\/form-data/i.test(n)&&r.body instanceof B&&(delete r.headers["content-type"],delete r.headers["Content-Type"]),e.prev=14,e.next=17,(r.userFetch||fetch)(r.url,r);case 17:return o=e.sent,e.next=20,Z.serializeRes(o,t,r);case 20:if(o=e.sent,!r.responseInterceptor){e.next=28;break}return e.next=24,r.responseInterceptor(o);case 24:if(e.t1=e.sent,e.t1){e.next=27;break}e.t1=o;case 27:o=e.t1;case 28:e.next=39;break;case 30:if(e.prev=30,e.t2=e.catch(14),o){e.next=34;break}throw e.t2;case 34:throw(a=new Error(o.statusText||"response status is ".concat(o.status))).status=o.status,a.statusCode=o.status,a.responseError=e.t2,a;case 39:if(o.ok){e.next=45;break}throw(i=new Error(o.statusText||"response status is ".concat(o.status))).status=o.status,i.statusCode=o.status,i.response=o,i;case 45:return e.abrupt("return",o);case 46:case"end":return e.stop()}}),e,null,[[14,30]])}))),Q.apply(this,arguments)}var X=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return/(json|xml|yaml|text)\b/.test(e)};function ee(e,t){return t&&(0===t.indexOf("application/json")||t.indexOf("+json")>0)?JSON.parse(e):D.ZP.load(e)}function te(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=r.loadSpec,o=void 0!==n&&n,a={ok:e.ok,url:e.url||t,status:e.status,statusText:e.statusText,headers:ne(e.headers)},i=a.headers["content-type"],s=o||X(i),l=s?e.text:e.blob||e.buffer;return l.call(e).then((function(e){if(a.text=e,a.data=e,s)try{var t=ee(e,i);a.body=t,a.obj=t}catch(e){a.parseError=e}return a}))}function re(e){return v()(e).call(e,", ")?e.split(", "):e}function ne(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return"function"!=typeof b()(e)?{}:E()(b()(e).call(e)).reduce((function(e,t){var r=m()(t,2),n=r[0],o=r[1];return e[n]=re(o),e}),{})}function oe(e,t){return t||"undefined"==typeof navigator||(t=navigator),t&&"ReactNative"===t.product?!(!e||"object"!==h()(e)||"string"!=typeof e.uri):void 0!==z&&e instanceof z||(void 0!==F&&e instanceof F||(!!ArrayBuffer.isView(e)||null!==e&&"object"===h()(e)&&"function"==typeof e.pipe))}function ae(e,t){return Array.isArray(e)&&e.some((function(e){return oe(e,t)}))}var ie={form:",",spaceDelimited:"%20",pipeDelimited:"|"},se={csv:",",ssv:"%20",tsv:"%09",pipes:"|"};function le(e,t){var r=arguments.length>2&&void 0!==arguments[2]&&arguments[2],n=t.collectionFormat,o=t.allowEmptyValue,a=t.serializationOption,i=t.encoding,s="object"!==h()(t)||Array.isArray(t)?t:t.value,l=r?function(e){return e.toString()}:function(e){return encodeURIComponent(e)},u=l(e);if(void 0===s&&o)return[[u,""]];if(oe(s)||ae(s))return[[u,s]];if(a)return ue(e,s,r,a);if(i){if([h()(i.style),h()(i.explode),h()(i.allowReserved)].some((function(e){return"undefined"!==e}))){var c=i.style,p=i.explode,f=i.allowReserved;return ue(e,s,r,{style:c,explode:p,allowReserved:f})}if(i.contentType){if("application/json"===i.contentType){var d="string"==typeof s?s:_()(s);return[[u,l(d)]]}return[[u,l(s.toString())]]}return"object"!==h()(s)?[[u,l(s)]]:Array.isArray(s)&&s.every((function(e){return"object"!==h()(e)}))?[[u,A()(s).call(s,l).join(",")]]:[[u,l(_()(s))]]}return"object"!==h()(s)?[[u,l(s)]]:Array.isArray(s)?"multi"===n?[[u,A()(s).call(s,l)]]:[[u,A()(s).call(s,l).join(se[n||"csv"])]]:[[u,""]]}function ue(e,t,r,n){var o,a,i,s=n.style||"form",l=void 0===n.explode?"form"===s:n.explode,u=!r&&(n&&n.allowReserved?"unsafe":"reserved"),c=function(e){return J(e,{escape:u})},p=r?function(e){return e}:function(e){return J(e,{escape:u})};return"object"!==h()(t)?[[p(e),c(t)]]:Array.isArray(t)?l?[[p(e),A()(t).call(t,c)]]:[[p(e),A()(t).call(t,c).join(ie[s])]]:"deepObject"===s?A()(a=C()(t)).call(a,(function(r){var n;return[p(j()(n="".concat(e,"[")).call(n,r,"]")),c(t[r])]})):l?A()(i=C()(t)).call(i,(function(e){return[p(e),c(t[e])]})):[[p(e),A()(o=C()(t)).call(o,(function(e){var r;return[j()(r="".concat(p(e),",")).call(r,c(t[e]))]})).join(",")]]}function ce(e){return N()(e).reduce((function(e,t){var r,n=m()(t,2),o=n[0],a=n[1],i=p()(le(o,a,!0));try{for(i.s();!(r=i.n()).done;){var s=m()(r.value,2),l=s[0],u=s[1];if(Array.isArray(u)){var c,f=p()(u);try{for(f.s();!(c=f.n()).done;){var h=c.value;if(ArrayBuffer.isView(h)){var d=new F([h]);e.append(l,d)}else e.append(l,h)}}catch(e){f.e(e)}finally{f.f()}}else if(ArrayBuffer.isView(u)){var g=new F([u]);e.append(l,g)}else e.append(l,u)}}catch(e){i.e(e)}finally{i.f()}return e}),new B)}function pe(e){var t=C()(e).reduce((function(t,r){var n,o=p()(le(r,e[r]));try{for(o.s();!(n=o.n()).done;){var a=m()(n.value,2),i=a[0],s=a[1];t[i]=s}}catch(e){o.e(e)}finally{o.f()}return t}),{});return M().stringify(t,{encode:!1,indices:!1})||""}function fe(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.url,r=void 0===t?"":t,n=e.query,o=e.form,a=function(){for(var e=arguments.length,t=new Array(e),r=0;r=48&&t<=57))return!1;r++}return!0}function Re(e){return-1===e.indexOf("/")&&-1===e.indexOf("~")?e:e.replace(/~/g,"~0").replace(/\//g,"~1")}function Me(e){return e.replace(/~1/g,"/").replace(/~0/g,"~")}function De(e){if(void 0===e)return!0;if(e)if(Array.isArray(e)){for(var t=0,r=e.length;t0&&"constructor"==s[u-1]))throw new TypeError("JSON-Patch: modifying `__proto__` or `constructor/prototype` prop is banned for security reasons, if this was on purpose, please set `banPrototypeModifications` flag false and pass it to this function. More info in fast-json-patch README");if(r&&void 0===p&&(void 0===l[f]?p=s.slice(0,u).join("/"):u==c-1&&(p=t.path),void 0!==p&&h(t,0,e,p)),u++,Array.isArray(l)){if("-"===f)f=l.length;else{if(r&&!Pe(f))throw new Fe("Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index","OPERATION_PATH_ILLEGAL_ARRAY_INDEX",a,t,e);Pe(f)&&(f=~~f)}if(u>=c){if(r&&"add"===t.op&&f>l.length)throw new Fe("The specified index MUST NOT be greater than the number of elements in the array","OPERATION_VALUE_OUT_OF_BOUNDS",a,t,e);if(!1===(i=qe[t.op].call(t,l,f,e)).test)throw new Fe("Test operation failed","TEST_OPERATION_FAILED",a,t,e);return i}}else if(u>=c){if(!1===(i=Ue[t.op].call(t,l,f,e)).test)throw new Fe("Test operation failed","TEST_OPERATION_FAILED",a,t,e);return i}if(l=l[f],r&&u0)throw new Fe('Operation `path` property must start with "/"',"OPERATION_PATH_INVALID",t,e,r);if(("move"===e.op||"copy"===e.op)&&"string"!=typeof e.from)throw new Fe("Operation `from` property is not present (applicable in `move` and `copy` operations)","OPERATION_FROM_REQUIRED",t,e,r);if(("add"===e.op||"replace"===e.op||"test"===e.op)&&void 0===e.value)throw new Fe("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_REQUIRED",t,e,r);if(("add"===e.op||"replace"===e.op||"test"===e.op)&&De(e.value))throw new Fe("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED",t,e,r);if(r)if("add"==e.op){var o=e.path.split("/").length,a=n.split("/").length;if(o!==a+1&&o!==a)throw new Fe("Cannot perform an `add` operation at the desired path","OPERATION_PATH_CANNOT_ADD",t,e,r)}else if("replace"===e.op||"remove"===e.op||"_get"===e.op){if(e.path!==n)throw new Fe("Cannot perform the operation at a path that does not exist","OPERATION_PATH_UNRESOLVABLE",t,e,r)}else if("move"===e.op||"copy"===e.op){var i=Ke([{op:"_get",path:e.from,value:void 0}],r);if(i&&"OPERATION_PATH_UNRESOLVABLE"===i.name)throw new Fe("Cannot perform the operation from a path that does not exist","OPERATION_FROM_UNRESOLVABLE",t,e,r)}}function Ke(e,t,r){try{if(!Array.isArray(e))throw new Fe("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");if(t)We(Te(t),Te(e),r||!0);else{r=r||Je;for(var n=0;n0&&(e.patches=[],e.callback&&e.callback(n)),n}function rt(e,t,r,n,o){if(t!==e){"function"==typeof t.toJSON&&(t=t.toJSON());for(var a=Ne(t),i=Ne(e),s=!1,l=i.length-1;l>=0;l--){var u=e[p=i[l]];if(!Ie(t,p)||void 0===t[p]&&void 0!==u&&!1===Array.isArray(t))Array.isArray(e)===Array.isArray(t)?(o&&r.push({op:"test",path:n+"/"+Re(p),value:Te(u)}),r.push({op:"remove",path:n+"/"+Re(p)}),s=!0):(o&&r.push({op:"test",path:n,value:e}),r.push({op:"replace",path:n,value:t}),!0);else{var c=t[p];"object"==typeof u&&null!=u&&"object"==typeof c&&null!=c&&Array.isArray(u)===Array.isArray(c)?rt(u,c,r,n+"/"+Re(p),o):u!==c&&(!0,o&&r.push({op:"test",path:n+"/"+Re(p),value:Te(u)}),r.push({op:"replace",path:n+"/"+Re(p),value:Te(c)}))}}if(s||a.length!=i.length)for(l=0;l0){var o=t(e,r[r.length-1],r);o&&(n=j()(n).call(n,o))}if(Array.isArray(e)){var a=A()(e).call(e,(function(e,n){return pt(e,t,j()(r).call(r,n))}));a&&(n=j()(n).call(n,a))}else if(mt(e)){var i,s=A()(i=C()(e)).call(i,(function(n){return pt(e[n],t,j()(r).call(r,n))}));s&&(n=j()(n).call(n,s))}return n=ht(n)}function ft(e){return Array.isArray(e)?e:[e]}function ht(e){var t;return j()(t=[]).apply(t,q()(A()(e).call(e,(function(e){return Array.isArray(e)?ht(e):e}))))}function dt(e){return P()(e).call(e,(function(e){return void 0!==e}))}function mt(e){return e&&"object"===h()(e)}function gt(e){return e&&"function"==typeof e}function vt(e){if(wt(e)){var t=e.op;return"add"===t||"remove"===t||"replace"===t}return!1}function yt(e){return vt(e)||wt(e)&&"mutation"===e.type}function bt(e){return yt(e)&&("add"===e.op||"replace"===e.op||"merge"===e.op||"mergeDeep"===e.op)}function wt(e){return e&&"object"===h()(e)}function Et(e,t){try{return Ve(e,t)}catch(e){return console.error(e),{}}}var xt=r(28886),_t=r.n(xt),St=r(37659),At=r.n(St),kt=r(8575);function Ct(e,t){function r(){Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack;for(var e=arguments.length,r=new Array(e),n=0;n-1&&-1===Nt.indexOf(r)||Tt.indexOf(n)>-1||Pt.some((function(e){return n.indexOf(e)>-1}))}function Mt(e,t){var r,n=e.split("#"),o=m()(n,2),a=o[0],i=o[1],s=kt.resolve(a||"",t||"");return i?j()(r="".concat(s,"#")).call(r,i):s}var Dt="application/json, application/yaml",Lt=/^([a-z]+:\/\/|\/\/)/i,Bt=Ct("JSONRefError",(function(e,t,r){this.originalError=r,Ee()(this,t||{})})),Ft={},zt=new(_t()),Ut=[function(e){return"paths"===e[0]&&"responses"===e[3]&&"examples"===e[5]},function(e){return"paths"===e[0]&&"responses"===e[3]&&"content"===e[5]&&"example"===e[7]},function(e){return"paths"===e[0]&&"responses"===e[3]&&"content"===e[5]&&"examples"===e[7]&&"value"===e[9]},function(e){return"paths"===e[0]&&"requestBody"===e[3]&&"content"===e[4]&&"example"===e[6]},function(e){return"paths"===e[0]&&"requestBody"===e[3]&&"content"===e[4]&&"examples"===e[6]&&"value"===e[8]},function(e){return"paths"===e[0]&&"parameters"===e[2]&&"example"===e[4]},function(e){return"paths"===e[0]&&"parameters"===e[3]&&"example"===e[5]},function(e){return"paths"===e[0]&&"parameters"===e[2]&&"examples"===e[4]&&"value"===e[6]},function(e){return"paths"===e[0]&&"parameters"===e[3]&&"examples"===e[5]&&"value"===e[7]},function(e){return"paths"===e[0]&&"parameters"===e[2]&&"content"===e[4]&&"example"===e[6]},function(e){return"paths"===e[0]&&"parameters"===e[2]&&"content"===e[4]&&"examples"===e[6]&&"value"===e[8]},function(e){return"paths"===e[0]&&"parameters"===e[3]&&"content"===e[4]&&"example"===e[7]},function(e){return"paths"===e[0]&&"parameters"===e[3]&&"content"===e[5]&&"examples"===e[7]&&"value"===e[9]}],qt={key:"$ref",plugin:function(e,t,r,n){var o=n.getInstance(),a=$()(r).call(r,0,-1);if(!Rt(a)&&!function(e){return Ut.some((function(t){return t(e)}))}(a)){var i=n.getContext(r).baseDoc;if("string"!=typeof e)return new Bt("$ref: must be a string (JSON-Ref)",{$ref:e,baseDoc:i,fullPath:r});var s,l,u,c=Jt(e),p=c[0],f=c[1]||"";try{s=i||p?Wt(p,i):null}catch(t){return Ht(t,{pointer:f,$ref:e,basePath:s,fullPath:r})}if(function(e,t,r,n){var o,a,i=zt.get(n);i||(i={},zt.set(n,i));var s=function(e){if(0===e.length)return"";return"/".concat(A()(e).call(e,Xt).join("/"))}(r),l=j()(o="".concat(t||"","#")).call(o,e),u=s.replace(/allOf\/\d+\/?/g,""),c=n.contextTree.get([]).baseDoc;if(t===c&&er(u,e))return!0;var p="",f=r.some((function(e){var t;return p=j()(t="".concat(p,"/")).call(t,Xt(e)),i[p]&&i[p].some((function(e){return er(e,l)||er(l,e)}))}));if(f)return!0;return void(i[u]=j()(a=i[u]||[]).call(a,l))}(f,s,a,n)&&!o.useCircularStructures){var h=Mt(e,s);return e===h?null:it.replace(r,h)}if(null==s?(u=Yt(f),void 0===(l=n.get(u))&&(l=new Bt("Could not resolve reference: ".concat(e),{pointer:f,$ref:e,baseDoc:i,fullPath:r}))):l=null!=(l=Kt(s,f)).__value?l.__value:l.catch((function(t){throw Ht(t,{pointer:f,$ref:e,baseDoc:i,fullPath:r})})),l instanceof Error)return[it.remove(r),l];var d=Mt(e,s),m=it.replace(a,l,{$$ref:d});if(s&&s!==i)return[m,it.context(a,{baseDoc:s})];try{if(!function(e,t){var r=[e];return t.path.reduce((function(e,t){return r.push(e[t]),e[t]}),e),n(t.value);function n(e){return it.isObject(e)&&(r.indexOf(e)>=0||C()(e).some((function(t){return n(e[t])})))}}(n.state,m)||o.useCircularStructures)return m}catch(e){return null}}}},Vt=Ee()(qt,{docCache:Ft,absoluteify:Wt,clearCache:function(e){void 0!==e?delete Ft[e]:C()(Ft).forEach((function(e){delete Ft[e]}))},JSONRefError:Bt,wrapError:Ht,getDoc:Gt,split:Jt,extractFromDoc:Kt,fetchJSON:function(e){return fetch(e,{headers:{Accept:Dt},loadSpec:!0}).then((function(e){return e.text()})).then((function(e){return D.ZP.load(e)}))},extract:Zt,jsonPointerToArray:Yt,unescapeJsonPointerToken:Qt});const $t=Vt;function Wt(e,t){if(!Lt.test(e)){var r;if(!t)throw new Bt(j()(r="Tried to resolve a relative URL, without having a basePath. path: '".concat(e,"' basePath: '")).call(r,t,"'"));return kt.resolve(t,e)}return e}function Ht(e,t){var r,n;e&&e.response&&e.response.body?r=j()(n="".concat(e.response.body.code," ")).call(n,e.response.body.message):r=e.message;return new Bt("Could not resolve reference: ".concat(r),t,e)}function Jt(e){return(e+"").split("#")}function Kt(e,t){var r=Ft[e];if(r&&!it.isPromise(r))try{var n=Zt(t,r);return Ee()(Ae().resolve(n),{__value:n})}catch(e){return Ae().reject(e)}return Gt(e).then((function(e){return Zt(t,e)}))}function Gt(e){var t=Ft[e];return t?it.isPromise(t)?t:Ae().resolve(t):(Ft[e]=Vt.fetchJSON(e).then((function(t){return Ft[e]=t,t})),Ft[e])}function Zt(e,t){var r=Yt(e);if(r.length<1)return t;var n=it.getIn(t,r);if(void 0===n)throw new Bt("Could not resolve pointer: ".concat(e," does not exist in document"),{pointer:e});return n}function Yt(e){var t;if("string"!=typeof e)throw new TypeError("Expected a string, got a ".concat(h()(e)));return"/"===e[0]&&(e=e.substr(1)),""===e?[]:A()(t=e.split("/")).call(t,Qt)}function Qt(e){return"string"!=typeof e?e:new(At())("=".concat(e.replace(/~1/g,"/").replace(/~0/g,"~"))).get("")}function Xt(e){var t,r=new(At())([["",e.replace(/~/g,"~0").replace(/\//g,"~1")]]);return $()(t=r.toString()).call(t,1)}function er(e,t){if(!(r=t)||"/"===r||"#"===r)return!0;var r,n=e.charAt(t.length),o=$()(t).call(t,-1);return 0===e.indexOf(t)&&(!n||"/"===n||"#"===n)&&"#"!==o}const tr={key:"allOf",plugin:function(e,t,r,n,o){if(!o.meta||!o.meta.$$ref){var a=$()(r).call(r,0,-1);if(!Rt(a)){if(!Array.isArray(e)){var i=new TypeError("allOf must be an array");return i.fullPath=r,i}var s=!1,l=o.value;if(a.forEach((function(e){l&&(l=l[e])})),l=me()({},l),0!==C()(l).length){delete l.allOf;var u,c,p=[];if(p.push(n.replace(a,{})),e.forEach((function(e,t){if(!n.isObject(e)){if(s)return null;s=!0;var o=new TypeError("Elements in allOf must be objects");return o.fullPath=r,p.push(o)}p.push(n.mergeDeep(a,e));var i=function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=r.specmap,o=r.getBaseUrlForNodePath,a=void 0===o?function(e){var r;return n.getContext(j()(r=[]).call(r,q()(t),q()(e))).baseDoc}:o,i=r.targetKeys,s=void 0===i?["$ref","$$ref"]:i,l=[];return jt()(e).forEach((function(){if(v()(s).call(s,this.key)&&"string"==typeof this.node){var e=this.path,r=j()(t).call(t,this.path),o=Mt(this.node,a(e));l.push(n.replace(r,o))}})),l}(e,$()(r).call(r,0,-1),{getBaseUrlForNodePath:function(e){var o;return n.getContext(j()(o=[]).call(o,q()(r),[t],q()(e))).baseDoc},specmap:n});p.push.apply(p,q()(i))})),l.example)p.push(n.remove(j()(u=[]).call(u,a,"example")));if(p.push(n.mergeDeep(a,l)),!l.$$ref)p.push(n.remove(j()(c=[]).call(c,a,"$$ref")));return p}}}}},rr={key:"parameters",plugin:function(e,t,r,n){if(Array.isArray(e)&&e.length){var o=Ee()([],e),a=$()(r).call(r,0,-1),i=me()({},it.getIn(n.spec,a));return e.forEach((function(e,t){try{o[t].default=n.parameterMacro(i,e)}catch(e){var a=new Error(e);return a.fullPath=r,a}})),it.replace(r,o)}return it.replace(r,e)}},nr={key:"properties",plugin:function(e,t,r,n){var o=me()({},e);for(var a in e)try{o[a].default=n.modelPropertyMacro(o[a])}catch(e){var i=new Error(e);return i.fullPath=r,i}return it.replace(r,o)}};var or=function(){function e(t){ve()(this,e),this.root=ar(t||{})}return be()(e,[{key:"set",value:function(e,t){var r=this.getParent(e,!0);if(r){var n=e[e.length-1],o=r.children;o[n]?ir(o[n],t,r):o[n]=ar(t,r)}else ir(this.root,t,null)}},{key:"get",value:function(e){if((e=e||[]).length<1)return this.root.value;for(var t,r,n=this.root,o=0;o1?r-1:0),o=1;o1?n-1:0),a=1;a0}))}},{key:"nextPromisedPatch",value:function(){var e;if(this.promisedPatches.length>0)return Ae().race(A()(e=this.promisedPatches).call(e,(function(e){return e.value})))}},{key:"getPluginHistory",value:function(e){var t=this.constructor.getPluginName(e);return this.pluginHistory[t]||[]}},{key:"getPluginRunCount",value:function(e){return this.getPluginHistory(e).length}},{key:"getPluginHistoryTip",value:function(e){var t=this.getPluginHistory(e);return t&&t[t.length-1]||{}}},{key:"getPluginMutationIndex",value:function(e){var t=this.getPluginHistoryTip(e).mutationIndex;return"number"!=typeof t?-1:t}},{key:"updatePluginHistory",value:function(e,t){var r=this.constructor.getPluginName(e);this.pluginHistory[r]=this.pluginHistory[r]||[],this.pluginHistory[r].push(t)}},{key:"updatePatches",value:function(e){var t=this;it.normalizeArray(e).forEach((function(e){if(e instanceof Error)t.errors.push(e);else try{if(!it.isObject(e))return void t.debug("updatePatches","Got a non-object patch",e);if(t.showDebug&&t.allPatches.push(e),it.isPromise(e.value))return t.promisedPatches.push(e),void t.promisedPatchThen(e);if(it.isContextPatch(e))return void t.setContext(e.path,e.value);if(it.isMutation(e))return void t.updateMutations(e)}catch(e){console.error(e),t.errors.push(e)}}))}},{key:"updateMutations",value:function(e){"object"===h()(e.value)&&!Array.isArray(e.value)&&this.allowMetaPatches&&(e.value=me()({},e.value));var t=it.applyPatch(this.state,e,{allowMetaPatches:this.allowMetaPatches});t&&(this.mutations.push(e),this.state=t)}},{key:"removePromisedPatch",value:function(e){var t,r=this.promisedPatches.indexOf(e);r<0?this.debug("Tried to remove a promisedPatch that isn't there!"):Ce()(t=this.promisedPatches).call(t,r,1)}},{key:"promisedPatchThen",value:function(e){var t=this;return e.value=e.value.then((function(r){var n=me()(me()({},e),{},{value:r});t.removePromisedPatch(e),t.updatePatches(n)})).catch((function(r){t.removePromisedPatch(e),t.updatePatches(r)})),e.value}},{key:"getMutations",value:function(e,t){var r;return e=e||0,"number"!=typeof t&&(t=this.mutations.length),$()(r=this.mutations).call(r,e,t)}},{key:"getCurrentMutations",value:function(){return this.getMutationsForPlugin(this.getCurrentPlugin())}},{key:"getMutationsForPlugin",value:function(e){var t=this.getPluginMutationIndex(e);return this.getMutations(t+1)}},{key:"getCurrentPlugin",value:function(){return this.currentPlugin}},{key:"getLib",value:function(){return this.libMethods}},{key:"_get",value:function(e){return it.getIn(this.state,e)}},{key:"_getContext",value:function(e){return this.contextTree.get(e)}},{key:"setContext",value:function(e,t){return this.contextTree.set(e,t)}},{key:"_hasRun",value:function(e){return this.getPluginRunCount(this.getCurrentPlugin())>(e||0)}},{key:"dispatch",value:function(){var e,t=this,r=this,n=this.nextPlugin();if(!n){var o=this.nextPromisedPatch();if(o)return o.then((function(){return t.dispatch()})).catch((function(){return t.dispatch()}));var a={spec:this.state,errors:this.errors};return this.showDebug&&(a.patches=this.allPatches),Ae().resolve(a)}if(r.pluginCount=r.pluginCount||{},r.pluginCount[n]=(r.pluginCount[n]||0)+1,r.pluginCount[n]>100)return Ae().resolve({spec:r.state,errors:j()(e=r.errors).call(e,new Error("We've reached a hard limit of ".concat(100," plugin runs")))});if(n!==this.currentPlugin&&this.promisedPatches.length){var i,s=A()(i=this.promisedPatches).call(i,(function(e){return e.value}));return Ae().all(A()(s).call(s,(function(e){return e.then(sr,sr)}))).then((function(){return t.dispatch()}))}return function(){r.currentPlugin=n;var e=r.getCurrentMutations(),t=r.mutations.length-1;try{if(n.isGenerator){var o,a=p()(n(e,r.getLib()));try{for(a.s();!(o=a.n()).done;){l(o.value)}}catch(e){a.e(e)}finally{a.f()}}else{l(n(e,r.getLib()))}}catch(e){console.error(e),l([Ee()(Object.create(e),{plugin:n})])}finally{r.updatePluginHistory(n,{mutationIndex:t})}return r.dispatch()}();function l(e){e&&(e=it.fullyNormalizeArray(e),r.updatePatches(e,n))}}}],[{key:"getPluginName",value:function(e){return e.pluginName}},{key:"getPatchesOfType",value:function(e,t){return P()(e).call(e,t)}}]),e}();var ur={refs:$t,allOf:tr,parameters:rr,properties:nr},cr=r(23159);function pr(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=t.requestInterceptor,n=t.responseInterceptor,o=e.withCredentials?"include":"same-origin";return function(t){return e({url:t,loadSpec:!0,requestInterceptor:r,responseInterceptor:n,headers:{Accept:Dt},credentials:o}).then((function(e){return e.body}))}}function fr(e){var t=e.fetch,r=e.spec,n=e.url,o=e.mode,a=e.allowMetaPatches,i=void 0===a||a,l=e.pathDiscriminator,c=e.modelPropertyMacro,p=e.parameterMacro,f=e.requestInterceptor,h=e.responseInterceptor,d=e.skipNormalization,m=e.useCircularStructures,g=e.http,v=e.baseDoc;return v=v||n,g=t||g||Y,r?y(r):pr(g,{requestInterceptor:f,responseInterceptor:h})(v).then(y);function y(e){v&&(ur.refs.docCache[v]=e),ur.refs.fetchJSON=pr(g,{requestInterceptor:f,responseInterceptor:h});var t,r=[ur.refs];return"function"==typeof p&&r.push(ur.parameters),"function"==typeof c&&r.push(ur.properties),"strict"!==o&&r.push(ur.allOf),(t={spec:e,context:{baseDoc:v},plugins:r,allowMetaPatches:i,pathDiscriminator:l,parameterMacro:p,modelPropertyMacro:c,useCircularStructures:m},new lr(t).dispatch()).then(d?function(){var e=s()(u().mark((function e(t){return u().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.abrupt("return",t);case 1:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}():cr.K1)}}var hr=r(88436),dr=r.n(hr),mr=r(27361),gr=r.n(mr),vr=r(30006);function yr(e){return"[object Object]"===Object.prototype.toString.call(e)}function br(e){var t,r;return!1!==yr(e)&&(void 0===(t=e.constructor)||!1!==yr(r=t.prototype)&&!1!==r.hasOwnProperty("isPrototypeOf"))}const wr={body:function(e){var t=e.req,r=e.value;t.body=r},header:function(e){var t=e.req,r=e.parameter,n=e.value;t.headers=t.headers||{},void 0!==n&&(t.headers[r.name]=n)},query:function(e){var t=e.req,r=e.value,n=e.parameter;t.query=t.query||{},!1===r&&"boolean"===n.type&&(r="false");0===r&&["number","integer"].indexOf(n.type)>-1&&(r="0");if(r)t.query[n.name]={collectionFormat:n.collectionFormat,value:r};else if(n.allowEmptyValue&&void 0!==r){var o=n.name;t.query[o]=t.query[o]||{},t.query[o].allowEmptyValue=!0}},path:function(e){var t=e.req,r=e.value,n=e.parameter;t.url=t.url.split("{".concat(n.name,"}")).join(encodeURIComponent(r))},formData:function(e){var t=e.req,r=e.value,n=e.parameter;(r||n.allowEmptyValue)&&(t.form=t.form||{},t.form[n.name]={value:r,allowEmptyValue:n.allowEmptyValue,collectionFormat:n.collectionFormat})}};function Er(e,t){return v()(t).call(t,"application/json")?"string"==typeof e?e:_()(e):e.toString()}function xr(e){var t=e.req,r=e.value,n=e.parameter,o=n.name,a=n.style,i=n.explode,s=n.content;if(s){var l=C()(s)[0];t.url=t.url.split("{".concat(o,"}")).join(J(Er(r,l),{escape:!0}))}else{var u=K({key:n.name,value:r,style:a||"simple",explode:i||!1,escape:!0});t.url=t.url.split("{".concat(o,"}")).join(u)}}function _r(e){var t=e.req,r=e.value,n=e.parameter;if(t.query=t.query||{},n.content){var o=C()(n.content)[0];t.query[n.name]=Er(r,o)}else if(!1===r&&(r="false"),0===r&&(r="0"),r){var a=n.style,i=n.explode,s=n.allowReserved;t.query[n.name]={value:r,serializationOption:{style:a,explode:i,allowReserved:s}}}else if(n.allowEmptyValue&&void 0!==r){var l=n.name;t.query[l]=t.query[l]||{},t.query[l].allowEmptyValue=!0}}var Sr=["accept","authorization","content-type"];function Ar(e){var t=e.req,r=e.parameter,n=e.value;if(t.headers=t.headers||{},!(Sr.indexOf(r.name.toLowerCase())>-1))if(r.content){var o=C()(r.content)[0];t.headers[r.name]=Er(n,o)}else void 0!==n&&(t.headers[r.name]=K({key:r.name,value:n,style:r.style||"simple",explode:void 0!==r.explode&&r.explode,escape:!1}))}function kr(e){var t=e.req,r=e.parameter,n=e.value;t.headers=t.headers||{};var o=h()(n);if(r.content){var a,i=C()(r.content)[0];t.headers.Cookie=j()(a="".concat(r.name,"=")).call(a,Er(n,i))}else if("undefined"!==o){var s="object"===o&&!Array.isArray(n)&&r.explode?"":"".concat(r.name,"=");t.headers.Cookie=s+K({key:r.name,value:n,escape:!1,style:r.style||"form",explode:void 0!==r.explode&&r.explode})}}var Cr=r(92381),Or=r.n(Cr);const jr=(void 0!==Or()?Or():"undefined"!=typeof self?self:window).btoa;function Ir(e,t){var r=e.operation,n=e.requestBody,o=e.securities,a=e.spec,i=e.attachContentTypeForEmptyPayload,s=e.requestContentType;t=function(e){var t=e.request,r=e.securities,n=void 0===r?{}:r,o=e.operation,a=void 0===o?{}:o,i=e.spec,s=me()({},t),l=n.authorized,u=void 0===l?{}:l,c=a.security||i.security||[],p=u&&!!C()(u).length,f=gr()(i,["components","securitySchemes"])||{};if(s.headers=s.headers||{},s.query=s.query||{},!C()(n).length||!p||!c||Array.isArray(a.security)&&!a.security.length)return t;return c.forEach((function(e){C()(e).forEach((function(e){var t=u[e],r=f[e];if(t){var n=t.value||t,o=r.type;if(t)if("apiKey"===o)"query"===r.in&&(s.query[r.name]=n),"header"===r.in&&(s.headers[r.name]=n),"cookie"===r.in&&(s.cookies[r.name]=n);else if("http"===o){if(/^basic$/i.test(r.scheme)){var a,i=n.username||"",l=n.password||"",c=jr(j()(a="".concat(i,":")).call(a,l));s.headers.Authorization="Basic ".concat(c)}/^bearer$/i.test(r.scheme)&&(s.headers.Authorization="Bearer ".concat(n))}else if("oauth2"===o||"openIdConnect"===o){var p,h=t.token||{},d=h[r["x-tokenName"]||"access_token"],m=h.token_type;m&&"bearer"!==m.toLowerCase()||(m="Bearer"),s.headers.Authorization=j()(p="".concat(m," ")).call(p,d)}}}))})),s}({request:t,securities:o,operation:r,spec:a});var l=r.requestBody||{},u=C()(l.content||{}),c=s&&u.indexOf(s)>-1;if(n||i){if(s&&c)t.headers["Content-Type"]=s;else if(!s){var p=u[0];p&&(t.headers["Content-Type"]=p,s=p)}}else s&&c&&(t.headers["Content-Type"]=s);if(!e.responseContentType&&r.responses){var f,d=P()(f=N()(r.responses)).call(f,(function(e){var t=m()(e,2),r=t[0],n=t[1],o=parseInt(r,10);return o>=200&&o<300&&br(n.content)})).reduce((function(e,t){var r=m()(t,2)[1];return j()(e).call(e,C()(r.content))}),[]);d.length>0&&(t.headers.accept=d.join(", "))}if(n)if(s){if(u.indexOf(s)>-1)if("application/x-www-form-urlencoded"===s||"multipart/form-data"===s)if("object"===h()(n)){var g=(l.content[s]||{}).encoding||{};t.form={},C()(n).forEach((function(e){t.form[e]={value:n[e],encoding:g[e]||{}}}))}else t.form=n;else t.body=n}else t.body=n;return t}function Nr(e,t){var r,n,o=e.spec,a=e.operation,i=e.securities,s=e.requestContentType,l=e.responseContentType,u=e.attachContentTypeForEmptyPayload;if(t=function(e){var t=e.request,r=e.securities,n=void 0===r?{}:r,o=e.operation,a=void 0===o?{}:o,i=e.spec,s=me()({},t),l=n.authorized,u=void 0===l?{}:l,c=n.specSecurity,p=void 0===c?[]:c,f=a.security||p,h=u&&!!C()(u).length,d=i.securityDefinitions;if(s.headers=s.headers||{},s.query=s.query||{},!C()(n).length||!h||!f||Array.isArray(a.security)&&!a.security.length)return t;return f.forEach((function(e){C()(e).forEach((function(e){var t=u[e];if(t){var r=t.token,n=t.value||t,o=d[e],a=o.type,i=o["x-tokenName"]||"access_token",l=r&&r[i],c=r&&r.token_type;if(t)if("apiKey"===a){var p="query"===o.in?"query":"headers";s[p]=s[p]||{},s[p][o.name]=n}else if("basic"===a)if(n.header)s.headers.authorization=n.header;else{var f,h=n.username||"",m=n.password||"";n.base64=jr(j()(f="".concat(h,":")).call(f,m)),s.headers.authorization="Basic ".concat(n.base64)}else if("oauth2"===a&&l){var g;c=c&&"bearer"!==c.toLowerCase()?c:"Bearer",s.headers.authorization=j()(g="".concat(c," ")).call(g,l)}}}))})),s}({request:t,securities:i,operation:a,spec:o}),t.body||t.form||u)if(s)t.headers["Content-Type"]=s;else if(Array.isArray(a.consumes)){var c=m()(a.consumes,1);t.headers["Content-Type"]=c[0]}else if(Array.isArray(o.consumes)){var p=m()(o.consumes,1);t.headers["Content-Type"]=p[0]}else a.parameters&&P()(r=a.parameters).call(r,(function(e){return"file"===e.type})).length?t.headers["Content-Type"]="multipart/form-data":a.parameters&&P()(n=a.parameters).call(n,(function(e){return"formData"===e.in})).length&&(t.headers["Content-Type"]="application/x-www-form-urlencoded");else if(s){var f,h,d=a.parameters&&P()(f=a.parameters).call(f,(function(e){return"body"===e.in})).length>0,g=a.parameters&&P()(h=a.parameters).call(h,(function(e){return"formData"===e.in})).length>0;(d||g)&&(t.headers["Content-Type"]=s)}return!l&&Array.isArray(a.produces)&&a.produces.length>0&&(t.headers.accept=a.produces.join(", ")),t}var Tr=["http","fetch","spec","operationId","pathName","method","parameters","securities"],Pr=function(e){return Array.isArray(e)?e:[]},Rr=Ct("OperationNotFoundError",(function(e,t,r){this.originalError=r,Ee()(this,t||{})})),Mr={buildRequest:Lr};function Dr(e){var t=e.http,r=e.fetch,n=e.spec,o=e.operationId,a=e.pathName,i=e.method,s=e.parameters,l=e.securities,u=dr()(e,Tr),c=t||r||Y;a&&i&&!o&&(o=(0,cr.nc)(a,i));var p=Mr.buildRequest(me()({spec:n,operationId:o,parameters:s,securities:l,http:c},u));return p.body&&(br(p.body)||Array.isArray(p.body))&&(p.body=_()(p.body)),c(p)}function Lr(e){var t,r,n=e.spec,o=e.operationId,i=e.responseContentType,s=e.scheme,l=e.requestInterceptor,u=e.responseInterceptor,c=e.contextUrl,p=e.userFetch,f=e.server,h=e.serverVariables,d=e.http,g=e.signal,v=e.parameters,y=e.parameterBuilders,b=(0,cr.z6)(n);y||(y=b?a:wr);var w={url:"",credentials:d&&d.withCredentials?"include":"same-origin",headers:{},cookies:{}};g&&(w.signal=g),l&&(w.requestInterceptor=l),u&&(w.responseInterceptor=u),p&&(w.userFetch=p);var E=(0,cr.$r)(n,o);if(!E)throw new Rr("Operation ".concat(o," not found"));var x,_=E.operation,S=void 0===_?{}:_,k=E.method,O=E.pathName;if(w.url+=(x={spec:n,scheme:s,contextUrl:c,server:f,serverVariables:h,pathName:O,method:k},(0,cr.z6)(x.spec)?function(e){var t=e.spec,r=e.pathName,n=e.method,o=e.server,a=e.contextUrl,i=e.serverVariables,s=void 0===i?{}:i,l=gr()(t,["paths",r,(n||"").toLowerCase(),"servers"])||gr()(t,["paths",r,"servers"])||gr()(t,["servers"]),u="",c=null;if(o&&l&&l.length){var p=A()(l).call(l,(function(e){return e.url}));p.indexOf(o)>-1&&(u=o,c=l[p.indexOf(o)])}if(!u&&l&&l.length){u=l[0].url;var f=m()(l,1);c=f[0]}return u.indexOf("{")>-1&&function(e){for(var t,r=[],n=/{([^}]+)}/g;t=n.exec(e);)r.push(t[1]);return r}(u).forEach((function(e){if(c.variables&&c.variables[e]){var t=c.variables[e],r=s[e]||t.default,n=new RegExp("{".concat(e,"}"),"g");u=u.replace(n,r)}})),function(){var e,t,r=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",o=r&&n?kt.parse(kt.resolve(n,r)):kt.parse(r),a=kt.parse(n),i=Br(o.protocol)||Br(a.protocol)||"",s=o.host||a.host,l=o.pathname||"";return"/"===(e=i&&s?j()(t="".concat(i,"://")).call(t,s+l):l)[e.length-1]?$()(e).call(e,0,-1):e}(u,a)}(x):function(e){var t,r,n=e.spec,o=e.scheme,a=e.contextUrl,i=void 0===a?"":a,s=kt.parse(i),l=Array.isArray(n.schemes)?n.schemes[0]:null,u=o||l||Br(s.protocol)||"http",c=n.host||s.host||"",p=n.basePath||"";return"/"===(t=u&&c?j()(r="".concat(u,"://")).call(r,c+p):p)[t.length-1]?$()(t).call(t,0,-1):t}(x)),!o)return delete w.cookies,w;w.url+=O,w.method="".concat(k).toUpperCase(),v=v||{};var I=n.paths[O]||{};i&&(w.headers.accept=i);var N=function(e){var t={};e.forEach((function(e){t[e.in]||(t[e.in]={}),t[e.in][e.name]=e}));var r=[];return C()(t).forEach((function(e){C()(t[e]).forEach((function(n){r.push(t[e][n])}))})),r}(j()(t=j()(r=[]).call(r,Pr(S.parameters))).call(t,Pr(I.parameters)));N.forEach((function(e){var t,r,o=y[e.in];if("body"===e.in&&e.schema&&e.schema.properties&&(t=v),void 0===(t=e&&e.name&&v[e.name]))t=e&&e.name&&v[j()(r="".concat(e.in,".")).call(r,e.name)];else if(function(e,t){return P()(t).call(t,(function(t){return t.name===e}))}(e.name,N).length>1){var a;console.warn(j()(a="Parameter '".concat(e.name,"' is ambiguous because the defined spec has more than one parameter with the name: '")).call(a,e.name,"' and the passed-in parameter values did not define an 'in' value."))}if(null!==t){if(void 0!==e.default&&void 0===t&&(t=e.default),void 0===t&&e.required&&!e.allowEmptyValue)throw new Error("Required parameter ".concat(e.name," is not provided"));if(b&&e.schema&&"object"===e.schema.type&&"string"==typeof t)try{t=JSON.parse(t)}catch(e){throw new Error("Could not parse object parameter value string as JSON")}o&&o({req:w,parameter:e,value:t,operation:S,spec:n})}}));var T=me()(me()({},e),{},{operation:S});if((w=b?Ir(T,w):Nr(T,w)).cookies&&C()(w.cookies).length){var R=C()(w.cookies).reduce((function(e,t){var r=w.cookies[t];return e+(e?"&":"")+vr.serialize(t,r)}),"");w.headers.Cookie=R}return w.cookies&&delete w.cookies,fe(w),w}var Br=function(e){return e?e.replace(/\W/g,""):null};function Fr(e,t){return zr.apply(this,arguments)}function zr(){return zr=s()(u().mark((function e(t,r){var n,o,a,i,s,l,c,p,f,h,d,m,g=arguments;return u().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return n=g.length>2&&void 0!==g[2]?g[2]:{},o=n.returnEntireTree,a=n.baseDoc,i=n.requestInterceptor,s=n.responseInterceptor,l=n.parameterMacro,c=n.modelPropertyMacro,p=n.useCircularStructures,f={pathDiscriminator:r,baseDoc:a,requestInterceptor:i,responseInterceptor:s,parameterMacro:l,modelPropertyMacro:c,useCircularStructures:p},h=(0,cr.K1)({spec:t}),d=h.spec,e.next=6,fr(me()(me()({},f),{},{spec:d,allowMetaPatches:!0,skipNormalization:!0}));case 6:return m=e.sent,!o&&Array.isArray(r)&&r.length&&(m.spec=gr()(m.spec,r)||null),e.abrupt("return",m);case 9:case"end":return e.stop()}}),e)}))),zr.apply(this,arguments)}var Ur=r(34852);function qr(e){let{configs:t,getConfigs:r}=e;return{fn:{fetch:(n=Y,o=t.preFetch,a=t.postFetch,a=a||function(e){return e},o=o||function(e){return e},function(e){return"string"==typeof e&&(e={url:e}),Z.mergeInQueryOrForm(e),e=o(e),a(n(e))}),buildRequest:Lr,execute:Dr,resolve:fr,resolveSubtree:function(e,t,n){if(void 0===n){const e=r();n={modelPropertyMacro:e.modelPropertyMacro,parameterMacro:e.parameterMacro,requestInterceptor:e.requestInterceptor,responseInterceptor:e.responseInterceptor}}for(var o=arguments.length,a=new Array(o>3?o-3:0),i=3;i{"use strict";r.r(t),r.d(t,{default:()=>o});var n=r(90242);function o(){return{fn:{shallowEqualKeys:n.be}}}},48347:(e,t,r)=>{"use strict";r.r(t),r.d(t,{getDisplayName:()=>n});const n=e=>e.displayName||e.name||"Component"},73420:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>u});var n=r(35627),o=r.n(n),a=r(90242),i=r(55776),s=r(48347),l=r(60314);const u=e=>{let{getComponents:t,getStore:r,getSystem:n}=e;const u=(c=(0,i.getComponent)(n,r,t),(0,a.HP)(c,(function(){for(var e=arguments.length,t=new Array(e),r=0;r(0,l.Z)(e,(function(){for(var e=arguments.length,t=new Array(e),r=0;r{"use strict";r.r(t),r.d(t,{getComponent:()=>ne,render:()=>re,withMappedContainer:()=>te});var n=r(23101),o=r.n(n),a=r(28222),i=r.n(a),s=r(67294),l=r(73935),u=r(97779),c=s.createContext(null);var p=function(e){e()},f=function(){return p},h={notify:function(){}};var d=function(){function e(e,t){this.store=e,this.parentSub=t,this.unsubscribe=null,this.listeners=h,this.handleChangeWrapper=this.handleChangeWrapper.bind(this)}var t=e.prototype;return t.addNestedSub=function(e){return this.trySubscribe(),this.listeners.subscribe(e)},t.notifyNestedSubs=function(){this.listeners.notify()},t.handleChangeWrapper=function(){this.onStateChange&&this.onStateChange()},t.isSubscribed=function(){return Boolean(this.unsubscribe)},t.trySubscribe=function(){this.unsubscribe||(this.unsubscribe=this.parentSub?this.parentSub.addNestedSub(this.handleChangeWrapper):this.store.subscribe(this.handleChangeWrapper),this.listeners=function(){var e=f(),t=null,r=null;return{clear:function(){t=null,r=null},notify:function(){e((function(){for(var e=t;e;)e.callback(),e=e.next}))},get:function(){for(var e=[],r=t;r;)e.push(r),r=r.next;return e},subscribe:function(e){var n=!0,o=r={callback:e,next:null,prev:r};return o.prev?o.prev.next=o:t=o,function(){n&&null!==t&&(n=!1,o.next?o.next.prev=o.prev:r=o.prev,o.prev?o.prev.next=o.next:t=o.next)}}}}())},t.tryUnsubscribe=function(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null,this.listeners.clear(),this.listeners=h)},e}(),m="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?s.useLayoutEffect:s.useEffect;const g=function(e){var t=e.store,r=e.context,n=e.children,o=(0,s.useMemo)((function(){var e=new d(t);return e.onStateChange=e.notifyNestedSubs,{store:t,subscription:e}}),[t]),a=(0,s.useMemo)((function(){return t.getState()}),[t]);m((function(){var e=o.subscription;return e.trySubscribe(),a!==t.getState()&&e.notifyNestedSubs(),function(){e.tryUnsubscribe(),e.onStateChange=null}}),[o,a]);var i=r||c;return s.createElement(i.Provider,{value:o},n)};var v=r(87462),y=r(63366),b=r(8679),w=r.n(b),E=r(72973),x=[],_=[null,null];function S(e,t){var r=e[1];return[t.payload,r+1]}function A(e,t,r){m((function(){return e.apply(void 0,t)}),r)}function k(e,t,r,n,o,a,i){e.current=n,t.current=o,r.current=!1,a.current&&(a.current=null,i())}function C(e,t,r,n,o,a,i,s,l,u){if(e){var c=!1,p=null,f=function(){if(!c){var e,r,f=t.getState();try{e=n(f,o.current)}catch(e){r=e,p=e}r||(p=null),e===a.current?i.current||l():(a.current=e,s.current=e,i.current=!0,u({type:"STORE_UPDATED",payload:{error:r}}))}};r.onStateChange=f,r.trySubscribe(),f();return function(){if(c=!0,r.tryUnsubscribe(),r.onStateChange=null,p)throw p}}}var O=function(){return[null,0]};function j(e,t){void 0===t&&(t={});var r=t,n=r.getDisplayName,o=void 0===n?function(e){return"ConnectAdvanced("+e+")"}:n,a=r.methodName,i=void 0===a?"connectAdvanced":a,l=r.renderCountProp,u=void 0===l?void 0:l,p=r.shouldHandleStateChanges,f=void 0===p||p,h=r.storeKey,m=void 0===h?"store":h,g=(r.withRef,r.forwardRef),b=void 0!==g&&g,j=r.context,I=void 0===j?c:j,N=(0,y.Z)(r,["getDisplayName","methodName","renderCountProp","shouldHandleStateChanges","storeKey","withRef","forwardRef","context"]),T=I;return function(t){var r=t.displayName||t.name||"Component",n=o(r),a=(0,v.Z)({},N,{getDisplayName:o,methodName:i,renderCountProp:u,shouldHandleStateChanges:f,storeKey:m,displayName:n,wrappedComponentName:r,WrappedComponent:t}),l=N.pure;var c=l?s.useMemo:function(e){return e()};function p(r){var n=(0,s.useMemo)((function(){var e=r.reactReduxForwardedRef,t=(0,y.Z)(r,["reactReduxForwardedRef"]);return[r.context,e,t]}),[r]),o=n[0],i=n[1],l=n[2],u=(0,s.useMemo)((function(){return o&&o.Consumer&&(0,E.isContextConsumer)(s.createElement(o.Consumer,null))?o:T}),[o,T]),p=(0,s.useContext)(u),h=Boolean(r.store)&&Boolean(r.store.getState)&&Boolean(r.store.dispatch);Boolean(p)&&Boolean(p.store);var m=h?r.store:p.store,g=(0,s.useMemo)((function(){return function(t){return e(t.dispatch,a)}(m)}),[m]),b=(0,s.useMemo)((function(){if(!f)return _;var e=new d(m,h?null:p.subscription),t=e.notifyNestedSubs.bind(e);return[e,t]}),[m,h,p]),w=b[0],j=b[1],I=(0,s.useMemo)((function(){return h?p:(0,v.Z)({},p,{subscription:w})}),[h,p,w]),N=(0,s.useReducer)(S,x,O),P=N[0][0],R=N[1];if(P&&P.error)throw P.error;var M=(0,s.useRef)(),D=(0,s.useRef)(l),L=(0,s.useRef)(),B=(0,s.useRef)(!1),F=c((function(){return L.current&&l===D.current?L.current:g(m.getState(),l)}),[m,P,l]);A(k,[D,M,B,l,F,L,j]),A(C,[f,m,w,g,D,M,B,L,j,R],[m,w,g]);var z=(0,s.useMemo)((function(){return s.createElement(t,(0,v.Z)({},F,{ref:i}))}),[i,t,F]);return(0,s.useMemo)((function(){return f?s.createElement(u.Provider,{value:I},z):z}),[u,z,I])}var h=l?s.memo(p):p;if(h.WrappedComponent=t,h.displayName=p.displayName=n,b){var g=s.forwardRef((function(e,t){return s.createElement(h,(0,v.Z)({},e,{reactReduxForwardedRef:t}))}));return g.displayName=n,g.WrappedComponent=t,w()(g,t)}return w()(h,t)}}function I(e,t){return e===t?0!==e||0!==t||1/e==1/t:e!=e&&t!=t}function N(e,t){if(I(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var r=Object.keys(e),n=Object.keys(t);if(r.length!==n.length)return!1;for(var o=0;o=0;n--){var o=t[n](e);if(o)return o}return function(t,n){throw new Error("Invalid value of type "+typeof e+" for "+r+" argument when connecting component "+n.wrappedComponentName+".")}}function V(e,t){return e===t}function $(e){var t=void 0===e?{}:e,r=t.connectHOC,n=void 0===r?j:r,o=t.mapStateToPropsFactories,a=void 0===o?D:o,i=t.mapDispatchToPropsFactories,s=void 0===i?M:i,l=t.mergePropsFactories,u=void 0===l?B:l,c=t.selectorFactory,p=void 0===c?U:c;return function(e,t,r,o){void 0===o&&(o={});var i=o,l=i.pure,c=void 0===l||l,f=i.areStatesEqual,h=void 0===f?V:f,d=i.areOwnPropsEqual,m=void 0===d?N:d,g=i.areStatePropsEqual,b=void 0===g?N:g,w=i.areMergedPropsEqual,E=void 0===w?N:w,x=(0,y.Z)(i,["pure","areStatesEqual","areOwnPropsEqual","areStatePropsEqual","areMergedPropsEqual"]),_=q(e,a,"mapStateToProps"),S=q(t,s,"mapDispatchToProps"),A=q(r,u,"mergeProps");return n(p,(0,v.Z)({methodName:"connect",getDisplayName:function(e){return"Connect("+e+")"},shouldHandleStateChanges:Boolean(e),initMapStateToProps:_,initMapDispatchToProps:S,initMergeProps:A,pure:c,areStatesEqual:h,areOwnPropsEqual:m,areStatePropsEqual:b,areMergedPropsEqual:E},x))}}const W=$();var H;H=l.unstable_batchedUpdates,p=H;var J=r(57557),K=r.n(J),G=r(6557),Z=r.n(G);const Y=e=>t=>{const{fn:r}=e();class n extends s.Component{render(){return s.createElement(t,o()({},e(),this.props,this.context))}}return n.displayName=`WithSystem(${r.getDisplayName(t)})`,n},Q=(e,t)=>r=>{const{fn:n}=e();class a extends s.Component{render(){return s.createElement(g,{store:t},s.createElement(r,o()({},this.props,this.context)))}}return a.displayName=`WithRoot(${n.getDisplayName(r)})`,a},X=(e,t,r)=>(0,u.qC)(r?Q(e,r):Z(),W(((r,n)=>{var o;const a={...n,...e()},i=(null===(o=t.prototype)||void 0===o?void 0:o.mapStateToProps)||(e=>({state:e}));return i(r,a)})),Y(e))(t),ee=(e,t,r,n)=>{for(const o in t){const a=t[o];"function"==typeof a&&a(r[o],n[o],e())}},te=(e,t,r)=>(t,n)=>{const{fn:o}=e(),a=r(t,"root");class l extends s.Component{constructor(t,r){super(t,r),ee(e,n,t,{})}UNSAFE_componentWillReceiveProps(t){ee(e,n,t,this.props)}render(){const e=K()(this.props,n?i()(n):[]);return s.createElement(a,e)}}return l.displayName=`WithMappedContainer(${o.getDisplayName(a)})`,l},re=(e,t,r,n)=>o=>{const a=r(e,t,n)("App","root");l.render(s.createElement(a,null),o)},ne=(e,t,r)=>function(n,o){let a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if("string"!=typeof n)throw new TypeError("Need a string, to fetch a component. Was given a "+typeof n);const i=r(n);return i?o?"root"===o?X(e,i,t()):X(e,i):i:(a.failSilently||e().log.warn("Could not find component:",n),null)}},36581:(e,t,r)=>{"use strict";r.d(t,{d3:()=>T,C2:()=>Z});var n=r(28222),o=r.n(n),a=r(58118),i=r.n(a),s=r(63366);function l(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r=4?[t[0],t[1],t[2],t[3],"".concat(t[0],".").concat(t[1]),"".concat(t[0],".").concat(t[2]),"".concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[0]),"".concat(t[1],".").concat(t[2]),"".concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[0]),"".concat(t[2],".").concat(t[1]),"".concat(t[2],".").concat(t[3]),"".concat(t[3],".").concat(t[0]),"".concat(t[3],".").concat(t[1]),"".concat(t[3],".").concat(t[2]),"".concat(t[0],".").concat(t[1],".").concat(t[2]),"".concat(t[0],".").concat(t[1],".").concat(t[3]),"".concat(t[0],".").concat(t[2],".").concat(t[1]),"".concat(t[0],".").concat(t[2],".").concat(t[3]),"".concat(t[0],".").concat(t[3],".").concat(t[1]),"".concat(t[0],".").concat(t[3],".").concat(t[2]),"".concat(t[1],".").concat(t[0],".").concat(t[2]),"".concat(t[1],".").concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[2],".").concat(t[0]),"".concat(t[1],".").concat(t[2],".").concat(t[3]),"".concat(t[1],".").concat(t[3],".").concat(t[0]),"".concat(t[1],".").concat(t[3],".").concat(t[2]),"".concat(t[2],".").concat(t[0],".").concat(t[1]),"".concat(t[2],".").concat(t[0],".").concat(t[3]),"".concat(t[2],".").concat(t[1],".").concat(t[0]),"".concat(t[2],".").concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[3],".").concat(t[0]),"".concat(t[2],".").concat(t[3],".").concat(t[1]),"".concat(t[3],".").concat(t[0],".").concat(t[1]),"".concat(t[3],".").concat(t[0],".").concat(t[2]),"".concat(t[3],".").concat(t[1],".").concat(t[0]),"".concat(t[3],".").concat(t[1],".").concat(t[2]),"".concat(t[3],".").concat(t[2],".").concat(t[0]),"".concat(t[3],".").concat(t[2],".").concat(t[1]),"".concat(t[0],".").concat(t[1],".").concat(t[2],".").concat(t[3]),"".concat(t[0],".").concat(t[1],".").concat(t[3],".").concat(t[2]),"".concat(t[0],".").concat(t[2],".").concat(t[1],".").concat(t[3]),"".concat(t[0],".").concat(t[2],".").concat(t[3],".").concat(t[1]),"".concat(t[0],".").concat(t[3],".").concat(t[1],".").concat(t[2]),"".concat(t[0],".").concat(t[3],".").concat(t[2],".").concat(t[1]),"".concat(t[1],".").concat(t[0],".").concat(t[2],".").concat(t[3]),"".concat(t[1],".").concat(t[0],".").concat(t[3],".").concat(t[2]),"".concat(t[1],".").concat(t[2],".").concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[2],".").concat(t[3],".").concat(t[0]),"".concat(t[1],".").concat(t[3],".").concat(t[0],".").concat(t[2]),"".concat(t[1],".").concat(t[3],".").concat(t[2],".").concat(t[0]),"".concat(t[2],".").concat(t[0],".").concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[0],".").concat(t[3],".").concat(t[1]),"".concat(t[2],".").concat(t[1],".").concat(t[0],".").concat(t[3]),"".concat(t[2],".").concat(t[1],".").concat(t[3],".").concat(t[0]),"".concat(t[2],".").concat(t[3],".").concat(t[0],".").concat(t[1]),"".concat(t[2],".").concat(t[3],".").concat(t[1],".").concat(t[0]),"".concat(t[3],".").concat(t[0],".").concat(t[1],".").concat(t[2]),"".concat(t[3],".").concat(t[0],".").concat(t[2],".").concat(t[1]),"".concat(t[3],".").concat(t[1],".").concat(t[0],".").concat(t[2]),"".concat(t[3],".").concat(t[1],".").concat(t[2],".").concat(t[0]),"".concat(t[3],".").concat(t[2],".").concat(t[0],".").concat(t[1]),"".concat(t[3],".").concat(t[2],".").concat(t[1],".").concat(t[0])]:void 0),d[n]}function g(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=arguments.length>2?arguments[2]:void 0,n=e.filter((function(e){return"token"!==e})),o=m(n);return o.reduce((function(e,t){return p({},e,r[t])}),t)}function v(e){return e.join(" ")}function y(e){var t=e.node,r=e.stylesheet,n=e.style,o=void 0===n?{}:n,a=e.useInlineStyles,i=e.key,s=t.properties,l=t.type,u=t.tagName,c=t.value;if("text"===l)return c;if(u){var d,m=function(e,t){var r=0;return function(n){return r+=1,n.map((function(n,o){return y({node:n,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(r,"-").concat(o)})}))}}(r,a);if(a){var b=Object.keys(r).reduce((function(e,t){return t.split(".").forEach((function(t){e.includes(t)||e.push(t)})),e}),[]),w=s.className&&s.className.includes("token")?["token"]:[],E=s.className&&w.concat(s.className.filter((function(e){return!b.includes(e)})));d=p({},s,{className:v(E)||void 0,style:g(s.className,Object.assign({},s.style,o),r)})}else d=p({},s,{className:v(s.className)});var x=m(t.children);return f.createElement(u,(0,h.Z)({key:i},d),x)}}var b=/\n/g;function w(e){var t=e.codeString,r=e.codeStyle,n=e.containerStyle,o=void 0===n?{float:"left",paddingRight:"10px"}:n,a=e.numberStyle,i=void 0===a?{}:a,s=e.startingLineNumber;return f.createElement("code",{style:Object.assign({},r,o)},function(e){var t=e.lines,r=e.startingLineNumber,n=e.style;return t.map((function(e,t){var o=t+r;return f.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof n?n(o):n},"".concat(o,"\n"))}))}({lines:t.replace(/\n$/,"").split("\n"),style:i,startingLineNumber:s}))}function E(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function x(e,t,r){var n;return p({},{display:"inline-block",minWidth:(n=r,"".concat(n.toString().length,".25em")),paddingRight:"1em",textAlign:"right",userSelect:"none"},"function"==typeof e?e(t):e)}function _(e){var t=e.children,r=e.lineNumber,n=e.lineNumberStyle,o=e.largestLineNumber,a=e.showInlineLineNumbers,i=e.lineProps,s=void 0===i?{}:i,l=e.className,u=void 0===l?[]:l,c=e.showLineNumbers,f=e.wrapLongLines,h="function"==typeof s?s(r):s;if(h.className=u,r&&a){var d=x(n,r,o);t.unshift(E(r,d))}return f&c&&(h.style=p({},h.style,{display:"flex"})),{type:"element",tagName:"span",properties:h,children:t}}function S(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],n=0;n2&&void 0!==arguments[2]?arguments[2]:[];return _({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:i,showInlineLineNumbers:o,lineProps:r,className:a,showLineNumbers:n,wrapLongLines:l})}function m(e,t){if(n&&t&&o){var r=x(s,t,i);e.unshift(E(t,r))}return e}function g(e,r){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||n.length>0?d(e,r,n):m(e,r)}for(var v=function(){var e=c[h],t=e.children[0].value;if(t.match(b)){var r=t.split("\n");r.forEach((function(t,o){var i=n&&p.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===o){var l=g(c.slice(f+1,h).concat(_({children:[s],className:e.properties.className})),i);p.push(l)}else if(o===r.length-1){if(c[h+1]&&c[h+1].children&&c[h+1].children[0]){var u=_({children:[{type:"text",value:"".concat(t)}],className:e.properties.className});c.splice(h+1,0,u)}else{var d=g([s],i,e.properties.className);p.push(d)}}else{var m=g([s],i,e.properties.className);p.push(m)}})),f=h}h++};h=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}(e,["language","children","style","customStyle","codeTagProps","useInlineStyles","showLineNumbers","showInlineLineNumbers","startingLineNumber","lineNumberContainerStyle","lineNumberStyle","wrapLines","wrapLongLines","lineProps","renderer","PreTag","CodeTag","code","astGenerator"]);U=U||O;var V=m?f.createElement(w,{containerStyle:E,codeStyle:u.style||{},numberStyle:_,startingLineNumber:b,codeString:z}):null,$=o.hljs||o['pre[class*="language-"]']||{backgroundColor:"#fff"},W=C(U)?"hljs":"prismjs",H=h?Object.assign({},q,{style:Object.assign({},$,i)}):Object.assign({},q,{className:q.className?"".concat(W," ").concat(q.className):W,style:Object.assign({},i)});if(!U)return f.createElement(D,H,V,f.createElement(B,u,z));(void 0===S&&R||N)&&(S=!0),R=R||k;var J=[{type:"text",value:z}],K=function(e){var t=e.astGenerator,r=e.language,n=e.code,o=e.defaultCodeValue;if(C(t)){var a=function(e,t){return-1!==e.listLanguages().indexOf(t)}(t,r);return"text"===r?{value:o,language:"text"}:a?t.highlight(r,n):t.highlightAuto(n)}try{return r&&"text"!==r?{value:t.highlight(n,r)}:{value:o}}catch(e){return{value:o}}}({astGenerator:U,language:t,code:z,defaultCodeValue:J});null===K.language&&(K.value=J);var G=A(K,S,P,m,v,b,K.value.length+b,_,N);return u.style=p({},u.style,N?{whiteSpace:"pre-wrap"}:{whiteSpace:"pre"}),f.createElement(D,H,f.createElement(B,u,!v&&V,R({rows:G,stylesheet:o,useInlineStyles:h})))});N.registerLanguage=I.registerLanguage;const T=N;var P=r(96344);const R=r.n(P)();var M=r(82026);const D=r.n(M)();var L=r(42157);const B=r.n(L)();var F=r(61519);const z=r.n(F)();var U=r(54587);const q=r.n(U)();var V=r(30786);const $=r.n(V)();var W=r(66336);const H=r.n(W)(),J={hljs:{display:"block",overflowX:"auto",padding:"0.5em",background:"#333",color:"white"},"hljs-name":{fontWeight:"bold"},"hljs-strong":{fontWeight:"bold"},"hljs-code":{fontStyle:"italic",color:"#888"},"hljs-emphasis":{fontStyle:"italic"},"hljs-tag":{color:"#62c8f3"},"hljs-variable":{color:"#ade5fc"},"hljs-template-variable":{color:"#ade5fc"},"hljs-selector-id":{color:"#ade5fc"},"hljs-selector-class":{color:"#ade5fc"},"hljs-string":{color:"#a2fca2"},"hljs-bullet":{color:"#d36363"},"hljs-type":{color:"#ffa"},"hljs-title":{color:"#ffa"},"hljs-section":{color:"#ffa"},"hljs-attribute":{color:"#ffa"},"hljs-quote":{color:"#ffa"},"hljs-built_in":{color:"#ffa"},"hljs-builtin-name":{color:"#ffa"},"hljs-number":{color:"#d36363"},"hljs-symbol":{color:"#d36363"},"hljs-keyword":{color:"#fcc28c"},"hljs-selector-tag":{color:"#fcc28c"},"hljs-literal":{color:"#fcc28c"},"hljs-comment":{color:"#888"},"hljs-deletion":{color:"#333",backgroundColor:"#fc9b9b"},"hljs-regexp":{color:"#c6b4f0"},"hljs-link":{color:"#c6b4f0"},"hljs-meta":{color:"#fc9b9b"},"hljs-addition":{backgroundColor:"#a2fca2",color:"#333"}};T.registerLanguage("json",D),T.registerLanguage("js",R),T.registerLanguage("xml",B),T.registerLanguage("yaml",q),T.registerLanguage("http",$),T.registerLanguage("bash",z),T.registerLanguage("powershell",H),T.registerLanguage("javascript",R);const K={agate:J,arta:{hljs:{display:"block",overflowX:"auto",padding:"0.5em",background:"#222",color:"#aaa"},"hljs-subst":{color:"#aaa"},"hljs-section":{color:"#fff",fontWeight:"bold"},"hljs-comment":{color:"#444"},"hljs-quote":{color:"#444"},"hljs-meta":{color:"#444"},"hljs-string":{color:"#ffcc33"},"hljs-symbol":{color:"#ffcc33"},"hljs-bullet":{color:"#ffcc33"},"hljs-regexp":{color:"#ffcc33"},"hljs-number":{color:"#00cc66"},"hljs-addition":{color:"#00cc66"},"hljs-built_in":{color:"#32aaee"},"hljs-builtin-name":{color:"#32aaee"},"hljs-literal":{color:"#32aaee"},"hljs-type":{color:"#32aaee"},"hljs-template-variable":{color:"#32aaee"},"hljs-attribute":{color:"#32aaee"},"hljs-link":{color:"#32aaee"},"hljs-keyword":{color:"#6644aa"},"hljs-selector-tag":{color:"#6644aa"},"hljs-name":{color:"#6644aa"},"hljs-selector-id":{color:"#6644aa"},"hljs-selector-class":{color:"#6644aa"},"hljs-title":{color:"#bb1166"},"hljs-variable":{color:"#bb1166"},"hljs-deletion":{color:"#bb1166"},"hljs-template-tag":{color:"#bb1166"},"hljs-doctag":{fontWeight:"bold"},"hljs-strong":{fontWeight:"bold"},"hljs-emphasis":{fontStyle:"italic"}},monokai:{hljs:{display:"block",overflowX:"auto",padding:"0.5em",background:"#272822",color:"#ddd"},"hljs-tag":{color:"#f92672"},"hljs-keyword":{color:"#f92672",fontWeight:"bold"},"hljs-selector-tag":{color:"#f92672",fontWeight:"bold"},"hljs-literal":{color:"#f92672",fontWeight:"bold"},"hljs-strong":{color:"#f92672"},"hljs-name":{color:"#f92672"},"hljs-code":{color:"#66d9ef"},"hljs-class .hljs-title":{color:"white"},"hljs-attribute":{color:"#bf79db"},"hljs-symbol":{color:"#bf79db"},"hljs-regexp":{color:"#bf79db"},"hljs-link":{color:"#bf79db"},"hljs-string":{color:"#a6e22e"},"hljs-bullet":{color:"#a6e22e"},"hljs-subst":{color:"#a6e22e"},"hljs-title":{color:"#a6e22e",fontWeight:"bold"},"hljs-section":{color:"#a6e22e",fontWeight:"bold"},"hljs-emphasis":{color:"#a6e22e"},"hljs-type":{color:"#a6e22e",fontWeight:"bold"},"hljs-built_in":{color:"#a6e22e"},"hljs-builtin-name":{color:"#a6e22e"},"hljs-selector-attr":{color:"#a6e22e"},"hljs-selector-pseudo":{color:"#a6e22e"},"hljs-addition":{color:"#a6e22e"},"hljs-variable":{color:"#a6e22e"},"hljs-template-tag":{color:"#a6e22e"},"hljs-template-variable":{color:"#a6e22e"},"hljs-comment":{color:"#75715e"},"hljs-quote":{color:"#75715e"},"hljs-deletion":{color:"#75715e"},"hljs-meta":{color:"#75715e"},"hljs-doctag":{fontWeight:"bold"},"hljs-selector-id":{fontWeight:"bold"}},nord:{hljs:{display:"block",overflowX:"auto",padding:"0.5em",background:"#2E3440",color:"#D8DEE9"},"hljs-subst":{color:"#D8DEE9"},"hljs-selector-tag":{color:"#81A1C1"},"hljs-selector-id":{color:"#8FBCBB",fontWeight:"bold"},"hljs-selector-class":{color:"#8FBCBB"},"hljs-selector-attr":{color:"#8FBCBB"},"hljs-selector-pseudo":{color:"#88C0D0"},"hljs-addition":{backgroundColor:"rgba(163, 190, 140, 0.5)"},"hljs-deletion":{backgroundColor:"rgba(191, 97, 106, 0.5)"},"hljs-built_in":{color:"#8FBCBB"},"hljs-type":{color:"#8FBCBB"},"hljs-class":{color:"#8FBCBB"},"hljs-function":{color:"#88C0D0"},"hljs-function > .hljs-title":{color:"#88C0D0"},"hljs-keyword":{color:"#81A1C1"},"hljs-literal":{color:"#81A1C1"},"hljs-symbol":{color:"#81A1C1"},"hljs-number":{color:"#B48EAD"},"hljs-regexp":{color:"#EBCB8B"},"hljs-string":{color:"#A3BE8C"},"hljs-title":{color:"#8FBCBB"},"hljs-params":{color:"#D8DEE9"},"hljs-bullet":{color:"#81A1C1"},"hljs-code":{color:"#8FBCBB"},"hljs-emphasis":{fontStyle:"italic"},"hljs-formula":{color:"#8FBCBB"},"hljs-strong":{fontWeight:"bold"},"hljs-link:hover":{textDecoration:"underline"},"hljs-quote":{color:"#4C566A"},"hljs-comment":{color:"#4C566A"},"hljs-doctag":{color:"#8FBCBB"},"hljs-meta":{color:"#5E81AC"},"hljs-meta-keyword":{color:"#5E81AC"},"hljs-meta-string":{color:"#A3BE8C"},"hljs-attr":{color:"#8FBCBB"},"hljs-attribute":{color:"#D8DEE9"},"hljs-builtin-name":{color:"#81A1C1"},"hljs-name":{color:"#81A1C1"},"hljs-section":{color:"#88C0D0"},"hljs-tag":{color:"#81A1C1"},"hljs-variable":{color:"#D8DEE9"},"hljs-template-variable":{color:"#D8DEE9"},"hljs-template-tag":{color:"#5E81AC"},"abnf .hljs-attribute":{color:"#88C0D0"},"abnf .hljs-symbol":{color:"#EBCB8B"},"apache .hljs-attribute":{color:"#88C0D0"},"apache .hljs-section":{color:"#81A1C1"},"arduino .hljs-built_in":{color:"#88C0D0"},"aspectj .hljs-meta":{color:"#D08770"},"aspectj > .hljs-title":{color:"#88C0D0"},"bnf .hljs-attribute":{color:"#8FBCBB"},"clojure .hljs-name":{color:"#88C0D0"},"clojure .hljs-symbol":{color:"#EBCB8B"},"coq .hljs-built_in":{color:"#88C0D0"},"cpp .hljs-meta-string":{color:"#8FBCBB"},"css .hljs-built_in":{color:"#88C0D0"},"css .hljs-keyword":{color:"#D08770"},"diff .hljs-meta":{color:"#8FBCBB"},"ebnf .hljs-attribute":{color:"#8FBCBB"},"glsl .hljs-built_in":{color:"#88C0D0"},"groovy .hljs-meta:not(:first-child)":{color:"#D08770"},"haxe .hljs-meta":{color:"#D08770"},"java .hljs-meta":{color:"#D08770"},"ldif .hljs-attribute":{color:"#8FBCBB"},"lisp .hljs-name":{color:"#88C0D0"},"lua .hljs-built_in":{color:"#88C0D0"},"moonscript .hljs-built_in":{color:"#88C0D0"},"nginx .hljs-attribute":{color:"#88C0D0"},"nginx .hljs-section":{color:"#5E81AC"},"pf .hljs-built_in":{color:"#88C0D0"},"processing .hljs-built_in":{color:"#88C0D0"},"scss .hljs-keyword":{color:"#81A1C1"},"stylus .hljs-keyword":{color:"#81A1C1"},"swift .hljs-meta":{color:"#D08770"},"vim .hljs-built_in":{color:"#88C0D0",fontStyle:"italic"},"yaml .hljs-meta":{color:"#D08770"}},obsidian:{hljs:{display:"block",overflowX:"auto",padding:"0.5em",background:"#282b2e",color:"#e0e2e4"},"hljs-keyword":{color:"#93c763",fontWeight:"bold"},"hljs-selector-tag":{color:"#93c763",fontWeight:"bold"},"hljs-literal":{color:"#93c763",fontWeight:"bold"},"hljs-selector-id":{color:"#93c763"},"hljs-number":{color:"#ffcd22"},"hljs-attribute":{color:"#668bb0"},"hljs-code":{color:"white"},"hljs-class .hljs-title":{color:"white"},"hljs-section":{color:"white",fontWeight:"bold"},"hljs-regexp":{color:"#d39745"},"hljs-link":{color:"#d39745"},"hljs-meta":{color:"#557182"},"hljs-tag":{color:"#8cbbad"},"hljs-name":{color:"#8cbbad",fontWeight:"bold"},"hljs-bullet":{color:"#8cbbad"},"hljs-subst":{color:"#8cbbad"},"hljs-emphasis":{color:"#8cbbad"},"hljs-type":{color:"#8cbbad",fontWeight:"bold"},"hljs-built_in":{color:"#8cbbad"},"hljs-selector-attr":{color:"#8cbbad"},"hljs-selector-pseudo":{color:"#8cbbad"},"hljs-addition":{color:"#8cbbad"},"hljs-variable":{color:"#8cbbad"},"hljs-template-tag":{color:"#8cbbad"},"hljs-template-variable":{color:"#8cbbad"},"hljs-string":{color:"#ec7600"},"hljs-symbol":{color:"#ec7600"},"hljs-comment":{color:"#818e96"},"hljs-quote":{color:"#818e96"},"hljs-deletion":{color:"#818e96"},"hljs-selector-class":{color:"#A082BD"},"hljs-doctag":{fontWeight:"bold"},"hljs-title":{fontWeight:"bold"},"hljs-strong":{fontWeight:"bold"}},"tomorrow-night":{"hljs-comment":{color:"#969896"},"hljs-quote":{color:"#969896"},"hljs-variable":{color:"#cc6666"},"hljs-template-variable":{color:"#cc6666"},"hljs-tag":{color:"#cc6666"},"hljs-name":{color:"#cc6666"},"hljs-selector-id":{color:"#cc6666"},"hljs-selector-class":{color:"#cc6666"},"hljs-regexp":{color:"#cc6666"},"hljs-deletion":{color:"#cc6666"},"hljs-number":{color:"#de935f"},"hljs-built_in":{color:"#de935f"},"hljs-builtin-name":{color:"#de935f"},"hljs-literal":{color:"#de935f"},"hljs-type":{color:"#de935f"},"hljs-params":{color:"#de935f"},"hljs-meta":{color:"#de935f"},"hljs-link":{color:"#de935f"},"hljs-attribute":{color:"#f0c674"},"hljs-string":{color:"#b5bd68"},"hljs-symbol":{color:"#b5bd68"},"hljs-bullet":{color:"#b5bd68"},"hljs-addition":{color:"#b5bd68"},"hljs-title":{color:"#81a2be"},"hljs-section":{color:"#81a2be"},"hljs-keyword":{color:"#b294bb"},"hljs-selector-tag":{color:"#b294bb"},hljs:{display:"block",overflowX:"auto",background:"#1d1f21",color:"#c5c8c6",padding:"0.5em"},"hljs-emphasis":{fontStyle:"italic"},"hljs-strong":{fontWeight:"bold"}}},G=o()(K),Z=e=>i()(G).call(G,e)?K[e]:(console.warn(`Request style '${e}' is not available, returning default instead`),J)},90242:(e,t,r)=>{"use strict";r.d(t,{mz:()=>pe,oG:()=>fe,AF:()=>he,LQ:()=>de,Kn:()=>me,Wl:()=>ge,kJ:()=>ve,HP:()=>ye,Ay:()=>be,Q2:()=>we,_5:()=>Ee,iQ:()=>xe,gp:()=>_e,DR:()=>Se,Zl:()=>Ae,Ik:()=>Ce,xi:()=>Pe,UG:()=>Re,r3:()=>Me,wh:()=>De,GZ:()=>Le,be:()=>Be,Nm:()=>Fe,hW:()=>ze,QG:()=>Ue,oJ:()=>qe,J6:()=>Ve,nX:()=>$e,po:()=>We,XV:()=>He,Pz:()=>Je,D$:()=>Ke,V9:()=>Ge,cz:()=>Ze,Uj:()=>Ye,Xb:()=>Qe,O2:()=>et});var n=r(58309),o=r.n(n),a=r(97606),i=r.n(a),s=r(74386),l=r.n(s),u=r(86),c=r.n(u),p=r(14418),f=r.n(p),h=r(28222),d=r.n(h),m=(r(11189),r(24282)),g=r.n(m),v=r(76986),y=r.n(v),b=r(2578),w=r.n(b),E=r(24278),x=r.n(E),_=(r(39022),r(92039)),S=r.n(_),A=(r(58118),r(35627)),k=r.n(A),C=r(11882),O=r.n(C),j=r(51679),I=r.n(j),N=r(27043),T=r.n(N),P=r(81607),R=r.n(P),M=r(43393),D=r.n(M),L=r(17967),B=r(68929),F=r.n(B),z=r(11700),U=r.n(z),q=r(88306),V=r.n(q),$=r(13311),W=r.n($),H=r(59704),J=r.n(H),K=r(77813),G=r.n(K),Z=r(23560),Y=r.n(Z),Q=r(57050),X=r(27504),ee=r(8269),te=r.n(ee),re=r(19069),ne=r(92282),oe=r.n(ne),ae=r(89072),ie=r.n(ae),se=r(1272),le=r(48764).Buffer;const ue="default",ce=e=>D().Iterable.isIterable(e);function pe(e){return me(e)?ce(e)?e.toJS():e:{}}function fe(e){var t,r;if(ce(e))return e;if(e instanceof X.Z.File)return e;if(!me(e))return e;if(o()(e))return i()(r=D().Seq(e)).call(r,fe).toList();if(Y()(l()(e))){var n;const t=function(e){if(!Y()(l()(e)))return e;const t={},r="_**[]",n={};for(let o of l()(e).call(e))if(t[o[0]]||n[o[0]]&&n[o[0]].containsMultiple){if(!n[o[0]]){n[o[0]]={containsMultiple:!0,length:1},t[`${o[0]}${r}${n[o[0]].length}`]=t[o[0]],delete t[o[0]]}n[o[0]].length+=1,t[`${o[0]}${r}${n[o[0]].length}`]=o[1]}else t[o[0]]=o[1];return t}(e);return i()(n=D().OrderedMap(t)).call(n,fe)}return i()(t=D().OrderedMap(e)).call(t,fe)}function he(e){return o()(e)?e:[e]}function de(e){return"function"==typeof e}function me(e){return!!e&&"object"==typeof e}function ge(e){return"function"==typeof e}function ve(e){return o()(e)}const ye=V();function be(e,t){var r;return g()(r=d()(e)).call(r,((r,n)=>(r[n]=t(e[n],n),r)),{})}function we(e,t){var r;return g()(r=d()(e)).call(r,((r,n)=>{let o=t(e[n],n);return o&&"object"==typeof o&&y()(r,o),r}),{})}function Ee(e){return t=>{let{dispatch:r,getState:n}=t;return t=>r=>"function"==typeof r?r(e()):t(r)}}function xe(e){var t;let r=e.keySeq();return r.contains(ue)?ue:w()(t=f()(r).call(r,(e=>"2"===(e+"")[0]))).call(t).first()}function _e(e,t){if(!D().Iterable.isIterable(e))return D().List();let r=e.getIn(o()(t)?t:[t]);return D().List.isList(r)?r:D().List()}function Se(e){let t,r=[/filename\*=[^']+'\w*'"([^"]+)";?/i,/filename\*=[^']+'\w*'([^;]+);?/i,/filename="([^;]*);?"/i,/filename=([^;]*);?/i];if(S()(r).call(r,(r=>(t=r.exec(e),null!==t))),null!==t&&t.length>1)try{return decodeURIComponent(t[1])}catch(e){console.error(e)}return null}function Ae(e){return t=e.replace(/\.[^./]*$/,""),U()(F()(t));var t}function ke(e,t,r,n,a){if(!t)return[];let s=[],l=t.get("nullable"),u=t.get("required"),p=t.get("maximum"),h=t.get("minimum"),d=t.get("type"),m=t.get("format"),g=t.get("maxLength"),v=t.get("minLength"),y=t.get("uniqueItems"),b=t.get("maxItems"),w=t.get("minItems"),E=t.get("pattern");const x=r||!0===u,_=null!=e;if(l&&null===e||!d||!(x||_&&"array"===d||!(!x&&!_)))return[];let A="string"===d&&e,k="array"===d&&o()(e)&&e.length,C="array"===d&&D().List.isList(e)&&e.count();const O=[A,k,C,"array"===d&&"string"==typeof e&&e,"file"===d&&e instanceof X.Z.File,"boolean"===d&&(e||!1===e),"number"===d&&(e||0===e),"integer"===d&&(e||0===e),"object"===d&&"object"==typeof e&&null!==e,"object"===d&&"string"==typeof e&&e],j=S()(O).call(O,(e=>!!e));if(x&&!j&&!n)return s.push("Required field is not provided"),s;if("object"===d&&(null===a||"application/json"===a)){let r=e;if("string"==typeof e)try{r=JSON.parse(e)}catch(e){return s.push("Parameter string value must be valid JSON"),s}var I;if(t&&t.has("required")&&ge(u.isList)&&u.isList()&&c()(u).call(u,(e=>{void 0===r[e]&&s.push({propKey:e,error:"Required property not found"})})),t&&t.has("properties"))c()(I=t.get("properties")).call(I,((e,t)=>{const o=ke(r[t],e,!1,n,a);s.push(...i()(o).call(o,(e=>({propKey:t,error:e}))))}))}if(E){let t=((e,t)=>{if(!new RegExp(t).test(e))return"Value must follow pattern "+t})(e,E);t&&s.push(t)}if(w&&"array"===d){let t=((e,t)=>{if(!e&&t>=1||e&&e.length{if(e&&e.length>t)return`Array must not contain more then ${t} item${1===t?"":"s"}`})(e,b);t&&s.push({needRemove:!0,error:t})}if(y&&"array"===d){let t=((e,t)=>{if(e&&("true"===t||!0===t)){const t=(0,M.fromJS)(e),r=t.toSet();if(e.length>r.size){let e=(0,M.Set)();if(c()(t).call(t,((r,n)=>{f()(t).call(t,(e=>ge(e.equals)?e.equals(r):e===r)).size>1&&(e=e.add(n))})),0!==e.size)return i()(e).call(e,(e=>({index:e,error:"No duplicates allowed."}))).toArray()}}})(e,y);t&&s.push(...t)}if(g||0===g){let t=((e,t)=>{if(e.length>t)return`Value must be no longer than ${t} character${1!==t?"s":""}`})(e,g);t&&s.push(t)}if(v){let t=((e,t)=>{if(e.length{if(e>t)return`Value must be less than ${t}`})(e,p);t&&s.push(t)}if(h||0===h){let t=((e,t)=>{if(e{if(isNaN(Date.parse(e)))return"Value must be a DateTime"})(e):"uuid"===m?(e=>{if(e=e.toString().toLowerCase(),!/^[{(]?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}[)}]?$/.test(e))return"Value must be a Guid"})(e):(e=>{if(e&&"string"!=typeof e)return"Value must be a string"})(e),!t)return s;s.push(t)}else if("boolean"===d){let t=(e=>{if("true"!==e&&"false"!==e&&!0!==e&&!1!==e)return"Value must be a boolean"})(e);if(!t)return s;s.push(t)}else if("number"===d){let t=(e=>{if(!/^-?\d+(\.?\d+)?$/.test(e))return"Value must be a number"})(e);if(!t)return s;s.push(t)}else if("integer"===d){let t=(e=>{if(!/^-?\d+$/.test(e))return"Value must be an integer"})(e);if(!t)return s;s.push(t)}else if("array"===d){if(!k&&!C)return s;e&&c()(e).call(e,((e,r)=>{const o=ke(e,t.get("items"),!1,n,a);s.push(...i()(o).call(o,(e=>({index:r,error:e}))))}))}else if("file"===d){let t=(e=>{if(e&&!(e instanceof X.Z.File))return"Value must be a file"})(e);if(!t)return s;s.push(t)}return s}const Ce=function(e,t){let{isOAS3:r=!1,bypassRequiredCheck:n=!1}=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=e.get("required"),{schema:a,parameterContentMediaType:i}=(0,re.Z)(e,{isOAS3:r});return ke(t,a,o,n,i)},Oe=(e,t,r)=>{if(e&&(!e.xml||!e.xml.name)){if(e.xml=e.xml||{},!e.$$ref)return e.type||e.items||e.properties||e.additionalProperties?'\n\x3c!-- XML example cannot be generated; root element name is undefined --\x3e':null;{let t=e.$$ref.match(/\S*\/(\S+)$/);e.xml.name=t[1]}}return(0,Q.memoizedCreateXMLExample)(e,t,r)},je=[{when:/json/,shouldStringifyTypes:["string"]}],Ie=["object"],Ne=(e,t,r,n)=>{const o=(0,Q.memoizedSampleFromSchema)(e,t,n),a=typeof o,i=g()(je).call(je,((e,t)=>t.when.test(r)?[...e,...t.shouldStringifyTypes]:e),Ie);return J()(i,(e=>e===a))?k()(o,null,2):o},Te=(e,t,r,n)=>{const o=Ne(e,t,r,n);let a;try{a=se.ZP.dump(se.ZP.load(o),{lineWidth:-1},{schema:se.A8}),"\n"===a[a.length-1]&&(a=x()(a).call(a,0,a.length-1))}catch(e){return console.error(e),"error: could not generate yaml example"}return a.replace(/\t/g," ")},Pe=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:void 0;return e&&ge(e.toJS)&&(e=e.toJS()),n&&ge(n.toJS)&&(n=n.toJS()),/xml/.test(t)?Oe(e,r,n):/(yaml|yml)/.test(t)?Te(e,r,t,n):Ne(e,r,t,n)},Re=()=>{let e={},t=X.Z.location.search;if(!t)return{};if(""!=t){let r=t.substr(1).split("&");for(let t in r)Object.prototype.hasOwnProperty.call(r,t)&&(t=r[t].split("="),e[decodeURIComponent(t[0])]=t[1]&&decodeURIComponent(t[1])||"")}return e},Me=e=>{let t;return t=e instanceof le?e:le.from(e.toString(),"utf-8"),t.toString("base64")},De={operationsSorter:{alpha:(e,t)=>e.get("path").localeCompare(t.get("path")),method:(e,t)=>e.get("method").localeCompare(t.get("method"))},tagsSorter:{alpha:(e,t)=>e.localeCompare(t)}},Le=e=>{let t=[];for(let r in e){let n=e[r];void 0!==n&&""!==n&&t.push([r,"=",encodeURIComponent(n).replace(/%20/g,"+")].join(""))}return t.join("&")},Be=(e,t,r)=>!!W()(r,(r=>G()(e[r],t[r])));function Fe(e){return"string"!=typeof e||""===e?"":(0,L.N)(e)}function ze(e){return!(!e||O()(e).call(e,"localhost")>=0||O()(e).call(e,"127.0.0.1")>=0||"none"===e)}function Ue(e){if(!D().OrderedMap.isOrderedMap(e))return null;if(!e.size)return null;const t=I()(e).call(e,((e,t)=>T()(t).call(t,"2")&&d()(e.get("content")||{}).length>0)),r=e.get("default")||D().OrderedMap(),n=(r.get("content")||D().OrderedMap()).keySeq().toJS().length?r:null;return t||n}const qe=e=>"string"==typeof e||e instanceof String?R()(e).call(e).replace(/\s/g,"%20"):"",Ve=e=>te()(qe(e).replace(/%20/g,"_")),$e=e=>f()(e).call(e,((e,t)=>/^x-/.test(t))),We=e=>f()(e).call(e,((e,t)=>/^pattern|maxLength|minLength|maximum|minimum/.test(t)));function He(e,t){var r;let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:()=>!0;if("object"!=typeof e||o()(e)||null===e||!t)return e;const a=y()({},e);return c()(r=d()(a)).call(r,(e=>{e===t&&n(a[e],e)?delete a[e]:a[e]=He(a[e],t,n)})),a}function Je(e){if("string"==typeof e)return e;if(e&&e.toJS&&(e=e.toJS()),"object"==typeof e&&null!==e)try{return k()(e,null,2)}catch(t){return String(e)}return null==e?"":e.toString()}function Ke(e){return"number"==typeof e?e.toString():e}function Ge(e){let{returnAll:t=!1,allowHashes:r=!0}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!D().Map.isMap(e))throw new Error("paramToIdentifier: received a non-Im.Map parameter as input");const n=e.get("name"),o=e.get("in");let a=[];return e&&e.hashCode&&o&&n&&r&&a.push(`${o}.${n}.hash-${e.hashCode()}`),o&&n&&a.push(`${o}.${n}`),a.push(n),t?a:a[0]||""}function Ze(e,t){var r;const n=Ge(e,{returnAll:!0});return f()(r=i()(n).call(n,(e=>t[e]))).call(r,(e=>void 0!==e))[0]}function Ye(){return Xe(oe()(32).toString("base64"))}function Qe(e){return Xe(ie()("sha256").update(e).digest("base64"))}function Xe(e){return e.replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}const et=e=>!e||!(!ce(e)||!e.isEmpty())},2518:(e,t,r)=>{"use strict";function n(e){return function(e){try{return!!JSON.parse(e)}catch(e){return null}}(e)?"json":null}r.d(t,{O:()=>n})},27504:(e,t,r)=>{"use strict";r.d(t,{Z:()=>n});const n=function(){var e={location:{},history:{},open:()=>{},close:()=>{},File:function(){}};if("undefined"==typeof window)return e;try{e=window;for(var t of["File","Blob","FormData"])t in window&&(e[t]=window[t])}catch(e){console.error(e)}return e}()},19069:(e,t,r)=>{"use strict";r.d(t,{Z:()=>c});var n=r(14418),o=r.n(n),a=r(58118),i=r.n(a),s=r(43393),l=r.n(s);const u=l().Set.of("type","format","items","default","maximum","exclusiveMaximum","minimum","exclusiveMinimum","maxLength","minLength","pattern","maxItems","minItems","uniqueItems","enum","multipleOf");function c(e){let{isOAS3:t}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!l().Map.isMap(e))return{schema:l().Map(),parameterContentMediaType:null};if(!t)return"body"===e.get("in")?{schema:e.get("schema",l().Map()),parameterContentMediaType:null}:{schema:o()(e).call(e,((e,t)=>i()(u).call(u,t))),parameterContentMediaType:null};if(e.get("content")){const t=e.get("content",l().Map({})).keySeq().first();return{schema:e.getIn(["content",t,"schema"],l().Map()),parameterContentMediaType:t}}return{schema:e.get("schema",l().Map()),parameterContentMediaType:null}}},60314:(e,t,r)=>{"use strict";r.d(t,{Z:()=>x});var n=r(58309),o=r.n(n),a=r(2250),i=r.n(a),s=r(25110),l=r.n(s),u=r(8712),c=r.n(u),p=r(51679),f=r.n(p),h=r(12373),d=r.n(h),m=r(18492),g=r.n(m),v=r(88306),y=r.n(v);const b=e=>t=>o()(e)&&o()(t)&&e.length===t.length&&i()(e).call(e,((e,r)=>e===t[r])),w=function(){for(var e=arguments.length,t=new Array(e),r=0;r1&&void 0!==arguments[1]?arguments[1]:w;const{Cache:r}=y();y().Cache=E;const n=y()(e,t);return y().Cache=r,n}},79742:(e,t)=>{"use strict";t.byteLength=function(e){var t=l(e),r=t[0],n=t[1];return 3*(r+n)/4-n},t.toByteArray=function(e){var t,r,a=l(e),i=a[0],s=a[1],u=new o(function(e,t,r){return 3*(t+r)/4-r}(0,i,s)),c=0,p=s>0?i-4:i;for(r=0;r>16&255,u[c++]=t>>8&255,u[c++]=255&t;2===s&&(t=n[e.charCodeAt(r)]<<2|n[e.charCodeAt(r+1)]>>4,u[c++]=255&t);1===s&&(t=n[e.charCodeAt(r)]<<10|n[e.charCodeAt(r+1)]<<4|n[e.charCodeAt(r+2)]>>2,u[c++]=t>>8&255,u[c++]=255&t);return u},t.fromByteArray=function(e){for(var t,n=e.length,o=n%3,a=[],i=16383,s=0,l=n-o;sl?l:s+i));1===o?(t=e[n-1],a.push(r[t>>2]+r[t<<4&63]+"==")):2===o&&(t=(e[n-2]<<8)+e[n-1],a.push(r[t>>10]+r[t>>4&63]+r[t<<2&63]+"="));return a.join("")};for(var r=[],n=[],o="undefined"!=typeof Uint8Array?Uint8Array:Array,a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",i=0,s=a.length;i0)throw new Error("Invalid string. Length must be a multiple of 4");var r=e.indexOf("=");return-1===r&&(r=t),[r,r===t?0:4-r%4]}function u(e,t,n){for(var o,a,i=[],s=t;s>18&63]+r[a>>12&63]+r[a>>6&63]+r[63&a]);return i.join("")}n["-".charCodeAt(0)]=62,n["_".charCodeAt(0)]=63},48764:(e,t,r)=>{"use strict";const n=r(79742),o=r(80645),a="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;t.Buffer=l,t.SlowBuffer=function(e){+e!=e&&(e=0);return l.alloc(+e)},t.INSPECT_MAX_BYTES=50;const i=2147483647;function s(e){if(e>i)throw new RangeError('The value "'+e+'" is invalid for option "size"');const t=new Uint8Array(e);return Object.setPrototypeOf(t,l.prototype),t}function l(e,t,r){if("number"==typeof e){if("string"==typeof t)throw new TypeError('The "string" argument must be of type string. Received type number');return p(e)}return u(e,t,r)}function u(e,t,r){if("string"==typeof e)return function(e,t){"string"==typeof t&&""!==t||(t="utf8");if(!l.isEncoding(t))throw new TypeError("Unknown encoding: "+t);const r=0|m(e,t);let n=s(r);const o=n.write(e,t);o!==r&&(n=n.slice(0,o));return n}(e,t);if(ArrayBuffer.isView(e))return function(e){if(G(e,Uint8Array)){const t=new Uint8Array(e);return h(t.buffer,t.byteOffset,t.byteLength)}return f(e)}(e);if(null==e)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e);if(G(e,ArrayBuffer)||e&&G(e.buffer,ArrayBuffer))return h(e,t,r);if("undefined"!=typeof SharedArrayBuffer&&(G(e,SharedArrayBuffer)||e&&G(e.buffer,SharedArrayBuffer)))return h(e,t,r);if("number"==typeof e)throw new TypeError('The "value" argument must not be of type number. Received type number');const n=e.valueOf&&e.valueOf();if(null!=n&&n!==e)return l.from(n,t,r);const o=function(e){if(l.isBuffer(e)){const t=0|d(e.length),r=s(t);return 0===r.length||e.copy(r,0,0,t),r}if(void 0!==e.length)return"number"!=typeof e.length||Z(e.length)?s(0):f(e);if("Buffer"===e.type&&Array.isArray(e.data))return f(e.data)}(e);if(o)return o;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof e[Symbol.toPrimitive])return l.from(e[Symbol.toPrimitive]("string"),t,r);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e)}function c(e){if("number"!=typeof e)throw new TypeError('"size" argument must be of type number');if(e<0)throw new RangeError('The value "'+e+'" is invalid for option "size"')}function p(e){return c(e),s(e<0?0:0|d(e))}function f(e){const t=e.length<0?0:0|d(e.length),r=s(t);for(let n=0;n=i)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+i.toString(16)+" bytes");return 0|e}function m(e,t){if(l.isBuffer(e))return e.length;if(ArrayBuffer.isView(e)||G(e,ArrayBuffer))return e.byteLength;if("string"!=typeof e)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof e);const r=e.length,n=arguments.length>2&&!0===arguments[2];if(!n&&0===r)return 0;let o=!1;for(;;)switch(t){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":return H(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return J(e).length;default:if(o)return n?-1:H(e).length;t=(""+t).toLowerCase(),o=!0}}function g(e,t,r){let n=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return I(this,t,r);case"utf8":case"utf-8":return k(this,t,r);case"ascii":return O(this,t,r);case"latin1":case"binary":return j(this,t,r);case"base64":return A(this,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return N(this,t,r);default:if(n)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),n=!0}}function v(e,t,r){const n=e[t];e[t]=e[r],e[r]=n}function y(e,t,r,n,o){if(0===e.length)return-1;if("string"==typeof r?(n=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),Z(r=+r)&&(r=o?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(o)return-1;r=e.length-1}else if(r<0){if(!o)return-1;r=0}if("string"==typeof t&&(t=l.from(t,n)),l.isBuffer(t))return 0===t.length?-1:b(e,t,r,n,o);if("number"==typeof t)return t&=255,"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,r):Uint8Array.prototype.lastIndexOf.call(e,t,r):b(e,[t],r,n,o);throw new TypeError("val must be string, number or Buffer")}function b(e,t,r,n,o){let a,i=1,s=e.length,l=t.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(e.length<2||t.length<2)return-1;i=2,s/=2,l/=2,r/=2}function u(e,t){return 1===i?e[t]:e.readUInt16BE(t*i)}if(o){let n=-1;for(a=r;as&&(r=s-l),a=r;a>=0;a--){let r=!0;for(let n=0;no&&(n=o):n=o;const a=t.length;let i;for(n>a/2&&(n=a/2),i=0;i>8,o=r%256,a.push(o),a.push(n);return a}(t,e.length-r),e,r,n)}function A(e,t,r){return 0===t&&r===e.length?n.fromByteArray(e):n.fromByteArray(e.slice(t,r))}function k(e,t,r){r=Math.min(e.length,r);const n=[];let o=t;for(;o239?4:t>223?3:t>191?2:1;if(o+i<=r){let r,n,s,l;switch(i){case 1:t<128&&(a=t);break;case 2:r=e[o+1],128==(192&r)&&(l=(31&t)<<6|63&r,l>127&&(a=l));break;case 3:r=e[o+1],n=e[o+2],128==(192&r)&&128==(192&n)&&(l=(15&t)<<12|(63&r)<<6|63&n,l>2047&&(l<55296||l>57343)&&(a=l));break;case 4:r=e[o+1],n=e[o+2],s=e[o+3],128==(192&r)&&128==(192&n)&&128==(192&s)&&(l=(15&t)<<18|(63&r)<<12|(63&n)<<6|63&s,l>65535&&l<1114112&&(a=l))}}null===a?(a=65533,i=1):a>65535&&(a-=65536,n.push(a>>>10&1023|55296),a=56320|1023&a),n.push(a),o+=i}return function(e){const t=e.length;if(t<=C)return String.fromCharCode.apply(String,e);let r="",n=0;for(;nn.length?(l.isBuffer(t)||(t=l.from(t)),t.copy(n,o)):Uint8Array.prototype.set.call(n,t,o);else{if(!l.isBuffer(t))throw new TypeError('"list" argument must be an Array of Buffers');t.copy(n,o)}o+=t.length}return n},l.byteLength=m,l.prototype._isBuffer=!0,l.prototype.swap16=function(){const e=this.length;if(e%2!=0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let t=0;tr&&(e+=" ... "),""},a&&(l.prototype[a]=l.prototype.inspect),l.prototype.compare=function(e,t,r,n,o){if(G(e,Uint8Array)&&(e=l.from(e,e.offset,e.byteLength)),!l.isBuffer(e))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof e);if(void 0===t&&(t=0),void 0===r&&(r=e?e.length:0),void 0===n&&(n=0),void 0===o&&(o=this.length),t<0||r>e.length||n<0||o>this.length)throw new RangeError("out of range index");if(n>=o&&t>=r)return 0;if(n>=o)return-1;if(t>=r)return 1;if(this===e)return 0;let a=(o>>>=0)-(n>>>=0),i=(r>>>=0)-(t>>>=0);const s=Math.min(a,i),u=this.slice(n,o),c=e.slice(t,r);for(let e=0;e>>=0,isFinite(r)?(r>>>=0,void 0===n&&(n="utf8")):(n=r,r=void 0)}const o=this.length-t;if((void 0===r||r>o)&&(r=o),e.length>0&&(r<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");n||(n="utf8");let a=!1;for(;;)switch(n){case"hex":return w(this,e,t,r);case"utf8":case"utf-8":return E(this,e,t,r);case"ascii":case"latin1":case"binary":return x(this,e,t,r);case"base64":return _(this,e,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return S(this,e,t,r);default:if(a)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),a=!0}},l.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};const C=4096;function O(e,t,r){let n="";r=Math.min(e.length,r);for(let o=t;on)&&(r=n);let o="";for(let n=t;nr)throw new RangeError("Trying to access beyond buffer length")}function P(e,t,r,n,o,a){if(!l.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function R(e,t,r,n,o){q(t,n,o,e,r,7);let a=Number(t&BigInt(4294967295));e[r++]=a,a>>=8,e[r++]=a,a>>=8,e[r++]=a,a>>=8,e[r++]=a;let i=Number(t>>BigInt(32)&BigInt(4294967295));return e[r++]=i,i>>=8,e[r++]=i,i>>=8,e[r++]=i,i>>=8,e[r++]=i,r}function M(e,t,r,n,o){q(t,n,o,e,r,7);let a=Number(t&BigInt(4294967295));e[r+7]=a,a>>=8,e[r+6]=a,a>>=8,e[r+5]=a,a>>=8,e[r+4]=a;let i=Number(t>>BigInt(32)&BigInt(4294967295));return e[r+3]=i,i>>=8,e[r+2]=i,i>>=8,e[r+1]=i,i>>=8,e[r]=i,r+8}function D(e,t,r,n,o,a){if(r+n>e.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function L(e,t,r,n,a){return t=+t,r>>>=0,a||D(e,0,r,4),o.write(e,t,r,n,23,4),r+4}function B(e,t,r,n,a){return t=+t,r>>>=0,a||D(e,0,r,8),o.write(e,t,r,n,52,8),r+8}l.prototype.slice=function(e,t){const r=this.length;(e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(t=void 0===t?r:~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),t>>=0,t>>>=0,r||T(e,t,this.length);let n=this[e],o=1,a=0;for(;++a>>=0,t>>>=0,r||T(e,t,this.length);let n=this[e+--t],o=1;for(;t>0&&(o*=256);)n+=this[e+--t]*o;return n},l.prototype.readUint8=l.prototype.readUInt8=function(e,t){return e>>>=0,t||T(e,1,this.length),this[e]},l.prototype.readUint16LE=l.prototype.readUInt16LE=function(e,t){return e>>>=0,t||T(e,2,this.length),this[e]|this[e+1]<<8},l.prototype.readUint16BE=l.prototype.readUInt16BE=function(e,t){return e>>>=0,t||T(e,2,this.length),this[e]<<8|this[e+1]},l.prototype.readUint32LE=l.prototype.readUInt32LE=function(e,t){return e>>>=0,t||T(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},l.prototype.readUint32BE=l.prototype.readUInt32BE=function(e,t){return e>>>=0,t||T(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},l.prototype.readBigUInt64LE=Q((function(e){V(e>>>=0,"offset");const t=this[e],r=this[e+7];void 0!==t&&void 0!==r||$(e,this.length-8);const n=t+256*this[++e]+65536*this[++e]+this[++e]*2**24,o=this[++e]+256*this[++e]+65536*this[++e]+r*2**24;return BigInt(n)+(BigInt(o)<>>=0,"offset");const t=this[e],r=this[e+7];void 0!==t&&void 0!==r||$(e,this.length-8);const n=t*2**24+65536*this[++e]+256*this[++e]+this[++e],o=this[++e]*2**24+65536*this[++e]+256*this[++e]+r;return(BigInt(n)<>>=0,t>>>=0,r||T(e,t,this.length);let n=this[e],o=1,a=0;for(;++a=o&&(n-=Math.pow(2,8*t)),n},l.prototype.readIntBE=function(e,t,r){e>>>=0,t>>>=0,r||T(e,t,this.length);let n=t,o=1,a=this[e+--n];for(;n>0&&(o*=256);)a+=this[e+--n]*o;return o*=128,a>=o&&(a-=Math.pow(2,8*t)),a},l.prototype.readInt8=function(e,t){return e>>>=0,t||T(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},l.prototype.readInt16LE=function(e,t){e>>>=0,t||T(e,2,this.length);const r=this[e]|this[e+1]<<8;return 32768&r?4294901760|r:r},l.prototype.readInt16BE=function(e,t){e>>>=0,t||T(e,2,this.length);const r=this[e+1]|this[e]<<8;return 32768&r?4294901760|r:r},l.prototype.readInt32LE=function(e,t){return e>>>=0,t||T(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},l.prototype.readInt32BE=function(e,t){return e>>>=0,t||T(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},l.prototype.readBigInt64LE=Q((function(e){V(e>>>=0,"offset");const t=this[e],r=this[e+7];void 0!==t&&void 0!==r||$(e,this.length-8);const n=this[e+4]+256*this[e+5]+65536*this[e+6]+(r<<24);return(BigInt(n)<>>=0,"offset");const t=this[e],r=this[e+7];void 0!==t&&void 0!==r||$(e,this.length-8);const n=(t<<24)+65536*this[++e]+256*this[++e]+this[++e];return(BigInt(n)<>>=0,t||T(e,4,this.length),o.read(this,e,!0,23,4)},l.prototype.readFloatBE=function(e,t){return e>>>=0,t||T(e,4,this.length),o.read(this,e,!1,23,4)},l.prototype.readDoubleLE=function(e,t){return e>>>=0,t||T(e,8,this.length),o.read(this,e,!0,52,8)},l.prototype.readDoubleBE=function(e,t){return e>>>=0,t||T(e,8,this.length),o.read(this,e,!1,52,8)},l.prototype.writeUintLE=l.prototype.writeUIntLE=function(e,t,r,n){if(e=+e,t>>>=0,r>>>=0,!n){P(this,e,t,r,Math.pow(2,8*r)-1,0)}let o=1,a=0;for(this[t]=255&e;++a>>=0,r>>>=0,!n){P(this,e,t,r,Math.pow(2,8*r)-1,0)}let o=r-1,a=1;for(this[t+o]=255&e;--o>=0&&(a*=256);)this[t+o]=e/a&255;return t+r},l.prototype.writeUint8=l.prototype.writeUInt8=function(e,t,r){return e=+e,t>>>=0,r||P(this,e,t,1,255,0),this[t]=255&e,t+1},l.prototype.writeUint16LE=l.prototype.writeUInt16LE=function(e,t,r){return e=+e,t>>>=0,r||P(this,e,t,2,65535,0),this[t]=255&e,this[t+1]=e>>>8,t+2},l.prototype.writeUint16BE=l.prototype.writeUInt16BE=function(e,t,r){return e=+e,t>>>=0,r||P(this,e,t,2,65535,0),this[t]=e>>>8,this[t+1]=255&e,t+2},l.prototype.writeUint32LE=l.prototype.writeUInt32LE=function(e,t,r){return e=+e,t>>>=0,r||P(this,e,t,4,4294967295,0),this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e,t+4},l.prototype.writeUint32BE=l.prototype.writeUInt32BE=function(e,t,r){return e=+e,t>>>=0,r||P(this,e,t,4,4294967295,0),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},l.prototype.writeBigUInt64LE=Q((function(e,t=0){return R(this,e,t,BigInt(0),BigInt("0xffffffffffffffff"))})),l.prototype.writeBigUInt64BE=Q((function(e,t=0){return M(this,e,t,BigInt(0),BigInt("0xffffffffffffffff"))})),l.prototype.writeIntLE=function(e,t,r,n){if(e=+e,t>>>=0,!n){const n=Math.pow(2,8*r-1);P(this,e,t,r,n-1,-n)}let o=0,a=1,i=0;for(this[t]=255&e;++o>0)-i&255;return t+r},l.prototype.writeIntBE=function(e,t,r,n){if(e=+e,t>>>=0,!n){const n=Math.pow(2,8*r-1);P(this,e,t,r,n-1,-n)}let o=r-1,a=1,i=0;for(this[t+o]=255&e;--o>=0&&(a*=256);)e<0&&0===i&&0!==this[t+o+1]&&(i=1),this[t+o]=(e/a>>0)-i&255;return t+r},l.prototype.writeInt8=function(e,t,r){return e=+e,t>>>=0,r||P(this,e,t,1,127,-128),e<0&&(e=255+e+1),this[t]=255&e,t+1},l.prototype.writeInt16LE=function(e,t,r){return e=+e,t>>>=0,r||P(this,e,t,2,32767,-32768),this[t]=255&e,this[t+1]=e>>>8,t+2},l.prototype.writeInt16BE=function(e,t,r){return e=+e,t>>>=0,r||P(this,e,t,2,32767,-32768),this[t]=e>>>8,this[t+1]=255&e,t+2},l.prototype.writeInt32LE=function(e,t,r){return e=+e,t>>>=0,r||P(this,e,t,4,2147483647,-2147483648),this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24,t+4},l.prototype.writeInt32BE=function(e,t,r){return e=+e,t>>>=0,r||P(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},l.prototype.writeBigInt64LE=Q((function(e,t=0){return R(this,e,t,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),l.prototype.writeBigInt64BE=Q((function(e,t=0){return M(this,e,t,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),l.prototype.writeFloatLE=function(e,t,r){return L(this,e,t,!0,r)},l.prototype.writeFloatBE=function(e,t,r){return L(this,e,t,!1,r)},l.prototype.writeDoubleLE=function(e,t,r){return B(this,e,t,!0,r)},l.prototype.writeDoubleBE=function(e,t,r){return B(this,e,t,!1,r)},l.prototype.copy=function(e,t,r,n){if(!l.isBuffer(e))throw new TypeError("argument should be a Buffer");if(r||(r=0),n||0===n||(n=this.length),t>=e.length&&(t=e.length),t||(t=0),n>0&&n=this.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),e.length-t>>=0,r=void 0===r?this.length:r>>>0,e||(e=0),"number"==typeof e)for(o=t;o=n+4;r-=3)t=`_${e.slice(r-3,r)}${t}`;return`${e.slice(0,r)}${t}`}function q(e,t,r,n,o,a){if(e>r||e3?0===t||t===BigInt(0)?`>= 0${n} and < 2${n} ** ${8*(a+1)}${n}`:`>= -(2${n} ** ${8*(a+1)-1}${n}) and < 2 ** ${8*(a+1)-1}${n}`:`>= ${t}${n} and <= ${r}${n}`,new F.ERR_OUT_OF_RANGE("value",o,e)}!function(e,t,r){V(t,"offset"),void 0!==e[t]&&void 0!==e[t+r]||$(t,e.length-(r+1))}(n,o,a)}function V(e,t){if("number"!=typeof e)throw new F.ERR_INVALID_ARG_TYPE(t,"number",e)}function $(e,t,r){if(Math.floor(e)!==e)throw V(e,r),new F.ERR_OUT_OF_RANGE(r||"offset","an integer",e);if(t<0)throw new F.ERR_BUFFER_OUT_OF_BOUNDS;throw new F.ERR_OUT_OF_RANGE(r||"offset",`>= ${r?1:0} and <= ${t}`,e)}z("ERR_BUFFER_OUT_OF_BOUNDS",(function(e){return e?`${e} is outside of buffer bounds`:"Attempt to access memory outside buffer bounds"}),RangeError),z("ERR_INVALID_ARG_TYPE",(function(e,t){return`The "${e}" argument must be of type number. Received type ${typeof t}`}),TypeError),z("ERR_OUT_OF_RANGE",(function(e,t,r){let n=`The value of "${e}" is out of range.`,o=r;return Number.isInteger(r)&&Math.abs(r)>2**32?o=U(String(r)):"bigint"==typeof r&&(o=String(r),(r>BigInt(2)**BigInt(32)||r<-(BigInt(2)**BigInt(32)))&&(o=U(o)),o+="n"),n+=` It must be ${t}. Received ${o}`,n}),RangeError);const W=/[^+/0-9A-Za-z-_]/g;function H(e,t){let r;t=t||1/0;const n=e.length;let o=null;const a=[];for(let i=0;i55295&&r<57344){if(!o){if(r>56319){(t-=3)>-1&&a.push(239,191,189);continue}if(i+1===n){(t-=3)>-1&&a.push(239,191,189);continue}o=r;continue}if(r<56320){(t-=3)>-1&&a.push(239,191,189),o=r;continue}r=65536+(o-55296<<10|r-56320)}else o&&(t-=3)>-1&&a.push(239,191,189);if(o=null,r<128){if((t-=1)<0)break;a.push(r)}else if(r<2048){if((t-=2)<0)break;a.push(r>>6|192,63&r|128)}else if(r<65536){if((t-=3)<0)break;a.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;a.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return a}function J(e){return n.toByteArray(function(e){if((e=(e=e.split("=")[0]).trim().replace(W,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function K(e,t,r,n){let o;for(o=0;o=t.length||o>=e.length);++o)t[o+r]=e[o];return o}function G(e,t){return e instanceof t||null!=e&&null!=e.constructor&&null!=e.constructor.name&&e.constructor.name===t.name}function Z(e){return e!=e}const Y=function(){const e="0123456789abcdef",t=new Array(256);for(let r=0;r<16;++r){const n=16*r;for(let o=0;o<16;++o)t[n+o]=e[r]+e[o]}return t}();function Q(e){return"undefined"==typeof BigInt?X:e}function X(){throw new Error("BigInt not supported")}},21924:(e,t,r)=>{"use strict";var n=r(40210),o=r(55559),a=o(n("String.prototype.indexOf"));e.exports=function(e,t){var r=n(e,!!t);return"function"==typeof r&&a(e,".prototype.")>-1?o(r):r}},55559:(e,t,r)=>{"use strict";var n=r(58612),o=r(40210),a=o("%Function.prototype.apply%"),i=o("%Function.prototype.call%"),s=o("%Reflect.apply%",!0)||n.call(i,a),l=o("%Object.getOwnPropertyDescriptor%",!0),u=o("%Object.defineProperty%",!0),c=o("%Math.max%");if(u)try{u({},"a",{value:1})}catch(e){u=null}e.exports=function(e){var t=s(n,i,arguments);if(l&&u){var r=l(t,"length");r.configurable&&u(t,"length",{value:1+c(0,e.length-(arguments.length-1))})}return t};var p=function(){return s(n,a,arguments)};u?u(e.exports,"apply",{value:p}):e.exports.apply=p},94184:(e,t)=>{var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t{"use strict";var n=r(11742),o={"text/plain":"Text","text/html":"Url",default:"Text"};e.exports=function(e,t){var r,a,i,s,l,u,c=!1;t||(t={}),r=t.debug||!1;try{if(i=n(),s=document.createRange(),l=document.getSelection(),(u=document.createElement("span")).textContent=e,u.style.all="unset",u.style.position="fixed",u.style.top=0,u.style.clip="rect(0, 0, 0, 0)",u.style.whiteSpace="pre",u.style.webkitUserSelect="text",u.style.MozUserSelect="text",u.style.msUserSelect="text",u.style.userSelect="text",u.addEventListener("copy",(function(n){if(n.stopPropagation(),t.format)if(n.preventDefault(),void 0===n.clipboardData){r&&console.warn("unable to use e.clipboardData"),r&&console.warn("trying IE specific stuff"),window.clipboardData.clearData();var a=o[t.format]||o.default;window.clipboardData.setData(a,e)}else n.clipboardData.clearData(),n.clipboardData.setData(t.format,e);t.onCopy&&(n.preventDefault(),t.onCopy(n.clipboardData))})),document.body.appendChild(u),s.selectNodeContents(u),l.addRange(s),!document.execCommand("copy"))throw new Error("copy command was unsuccessful");c=!0}catch(n){r&&console.error("unable to copy using execCommand: ",n),r&&console.warn("trying IE specific stuff");try{window.clipboardData.setData(t.format||"text",e),t.onCopy&&t.onCopy(window.clipboardData),c=!0}catch(n){r&&console.error("unable to copy using clipboardData: ",n),r&&console.error("falling back to prompt"),a=function(e){var t=(/mac os x/i.test(navigator.userAgent)?"⌘":"Ctrl")+"+C";return e.replace(/#{\s*key\s*}/g,t)}("message"in t?t.message:"Copy to clipboard: #{key}, Enter"),window.prompt(a,e)}}finally{l&&("function"==typeof l.removeRange?l.removeRange(s):l.removeAllRanges()),u&&document.body.removeChild(u),i()}return c}},95299:(e,t,r)=>{var n=r(24848);e.exports=n},83450:(e,t,r)=>{var n=r(83363);e.exports=n},66820:(e,t,r)=>{var n=r(56243);e.exports=n},5023:(e,t,r)=>{var n=r(72369);e.exports=n},90093:(e,t,r)=>{var n=r(28196);e.exports=n},3688:(e,t,r)=>{var n=r(11955);e.exports=n},83838:(e,t,r)=>{var n=r(46279);e.exports=n},15684:(e,t,r)=>{var n=r(19373);e.exports=n},99826:(e,t,r)=>{var n=r(28427);e.exports=n},84234:(e,t,r)=>{var n=r(82073);e.exports=n},65362:(e,t,r)=>{var n=r(63383);e.exports=n},32271:(e,t,r)=>{var n=r(14471);e.exports=n},91254:(e,t,r)=>{var n=r(57396);e.exports=n},43536:(e,t,r)=>{var n=r(41910);e.exports=n},37331:(e,t,r)=>{var n=r(79427);e.exports=n},68522:(e,t,r)=>{var n=r(62857);e.exports=n},73151:(e,t,r)=>{var n=r(9534);e.exports=n},99565:(e,t,r)=>{var n=r(96507);e.exports=n},45012:(e,t,r)=>{var n=r(23059);e.exports=n},78690:(e,t,r)=>{var n=r(16670);e.exports=n},25626:(e,t,r)=>{var n=r(27460);e.exports=n},80281:(e,t,r)=>{var n=r(92547);e.exports=n},40031:(e,t,r)=>{var n=r(46509);e.exports=n},54493:(e,t,r)=>{r(77971),r(53242);var n=r(54058);e.exports=n.Array.from},24034:(e,t,r)=>{r(92737);var n=r(54058);e.exports=n.Array.isArray},15367:(e,t,r)=>{r(85906);var n=r(35703);e.exports=n("Array").concat},12710:(e,t,r)=>{r(66274),r(55967);var n=r(35703);e.exports=n("Array").entries},51459:(e,t,r)=>{r(48851);var n=r(35703);e.exports=n("Array").every},6172:(e,t,r)=>{r(80290);var n=r(35703);e.exports=n("Array").fill},62383:(e,t,r)=>{r(21501);var n=r(35703);e.exports=n("Array").filter},60009:(e,t,r)=>{r(44929);var n=r(35703);e.exports=n("Array").findIndex},17671:(e,t,r)=>{r(80833);var n=r(35703);e.exports=n("Array").find},99324:(e,t,r)=>{r(2437);var n=r(35703);e.exports=n("Array").forEach},80991:(e,t,r)=>{r(97690);var n=r(35703);e.exports=n("Array").includes},8700:(e,t,r)=>{r(99076);var n=r(35703);e.exports=n("Array").indexOf},95909:(e,t,r)=>{r(66274),r(55967);var n=r(35703);e.exports=n("Array").keys},6442:(e,t,r)=>{r(75915);var n=r(35703);e.exports=n("Array").lastIndexOf},23866:(e,t,r)=>{r(68787);var n=r(35703);e.exports=n("Array").map},52999:(e,t,r)=>{r(81876);var n=r(35703);e.exports=n("Array").reduce},91876:(e,t,r)=>{r(11490);var n=r(35703);e.exports=n("Array").reverse},24900:(e,t,r)=>{r(60186);var n=r(35703);e.exports=n("Array").slice},3824:(e,t,r)=>{r(36026);var n=r(35703);e.exports=n("Array").some},2948:(e,t,r)=>{r(4115);var n=r(35703);e.exports=n("Array").sort},78209:(e,t,r)=>{r(98611);var n=r(35703);e.exports=n("Array").splice},14423:(e,t,r)=>{r(66274),r(55967);var n=r(35703);e.exports=n("Array").values},81103:(e,t,r)=>{r(95160);var n=r(54058);e.exports=n.Date.now},27700:(e,t,r)=>{r(73381);var n=r(35703);e.exports=n("Function").bind},13830:(e,t,r)=>{r(66274),r(77971);var n=r(22902);e.exports=n},91031:(e,t,r)=>{r(52595),e.exports=r(21899)},16246:(e,t,r)=>{var n=r(7046),o=r(27700),a=Function.prototype;e.exports=function(e){var t=e.bind;return e===a||n(a,e)&&t===a.bind?o:t}},56043:(e,t,r)=>{var n=r(7046),o=r(15367),a=Array.prototype;e.exports=function(e){var t=e.concat;return e===a||n(a,e)&&t===a.concat?o:t}},13160:(e,t,r)=>{var n=r(7046),o=r(51459),a=Array.prototype;e.exports=function(e){var t=e.every;return e===a||n(a,e)&&t===a.every?o:t}},80446:(e,t,r)=>{var n=r(7046),o=r(6172),a=Array.prototype;e.exports=function(e){var t=e.fill;return e===a||n(a,e)&&t===a.fill?o:t}},2480:(e,t,r)=>{var n=r(7046),o=r(62383),a=Array.prototype;e.exports=function(e){var t=e.filter;return e===a||n(a,e)&&t===a.filter?o:t}},7147:(e,t,r)=>{var n=r(7046),o=r(60009),a=Array.prototype;e.exports=function(e){var t=e.findIndex;return e===a||n(a,e)&&t===a.findIndex?o:t}},32236:(e,t,r)=>{var n=r(7046),o=r(17671),a=Array.prototype;e.exports=function(e){var t=e.find;return e===a||n(a,e)&&t===a.find?o:t}},58557:(e,t,r)=>{var n=r(7046),o=r(80991),a=r(21631),i=Array.prototype,s=String.prototype;e.exports=function(e){var t=e.includes;return e===i||n(i,e)&&t===i.includes?o:"string"==typeof e||e===s||n(s,e)&&t===s.includes?a:t}},34570:(e,t,r)=>{var n=r(7046),o=r(8700),a=Array.prototype;e.exports=function(e){var t=e.indexOf;return e===a||n(a,e)&&t===a.indexOf?o:t}},57564:(e,t,r)=>{var n=r(7046),o=r(6442),a=Array.prototype;e.exports=function(e){var t=e.lastIndexOf;return e===a||n(a,e)&&t===a.lastIndexOf?o:t}},88287:(e,t,r)=>{var n=r(7046),o=r(23866),a=Array.prototype;e.exports=function(e){var t=e.map;return e===a||n(a,e)&&t===a.map?o:t}},68025:(e,t,r)=>{var n=r(7046),o=r(52999),a=Array.prototype;e.exports=function(e){var t=e.reduce;return e===a||n(a,e)&&t===a.reduce?o:t}},59257:(e,t,r)=>{var n=r(7046),o=r(80454),a=String.prototype;e.exports=function(e){var t=e.repeat;return"string"==typeof e||e===a||n(a,e)&&t===a.repeat?o:t}},91060:(e,t,r)=>{var n=r(7046),o=r(91876),a=Array.prototype;e.exports=function(e){var t=e.reverse;return e===a||n(a,e)&&t===a.reverse?o:t}},69601:(e,t,r)=>{var n=r(7046),o=r(24900),a=Array.prototype;e.exports=function(e){var t=e.slice;return e===a||n(a,e)&&t===a.slice?o:t}},28299:(e,t,r)=>{var n=r(7046),o=r(3824),a=Array.prototype;e.exports=function(e){var t=e.some;return e===a||n(a,e)&&t===a.some?o:t}},69355:(e,t,r)=>{var n=r(7046),o=r(2948),a=Array.prototype;e.exports=function(e){var t=e.sort;return e===a||n(a,e)&&t===a.sort?o:t}},18339:(e,t,r)=>{var n=r(7046),o=r(78209),a=Array.prototype;e.exports=function(e){var t=e.splice;return e===a||n(a,e)&&t===a.splice?o:t}},71611:(e,t,r)=>{var n=r(7046),o=r(3269),a=String.prototype;e.exports=function(e){var t=e.startsWith;return"string"==typeof e||e===a||n(a,e)&&t===a.startsWith?o:t}},62774:(e,t,r)=>{var n=r(7046),o=r(13348),a=String.prototype;e.exports=function(e){var t=e.trim;return"string"==typeof e||e===a||n(a,e)&&t===a.trim?o:t}},84426:(e,t,r)=>{r(32619);var n=r(54058),o=r(79730);n.JSON||(n.JSON={stringify:JSON.stringify}),e.exports=function(e,t,r){return o(n.JSON.stringify,null,arguments)}},91018:(e,t,r)=>{r(66274),r(37501),r(55967),r(77971);var n=r(54058);e.exports=n.Map},45999:(e,t,r)=>{r(49221);var n=r(54058);e.exports=n.Object.assign},35254:(e,t,r)=>{r(53882);var n=r(54058).Object;e.exports=function(e,t){return n.create(e,t)}},7702:(e,t,r)=>{r(74979);var n=r(54058).Object,o=e.exports=function(e,t){return n.defineProperties(e,t)};n.defineProperties.sham&&(o.sham=!0)},48171:(e,t,r)=>{r(86450);var n=r(54058).Object,o=e.exports=function(e,t,r){return n.defineProperty(e,t,r)};n.defineProperty.sham&&(o.sham=!0)},73081:(e,t,r)=>{r(94366);var n=r(54058);e.exports=n.Object.entries},286:(e,t,r)=>{r(46924);var n=r(54058).Object,o=e.exports=function(e,t){return n.getOwnPropertyDescriptor(e,t)};n.getOwnPropertyDescriptor.sham&&(o.sham=!0)},92766:(e,t,r)=>{r(88482);var n=r(54058);e.exports=n.Object.getOwnPropertyDescriptors},30498:(e,t,r)=>{r(35824);var n=r(54058);e.exports=n.Object.getOwnPropertySymbols},13966:(e,t,r)=>{r(17405);var n=r(54058);e.exports=n.Object.getPrototypeOf},48494:(e,t,r)=>{r(21724);var n=r(54058);e.exports=n.Object.keys},3065:(e,t,r)=>{r(90108);var n=r(54058);e.exports=n.Object.setPrototypeOf},98430:(e,t,r)=>{r(26614);var n=r(54058);e.exports=n.Object.values},52956:(e,t,r)=>{r(47627),r(66274),r(55967),r(98881),r(4560),r(91302),r(44349),r(77971);var n=r(54058);e.exports=n.Promise},21631:(e,t,r)=>{r(11035);var n=r(35703);e.exports=n("String").includes},80454:(e,t,r)=>{r(60986);var n=r(35703);e.exports=n("String").repeat},3269:(e,t,r)=>{r(94761);var n=r(35703);e.exports=n("String").startsWith},13348:(e,t,r)=>{r(57398);var n=r(35703);e.exports=n("String").trim},57473:(e,t,r)=>{r(85906),r(55967),r(35824),r(8555),r(52615),r(21732),r(35903),r(1825),r(28394),r(45915),r(61766),r(62737),r(89911),r(74315),r(63131),r(64714),r(70659),r(69120),r(79413),r(1502);var n=r(54058);e.exports=n.Symbol},24227:(e,t,r)=>{r(66274),r(55967),r(77971),r(1825);var n=r(11477);e.exports=n.f("iterator")},32304:(e,t,r)=>{r(66274),r(55967),r(54334);var n=r(54058);e.exports=n.WeakMap},27385:(e,t,r)=>{var n=r(95299);e.exports=n},81522:(e,t,r)=>{var n=r(83450);e.exports=n},32209:(e,t,r)=>{var n=r(66820);e.exports=n},30888:(e,t,r)=>{r(9668);var n=r(5023);e.exports=n},14122:(e,t,r)=>{var n=r(90093);e.exports=n},44442:(e,t,r)=>{var n=r(3688);e.exports=n},57152:(e,t,r)=>{var n=r(83838);e.exports=n},69447:(e,t,r)=>{var n=r(15684);e.exports=n},17579:(e,t,r)=>{var n=r(99826);e.exports=n},81493:(e,t,r)=>{var n=r(84234);e.exports=n},60269:(e,t,r)=>{var n=r(65362);e.exports=n},76094:(e,t,r)=>{var n=r(32271);e.exports=n},70573:(e,t,r)=>{var n=r(91254);e.exports=n},73685:(e,t,r)=>{var n=r(43536);e.exports=n},27533:(e,t,r)=>{var n=r(37331);e.exports=n},39057:(e,t,r)=>{var n=r(68522);e.exports=n},84710:(e,t,r)=>{var n=r(73151);e.exports=n},74303:(e,t,r)=>{var n=r(99565);e.exports=n},93799:(e,t,r)=>{var n=r(45012);e.exports=n},55122:(e,t,r)=>{var n=r(78690);e.exports=n},29531:(e,t,r)=>{var n=r(25626);r(89731),r(55708),r(30014),r(88731),e.exports=n},86600:(e,t,r)=>{var n=r(80281);r(28783),r(43975),r(65799),r(45414),r(46774),r(80620),r(36172),e.exports=n},9759:(e,t,r)=>{var n=r(40031);e.exports=n},24883:(e,t,r)=>{var n=r(21899),o=r(57475),a=r(69826),i=n.TypeError;e.exports=function(e){if(o(e))return e;throw i(a(e)+" is not a function")}},174:(e,t,r)=>{var n=r(21899),o=r(24284),a=r(69826),i=n.TypeError;e.exports=function(e){if(o(e))return e;throw i(a(e)+" is not a constructor")}},11851:(e,t,r)=>{var n=r(21899),o=r(57475),a=n.String,i=n.TypeError;e.exports=function(e){if("object"==typeof e||o(e))return e;throw i("Can't set "+a(e)+" as a prototype")}},18479:e=>{e.exports=function(){}},5743:(e,t,r)=>{var n=r(21899),o=r(7046),a=n.TypeError;e.exports=function(e,t){if(o(t,e))return e;throw a("Incorrect invocation")}},96059:(e,t,r)=>{var n=r(21899),o=r(10941),a=n.String,i=n.TypeError;e.exports=function(e){if(o(e))return e;throw i(a(e)+" is not an object")}},97135:(e,t,r)=>{var n=r(95981);e.exports=n((function(){if("function"==typeof ArrayBuffer){var e=new ArrayBuffer(8);Object.isExtensible(e)&&Object.defineProperty(e,"a",{value:8})}}))},91860:(e,t,r)=>{"use strict";var n=r(89678),o=r(59413),a=r(10623);e.exports=function(e){for(var t=n(this),r=a(t),i=arguments.length,s=o(i>1?arguments[1]:void 0,r),l=i>2?arguments[2]:void 0,u=void 0===l?r:o(l,r);u>s;)t[s++]=e;return t}},56837:(e,t,r)=>{"use strict";var n=r(3610).forEach,o=r(34194)("forEach");e.exports=o?[].forEach:function(e){return n(this,e,arguments.length>1?arguments[1]:void 0)}},11354:(e,t,r)=>{"use strict";var n=r(21899),o=r(86843),a=r(78834),i=r(89678),s=r(75196),l=r(6782),u=r(24284),c=r(10623),p=r(55449),f=r(53476),h=r(22902),d=n.Array;e.exports=function(e){var t=i(e),r=u(this),n=arguments.length,m=n>1?arguments[1]:void 0,g=void 0!==m;g&&(m=o(m,n>2?arguments[2]:void 0));var v,y,b,w,E,x,_=h(t),S=0;if(!_||this==d&&l(_))for(v=c(t),y=r?new this(v):d(v);v>S;S++)x=g?m(t[S],S):t[S],p(y,S,x);else for(E=(w=f(t,_)).next,y=r?new this:[];!(b=a(E,w)).done;S++)x=g?s(w,m,[b.value,S],!0):b.value,p(y,S,x);return y.length=S,y}},31692:(e,t,r)=>{var n=r(74529),o=r(59413),a=r(10623),i=function(e){return function(t,r,i){var s,l=n(t),u=a(l),c=o(i,u);if(e&&r!=r){for(;u>c;)if((s=l[c++])!=s)return!0}else for(;u>c;c++)if((e||c in l)&&l[c]===r)return e||c||0;return!e&&-1}};e.exports={includes:i(!0),indexOf:i(!1)}},3610:(e,t,r)=>{var n=r(86843),o=r(95329),a=r(37026),i=r(89678),s=r(10623),l=r(64692),u=o([].push),c=function(e){var t=1==e,r=2==e,o=3==e,c=4==e,p=6==e,f=7==e,h=5==e||p;return function(d,m,g,v){for(var y,b,w=i(d),E=a(w),x=n(m,g),_=s(E),S=0,A=v||l,k=t?A(d,_):r||f?A(d,0):void 0;_>S;S++)if((h||S in E)&&(b=x(y=E[S],S,w),e))if(t)k[S]=b;else if(b)switch(e){case 3:return!0;case 5:return y;case 6:return S;case 2:u(k,y)}else switch(e){case 4:return!1;case 7:u(k,y)}return p?-1:o||c?c:k}};e.exports={forEach:c(0),map:c(1),filter:c(2),some:c(3),every:c(4),find:c(5),findIndex:c(6),filterReject:c(7)}},67145:(e,t,r)=>{"use strict";var n=r(79730),o=r(74529),a=r(62435),i=r(10623),s=r(34194),l=Math.min,u=[].lastIndexOf,c=!!u&&1/[1].lastIndexOf(1,-0)<0,p=s("lastIndexOf"),f=c||!p;e.exports=f?function(e){if(c)return n(u,this,arguments)||0;var t=o(this),r=i(t),s=r-1;for(arguments.length>1&&(s=l(s,a(arguments[1]))),s<0&&(s=r+s);s>=0;s--)if(s in t&&t[s]===e)return s||0;return-1}:u},50568:(e,t,r)=>{var n=r(95981),o=r(99813),a=r(53385),i=o("species");e.exports=function(e){return a>=51||!n((function(){var t=[];return(t.constructor={})[i]=function(){return{foo:1}},1!==t[e](Boolean).foo}))}},34194:(e,t,r)=>{"use strict";var n=r(95981);e.exports=function(e,t){var r=[][e];return!!r&&n((function(){r.call(null,t||function(){throw 1},1)}))}},46499:(e,t,r)=>{var n=r(21899),o=r(24883),a=r(89678),i=r(37026),s=r(10623),l=n.TypeError,u=function(e){return function(t,r,n,u){o(r);var c=a(t),p=i(c),f=s(c),h=e?f-1:0,d=e?-1:1;if(n<2)for(;;){if(h in p){u=p[h],h+=d;break}if(h+=d,e?h<0:f<=h)throw l("Reduce of empty array with no initial value")}for(;e?h>=0:f>h;h+=d)h in p&&(u=r(u,p[h],h,c));return u}};e.exports={left:u(!1),right:u(!0)}},15790:(e,t,r)=>{var n=r(21899),o=r(59413),a=r(10623),i=r(55449),s=n.Array,l=Math.max;e.exports=function(e,t,r){for(var n=a(e),u=o(t,n),c=o(void 0===r?n:r,n),p=s(l(c-u,0)),f=0;u{var n=r(95329);e.exports=n([].slice)},61388:(e,t,r)=>{var n=r(15790),o=Math.floor,a=function(e,t){var r=e.length,l=o(r/2);return r<8?i(e,t):s(e,a(n(e,0,l),t),a(n(e,l),t),t)},i=function(e,t){for(var r,n,o=e.length,a=1;a0;)e[n]=e[--n];n!==a++&&(e[n]=r)}return e},s=function(e,t,r,n){for(var o=t.length,a=r.length,i=0,s=0;i{var n=r(21899),o=r(1052),a=r(24284),i=r(10941),s=r(99813)("species"),l=n.Array;e.exports=function(e){var t;return o(e)&&(t=e.constructor,(a(t)&&(t===l||o(t.prototype))||i(t)&&null===(t=t[s]))&&(t=void 0)),void 0===t?l:t}},64692:(e,t,r)=>{var n=r(5693);e.exports=function(e,t){return new(n(e))(0===t?0:t)}},75196:(e,t,r)=>{var n=r(96059),o=r(7609);e.exports=function(e,t,r,a){try{return a?t(n(r)[0],r[1]):t(r)}catch(t){o(e,"throw",t)}}},21385:(e,t,r)=>{var n=r(99813)("iterator"),o=!1;try{var a=0,i={next:function(){return{done:!!a++}},return:function(){o=!0}};i[n]=function(){return this},Array.from(i,(function(){throw 2}))}catch(e){}e.exports=function(e,t){if(!t&&!o)return!1;var r=!1;try{var a={};a[n]=function(){return{next:function(){return{done:r=!0}}}},e(a)}catch(e){}return r}},82532:(e,t,r)=>{var n=r(95329),o=n({}.toString),a=n("".slice);e.exports=function(e){return a(o(e),8,-1)}},9697:(e,t,r)=>{var n=r(21899),o=r(22885),a=r(57475),i=r(82532),s=r(99813)("toStringTag"),l=n.Object,u="Arguments"==i(function(){return arguments}());e.exports=o?i:function(e){var t,r,n;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(r=function(e,t){try{return e[t]}catch(e){}}(t=l(e),s))?r:u?i(t):"Object"==(n=i(t))&&a(t.callee)?"Arguments":n}},38694:(e,t,r)=>{var n=r(95329)("".replace),o=String(Error("zxcasd").stack),a=/\n\s*at [^:]*:[^\n]*/,i=a.test(o);e.exports=function(e,t){if(i&&"string"==typeof e)for(;t--;)e=n(e,a,"");return e}},85616:(e,t,r)=>{"use strict";var n=r(65988).f,o=r(29290),a=r(87524),i=r(86843),s=r(5743),l=r(93091),u=r(47771),c=r(94431),p=r(55746),f=r(21647).fastKey,h=r(45402),d=h.set,m=h.getterFor;e.exports={getConstructor:function(e,t,r,u){var c=e((function(e,n){s(e,h),d(e,{type:t,index:o(null),first:void 0,last:void 0,size:0}),p||(e.size=0),null!=n&&l(n,e[u],{that:e,AS_ENTRIES:r})})),h=c.prototype,g=m(t),v=function(e,t,r){var n,o,a=g(e),i=y(e,t);return i?i.value=r:(a.last=i={index:o=f(t,!0),key:t,value:r,previous:n=a.last,next:void 0,removed:!1},a.first||(a.first=i),n&&(n.next=i),p?a.size++:e.size++,"F"!==o&&(a.index[o]=i)),e},y=function(e,t){var r,n=g(e),o=f(t);if("F"!==o)return n.index[o];for(r=n.first;r;r=r.next)if(r.key==t)return r};return a(h,{clear:function(){for(var e=g(this),t=e.index,r=e.first;r;)r.removed=!0,r.previous&&(r.previous=r.previous.next=void 0),delete t[r.index],r=r.next;e.first=e.last=void 0,p?e.size=0:this.size=0},delete:function(e){var t=this,r=g(t),n=y(t,e);if(n){var o=n.next,a=n.previous;delete r.index[n.index],n.removed=!0,a&&(a.next=o),o&&(o.previous=a),r.first==n&&(r.first=o),r.last==n&&(r.last=a),p?r.size--:t.size--}return!!n},forEach:function(e){for(var t,r=g(this),n=i(e,arguments.length>1?arguments[1]:void 0);t=t?t.next:r.first;)for(n(t.value,t.key,this);t&&t.removed;)t=t.previous},has:function(e){return!!y(this,e)}}),a(h,r?{get:function(e){var t=y(this,e);return t&&t.value},set:function(e,t){return v(this,0===e?0:e,t)}}:{add:function(e){return v(this,e=0===e?0:e,e)}}),p&&n(h,"size",{get:function(){return g(this).size}}),c},setStrong:function(e,t,r){var n=t+" Iterator",o=m(t),a=m(n);u(e,t,(function(e,t){d(this,{type:n,target:e,state:o(e),kind:t,last:void 0})}),(function(){for(var e=a(this),t=e.kind,r=e.last;r&&r.removed;)r=r.previous;return e.target&&(e.last=r=r?r.next:e.state.first)?"keys"==t?{value:r.key,done:!1}:"values"==t?{value:r.value,done:!1}:{value:[r.key,r.value],done:!1}:(e.target=void 0,{value:void 0,done:!0})}),r?"entries":"values",!r,!0),c(t)}}},8850:(e,t,r)=>{"use strict";var n=r(95329),o=r(87524),a=r(21647).getWeakData,i=r(96059),s=r(10941),l=r(5743),u=r(93091),c=r(3610),p=r(90953),f=r(45402),h=f.set,d=f.getterFor,m=c.find,g=c.findIndex,v=n([].splice),y=0,b=function(e){return e.frozen||(e.frozen=new w)},w=function(){this.entries=[]},E=function(e,t){return m(e.entries,(function(e){return e[0]===t}))};w.prototype={get:function(e){var t=E(this,e);if(t)return t[1]},has:function(e){return!!E(this,e)},set:function(e,t){var r=E(this,e);r?r[1]=t:this.entries.push([e,t])},delete:function(e){var t=g(this.entries,(function(t){return t[0]===e}));return~t&&v(this.entries,t,1),!!~t}},e.exports={getConstructor:function(e,t,r,n){var c=e((function(e,o){l(e,f),h(e,{type:t,id:y++,frozen:void 0}),null!=o&&u(o,e[n],{that:e,AS_ENTRIES:r})})),f=c.prototype,m=d(t),g=function(e,t,r){var n=m(e),o=a(i(t),!0);return!0===o?b(n).set(t,r):o[n.id]=r,e};return o(f,{delete:function(e){var t=m(this);if(!s(e))return!1;var r=a(e);return!0===r?b(t).delete(e):r&&p(r,t.id)&&delete r[t.id]},has:function(e){var t=m(this);if(!s(e))return!1;var r=a(e);return!0===r?b(t).has(e):r&&p(r,t.id)}}),o(f,r?{get:function(e){var t=m(this);if(s(e)){var r=a(e);return!0===r?b(t).get(e):r?r[t.id]:void 0}},set:function(e,t){return g(this,e,t)}}:{add:function(e){return g(this,e,!0)}}),c}}},24683:(e,t,r)=>{"use strict";var n=r(76887),o=r(21899),a=r(21647),i=r(95981),s=r(32029),l=r(93091),u=r(5743),c=r(57475),p=r(10941),f=r(90904),h=r(65988).f,d=r(3610).forEach,m=r(55746),g=r(45402),v=g.set,y=g.getterFor;e.exports=function(e,t,r){var g,b=-1!==e.indexOf("Map"),w=-1!==e.indexOf("Weak"),E=b?"set":"add",x=o[e],_=x&&x.prototype,S={};if(m&&c(x)&&(w||_.forEach&&!i((function(){(new x).entries().next()})))){var A=(g=t((function(t,r){v(u(t,A),{type:e,collection:new x}),null!=r&&l(r,t[E],{that:t,AS_ENTRIES:b})}))).prototype,k=y(e);d(["add","clear","delete","forEach","get","has","set","keys","values","entries"],(function(e){var t="add"==e||"set"==e;!(e in _)||w&&"clear"==e||s(A,e,(function(r,n){var o=k(this).collection;if(!t&&w&&!p(r))return"get"==e&&void 0;var a=o[e](0===r?0:r,n);return t?this:a}))})),w||h(A,"size",{configurable:!0,get:function(){return k(this).collection.size}})}else g=r.getConstructor(t,e,b,E),a.enable();return f(g,e,!1,!0),S[e]=g,n({global:!0,forced:!0},S),w||r.setStrong(g,e,b),g}},23489:(e,t,r)=>{var n=r(90953),o=r(31136),a=r(49677),i=r(65988);e.exports=function(e,t,r){for(var s=o(t),l=i.f,u=a.f,c=0;c{var n=r(99813)("match");e.exports=function(e){var t=/./;try{"/./"[e](t)}catch(r){try{return t[n]=!1,"/./"[e](t)}catch(e){}}return!1}},64160:(e,t,r)=>{var n=r(95981);e.exports=!n((function(){function e(){}return e.prototype.constructor=null,Object.getPrototypeOf(new e)!==e.prototype}))},31046:(e,t,r)=>{"use strict";var n=r(35143).IteratorPrototype,o=r(29290),a=r(31887),i=r(90904),s=r(12077),l=function(){return this};e.exports=function(e,t,r,u){var c=t+" Iterator";return e.prototype=o(n,{next:a(+!u,r)}),i(e,c,!1,!0),s[c]=l,e}},32029:(e,t,r)=>{var n=r(55746),o=r(65988),a=r(31887);e.exports=n?function(e,t,r){return o.f(e,t,a(1,r))}:function(e,t,r){return e[t]=r,e}},31887:e=>{e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},55449:(e,t,r)=>{"use strict";var n=r(83894),o=r(65988),a=r(31887);e.exports=function(e,t,r){var i=n(t);i in e?o.f(e,i,a(0,r)):e[i]=r}},47771:(e,t,r)=>{"use strict";var n=r(76887),o=r(78834),a=r(82529),i=r(79417),s=r(57475),l=r(31046),u=r(249),c=r(88929),p=r(90904),f=r(32029),h=r(99754),d=r(99813),m=r(12077),g=r(35143),v=i.PROPER,y=i.CONFIGURABLE,b=g.IteratorPrototype,w=g.BUGGY_SAFARI_ITERATORS,E=d("iterator"),x="keys",_="values",S="entries",A=function(){return this};e.exports=function(e,t,r,i,d,g,k){l(r,t,i);var C,O,j,I=function(e){if(e===d&&M)return M;if(!w&&e in P)return P[e];switch(e){case x:case _:case S:return function(){return new r(this,e)}}return function(){return new r(this)}},N=t+" Iterator",T=!1,P=e.prototype,R=P[E]||P["@@iterator"]||d&&P[d],M=!w&&R||I(d),D="Array"==t&&P.entries||R;if(D&&(C=u(D.call(new e)))!==Object.prototype&&C.next&&(a||u(C)===b||(c?c(C,b):s(C[E])||h(C,E,A)),p(C,N,!0,!0),a&&(m[N]=A)),v&&d==_&&R&&R.name!==_&&(!a&&y?f(P,"name",_):(T=!0,M=function(){return o(R,this)})),d)if(O={values:I(_),keys:g?M:I(x),entries:I(S)},k)for(j in O)(w||T||!(j in P))&&h(P,j,O[j]);else n({target:t,proto:!0,forced:w||T},O);return a&&!k||P[E]===M||h(P,E,M,{name:d}),m[t]=M,O}},66349:(e,t,r)=>{var n=r(54058),o=r(90953),a=r(11477),i=r(65988).f;e.exports=function(e){var t=n.Symbol||(n.Symbol={});o(t,e)||i(t,e,{value:a.f(e)})}},55746:(e,t,r)=>{var n=r(95981);e.exports=!n((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},61333:(e,t,r)=>{var n=r(21899),o=r(10941),a=n.document,i=o(a)&&o(a.createElement);e.exports=function(e){return i?a.createElement(e):{}}},63281:e=>{e.exports={CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0}},34342:(e,t,r)=>{var n=r(2861).match(/firefox\/(\d+)/i);e.exports=!!n&&+n[1]},23321:e=>{e.exports="object"==typeof window},81046:(e,t,r)=>{var n=r(2861);e.exports=/MSIE|Trident/.test(n)},4470:(e,t,r)=>{var n=r(2861),o=r(21899);e.exports=/ipad|iphone|ipod/i.test(n)&&void 0!==o.Pebble},22749:(e,t,r)=>{var n=r(2861);e.exports=/(?:ipad|iphone|ipod).*applewebkit/i.test(n)},6049:(e,t,r)=>{var n=r(82532),o=r(21899);e.exports="process"==n(o.process)},58045:(e,t,r)=>{var n=r(2861);e.exports=/web0s(?!.*chrome)/i.test(n)},2861:(e,t,r)=>{var n=r(626);e.exports=n("navigator","userAgent")||""},53385:(e,t,r)=>{var n,o,a=r(21899),i=r(2861),s=a.process,l=a.Deno,u=s&&s.versions||l&&l.version,c=u&&u.v8;c&&(o=(n=c.split("."))[0]>0&&n[0]<4?1:+(n[0]+n[1])),!o&&i&&(!(n=i.match(/Edge\/(\d+)/))||n[1]>=74)&&(n=i.match(/Chrome\/(\d+)/))&&(o=+n[1]),e.exports=o},18938:(e,t,r)=>{var n=r(2861).match(/AppleWebKit\/(\d+)\./);e.exports=!!n&&+n[1]},35703:(e,t,r)=>{var n=r(54058);e.exports=function(e){return n[e+"Prototype"]}},56759:e=>{e.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},18780:(e,t,r)=>{var n=r(95981),o=r(31887);e.exports=!n((function(){var e=Error("a");return!("stack"in e)||(Object.defineProperty(e,"stack",o(1,7)),7!==e.stack)}))},76887:(e,t,r)=>{"use strict";var n=r(21899),o=r(79730),a=r(95329),i=r(57475),s=r(49677).f,l=r(37252),u=r(54058),c=r(86843),p=r(32029),f=r(90953),h=function(e){var t=function(r,n,a){if(this instanceof t){switch(arguments.length){case 0:return new e;case 1:return new e(r);case 2:return new e(r,n)}return new e(r,n,a)}return o(e,this,arguments)};return t.prototype=e.prototype,t};e.exports=function(e,t){var r,o,d,m,g,v,y,b,w=e.target,E=e.global,x=e.stat,_=e.proto,S=E?n:x?n[w]:(n[w]||{}).prototype,A=E?u:u[w]||p(u,w,{})[w],k=A.prototype;for(d in t)r=!l(E?d:w+(x?".":"#")+d,e.forced)&&S&&f(S,d),g=A[d],r&&(v=e.noTargetGet?(b=s(S,d))&&b.value:S[d]),m=r&&v?v:t[d],r&&typeof g==typeof m||(y=e.bind&&r?c(m,n):e.wrap&&r?h(m):_&&i(m)?a(m):m,(e.sham||m&&m.sham||g&&g.sham)&&p(y,"sham",!0),p(A,d,y),_&&(f(u,o=w+"Prototype")||p(u,o,{}),p(u[o],d,m),e.real&&k&&!k[d]&&p(k,d,m)))}},95981:e=>{e.exports=function(e){try{return!!e()}catch(e){return!0}}},45602:(e,t,r)=>{var n=r(95981);e.exports=!n((function(){return Object.isExtensible(Object.preventExtensions({}))}))},79730:(e,t,r)=>{var n=r(18285),o=Function.prototype,a=o.apply,i=o.call;e.exports="object"==typeof Reflect&&Reflect.apply||(n?i.bind(a):function(){return i.apply(a,arguments)})},86843:(e,t,r)=>{var n=r(95329),o=r(24883),a=r(18285),i=n(n.bind);e.exports=function(e,t){return o(e),void 0===t?e:a?i(e,t):function(){return e.apply(t,arguments)}}},18285:(e,t,r)=>{var n=r(95981);e.exports=!n((function(){var e=function(){}.bind();return"function"!=typeof e||e.hasOwnProperty("prototype")}))},98308:(e,t,r)=>{"use strict";var n=r(21899),o=r(95329),a=r(24883),i=r(10941),s=r(90953),l=r(93765),u=r(18285),c=n.Function,p=o([].concat),f=o([].join),h={},d=function(e,t,r){if(!s(h,t)){for(var n=[],o=0;o{var n=r(18285),o=Function.prototype.call;e.exports=n?o.bind(o):function(){return o.apply(o,arguments)}},79417:(e,t,r)=>{var n=r(55746),o=r(90953),a=Function.prototype,i=n&&Object.getOwnPropertyDescriptor,s=o(a,"name"),l=s&&"something"===function(){}.name,u=s&&(!n||n&&i(a,"name").configurable);e.exports={EXISTS:s,PROPER:l,CONFIGURABLE:u}},95329:(e,t,r)=>{var n=r(18285),o=Function.prototype,a=o.bind,i=o.call,s=n&&a.bind(i,i);e.exports=n?function(e){return e&&s(e)}:function(e){return e&&function(){return i.apply(e,arguments)}}},626:(e,t,r)=>{var n=r(54058),o=r(21899),a=r(57475),i=function(e){return a(e)?e:void 0};e.exports=function(e,t){return arguments.length<2?i(n[e])||i(o[e]):n[e]&&n[e][t]||o[e]&&o[e][t]}},22902:(e,t,r)=>{var n=r(9697),o=r(14229),a=r(12077),i=r(99813)("iterator");e.exports=function(e){if(null!=e)return o(e,i)||o(e,"@@iterator")||a[n(e)]}},53476:(e,t,r)=>{var n=r(21899),o=r(78834),a=r(24883),i=r(96059),s=r(69826),l=r(22902),u=n.TypeError;e.exports=function(e,t){var r=arguments.length<2?l(e):t;if(a(r))return i(o(r,e));throw u(s(e)+" is not iterable")}},14229:(e,t,r)=>{var n=r(24883);e.exports=function(e,t){var r=e[t];return null==r?void 0:n(r)}},21899:(e,t,r)=>{var n=function(e){return e&&e.Math==Math&&e};e.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof r.g&&r.g)||function(){return this}()||Function("return this")()},90953:(e,t,r)=>{var n=r(95329),o=r(89678),a=n({}.hasOwnProperty);e.exports=Object.hasOwn||function(e,t){return a(o(e),t)}},27748:e=>{e.exports={}},34845:(e,t,r)=>{var n=r(21899);e.exports=function(e,t){var r=n.console;r&&r.error&&(1==arguments.length?r.error(e):r.error(e,t))}},15463:(e,t,r)=>{var n=r(626);e.exports=n("document","documentElement")},2840:(e,t,r)=>{var n=r(55746),o=r(95981),a=r(61333);e.exports=!n&&!o((function(){return 7!=Object.defineProperty(a("div"),"a",{get:function(){return 7}}).a}))},37026:(e,t,r)=>{var n=r(21899),o=r(95329),a=r(95981),i=r(82532),s=n.Object,l=o("".split);e.exports=a((function(){return!s("z").propertyIsEnumerable(0)}))?function(e){return"String"==i(e)?l(e,""):s(e)}:s},81302:(e,t,r)=>{var n=r(95329),o=r(57475),a=r(63030),i=n(Function.toString);o(a.inspectSource)||(a.inspectSource=function(e){return i(e)}),e.exports=a.inspectSource},53794:(e,t,r)=>{var n=r(10941),o=r(32029);e.exports=function(e,t){n(t)&&"cause"in t&&o(e,"cause",t.cause)}},21647:(e,t,r)=>{var n=r(76887),o=r(95329),a=r(27748),i=r(10941),s=r(90953),l=r(65988).f,u=r(10946),c=r(684),p=r(91584),f=r(99418),h=r(45602),d=!1,m=f("meta"),g=0,v=function(e){l(e,m,{value:{objectID:"O"+g++,weakData:{}}})},y=e.exports={enable:function(){y.enable=function(){},d=!0;var e=u.f,t=o([].splice),r={};r[m]=1,e(r).length&&(u.f=function(r){for(var n=e(r),o=0,a=n.length;o{var n,o,a,i=r(38019),s=r(21899),l=r(95329),u=r(10941),c=r(32029),p=r(90953),f=r(63030),h=r(44262),d=r(27748),m="Object already initialized",g=s.TypeError,v=s.WeakMap;if(i||f.state){var y=f.state||(f.state=new v),b=l(y.get),w=l(y.has),E=l(y.set);n=function(e,t){if(w(y,e))throw new g(m);return t.facade=e,E(y,e,t),t},o=function(e){return b(y,e)||{}},a=function(e){return w(y,e)}}else{var x=h("state");d[x]=!0,n=function(e,t){if(p(e,x))throw new g(m);return t.facade=e,c(e,x,t),t},o=function(e){return p(e,x)?e[x]:{}},a=function(e){return p(e,x)}}e.exports={set:n,get:o,has:a,enforce:function(e){return a(e)?o(e):n(e,{})},getterFor:function(e){return function(t){var r;if(!u(t)||(r=o(t)).type!==e)throw g("Incompatible receiver, "+e+" required");return r}}}},6782:(e,t,r)=>{var n=r(99813),o=r(12077),a=n("iterator"),i=Array.prototype;e.exports=function(e){return void 0!==e&&(o.Array===e||i[a]===e)}},1052:(e,t,r)=>{var n=r(82532);e.exports=Array.isArray||function(e){return"Array"==n(e)}},57475:e=>{e.exports=function(e){return"function"==typeof e}},24284:(e,t,r)=>{var n=r(95329),o=r(95981),a=r(57475),i=r(9697),s=r(626),l=r(81302),u=function(){},c=[],p=s("Reflect","construct"),f=/^\s*(?:class|function)\b/,h=n(f.exec),d=!f.exec(u),m=function(e){if(!a(e))return!1;try{return p(u,c,e),!0}catch(e){return!1}},g=function(e){if(!a(e))return!1;switch(i(e)){case"AsyncFunction":case"GeneratorFunction":case"AsyncGeneratorFunction":return!1}try{return d||!!h(f,l(e))}catch(e){return!0}};g.sham=!0,e.exports=!p||o((function(){var e;return m(m.call)||!m(Object)||!m((function(){e=!0}))||e}))?g:m},37252:(e,t,r)=>{var n=r(95981),o=r(57475),a=/#|\.prototype\./,i=function(e,t){var r=l[s(e)];return r==c||r!=u&&(o(t)?n(t):!!t)},s=i.normalize=function(e){return String(e).replace(a,".").toLowerCase()},l=i.data={},u=i.NATIVE="N",c=i.POLYFILL="P";e.exports=i},10941:(e,t,r)=>{var n=r(57475);e.exports=function(e){return"object"==typeof e?null!==e:n(e)}},82529:e=>{e.exports=!0},60685:(e,t,r)=>{var n=r(10941),o=r(82532),a=r(99813)("match");e.exports=function(e){var t;return n(e)&&(void 0!==(t=e[a])?!!t:"RegExp"==o(e))}},56664:(e,t,r)=>{var n=r(21899),o=r(626),a=r(57475),i=r(7046),s=r(32302),l=n.Object;e.exports=s?function(e){return"symbol"==typeof e}:function(e){var t=o("Symbol");return a(t)&&i(t.prototype,l(e))}},93091:(e,t,r)=>{var n=r(21899),o=r(86843),a=r(78834),i=r(96059),s=r(69826),l=r(6782),u=r(10623),c=r(7046),p=r(53476),f=r(22902),h=r(7609),d=n.TypeError,m=function(e,t){this.stopped=e,this.result=t},g=m.prototype;e.exports=function(e,t,r){var n,v,y,b,w,E,x,_=r&&r.that,S=!(!r||!r.AS_ENTRIES),A=!(!r||!r.IS_ITERATOR),k=!(!r||!r.INTERRUPTED),C=o(t,_),O=function(e){return n&&h(n,"normal",e),new m(!0,e)},j=function(e){return S?(i(e),k?C(e[0],e[1],O):C(e[0],e[1])):k?C(e,O):C(e)};if(A)n=e;else{if(!(v=f(e)))throw d(s(e)+" is not iterable");if(l(v)){for(y=0,b=u(e);b>y;y++)if((w=j(e[y]))&&c(g,w))return w;return new m(!1)}n=p(e,v)}for(E=n.next;!(x=a(E,n)).done;){try{w=j(x.value)}catch(e){h(n,"throw",e)}if("object"==typeof w&&w&&c(g,w))return w}return new m(!1)}},7609:(e,t,r)=>{var n=r(78834),o=r(96059),a=r(14229);e.exports=function(e,t,r){var i,s;o(e);try{if(!(i=a(e,"return"))){if("throw"===t)throw r;return r}i=n(i,e)}catch(e){s=!0,i=e}if("throw"===t)throw r;if(s)throw i;return o(i),r}},35143:(e,t,r)=>{"use strict";var n,o,a,i=r(95981),s=r(57475),l=r(29290),u=r(249),c=r(99754),p=r(99813),f=r(82529),h=p("iterator"),d=!1;[].keys&&("next"in(a=[].keys())?(o=u(u(a)))!==Object.prototype&&(n=o):d=!0),null==n||i((function(){var e={};return n[h].call(e)!==e}))?n={}:f&&(n=l(n)),s(n[h])||c(n,h,(function(){return this})),e.exports={IteratorPrototype:n,BUGGY_SAFARI_ITERATORS:d}},12077:e=>{e.exports={}},10623:(e,t,r)=>{var n=r(43057);e.exports=function(e){return n(e.length)}},66132:(e,t,r)=>{var n,o,a,i,s,l,u,c,p=r(21899),f=r(86843),h=r(49677).f,d=r(42941).set,m=r(22749),g=r(4470),v=r(58045),y=r(6049),b=p.MutationObserver||p.WebKitMutationObserver,w=p.document,E=p.process,x=p.Promise,_=h(p,"queueMicrotask"),S=_&&_.value;S||(n=function(){var e,t;for(y&&(e=E.domain)&&e.exit();o;){t=o.fn,o=o.next;try{t()}catch(e){throw o?i():a=void 0,e}}a=void 0,e&&e.enter()},m||y||v||!b||!w?!g&&x&&x.resolve?((u=x.resolve(void 0)).constructor=x,c=f(u.then,u),i=function(){c(n)}):y?i=function(){E.nextTick(n)}:(d=f(d,p),i=function(){d(n)}):(s=!0,l=w.createTextNode(""),new b(n).observe(l,{characterData:!0}),i=function(){l.data=s=!s})),e.exports=S||function(e){var t={fn:e,next:void 0};a&&(a.next=t),o||(o=t,i()),a=t}},19297:(e,t,r)=>{var n=r(21899);e.exports=n.Promise},72497:(e,t,r)=>{var n=r(53385),o=r(95981);e.exports=!!Object.getOwnPropertySymbols&&!o((function(){var e=Symbol();return!String(e)||!(Object(e)instanceof Symbol)||!Symbol.sham&&n&&n<41}))},28468:(e,t,r)=>{var n=r(95981),o=r(99813),a=r(82529),i=o("iterator");e.exports=!n((function(){var e=new URL("b?a=1&b=2&c=3","http://a"),t=e.searchParams,r="";return e.pathname="c%20d",t.forEach((function(e,n){t.delete("b"),r+=n+e})),a&&!e.toJSON||!t.sort||"http://a/c%20d?a=1&c=3"!==e.href||"3"!==t.get("c")||"a=1"!==String(new URLSearchParams("?a=1"))||!t[i]||"a"!==new URL("https://a@b").username||"b"!==new URLSearchParams(new URLSearchParams("a=b")).get("a")||"xn--e1aybc"!==new URL("http://тест").host||"#%D0%B1"!==new URL("http://a#б").hash||"a1c3"!==r||"x"!==new URL("http://x",void 0).host}))},38019:(e,t,r)=>{var n=r(21899),o=r(57475),a=r(81302),i=n.WeakMap;e.exports=o(i)&&/native code/.test(a(i))},69520:(e,t,r)=>{"use strict";var n=r(24883),o=function(e){var t,r;this.promise=new e((function(e,n){if(void 0!==t||void 0!==r)throw TypeError("Bad Promise constructor");t=e,r=n})),this.resolve=n(t),this.reject=n(r)};e.exports.f=function(e){return new o(e)}},14649:(e,t,r)=>{var n=r(85803);e.exports=function(e,t){return void 0===e?arguments.length<2?"":t:n(e)}},70344:(e,t,r)=>{var n=r(21899),o=r(60685),a=n.TypeError;e.exports=function(e){if(o(e))throw a("The method doesn't accept regular expressions");return e}},24420:(e,t,r)=>{"use strict";var n=r(55746),o=r(95329),a=r(78834),i=r(95981),s=r(14771),l=r(87857),u=r(36760),c=r(89678),p=r(37026),f=Object.assign,h=Object.defineProperty,d=o([].concat);e.exports=!f||i((function(){if(n&&1!==f({b:1},f(h({},"a",{enumerable:!0,get:function(){h(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var e={},t={},r=Symbol(),o="abcdefghijklmnopqrst";return e[r]=7,o.split("").forEach((function(e){t[e]=e})),7!=f({},e)[r]||s(f({},t)).join("")!=o}))?function(e,t){for(var r=c(e),o=arguments.length,i=1,f=l.f,h=u.f;o>i;)for(var m,g=p(arguments[i++]),v=f?d(s(g),f(g)):s(g),y=v.length,b=0;y>b;)m=v[b++],n&&!a(h,g,m)||(r[m]=g[m]);return r}:f},29290:(e,t,r)=>{var n,o=r(96059),a=r(59938),i=r(56759),s=r(27748),l=r(15463),u=r(61333),c=r(44262),p=c("IE_PROTO"),f=function(){},h=function(e){return" + + + +
+ + + diff --git a/frontend/index.d.ts b/frontend/index.d.ts new file mode 100644 index 0000000000..e7461e8266 --- /dev/null +++ b/frontend/index.d.ts @@ -0,0 +1 @@ +declare module 'redux-socket.io-middleware'; diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000000..df66231735 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,12 @@ + + + + + + InvokeAI Stable Diffusion Dream Server + + +
+ + + diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000000..fce53f625f --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,46 @@ +{ + "name": "invoke-ai-ui", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "tsc && vite build", + "build-dev": "tsc && vite build -m development", + "preview": "vite preview" + }, + "dependencies": { + "@chakra-ui/icons": "^2.0.10", + "@chakra-ui/react": "^2.3.1", + "@emotion/react": "^11.10.4", + "@emotion/styled": "^11.10.4", + "@reduxjs/toolkit": "^1.8.5", + "@types/uuid": "^8.3.4", + "dateformat": "^5.0.3", + "framer-motion": "^7.2.1", + "lodash": "^4.17.21", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-dropzone": "^14.2.2", + "react-icons": "^4.4.0", + "react-redux": "^8.0.2", + "redux-persist": "^6.0.0", + "socket.io-client": "^4.5.2", + "uuid": "^9.0.0" + }, + "devDependencies": { + "@types/dateformat": "^5.0.0", + "@types/react": "^18.0.17", + "@types/react-dom": "^18.0.6", + "@typescript-eslint/eslint-plugin": "^5.36.2", + "@typescript-eslint/parser": "^5.36.2", + "@vitejs/plugin-react": "^2.0.1", + "eslint": "^8.23.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react-hooks": "^4.6.0", + "tsc-watch": "^5.0.3", + "typescript": "^4.6.4", + "vite": "^3.0.7", + "vite-plugin-eslint": "^1.8.1" + } +} diff --git a/frontend/src/Loading.tsx b/frontend/src/Loading.tsx new file mode 100644 index 0000000000..83dba59fc4 --- /dev/null +++ b/frontend/src/Loading.tsx @@ -0,0 +1,22 @@ +import { Flex, Spinner } from '@chakra-ui/react'; + +const Loading = () => { + return ( + + + + ); +}; + +export default Loading; diff --git a/frontend/src/app/App.tsx b/frontend/src/app/App.tsx new file mode 100644 index 0000000000..354d914b68 --- /dev/null +++ b/frontend/src/app/App.tsx @@ -0,0 +1,69 @@ +import { Grid, GridItem } from '@chakra-ui/react'; +import { useEffect, useState } from 'react'; +import CurrentImageDisplay from '../features/gallery/CurrentImageDisplay'; +import ImageGallery from '../features/gallery/ImageGallery'; +import ProgressBar from '../features/system/ProgressBar'; +import SiteHeader from '../features/system/SiteHeader'; +import OptionsAccordion from '../features/options/OptionsAccordion'; +import ProcessButtons from '../features/options/ProcessButtons'; +import PromptInput from '../features/options/PromptInput'; +import LogViewer from '../features/system/LogViewer'; +import Loading from '../Loading'; +import { useAppDispatch } from './store'; +import { requestAllImages, requestSystemConfig } from './socketio/actions'; + +const App = () => { + const dispatch = useAppDispatch(); + const [isReady, setIsReady] = useState(false); + + // Load images from the gallery once + useEffect(() => { + dispatch(requestAllImages()); + dispatch(requestSystemConfig()); + setIsReady(true); + }, [dispatch]); + + return isReady ? ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + + ) : ( + + ); +}; + +export default App; diff --git a/frontend/src/app/constants.ts b/frontend/src/app/constants.ts new file mode 100644 index 0000000000..3e12201c35 --- /dev/null +++ b/frontend/src/app/constants.ts @@ -0,0 +1,55 @@ +// TODO: use Enums? + +// Valid samplers +export const SAMPLERS: Array = [ + 'ddim', + 'plms', + 'k_lms', + 'k_dpm_2', + 'k_dpm_2_a', + 'k_euler', + 'k_euler_a', + 'k_heun', +]; + +// Valid image widths +export const WIDTHS: Array = [ + 64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, + 1024, +]; + +// Valid image heights +export const HEIGHTS: Array = [ + 64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, + 1024, +]; + +// Valid upscaling levels +export const UPSCALING_LEVELS: Array<{ key: string; value: number }> = [ + { key: '2x', value: 2 }, + { key: '4x', value: 4 }, +]; + +// Internal to human-readable parameters +export const PARAMETERS: { [key: string]: string } = { + prompt: 'Prompt', + iterations: 'Iterations', + steps: 'Steps', + cfgScale: 'CFG Scale', + height: 'Height', + width: 'Width', + sampler: 'Sampler', + seed: 'Seed', + img2imgStrength: 'img2img Strength', + gfpganStrength: 'GFPGAN Strength', + upscalingLevel: 'Upscaling Level', + upscalingStrength: 'Upscaling Strength', + initialImagePath: 'Initial Image', + maskPath: 'Initial Image Mask', + shouldFitToWidthHeight: 'Fit Initial Image', + seamless: 'Seamless Tiling', +}; + +export const NUMPY_RAND_MIN = 0; + +export const NUMPY_RAND_MAX = 4294967295; diff --git a/frontend/src/app/features.ts b/frontend/src/app/features.ts new file mode 100644 index 0000000000..cb8455f09d --- /dev/null +++ b/frontend/src/app/features.ts @@ -0,0 +1,59 @@ +type FeatureHelpInfo = { + text: string; + href: string; + guideImage: string; +}; + +export enum Feature { + PROMPT, + GALLERY, + OUTPUT, + SEED_AND_VARIATION, + ESRGAN, + FACE_CORRECTION, + IMAGE_TO_IMAGE, + SAMPLER, +} + +export const FEATURES: Record = { + [Feature.PROMPT]: { + text: 'This field will take all prompt text, including both content and stylistic terms. CLI Commands will not work in the prompt.', + href: 'link/to/docs/feature3.html', + guideImage: 'asset/path.gif', + }, + [Feature.GALLERY]: { + text: 'As new invocations are generated, files from the output directory will be displayed here. Generations have additional options to configure new generations.', + href: 'link/to/docs/feature3.html', + guideImage: 'asset/path.gif', + }, + [Feature.OUTPUT]: { + text: 'The Height and Width of generations can be controlled here. If you experience errors, you may be generating an image too large for your system. The seamless option will more often result in repeating patterns in outputs.', + href: 'link/to/docs/feature3.html', + guideImage: 'asset/path.gif', + }, + [Feature.SEED_AND_VARIATION]: { + text: 'Seed values provide an initial set of noise which guide the denoising process. Try a variation with an amount of between 0 and 1 to change the output image for that seed.', + href: 'link/to/docs/feature3.html', + guideImage: 'asset/path.gif', + }, + [Feature.ESRGAN]: { + text: 'The ESRGAN setting can be used to increase the output resolution without requiring a higher width/height in the initial generation.', + href: 'link/to/docs/feature1.html', + guideImage: 'asset/path.gif', + }, + [Feature.FACE_CORRECTION]: { + text: 'Using GFPGAN or CodeFormer, Face Correction will attempt to identify faces in outputs, and correct any defects/abnormalities. Higher values will apply a stronger corrective pressure on outputs.', + href: 'link/to/docs/feature2.html', + guideImage: 'asset/path.gif', + }, + [Feature.IMAGE_TO_IMAGE]: { + text: 'ImageToImage allows the upload of an initial image, which InvokeAI will use to guide the generation process, along with a prompt. A lower value for this setting will more closely resemble the original image. Values between 0-1 are accepted, and a range of .25-.75 is recommended ', + href: 'link/to/docs/feature3.html', + guideImage: 'asset/path.gif', + }, + [Feature.SAMPLER]: { + text: 'This setting allows for different denoising samplers to be used, as well as the number of denoising steps used, which will change the resulting output.', + href: 'link/to/docs/feature3.html', + guideImage: 'asset/path.gif', + }, +}; diff --git a/frontend/src/app/invokeai.d.ts b/frontend/src/app/invokeai.d.ts new file mode 100644 index 0000000000..e32f9a0626 --- /dev/null +++ b/frontend/src/app/invokeai.d.ts @@ -0,0 +1,170 @@ +/** + * Types for images, the things they are made of, and the things + * they make up. + * + * Generated images are txt2img and img2img images. They may have + * had additional postprocessing done on them when they were first + * generated. + * + * Postprocessed images are images which were not generated here + * but only postprocessed by the app. They only get postprocessing + * metadata and have a different image type, e.g. 'esrgan' or + * 'gfpgan'. + */ + +/** + * TODO: + * Once an image has been generated, if it is postprocessed again, + * additional postprocessing steps are added to its postprocessing + * array. + * + * TODO: Better documentation of types. + */ + +export declare type PromptItem = { + prompt: string; + weight: number; +}; + +export declare type Prompt = Array; + +export declare type SeedWeightPair = { + seed: number; + weight: number; +}; + +export declare type SeedWeights = Array; + +// All generated images contain these metadata. +export declare type CommonGeneratedImageMetadata = { + postprocessing: null | Array; + sampler: + | 'ddim' + | 'k_dpm_2_a' + | 'k_dpm_2' + | 'k_euler_a' + | 'k_euler' + | 'k_heun' + | 'k_lms' + | 'plms'; + prompt: Prompt; + seed: number; + variations: SeedWeights; + steps: number; + cfg_scale: number; + width: number; + height: number; + seamless: boolean; + extra: null | Record; // Pending development of RFC #266 +}; + +// txt2img and img2img images have some unique attributes. +export declare type Txt2ImgMetadata = GeneratedImageMetadata & { + type: 'txt2img'; +}; + +export declare type Img2ImgMetadata = GeneratedImageMetadata & { + type: 'img2img'; + orig_hash: string; + strength: number; + fit: boolean; + init_image_path: string; + mask_image_path?: string; +}; + +// Superset of generated image metadata types. +export declare type GeneratedImageMetadata = Txt2ImgMetadata | Img2ImgMetadata; + +// All post processed images contain these metadata. +export declare type CommonPostProcessedImageMetadata = { + orig_path: string; + orig_hash: string; +}; + +// esrgan and gfpgan images have some unique attributes. +export declare type ESRGANMetadata = CommonPostProcessedImageMetadata & { + type: 'esrgan'; + scale: 2 | 4; + strength: number; +}; + +export declare type GFPGANMetadata = CommonPostProcessedImageMetadata & { + type: 'gfpgan'; + strength: number; +}; + +// Superset of all postprocessed image metadata types.. +export declare type PostProcessedImageMetadata = + | ESRGANMetadata + | GFPGANMetadata; + +// Metadata includes the system config and image metadata. +export declare type Metadata = SystemConfig & { + image: GeneratedImageMetadata | PostProcessedImageMetadata; +}; + +// An Image has a UUID, url (path?) and Metadata. +export declare type Image = { + uuid: string; + url: string; + metadata: Metadata; +}; + +// GalleryImages is an array of Image. +export declare type GalleryImages = { + images: Array; +}; + +/** + * Types related to the system status. + */ + +// This represents the processing status of the backend. +export declare type SystemStatus = { + isProcessing: boolean; + currentStep: number; + totalSteps: number; + currentIteration: number; + totalIterations: number; + currentStatus: string; + currentStatusHasSteps: boolean; +}; + +export declare type SystemConfig = { + model: string; + model_id: string; + model_hash: string; + app_id: string; + app_version: string; +}; + +/** + * These types type data received from the server via socketio. + */ + +export declare type SystemStatusResponse = SystemStatus; + +export declare type SystemConfigResponse = SystemConfig; + +export declare type ImageResultResponse = { + url: string; + metadata: Metadata; +}; + +export declare type ErrorResponse = { + message: string; + additionalData?: string; +}; + +export declare type GalleryImagesResponse = { + images: Array<{ url: string; metadata: Metadata }>; +}; + +export declare type ImageUrlAndUuidResponse = { + uuid: string; + url: string; +}; + +export declare type ImageUrlResponse = { + url: string; +}; diff --git a/frontend/src/app/socketio/actions.ts b/frontend/src/app/socketio/actions.ts new file mode 100644 index 0000000000..1bb2b0acac --- /dev/null +++ b/frontend/src/app/socketio/actions.ts @@ -0,0 +1,26 @@ +import { createAction } from '@reduxjs/toolkit'; +import * as InvokeAI from '../invokeai'; + +/** + * We can't use redux-toolkit's createSlice() to make these actions, + * because they have no associated reducer. They only exist to dispatch + * requests to the server via socketio. These actions will be handled + * by the middleware. + */ + +export const generateImage = createAction('socketio/generateImage'); +export const runESRGAN = createAction('socketio/runESRGAN'); +export const runGFPGAN = createAction('socketio/runGFPGAN'); +export const deleteImage = createAction('socketio/deleteImage'); +export const requestAllImages = createAction( + 'socketio/requestAllImages' +); +export const cancelProcessing = createAction( + 'socketio/cancelProcessing' +); +export const uploadInitialImage = createAction( + 'socketio/uploadInitialImage' +); +export const uploadMaskImage = createAction('socketio/uploadMaskImage'); + +export const requestSystemConfig = createAction('socketio/requestSystemConfig'); diff --git a/frontend/src/app/socketio/emitters.ts b/frontend/src/app/socketio/emitters.ts new file mode 100644 index 0000000000..64b2d8e659 --- /dev/null +++ b/frontend/src/app/socketio/emitters.ts @@ -0,0 +1,104 @@ +import { AnyAction, Dispatch, MiddlewareAPI } from '@reduxjs/toolkit'; +import dateFormat from 'dateformat'; +import { Socket } from 'socket.io-client'; +import { frontendToBackendParameters } from '../../common/util/parameterTranslation'; +import { + addLogEntry, + setIsProcessing, +} from '../../features/system/systemSlice'; +import * as InvokeAI from '../invokeai'; + +/** + * Returns an object containing all functions which use `socketio.emit()`. + * i.e. those which make server requests. + */ +const makeSocketIOEmitters = ( + store: MiddlewareAPI, any>, + socketio: Socket +) => { + // We need to dispatch actions to redux and get pieces of state from the store. + const { dispatch, getState } = store; + + return { + emitGenerateImage: () => { + dispatch(setIsProcessing(true)); + + const { generationParameters, esrganParameters, gfpganParameters } = + frontendToBackendParameters(getState().options, getState().system); + + socketio.emit( + 'generateImage', + generationParameters, + esrganParameters, + gfpganParameters + ); + + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Image generation requested: ${JSON.stringify({ + ...generationParameters, + ...esrganParameters, + ...gfpganParameters, + })}`, + }) + ); + }, + emitRunESRGAN: (imageToProcess: InvokeAI.Image) => { + dispatch(setIsProcessing(true)); + const { upscalingLevel, upscalingStrength } = getState().options; + const esrganParameters = { + upscale: [upscalingLevel, upscalingStrength], + }; + socketio.emit('runESRGAN', imageToProcess, esrganParameters); + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `ESRGAN upscale requested: ${JSON.stringify({ + file: imageToProcess.url, + ...esrganParameters, + })}`, + }) + ); + }, + emitRunGFPGAN: (imageToProcess: InvokeAI.Image) => { + dispatch(setIsProcessing(true)); + const { gfpganStrength } = getState().options; + + const gfpganParameters = { + gfpgan_strength: gfpganStrength, + }; + socketio.emit('runGFPGAN', imageToProcess, gfpganParameters); + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `GFPGAN fix faces requested: ${JSON.stringify({ + file: imageToProcess.url, + ...gfpganParameters, + })}`, + }) + ); + }, + emitDeleteImage: (imageToDelete: InvokeAI.Image) => { + const { url, uuid } = imageToDelete; + socketio.emit('deleteImage', url, uuid); + }, + emitRequestAllImages: () => { + socketio.emit('requestAllImages'); + }, + emitCancelProcessing: () => { + socketio.emit('cancel'); + }, + emitUploadInitialImage: (file: File) => { + socketio.emit('uploadInitialImage', file, file.name); + }, + emitUploadMaskImage: (file: File) => { + socketio.emit('uploadMaskImage', file, file.name); + }, + emitRequestSystemConfig: () => { + socketio.emit('requestSystemConfig') + } + }; +}; + +export default makeSocketIOEmitters; diff --git a/frontend/src/app/socketio/listeners.ts b/frontend/src/app/socketio/listeners.ts new file mode 100644 index 0000000000..c03317b9b9 --- /dev/null +++ b/frontend/src/app/socketio/listeners.ts @@ -0,0 +1,300 @@ +import { AnyAction, MiddlewareAPI, Dispatch } from '@reduxjs/toolkit'; +import { v4 as uuidv4 } from 'uuid'; +import dateFormat from 'dateformat'; + +import * as InvokeAI from '../invokeai'; + +import { + addLogEntry, + setIsConnected, + setIsProcessing, + setSystemStatus, + setCurrentStatus, + setSystemConfig, +} from '../../features/system/systemSlice'; + +import { + addImage, + clearIntermediateImage, + removeImage, + setGalleryImages, + setIntermediateImage, +} from '../../features/gallery/gallerySlice'; + +import { + setInitialImagePath, + setMaskPath, +} from '../../features/options/optionsSlice'; + +/** + * Returns an object containing listener callbacks for socketio events. + * TODO: This file is large, but simple. Should it be split up further? + */ +const makeSocketIOListeners = ( + store: MiddlewareAPI, any> +) => { + const { dispatch, getState } = store; + + return { + /** + * Callback to run when we receive a 'connect' event. + */ + onConnect: () => { + try { + dispatch(setIsConnected(true)); + dispatch(setCurrentStatus('Connected')); + } catch (e) { + console.error(e); + } + }, + /** + * Callback to run when we receive a 'disconnect' event. + */ + onDisconnect: () => { + try { + dispatch(setIsConnected(false)); + dispatch(setIsProcessing(false)); + dispatch(setCurrentStatus('Disconnected')); + + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Disconnected from server`, + level: 'warning', + }) + ); + } catch (e) { + console.error(e); + } + }, + /** + * Callback to run when we receive a 'generationResult' event. + */ + onGenerationResult: (data: InvokeAI.ImageResultResponse) => { + try { + const { url, metadata } = data; + const newUuid = uuidv4(); + + dispatch( + addImage({ + uuid: newUuid, + url, + metadata: metadata, + }) + ); + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Image generated: ${url}`, + }) + ); + dispatch(setIsProcessing(false)); + } catch (e) { + console.error(e); + } + }, + /** + * Callback to run when we receive a 'intermediateResult' event. + */ + onIntermediateResult: (data: InvokeAI.ImageResultResponse) => { + try { + const uuid = uuidv4(); + const { url, metadata } = data; + dispatch( + setIntermediateImage({ + uuid, + url, + metadata, + }) + ); + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Intermediate image generated: ${url}`, + }) + ); + dispatch(setIsProcessing(false)); + } catch (e) { + console.error(e); + } + }, + /** + * Callback to run when we receive an 'esrganResult' event. + */ + onESRGANResult: (data: InvokeAI.ImageResultResponse) => { + try { + const { url, metadata } = data; + + dispatch( + addImage({ + uuid: uuidv4(), + url, + metadata, + }) + ); + + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Upscaled: ${url}`, + }) + ); + dispatch(setIsProcessing(false)); + } catch (e) { + console.error(e); + } + }, + /** + * Callback to run when we receive a 'gfpganResult' event. + */ + onGFPGANResult: (data: InvokeAI.ImageResultResponse) => { + try { + const { url, metadata } = data; + + dispatch( + addImage({ + uuid: uuidv4(), + url, + metadata, + }) + ); + + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Fixed faces: ${url}`, + }) + ); + } catch (e) { + console.error(e); + } + }, + /** + * Callback to run when we receive a 'progressUpdate' event. + * TODO: Add additional progress phases + */ + onProgressUpdate: (data: InvokeAI.SystemStatus) => { + try { + dispatch(setIsProcessing(true)); + dispatch(setSystemStatus(data)); + } catch (e) { + console.error(e); + } + }, + /** + * Callback to run when we receive a 'progressUpdate' event. + */ + onError: (data: InvokeAI.ErrorResponse) => { + const { message, additionalData } = data; + + if (additionalData) { + // TODO: handle more data than short message + } + + try { + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Server error: ${message}`, + level: 'error', + }) + ); + dispatch(setIsProcessing(false)); + dispatch(clearIntermediateImage()); + } catch (e) { + console.error(e); + } + }, + /** + * Callback to run when we receive a 'galleryImages' event. + */ + onGalleryImages: (data: InvokeAI.GalleryImagesResponse) => { + const { images } = data; + const preparedImages = images.map((image): InvokeAI.Image => { + const { url, metadata } = image; + return { + uuid: uuidv4(), + url, + metadata, + }; + }); + dispatch(setGalleryImages(preparedImages)); + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Loaded ${images.length} images`, + }) + ); + }, + /** + * Callback to run when we receive a 'processingCanceled' event. + */ + onProcessingCanceled: () => { + dispatch(setIsProcessing(false)); + + const { intermediateImage } = getState().gallery; + + if (intermediateImage) { + dispatch(addImage(intermediateImage)); + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Intermediate image saved: ${intermediateImage.url}`, + }) + ); + dispatch(clearIntermediateImage()); + } + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Processing canceled`, + level: 'warning', + }) + ); + }, + /** + * Callback to run when we receive a 'imageDeleted' event. + */ + onImageDeleted: (data: InvokeAI.ImageUrlAndUuidResponse) => { + const { url, uuid } = data; + dispatch(removeImage(uuid)); + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Image deleted: ${url}`, + }) + ); + }, + /** + * Callback to run when we receive a 'initialImageUploaded' event. + */ + onInitialImageUploaded: (data: InvokeAI.ImageUrlResponse) => { + const { url } = data; + dispatch(setInitialImagePath(url)); + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Initial image uploaded: ${url}`, + }) + ); + }, + /** + * Callback to run when we receive a 'maskImageUploaded' event. + */ + onMaskImageUploaded: (data: InvokeAI.ImageUrlResponse) => { + const { url } = data; + dispatch(setMaskPath(url)); + dispatch( + addLogEntry({ + timestamp: dateFormat(new Date(), 'isoDateTime'), + message: `Mask image uploaded: ${url}`, + }) + ); + }, + onSystemConfig: (data: InvokeAI.SystemConfig) => { + dispatch(setSystemConfig(data)); + }, + }; +}; + +export default makeSocketIOListeners; diff --git a/frontend/src/app/socketio/middleware.ts b/frontend/src/app/socketio/middleware.ts new file mode 100644 index 0000000000..e358449b3b --- /dev/null +++ b/frontend/src/app/socketio/middleware.ts @@ -0,0 +1,173 @@ +import { Middleware } from '@reduxjs/toolkit'; +import { io } from 'socket.io-client'; + +import makeSocketIOListeners from './listeners'; +import makeSocketIOEmitters from './emitters'; + +import * as InvokeAI from '../invokeai'; + +/** + * Creates a socketio middleware to handle communication with server. + * + * Special `socketio/actionName` actions are created in actions.ts and + * exported for use by the application, which treats them like any old + * action, using `dispatch` to dispatch them. + * + * These actions are intercepted here, where `socketio.emit()` calls are + * made on their behalf - see `emitters.ts`. The emitter functions + * are the outbound communication to the server. + * + * Listeners are also established here - see `listeners.ts`. The listener + * functions receive communication from the server and usually dispatch + * some new action to handle whatever data was sent from the server. + */ +export const socketioMiddleware = () => { + const { hostname, port } = new URL(window.location.href); + + const socketio = io(`http://${hostname}:9090`); + + let areListenersSet = false; + + const middleware: Middleware = (store) => (next) => (action) => { + const { + onConnect, + onDisconnect, + onError, + onESRGANResult, + onGFPGANResult, + onGenerationResult, + onIntermediateResult, + onProgressUpdate, + onGalleryImages, + onProcessingCanceled, + onImageDeleted, + onInitialImageUploaded, + onMaskImageUploaded, + onSystemConfig, + } = makeSocketIOListeners(store); + + const { + emitGenerateImage, + emitRunESRGAN, + emitRunGFPGAN, + emitDeleteImage, + emitRequestAllImages, + emitCancelProcessing, + emitUploadInitialImage, + emitUploadMaskImage, + emitRequestSystemConfig, + } = makeSocketIOEmitters(store, socketio); + + /** + * If this is the first time the middleware has been called (e.g. during store setup), + * initialize all our socket.io listeners. + */ + if (!areListenersSet) { + socketio.on('connect', () => onConnect()); + + socketio.on('disconnect', () => onDisconnect()); + + socketio.on('error', (data: InvokeAI.ErrorResponse) => onError(data)); + + socketio.on('generationResult', (data: InvokeAI.ImageResultResponse) => + onGenerationResult(data) + ); + + socketio.on('esrganResult', (data: InvokeAI.ImageResultResponse) => + onESRGANResult(data) + ); + + socketio.on('gfpganResult', (data: InvokeAI.ImageResultResponse) => + onGFPGANResult(data) + ); + + socketio.on('intermediateResult', (data: InvokeAI.ImageResultResponse) => + onIntermediateResult(data) + ); + + socketio.on('progressUpdate', (data: InvokeAI.SystemStatus) => + onProgressUpdate(data) + ); + + socketio.on('galleryImages', (data: InvokeAI.GalleryImagesResponse) => + onGalleryImages(data) + ); + + socketio.on('processingCanceled', () => { + onProcessingCanceled(); + }); + + socketio.on('imageDeleted', (data: InvokeAI.ImageUrlAndUuidResponse) => { + onImageDeleted(data); + }); + + socketio.on('initialImageUploaded', (data: InvokeAI.ImageUrlResponse) => { + onInitialImageUploaded(data); + }); + + socketio.on('maskImageUploaded', (data: InvokeAI.ImageUrlResponse) => { + onMaskImageUploaded(data); + }); + + socketio.on('systemConfig', (data: InvokeAI.SystemConfig) => { + onSystemConfig(data); + }); + + areListenersSet = true; + } + + /** + * Handle redux actions caught by middleware. + */ + switch (action.type) { + case 'socketio/generateImage': { + emitGenerateImage(); + break; + } + + case 'socketio/runESRGAN': { + emitRunESRGAN(action.payload); + break; + } + + case 'socketio/runGFPGAN': { + emitRunGFPGAN(action.payload); + break; + } + + case 'socketio/deleteImage': { + emitDeleteImage(action.payload); + break; + } + + case 'socketio/requestAllImages': { + emitRequestAllImages(); + break; + } + + case 'socketio/cancelProcessing': { + emitCancelProcessing(); + break; + } + + case 'socketio/uploadInitialImage': { + emitUploadInitialImage(action.payload); + break; + } + + case 'socketio/uploadMaskImage': { + emitUploadMaskImage(action.payload); + break; + } + + case 'socketio/requestSystemConfig': { + emitRequestSystemConfig(); + break; + } + } + + next(action); + }; + + return middleware; +}; diff --git a/frontend/src/app/store.ts b/frontend/src/app/store.ts new file mode 100644 index 0000000000..e4c583ee53 --- /dev/null +++ b/frontend/src/app/store.ts @@ -0,0 +1,78 @@ +import { combineReducers, configureStore } from '@reduxjs/toolkit'; +import { useDispatch, useSelector } from 'react-redux'; +import type { TypedUseSelectorHook } from 'react-redux'; + +import { persistReducer } from 'redux-persist'; +import storage from 'redux-persist/lib/storage'; // defaults to localStorage for web + +import optionsReducer from '../features/options/optionsSlice'; +import galleryReducer from '../features/gallery/gallerySlice'; +import systemReducer from '../features/system/systemSlice'; +import { socketioMiddleware } from './socketio/middleware'; + +/** + * redux-persist provides an easy and reliable way to persist state across reloads. + * + * While we definitely want generation parameters to be persisted, there are a number + * of things we do *not* want to be persisted across reloads: + * - Gallery/selected image (user may add/delete images from disk between page loads) + * - Connection/processing status + * - Availability of external libraries like ESRGAN/GFPGAN + * + * These can be blacklisted in redux-persist. + * + * The necesssary nested persistors with blacklists are configured below. + * + * TODO: Do we blacklist initialImagePath? If the image is deleted from disk we get an + * ugly 404. But if we blacklist it, then this is a valuable parameter that is lost + * on reload. Need to figure out a good way to handle this. + */ + +const rootPersistConfig = { + key: 'root', + storage, + blacklist: ['gallery', 'system'], +}; + +const systemPersistConfig = { + key: 'system', + storage, + blacklist: [ + 'isConnected', + 'isProcessing', + 'currentStep', + 'socketId', + 'isESRGANAvailable', + 'isGFPGANAvailable', + 'currentStep', + 'totalSteps', + 'currentIteration', + 'totalIterations', + 'currentStatus', + ], +}; + +const reducers = combineReducers({ + options: optionsReducer, + gallery: galleryReducer, + system: persistReducer(systemPersistConfig, systemReducer), +}); + +const persistedReducer = persistReducer(rootPersistConfig, reducers); + +// Continue with store setup +export const store = configureStore({ + reducer: persistedReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + // redux-persist sometimes needs to temporarily put a function in redux state, need to disable this check + serializableCheck: false, + }).concat(socketioMiddleware()), +}); + +export type RootState = ReturnType; +export type AppDispatch = typeof store.dispatch; + +// Use throughout your app instead of plain `useDispatch` and `useSelector` +export const useAppDispatch: () => AppDispatch = useDispatch; +export const useAppSelector: TypedUseSelectorHook = useSelector; diff --git a/frontend/src/app/theme.ts b/frontend/src/app/theme.ts new file mode 100644 index 0000000000..06b28a66ac --- /dev/null +++ b/frontend/src/app/theme.ts @@ -0,0 +1,52 @@ +import { extendTheme } from '@chakra-ui/react'; +import type { StyleFunctionProps } from '@chakra-ui/styled-system'; + +export const theme = extendTheme({ + config: { + initialColorMode: 'dark', + useSystemColorMode: false, + }, + components: { + Tooltip: { + baseStyle: (props: StyleFunctionProps) => ({ + textColor: props.colorMode === 'dark' ? 'gray.800' : 'gray.100', + }), + }, + Accordion: { + baseStyle: (props: StyleFunctionProps) => ({ + button: { + fontWeight: 'bold', + _hover: { + bgColor: + props.colorMode === 'dark' + ? 'rgba(255,255,255,0.05)' + : 'rgba(0,0,0,0.05)', + }, + }, + panel: { + paddingBottom: 2, + }, + }), + }, + FormLabel: { + baseStyle: { + fontWeight: 'light', + }, + }, + Button: { + variants: { + imageHoverIconButton: (props: StyleFunctionProps) => ({ + bg: props.colorMode === 'dark' ? 'blackAlpha.700' : 'whiteAlpha.800', + color: + props.colorMode === 'dark' ? 'whiteAlpha.700' : 'blackAlpha.700', + _hover: { + bg: + props.colorMode === 'dark' ? 'blackAlpha.800' : 'whiteAlpha.800', + color: + props.colorMode === 'dark' ? 'whiteAlpha.900' : 'blackAlpha.900', + }, + }), + }, + }, + }, +}); diff --git a/frontend/src/common/components/GuideIcon.tsx b/frontend/src/common/components/GuideIcon.tsx new file mode 100644 index 0000000000..2f4312ae76 --- /dev/null +++ b/frontend/src/common/components/GuideIcon.tsx @@ -0,0 +1,22 @@ +import { Box, forwardRef, Icon } from '@chakra-ui/react'; +import { IconType } from 'react-icons'; +import { MdHelp } from 'react-icons/md'; +import { Feature } from '../../app/features'; +import GuidePopover from './GuidePopover'; + +type GuideIconProps = { + feature: Feature; + icon?: IconType; +}; + +const GuideIcon = forwardRef( + ({ feature, icon = MdHelp }: GuideIconProps, ref) => ( + + + + + + ) +); + +export default GuideIcon; diff --git a/frontend/src/common/components/GuidePopover.tsx b/frontend/src/common/components/GuidePopover.tsx new file mode 100644 index 0000000000..48a2f8d48f --- /dev/null +++ b/frontend/src/common/components/GuidePopover.tsx @@ -0,0 +1,51 @@ +import { + Popover, + PopoverArrow, + PopoverContent, + PopoverTrigger, + PopoverHeader, + Flex, + Box, +} from '@chakra-ui/react'; +import { SystemState } from '../../features/system/systemSlice'; +import { useAppSelector } from '../../app/store'; +import { RootState } from '../../app/store'; +import { createSelector } from '@reduxjs/toolkit'; +import { ReactElement } from 'react'; +import { Feature, FEATURES } from '../../app/features'; + +type GuideProps = { + children: ReactElement; + feature: Feature; +}; + +const systemSelector = createSelector( + (state: RootState) => state.system, + (system: SystemState) => system.shouldDisplayGuides +); + +const GuidePopover = ({ children, feature }: GuideProps) => { + const shouldDisplayGuides = useAppSelector(systemSelector); + const { text } = FEATURES[feature]; + return shouldDisplayGuides ? ( + + + {children} + + e.preventDefault()} + cursor={'initial'} + > + + + {text} + + + + ) : ( + <> + ); +}; + +export default GuidePopover; diff --git a/frontend/src/common/components/SDButton.tsx b/frontend/src/common/components/SDButton.tsx new file mode 100644 index 0000000000..1107166923 --- /dev/null +++ b/frontend/src/common/components/SDButton.tsx @@ -0,0 +1,21 @@ +import { Button, ButtonProps } from '@chakra-ui/react'; + +interface Props extends ButtonProps { + label: string; +} + +/** + * Reusable customized button component. Originally was more customized - now probably unecessary. + * + * TODO: Get rid of this. + */ +const SDButton = (props: Props) => { + const { label, size = 'sm', ...rest } = props; + return ( + + ); +}; + +export default SDButton; diff --git a/frontend/src/common/components/SDNumberInput.tsx b/frontend/src/common/components/SDNumberInput.tsx new file mode 100644 index 0000000000..d293e109ca --- /dev/null +++ b/frontend/src/common/components/SDNumberInput.tsx @@ -0,0 +1,59 @@ +import { + FormControl, + NumberInput, + NumberInputField, + NumberInputStepper, + NumberIncrementStepper, + NumberDecrementStepper, + Text, + FormLabel, + NumberInputProps, + Flex, +} from '@chakra-ui/react'; + +interface Props extends NumberInputProps { + label?: string; + width?: string | number; +} + +/** + * Customized Chakra FormControl + NumberInput multi-part component. + */ +const SDNumberInput = (props: Props) => { + const { + label, + isDisabled = false, + fontSize = 'md', + size = 'sm', + width, + isInvalid, + ...rest + } = props; + return ( + + + {label && ( + + + {label} + + + )} + + + + + + + + + + ); +}; + +export default SDNumberInput; diff --git a/frontend/src/common/components/SDSelect.tsx b/frontend/src/common/components/SDSelect.tsx new file mode 100644 index 0000000000..09f7c0f040 --- /dev/null +++ b/frontend/src/common/components/SDSelect.tsx @@ -0,0 +1,56 @@ +import { + Flex, + FormControl, + FormLabel, + Select, + SelectProps, + Text, +} from '@chakra-ui/react'; + +interface Props extends SelectProps { + label: string; + validValues: + | Array + | Array<{ key: string; value: string | number }>; +} +/** + * Customized Chakra FormControl + Select multi-part component. + */ +const SDSelect = (props: Props) => { + const { + label, + isDisabled, + validValues, + size = 'sm', + fontSize = 'md', + marginBottom = 1, + whiteSpace = 'nowrap', + ...rest + } = props; + return ( + + + + + {label} + + + + + + ); +}; + +export default SDSelect; diff --git a/frontend/src/common/components/SDSwitch.tsx b/frontend/src/common/components/SDSwitch.tsx new file mode 100644 index 0000000000..32c106041e --- /dev/null +++ b/frontend/src/common/components/SDSwitch.tsx @@ -0,0 +1,45 @@ +import { + Flex, + FormControl, + FormLabel, + Switch, + SwitchProps, +} from '@chakra-ui/react'; + +interface Props extends SwitchProps { + label?: string; + width?: string | number; +} + +/** + * Customized Chakra FormControl + Switch multi-part component. + */ +const SDSwitch = (props: Props) => { + const { + label, + isDisabled = false, + fontSize = 'md', + size = 'md', + width, + ...rest + } = props; + return ( + + + {label && ( + + {label} + + )} + + + + ); +}; + +export default SDSwitch; diff --git a/frontend/src/common/hooks/useCheckParameters.ts b/frontend/src/common/hooks/useCheckParameters.ts new file mode 100644 index 0000000000..7bc87dd0af --- /dev/null +++ b/frontend/src/common/hooks/useCheckParameters.ts @@ -0,0 +1,104 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { isEqual } from 'lodash'; +import { useMemo } from 'react'; +import { useAppSelector } from '../../app/store'; +import { RootState } from '../../app/store'; +import { OptionsState } from '../../features/options/optionsSlice'; +import { SystemState } from '../../features/system/systemSlice'; +import { validateSeedWeights } from '../util/seedWeightPairs'; + +const optionsSelector = createSelector( + (state: RootState) => state.options, + (options: OptionsState) => { + return { + prompt: options.prompt, + shouldGenerateVariations: options.shouldGenerateVariations, + seedWeights: options.seedWeights, + maskPath: options.maskPath, + initialImagePath: options.initialImagePath, + seed: options.seed, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +const systemSelector = createSelector( + (state: RootState) => state.system, + (system: SystemState) => { + return { + isProcessing: system.isProcessing, + isConnected: system.isConnected, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +/** + * Checks relevant pieces of state to confirm generation will not deterministically fail. + * This is used to prevent the 'Generate' button from being clicked. + */ +const useCheckParameters = (): boolean => { + const { + prompt, + shouldGenerateVariations, + seedWeights, + maskPath, + initialImagePath, + seed, + } = useAppSelector(optionsSelector); + + const { isProcessing, isConnected } = useAppSelector(systemSelector); + + return useMemo(() => { + // Cannot generate without a prompt + if (!prompt) { + return false; + } + + // Cannot generate with a mask without img2img + if (maskPath && !initialImagePath) { + return false; + } + + // TODO: job queue + // Cannot generate if already processing an image + if (isProcessing) { + return false; + } + + // Cannot generate if not connected + if (!isConnected) { + return false; + } + + // Cannot generate variations without valid seed weights + if ( + shouldGenerateVariations && + (!(validateSeedWeights(seedWeights) || seedWeights === '') || seed === -1) + ) { + return false; + } + + // All good + return true; + }, [ + prompt, + maskPath, + initialImagePath, + isProcessing, + isConnected, + shouldGenerateVariations, + seedWeights, + seed, + ]); +}; + +export default useCheckParameters; diff --git a/frontend/src/common/util/parameterTranslation.ts b/frontend/src/common/util/parameterTranslation.ts new file mode 100644 index 0000000000..52ecfbc9b6 --- /dev/null +++ b/frontend/src/common/util/parameterTranslation.ts @@ -0,0 +1,182 @@ +/* + These functions translate frontend state into parameters + suitable for consumption by the backend, and vice-versa. +*/ + +import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from '../../app/constants'; +import { OptionsState } from '../../features/options/optionsSlice'; +import { SystemState } from '../../features/system/systemSlice'; +import { + seedWeightsToString, + stringToSeedWeightsArray, +} from './seedWeightPairs'; +import randomInt from './randomInt'; + +export const frontendToBackendParameters = ( + optionsState: OptionsState, + systemState: SystemState +): { [key: string]: any } => { + const { + prompt, + iterations, + steps, + cfgScale, + height, + width, + sampler, + seed, + seamless, + shouldUseInitImage, + img2imgStrength, + initialImagePath, + maskPath, + shouldFitToWidthHeight, + shouldGenerateVariations, + variationAmount, + seedWeights, + shouldRunESRGAN, + upscalingLevel, + upscalingStrength, + shouldRunGFPGAN, + gfpganStrength, + shouldRandomizeSeed, + } = optionsState; + + const { shouldDisplayInProgress } = systemState; + + const generationParameters: { [k: string]: any } = { + prompt, + iterations, + steps, + cfg_scale: cfgScale, + height, + width, + sampler_name: sampler, + seed, + seamless, + progress_images: shouldDisplayInProgress, + }; + + generationParameters.seed = shouldRandomizeSeed + ? randomInt(NUMPY_RAND_MIN, NUMPY_RAND_MAX) + : seed; + + if (shouldUseInitImage) { + generationParameters.init_img = initialImagePath; + generationParameters.strength = img2imgStrength; + generationParameters.fit = shouldFitToWidthHeight; + if (maskPath) { + generationParameters.init_mask = maskPath; + } + } + + if (shouldGenerateVariations) { + generationParameters.variation_amount = variationAmount; + if (seedWeights) { + generationParameters.with_variations = + stringToSeedWeightsArray(seedWeights); + } + } else { + generationParameters.variation_amount = 0; + } + + let esrganParameters: false | { [k: string]: any } = false; + let gfpganParameters: false | { [k: string]: any } = false; + + if (shouldRunESRGAN) { + esrganParameters = { + level: upscalingLevel, + strength: upscalingStrength, + }; + } + + if (shouldRunGFPGAN) { + gfpganParameters = { + strength: gfpganStrength, + }; + } + + return { + generationParameters, + esrganParameters, + gfpganParameters, + }; +}; + +export const backendToFrontendParameters = (parameters: { + [key: string]: any; +}) => { + const { + prompt, + iterations, + steps, + cfg_scale, + height, + width, + sampler_name, + seed, + seamless, + progress_images, + variation_amount, + with_variations, + gfpgan_strength, + upscale, + init_img, + init_mask, + strength, + } = parameters; + + const options: { [key: string]: any } = { + shouldDisplayInProgress: progress_images, + // init + shouldGenerateVariations: false, + shouldRunESRGAN: false, + shouldRunGFPGAN: false, + initialImagePath: '', + maskPath: '', + }; + + if (variation_amount > 0) { + options.shouldGenerateVariations = true; + options.variationAmount = variation_amount; + if (with_variations) { + options.seedWeights = seedWeightsToString(with_variations); + } + } + + if (gfpgan_strength > 0) { + options.shouldRunGFPGAN = true; + options.gfpganStrength = gfpgan_strength; + } + + if (upscale) { + options.shouldRunESRGAN = true; + options.upscalingLevel = upscale[0]; + options.upscalingStrength = upscale[1]; + } + + if (init_img) { + options.shouldUseInitImage = true; + options.initialImagePath = init_img; + options.strength = strength; + if (init_mask) { + options.maskPath = init_mask; + } + } + + // if we had a prompt, add all the metadata, but if we don't have a prompt, + // we must have only done ESRGAN or GFPGAN so do not add that metadata + if (prompt) { + options.prompt = prompt; + options.iterations = iterations; + options.steps = steps; + options.cfgScale = cfg_scale; + options.height = height; + options.width = width; + options.sampler = sampler_name; + options.seed = seed; + options.seamless = seamless; + } + + return options; +}; diff --git a/frontend/src/common/util/promptToString.ts b/frontend/src/common/util/promptToString.ts new file mode 100644 index 0000000000..d84a24acf8 --- /dev/null +++ b/frontend/src/common/util/promptToString.ts @@ -0,0 +1,16 @@ +import * as InvokeAI from '../../app/invokeai'; + +const promptToString = (prompt: InvokeAI.Prompt): string => { + if (prompt.length === 1) { + return prompt[0].prompt; + } + + return prompt + .map( + (promptItem: InvokeAI.PromptItem): string => + `${promptItem.prompt}:${promptItem.weight}` + ) + .join(' '); +}; + +export default promptToString; diff --git a/frontend/src/common/util/randomInt.ts b/frontend/src/common/util/randomInt.ts new file mode 100644 index 0000000000..078186f3da --- /dev/null +++ b/frontend/src/common/util/randomInt.ts @@ -0,0 +1,5 @@ +const randomInt = (min: number, max: number): number => { + return Math.floor(Math.random() * (max - min + 1) + min); +}; + +export default randomInt; diff --git a/frontend/src/common/util/seedWeightPairs.ts b/frontend/src/common/util/seedWeightPairs.ts new file mode 100644 index 0000000000..0bdb287554 --- /dev/null +++ b/frontend/src/common/util/seedWeightPairs.ts @@ -0,0 +1,68 @@ +import * as InvokeAI from '../../app/invokeai'; + +export const stringToSeedWeights = ( + string: string +): InvokeAI.SeedWeights | boolean => { + const stringPairs = string.split(','); + const arrPairs = stringPairs.map((p) => p.split(':')); + const pairs = arrPairs.map((p: Array): InvokeAI.SeedWeightPair => { + return { seed: parseInt(p[0]), weight: parseFloat(p[1]) }; + }); + + if (!validateSeedWeights(pairs)) { + return false; + } + + return pairs; +}; + +export const validateSeedWeights = ( + seedWeights: InvokeAI.SeedWeights | string +): boolean => { + return typeof seedWeights === 'string' + ? Boolean(stringToSeedWeights(seedWeights)) + : Boolean( + seedWeights.length && + !seedWeights.some((pair: InvokeAI.SeedWeightPair) => { + const { seed, weight } = pair; + const isSeedValid = !isNaN(parseInt(seed.toString(), 10)); + const isWeightValid = + !isNaN(parseInt(weight.toString(), 10)) && + weight >= 0 && + weight <= 1; + return !(isSeedValid && isWeightValid); + }) + ); +}; + +export const seedWeightsToString = ( + seedWeights: InvokeAI.SeedWeights +): string => { + return seedWeights.reduce((acc, pair, i, arr) => { + const { seed, weight } = pair; + acc += `${seed}:${weight}`; + if (i !== arr.length - 1) { + acc += ','; + } + return acc; + }, ''); +}; + +export const seedWeightsToArray = ( + seedWeights: InvokeAI.SeedWeights +): Array> => { + return seedWeights.map((pair: InvokeAI.SeedWeightPair) => [ + pair.seed, + pair.weight, + ]); +}; + +export const stringToSeedWeightsArray = ( + string: string +): Array> => { + const stringPairs = string.split(','); + const arrPairs = stringPairs.map((p) => p.split(':')); + return arrPairs.map( + (p: Array): Array => [parseInt(p[0]), parseFloat(p[1])] + ); +}; diff --git a/frontend/src/features/gallery/CurrentImageButtons.tsx b/frontend/src/features/gallery/CurrentImageButtons.tsx new file mode 100644 index 0000000000..4dc1001c74 --- /dev/null +++ b/frontend/src/features/gallery/CurrentImageButtons.tsx @@ -0,0 +1,155 @@ +import { Flex } from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { isEqual } from 'lodash'; + +import * as InvokeAI from '../../app/invokeai'; + +import { useAppDispatch, useAppSelector } from '../../app/store'; +import { RootState } from '../../app/store'; +import { + setAllParameters, + setInitialImagePath, + setSeed, +} from '../options/optionsSlice'; +import DeleteImageModal from './DeleteImageModal'; +import { SystemState } from '../system/systemSlice'; +import SDButton from '../../common/components/SDButton'; +import { runESRGAN, runGFPGAN } from '../../app/socketio/actions'; + +const systemSelector = createSelector( + (state: RootState) => state.system, + (system: SystemState) => { + return { + isProcessing: system.isProcessing, + isConnected: system.isConnected, + isGFPGANAvailable: system.isGFPGANAvailable, + isESRGANAvailable: system.isESRGANAvailable, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +type CurrentImageButtonsProps = { + image: InvokeAI.Image; + shouldShowImageDetails: boolean; + setShouldShowImageDetails: (b: boolean) => void; +}; + +/** + * Row of buttons for common actions: + * Use as init image, use all params, use seed, upscale, fix faces, details, delete. + */ +const CurrentImageButtons = ({ + image, + shouldShowImageDetails, + setShouldShowImageDetails, +}: CurrentImageButtonsProps) => { + const dispatch = useAppDispatch(); + + const { intermediateImage } = useAppSelector( + (state: RootState) => state.gallery + ); + + const { upscalingLevel, gfpganStrength } = useAppSelector( + (state: RootState) => state.options + ); + + const { isProcessing, isConnected, isGFPGANAvailable, isESRGANAvailable } = + useAppSelector(systemSelector); + + const handleClickUseAsInitialImage = () => + dispatch(setInitialImagePath(image.url)); + + const handleClickUseAllParameters = () => + dispatch(setAllParameters(image.metadata)); + + // Non-null assertion: this button is disabled if there is no seed. + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const handleClickUseSeed = () => dispatch(setSeed(image.metadata.image.seed)); + const handleClickUpscale = () => dispatch(runESRGAN(image)); + + const handleClickFixFaces = () => dispatch(runGFPGAN(image)); + + const handleClickShowImageDetails = () => + setShouldShowImageDetails(!shouldShowImageDetails); + + return ( + + + + + + + + + + + + + + + ); +}; + +export default CurrentImageButtons; diff --git a/frontend/src/features/gallery/CurrentImageDisplay.tsx b/frontend/src/features/gallery/CurrentImageDisplay.tsx new file mode 100644 index 0000000000..88b19f865b --- /dev/null +++ b/frontend/src/features/gallery/CurrentImageDisplay.tsx @@ -0,0 +1,67 @@ +import { Center, Flex, Image, Text, useColorModeValue } from '@chakra-ui/react'; +import { useAppSelector } from '../../app/store'; +import { RootState } from '../../app/store'; +import { useState } from 'react'; +import ImageMetadataViewer from './ImageMetadataViewer'; +import CurrentImageButtons from './CurrentImageButtons'; + +// TODO: With CSS Grid I had a hard time centering the image in a grid item. This is needed for that. +const height = 'calc(100vh - 238px)'; + +/** + * Displays the current image if there is one, plus associated actions. + */ +const CurrentImageDisplay = () => { + const { currentImage, intermediateImage } = useAppSelector( + (state: RootState) => state.gallery + ); + + const bgColor = useColorModeValue( + 'rgba(255, 255, 255, 0.85)', + 'rgba(0, 0, 0, 0.8)' + ); + + const [shouldShowImageDetails, setShouldShowImageDetails] = + useState(false); + + const imageToDisplay = intermediateImage || currentImage; + + return imageToDisplay ? ( + + +
+ + {shouldShowImageDetails && ( + + + + )} +
+
+ ) : ( +
+ No image selected +
+ ); +}; + +export default CurrentImageDisplay; diff --git a/frontend/src/features/gallery/DeleteImageModal.tsx b/frontend/src/features/gallery/DeleteImageModal.tsx new file mode 100644 index 0000000000..91ff3f8885 --- /dev/null +++ b/frontend/src/features/gallery/DeleteImageModal.tsx @@ -0,0 +1,125 @@ +import { + Text, + AlertDialog, + AlertDialogBody, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogContent, + AlertDialogOverlay, + useDisclosure, + Button, + Switch, + FormControl, + FormLabel, + Flex, +} from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { + ChangeEvent, + cloneElement, + forwardRef, + ReactElement, + SyntheticEvent, + useRef, +} from 'react'; +import { useAppDispatch, useAppSelector } from '../../app/store'; +import { deleteImage } from '../../app/socketio/actions'; +import { RootState } from '../../app/store'; +import { setShouldConfirmOnDelete, SystemState } from '../system/systemSlice'; +import * as InvokeAI from '../../app/invokeai'; + +interface DeleteImageModalProps { + /** + * Component which, on click, should delete the image/open the modal. + */ + children: ReactElement; + /** + * The image to delete. + */ + image: InvokeAI.Image; +} + +const systemSelector = createSelector( + (state: RootState) => state.system, + (system: SystemState) => system.shouldConfirmOnDelete +); + +/** + * Needs a child, which will act as the button to delete an image. + * If system.shouldConfirmOnDelete is true, a confirmation modal is displayed. + * If it is false, the image is deleted immediately. + * The confirmation modal has a "Don't ask me again" switch to set the boolean. + */ +const DeleteImageModal = forwardRef( + ({ image, children }: DeleteImageModalProps, ref) => { + const { isOpen, onOpen, onClose } = useDisclosure(); + const dispatch = useAppDispatch(); + const shouldConfirmOnDelete = useAppSelector(systemSelector); + const cancelRef = useRef(null); + + const handleClickDelete = (e: SyntheticEvent) => { + e.stopPropagation(); + shouldConfirmOnDelete ? onOpen() : handleDelete(); + }; + + const handleDelete = () => { + dispatch(deleteImage(image)); + onClose(); + }; + + const handleChangeShouldConfirmOnDelete = ( + e: ChangeEvent + ) => dispatch(setShouldConfirmOnDelete(!e.target.checked)); + + return ( + <> + {cloneElement(children, { + // TODO: This feels wrong. + onClick: handleClickDelete, + ref: ref, + })} + + + + + + Delete image + + + + + + Are you sure? You can't undo this action afterwards. + + + + Don't ask me again + + + + + + + + + + + + + + ); + } +); + +export default DeleteImageModal; diff --git a/frontend/src/features/gallery/HoverableImage.tsx b/frontend/src/features/gallery/HoverableImage.tsx new file mode 100644 index 0000000000..3809888bf9 --- /dev/null +++ b/frontend/src/features/gallery/HoverableImage.tsx @@ -0,0 +1,141 @@ +import { + Box, + Flex, + Icon, + IconButton, + Image, + Tooltip, + useColorModeValue, +} from '@chakra-ui/react'; +import { useAppDispatch } from '../../app/store'; +import { setCurrentImage } from './gallerySlice'; +import { FaCheck, FaSeedling, FaTrashAlt } from 'react-icons/fa'; +import DeleteImageModal from './DeleteImageModal'; +import { memo, SyntheticEvent, useState } from 'react'; +import { setAllParameters, setSeed } from '../options/optionsSlice'; +import * as InvokeAI from '../../app/invokeai'; +import { IoArrowUndoCircleOutline } from 'react-icons/io5'; + +interface HoverableImageProps { + image: InvokeAI.Image; + isSelected: boolean; +} + +const memoEqualityCheck = ( + prev: HoverableImageProps, + next: HoverableImageProps +) => prev.image.uuid === next.image.uuid && prev.isSelected === next.isSelected; + +/** + * Gallery image component with delete/use all/use seed buttons on hover. + */ +const HoverableImage = memo((props: HoverableImageProps) => { + const [isHovered, setIsHovered] = useState(false); + const dispatch = useAppDispatch(); + + const checkColor = useColorModeValue('green.600', 'green.300'); + const bgColor = useColorModeValue('gray.200', 'gray.700'); + const bgGradient = useColorModeValue( + 'radial-gradient(circle, rgba(255,255,255,0.7) 0%, rgba(255,255,255,0.7) 20%, rgba(0,0,0,0) 100%)', + 'radial-gradient(circle, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.7) 20%, rgba(0,0,0,0) 100%)' + ); + + const { image, isSelected } = props; + const { url, uuid, metadata } = image; + + const handleMouseOver = () => setIsHovered(true); + const handleMouseOut = () => setIsHovered(false); + + const handleClickSetAllParameters = (e: SyntheticEvent) => { + e.stopPropagation(); + dispatch(setAllParameters(metadata)); + }; + + const handleClickSetSeed = (e: SyntheticEvent) => { + e.stopPropagation(); + dispatch(setSeed(image.metadata.image.seed)); + }; + + const handleClickImage = () => dispatch(setCurrentImage(image)); + + return ( + + + + {isSelected && ( + + )} + {isHovered && ( + + + + } + size="xs" + variant={'imageHoverIconButton'} + fontSize={14} + /> + + + {['txt2img', 'img2img'].includes(image?.metadata?.image?.type) && ( + + } + size="xs" + fontSize={18} + variant={'imageHoverIconButton'} + onClickCapture={handleClickSetAllParameters} + /> + + )} + {image?.metadata?.image?.seed && ( + + } + size="xs" + fontSize={16} + variant={'imageHoverIconButton'} + onClickCapture={handleClickSetSeed} + /> + + )} + + )} + + + ); +}, memoEqualityCheck); + +export default HoverableImage; diff --git a/frontend/src/features/gallery/ImageGallery.tsx b/frontend/src/features/gallery/ImageGallery.tsx new file mode 100644 index 0000000000..cdc45aedc0 --- /dev/null +++ b/frontend/src/features/gallery/ImageGallery.tsx @@ -0,0 +1,39 @@ +import { Center, Flex, Text } from '@chakra-ui/react'; +import { RootState } from '../../app/store'; +import { useAppSelector } from '../../app/store'; +import HoverableImage from './HoverableImage'; + +/** + * Simple image gallery. + */ +const ImageGallery = () => { + const { images, currentImageUuid } = useAppSelector( + (state: RootState) => state.gallery + ); + + /** + * I don't like that this needs to rerender whenever the current image is changed. + * What if we have a large number of images? I suppose pagination (planned) will + * mitigate this issue. + * + * TODO: Refactor if performance complaints, or after migrating to new API which supports pagination. + */ + + return images.length ? ( + + {[...images].reverse().map((image) => { + const { uuid } = image; + const isSelected = currentImageUuid === uuid; + return ( + + ); + })} + + ) : ( +
+ No images in gallery +
+ ); +}; + +export default ImageGallery; diff --git a/frontend/src/features/gallery/ImageMetadataViewer.tsx b/frontend/src/features/gallery/ImageMetadataViewer.tsx new file mode 100644 index 0000000000..81300b1ced --- /dev/null +++ b/frontend/src/features/gallery/ImageMetadataViewer.tsx @@ -0,0 +1,321 @@ +import { + Box, + Center, + Flex, + IconButton, + Link, + Text, + Tooltip, + useColorModeValue, +} from '@chakra-ui/react'; +import { ExternalLinkIcon } from '@chakra-ui/icons'; +import { memo } from 'react'; +import { IoArrowUndoCircleOutline } from 'react-icons/io5'; +import { useAppDispatch } from '../../app/store'; +import * as InvokeAI from '../../app/invokeai'; +import { + setCfgScale, + setGfpganStrength, + setHeight, + setImg2imgStrength, + setInitialImagePath, + setMaskPath, + setPrompt, + setSampler, + setSeed, + setSeedWeights, + setShouldFitToWidthHeight, + setSteps, + setUpscalingLevel, + setUpscalingStrength, + setWidth, +} from '../options/optionsSlice'; +import promptToString from '../../common/util/promptToString'; +import { seedWeightsToString } from '../../common/util/seedWeightPairs'; +import { FaCopy } from 'react-icons/fa'; + +type MetadataItemProps = { + isLink?: boolean; + label: string; + onClick?: () => void; + value: number | string | boolean; +}; + +/** + * Component to display an individual metadata item or parameter. + */ +const MetadataItem = ({ label, value, onClick, isLink }: MetadataItemProps) => { + return ( + + {onClick && ( + + } + size={'xs'} + variant={'ghost'} + fontSize={20} + onClick={onClick} + /> + + )} + + {label}: + + {isLink ? ( + + {value.toString()} + + ) : ( + + {value.toString()} + + )} + + ); +}; + +type ImageMetadataViewerProps = { + image: InvokeAI.Image; +}; + +// TODO: I don't know if this is needed. +const memoEqualityCheck = ( + prev: ImageMetadataViewerProps, + next: ImageMetadataViewerProps +) => prev.image.uuid === next.image.uuid; + +// TODO: Show more interesting information in this component. + +/** + * Image metadata viewer overlays currently selected image and provides + * access to any of its metadata for use in processing. + */ +const ImageMetadataViewer = memo(({ image }: ImageMetadataViewerProps) => { + const dispatch = useAppDispatch(); + const jsonBgColor = useColorModeValue('blackAlpha.100', 'whiteAlpha.100'); + + const metadata = image?.metadata?.image || {}; + const { + type, + postprocessing, + sampler, + prompt, + seed, + variations, + steps, + cfg_scale, + seamless, + width, + height, + strength, + fit, + init_image_path, + mask_image_path, + orig_path, + scale, + } = metadata; + + const metadataJSON = JSON.stringify(metadata, null, 2); + + return ( + + + File: + + {image.url} + + + + {Object.keys(metadata).length > 0 ? ( + <> + {type && } + {['esrgan', 'gfpgan'].includes(type) && ( + + )} + {type === 'gfpgan' && strength && ( + dispatch(setGfpganStrength(strength))} + /> + )} + {type === 'esrgan' && scale && ( + dispatch(setUpscalingLevel(scale))} + /> + )} + {type === 'esrgan' && strength && ( + dispatch(setUpscalingStrength(strength))} + /> + )} + {prompt && ( + dispatch(setPrompt(prompt))} + /> + )} + {seed && ( + dispatch(setSeed(seed))} + /> + )} + {sampler && ( + dispatch(setSampler(sampler))} + /> + )} + {steps && ( + dispatch(setSteps(steps))} + /> + )} + {cfg_scale && ( + dispatch(setCfgScale(cfg_scale))} + /> + )} + {variations && variations.length > 0 && ( + + dispatch(setSeedWeights(seedWeightsToString(variations))) + } + /> + )} + {seamless && ( + dispatch(setWidth(seamless))} + /> + )} + {width && ( + dispatch(setWidth(width))} + /> + )} + {height && ( + dispatch(setHeight(height))} + /> + )} + {init_image_path && ( + dispatch(setInitialImagePath(init_image_path))} + /> + )} + {mask_image_path && ( + dispatch(setMaskPath(mask_image_path))} + /> + )} + {type === 'img2img' && strength && ( + dispatch(setImg2imgStrength(strength))} + /> + )} + {fit && ( + dispatch(setShouldFitToWidthHeight(fit))} + /> + )} + {postprocessing && + postprocessing.length > 0 && + postprocessing.map( + (postprocess: InvokeAI.PostProcessedImageMetadata) => { + if (postprocess.type === 'esrgan') { + const { scale, strength } = postprocess; + return ( + <> + dispatch(setUpscalingLevel(scale))} + /> + dispatch(setUpscalingStrength(strength))} + /> + + ); + } else if (postprocess.type === 'gfpgan') { + const { strength } = postprocess; + return ( + dispatch(setGfpganStrength(strength))} + /> + ); + } + } + )} + + + + } + size={'xs'} + variant={'ghost'} + fontSize={14} + onClick={() => navigator.clipboard.writeText(metadataJSON)} + /> + + Metadata JSON: + + +
{metadataJSON}
+
+
+ + ) : ( +
+ + No metadata available + +
+ )} +
+ ); +}, memoEqualityCheck); + +export default ImageMetadataViewer; diff --git a/frontend/src/features/gallery/gallerySlice.ts b/frontend/src/features/gallery/gallerySlice.ts new file mode 100644 index 0000000000..8870d90466 --- /dev/null +++ b/frontend/src/features/gallery/gallerySlice.ts @@ -0,0 +1,102 @@ +import { createSlice } from '@reduxjs/toolkit'; +import type { PayloadAction } from '@reduxjs/toolkit'; +import { clamp } from 'lodash'; +import * as InvokeAI from '../../app/invokeai'; + +export interface GalleryState { + currentImage?: InvokeAI.Image; + currentImageUuid: string; + images: Array; + intermediateImage?: InvokeAI.Image; +} + +const initialState: GalleryState = { + currentImageUuid: '', + images: [], +}; + +export const gallerySlice = createSlice({ + name: 'gallery', + initialState, + reducers: { + setCurrentImage: (state, action: PayloadAction) => { + state.currentImage = action.payload; + state.currentImageUuid = action.payload.uuid; + }, + removeImage: (state, action: PayloadAction) => { + const uuid = action.payload; + + const newImages = state.images.filter((image) => image.uuid !== uuid); + + if (uuid === state.currentImageUuid) { + /** + * We are deleting the currently selected image. + * + * We want the new currentl selected image to be under the cursor in the + * gallery, so we need to do some fanagling. The currently selected image + * is set by its UUID, not its index in the image list. + * + * Get the currently selected image's index. + */ + const imageToDeleteIndex = state.images.findIndex( + (image) => image.uuid === uuid + ); + + /** + * New current image needs to be in the same spot, but because the gallery + * is sorted in reverse order, the new current image's index will actuall be + * one less than the deleted image's index. + * + * Clamp the new index to ensure it is valid.. + */ + const newCurrentImageIndex = clamp( + imageToDeleteIndex - 1, + 0, + newImages.length - 1 + ); + + state.currentImage = newImages.length + ? newImages[newCurrentImageIndex] + : undefined; + + state.currentImageUuid = newImages.length + ? newImages[newCurrentImageIndex].uuid + : ''; + } + + state.images = newImages; + }, + addImage: (state, action: PayloadAction) => { + state.images.push(action.payload); + state.currentImageUuid = action.payload.uuid; + state.intermediateImage = undefined; + state.currentImage = action.payload; + }, + setIntermediateImage: (state, action: PayloadAction) => { + state.intermediateImage = action.payload; + }, + clearIntermediateImage: (state) => { + state.intermediateImage = undefined; + }, + setGalleryImages: (state, action: PayloadAction>) => { + const newImages = action.payload; + if (newImages.length) { + const newCurrentImage = newImages[newImages.length - 1]; + state.images = newImages; + state.currentImage = newCurrentImage; + state.currentImageUuid = newCurrentImage.uuid; + } + }, + }, +}); + +export const { + addImage, + clearIntermediateImage, + removeImage, + setCurrentImage, + setGalleryImages, + setIntermediateImage, +} = gallerySlice.actions; + +export default gallerySlice.reducer; diff --git a/frontend/src/features/options/ESRGANOptions.tsx b/frontend/src/features/options/ESRGANOptions.tsx new file mode 100644 index 0000000000..71bbd16182 --- /dev/null +++ b/frontend/src/features/options/ESRGANOptions.tsx @@ -0,0 +1,87 @@ +import { Flex } from '@chakra-ui/react'; + +import { RootState } from '../../app/store'; +import { useAppDispatch, useAppSelector } from '../../app/store'; + +import { + setUpscalingLevel, + setUpscalingStrength, + UpscalingLevel, + OptionsState, +} from '../options/optionsSlice'; + + +import { UPSCALING_LEVELS } from '../../app/constants'; +import { createSelector } from '@reduxjs/toolkit'; +import { isEqual } from 'lodash'; +import { SystemState } from '../system/systemSlice'; +import { ChangeEvent } from 'react'; +import SDNumberInput from '../../common/components/SDNumberInput'; +import SDSelect from '../../common/components/SDSelect'; + +const optionsSelector = createSelector( + (state: RootState) => state.options, + (options: OptionsState) => { + return { + upscalingLevel: options.upscalingLevel, + upscalingStrength: options.upscalingStrength, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +const systemSelector = createSelector( + (state: RootState) => state.system, + (system: SystemState) => { + return { + isESRGANAvailable: system.isESRGANAvailable, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +/** + * Displays upscaling/ESRGAN options (level and strength). + */ +const ESRGANOptions = () => { + const dispatch = useAppDispatch(); + const { upscalingLevel, upscalingStrength } = useAppSelector(optionsSelector); + const { isESRGANAvailable } = useAppSelector(systemSelector); + + const handleChangeLevel = (e: ChangeEvent) => + dispatch(setUpscalingLevel(Number(e.target.value) as UpscalingLevel)); + + const handleChangeStrength = (v: string | number) => + dispatch(setUpscalingStrength(Number(v))); + + return ( + + + + + ); +}; + +export default ESRGANOptions; diff --git a/frontend/src/features/options/GFPGANOptions.tsx b/frontend/src/features/options/GFPGANOptions.tsx new file mode 100644 index 0000000000..463f3b1686 --- /dev/null +++ b/frontend/src/features/options/GFPGANOptions.tsx @@ -0,0 +1,68 @@ +import { Flex } from '@chakra-ui/react'; + +import { RootState } from '../../app/store'; +import { useAppDispatch, useAppSelector } from '../../app/store'; + +import { OptionsState, setGfpganStrength } from '../options/optionsSlice'; + + +import { createSelector } from '@reduxjs/toolkit'; +import { isEqual } from 'lodash'; +import { SystemState } from '../system/systemSlice'; +import SDNumberInput from '../../common/components/SDNumberInput'; + +const optionsSelector = createSelector( + (state: RootState) => state.options, + (options: OptionsState) => { + return { + gfpganStrength: options.gfpganStrength, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +const systemSelector = createSelector( + (state: RootState) => state.system, + (system: SystemState) => { + return { + isGFPGANAvailable: system.isGFPGANAvailable, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +/** + * Displays face-fixing/GFPGAN options (strength). + */ +const GFPGANOptions = () => { + const dispatch = useAppDispatch(); + const { gfpganStrength } = useAppSelector(optionsSelector); + const { isGFPGANAvailable } = useAppSelector(systemSelector); + + const handleChangeStrength = (v: string | number) => + dispatch(setGfpganStrength(Number(v))); + + return ( + + + + ); +}; + +export default GFPGANOptions; diff --git a/frontend/src/features/options/ImageToImageOptions.tsx b/frontend/src/features/options/ImageToImageOptions.tsx new file mode 100644 index 0000000000..d9be3f7b53 --- /dev/null +++ b/frontend/src/features/options/ImageToImageOptions.tsx @@ -0,0 +1,59 @@ +import { Flex } from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { ChangeEvent } from 'react'; +import { useAppDispatch, useAppSelector } from '../../app/store'; +import { RootState } from '../../app/store'; +import SDNumberInput from '../../common/components/SDNumberInput'; +import SDSwitch from '../../common/components/SDSwitch'; +import InitAndMaskImage from './InitAndMaskImage'; +import { + OptionsState, + setImg2imgStrength, + setShouldFitToWidthHeight, +} from './optionsSlice'; + +const optionsSelector = createSelector( + (state: RootState) => state.options, + (options: OptionsState) => { + return { + img2imgStrength: options.img2imgStrength, + shouldFitToWidthHeight: options.shouldFitToWidthHeight, + }; + } +); + +/** + * Options for img2img generation (strength, fit, init/mask upload). + */ +const ImageToImageOptions = () => { + const dispatch = useAppDispatch(); + const { img2imgStrength, shouldFitToWidthHeight } = + useAppSelector(optionsSelector); + + const handleChangeStrength = (v: string | number) => + dispatch(setImg2imgStrength(Number(v))); + + const handleChangeFit = (e: ChangeEvent) => + dispatch(setShouldFitToWidthHeight(e.target.checked)); + + return ( + + + + + + ); +}; + +export default ImageToImageOptions; diff --git a/frontend/src/features/options/ImageUploader.tsx b/frontend/src/features/options/ImageUploader.tsx new file mode 100644 index 0000000000..e7da2f14ba --- /dev/null +++ b/frontend/src/features/options/ImageUploader.tsx @@ -0,0 +1,64 @@ +import { Box } from '@chakra-ui/react'; +import { cloneElement, ReactElement, SyntheticEvent, useCallback } from 'react'; +import { FileRejection, useDropzone } from 'react-dropzone'; + +type ImageUploaderProps = { + /** + * Component which, on click, should open the upload interface. + */ + children: ReactElement; + /** + * Callback to handle uploading the selected file. + */ + fileAcceptedCallback: (file: File) => void; + /** + * Callback to handle a file being rejected. + */ + fileRejectionCallback: (rejection: FileRejection) => void; +}; + +/** + * File upload using react-dropzone. + * Needs a child to be the button to activate the upload interface. + */ +const ImageUploader = ({ + children, + fileAcceptedCallback, + fileRejectionCallback, +}: ImageUploaderProps) => { + const onDrop = useCallback( + (acceptedFiles: Array, fileRejections: Array) => { + fileRejections.forEach((rejection: FileRejection) => { + fileRejectionCallback(rejection); + }); + + acceptedFiles.forEach((file: File) => { + fileAcceptedCallback(file); + }); + }, + [fileAcceptedCallback, fileRejectionCallback] + ); + + const { getRootProps, getInputProps, open } = useDropzone({ + onDrop, + accept: { + 'image/jpeg': ['.jpg', '.jpeg', '.png'], + }, + }); + + const handleClickUploadIcon = (e: SyntheticEvent) => { + e.stopPropagation(); + open(); + }; + + return ( + + + {cloneElement(children, { + onClick: handleClickUploadIcon, + })} + + ); +}; + +export default ImageUploader; diff --git a/frontend/src/features/options/InitAndMaskImage.css b/frontend/src/features/options/InitAndMaskImage.css new file mode 100644 index 0000000000..31fe87fa17 --- /dev/null +++ b/frontend/src/features/options/InitAndMaskImage.css @@ -0,0 +1,20 @@ +.checkerboard { + background-position: 0px 0px, 10px 10px; + background-size: 20px 20px; + background-image: linear-gradient( + 45deg, + #eee 25%, + transparent 25%, + transparent 75%, + #eee 75%, + #eee 100% + ), + linear-gradient( + 45deg, + #eee 25%, + white 25%, + white 75%, + #eee 75%, + #eee 100% + ); +} diff --git a/frontend/src/features/options/InitAndMaskImage.tsx b/frontend/src/features/options/InitAndMaskImage.tsx new file mode 100644 index 0000000000..f129b54129 --- /dev/null +++ b/frontend/src/features/options/InitAndMaskImage.tsx @@ -0,0 +1,57 @@ +import { Flex, Image } from '@chakra-ui/react'; +import { useState } from 'react'; +import { useAppSelector } from '../../app/store'; +import { RootState } from '../../app/store'; +import { OptionsState } from '../../features/options/optionsSlice'; +import './InitAndMaskImage.css'; +import { createSelector } from '@reduxjs/toolkit'; +import { isEqual } from 'lodash'; +import InitAndMaskUploadButtons from './InitAndMaskUploadButtons'; + +const optionsSelector = createSelector( + (state: RootState) => state.options, + (options: OptionsState) => { + return { + initialImagePath: options.initialImagePath, + maskPath: options.maskPath, + }; + }, + { memoizeOptions: { resultEqualityCheck: isEqual } } +); + +/** + * Displays init and mask images and buttons to upload/delete them. + */ +const InitAndMaskImage = () => { + const { initialImagePath, maskPath } = useAppSelector(optionsSelector); + const [shouldShowMask, setShouldShowMask] = useState(false); + + return ( + + + {initialImagePath && ( + + + {shouldShowMask && maskPath && ( + + )} + + )} + + ); +}; + +export default InitAndMaskImage; diff --git a/frontend/src/features/options/InitAndMaskUploadButtons.tsx b/frontend/src/features/options/InitAndMaskUploadButtons.tsx new file mode 100644 index 0000000000..8f0f5748e5 --- /dev/null +++ b/frontend/src/features/options/InitAndMaskUploadButtons.tsx @@ -0,0 +1,151 @@ +import { Button, Flex, IconButton, useToast } from '@chakra-ui/react'; +import { SyntheticEvent, useCallback } from 'react'; +import { FaTrash, FaUpload } from 'react-icons/fa'; +import { useAppDispatch, useAppSelector } from '../../app/store'; +import { RootState } from '../../app/store'; +import { + OptionsState, + setInitialImagePath, + setMaskPath, +} from '../../features/options/optionsSlice'; +import { + uploadInitialImage, + uploadMaskImage, +} from '../../app/socketio/actions'; +import { createSelector } from '@reduxjs/toolkit'; +import { isEqual } from 'lodash'; +import ImageUploader from './ImageUploader'; +import { FileRejection } from 'react-dropzone'; + +const optionsSelector = createSelector( + (state: RootState) => state.options, + (options: OptionsState) => { + return { + initialImagePath: options.initialImagePath, + maskPath: options.maskPath, + }; + }, + { memoizeOptions: { resultEqualityCheck: isEqual } } +); + +type InitAndMaskUploadButtonsProps = { + setShouldShowMask: (b: boolean) => void; +}; + +/** + * Init and mask image upload buttons. + */ +const InitAndMaskUploadButtons = ({ + setShouldShowMask, +}: InitAndMaskUploadButtonsProps) => { + const dispatch = useAppDispatch(); + const { initialImagePath, maskPath } = useAppSelector(optionsSelector); + + // Use a toast to alert user when a file upload is rejected + const toast = useToast(); + + // Clear the init and mask images + const handleClickResetInitialImage = (e: SyntheticEvent) => { + e.stopPropagation(); + dispatch(setInitialImagePath('')); + }; + + // Clear the init and mask images + const handleClickResetMask = (e: SyntheticEvent) => { + e.stopPropagation(); + dispatch(setMaskPath('')); + }; + + // Handle hover to view initial image and mask image + const handleMouseOverInitialImageUploadButton = () => + setShouldShowMask(false); + const handleMouseOutInitialImageUploadButton = () => setShouldShowMask(true); + + const handleMouseOverMaskUploadButton = () => setShouldShowMask(true); + const handleMouseOutMaskUploadButton = () => setShouldShowMask(true); + + // Callbacks to for handling file upload attempts + const initImageFileAcceptedCallback = useCallback( + (file: File) => dispatch(uploadInitialImage(file)), + [dispatch] + ); + + const maskImageFileAcceptedCallback = useCallback( + (file: File) => dispatch(uploadMaskImage(file)), + [dispatch] + ); + + const fileRejectionCallback = useCallback( + (rejection: FileRejection) => { + const msg = rejection.errors.reduce( + (acc: string, cur: { message: string }) => acc + '\n' + cur.message, + '' + ); + + toast({ + title: 'Upload failed', + description: msg, + status: 'error', + isClosable: true, + }); + }, + [toast] + ); + + return ( + + + + + + } + /> + + + + + + } + /> + + ); +}; + +export default InitAndMaskUploadButtons; diff --git a/frontend/src/features/options/OptionsAccordion.tsx b/frontend/src/features/options/OptionsAccordion.tsx new file mode 100644 index 0000000000..2568717090 --- /dev/null +++ b/frontend/src/features/options/OptionsAccordion.tsx @@ -0,0 +1,226 @@ +import { + Flex, + Box, + Text, + Accordion, + AccordionItem, + AccordionButton, + AccordionIcon, + AccordionPanel, + Switch, + ExpandedIndex, +} from '@chakra-ui/react'; + +import { RootState } from '../../app/store'; +import { useAppDispatch, useAppSelector } from '../../app/store'; + +import { + setShouldRunGFPGAN, + setShouldRunESRGAN, + OptionsState, + setShouldUseInitImage, +} from '../options/optionsSlice'; +import { createSelector } from '@reduxjs/toolkit'; +import { isEqual } from 'lodash'; +import { setOpenAccordions, SystemState } from '../system/systemSlice'; +import SeedVariationOptions from './SeedVariationOptions'; +import SamplerOptions from './SamplerOptions'; +import ESRGANOptions from './ESRGANOptions'; +import GFPGANOptions from './GFPGANOptions'; +import OutputOptions from './OutputOptions'; +import ImageToImageOptions from './ImageToImageOptions'; +import { ChangeEvent } from 'react'; + +import GuideIcon from '../../common/components/GuideIcon'; +import { Feature } from '../../app/features'; + +const optionsSelector = createSelector( + (state: RootState) => state.options, + (options: OptionsState) => { + return { + initialImagePath: options.initialImagePath, + shouldUseInitImage: options.shouldUseInitImage, + shouldRunESRGAN: options.shouldRunESRGAN, + shouldRunGFPGAN: options.shouldRunGFPGAN, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +const systemSelector = createSelector( + (state: RootState) => state.system, + (system: SystemState) => { + return { + isGFPGANAvailable: system.isGFPGANAvailable, + isESRGANAvailable: system.isESRGANAvailable, + openAccordions: system.openAccordions, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +/** + * Main container for generation and processing parameters. + */ +const OptionsAccordion = () => { + const { + shouldRunESRGAN, + shouldRunGFPGAN, + shouldUseInitImage, + initialImagePath, + } = useAppSelector(optionsSelector); + + const { isGFPGANAvailable, isESRGANAvailable, openAccordions } = + useAppSelector(systemSelector); + + const dispatch = useAppDispatch(); + + /** + * Stores accordion state in redux so preferred UI setup is retained. + */ + const handleChangeAccordionState = (openAccordions: ExpandedIndex) => + dispatch(setOpenAccordions(openAccordions)); + + const handleChangeShouldRunESRGAN = (e: ChangeEvent) => + dispatch(setShouldRunESRGAN(e.target.checked)); + + const handleChangeShouldRunGFPGAN = (e: ChangeEvent) => + dispatch(setShouldRunGFPGAN(e.target.checked)); + + const handleChangeShouldUseInitImage = (e: ChangeEvent) => + dispatch(setShouldUseInitImage(e.target.checked)); + + return ( + + +

+ + + Seed & Variation + + + + +

+ + + +
+ +

+ + + Sampler + + + + +

+ + + +
+ +

+ + + Upscale (ESRGAN) + + + + + +

+ + + +
+ +

+ + + Face Correction + + + + + +

+ + + +
+ +

+ + + Image to Image + + + + + +

+ + + +
+ +

+ + + Output + + + + +

+ + + +
+
+ ); +}; + +export default OptionsAccordion; diff --git a/frontend/src/features/options/OutputOptions.tsx b/frontend/src/features/options/OutputOptions.tsx new file mode 100644 index 0000000000..32ff6f5a82 --- /dev/null +++ b/frontend/src/features/options/OutputOptions.tsx @@ -0,0 +1,76 @@ +import { Flex } from '@chakra-ui/react'; + +import { RootState } from '../../app/store'; +import { useAppDispatch, useAppSelector } from '../../app/store'; + +import { setHeight, setWidth, setSeamless, OptionsState } from '../options/optionsSlice'; + + +import { HEIGHTS, WIDTHS } from '../../app/constants'; +import { createSelector } from '@reduxjs/toolkit'; +import { isEqual } from 'lodash'; +import { ChangeEvent } from 'react'; +import SDSelect from '../../common/components/SDSelect'; +import SDSwitch from '../../common/components/SDSwitch'; + +const optionsSelector = createSelector( + (state: RootState) => state.options, + (options: OptionsState) => { + return { + height: options.height, + width: options.width, + seamless: options.seamless, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +/** + * Image output options. Includes width, height, seamless tiling. + */ +const OutputOptions = () => { + const dispatch = useAppDispatch(); + const { height, width, seamless } = useAppSelector(optionsSelector); + + const handleChangeWidth = (e: ChangeEvent) => + dispatch(setWidth(Number(e.target.value))); + + const handleChangeHeight = (e: ChangeEvent) => + dispatch(setHeight(Number(e.target.value))); + + const handleChangeSeamless = (e: ChangeEvent) => + dispatch(setSeamless(e.target.checked)); + + return ( + + + + + + + + ); +}; + +export default OutputOptions; diff --git a/frontend/src/features/options/ProcessButtons.tsx b/frontend/src/features/options/ProcessButtons.tsx new file mode 100644 index 0000000000..d1960d3271 --- /dev/null +++ b/frontend/src/features/options/ProcessButtons.tsx @@ -0,0 +1,68 @@ +import { Flex } from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { isEqual } from 'lodash'; +import { useAppDispatch, useAppSelector } from '../../app/store'; +import { cancelProcessing, generateImage } from '../../app/socketio/actions'; +import { RootState } from '../../app/store'; +import SDButton from '../../common/components/SDButton'; +import useCheckParameters from '../../common/hooks/useCheckParameters'; +import { SystemState } from '../system/systemSlice'; + +const systemSelector = createSelector( + (state: RootState) => state.system, + (system: SystemState) => { + return { + isProcessing: system.isProcessing, + isConnected: system.isConnected, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +/** + * Buttons to start and cancel image generation. + */ +const ProcessButtons = () => { + const dispatch = useAppDispatch(); + const { isProcessing, isConnected } = useAppSelector(systemSelector); + const isReady = useCheckParameters(); + + const handleClickGenerate = () => dispatch(generateImage()); + + const handleClickCancel = () => dispatch(cancelProcessing()); + + return ( + + + + + ); +}; + +export default ProcessButtons; diff --git a/frontend/src/features/options/PromptInput.tsx b/frontend/src/features/options/PromptInput.tsx new file mode 100644 index 0000000000..bed6af411c --- /dev/null +++ b/frontend/src/features/options/PromptInput.tsx @@ -0,0 +1,44 @@ +import { Textarea } from '@chakra-ui/react'; +import { + ChangeEvent, + KeyboardEvent, +} from 'react'; +import { useAppDispatch, useAppSelector } from '../../app/store'; +import { generateImage } from '../../app/socketio/actions'; +import { RootState } from '../../app/store'; +import { setPrompt } from '../options/optionsSlice'; + +/** + * Prompt input text area. + */ +const PromptInput = () => { + const { prompt } = useAppSelector((state: RootState) => state.options); + const dispatch = useAppDispatch(); + + const handleChangePrompt = (e: ChangeEvent) => + dispatch(setPrompt(e.target.value)); + + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Enter' && e.shiftKey === false) { + e.preventDefault(); + dispatch(generateImage()) + } + }; + + return ( + - - + + Stable Diffusion Dream Server + + + + + + + + + + + +
+

Stable Diffusion Dream Server

+
+ For news and support for this web service, visit our GitHub + site +
+
+ +
+ +
+
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + +
+
+
+ + + + +
+ + + +
+
+ + + + + + + +
-
- - - - - - - - - - -
- - - - - - - - - - -
- - - - -
-
- - - -
- - - - -
-
+
+
- + + + + + - +
+
+ + + + +
- -
-
-
- - -
- -
- Postprocessing...1/3 -
-
-
- -
-
-

No results...

+
+ + +
+
+
+ + +
+ +
+ Postprocessing...1/3
-
- + + +
+
+ + + diff --git a/static/dream_web/index.js b/static/dream_web/index.js index ac68034920..5de690297d 100644 --- a/static/dream_web/index.js +++ b/static/dream_web/index.js @@ -1,3 +1,109 @@ +const socket = io(); + +var priorResultsLoadState = { + page: 0, + pages: 1, + per_page: 10, + total: 20, + offset: 0, // number of items generated since last load + loading: false, + initialized: false +}; + +function loadPriorResults() { + // Fix next page by offset + let offsetPages = priorResultsLoadState.offset / priorResultsLoadState.per_page; + priorResultsLoadState.page += offsetPages; + priorResultsLoadState.pages += offsetPages; + priorResultsLoadState.total += priorResultsLoadState.offset; + priorResultsLoadState.offset = 0; + + if (priorResultsLoadState.loading) { + return; + } + + if (priorResultsLoadState.page >= priorResultsLoadState.pages) { + return; // Nothing more to load + } + + // Load + priorResultsLoadState.loading = true + let url = new URL('/api/images', document.baseURI); + url.searchParams.append('page', priorResultsLoadState.initialized ? priorResultsLoadState.page + 1 : priorResultsLoadState.page); + url.searchParams.append('per_page', priorResultsLoadState.per_page); + fetch(url.href, { + method: 'GET', + headers: new Headers({'content-type': 'application/json'}) + }) + .then(response => response.json()) + .then(data => { + priorResultsLoadState.page = data.page; + priorResultsLoadState.pages = data.pages; + priorResultsLoadState.per_page = data.per_page; + priorResultsLoadState.total = data.total; + + data.items.forEach(function(dreamId, index) { + let src = 'api/images/' + dreamId; + fetch('/api/images/' + dreamId + '/metadata', { + method: 'GET', + headers: new Headers({'content-type': 'application/json'}) + }) + .then(response => response.json()) + .then(metadata => { + let seed = metadata.seed || 0; // TODO: Parse old metadata + appendOutput(src, seed, metadata, true); + }); + }); + + // Load until page is full + if (!priorResultsLoadState.initialized) { + if (document.body.scrollHeight <= window.innerHeight) { + loadPriorResults(); + } + } + }) + .finally(() => { + priorResultsLoadState.loading = false; + priorResultsLoadState.initialized = true; + }); +} + +function resetForm() { + var form = document.getElementById('generate-form'); + form.querySelector('fieldset').removeAttribute('disabled'); +} + +function initProgress(totalSteps, showProgressImages) { + // TODO: Progress could theoretically come from multiple jobs at the same time (in the future) + let progressSectionEle = document.querySelector('#progress-section'); + progressSectionEle.style.display = 'initial'; + let progressEle = document.querySelector('#progress-bar'); + progressEle.setAttribute('max', totalSteps); + + let progressImageEle = document.querySelector('#progress-image'); + progressImageEle.src = BLANK_IMAGE_URL; + progressImageEle.style.display = showProgressImages ? 'initial': 'none'; +} + +function setProgress(step, totalSteps, src) { + let progressEle = document.querySelector('#progress-bar'); + progressEle.setAttribute('value', step); + + if (src) { + let progressImageEle = document.querySelector('#progress-image'); + progressImageEle.src = src; + } +} + +function resetProgress(hide = true) { + if (hide) { + let progressSectionEle = document.querySelector('#progress-section'); + progressSectionEle.style.display = 'none'; + } + let progressEle = document.querySelector('#progress-bar'); + progressEle.setAttribute('value', 0); +} + function toBase64(file) { return new Promise((resolve, reject) => { const r = new FileReader(); @@ -7,17 +113,41 @@ function toBase64(file) { }); } -function appendOutput(src, seed, config) { - let outputNode = document.createElement("figure"); - - let variations = config.with_variations; - if (config.variation_amount > 0) { - variations = (variations ? variations + ',' : '') + seed + ':' + config.variation_amount; +function ondragdream(event) { + let dream = event.target.dataset.dream; + event.dataTransfer.setData("dream", dream); +} + +function seedClick(event) { + // Get element + var image = event.target.closest('figure').querySelector('img'); + var dream = JSON.parse(decodeURIComponent(image.dataset.dream)); + + let form = document.querySelector("#generate-form"); + for (const [k, v] of new FormData(form)) { + if (k == 'initimg') { continue; } + let formElem = form.querySelector(`*[name=${k}]`); + formElem.value = dream[k] !== undefined ? dream[k] : formElem.defaultValue; } - let baseseed = (config.with_variations || config.variation_amount > 0) ? config.seed : seed; - let altText = baseseed + ' | ' + (variations ? variations + ' | ' : '') + config.prompt; + + document.querySelector("#seed").value = dream.seed; + document.querySelector('#iterations').value = 1; // Reset to 1 iteration since we clicked a single image (not a full job) + + // NOTE: leaving this manual for the user for now - it was very confusing with this behavior + // document.querySelector("#with_variations").value = variations || ''; + // if (document.querySelector("#variation_amount").value <= 0) { + // document.querySelector("#variation_amount").value = 0.2; + // } + + saveFields(document.querySelector("#generate-form")); +} + +function appendOutput(src, seed, config, toEnd=false) { + let outputNode = document.createElement("figure"); + let altText = seed.toString() + " | " + config.prompt; // img needs width and height for lazy loading to work + // TODO: store the full config in a data attribute on the image? const figureContents = ` + height="256" + draggable="true" + ondragstart="ondragdream(event, this)" + data-dream="${encodeURIComponent(JSON.stringify(config))}" + data-dreamId="${encodeURIComponent(config.dreamId)}"> -
${seed}
+
${seed}
`; outputNode.innerHTML = figureContents; - let figcaption = outputNode.querySelector('figcaption'); - // Reload image config - figcaption.addEventListener('click', () => { - let form = document.querySelector("#generate-form"); - for (const [k, v] of new FormData(form)) { - if (k == 'initimg') { continue; } - form.querySelector(`*[name=${k}]`).value = config[k]; - } - - document.querySelector("#seed").value = baseseed; - document.querySelector("#with_variations").value = variations || ''; - if (document.querySelector("#variation_amount").value <= 0) { - document.querySelector("#variation_amount").value = 0.2; - } - - saveFields(document.querySelector("#generate-form")); - }); - - document.querySelector("#results").prepend(outputNode); + if (toEnd) { + document.querySelector("#results").append(outputNode); + } else { + document.querySelector("#results").prepend(outputNode); + } + document.querySelector("#no-results-message")?.remove(); } function saveFields(form) { @@ -79,93 +200,109 @@ function clearFields(form) { const BLANK_IMAGE_URL = 'data:image/svg+xml,'; async function generateSubmit(form) { - const prompt = document.querySelector("#prompt").value; - // Convert file data to base64 + // TODO: Should probably uplaod files with formdata or something, and store them in the backend? let formData = Object.fromEntries(new FormData(form)); + if (!formData.enable_generate && !formData.enable_init_image) { + gen_label = document.querySelector("label[for=enable_generate]").innerHTML; + initimg_label = document.querySelector("label[for=enable_init_image]").innerHTML; + alert(`Error: one of "${gen_label}" or "${initimg_label}" must be set`); + } + + formData.initimg_name = formData.initimg.name formData.initimg = formData.initimg.name !== '' ? await toBase64(formData.initimg) : null; - let strength = formData.strength; - let totalSteps = formData.initimg ? Math.floor(strength * formData.steps) : formData.steps; - - let progressSectionEle = document.querySelector('#progress-section'); - progressSectionEle.style.display = 'initial'; - let progressEle = document.querySelector('#progress-bar'); - progressEle.setAttribute('max', totalSteps); - let progressImageEle = document.querySelector('#progress-image'); - progressImageEle.src = BLANK_IMAGE_URL; - - progressImageEle.style.display = {}.hasOwnProperty.call(formData, 'progress_images') ? 'initial': 'none'; - - // Post as JSON, using Fetch streaming to get results - fetch(form.action, { - method: form.method, - body: JSON.stringify(formData), - }).then(async (response) => { - const reader = response.body.getReader(); - - let noOutputs = true; - while (true) { - let {value, done} = await reader.read(); - value = new TextDecoder().decode(value); - if (done) { - progressSectionEle.style.display = 'none'; - break; - } - - for (let event of value.split('\n').filter(e => e !== '')) { - const data = JSON.parse(event); - - if (data.event === 'result') { - noOutputs = false; - appendOutput(data.url, data.seed, data.config); - progressEle.setAttribute('value', 0); - progressEle.setAttribute('max', totalSteps); - } else if (data.event === 'upscaling-started') { - document.getElementById("processing_cnt").textContent=data.processed_file_cnt; - document.getElementById("scaling-inprocess-message").style.display = "block"; - } else if (data.event === 'upscaling-done') { - document.getElementById("scaling-inprocess-message").style.display = "none"; - } else if (data.event === 'step') { - progressEle.setAttribute('value', data.step); - if (data.url) { - progressImageEle.src = data.url; - } - } else if (data.event === 'canceled') { - // avoid alerting as if this were an error case - noOutputs = false; - } - } - } - - // Re-enable form, remove no-results-message - form.querySelector('fieldset').removeAttribute('disabled'); - document.querySelector("#prompt").value = prompt; - document.querySelector('progress').setAttribute('value', '0'); - - if (noOutputs) { - alert("Error occurred while generating."); - } + // Evaluate all checkboxes + let checkboxes = form.querySelectorAll('input[type=checkbox]'); + checkboxes.forEach(function (checkbox) { + if (checkbox.checked) { + formData[checkbox.name] = 'true'; + } + }); + + let strength = formData.strength; + let totalSteps = formData.initimg ? Math.floor(strength * formData.steps) : formData.steps; + let showProgressImages = formData.progress_images; + + // Set enabling flags + + + // Initialize the progress bar + initProgress(totalSteps, showProgressImages); + + // POST, use response to listen for events + fetch(form.action, { + method: form.method, + headers: new Headers({'content-type': 'application/json'}), + body: JSON.stringify(formData), + }) + .then(response => response.json()) + .then(data => { + var jobId = data.jobId; + socket.emit('join_room', { 'room': jobId }); }); - // Disable form while generating form.querySelector('fieldset').setAttribute('disabled',''); - document.querySelector("#prompt").value = `Generating: "${prompt}"`; } -async function fetchRunLog() { - try { - let response = await fetch('/run_log.json') - const data = await response.json(); - for(let item of data.run_log) { - appendOutput(item.url, item.seed, item); - } - } catch (e) { - console.error(e); - } +function fieldSetEnableChecked(event) { + cb = event.target; + fields = cb.closest('fieldset'); + fields.disabled = !cb.checked; } +// Socket listeners +socket.on('job_started', (data) => {}) + +socket.on('dream_result', (data) => { + var jobId = data.jobId; + var dreamId = data.dreamId; + var dreamRequest = data.dreamRequest; + var src = 'api/images/' + dreamId; + + priorResultsLoadState.offset += 1; + appendOutput(src, dreamRequest.seed, dreamRequest); + + resetProgress(false); +}) + +socket.on('dream_progress', (data) => { + // TODO: it'd be nice if we could get a seed reported here, but the generator would need to be updated + var step = data.step; + var totalSteps = data.totalSteps; + var jobId = data.jobId; + var dreamId = data.dreamId; + + var progressType = data.progressType + if (progressType === 'GENERATION') { + var src = data.hasProgressImage ? + 'api/intermediates/' + dreamId + '/' + step + : null; + setProgress(step, totalSteps, src); + } else if (progressType === 'UPSCALING_STARTED') { + // step and totalSteps are used for upscale count on this message + document.getElementById("processing_cnt").textContent = step; + document.getElementById("processing_total").textContent = totalSteps; + document.getElementById("scaling-inprocess-message").style.display = "block"; + } else if (progressType == 'UPSCALING_DONE') { + document.getElementById("scaling-inprocess-message").style.display = "none"; + } +}) + +socket.on('job_canceled', (data) => { + resetForm(); + resetProgress(); +}) + +socket.on('job_done', (data) => { + jobId = data.jobId + socket.emit('leave_room', { 'room': jobId }); + + resetForm(); + resetProgress(); +}) + window.onload = async () => { document.querySelector("#prompt").addEventListener("keydown", (e) => { if (e.key === "Enter" && !e.shiftKey) { @@ -183,7 +320,7 @@ window.onload = async () => { saveFields(e.target.form); }); document.querySelector("#reset-seed").addEventListener('click', (e) => { - document.querySelector("#seed").value = -1; + document.querySelector("#seed").value = 0; saveFields(e.target.form); }); document.querySelector("#reset-all").addEventListener('click', (e) => { @@ -195,13 +332,13 @@ window.onload = async () => { loadFields(document.querySelector("#generate-form")); document.querySelector('#cancel-button').addEventListener('click', () => { - fetch('/cancel').catch(e => { + fetch('/api/cancel').catch(e => { console.error(e); }); }); document.documentElement.addEventListener('keydown', (e) => { if (e.key === "Escape") - fetch('/cancel').catch(err => { + fetch('/api/cancel').catch(err => { console.error(err); }); }); @@ -209,5 +346,51 @@ window.onload = async () => { if (!config.gfpgan_model_exists) { document.querySelector("#gfpgan").style.display = 'none'; } - await fetchRunLog() + + window.addEventListener("scroll", () => { + if ((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) { + loadPriorResults(); + } + }); + + + + // Enable/disable forms by checkboxes + document.querySelectorAll("legend > input[type=checkbox]").forEach(function(cb) { + cb.addEventListener('change', fieldSetEnableChecked); + fieldSetEnableChecked({ target: cb}) + }); + + + // Load some of the previous results + loadPriorResults(); + + // Image drop/upload WIP + /* + let drop = document.getElementById('dropper'); + function ondrop(event) { + let dreamData = event.dataTransfer.getData('dream'); + if (dreamData) { + var dream = JSON.parse(decodeURIComponent(dreamData)); + alert(dream.dreamId); + } + }; + + function ondragenter(event) { + event.preventDefault(); + }; + + function ondragover(event) { + event.preventDefault(); + }; + + function ondragleave(event) { + + } + + drop.addEventListener('drop', ondrop); + drop.addEventListener('dragenter', ondragenter); + drop.addEventListener('dragover', ondragover); + drop.addEventListener('dragleave', ondragleave); + */ }; diff --git a/static/legacy_web/favicon.ico b/static/legacy_web/favicon.ico new file mode 100644 index 0000000000..51eb844a6a Binary files /dev/null and b/static/legacy_web/favicon.ico differ diff --git a/static/legacy_web/index.css b/static/legacy_web/index.css new file mode 100644 index 0000000000..51f0f267c3 --- /dev/null +++ b/static/legacy_web/index.css @@ -0,0 +1,152 @@ +* { + font-family: 'Arial'; + font-size: 100%; +} +body { + font-size: 1em; +} +textarea { + font-size: 0.95em; +} +header, form, #progress-section { + margin-left: auto; + margin-right: auto; + max-width: 1024px; + text-align: center; +} +fieldset { + border: none; + line-height: 2.2em; +} +select, input { + margin-right: 10px; + padding: 2px; +} +input[type=submit] { + background-color: #666; + color: white; +} +input[type=checkbox] { + margin-right: 0px; + width: 20px; + height: 20px; + vertical-align: middle; +} +input#seed { + margin-right: 0px; +} +div { + padding: 10px 10px 10px 10px; +} +header { + margin-bottom: 16px; +} +header h1 { + margin-bottom: 0; + font-size: 2em; +} +#search-box { + display: flex; +} +#scaling-inprocess-message { + font-weight: bold; + font-style: italic; + display: none; +} +#prompt { + flex-grow: 1; + padding: 5px 10px 5px 10px; + border: 1px solid #999; + outline: none; +} +#submit { + padding: 5px 10px 5px 10px; + border: 1px solid #999; +} +#reset-all, #remove-image { + margin-top: 12px; + font-size: 0.8em; + background-color: pink; + border: 1px solid #999; + border-radius: 4px; +} +#results { + text-align: center; + margin: auto; + padding-top: 10px; +} +#results figure { + display: inline-block; + margin: 10px; +} +#results figcaption { + font-size: 0.8em; + padding: 3px; + color: #888; + cursor: pointer; +} +#results img { + border-radius: 5px; + object-fit: cover; +} +#fieldset-config { + line-height:2em; + background-color: #F0F0F0; +} +input[type="number"] { + width: 60px; +} +#seed { + width: 150px; +} +button#reset-seed { + font-size: 1.7em; + background: #efefef; + border: 1px solid #999; + border-radius: 4px; + line-height: 0.8; + margin: 0 10px 0 0; + padding: 0 5px 3px; + vertical-align: middle; +} +label { + white-space: nowrap; +} +#progress-section { + display: none; +} +#progress-image { + width: 30vh; + height: 30vh; +} +#cancel-button { + cursor: pointer; + color: red; +} +#basic-parameters { + background-color: #EEEEEE; +} +#txt2img { + background-color: #DCDCDC; +} +#variations { + background-color: #EEEEEE; +} +#img2img { + background-color: #DCDCDC; +} +#gfpgan { + background-color: #EEEEEE; +} +#progress-section { + background-color: #F5F5F5; +} +.section-header { + text-align: left; + font-weight: bold; + padding: 0 0 0 0; +} +#no-results-message:not(:only-child) { + display: none; +} + diff --git a/static/legacy_web/index.html b/static/legacy_web/index.html new file mode 100644 index 0000000000..5ce8b45baf --- /dev/null +++ b/static/legacy_web/index.html @@ -0,0 +1,129 @@ + + + Stable Diffusion Dream Server + + + + + + + + +
+

Stable Diffusion Dream Server

+
+ For news and support for this web service, visit our GitHub site +
+
+ +
+
+
+ +
+
+
Basic options
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+
+
Image-to-image options
+ + + +
+ + + + +
+
+
Post-processing options
+ + + + + + +
+
+
+
+
+ + +
+ +
+ Postprocessing...1/3 +
+ +
+ +
+
+

No results...

+
+
+
+ + diff --git a/static/legacy_web/index.js b/static/legacy_web/index.js new file mode 100644 index 0000000000..ac68034920 --- /dev/null +++ b/static/legacy_web/index.js @@ -0,0 +1,213 @@ +function toBase64(file) { + return new Promise((resolve, reject) => { + const r = new FileReader(); + r.readAsDataURL(file); + r.onload = () => resolve(r.result); + r.onerror = (error) => reject(error); + }); +} + +function appendOutput(src, seed, config) { + let outputNode = document.createElement("figure"); + + let variations = config.with_variations; + if (config.variation_amount > 0) { + variations = (variations ? variations + ',' : '') + seed + ':' + config.variation_amount; + } + let baseseed = (config.with_variations || config.variation_amount > 0) ? config.seed : seed; + let altText = baseseed + ' | ' + (variations ? variations + ' | ' : '') + config.prompt; + + // img needs width and height for lazy loading to work + const figureContents = ` + + ${altText} + +
${seed}
+ `; + + outputNode.innerHTML = figureContents; + let figcaption = outputNode.querySelector('figcaption'); + + // Reload image config + figcaption.addEventListener('click', () => { + let form = document.querySelector("#generate-form"); + for (const [k, v] of new FormData(form)) { + if (k == 'initimg') { continue; } + form.querySelector(`*[name=${k}]`).value = config[k]; + } + + document.querySelector("#seed").value = baseseed; + document.querySelector("#with_variations").value = variations || ''; + if (document.querySelector("#variation_amount").value <= 0) { + document.querySelector("#variation_amount").value = 0.2; + } + + saveFields(document.querySelector("#generate-form")); + }); + + document.querySelector("#results").prepend(outputNode); +} + +function saveFields(form) { + for (const [k, v] of new FormData(form)) { + if (typeof v !== 'object') { // Don't save 'file' type + localStorage.setItem(k, v); + } + } +} + +function loadFields(form) { + for (const [k, v] of new FormData(form)) { + const item = localStorage.getItem(k); + if (item != null) { + form.querySelector(`*[name=${k}]`).value = item; + } + } +} + +function clearFields(form) { + localStorage.clear(); + let prompt = form.prompt.value; + form.reset(); + form.prompt.value = prompt; +} + +const BLANK_IMAGE_URL = 'data:image/svg+xml,'; +async function generateSubmit(form) { + const prompt = document.querySelector("#prompt").value; + + // Convert file data to base64 + let formData = Object.fromEntries(new FormData(form)); + formData.initimg_name = formData.initimg.name + formData.initimg = formData.initimg.name !== '' ? await toBase64(formData.initimg) : null; + + let strength = formData.strength; + let totalSteps = formData.initimg ? Math.floor(strength * formData.steps) : formData.steps; + + let progressSectionEle = document.querySelector('#progress-section'); + progressSectionEle.style.display = 'initial'; + let progressEle = document.querySelector('#progress-bar'); + progressEle.setAttribute('max', totalSteps); + let progressImageEle = document.querySelector('#progress-image'); + progressImageEle.src = BLANK_IMAGE_URL; + + progressImageEle.style.display = {}.hasOwnProperty.call(formData, 'progress_images') ? 'initial': 'none'; + + // Post as JSON, using Fetch streaming to get results + fetch(form.action, { + method: form.method, + body: JSON.stringify(formData), + }).then(async (response) => { + const reader = response.body.getReader(); + + let noOutputs = true; + while (true) { + let {value, done} = await reader.read(); + value = new TextDecoder().decode(value); + if (done) { + progressSectionEle.style.display = 'none'; + break; + } + + for (let event of value.split('\n').filter(e => e !== '')) { + const data = JSON.parse(event); + + if (data.event === 'result') { + noOutputs = false; + appendOutput(data.url, data.seed, data.config); + progressEle.setAttribute('value', 0); + progressEle.setAttribute('max', totalSteps); + } else if (data.event === 'upscaling-started') { + document.getElementById("processing_cnt").textContent=data.processed_file_cnt; + document.getElementById("scaling-inprocess-message").style.display = "block"; + } else if (data.event === 'upscaling-done') { + document.getElementById("scaling-inprocess-message").style.display = "none"; + } else if (data.event === 'step') { + progressEle.setAttribute('value', data.step); + if (data.url) { + progressImageEle.src = data.url; + } + } else if (data.event === 'canceled') { + // avoid alerting as if this were an error case + noOutputs = false; + } + } + } + + // Re-enable form, remove no-results-message + form.querySelector('fieldset').removeAttribute('disabled'); + document.querySelector("#prompt").value = prompt; + document.querySelector('progress').setAttribute('value', '0'); + + if (noOutputs) { + alert("Error occurred while generating."); + } + }); + + // Disable form while generating + form.querySelector('fieldset').setAttribute('disabled',''); + document.querySelector("#prompt").value = `Generating: "${prompt}"`; +} + +async function fetchRunLog() { + try { + let response = await fetch('/run_log.json') + const data = await response.json(); + for(let item of data.run_log) { + appendOutput(item.url, item.seed, item); + } + } catch (e) { + console.error(e); + } +} + +window.onload = async () => { + document.querySelector("#prompt").addEventListener("keydown", (e) => { + if (e.key === "Enter" && !e.shiftKey) { + const form = e.target.form; + generateSubmit(form); + } + }); + document.querySelector("#generate-form").addEventListener('submit', (e) => { + e.preventDefault(); + const form = e.target; + + generateSubmit(form); + }); + document.querySelector("#generate-form").addEventListener('change', (e) => { + saveFields(e.target.form); + }); + document.querySelector("#reset-seed").addEventListener('click', (e) => { + document.querySelector("#seed").value = -1; + saveFields(e.target.form); + }); + document.querySelector("#reset-all").addEventListener('click', (e) => { + clearFields(e.target.form); + }); + document.querySelector("#remove-image").addEventListener('click', (e) => { + initimg.value=null; + }); + loadFields(document.querySelector("#generate-form")); + + document.querySelector('#cancel-button').addEventListener('click', () => { + fetch('/cancel').catch(e => { + console.error(e); + }); + }); + document.documentElement.addEventListener('keydown', (e) => { + if (e.key === "Escape") + fetch('/cancel').catch(err => { + console.error(err); + }); + }); + + if (!config.gfpgan_model_exists) { + document.querySelector("#gfpgan").style.display = 'none'; + } + await fetchRunLog() +};