diff --git a/.ci/update_windows/update.py b/.ci/update_windows/update.py index 127247b2f..cc79a914e 100755 --- a/.ci/update_windows/update.py +++ b/.ci/update_windows/update.py @@ -62,8 +62,15 @@ except: print("checking out master branch") branch = repo.lookup_branch('master') -ref = repo.lookup_reference(branch.name) -repo.checkout(ref) +if branch is None: + ref = repo.lookup_reference('refs/remotes/origin/master') + repo.checkout(ref) + branch = repo.lookup_branch('master') + if branch is None: + repo.create_branch('master', repo.get(ref.target)) +else: + ref = repo.lookup_reference(branch.name) + repo.checkout(ref) print("pulling latest changes") pull(repo) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 000000000..39d1992d7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,48 @@ +name: Bug Report +description: "Something is broken inside of ComfyUI. (Do not use this if you're just having issues and need help, or if the issue relates to a custom node)" +labels: ["Potential Bug"] +body: + - type: markdown + attributes: + value: | + Before submitting a **Bug Report**, please ensure the following: + + - **1:** You are running the latest version of ComfyUI. + - **2:** You have looked at the existing bug reports and made sure this isn't already reported. + - **3:** You confirmed that the bug is not caused by a custom node. You can disable all custom nodes by passing + `--disable-all-custom-nodes` command line argument. + - **4:** This is an actual bug in ComfyUI, not just a support question. A bug is when you can specify exact + steps to replicate what went wrong and others will be able to repeat your steps and see the same issue happen. + + If unsure, ask on the [ComfyUI Matrix Space](https://app.element.io/#/room/%23comfyui_space%3Amatrix.org) or the [Comfy Org Discord](https://discord.gg/comfyorg) first. + - type: textarea + attributes: + label: Expected Behavior + description: "What you expected to happen." + validations: + required: true + - type: textarea + attributes: + label: Actual Behavior + description: "What actually happened. Please include a screenshot of the issue if possible." + validations: + required: true + - type: textarea + attributes: + label: Steps to Reproduce + description: "Describe how to reproduce the issue. Please be sure to attach a workflow JSON or PNG, ideally one that doesn't require custom nodes to test. If the bug open happens when certain custom nodes are used, most likely that custom node is what has the bug rather than ComfyUI, in which case it should be reported to the node's author." + validations: + required: true + - type: textarea + attributes: + label: Debug Logs + description: "Please copy the output from your terminal logs here." + render: powershell + validations: + required: true + - type: textarea + attributes: + label: Other + description: "Any other additional information you think might be helpful." + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..2c519ede5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: ComfyUI Matrix Space + url: https://app.element.io/#/room/%23comfyui_space%3Amatrix.org + about: The ComfyUI Matrix Space is available for support and general discussion related to ComfyUI (Matrix is like Discord but open source). + - name: Comfy Org Discord + url: https://discord.gg/comfyorg + about: The Comfy Org Discord is available for support and general discussion related to ComfyUI. diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 000000000..419721b63 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,32 @@ +name: Feature Request +description: "You have an idea for something new you would like to see added to ComfyUI's core." +labels: [ "Feature" ] +body: + - type: markdown + attributes: + value: | + Before submitting a **Feature Request**, please ensure the following: + + **1:** You are running the latest version of ComfyUI. + **2:** You have looked to make sure there is not already a feature that does what you need, and there is not already a Feature Request listed for the same idea. + **3:** This is something that makes sense to add to ComfyUI Core, and wouldn't make more sense as a custom node. + + If unsure, ask on the [ComfyUI Matrix Space](https://app.element.io/#/room/%23comfyui_space%3Amatrix.org) or the [Comfy Org Discord](https://discord.gg/comfyorg) first. + - type: textarea + attributes: + label: Feature Idea + description: "Describe the feature you want to see." + validations: + required: true + - type: textarea + attributes: + label: Existing Solutions + description: "Please search through available custom nodes / extensions to see if there are existing custom solutions for this. If so, please link the options you found here as a reference." + validations: + required: false + - type: textarea + attributes: + label: Other + description: "Any other additional information you think might be helpful." + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/user-support.yml b/.github/ISSUE_TEMPLATE/user-support.yml new file mode 100644 index 000000000..df28804c6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/user-support.yml @@ -0,0 +1,32 @@ +name: User Support +description: "Use this if you need help with something, or you're experiencing an issue." +labels: [ "User Support" ] +body: + - type: markdown + attributes: + value: | + Before submitting a **User Report** issue, please ensure the following: + + **1:** You are running the latest version of ComfyUI. + **2:** You have made an effort to find public answers to your question before asking here. In other words, you googled it first, and scrolled through recent help topics. + + If unsure, ask on the [ComfyUI Matrix Space](https://app.element.io/#/room/%23comfyui_space%3Amatrix.org) or the [Comfy Org Discord](https://discord.gg/comfyorg) first. + - type: textarea + attributes: + label: Your question + description: "Post your question here. Please be as detailed as possible." + validations: + required: true + - type: textarea + attributes: + label: Logs + description: "If your question relates to an issue you're experiencing, please go to `Server` -> `Logs` -> potentially set `View Type` to `Debug` as well, then copypaste all the text into here." + render: powershell + validations: + required: false + - type: textarea + attributes: + label: Other + description: "Any other additional information you think might be helpful." + validations: + required: false diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml new file mode 100644 index 000000000..5effbea35 --- /dev/null +++ b/.github/workflows/pylint.yml @@ -0,0 +1,23 @@ +name: Python Linting + +on: [push, pull_request] + +jobs: + pylint: + name: Run Pylint + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.x + + - name: Install Pylint + run: pip install pylint + + - name: Run Pylint + run: pylint --rcfile=.pylintrc $(find . -type f -name "*.py") diff --git a/.github/workflows/stable-release.yml b/.github/workflows/stable-release.yml new file mode 100644 index 000000000..19035c02c --- /dev/null +++ b/.github/workflows/stable-release.yml @@ -0,0 +1,110 @@ + +name: "Release Stable Version" + +on: + push: + tags: + - 'v*' + +jobs: + package_comfy_windows: + permissions: + contents: "write" + packages: "write" + pull-requests: "read" + runs-on: windows-latest + strategy: + matrix: + python_version: [3.11.8] + cuda_version: [121] + steps: + - name: Calculate Minor Version + shell: bash + run: | + # Extract the minor version from the Python version + MINOR_VERSION=$(echo "${{ matrix.python_version }}" | cut -d'.' -f2) + echo "MINOR_VERSION=$MINOR_VERSION" >> $GITHUB_ENV + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python_version }} + + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + persist-credentials: false + - shell: bash + run: | + echo "@echo off + call update_comfyui.bat nopause + echo - + echo This will try to update pytorch and all python dependencies. + echo - + echo If you just want to update normally, close this and run update_comfyui.bat instead. + echo - + pause + ..\python_embeded\python.exe -s -m pip install --upgrade torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu${{ matrix.cuda_version }} -r ../ComfyUI/requirements.txt pygit2 + pause" > update_comfyui_and_python_dependencies.bat + + python -m pip wheel --no-cache-dir torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu${{ matrix.cuda_version }} -r requirements.txt pygit2 -w ./temp_wheel_dir + python -m pip install --no-cache-dir ./temp_wheel_dir/* + echo installed basic + ls -lah temp_wheel_dir + mv temp_wheel_dir cu${{ matrix.cuda_version }}_python_deps + mv cu${{ matrix.cuda_version }}_python_deps ../ + mv update_comfyui_and_python_dependencies.bat ../ + cd .. + pwd + ls + + cp -r ComfyUI ComfyUI_copy + curl https://www.python.org/ftp/python/${{ matrix.python_version }}/python-${{ matrix.python_version }}-embed-amd64.zip -o python_embeded.zip + unzip python_embeded.zip -d python_embeded + cd python_embeded + echo ${{ env.MINOR_VERSION }} + echo 'import site' >> ./python3${{ env.MINOR_VERSION }}._pth + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + ./python.exe get-pip.py + ./python.exe --version + echo "Pip version:" + ./python.exe -m pip --version + + set PATH=$PWD/Scripts:$PATH + echo $PATH + ./python.exe -s -m pip install ../cu${{ matrix.cuda_version }}_python_deps/* + sed -i '1i../ComfyUI' ./python3${{ env.MINOR_VERSION }}._pth + cd .. + + git clone https://github.com/comfyanonymous/taesd + cp taesd/*.pth ./ComfyUI_copy/models/vae_approx/ + + mkdir ComfyUI_windows_portable + mv python_embeded ComfyUI_windows_portable + mv ComfyUI_copy ComfyUI_windows_portable/ComfyUI + + cd ComfyUI_windows_portable + + mkdir update + cp -r ComfyUI/.ci/update_windows/* ./update/ + cp -r ComfyUI/.ci/windows_base_files/* ./ + cp ../update_comfyui_and_python_dependencies.bat ./update/ + + cd .. + + "C:\Program Files\7-Zip\7z.exe" a -t7z -m0=lzma2 -mx=8 -mfb=64 -md=32m -ms=on -mf=BCJ2 ComfyUI_windows_portable.7z ComfyUI_windows_portable + mv ComfyUI_windows_portable.7z ComfyUI/ComfyUI_windows_portable_nvidia.7z + + cd ComfyUI_windows_portable + python_embeded/python.exe -s ComfyUI/main.py --quick-test-for-ci --cpu + + ls + + - name: Upload binaries to release + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ComfyUI_windows_portable_nvidia.7z + tag: ${{ github.ref }} + overwrite: true + prerelease: true + make_latest: false diff --git a/.github/workflows/test-browser.yml b/.github/workflows/test-browser.yml new file mode 100644 index 000000000..7beb0c696 --- /dev/null +++ b/.github/workflows/test-browser.yml @@ -0,0 +1,76 @@ +# This is a temporary action during frontend TS migration. +# This file should be removed after TS migration is completed. +# The browser test is here to ensure TS repo is working the same way as the +# current JS code. +# If you are adding UI feature, please sync your changes to the TS repo: +# huchenlei/ComfyUI_frontend and update test expectation files accordingly. +name: Playwright Browser Tests CI + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout ComfyUI + uses: actions/checkout@v4 + with: + repository: "comfyanonymous/ComfyUI" + path: "ComfyUI" + - name: Checkout ComfyUI_frontend + uses: actions/checkout@v4 + with: + repository: "huchenlei/ComfyUI_frontend" + path: "ComfyUI_frontend" + ref: "fcc54d803e5b6a9b08a462a1d94899318c96dcbb" + - uses: actions/setup-node@v3 + with: + node-version: lts/* + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Install requirements + run: | + python -m pip install --upgrade pip + pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu + pip install -r requirements.txt + pip install wait-for-it + working-directory: ComfyUI + - name: Start ComfyUI server + run: | + python main.py --cpu 2>&1 | tee console_output.log & + wait-for-it --service 127.0.0.1:8188 -t 600 + working-directory: ComfyUI + - name: Install ComfyUI_frontend dependencies + run: | + npm ci + working-directory: ComfyUI_frontend + - name: Install Playwright Browsers + run: npx playwright install --with-deps + working-directory: ComfyUI_frontend + - name: Run Playwright tests + run: npx playwright test + working-directory: ComfyUI_frontend + - name: Check for unhandled exceptions in server log + run: | + if grep -qE "Exception|Error" console_output.log; then + echo "Unhandled exception/error found in server log." + exit 1 + fi + working-directory: ComfyUI + - uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report + path: ComfyUI_frontend/playwright-report/ + retention-days: 30 + - uses: actions/upload-artifact@v4 + if: always() + with: + name: console-output + path: ComfyUI/console_output.log + retention-days: 30 diff --git a/.github/workflows/test-ui.yaml b/.github/workflows/test-ui.yaml index 4b8b97934..d947e9d5f 100644 --- a/.github/workflows/test-ui.yaml +++ b/.github/workflows/test-ui.yaml @@ -24,3 +24,7 @@ jobs: npm run test:generate npm test -- --verbose working-directory: ./tests-ui + - name: Run Unit Tests + run: | + pip install -r tests-unit/requirements.txt + python -m pytest tests-unit diff --git a/.github/workflows/windows_release_dependencies.yml b/.github/workflows/windows_release_dependencies.yml index ffd3e2216..8d3a8665d 100644 --- a/.github/workflows/windows_release_dependencies.yml +++ b/.github/workflows/windows_release_dependencies.yml @@ -8,11 +8,16 @@ on: required: false type: string default: "" + extra_dependencies: + description: 'extra dependencies' + required: false + type: string + default: "\"numpy<2\"" cu: description: 'cuda version' required: true type: string - default: "121" + default: "124" python_minor: description: 'python minor version' @@ -24,7 +29,7 @@ on: description: 'python patch version' required: true type: string - default: "8" + default: "9" # push: # branches: # - master @@ -33,8 +38,8 @@ jobs: build_dependencies: runs-on: windows-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: 3.${{ inputs.python_minor }}.${{ inputs.python_patch }} @@ -51,14 +56,14 @@ jobs: ..\python_embeded\python.exe -s -m pip install --upgrade torch torchvision torchaudio ${{ inputs.xformers }} --extra-index-url https://download.pytorch.org/whl/cu${{ inputs.cu }} -r ../ComfyUI/requirements.txt pygit2 pause" > update_comfyui_and_python_dependencies.bat - python -m pip wheel --no-cache-dir torch torchvision torchaudio ${{ inputs.xformers }} --extra-index-url https://download.pytorch.org/whl/cu${{ inputs.cu }} -r requirements.txt pygit2 -w ./temp_wheel_dir + python -m pip wheel --no-cache-dir torch torchvision torchaudio ${{ inputs.xformers }} ${{ inputs.extra_dependencies }} --extra-index-url https://download.pytorch.org/whl/cu${{ inputs.cu }} -r requirements.txt pygit2 -w ./temp_wheel_dir python -m pip install --no-cache-dir ./temp_wheel_dir/* echo installed basic ls -lah temp_wheel_dir mv temp_wheel_dir cu${{ inputs.cu }}_python_deps tar cf cu${{ inputs.cu }}_python_deps.tar cu${{ inputs.cu }}_python_deps - - uses: actions/cache/save@v3 + - uses: actions/cache/save@v4 with: path: | cu${{ inputs.cu }}_python_deps.tar diff --git a/.github/workflows/windows_release_nightly_pytorch.yml b/.github/workflows/windows_release_nightly_pytorch.yml index fa24a985c..ba388cd44 100644 --- a/.github/workflows/windows_release_nightly_pytorch.yml +++ b/.github/workflows/windows_release_nightly_pytorch.yml @@ -19,7 +19,7 @@ on: description: 'python patch version' required: true type: string - default: "3" + default: "4" # push: # branches: # - master @@ -32,11 +32,11 @@ jobs: pull-requests: "read" runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 persist-credentials: false - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: 3.${{ inputs.python_minor }}.${{ inputs.python_patch }} - shell: bash @@ -49,7 +49,7 @@ jobs: echo 'import site' >> ./python3${{ inputs.python_minor }}._pth curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py ./python.exe get-pip.py - python -m pip wheel torch torchvision torchaudio mpmath==1.3.0 numpy==1.26.4 --pre --extra-index-url https://download.pytorch.org/whl/nightly/cu${{ inputs.cu }} -r ../ComfyUI/requirements.txt pygit2 -w ../temp_wheel_dir + python -m pip wheel torch torchvision torchaudio --pre --extra-index-url https://download.pytorch.org/whl/nightly/cu${{ inputs.cu }} -r ../ComfyUI/requirements.txt pygit2 -w ../temp_wheel_dir ls ../temp_wheel_dir ./python.exe -s -m pip install --pre ../temp_wheel_dir/* sed -i '1i../ComfyUI' ./python3${{ inputs.python_minor }}._pth @@ -73,7 +73,7 @@ jobs: pause" > ./update/update_comfyui_and_python_dependencies.bat cd .. - "C:\Program Files\7-Zip\7z.exe" a -t7z -m0=lzma -mx=8 -mfb=64 -md=32m -ms=on -mf=BCJ2 ComfyUI_windows_portable_nightly_pytorch.7z ComfyUI_windows_portable_nightly_pytorch + "C:\Program Files\7-Zip\7z.exe" a -t7z -m0=lzma2 -mx=8 -mfb=64 -md=32m -ms=on -mf=BCJ2 ComfyUI_windows_portable_nightly_pytorch.7z ComfyUI_windows_portable_nightly_pytorch mv ComfyUI_windows_portable_nightly_pytorch.7z ComfyUI/ComfyUI_windows_portable_nvidia_or_cpu_nightly_pytorch.7z cd ComfyUI_windows_portable_nightly_pytorch diff --git a/.github/workflows/windows_release_package.yml b/.github/workflows/windows_release_package.yml index 4e3cdabd2..5aed73e55 100644 --- a/.github/workflows/windows_release_package.yml +++ b/.github/workflows/windows_release_package.yml @@ -7,7 +7,7 @@ on: description: 'cuda version' required: true type: string - default: "121" + default: "124" python_minor: description: 'python minor version' @@ -19,7 +19,7 @@ on: description: 'python patch version' required: true type: string - default: "8" + default: "9" # push: # branches: # - master @@ -32,7 +32,7 @@ jobs: pull-requests: "read" runs-on: windows-latest steps: - - uses: actions/cache/restore@v3 + - uses: actions/cache/restore@v4 id: cache with: path: | @@ -48,7 +48,7 @@ jobs: pwd ls - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 persist-credentials: false @@ -82,7 +82,7 @@ jobs: cd .. - "C:\Program Files\7-Zip\7z.exe" a -t7z -m0=lzma -mx=8 -mfb=64 -md=32m -ms=on -mf=BCJ2 ComfyUI_windows_portable.7z ComfyUI_windows_portable + "C:\Program Files\7-Zip\7z.exe" a -t7z -m0=lzma2 -mx=8 -mfb=64 -md=32m -ms=on -mf=BCJ2 ComfyUI_windows_portable.7z ComfyUI_windows_portable mv ComfyUI_windows_portable.7z ComfyUI/new_ComfyUI_windows_portable_nvidia_cu${{ inputs.cu }}_or_cpu.7z cd ComfyUI_windows_portable diff --git a/.gitignore b/.gitignore index 9f0389241..5092c98f4 100644 --- a/.gitignore +++ b/.gitignore @@ -9,10 +9,13 @@ __pycache__/ !custom_nodes/example_node.py.example extra_model_paths.yaml /.vs +.vscode/ .idea/ venv/ /web/extensions/* !/web/extensions/logging.js.example !/web/extensions/core/ /tests-ui/data/object_info.json -/user/ \ No newline at end of file +/user/ +*.log +web_custom_versions/ \ No newline at end of file diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 000000000..a5da56e57 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,3 @@ +[MESSAGES CONTROL] +disable=all +enable=eval-used diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..048f127e7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# Contributing to ComfyUI + +Welcome, and thank you for your interest in contributing to ComfyUI! + +There are several ways in which you can contribute, beyond writing code. The goal of this document is to provide a high-level overview of how you can get involved. + +## Asking Questions + +Have a question? Instead of opening an issue, please ask on [Discord](https://comfy.org/discord) or [Matrix](https://app.element.io/#/room/%23comfyui_space%3Amatrix.org) channels. Our team and the community will help you. + +## Providing Feedback + +Your comments and feedback are welcome, and the development team is available via a handful of different channels. + +See the `#bug-report`, `#feature-request` and `#feedback` channels on Discord. + +## Reporting Issues + +Have you identified a reproducible problem in ComfyUI? Do you have a feature request? We want to hear about it! Here's how you can report your issue as effectively as possible. + + +### Look For an Existing Issue + +Before you create a new issue, please do a search in [open issues](https://github.com/comfyanonymous/ComfyUI/issues) to see if the issue or feature request has already been filed. + +If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment: + +* 👍 - upvote +* 👎 - downvote + +If you cannot find an existing issue that describes your bug or feature, create a new issue. We have an issue template in place to organize new issues. + + +### Creating Pull Requests + +* Please refer to the article on [creating pull requests](https://github.com/comfyanonymous/ComfyUI/wiki/How-to-Contribute-Code) and contributing to this project. + + +## Thank You + +Your contributions to open source, large or small, make great projects like this possible. Thank you for taking the time to contribute. diff --git a/README.md b/README.md index 4620dfa0c..30ce3e5df 100644 --- a/README.md +++ b/README.md @@ -11,16 +11,16 @@ This ui will let you design and execute advanced stable diffusion pipelines usin ## Features - Nodes/graph/flowchart interface to experiment and create complex Stable Diffusion workflows without needing to code anything. -- Fully supports SD1.x, SD2.x, [SDXL](https://comfyanonymous.github.io/ComfyUI_examples/sdxl/), [Stable Video Diffusion](https://comfyanonymous.github.io/ComfyUI_examples/video/), [Stable Cascade](https://comfyanonymous.github.io/ComfyUI_examples/stable_cascade/) and [SD3](https://comfyanonymous.github.io/ComfyUI_examples/sd3/) +- Fully supports SD1.x, SD2.x, [SDXL](https://comfyanonymous.github.io/ComfyUI_examples/sdxl/), [Stable Video Diffusion](https://comfyanonymous.github.io/ComfyUI_examples/video/), [Stable Cascade](https://comfyanonymous.github.io/ComfyUI_examples/stable_cascade/), [SD3](https://comfyanonymous.github.io/ComfyUI_examples/sd3/) and [Stable Audio](https://comfyanonymous.github.io/ComfyUI_examples/audio/) - Asynchronous Queue system - Many optimizations: Only re-executes the parts of the workflow that changes between executions. -- Command line option: ```--lowvram``` to make it work on GPUs with less than 3GB vram (enabled automatically on GPUs with low vram) +- Smart memory management: can automatically run models on GPUs with as low as 1GB vram. - Works even if you don't have a GPU with: ```--cpu``` (slow) - Can load ckpt, safetensors and diffusers models/checkpoints. Standalone VAEs and CLIP models. - Embeddings/Textual inversion - [Loras (regular, locon and loha)](https://comfyanonymous.github.io/ComfyUI_examples/lora/) - [Hypernetworks](https://comfyanonymous.github.io/ComfyUI_examples/hypernetworks/) -- Loading full workflows (with seeds) from generated PNG files. +- Loading full workflows (with seeds) from generated PNG, WebP and FLAC files. - Saving/Loading workflows as Json files. - Nodes interface can be used to create complex workflows like one for [Hires fix](https://comfyanonymous.github.io/ComfyUI_examples/2_pass_txt2img/) or much more advanced ones. - [Area Composition](https://comfyanonymous.github.io/ComfyUI_examples/area_composition/) @@ -32,6 +32,8 @@ This ui will let you design and execute advanced stable diffusion pipelines usin - [Model Merging](https://comfyanonymous.github.io/ComfyUI_examples/model_merging/) - [LCM models and Loras](https://comfyanonymous.github.io/ComfyUI_examples/lcm/) - [SDXL Turbo](https://comfyanonymous.github.io/ComfyUI_examples/sdturbo/) +- [AuraFlow](https://comfyanonymous.github.io/ComfyUI_examples/aura_flow/) +- [HunyuanDiT](https://comfyanonymous.github.io/ComfyUI_examples/hunyuan_dit/) - Latent previews with [TAESD](#how-to-show-high-quality-previews) - Starts up very fast. - Works fully offline: will never download anything. @@ -76,7 +78,7 @@ Ctrl can also be replaced with Cmd instead for macOS users There is a portable standalone build for Windows that should work for running on Nvidia GPUs or for running on your CPU only on the [releases page](https://github.com/comfyanonymous/ComfyUI/releases). -### [Direct link to download](https://github.com/comfyanonymous/ComfyUI/releases/download/latest/ComfyUI_windows_portable_nvidia_cu121_or_cpu.7z) +### [Direct link to download](https://github.com/comfyanonymous/ComfyUI/releases/latest/download/ComfyUI_windows_portable_nvidia.7z) Simply download, extract with [7-Zip](https://7-zip.org) and run. Make sure you put your Stable Diffusion checkpoints/models (the huge ckpt/safetensors files) in: ComfyUI\models\checkpoints @@ -251,12 +253,11 @@ Use `--tls-keyfile key.pem --tls-certfile cert.pem` to enable TLS/SSL, the app w [Matrix space: #comfyui_space:matrix.org](https://app.element.io/#/room/%23comfyui_space%3Amatrix.org) (it's like discord but open source). +See also: [https://www.comfy.org/](https://www.comfy.org/) + # QA -### Why did you make this? +### Which GPU should I buy for this? -I wanted to learn how Stable Diffusion worked in detail. I also wanted something clean and powerful that would let me experiment with SD without restrictions. +[See this page for some recommendations](https://github.com/comfyanonymous/ComfyUI/wiki/Which-GPU-should-I-buy-for-ComfyUI) -### Who is this for? - -This is for anyone that wants to make complex workflows with SD or that wants to learn more how SD works. The interface follows closely how SD works and the code should be much more simple to understand than other SD UIs. diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/app/frontend_management.py b/app/frontend_management.py new file mode 100644 index 000000000..fb57b23f3 --- /dev/null +++ b/app/frontend_management.py @@ -0,0 +1,188 @@ +from __future__ import annotations +import argparse +import logging +import os +import re +import tempfile +import zipfile +from dataclasses import dataclass +from functools import cached_property +from pathlib import Path +from typing import TypedDict + +import requests +from typing_extensions import NotRequired +from comfy.cli_args import DEFAULT_VERSION_STRING + + +REQUEST_TIMEOUT = 10 # seconds + + +class Asset(TypedDict): + url: str + + +class Release(TypedDict): + id: int + tag_name: str + name: str + prerelease: bool + created_at: str + published_at: str + body: str + assets: NotRequired[list[Asset]] + + +@dataclass +class FrontEndProvider: + owner: str + repo: str + + @property + def folder_name(self) -> str: + return f"{self.owner}_{self.repo}" + + @property + def release_url(self) -> str: + return f"https://api.github.com/repos/{self.owner}/{self.repo}/releases" + + @cached_property + def all_releases(self) -> list[Release]: + releases = [] + api_url = self.release_url + while api_url: + response = requests.get(api_url, timeout=REQUEST_TIMEOUT) + response.raise_for_status() # Raises an HTTPError if the response was an error + releases.extend(response.json()) + # GitHub uses the Link header to provide pagination links. Check if it exists and update api_url accordingly. + if "next" in response.links: + api_url = response.links["next"]["url"] + else: + api_url = None + return releases + + @cached_property + def latest_release(self) -> Release: + latest_release_url = f"{self.release_url}/latest" + response = requests.get(latest_release_url, timeout=REQUEST_TIMEOUT) + response.raise_for_status() # Raises an HTTPError if the response was an error + return response.json() + + def get_release(self, version: str) -> Release: + if version == "latest": + return self.latest_release + else: + for release in self.all_releases: + if release["tag_name"] in [version, f"v{version}"]: + return release + raise ValueError(f"Version {version} not found in releases") + + +def download_release_asset_zip(release: Release, destination_path: str) -> None: + """Download dist.zip from github release.""" + asset_url = None + for asset in release.get("assets", []): + if asset["name"] == "dist.zip": + asset_url = asset["url"] + break + + if not asset_url: + raise ValueError("dist.zip not found in the release assets") + + # Use a temporary file to download the zip content + with tempfile.TemporaryFile() as tmp_file: + headers = {"Accept": "application/octet-stream"} + response = requests.get( + asset_url, headers=headers, allow_redirects=True, timeout=REQUEST_TIMEOUT + ) + response.raise_for_status() # Ensure we got a successful response + + # Write the content to the temporary file + tmp_file.write(response.content) + + # Go back to the beginning of the temporary file + tmp_file.seek(0) + + # Extract the zip file content to the destination path + with zipfile.ZipFile(tmp_file, "r") as zip_ref: + zip_ref.extractall(destination_path) + + +class FrontendManager: + DEFAULT_FRONTEND_PATH = str(Path(__file__).parents[1] / "web") + CUSTOM_FRONTENDS_ROOT = str(Path(__file__).parents[1] / "web_custom_versions") + + @classmethod + def parse_version_string(cls, value: str) -> tuple[str, str, str]: + """ + Args: + value (str): The version string to parse. + + Returns: + tuple[str, str]: A tuple containing provider name and version. + + Raises: + argparse.ArgumentTypeError: If the version string is invalid. + """ + VERSION_PATTERN = r"^([a-zA-Z0-9][a-zA-Z0-9-]{0,38})/([a-zA-Z0-9_.-]+)@(v?\d+\.\d+\.\d+|latest)$" + match_result = re.match(VERSION_PATTERN, value) + if match_result is None: + raise argparse.ArgumentTypeError(f"Invalid version string: {value}") + + return match_result.group(1), match_result.group(2), match_result.group(3) + + @classmethod + def init_frontend_unsafe(cls, version_string: str) -> str: + """ + Initializes the frontend for the specified version. + + Args: + version_string (str): The version string. + + Returns: + str: The path to the initialized frontend. + + Raises: + Exception: If there is an error during the initialization process. + main error source might be request timeout or invalid URL. + """ + if version_string == DEFAULT_VERSION_STRING: + return cls.DEFAULT_FRONTEND_PATH + + repo_owner, repo_name, version = cls.parse_version_string(version_string) + provider = FrontEndProvider(repo_owner, repo_name) + release = provider.get_release(version) + + semantic_version = release["tag_name"].lstrip("v") + web_root = str( + Path(cls.CUSTOM_FRONTENDS_ROOT) / provider.folder_name / semantic_version + ) + if not os.path.exists(web_root): + os.makedirs(web_root, exist_ok=True) + logging.info( + "Downloading frontend(%s) version(%s) to (%s)", + provider.folder_name, + semantic_version, + web_root, + ) + logging.debug(release) + download_release_asset_zip(release, destination_path=web_root) + return web_root + + @classmethod + def init_frontend(cls, version_string: str) -> str: + """ + Initializes the frontend with the specified version string. + + Args: + version_string (str): The version string to initialize the frontend with. + + Returns: + str: The path of the initialized frontend. + """ + try: + return cls.init_frontend_unsafe(version_string) + except Exception as e: + logging.error("Failed to initialize frontend: %s", e) + logging.info("Falling back to the default frontend.") + return cls.DEFAULT_FRONTEND_PATH diff --git a/app/user_manager.py b/app/user_manager.py index 209094af1..53dff18b7 100644 --- a/app/user_manager.py +++ b/app/user_manager.py @@ -2,6 +2,8 @@ import json import os import re import uuid +import glob +import shutil from aiohttp import web from comfy.cli_args import args from folder_paths import user_directory @@ -56,16 +58,16 @@ class UserManager(): if os.path.commonpath((root_dir, user_root)) != root_dir: return None - parent = user_root - if file is not None: # prevent leaving /{type}/{user} path = os.path.abspath(os.path.join(user_root, file)) if os.path.commonpath((user_root, path)) != user_root: return None + parent = os.path.split(path)[0] + if create_dir and not os.path.exists(parent): - os.mkdir(parent) + os.makedirs(parent, exist_ok=True) return path @@ -108,33 +110,96 @@ class UserManager(): user_id = self.add_user(username) return web.json_response(user_id) - @routes.get("/userdata/{file}") - async def getuserdata(request): - file = request.match_info.get("file", None) - if not file: + @routes.get("/userdata") + async def listuserdata(request): + directory = request.rel_url.query.get('dir', '') + if not directory: return web.Response(status=400) - path = self.get_request_user_filepath(request, file) + path = self.get_request_user_filepath(request, directory) if not path: return web.Response(status=403) if not os.path.exists(path): return web.Response(status=404) - return web.FileResponse(path) + recurse = request.rel_url.query.get('recurse', '').lower() == "true" + results = glob.glob(os.path.join( + glob.escape(path), '**/*'), recursive=recurse) + results = [os.path.relpath(x, path) for x in results if os.path.isfile(x)] + + split_path = request.rel_url.query.get('split', '').lower() == "true" + if split_path: + results = [[x] + x.split(os.sep) for x in results] - @routes.post("/userdata/{file}") - async def post_userdata(request): - file = request.match_info.get("file", None) + return web.json_response(results) + + def get_user_data_path(request, check_exists = False, param = "file"): + file = request.match_info.get(param, None) if not file: return web.Response(status=400) path = self.get_request_user_filepath(request, file) if not path: return web.Response(status=403) + + if check_exists and not os.path.exists(path): + return web.Response(status=404) + + return path + + @routes.get("/userdata/{file}") + async def getuserdata(request): + path = get_user_data_path(request, check_exists=True) + if not isinstance(path, str): + return path + + return web.FileResponse(path) + + @routes.post("/userdata/{file}") + async def post_userdata(request): + path = get_user_data_path(request) + if not isinstance(path, str): + return path + + overwrite = request.query["overwrite"] != "false" + if not overwrite and os.path.exists(path): + return web.Response(status=409) body = await request.read() + with open(path, "wb") as f: f.write(body) - return web.Response(status=200) + resp = os.path.relpath(path, self.get_request_user_filepath(request, None)) + return web.json_response(resp) + + @routes.delete("/userdata/{file}") + async def delete_userdata(request): + path = get_user_data_path(request, check_exists=True) + if not isinstance(path, str): + return path + + os.remove(path) + + return web.Response(status=204) + + @routes.post("/userdata/{file}/move/{dest}") + async def move_userdata(request): + source = get_user_data_path(request, check_exists=True) + if not isinstance(source, str): + return source + + dest = get_user_data_path(request, check_exists=False, param="dest") + if not isinstance(source, str): + return dest + + overwrite = request.query["overwrite"] != "false" + if not overwrite and os.path.exists(dest): + return web.Response(status=409) + + print(f"moving '{source}' -> '{dest}'") + shutil.move(source, dest) + + resp = os.path.relpath(dest, self.get_request_user_filepath(request, None)) + return web.json_response(resp) diff --git a/comfy/cldm/cldm.py b/comfy/cldm/cldm.py index 28076dd92..9ec64a227 100644 --- a/comfy/cldm/cldm.py +++ b/comfy/cldm/cldm.py @@ -13,7 +13,47 @@ from ..ldm.modules.diffusionmodules.util import ( from ..ldm.modules.attention import SpatialTransformer from ..ldm.modules.diffusionmodules.openaimodel import UNetModel, TimestepEmbedSequential, ResBlock, Downsample from ..ldm.util import exists +from .control_types import UNION_CONTROLNET_TYPES +from collections import OrderedDict import comfy.ops +from comfy.ldm.modules.attention import optimized_attention + +class OptimizedAttention(nn.Module): + def __init__(self, c, nhead, dropout=0.0, dtype=None, device=None, operations=None): + super().__init__() + self.heads = nhead + self.c = c + + self.in_proj = operations.Linear(c, c * 3, bias=True, dtype=dtype, device=device) + self.out_proj = operations.Linear(c, c, bias=True, dtype=dtype, device=device) + + def forward(self, x): + x = self.in_proj(x) + q, k, v = x.split(self.c, dim=2) + out = optimized_attention(q, k, v, self.heads) + return self.out_proj(out) + +class QuickGELU(nn.Module): + def forward(self, x: torch.Tensor): + return x * torch.sigmoid(1.702 * x) + +class ResBlockUnionControlnet(nn.Module): + def __init__(self, dim, nhead, dtype=None, device=None, operations=None): + super().__init__() + self.attn = OptimizedAttention(dim, nhead, dtype=dtype, device=device, operations=operations) + self.ln_1 = operations.LayerNorm(dim, dtype=dtype, device=device) + self.mlp = nn.Sequential( + OrderedDict([("c_fc", operations.Linear(dim, dim * 4, dtype=dtype, device=device)), ("gelu", QuickGELU()), + ("c_proj", operations.Linear(dim * 4, dim, dtype=dtype, device=device))])) + self.ln_2 = operations.LayerNorm(dim, dtype=dtype, device=device) + + def attention(self, x: torch.Tensor): + return self.attn(x) + + def forward(self, x: torch.Tensor): + x = x + self.attention(self.ln_1(x)) + x = x + self.mlp(self.ln_2(x)) + return x class ControlledUnetModel(UNetModel): #implemented in the ldm unet @@ -53,6 +93,7 @@ class ControlNet(nn.Module): transformer_depth_middle=None, transformer_depth_output=None, attn_precision=None, + union_controlnet_num_control_type=None, device=None, operations=comfy.ops.disable_weight_init, **kwargs, @@ -280,6 +321,65 @@ class ControlNet(nn.Module): self.middle_block_out = self.make_zero_conv(ch, operations=operations, dtype=self.dtype, device=device) self._feature_size += ch + if union_controlnet_num_control_type is not None: + self.num_control_type = union_controlnet_num_control_type + num_trans_channel = 320 + num_trans_head = 8 + num_trans_layer = 1 + num_proj_channel = 320 + # task_scale_factor = num_trans_channel ** 0.5 + self.task_embedding = nn.Parameter(torch.empty(self.num_control_type, num_trans_channel, dtype=self.dtype, device=device)) + + self.transformer_layes = nn.Sequential(*[ResBlockUnionControlnet(num_trans_channel, num_trans_head, dtype=self.dtype, device=device, operations=operations) for _ in range(num_trans_layer)]) + self.spatial_ch_projs = operations.Linear(num_trans_channel, num_proj_channel, dtype=self.dtype, device=device) + #----------------------------------------------------------------------------------------------------- + + control_add_embed_dim = 256 + class ControlAddEmbedding(nn.Module): + def __init__(self, in_dim, out_dim, num_control_type, dtype=None, device=None, operations=None): + super().__init__() + self.num_control_type = num_control_type + self.in_dim = in_dim + self.linear_1 = operations.Linear(in_dim * num_control_type, out_dim, dtype=dtype, device=device) + self.linear_2 = operations.Linear(out_dim, out_dim, dtype=dtype, device=device) + def forward(self, control_type, dtype, device): + c_type = torch.zeros((self.num_control_type,), device=device) + c_type[control_type] = 1.0 + c_type = timestep_embedding(c_type.flatten(), self.in_dim, repeat_only=False).to(dtype).reshape((-1, self.num_control_type * self.in_dim)) + return self.linear_2(torch.nn.functional.silu(self.linear_1(c_type))) + + self.control_add_embedding = ControlAddEmbedding(control_add_embed_dim, time_embed_dim, self.num_control_type, dtype=self.dtype, device=device, operations=operations) + else: + self.task_embedding = None + self.control_add_embedding = None + + def union_controlnet_merge(self, hint, control_type, emb, context): + # Equivalent to: https://github.com/xinsir6/ControlNetPlus/tree/main + inputs = [] + condition_list = [] + + for idx in range(min(1, len(control_type))): + controlnet_cond = self.input_hint_block(hint[idx], emb, context) + feat_seq = torch.mean(controlnet_cond, dim=(2, 3)) + if idx < len(control_type): + feat_seq += self.task_embedding[control_type[idx]].to(dtype=feat_seq.dtype, device=feat_seq.device) + + inputs.append(feat_seq.unsqueeze(1)) + condition_list.append(controlnet_cond) + + x = torch.cat(inputs, dim=1) + x = self.transformer_layes(x) + controlnet_cond_fuser = None + for idx in range(len(control_type)): + alpha = self.spatial_ch_projs(x[:, idx]) + alpha = alpha.unsqueeze(-1).unsqueeze(-1) + o = condition_list[idx] + alpha + if controlnet_cond_fuser is None: + controlnet_cond_fuser = o + else: + controlnet_cond_fuser += o + return controlnet_cond_fuser + def make_zero_conv(self, channels, operations=None, dtype=None, device=None): return TimestepEmbedSequential(operations.conv_nd(self.dims, channels, channels, 1, padding=0, dtype=dtype, device=device)) @@ -287,9 +387,33 @@ class ControlNet(nn.Module): t_emb = timestep_embedding(timesteps, self.model_channels, repeat_only=False).to(x.dtype) emb = self.time_embed(t_emb) - guided_hint = self.input_hint_block(hint, emb, context) + guided_hint = None + if self.control_add_embedding is not None: #Union Controlnet + control_type = kwargs.get("control_type", []) - outs = [] + if any([c >= self.num_control_type for c in control_type]): + max_type = max(control_type) + max_type_name = { + v: k for k, v in UNION_CONTROLNET_TYPES.items() + }[max_type] + raise ValueError( + f"Control type {max_type_name}({max_type}) is out of range for the number of control types" + + f"({self.num_control_type}) supported.\n" + + "Please consider using the ProMax ControlNet Union model.\n" + + "https://huggingface.co/xinsir/controlnet-union-sdxl-1.0/tree/main" + ) + + emb += self.control_add_embedding(control_type, emb.dtype, emb.device) + if len(control_type) > 0: + if len(hint.shape) < 5: + hint = hint.unsqueeze(dim=0) + guided_hint = self.union_controlnet_merge(hint, control_type, emb, context) + + if guided_hint is None: + guided_hint = self.input_hint_block(hint, emb, context) + + out_output = [] + out_middle = [] hs = [] if self.num_classes is not None: @@ -304,10 +428,10 @@ class ControlNet(nn.Module): guided_hint = None else: h = module(h, emb, context) - outs.append(zero_conv(h, emb, context)) + out_output.append(zero_conv(h, emb, context)) h = self.middle_block(h, emb, context) - outs.append(self.middle_block_out(h, emb, context)) + out_middle.append(self.middle_block_out(h, emb, context)) - return outs + return {"middle": out_middle, "output": out_output} diff --git a/comfy/cldm/control_types.py b/comfy/cldm/control_types.py new file mode 100644 index 000000000..4128631a3 --- /dev/null +++ b/comfy/cldm/control_types.py @@ -0,0 +1,10 @@ +UNION_CONTROLNET_TYPES = { + "openpose": 0, + "depth": 1, + "hed/pidi/scribble/ted": 2, + "canny/lineart/anime_lineart/mlsd": 3, + "normal": 4, + "segment": 5, + "tile": 6, + "repaint": 7, +} diff --git a/comfy/cldm/mmdit.py b/comfy/cldm/mmdit.py new file mode 100644 index 000000000..025c2fb5d --- /dev/null +++ b/comfy/cldm/mmdit.py @@ -0,0 +1,77 @@ +import torch +from typing import Dict, Optional +import comfy.ldm.modules.diffusionmodules.mmdit + +class ControlNet(comfy.ldm.modules.diffusionmodules.mmdit.MMDiT): + def __init__( + self, + num_blocks = None, + dtype = None, + device = None, + operations = None, + **kwargs, + ): + super().__init__(dtype=dtype, device=device, operations=operations, final_layer=False, num_blocks=num_blocks, **kwargs) + # controlnet_blocks + self.controlnet_blocks = torch.nn.ModuleList([]) + for _ in range(len(self.joint_blocks)): + self.controlnet_blocks.append(operations.Linear(self.hidden_size, self.hidden_size, device=device, dtype=dtype)) + + self.pos_embed_input = comfy.ldm.modules.diffusionmodules.mmdit.PatchEmbed( + None, + self.patch_size, + self.in_channels, + self.hidden_size, + bias=True, + strict_img_size=False, + dtype=dtype, + device=device, + operations=operations + ) + + def forward( + self, + x: torch.Tensor, + timesteps: torch.Tensor, + y: Optional[torch.Tensor] = None, + context: Optional[torch.Tensor] = None, + hint = None, + ) -> torch.Tensor: + + #weird sd3 controlnet specific stuff + y = torch.zeros_like(y) + + if self.context_processor is not None: + context = self.context_processor(context) + + hw = x.shape[-2:] + x = self.x_embedder(x) + self.cropped_pos_embed(hw, device=x.device).to(dtype=x.dtype, device=x.device) + x += self.pos_embed_input(hint) + + c = self.t_embedder(timesteps, dtype=x.dtype) + if y is not None and self.y_embedder is not None: + y = self.y_embedder(y) + c = c + y + + if context is not None: + context = self.context_embedder(context) + + output = [] + + blocks = len(self.joint_blocks) + for i in range(blocks): + context, x = self.joint_blocks[i]( + context, + x, + c=c, + use_checkpoint=self.use_checkpoint, + ) + + out = self.controlnet_blocks[i](x) + count = self.depth // blocks + if i == blocks - 1: + count -= 1 + for j in range(count): + output.append(out) + + return {"output": output} diff --git a/comfy/cli_args.py b/comfy/cli_args.py index fb0d37ce7..2397de3d6 100644 --- a/comfy/cli_args.py +++ b/comfy/cli_args.py @@ -1,7 +1,10 @@ import argparse import enum +import os +from typing import Optional import comfy.options + class EnumAction(argparse.Action): """ Argparse action for handling Enums @@ -109,6 +112,7 @@ vram_group.add_argument("--lowvram", action="store_true", help="Split the unet i vram_group.add_argument("--novram", action="store_true", help="When lowvram isn't enough.") vram_group.add_argument("--cpu", action="store_true", help="To use the CPU for everything (slow).") +parser.add_argument("--default-hashing-function", type=str, choices=['md5', 'sha1', 'sha256', 'sha512'], default='sha256', help="Allows you to choose the hash function to use for duplicate filename / contents comparison. Default is sha256.") parser.add_argument("--disable-smart-memory", action="store_true", help="Force ComfyUI to agressively offload to regular ram instead of keeping models in vram when it can.") parser.add_argument("--deterministic", action="store_true", help="Make pytorch use slower deterministic algorithms when it can. Note that this might not make images deterministic in all cases.") @@ -118,11 +122,44 @@ parser.add_argument("--quick-test-for-ci", action="store_true", help="Quick test parser.add_argument("--windows-standalone-build", action="store_true", help="Windows standalone build: Enable convenient things that most people using the standalone windows build will probably enjoy (like auto opening the page on startup).") parser.add_argument("--disable-metadata", action="store_true", help="Disable saving prompt metadata in files.") +parser.add_argument("--disable-all-custom-nodes", action="store_true", help="Disable loading all custom nodes.") parser.add_argument("--multi-user", action="store_true", help="Enables per-user storage.") parser.add_argument("--verbose", action="store_true", help="Enables more debug prints.") +# The default built-in provider hosted under web/ +DEFAULT_VERSION_STRING = "comfyanonymous/ComfyUI@latest" + +parser.add_argument( + "--front-end-version", + type=str, + default=DEFAULT_VERSION_STRING, + help=""" + Specifies the version of the frontend to be used. This command needs internet connectivity to query and + download available frontend implementations from GitHub releases. + + The version string should be in the format of: + [repoOwner]/[repoName]@[version] + where version is one of: "latest" or a valid version number (e.g. "1.0.0") + """, +) + +def is_valid_directory(path: Optional[str]) -> Optional[str]: + """Validate if the given path is a directory.""" + if path is None: + return None + + if not os.path.isdir(path): + raise argparse.ArgumentTypeError(f"{path} is not a valid directory.") + return path + +parser.add_argument( + "--front-end-root", + type=is_valid_directory, + default=None, + help="The local filesystem path to the directory where the frontend is located. Overrides --front-end-version.", +) if comfy.options.args_parsing: args = parser.parse_args() diff --git a/comfy/clip_vision.py b/comfy/clip_vision.py index acc86be85..20dc3345d 100644 --- a/comfy/clip_vision.py +++ b/comfy/clip_vision.py @@ -34,6 +34,7 @@ class ClipVisionModel(): with open(json_config) as f: config = json.load(f) + self.image_size = config.get("image_size", 224) self.load_device = comfy.model_management.text_encoder_device() offload_device = comfy.model_management.text_encoder_offload_device() self.dtype = comfy.model_management.text_encoder_dtype(self.load_device) @@ -50,7 +51,7 @@ class ClipVisionModel(): def encode_image(self, image): comfy.model_management.load_model_gpu(self.patcher) - pixel_values = clip_preprocess(image.to(self.load_device)).float() + pixel_values = clip_preprocess(image.to(self.load_device), size=self.image_size).float() out = self.model(pixel_values=pixel_values, intermediate_output=-2) outputs = Output() @@ -93,7 +94,10 @@ def load_clipvision_from_sd(sd, prefix="", convert_keys=False): elif "vision_model.encoder.layers.30.layer_norm1.weight" in sd: json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "clip_vision_config_h.json") elif "vision_model.encoder.layers.22.layer_norm1.weight" in sd: - json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "clip_vision_config_vitl.json") + if sd["vision_model.embeddings.position_embedding.weight"].shape[0] == 577: + json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "clip_vision_config_vitl_336.json") + else: + json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "clip_vision_config_vitl.json") else: return None diff --git a/comfy/clip_vision_config_vitl_336.json b/comfy/clip_vision_config_vitl_336.json new file mode 100644 index 000000000..f26945273 --- /dev/null +++ b/comfy/clip_vision_config_vitl_336.json @@ -0,0 +1,18 @@ +{ + "attention_dropout": 0.0, + "dropout": 0.0, + "hidden_act": "quick_gelu", + "hidden_size": 1024, + "image_size": 336, + "initializer_factor": 1.0, + "initializer_range": 0.02, + "intermediate_size": 4096, + "layer_norm_eps": 1e-5, + "model_type": "clip_vision_model", + "num_attention_heads": 16, + "num_channels": 3, + "num_hidden_layers": 24, + "patch_size": 14, + "projection_dim": 768, + "torch_dtype": "float32" +} diff --git a/comfy/controlnet.py b/comfy/controlnet.py index 8cf4a61a6..12e5f16c8 100644 --- a/comfy/controlnet.py +++ b/comfy/controlnet.py @@ -7,10 +7,12 @@ import comfy.model_management import comfy.model_detection import comfy.model_patcher import comfy.ops +import comfy.latent_formats import comfy.cldm.cldm import comfy.t2i_adapter.adapter import comfy.ldm.cascade.controlnet +import comfy.cldm.mmdit def broadcast_image_to(tensor, target_batch_size, batched_number): @@ -37,20 +39,25 @@ class ControlBase: self.cond_hint = None self.strength = 1.0 self.timestep_percent_range = (0.0, 1.0) + self.latent_format = None + self.vae = None self.global_average_pooling = False self.timestep_range = None self.compression_ratio = 8 self.upscale_algorithm = 'nearest-exact' + self.extra_args = {} if device is None: device = comfy.model_management.get_torch_device() self.device = device self.previous_controlnet = None - def set_cond_hint(self, cond_hint, strength=1.0, timestep_percent_range=(0.0, 1.0)): + def set_cond_hint(self, cond_hint, strength=1.0, timestep_percent_range=(0.0, 1.0), vae=None): self.cond_hint_original = cond_hint self.strength = strength self.timestep_percent_range = timestep_percent_range + if self.latent_format is not None: + self.vae = vae return self def pre_run(self, model, percent_to_timestep_function): @@ -83,43 +90,36 @@ class ControlBase: c.global_average_pooling = self.global_average_pooling c.compression_ratio = self.compression_ratio c.upscale_algorithm = self.upscale_algorithm + c.latent_format = self.latent_format + c.extra_args = self.extra_args.copy() + c.vae = self.vae def inference_memory_requirements(self, dtype): if self.previous_controlnet is not None: return self.previous_controlnet.inference_memory_requirements(dtype) return 0 - def control_merge(self, control_input, control_output, control_prev, output_dtype): + def control_merge(self, control, control_prev, output_dtype): out = {'input':[], 'middle':[], 'output': []} - if control_input is not None: - for i in range(len(control_input)): - key = 'input' - x = control_input[i] - if x is not None: - x *= self.strength - if x.dtype != output_dtype: - x = x.to(output_dtype) - out[key].insert(0, x) - - if control_output is not None: + for key in control: + control_output = control[key] + applied_to = set() for i in range(len(control_output)): - if i == (len(control_output) - 1): - key = 'middle' - index = 0 - else: - key = 'output' - index = i x = control_output[i] if x is not None: if self.global_average_pooling: x = torch.mean(x, dim=(2, 3), keepdim=True).repeat(1, 1, x.shape[2], x.shape[3]) - x *= self.strength + if x not in applied_to: #memory saving strategy, allow shared tensors and only apply strength to shared tensors once + applied_to.add(x) + x *= self.strength + if x.dtype != output_dtype: x = x.to(output_dtype) out[key].append(x) + if control_prev is not None: for x in ['input', 'middle', 'output']: o = out[x] @@ -134,20 +134,26 @@ class ControlBase: if o[i].shape[0] < prev_val.shape[0]: o[i] = prev_val + o[i] else: - o[i] += prev_val + o[i] = prev_val + o[i] #TODO: change back to inplace add if shared tensors stop being an issue return out + def set_extra_arg(self, argument, value=None): + self.extra_args[argument] = value + + class ControlNet(ControlBase): - def __init__(self, control_model=None, global_average_pooling=False, device=None, load_device=None, manual_cast_dtype=None): + def __init__(self, control_model=None, global_average_pooling=False, compression_ratio=8, latent_format=None, device=None, load_device=None, manual_cast_dtype=None): super().__init__(device) self.control_model = control_model self.load_device = load_device if control_model is not None: self.control_model_wrapped = comfy.model_patcher.ModelPatcher(self.control_model, load_device=load_device, offload_device=comfy.model_management.unet_offload_device()) + self.compression_ratio = compression_ratio self.global_average_pooling = global_average_pooling self.model_sampling_current = None self.manual_cast_dtype = manual_cast_dtype + self.latent_format = latent_format def get_control(self, x_noisy, t, cond, batched_number): control_prev = None @@ -170,7 +176,17 @@ class ControlNet(ControlBase): if self.cond_hint is not None: del self.cond_hint self.cond_hint = None - self.cond_hint = comfy.utils.common_upscale(self.cond_hint_original, x_noisy.shape[3] * self.compression_ratio, x_noisy.shape[2] * self.compression_ratio, self.upscale_algorithm, "center").to(dtype).to(self.device) + compression_ratio = self.compression_ratio + if self.vae is not None: + compression_ratio *= self.vae.downscale_ratio + self.cond_hint = comfy.utils.common_upscale(self.cond_hint_original, x_noisy.shape[3] * compression_ratio, x_noisy.shape[2] * compression_ratio, self.upscale_algorithm, "center") + if self.vae is not None: + loaded_models = comfy.model_management.loaded_models(only_currently_used=True) + self.cond_hint = self.vae.encode(self.cond_hint.movedim(1, -1)) + comfy.model_management.load_models_gpu(loaded_models) + if self.latent_format is not None: + self.cond_hint = self.latent_format.process_in(self.cond_hint) + self.cond_hint = self.cond_hint.to(device=self.device, dtype=dtype) if x_noisy.shape[0] != self.cond_hint.shape[0]: self.cond_hint = broadcast_image_to(self.cond_hint, x_noisy.shape[0], batched_number) @@ -181,8 +197,8 @@ class ControlNet(ControlBase): timestep = self.model_sampling_current.timestep(t) x_noisy = self.model_sampling_current.calculate_input(t, x_noisy) - control = self.control_model(x=x_noisy.to(dtype), hint=self.cond_hint, timesteps=timestep.float(), context=context.to(dtype), y=y) - return self.control_merge(None, control, control_prev, output_dtype) + control = self.control_model(x=x_noisy.to(dtype), hint=self.cond_hint, timesteps=timestep.float(), context=context.to(dtype), y=y, **self.extra_args) + return self.control_merge(control, control_prev, output_dtype) def copy(self): c = ControlNet(None, global_average_pooling=self.global_average_pooling, load_device=self.load_device, manual_cast_dtype=self.manual_cast_dtype) @@ -322,6 +338,39 @@ class ControlLora(ControlNet): def inference_memory_requirements(self, dtype): return comfy.utils.calculate_parameters(self.control_weights) * comfy.model_management.dtype_size(dtype) + ControlBase.inference_memory_requirements(self, dtype) +def load_controlnet_mmdit(sd): + new_sd = comfy.model_detection.convert_diffusers_mmdit(sd, "") + model_config = comfy.model_detection.model_config_from_unet(new_sd, "", True) + num_blocks = comfy.model_detection.count_blocks(new_sd, 'joint_blocks.{}.') + for k in sd: + new_sd[k] = sd[k] + + supported_inference_dtypes = model_config.supported_inference_dtypes + + controlnet_config = model_config.unet_config + unet_dtype = comfy.model_management.unet_dtype(supported_dtypes=supported_inference_dtypes) + load_device = comfy.model_management.get_torch_device() + manual_cast_dtype = comfy.model_management.unet_manual_cast(unet_dtype, load_device) + if manual_cast_dtype is not None: + operations = comfy.ops.manual_cast + else: + operations = comfy.ops.disable_weight_init + + control_model = comfy.cldm.mmdit.ControlNet(num_blocks=num_blocks, operations=operations, device=load_device, dtype=unet_dtype, **controlnet_config) + missing, unexpected = control_model.load_state_dict(new_sd, strict=False) + + if len(missing) > 0: + logging.warning("missing controlnet keys: {}".format(missing)) + + if len(unexpected) > 0: + logging.debug("unexpected controlnet keys: {}".format(unexpected)) + + latent_format = comfy.latent_formats.SD3() + latent_format.shift_factor = 0 #SD3 controlnet weirdness + control = ControlNet(control_model, compression_ratio=1, latent_format=latent_format, load_device=load_device, manual_cast_dtype=manual_cast_dtype) + return control + + def load_controlnet(ckpt_path, model=None): controlnet_data = comfy.utils.load_torch_file(ckpt_path, safe_load=True) if "lora_controlnet" in controlnet_data: @@ -370,10 +419,18 @@ def load_controlnet(ckpt_path, model=None): if k in controlnet_data: new_sd[diffusers_keys[k]] = controlnet_data.pop(k) + if "control_add_embedding.linear_1.bias" in controlnet_data: #Union Controlnet + controlnet_config["union_controlnet_num_control_type"] = controlnet_data["task_embedding"].shape[0] + for k in list(controlnet_data.keys()): + new_k = k.replace('.attn.in_proj_', '.attn.in_proj.') + new_sd[new_k] = controlnet_data.pop(k) + leftover_keys = controlnet_data.keys() if len(leftover_keys) > 0: logging.warning("leftover keys: {}".format(leftover_keys)) controlnet_data = new_sd + elif "controlnet_blocks.0.weight" in controlnet_data: #SD3 diffusers format + return load_controlnet_mmdit(controlnet_data) pth_key = 'control_model.zero_convs.0.0.weight' pth = False @@ -490,12 +547,11 @@ class T2IAdapter(ControlBase): self.control_input = self.t2i_model(self.cond_hint.to(x_noisy.dtype)) self.t2i_model.cpu() - control_input = list(map(lambda a: None if a is None else a.clone(), self.control_input)) - mid = None - if self.t2i_model.xl == True: - mid = control_input[-1:] - control_input = control_input[:-1] - return self.control_merge(control_input, mid, control_prev, x_noisy.dtype) + control_input = {} + for k in self.control_input: + control_input[k] = list(map(lambda a: None if a is None else a.clone(), self.control_input[k])) + + return self.control_merge(control_input, control_prev, x_noisy.dtype) def copy(self): c = T2IAdapter(self.t2i_model, self.channels_in, self.compression_ratio, self.upscale_algorithm) diff --git a/comfy/k_diffusion/deis.py b/comfy/k_diffusion/deis.py new file mode 100644 index 000000000..607410656 --- /dev/null +++ b/comfy/k_diffusion/deis.py @@ -0,0 +1,121 @@ +#Taken from: https://github.com/zju-pi/diff-sampler/blob/main/gits-main/solver_utils.py +#under Apache 2 license +import torch +import numpy as np + +# A pytorch reimplementation of DEIS (https://github.com/qsh-zh/deis). +############################# +### Utils for DEIS solver ### +############################# +#---------------------------------------------------------------------------- +# Transfer from the input time (sigma) used in EDM to that (t) used in DEIS. + +def edm2t(edm_steps, epsilon_s=1e-3, sigma_min=0.002, sigma_max=80): + vp_sigma = lambda beta_d, beta_min: lambda t: (np.e ** (0.5 * beta_d * (t ** 2) + beta_min * t) - 1) ** 0.5 + vp_sigma_inv = lambda beta_d, beta_min: lambda sigma: ((beta_min ** 2 + 2 * beta_d * (sigma ** 2 + 1).log()).sqrt() - beta_min) / beta_d + vp_beta_d = 2 * (np.log(torch.tensor(sigma_min).cpu() ** 2 + 1) / epsilon_s - np.log(torch.tensor(sigma_max).cpu() ** 2 + 1)) / (epsilon_s - 1) + vp_beta_min = np.log(torch.tensor(sigma_max).cpu() ** 2 + 1) - 0.5 * vp_beta_d + t_steps = vp_sigma_inv(vp_beta_d.clone().detach().cpu(), vp_beta_min.clone().detach().cpu())(edm_steps.clone().detach().cpu()) + return t_steps, vp_beta_min, vp_beta_d + vp_beta_min + +#---------------------------------------------------------------------------- + +def cal_poly(prev_t, j, taus): + poly = 1 + for k in range(prev_t.shape[0]): + if k == j: + continue + poly *= (taus - prev_t[k]) / (prev_t[j] - prev_t[k]) + return poly + +#---------------------------------------------------------------------------- +# Transfer from t to alpha_t. + +def t2alpha_fn(beta_0, beta_1, t): + return torch.exp(-0.5 * t ** 2 * (beta_1 - beta_0) - t * beta_0) + +#---------------------------------------------------------------------------- + +def cal_intergrand(beta_0, beta_1, taus): + with torch.inference_mode(mode=False): + taus = taus.clone() + beta_0 = beta_0.clone() + beta_1 = beta_1.clone() + with torch.enable_grad(): + taus.requires_grad_(True) + alpha = t2alpha_fn(beta_0, beta_1, taus) + log_alpha = alpha.log() + log_alpha.sum().backward() + d_log_alpha_dtau = taus.grad + integrand = -0.5 * d_log_alpha_dtau / torch.sqrt(alpha * (1 - alpha)) + return integrand + +#---------------------------------------------------------------------------- + +def get_deis_coeff_list(t_steps, max_order, N=10000, deis_mode='tab'): + """ + Get the coefficient list for DEIS sampling. + + Args: + t_steps: A pytorch tensor. The time steps for sampling. + max_order: A `int`. Maximum order of the solver. 1 <= max_order <= 4 + N: A `int`. Use how many points to perform the numerical integration when deis_mode=='tab'. + deis_mode: A `str`. Select between 'tab' and 'rhoab'. Type of DEIS. + Returns: + A pytorch tensor. A batch of generated samples or sampling trajectories if return_inters=True. + """ + if deis_mode == 'tab': + t_steps, beta_0, beta_1 = edm2t(t_steps) + C = [] + for i, (t_cur, t_next) in enumerate(zip(t_steps[:-1], t_steps[1:])): + order = min(i+1, max_order) + if order == 1: + C.append([]) + else: + taus = torch.linspace(t_cur, t_next, N) # split the interval for integral appximation + dtau = (t_next - t_cur) / N + prev_t = t_steps[[i - k for k in range(order)]] + coeff_temp = [] + integrand = cal_intergrand(beta_0, beta_1, taus) + for j in range(order): + poly = cal_poly(prev_t, j, taus) + coeff_temp.append(torch.sum(integrand * poly) * dtau) + C.append(coeff_temp) + + elif deis_mode == 'rhoab': + # Analytical solution, second order + def get_def_intergral_2(a, b, start, end, c): + coeff = (end**3 - start**3) / 3 - (end**2 - start**2) * (a + b) / 2 + (end - start) * a * b + return coeff / ((c - a) * (c - b)) + + # Analytical solution, third order + def get_def_intergral_3(a, b, c, start, end, d): + coeff = (end**4 - start**4) / 4 - (end**3 - start**3) * (a + b + c) / 3 \ + + (end**2 - start**2) * (a*b + a*c + b*c) / 2 - (end - start) * a * b * c + return coeff / ((d - a) * (d - b) * (d - c)) + + C = [] + for i, (t_cur, t_next) in enumerate(zip(t_steps[:-1], t_steps[1:])): + order = min(i, max_order) + if order == 0: + C.append([]) + else: + prev_t = t_steps[[i - k for k in range(order+1)]] + if order == 1: + coeff_cur = ((t_next - prev_t[1])**2 - (t_cur - prev_t[1])**2) / (2 * (t_cur - prev_t[1])) + coeff_prev1 = (t_next - t_cur)**2 / (2 * (prev_t[1] - t_cur)) + coeff_temp = [coeff_cur, coeff_prev1] + elif order == 2: + coeff_cur = get_def_intergral_2(prev_t[1], prev_t[2], t_cur, t_next, t_cur) + coeff_prev1 = get_def_intergral_2(t_cur, prev_t[2], t_cur, t_next, prev_t[1]) + coeff_prev2 = get_def_intergral_2(t_cur, prev_t[1], t_cur, t_next, prev_t[2]) + coeff_temp = [coeff_cur, coeff_prev1, coeff_prev2] + elif order == 3: + coeff_cur = get_def_intergral_3(prev_t[1], prev_t[2], prev_t[3], t_cur, t_next, t_cur) + coeff_prev1 = get_def_intergral_3(t_cur, prev_t[2], prev_t[3], t_cur, t_next, prev_t[1]) + coeff_prev2 = get_def_intergral_3(t_cur, prev_t[1], prev_t[3], t_cur, t_next, prev_t[2]) + coeff_prev3 = get_def_intergral_3(t_cur, prev_t[1], prev_t[2], t_cur, t_next, prev_t[3]) + coeff_temp = [coeff_cur, coeff_prev1, coeff_prev2, coeff_prev3] + C.append(coeff_temp) + return C + diff --git a/comfy/k_diffusion/sampling.py b/comfy/k_diffusion/sampling.py index 78896b8b5..763d8cc78 100644 --- a/comfy/k_diffusion/sampling.py +++ b/comfy/k_diffusion/sampling.py @@ -7,7 +7,8 @@ import torchsde from tqdm.auto import trange, tqdm from . import utils - +from . import deis +import comfy.model_patcher def append_zero(x): return torch.cat([x, x.new_zeros([1])]) @@ -945,3 +946,105 @@ def sample_ipndm_v(model, x, sigmas, extra_args=None, callback=None, disable=Non buffer_model.append(d_cur.detach()) return x_next + +#From https://github.com/zju-pi/diff-sampler/blob/main/diff-solvers-main/solvers.py +#under Apache 2 license +@torch.no_grad() +def sample_deis(model, x, sigmas, extra_args=None, callback=None, disable=None, max_order=3, deis_mode='tab'): + extra_args = {} if extra_args is None else extra_args + s_in = x.new_ones([x.shape[0]]) + + x_next = x + t_steps = sigmas + + coeff_list = deis.get_deis_coeff_list(t_steps, max_order, deis_mode=deis_mode) + + buffer_model = [] + for i in trange(len(sigmas) - 1, disable=disable): + t_cur = sigmas[i] + t_next = sigmas[i + 1] + + x_cur = x_next + + denoised = model(x_cur, t_cur * s_in, **extra_args) + if callback is not None: + callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised}) + + d_cur = (x_cur - denoised) / t_cur + + order = min(max_order, i+1) + if t_next <= 0: + order = 1 + + if order == 1: # First Euler step. + x_next = x_cur + (t_next - t_cur) * d_cur + elif order == 2: # Use one history point. + coeff_cur, coeff_prev1 = coeff_list[i] + x_next = x_cur + coeff_cur * d_cur + coeff_prev1 * buffer_model[-1] + elif order == 3: # Use two history points. + coeff_cur, coeff_prev1, coeff_prev2 = coeff_list[i] + x_next = x_cur + coeff_cur * d_cur + coeff_prev1 * buffer_model[-1] + coeff_prev2 * buffer_model[-2] + elif order == 4: # Use three history points. + coeff_cur, coeff_prev1, coeff_prev2, coeff_prev3 = coeff_list[i] + x_next = x_cur + coeff_cur * d_cur + coeff_prev1 * buffer_model[-1] + coeff_prev2 * buffer_model[-2] + coeff_prev3 * buffer_model[-3] + + if len(buffer_model) == max_order - 1: + for k in range(max_order - 2): + buffer_model[k] = buffer_model[k+1] + buffer_model[-1] = d_cur.detach() + else: + buffer_model.append(d_cur.detach()) + + return x_next + +@torch.no_grad() +def sample_euler_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None): + extra_args = {} if extra_args is None else extra_args + + temp = [0] + def post_cfg_function(args): + temp[0] = args["uncond_denoised"] + return args["denoised"] + + model_options = extra_args.get("model_options", {}).copy() + extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function(model_options, post_cfg_function, disable_cfg1_optimization=True) + + s_in = x.new_ones([x.shape[0]]) + for i in trange(len(sigmas) - 1, disable=disable): + sigma_hat = sigmas[i] + denoised = model(x, sigma_hat * s_in, **extra_args) + d = to_d(x, sigma_hat, temp[0]) + if callback is not None: + callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigma_hat, 'denoised': denoised}) + dt = sigmas[i + 1] - sigma_hat + # Euler method + x = denoised + d * sigmas[i + 1] + return x + +@torch.no_grad() +def sample_euler_ancestral_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None): + """Ancestral sampling with Euler method steps.""" + extra_args = {} if extra_args is None else extra_args + noise_sampler = default_noise_sampler(x) if noise_sampler is None else noise_sampler + + temp = [0] + def post_cfg_function(args): + temp[0] = args["uncond_denoised"] + return args["denoised"] + + model_options = extra_args.get("model_options", {}).copy() + extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function(model_options, post_cfg_function, disable_cfg1_optimization=True) + + s_in = x.new_ones([x.shape[0]]) + for i in trange(len(sigmas) - 1, disable=disable): + denoised = model(x, sigmas[i] * s_in, **extra_args) + sigma_down, sigma_up = get_ancestral_step(sigmas[i], sigmas[i + 1], eta=eta) + if callback is not None: + callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised}) + d = to_d(x, sigmas[i], temp[0]) + # Euler method + dt = sigma_down - sigmas[i] + x = denoised + d * sigma_down + if sigmas[i + 1] > 0: + x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up + return x diff --git a/comfy/ldm/aura/mmdit.py b/comfy/ldm/aura/mmdit.py new file mode 100644 index 000000000..c465619bd --- /dev/null +++ b/comfy/ldm/aura/mmdit.py @@ -0,0 +1,479 @@ +#AuraFlow MMDiT +#Originally written by the AuraFlow Authors + +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from comfy.ldm.modules.attention import optimized_attention + +def modulate(x, shift, scale): + return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1) + + +def find_multiple(n: int, k: int) -> int: + if n % k == 0: + return n + return n + k - (n % k) + + +class MLP(nn.Module): + def __init__(self, dim, hidden_dim=None, dtype=None, device=None, operations=None) -> None: + super().__init__() + if hidden_dim is None: + hidden_dim = 4 * dim + + n_hidden = int(2 * hidden_dim / 3) + n_hidden = find_multiple(n_hidden, 256) + + self.c_fc1 = operations.Linear(dim, n_hidden, bias=False, dtype=dtype, device=device) + self.c_fc2 = operations.Linear(dim, n_hidden, bias=False, dtype=dtype, device=device) + self.c_proj = operations.Linear(n_hidden, dim, bias=False, dtype=dtype, device=device) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = F.silu(self.c_fc1(x)) * self.c_fc2(x) + x = self.c_proj(x) + return x + + +class MultiHeadLayerNorm(nn.Module): + def __init__(self, hidden_size=None, eps=1e-5, dtype=None, device=None): + # Copy pasta from https://github.com/huggingface/transformers/blob/e5f71ecaae50ea476d1e12351003790273c4b2ed/src/transformers/models/cohere/modeling_cohere.py#L78 + + super().__init__() + self.weight = nn.Parameter(torch.empty(hidden_size, dtype=dtype, device=device)) + self.variance_epsilon = eps + + def forward(self, hidden_states): + input_dtype = hidden_states.dtype + hidden_states = hidden_states.to(torch.float32) + mean = hidden_states.mean(-1, keepdim=True) + variance = (hidden_states - mean).pow(2).mean(-1, keepdim=True) + hidden_states = (hidden_states - mean) * torch.rsqrt( + variance + self.variance_epsilon + ) + hidden_states = self.weight.to(torch.float32) * hidden_states + return hidden_states.to(input_dtype) + +class SingleAttention(nn.Module): + def __init__(self, dim, n_heads, mh_qknorm=False, dtype=None, device=None, operations=None): + super().__init__() + + self.n_heads = n_heads + self.head_dim = dim // n_heads + + # this is for cond + self.w1q = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + self.w1k = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + self.w1v = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + self.w1o = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + + self.q_norm1 = ( + MultiHeadLayerNorm((self.n_heads, self.head_dim), dtype=dtype, device=device) + if mh_qknorm + else operations.LayerNorm(self.head_dim, elementwise_affine=False, dtype=dtype, device=device) + ) + self.k_norm1 = ( + MultiHeadLayerNorm((self.n_heads, self.head_dim), dtype=dtype, device=device) + if mh_qknorm + else operations.LayerNorm(self.head_dim, elementwise_affine=False, dtype=dtype, device=device) + ) + + #@torch.compile() + def forward(self, c): + + bsz, seqlen1, _ = c.shape + + q, k, v = self.w1q(c), self.w1k(c), self.w1v(c) + q = q.view(bsz, seqlen1, self.n_heads, self.head_dim) + k = k.view(bsz, seqlen1, self.n_heads, self.head_dim) + v = v.view(bsz, seqlen1, self.n_heads, self.head_dim) + q, k = self.q_norm1(q), self.k_norm1(k) + + output = optimized_attention(q.permute(0, 2, 1, 3), k.permute(0, 2, 1, 3), v.permute(0, 2, 1, 3), self.n_heads, skip_reshape=True) + c = self.w1o(output) + return c + + + +class DoubleAttention(nn.Module): + def __init__(self, dim, n_heads, mh_qknorm=False, dtype=None, device=None, operations=None): + super().__init__() + + self.n_heads = n_heads + self.head_dim = dim // n_heads + + # this is for cond + self.w1q = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + self.w1k = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + self.w1v = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + self.w1o = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + + # this is for x + self.w2q = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + self.w2k = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + self.w2v = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + self.w2o = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device) + + self.q_norm1 = ( + MultiHeadLayerNorm((self.n_heads, self.head_dim), dtype=dtype, device=device) + if mh_qknorm + else operations.LayerNorm(self.head_dim, elementwise_affine=False, dtype=dtype, device=device) + ) + self.k_norm1 = ( + MultiHeadLayerNorm((self.n_heads, self.head_dim), dtype=dtype, device=device) + if mh_qknorm + else operations.LayerNorm(self.head_dim, elementwise_affine=False, dtype=dtype, device=device) + ) + + self.q_norm2 = ( + MultiHeadLayerNorm((self.n_heads, self.head_dim), dtype=dtype, device=device) + if mh_qknorm + else operations.LayerNorm(self.head_dim, elementwise_affine=False, dtype=dtype, device=device) + ) + self.k_norm2 = ( + MultiHeadLayerNorm((self.n_heads, self.head_dim), dtype=dtype, device=device) + if mh_qknorm + else operations.LayerNorm(self.head_dim, elementwise_affine=False, dtype=dtype, device=device) + ) + + + #@torch.compile() + def forward(self, c, x): + + bsz, seqlen1, _ = c.shape + bsz, seqlen2, _ = x.shape + seqlen = seqlen1 + seqlen2 + + cq, ck, cv = self.w1q(c), self.w1k(c), self.w1v(c) + cq = cq.view(bsz, seqlen1, self.n_heads, self.head_dim) + ck = ck.view(bsz, seqlen1, self.n_heads, self.head_dim) + cv = cv.view(bsz, seqlen1, self.n_heads, self.head_dim) + cq, ck = self.q_norm1(cq), self.k_norm1(ck) + + xq, xk, xv = self.w2q(x), self.w2k(x), self.w2v(x) + xq = xq.view(bsz, seqlen2, self.n_heads, self.head_dim) + xk = xk.view(bsz, seqlen2, self.n_heads, self.head_dim) + xv = xv.view(bsz, seqlen2, self.n_heads, self.head_dim) + xq, xk = self.q_norm2(xq), self.k_norm2(xk) + + # concat all + q, k, v = ( + torch.cat([cq, xq], dim=1), + torch.cat([ck, xk], dim=1), + torch.cat([cv, xv], dim=1), + ) + + output = optimized_attention(q.permute(0, 2, 1, 3), k.permute(0, 2, 1, 3), v.permute(0, 2, 1, 3), self.n_heads, skip_reshape=True) + + c, x = output.split([seqlen1, seqlen2], dim=1) + c = self.w1o(c) + x = self.w2o(x) + + return c, x + + +class MMDiTBlock(nn.Module): + def __init__(self, dim, heads=8, global_conddim=1024, is_last=False, dtype=None, device=None, operations=None): + super().__init__() + + self.normC1 = operations.LayerNorm(dim, elementwise_affine=False, dtype=dtype, device=device) + self.normC2 = operations.LayerNorm(dim, elementwise_affine=False, dtype=dtype, device=device) + if not is_last: + self.mlpC = MLP(dim, hidden_dim=dim * 4, dtype=dtype, device=device, operations=operations) + self.modC = nn.Sequential( + nn.SiLU(), + operations.Linear(global_conddim, 6 * dim, bias=False, dtype=dtype, device=device), + ) + else: + self.modC = nn.Sequential( + nn.SiLU(), + operations.Linear(global_conddim, 2 * dim, bias=False, dtype=dtype, device=device), + ) + + self.normX1 = operations.LayerNorm(dim, elementwise_affine=False, dtype=dtype, device=device) + self.normX2 = operations.LayerNorm(dim, elementwise_affine=False, dtype=dtype, device=device) + self.mlpX = MLP(dim, hidden_dim=dim * 4, dtype=dtype, device=device, operations=operations) + self.modX = nn.Sequential( + nn.SiLU(), + operations.Linear(global_conddim, 6 * dim, bias=False, dtype=dtype, device=device), + ) + + self.attn = DoubleAttention(dim, heads, dtype=dtype, device=device, operations=operations) + self.is_last = is_last + + #@torch.compile() + def forward(self, c, x, global_cond, **kwargs): + + cres, xres = c, x + + cshift_msa, cscale_msa, cgate_msa, cshift_mlp, cscale_mlp, cgate_mlp = ( + self.modC(global_cond).chunk(6, dim=1) + ) + + c = modulate(self.normC1(c), cshift_msa, cscale_msa) + + # xpath + xshift_msa, xscale_msa, xgate_msa, xshift_mlp, xscale_mlp, xgate_mlp = ( + self.modX(global_cond).chunk(6, dim=1) + ) + + x = modulate(self.normX1(x), xshift_msa, xscale_msa) + + # attention + c, x = self.attn(c, x) + + + c = self.normC2(cres + cgate_msa.unsqueeze(1) * c) + c = cgate_mlp.unsqueeze(1) * self.mlpC(modulate(c, cshift_mlp, cscale_mlp)) + c = cres + c + + x = self.normX2(xres + xgate_msa.unsqueeze(1) * x) + x = xgate_mlp.unsqueeze(1) * self.mlpX(modulate(x, xshift_mlp, xscale_mlp)) + x = xres + x + + return c, x + +class DiTBlock(nn.Module): + # like MMDiTBlock, but it only has X + def __init__(self, dim, heads=8, global_conddim=1024, dtype=None, device=None, operations=None): + super().__init__() + + self.norm1 = operations.LayerNorm(dim, elementwise_affine=False, dtype=dtype, device=device) + self.norm2 = operations.LayerNorm(dim, elementwise_affine=False, dtype=dtype, device=device) + + self.modCX = nn.Sequential( + nn.SiLU(), + operations.Linear(global_conddim, 6 * dim, bias=False, dtype=dtype, device=device), + ) + + self.attn = SingleAttention(dim, heads, dtype=dtype, device=device, operations=operations) + self.mlp = MLP(dim, hidden_dim=dim * 4, dtype=dtype, device=device, operations=operations) + + #@torch.compile() + def forward(self, cx, global_cond, **kwargs): + cxres = cx + shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.modCX( + global_cond + ).chunk(6, dim=1) + cx = modulate(self.norm1(cx), shift_msa, scale_msa) + cx = self.attn(cx) + cx = self.norm2(cxres + gate_msa.unsqueeze(1) * cx) + mlpout = self.mlp(modulate(cx, shift_mlp, scale_mlp)) + cx = gate_mlp.unsqueeze(1) * mlpout + + cx = cxres + cx + + return cx + + + +class TimestepEmbedder(nn.Module): + def __init__(self, hidden_size, frequency_embedding_size=256, dtype=None, device=None, operations=None): + super().__init__() + self.mlp = nn.Sequential( + operations.Linear(frequency_embedding_size, hidden_size, dtype=dtype, device=device), + nn.SiLU(), + operations.Linear(hidden_size, hidden_size, dtype=dtype, device=device), + ) + self.frequency_embedding_size = frequency_embedding_size + + @staticmethod + def timestep_embedding(t, dim, max_period=10000): + half = dim // 2 + freqs = 1000 * torch.exp( + -math.log(max_period) * torch.arange(start=0, end=half) / half + ).to(t.device) + args = t[:, None] * freqs[None] + embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1) + if dim % 2: + embedding = torch.cat( + [embedding, torch.zeros_like(embedding[:, :1])], dim=-1 + ) + return embedding + + #@torch.compile() + def forward(self, t, dtype): + t_freq = self.timestep_embedding(t, self.frequency_embedding_size).to(dtype) + t_emb = self.mlp(t_freq) + return t_emb + + +class MMDiT(nn.Module): + def __init__( + self, + in_channels=4, + out_channels=4, + patch_size=2, + dim=3072, + n_layers=36, + n_double_layers=4, + n_heads=12, + global_conddim=3072, + cond_seq_dim=2048, + max_seq=32 * 32, + device=None, + dtype=None, + operations=None, + ): + super().__init__() + self.dtype = dtype + + self.t_embedder = TimestepEmbedder(global_conddim, dtype=dtype, device=device, operations=operations) + + self.cond_seq_linear = operations.Linear( + cond_seq_dim, dim, bias=False, dtype=dtype, device=device + ) # linear for something like text sequence. + self.init_x_linear = operations.Linear( + patch_size * patch_size * in_channels, dim, dtype=dtype, device=device + ) # init linear for patchified image. + + self.positional_encoding = nn.Parameter(torch.empty(1, max_seq, dim, dtype=dtype, device=device)) + self.register_tokens = nn.Parameter(torch.empty(1, 8, dim, dtype=dtype, device=device)) + + self.double_layers = nn.ModuleList([]) + self.single_layers = nn.ModuleList([]) + + + for idx in range(n_double_layers): + self.double_layers.append( + MMDiTBlock(dim, n_heads, global_conddim, is_last=(idx == n_layers - 1), dtype=dtype, device=device, operations=operations) + ) + + for idx in range(n_double_layers, n_layers): + self.single_layers.append( + DiTBlock(dim, n_heads, global_conddim, dtype=dtype, device=device, operations=operations) + ) + + + self.final_linear = operations.Linear( + dim, patch_size * patch_size * out_channels, bias=False, dtype=dtype, device=device + ) + + self.modF = nn.Sequential( + nn.SiLU(), + operations.Linear(global_conddim, 2 * dim, bias=False, dtype=dtype, device=device), + ) + + self.out_channels = out_channels + self.patch_size = patch_size + self.n_double_layers = n_double_layers + self.n_layers = n_layers + + self.h_max = round(max_seq**0.5) + self.w_max = round(max_seq**0.5) + + @torch.no_grad() + def extend_pe(self, init_dim=(16, 16), target_dim=(64, 64)): + # extend pe + pe_data = self.positional_encoding.data.squeeze(0)[: init_dim[0] * init_dim[1]] + + pe_as_2d = pe_data.view(init_dim[0], init_dim[1], -1).permute(2, 0, 1) + + # now we need to extend this to target_dim. for this we will use interpolation. + # we will use torch.nn.functional.interpolate + pe_as_2d = F.interpolate( + pe_as_2d.unsqueeze(0), size=target_dim, mode="bilinear" + ) + pe_new = pe_as_2d.squeeze(0).permute(1, 2, 0).flatten(0, 1) + self.positional_encoding.data = pe_new.unsqueeze(0).contiguous() + self.h_max, self.w_max = target_dim + print("PE extended to", target_dim) + + def pe_selection_index_based_on_dim(self, h, w): + h_p, w_p = h // self.patch_size, w // self.patch_size + original_pe_indexes = torch.arange(self.positional_encoding.shape[1]) + original_pe_indexes = original_pe_indexes.view(self.h_max, self.w_max) + starth = self.h_max // 2 - h_p // 2 + endh =starth + h_p + startw = self.w_max // 2 - w_p // 2 + endw = startw + w_p + original_pe_indexes = original_pe_indexes[ + starth:endh, startw:endw + ] + return original_pe_indexes.flatten() + + def unpatchify(self, x, h, w): + c = self.out_channels + p = self.patch_size + + x = x.reshape(shape=(x.shape[0], h, w, p, p, c)) + x = torch.einsum("nhwpqc->nchpwq", x) + imgs = x.reshape(shape=(x.shape[0], c, h * p, w * p)) + return imgs + + def patchify(self, x): + B, C, H, W = x.size() + pad_h = (self.patch_size - H % self.patch_size) % self.patch_size + pad_w = (self.patch_size - W % self.patch_size) % self.patch_size + + x = torch.nn.functional.pad(x, (0, pad_w, 0, pad_h), mode='reflect') + x = x.view( + B, + C, + (H + 1) // self.patch_size, + self.patch_size, + (W + 1) // self.patch_size, + self.patch_size, + ) + x = x.permute(0, 2, 4, 1, 3, 5).flatten(-3).flatten(1, 2) + return x + + def apply_pos_embeds(self, x, h, w): + h = (h + 1) // self.patch_size + w = (w + 1) // self.patch_size + max_dim = max(h, w) + + cur_dim = self.h_max + pos_encoding = self.positional_encoding.reshape(1, cur_dim, cur_dim, -1).to(device=x.device, dtype=x.dtype) + + if max_dim > cur_dim: + pos_encoding = F.interpolate(pos_encoding.movedim(-1, 1), (max_dim, max_dim), mode="bilinear").movedim(1, -1) + cur_dim = max_dim + + from_h = (cur_dim - h) // 2 + from_w = (cur_dim - w) // 2 + pos_encoding = pos_encoding[:,from_h:from_h+h,from_w:from_w+w] + return x + pos_encoding.reshape(1, -1, self.positional_encoding.shape[-1]) + + def forward(self, x, timestep, context, **kwargs): + # patchify x, add PE + b, c, h, w = x.shape + + # pe_indexes = self.pe_selection_index_based_on_dim(h, w) + # print(pe_indexes, pe_indexes.shape) + + x = self.init_x_linear(self.patchify(x)) # B, T_x, D + x = self.apply_pos_embeds(x, h, w) + # x = x + self.positional_encoding[:, : x.size(1)].to(device=x.device, dtype=x.dtype) + # x = x + self.positional_encoding[:, pe_indexes].to(device=x.device, dtype=x.dtype) + + # process conditions for MMDiT Blocks + c_seq = context # B, T_c, D_c + t = timestep + + c = self.cond_seq_linear(c_seq) # B, T_c, D + c = torch.cat([self.register_tokens.to(device=c.device, dtype=c.dtype).repeat(c.size(0), 1, 1), c], dim=1) + + global_cond = self.t_embedder(t, x.dtype) # B, D + + if len(self.double_layers) > 0: + for layer in self.double_layers: + c, x = layer(c, x, global_cond, **kwargs) + + if len(self.single_layers) > 0: + c_len = c.size(1) + cx = torch.cat([c, x], dim=1) + for layer in self.single_layers: + cx = layer(cx, global_cond, **kwargs) + + x = cx[:, c_len:] + + fshift, fscale = self.modF(global_cond).chunk(2, dim=1) + + x = modulate(x, fshift, fscale) + x = self.final_linear(x) + x = self.unpatchify(x, (h + 1) // self.patch_size, (w + 1) // self.patch_size)[:,:,:h,:w] + return x diff --git a/comfy/ldm/cascade/controlnet.py b/comfy/ldm/cascade/controlnet.py index 5dac59394..7a52c3c26 100644 --- a/comfy/ldm/cascade/controlnet.py +++ b/comfy/ldm/cascade/controlnet.py @@ -90,4 +90,4 @@ class ControlNet(nn.Module): proj_outputs = [None for _ in range(max(self.proj_blocks) + 1)] for i, idx in enumerate(self.proj_blocks): proj_outputs[idx] = self.projections[i](x) - return proj_outputs + return {"input": proj_outputs[::-1]} diff --git a/comfy/ldm/hydit/attn_layers.py b/comfy/ldm/hydit/attn_layers.py new file mode 100644 index 000000000..920b84286 --- /dev/null +++ b/comfy/ldm/hydit/attn_layers.py @@ -0,0 +1,219 @@ +import torch +import torch.nn as nn +from typing import Tuple, Union, Optional +from comfy.ldm.modules.attention import optimized_attention + + +def reshape_for_broadcast(freqs_cis: Union[torch.Tensor, Tuple[torch.Tensor]], x: torch.Tensor, head_first=False): + """ + Reshape frequency tensor for broadcasting it with another tensor. + + This function reshapes the frequency tensor to have the same shape as the target tensor 'x' + for the purpose of broadcasting the frequency tensor during element-wise operations. + + Args: + freqs_cis (Union[torch.Tensor, Tuple[torch.Tensor]]): Frequency tensor to be reshaped. + x (torch.Tensor): Target tensor for broadcasting compatibility. + head_first (bool): head dimension first (except batch dim) or not. + + Returns: + torch.Tensor: Reshaped frequency tensor. + + Raises: + AssertionError: If the frequency tensor doesn't match the expected shape. + AssertionError: If the target tensor 'x' doesn't have the expected number of dimensions. + """ + ndim = x.ndim + assert 0 <= 1 < ndim + + if isinstance(freqs_cis, tuple): + # freqs_cis: (cos, sin) in real space + if head_first: + assert freqs_cis[0].shape == (x.shape[-2], x.shape[-1]), f'freqs_cis shape {freqs_cis[0].shape} does not match x shape {x.shape}' + shape = [d if i == ndim - 2 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)] + else: + assert freqs_cis[0].shape == (x.shape[1], x.shape[-1]), f'freqs_cis shape {freqs_cis[0].shape} does not match x shape {x.shape}' + shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)] + return freqs_cis[0].view(*shape), freqs_cis[1].view(*shape) + else: + # freqs_cis: values in complex space + if head_first: + assert freqs_cis.shape == (x.shape[-2], x.shape[-1]), f'freqs_cis shape {freqs_cis.shape} does not match x shape {x.shape}' + shape = [d if i == ndim - 2 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)] + else: + assert freqs_cis.shape == (x.shape[1], x.shape[-1]), f'freqs_cis shape {freqs_cis.shape} does not match x shape {x.shape}' + shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)] + return freqs_cis.view(*shape) + + +def rotate_half(x): + x_real, x_imag = x.float().reshape(*x.shape[:-1], -1, 2).unbind(-1) # [B, S, H, D//2] + return torch.stack([-x_imag, x_real], dim=-1).flatten(3) + + +def apply_rotary_emb( + xq: torch.Tensor, + xk: Optional[torch.Tensor], + freqs_cis: Union[torch.Tensor, Tuple[torch.Tensor]], + head_first: bool = False, +) -> Tuple[torch.Tensor, torch.Tensor]: + """ + Apply rotary embeddings to input tensors using the given frequency tensor. + + This function applies rotary embeddings to the given query 'xq' and key 'xk' tensors using the provided + frequency tensor 'freqs_cis'. The input tensors are reshaped as complex numbers, and the frequency tensor + is reshaped for broadcasting compatibility. The resulting tensors contain rotary embeddings and are + returned as real tensors. + + Args: + xq (torch.Tensor): Query tensor to apply rotary embeddings. [B, S, H, D] + xk (torch.Tensor): Key tensor to apply rotary embeddings. [B, S, H, D] + freqs_cis (Union[torch.Tensor, Tuple[torch.Tensor]]): Precomputed frequency tensor for complex exponentials. + head_first (bool): head dimension first (except batch dim) or not. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: Tuple of modified query tensor and key tensor with rotary embeddings. + + """ + xk_out = None + if isinstance(freqs_cis, tuple): + cos, sin = reshape_for_broadcast(freqs_cis, xq, head_first) # [S, D] + cos, sin = cos.to(xq.device), sin.to(xq.device) + xq_out = (xq.float() * cos + rotate_half(xq.float()) * sin).type_as(xq) + if xk is not None: + xk_out = (xk.float() * cos + rotate_half(xk.float()) * sin).type_as(xk) + else: + xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2)) # [B, S, H, D//2] + freqs_cis = reshape_for_broadcast(freqs_cis, xq_, head_first).to(xq.device) # [S, D//2] --> [1, S, 1, D//2] + xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3).type_as(xq) + if xk is not None: + xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2)) # [B, S, H, D//2] + xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3).type_as(xk) + + return xq_out, xk_out + + + +class CrossAttention(nn.Module): + """ + Use QK Normalization. + """ + def __init__(self, + qdim, + kdim, + num_heads, + qkv_bias=True, + qk_norm=False, + attn_drop=0.0, + proj_drop=0.0, + attn_precision=None, + device=None, + dtype=None, + operations=None, + ): + factory_kwargs = {'device': device, 'dtype': dtype} + super().__init__() + self.attn_precision = attn_precision + self.qdim = qdim + self.kdim = kdim + self.num_heads = num_heads + assert self.qdim % num_heads == 0, "self.qdim must be divisible by num_heads" + self.head_dim = self.qdim // num_heads + assert self.head_dim % 8 == 0 and self.head_dim <= 128, "Only support head_dim <= 128 and divisible by 8" + self.scale = self.head_dim ** -0.5 + + self.q_proj = operations.Linear(qdim, qdim, bias=qkv_bias, **factory_kwargs) + self.kv_proj = operations.Linear(kdim, 2 * qdim, bias=qkv_bias, **factory_kwargs) + + # TODO: eps should be 1 / 65530 if using fp16 + self.q_norm = operations.LayerNorm(self.head_dim, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device) if qk_norm else nn.Identity() + self.k_norm = operations.LayerNorm(self.head_dim, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device) if qk_norm else nn.Identity() + self.attn_drop = nn.Dropout(attn_drop) + self.out_proj = operations.Linear(qdim, qdim, bias=qkv_bias, **factory_kwargs) + self.proj_drop = nn.Dropout(proj_drop) + + def forward(self, x, y, freqs_cis_img=None): + """ + Parameters + ---------- + x: torch.Tensor + (batch, seqlen1, hidden_dim) (where hidden_dim = num heads * head dim) + y: torch.Tensor + (batch, seqlen2, hidden_dim2) + freqs_cis_img: torch.Tensor + (batch, hidden_dim // 2), RoPE for image + """ + b, s1, c = x.shape # [b, s1, D] + _, s2, c = y.shape # [b, s2, 1024] + + q = self.q_proj(x).view(b, s1, self.num_heads, self.head_dim) # [b, s1, h, d] + kv = self.kv_proj(y).view(b, s2, 2, self.num_heads, self.head_dim) # [b, s2, 2, h, d] + k, v = kv.unbind(dim=2) # [b, s, h, d] + q = self.q_norm(q) + k = self.k_norm(k) + + # Apply RoPE if needed + if freqs_cis_img is not None: + qq, _ = apply_rotary_emb(q, None, freqs_cis_img) + assert qq.shape == q.shape, f'qq: {qq.shape}, q: {q.shape}' + q = qq + + q = q.transpose(-2, -3).contiguous() # q -> B, L1, H, C - B, H, L1, C + k = k.transpose(-2, -3).contiguous() # k -> B, L2, H, C - B, H, C, L2 + v = v.transpose(-2, -3).contiguous() + + context = optimized_attention(q, k, v, self.num_heads, skip_reshape=True, attn_precision=self.attn_precision) + + out = self.out_proj(context) # context.reshape - B, L1, -1 + out = self.proj_drop(out) + + out_tuple = (out,) + + return out_tuple + + +class Attention(nn.Module): + """ + We rename some layer names to align with flash attention + """ + def __init__(self, dim, num_heads, qkv_bias=True, qk_norm=False, attn_drop=0., proj_drop=0., attn_precision=None, dtype=None, device=None, operations=None): + super().__init__() + self.attn_precision = attn_precision + self.dim = dim + self.num_heads = num_heads + assert self.dim % num_heads == 0, 'dim should be divisible by num_heads' + self.head_dim = self.dim // num_heads + # This assertion is aligned with flash attention + assert self.head_dim % 8 == 0 and self.head_dim <= 128, "Only support head_dim <= 128 and divisible by 8" + self.scale = self.head_dim ** -0.5 + + # qkv --> Wqkv + self.Wqkv = operations.Linear(dim, dim * 3, bias=qkv_bias, dtype=dtype, device=device) + # TODO: eps should be 1 / 65530 if using fp16 + self.q_norm = operations.LayerNorm(self.head_dim, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device) if qk_norm else nn.Identity() + self.k_norm = operations.LayerNorm(self.head_dim, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device) if qk_norm else nn.Identity() + self.attn_drop = nn.Dropout(attn_drop) + self.out_proj = operations.Linear(dim, dim, dtype=dtype, device=device) + self.proj_drop = nn.Dropout(proj_drop) + + def forward(self, x, freqs_cis_img=None): + B, N, C = x.shape + qkv = self.Wqkv(x).reshape(B, N, 3, self.num_heads, self.head_dim).permute(2, 0, 3, 1, 4) # [3, b, h, s, d] + q, k, v = qkv.unbind(0) # [b, h, s, d] + q = self.q_norm(q) # [b, h, s, d] + k = self.k_norm(k) # [b, h, s, d] + + # Apply RoPE if needed + if freqs_cis_img is not None: + qq, kk = apply_rotary_emb(q, k, freqs_cis_img, head_first=True) + assert qq.shape == q.shape and kk.shape == k.shape, \ + f'qq: {qq.shape}, q: {q.shape}, kk: {kk.shape}, k: {k.shape}' + q, k = qq, kk + + x = optimized_attention(q, k, v, self.num_heads, skip_reshape=True, attn_precision=self.attn_precision) + x = self.out_proj(x) + x = self.proj_drop(x) + + out_tuple = (x,) + + return out_tuple diff --git a/comfy/ldm/hydit/models.py b/comfy/ldm/hydit/models.py new file mode 100644 index 000000000..bde9687e2 --- /dev/null +++ b/comfy/ldm/hydit/models.py @@ -0,0 +1,404 @@ +from typing import Any + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from comfy.ldm.modules.diffusionmodules.mmdit import Mlp, TimestepEmbedder, PatchEmbed, RMSNorm +from comfy.ldm.modules.diffusionmodules.util import timestep_embedding +from torch.utils import checkpoint + +from .attn_layers import Attention, CrossAttention +from .poolers import AttentionPool +from .posemb_layers import get_2d_rotary_pos_embed, get_fill_resize_and_crop + +def calc_rope(x, patch_size, head_size): + th = (x.shape[2] + (patch_size // 2)) // patch_size + tw = (x.shape[3] + (patch_size // 2)) // patch_size + base_size = 512 // 8 // patch_size + start, stop = get_fill_resize_and_crop((th, tw), base_size) + sub_args = [start, stop, (th, tw)] + # head_size = HUNYUAN_DIT_CONFIG['DiT-g/2']['hidden_size'] // HUNYUAN_DIT_CONFIG['DiT-g/2']['num_heads'] + rope = get_2d_rotary_pos_embed(head_size, *sub_args) + return rope + + +def modulate(x, shift, scale): + return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1) + + +class HunYuanDiTBlock(nn.Module): + """ + A HunYuanDiT block with `add` conditioning. + """ + def __init__(self, + hidden_size, + c_emb_size, + num_heads, + mlp_ratio=4.0, + text_states_dim=1024, + qk_norm=False, + norm_type="layer", + skip=False, + attn_precision=None, + dtype=None, + device=None, + operations=None, + ): + super().__init__() + use_ele_affine = True + + if norm_type == "layer": + norm_layer = operations.LayerNorm + elif norm_type == "rms": + norm_layer = RMSNorm + else: + raise ValueError(f"Unknown norm_type: {norm_type}") + + # ========================= Self-Attention ========================= + self.norm1 = norm_layer(hidden_size, elementwise_affine=use_ele_affine, eps=1e-6, dtype=dtype, device=device) + self.attn1 = Attention(hidden_size, num_heads=num_heads, qkv_bias=True, qk_norm=qk_norm, attn_precision=attn_precision, dtype=dtype, device=device, operations=operations) + + # ========================= FFN ========================= + self.norm2 = norm_layer(hidden_size, elementwise_affine=use_ele_affine, eps=1e-6, dtype=dtype, device=device) + mlp_hidden_dim = int(hidden_size * mlp_ratio) + approx_gelu = lambda: nn.GELU(approximate="tanh") + self.mlp = Mlp(in_features=hidden_size, hidden_features=mlp_hidden_dim, act_layer=approx_gelu, drop=0, dtype=dtype, device=device, operations=operations) + + # ========================= Add ========================= + # Simply use add like SDXL. + self.default_modulation = nn.Sequential( + nn.SiLU(), + operations.Linear(c_emb_size, hidden_size, bias=True, dtype=dtype, device=device) + ) + + # ========================= Cross-Attention ========================= + self.attn2 = CrossAttention(hidden_size, text_states_dim, num_heads=num_heads, qkv_bias=True, + qk_norm=qk_norm, attn_precision=attn_precision, dtype=dtype, device=device, operations=operations) + self.norm3 = norm_layer(hidden_size, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device) + + # ========================= Skip Connection ========================= + if skip: + self.skip_norm = norm_layer(2 * hidden_size, elementwise_affine=True, eps=1e-6, dtype=dtype, device=device) + self.skip_linear = operations.Linear(2 * hidden_size, hidden_size, dtype=dtype, device=device) + else: + self.skip_linear = None + + self.gradient_checkpointing = False + + def _forward(self, x, c=None, text_states=None, freq_cis_img=None, skip=None): + # Long Skip Connection + if self.skip_linear is not None: + cat = torch.cat([x, skip], dim=-1) + cat = self.skip_norm(cat) + x = self.skip_linear(cat) + + # Self-Attention + shift_msa = self.default_modulation(c).unsqueeze(dim=1) + attn_inputs = ( + self.norm1(x) + shift_msa, freq_cis_img, + ) + x = x + self.attn1(*attn_inputs)[0] + + # Cross-Attention + cross_inputs = ( + self.norm3(x), text_states, freq_cis_img + ) + x = x + self.attn2(*cross_inputs)[0] + + # FFN Layer + mlp_inputs = self.norm2(x) + x = x + self.mlp(mlp_inputs) + + return x + + def forward(self, x, c=None, text_states=None, freq_cis_img=None, skip=None): + if self.gradient_checkpointing and self.training: + return checkpoint.checkpoint(self._forward, x, c, text_states, freq_cis_img, skip) + return self._forward(x, c, text_states, freq_cis_img, skip) + + +class FinalLayer(nn.Module): + """ + The final layer of HunYuanDiT. + """ + def __init__(self, final_hidden_size, c_emb_size, patch_size, out_channels, dtype=None, device=None, operations=None): + super().__init__() + self.norm_final = operations.LayerNorm(final_hidden_size, elementwise_affine=False, eps=1e-6, dtype=dtype, device=device) + self.linear = operations.Linear(final_hidden_size, patch_size * patch_size * out_channels, bias=True, dtype=dtype, device=device) + self.adaLN_modulation = nn.Sequential( + nn.SiLU(), + operations.Linear(c_emb_size, 2 * final_hidden_size, bias=True, dtype=dtype, device=device) + ) + + def forward(self, x, c): + shift, scale = self.adaLN_modulation(c).chunk(2, dim=1) + x = modulate(self.norm_final(x), shift, scale) + x = self.linear(x) + return x + + +class HunYuanDiT(nn.Module): + """ + HunYuanDiT: Diffusion model with a Transformer backbone. + + Inherit ModelMixin and ConfigMixin to be compatible with the sampler StableDiffusionPipeline of diffusers. + + Inherit PeftAdapterMixin to be compatible with the PEFT training pipeline. + + Parameters + ---------- + args: argparse.Namespace + The arguments parsed by argparse. + input_size: tuple + The size of the input image. + patch_size: int + The size of the patch. + in_channels: int + The number of input channels. + hidden_size: int + The hidden size of the transformer backbone. + depth: int + The number of transformer blocks. + num_heads: int + The number of attention heads. + mlp_ratio: float + The ratio of the hidden size of the MLP in the transformer block. + log_fn: callable + The logging function. + """ + #@register_to_config + def __init__(self, + input_size: tuple = 32, + patch_size: int = 2, + in_channels: int = 4, + hidden_size: int = 1152, + depth: int = 28, + num_heads: int = 16, + mlp_ratio: float = 4.0, + text_states_dim = 1024, + text_states_dim_t5 = 2048, + text_len = 77, + text_len_t5 = 256, + qk_norm = True,# See http://arxiv.org/abs/2302.05442 for details. + size_cond = False, + use_style_cond = False, + learn_sigma = True, + norm = "layer", + log_fn: callable = print, + attn_precision=None, + dtype=None, + device=None, + operations=None, + **kwargs, + ): + super().__init__() + self.log_fn = log_fn + self.depth = depth + self.learn_sigma = learn_sigma + self.in_channels = in_channels + self.out_channels = in_channels * 2 if learn_sigma else in_channels + self.patch_size = patch_size + self.num_heads = num_heads + self.hidden_size = hidden_size + self.text_states_dim = text_states_dim + self.text_states_dim_t5 = text_states_dim_t5 + self.text_len = text_len + self.text_len_t5 = text_len_t5 + self.size_cond = size_cond + self.use_style_cond = use_style_cond + self.norm = norm + self.dtype = dtype + #import pdb + #pdb.set_trace() + + self.mlp_t5 = nn.Sequential( + operations.Linear(self.text_states_dim_t5, self.text_states_dim_t5 * 4, bias=True, dtype=dtype, device=device), + nn.SiLU(), + operations.Linear(self.text_states_dim_t5 * 4, self.text_states_dim, bias=True, dtype=dtype, device=device), + ) + # learnable replace + self.text_embedding_padding = nn.Parameter( + torch.empty(self.text_len + self.text_len_t5, self.text_states_dim, dtype=dtype, device=device)) + + # Attention pooling + pooler_out_dim = 1024 + self.pooler = AttentionPool(self.text_len_t5, self.text_states_dim_t5, num_heads=8, output_dim=pooler_out_dim, dtype=dtype, device=device, operations=operations) + + # Dimension of the extra input vectors + self.extra_in_dim = pooler_out_dim + + if self.size_cond: + # Image size and crop size conditions + self.extra_in_dim += 6 * 256 + + if self.use_style_cond: + # Here we use a default learned embedder layer for future extension. + self.style_embedder = nn.Embedding(1, hidden_size, dtype=dtype, device=device) + self.extra_in_dim += hidden_size + + # Text embedding for `add` + self.x_embedder = PatchEmbed(input_size, patch_size, in_channels, hidden_size, dtype=dtype, device=device, operations=operations) + self.t_embedder = TimestepEmbedder(hidden_size, dtype=dtype, device=device, operations=operations) + self.extra_embedder = nn.Sequential( + operations.Linear(self.extra_in_dim, hidden_size * 4, dtype=dtype, device=device), + nn.SiLU(), + operations.Linear(hidden_size * 4, hidden_size, bias=True, dtype=dtype, device=device), + ) + + # Image embedding + num_patches = self.x_embedder.num_patches + + # HUnYuanDiT Blocks + self.blocks = nn.ModuleList([ + HunYuanDiTBlock(hidden_size=hidden_size, + c_emb_size=hidden_size, + num_heads=num_heads, + mlp_ratio=mlp_ratio, + text_states_dim=self.text_states_dim, + qk_norm=qk_norm, + norm_type=self.norm, + skip=layer > depth // 2, + attn_precision=attn_precision, + dtype=dtype, + device=device, + operations=operations, + ) + for layer in range(depth) + ]) + + self.final_layer = FinalLayer(hidden_size, hidden_size, patch_size, self.out_channels, dtype=dtype, device=device, operations=operations) + self.unpatchify_channels = self.out_channels + + + + def forward(self, + x, + t, + context,#encoder_hidden_states=None, + text_embedding_mask=None, + encoder_hidden_states_t5=None, + text_embedding_mask_t5=None, + image_meta_size=None, + style=None, + return_dict=False, + control=None, + transformer_options=None, + ): + """ + Forward pass of the encoder. + + Parameters + ---------- + x: torch.Tensor + (B, D, H, W) + t: torch.Tensor + (B) + encoder_hidden_states: torch.Tensor + CLIP text embedding, (B, L_clip, D) + text_embedding_mask: torch.Tensor + CLIP text embedding mask, (B, L_clip) + encoder_hidden_states_t5: torch.Tensor + T5 text embedding, (B, L_t5, D) + text_embedding_mask_t5: torch.Tensor + T5 text embedding mask, (B, L_t5) + image_meta_size: torch.Tensor + (B, 6) + style: torch.Tensor + (B) + cos_cis_img: torch.Tensor + sin_cis_img: torch.Tensor + return_dict: bool + Whether to return a dictionary. + """ + #import pdb + #pdb.set_trace() + encoder_hidden_states = context + text_states = encoder_hidden_states # 2,77,1024 + text_states_t5 = encoder_hidden_states_t5 # 2,256,2048 + text_states_mask = text_embedding_mask.bool() # 2,77 + text_states_t5_mask = text_embedding_mask_t5.bool() # 2,256 + b_t5, l_t5, c_t5 = text_states_t5.shape + text_states_t5 = self.mlp_t5(text_states_t5.view(-1, c_t5)).view(b_t5, l_t5, -1) + + padding = self.text_embedding_padding.to(text_states) + + text_states[:,-self.text_len:] = torch.where(text_states_mask[:,-self.text_len:].unsqueeze(2), text_states[:,-self.text_len:], padding[:self.text_len]) + text_states_t5[:,-self.text_len_t5:] = torch.where(text_states_t5_mask[:,-self.text_len_t5:].unsqueeze(2), text_states_t5[:,-self.text_len_t5:], padding[self.text_len:]) + + text_states = torch.cat([text_states, text_states_t5], dim=1) # 2,205,1024 + # clip_t5_mask = torch.cat([text_states_mask, text_states_t5_mask], dim=-1) + + _, _, oh, ow = x.shape + th, tw = (oh + (self.patch_size // 2)) // self.patch_size, (ow + (self.patch_size // 2)) // self.patch_size + + + # Get image RoPE embedding according to `reso`lution. + freqs_cis_img = calc_rope(x, self.patch_size, self.hidden_size // self.num_heads) #(cos_cis_img, sin_cis_img) + + # ========================= Build time and image embedding ========================= + t = self.t_embedder(t, dtype=x.dtype) + x = self.x_embedder(x) + + # ========================= Concatenate all extra vectors ========================= + # Build text tokens with pooling + extra_vec = self.pooler(encoder_hidden_states_t5) + + # Build image meta size tokens if applicable + if self.size_cond: + image_meta_size = timestep_embedding(image_meta_size.view(-1), 256).to(x.dtype) # [B * 6, 256] + image_meta_size = image_meta_size.view(-1, 6 * 256) + extra_vec = torch.cat([extra_vec, image_meta_size], dim=1) # [B, D + 6 * 256] + + # Build style tokens + if self.use_style_cond: + if style is None: + style = torch.zeros((extra_vec.shape[0],), device=x.device, dtype=torch.int) + style_embedding = self.style_embedder(style) + extra_vec = torch.cat([extra_vec, style_embedding], dim=1) + + # Concatenate all extra vectors + c = t + self.extra_embedder(extra_vec) # [B, D] + + controls = None + # ========================= Forward pass through HunYuanDiT blocks ========================= + skips = [] + for layer, block in enumerate(self.blocks): + if layer > self.depth // 2: + if controls is not None: + skip = skips.pop() + controls.pop() + else: + skip = skips.pop() + x = block(x, c, text_states, freqs_cis_img, skip) # (N, L, D) + else: + x = block(x, c, text_states, freqs_cis_img) # (N, L, D) + + if layer < (self.depth // 2 - 1): + skips.append(x) + if controls is not None and len(controls) != 0: + raise ValueError("The number of controls is not equal to the number of skip connections.") + + # ========================= Final layer ========================= + x = self.final_layer(x, c) # (N, L, patch_size ** 2 * out_channels) + x = self.unpatchify(x, th, tw) # (N, out_channels, H, W) + + if return_dict: + return {'x': x} + if self.learn_sigma: + return x[:,:self.out_channels // 2,:oh,:ow] + return x[:,:,:oh,:ow] + + def unpatchify(self, x, h, w): + """ + x: (N, T, patch_size**2 * C) + imgs: (N, H, W, C) + """ + c = self.unpatchify_channels + p = self.x_embedder.patch_size[0] + # h = w = int(x.shape[1] ** 0.5) + assert h * w == x.shape[1] + + x = x.reshape(shape=(x.shape[0], h, w, p, p, c)) + x = torch.einsum('nhwpqc->nchpwq', x) + imgs = x.reshape(shape=(x.shape[0], c, h * p, w * p)) + return imgs diff --git a/comfy/ldm/hydit/poolers.py b/comfy/ldm/hydit/poolers.py new file mode 100644 index 000000000..2c6e46e67 --- /dev/null +++ b/comfy/ldm/hydit/poolers.py @@ -0,0 +1,37 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from comfy.ldm.modules.attention import optimized_attention #TODO + + +class AttentionPool(nn.Module): + def __init__(self, spacial_dim: int, embed_dim: int, num_heads: int, output_dim: int = None, dtype=None, device=None, operations=None): + super().__init__() + self.positional_embedding = nn.Parameter(torch.empty(spacial_dim + 1, embed_dim, dtype=dtype, device=device)) + self.k_proj = operations.Linear(embed_dim, embed_dim, dtype=dtype, device=device) + self.q_proj = operations.Linear(embed_dim, embed_dim, dtype=dtype, device=device) + self.v_proj = operations.Linear(embed_dim, embed_dim, dtype=dtype, device=device) + self.c_proj = operations.Linear(embed_dim, output_dim or embed_dim, dtype=dtype, device=device) + self.num_heads = num_heads + self.embed_dim = embed_dim + + def forward(self, x): + x = x[:,:self.positional_embedding.shape[0] - 1] + x = x.permute(1, 0, 2) # NLC -> LNC + x = torch.cat([x.mean(dim=0, keepdim=True), x], dim=0) # (L+1)NC + x = x + self.positional_embedding[:, None, :].to(dtype=x.dtype, device=x.device) # (L+1)NC + + q = self.q_proj(x[:1]) + k = self.k_proj(x) + v = self.v_proj(x) + + batch_size = q.shape[1] + head_dim = self.embed_dim // self.num_heads + q = q.view(1, batch_size * self.num_heads, head_dim).transpose(0, 1).view(batch_size, self.num_heads, -1, head_dim) + k = k.view(k.shape[0], batch_size * self.num_heads, head_dim).transpose(0, 1).view(batch_size, self.num_heads, -1, head_dim) + v = v.view(v.shape[0], batch_size * self.num_heads, head_dim).transpose(0, 1).view(batch_size, self.num_heads, -1, head_dim) + + attn_output = optimized_attention(q, k, v, self.num_heads, skip_reshape=True).transpose(0, 1) + + attn_output = self.c_proj(attn_output) + return attn_output.squeeze(0) diff --git a/comfy/ldm/hydit/posemb_layers.py b/comfy/ldm/hydit/posemb_layers.py new file mode 100644 index 000000000..dcb41a713 --- /dev/null +++ b/comfy/ldm/hydit/posemb_layers.py @@ -0,0 +1,224 @@ +import torch +import numpy as np +from typing import Union + + +def _to_tuple(x): + if isinstance(x, int): + return x, x + else: + return x + + +def get_fill_resize_and_crop(src, tgt): + th, tw = _to_tuple(tgt) + h, w = _to_tuple(src) + + tr = th / tw # base resolution + r = h / w # target resolution + + # resize + if r > tr: + resize_height = th + resize_width = int(round(th / h * w)) + else: + resize_width = tw + resize_height = int(round(tw / w * h)) # resize the target resolution down based on the base resolution + + crop_top = int(round((th - resize_height) / 2.0)) + crop_left = int(round((tw - resize_width) / 2.0)) + + return (crop_top, crop_left), (crop_top + resize_height, crop_left + resize_width) + + +def get_meshgrid(start, *args): + if len(args) == 0: + # start is grid_size + num = _to_tuple(start) + start = (0, 0) + stop = num + elif len(args) == 1: + # start is start, args[0] is stop, step is 1 + start = _to_tuple(start) + stop = _to_tuple(args[0]) + num = (stop[0] - start[0], stop[1] - start[1]) + elif len(args) == 2: + # start is start, args[0] is stop, args[1] is num + start = _to_tuple(start) + stop = _to_tuple(args[0]) + num = _to_tuple(args[1]) + else: + raise ValueError(f"len(args) should be 0, 1 or 2, but got {len(args)}") + + grid_h = np.linspace(start[0], stop[0], num[0], endpoint=False, dtype=np.float32) + grid_w = np.linspace(start[1], stop[1], num[1], endpoint=False, dtype=np.float32) + grid = np.meshgrid(grid_w, grid_h) # here w goes first + grid = np.stack(grid, axis=0) # [2, W, H] + return grid + +################################################################################# +# Sine/Cosine Positional Embedding Functions # +################################################################################# +# https://github.com/facebookresearch/mae/blob/main/util/pos_embed.py + +def get_2d_sincos_pos_embed(embed_dim, start, *args, cls_token=False, extra_tokens=0): + """ + grid_size: int of the grid height and width + return: + pos_embed: [grid_size*grid_size, embed_dim] or [1+grid_size*grid_size, embed_dim] (w/ or w/o cls_token) + """ + grid = get_meshgrid(start, *args) # [2, H, w] + # grid_h = np.arange(grid_size, dtype=np.float32) + # grid_w = np.arange(grid_size, dtype=np.float32) + # grid = np.meshgrid(grid_w, grid_h) # here w goes first + # grid = np.stack(grid, axis=0) # [2, W, H] + + grid = grid.reshape([2, 1, *grid.shape[1:]]) + pos_embed = get_2d_sincos_pos_embed_from_grid(embed_dim, grid) + if cls_token and extra_tokens > 0: + pos_embed = np.concatenate([np.zeros([extra_tokens, embed_dim]), pos_embed], axis=0) + return pos_embed + + +def get_2d_sincos_pos_embed_from_grid(embed_dim, grid): + assert embed_dim % 2 == 0 + + # use half of dimensions to encode grid_h + emb_h = get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[0]) # (H*W, D/2) + emb_w = get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[1]) # (H*W, D/2) + + emb = np.concatenate([emb_h, emb_w], axis=1) # (H*W, D) + return emb + + +def get_1d_sincos_pos_embed_from_grid(embed_dim, pos): + """ + embed_dim: output dimension for each position + pos: a list of positions to be encoded: size (W,H) + out: (M, D) + """ + assert embed_dim % 2 == 0 + omega = np.arange(embed_dim // 2, dtype=np.float64) + omega /= embed_dim / 2. + omega = 1. / 10000**omega # (D/2,) + + pos = pos.reshape(-1) # (M,) + out = np.einsum('m,d->md', pos, omega) # (M, D/2), outer product + + emb_sin = np.sin(out) # (M, D/2) + emb_cos = np.cos(out) # (M, D/2) + + emb = np.concatenate([emb_sin, emb_cos], axis=1) # (M, D) + return emb + + +################################################################################# +# Rotary Positional Embedding Functions # +################################################################################# +# https://github.com/facebookresearch/llama/blob/main/llama/model.py#L443 + +def get_2d_rotary_pos_embed(embed_dim, start, *args, use_real=True): + """ + This is a 2d version of precompute_freqs_cis, which is a RoPE for image tokens with 2d structure. + + Parameters + ---------- + embed_dim: int + embedding dimension size + start: int or tuple of int + If len(args) == 0, start is num; If len(args) == 1, start is start, args[0] is stop, step is 1; + If len(args) == 2, start is start, args[0] is stop, args[1] is num. + use_real: bool + If True, return real part and imaginary part separately. Otherwise, return complex numbers. + + Returns + ------- + pos_embed: torch.Tensor + [HW, D/2] + """ + grid = get_meshgrid(start, *args) # [2, H, w] + grid = grid.reshape([2, 1, *grid.shape[1:]]) # Returns a sampling matrix with the same resolution as the target resolution + pos_embed = get_2d_rotary_pos_embed_from_grid(embed_dim, grid, use_real=use_real) + return pos_embed + + +def get_2d_rotary_pos_embed_from_grid(embed_dim, grid, use_real=False): + assert embed_dim % 4 == 0 + + # use half of dimensions to encode grid_h + emb_h = get_1d_rotary_pos_embed(embed_dim // 2, grid[0].reshape(-1), use_real=use_real) # (H*W, D/4) + emb_w = get_1d_rotary_pos_embed(embed_dim // 2, grid[1].reshape(-1), use_real=use_real) # (H*W, D/4) + + if use_real: + cos = torch.cat([emb_h[0], emb_w[0]], dim=1) # (H*W, D/2) + sin = torch.cat([emb_h[1], emb_w[1]], dim=1) # (H*W, D/2) + return cos, sin + else: + emb = torch.cat([emb_h, emb_w], dim=1) # (H*W, D/2) + return emb + + +def get_1d_rotary_pos_embed(dim: int, pos: Union[np.ndarray, int], theta: float = 10000.0, use_real=False): + """ + Precompute the frequency tensor for complex exponentials (cis) with given dimensions. + + This function calculates a frequency tensor with complex exponentials using the given dimension 'dim' + and the end index 'end'. The 'theta' parameter scales the frequencies. + The returned tensor contains complex values in complex64 data type. + + Args: + dim (int): Dimension of the frequency tensor. + pos (np.ndarray, int): Position indices for the frequency tensor. [S] or scalar + theta (float, optional): Scaling factor for frequency computation. Defaults to 10000.0. + use_real (bool, optional): If True, return real part and imaginary part separately. + Otherwise, return complex numbers. + + Returns: + torch.Tensor: Precomputed frequency tensor with complex exponentials. [S, D/2] + + """ + if isinstance(pos, int): + pos = np.arange(pos) + freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim)) # [D/2] + t = torch.from_numpy(pos).to(freqs.device) # type: ignore # [S] + freqs = torch.outer(t, freqs).float() # type: ignore # [S, D/2] + if use_real: + freqs_cos = freqs.cos().repeat_interleave(2, dim=1) # [S, D] + freqs_sin = freqs.sin().repeat_interleave(2, dim=1) # [S, D] + return freqs_cos, freqs_sin + else: + freqs_cis = torch.polar(torch.ones_like(freqs), freqs) # complex64 # [S, D/2] + return freqs_cis + + + +def calc_sizes(rope_img, patch_size, th, tw): + if rope_img == 'extend': + # Expansion mode + sub_args = [(th, tw)] + elif rope_img.startswith('base'): + # Based on the specified dimensions, other dimensions are obtained through interpolation. + base_size = int(rope_img[4:]) // 8 // patch_size + start, stop = get_fill_resize_and_crop((th, tw), base_size) + sub_args = [start, stop, (th, tw)] + else: + raise ValueError(f"Unknown rope_img: {rope_img}") + return sub_args + + +def init_image_posemb(rope_img, + resolutions, + patch_size, + hidden_size, + num_heads, + log_fn, + rope_real=True, + ): + freqs_cis_img = {} + for reso in resolutions: + th, tw = reso.height // 8 // patch_size, reso.width // 8 // patch_size + sub_args = calc_sizes(rope_img, patch_size, th, tw) + freqs_cis_img[str(reso)] = get_2d_rotary_pos_embed(hidden_size // num_heads, *sub_args, use_real=rope_real) + log_fn(f" Using image RoPE ({rope_img}) ({'real' if rope_real else 'complex'}): {sub_args} | ({reso}) " + f"{freqs_cis_img[str(reso)][0].shape if rope_real else freqs_cis_img[str(reso)].shape}") + return freqs_cis_img diff --git a/comfy/ldm/modules/diffusionmodules/mmdit.py b/comfy/ldm/modules/diffusionmodules/mmdit.py index 20d3a321a..f37f7ff77 100644 --- a/comfy/ldm/modules/diffusionmodules/mmdit.py +++ b/comfy/ldm/modules/diffusionmodules/mmdit.py @@ -7,6 +7,7 @@ import torch import torch.nn as nn from .. import attention from einops import rearrange, repeat +from .util import timestep_embedding def default(x, y): if x is not None: @@ -230,34 +231,8 @@ class TimestepEmbedder(nn.Module): ) self.frequency_embedding_size = frequency_embedding_size - @staticmethod - def timestep_embedding(t, dim, max_period=10000): - """ - Create sinusoidal timestep embeddings. - :param t: a 1-D Tensor of N indices, one per batch element. - These may be fractional. - :param dim: the dimension of the output. - :param max_period: controls the minimum frequency of the embeddings. - :return: an (N, D) Tensor of positional embeddings. - """ - half = dim // 2 - freqs = torch.exp( - -math.log(max_period) - * torch.arange(start=0, end=half, dtype=torch.float32, device=t.device) - / half - ) - args = t[:, None].float() * freqs[None] - embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1) - if dim % 2: - embedding = torch.cat( - [embedding, torch.zeros_like(embedding[:, :1])], dim=-1 - ) - if torch.is_floating_point(t): - embedding = embedding.to(dtype=t.dtype) - return embedding - def forward(self, t, dtype, **kwargs): - t_freq = self.timestep_embedding(t, self.frequency_embedding_size).to(dtype) + t_freq = timestep_embedding(t, self.frequency_embedding_size).to(dtype) t_emb = self.mlp(t_freq) return t_emb @@ -745,6 +720,8 @@ class MMDiT(nn.Module): qkv_bias: bool = True, context_processor_layers = None, context_size = 4096, + num_blocks = None, + final_layer = True, dtype = None, #TODO device = None, operations = None, @@ -766,7 +743,10 @@ class MMDiT(nn.Module): # apply magic --> this defines a head_size of 64 self.hidden_size = 64 * depth num_heads = depth + if num_blocks is None: + num_blocks = depth + self.depth = depth self.num_heads = num_heads self.x_embedder = PatchEmbed( @@ -821,7 +801,7 @@ class MMDiT(nn.Module): mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, attn_mode=attn_mode, - pre_only=i == depth - 1, + pre_only=(i == num_blocks - 1) and final_layer, rmsnorm=rmsnorm, scale_mod_only=scale_mod_only, swiglu=swiglu, @@ -830,11 +810,12 @@ class MMDiT(nn.Module): device=device, operations=operations ) - for i in range(depth) + for i in range(num_blocks) ] ) - self.final_layer = FinalLayer(self.hidden_size, patch_size, self.out_channels, dtype=dtype, device=device, operations=operations) + if final_layer: + self.final_layer = FinalLayer(self.hidden_size, patch_size, self.out_channels, dtype=dtype, device=device, operations=operations) if compile_core: assert False @@ -893,6 +874,7 @@ class MMDiT(nn.Module): x: torch.Tensor, c_mod: torch.Tensor, context: Optional[torch.Tensor] = None, + control = None, ) -> torch.Tensor: if self.register_length > 0: context = torch.cat( @@ -905,13 +887,20 @@ class MMDiT(nn.Module): # context is B, L', D # x is B, L, D - for block in self.joint_blocks: - context, x = block( + blocks = len(self.joint_blocks) + for i in range(blocks): + context, x = self.joint_blocks[i]( context, x, c=c_mod, use_checkpoint=self.use_checkpoint, ) + if control is not None: + control_o = control.get("output") + if i < len(control_o): + add = control_o[i] + if add is not None: + x += add x = self.final_layer(x, c_mod) # (N, T, patch_size ** 2 * out_channels) return x @@ -922,6 +911,7 @@ class MMDiT(nn.Module): t: torch.Tensor, y: Optional[torch.Tensor] = None, context: Optional[torch.Tensor] = None, + control = None, ) -> torch.Tensor: """ Forward pass of DiT. @@ -943,7 +933,7 @@ class MMDiT(nn.Module): if context is not None: context = self.context_embedder(context) - x = self.forward_core_with_concat(x, c, context) + x = self.forward_core_with_concat(x, c, context, control) x = self.unpatchify(x, hw=hw) # (N, out_channels, H, W) return x[:,:,:hw[-2],:hw[-1]] @@ -956,7 +946,8 @@ class OpenAISignatureMMDITWrapper(MMDiT): timesteps: torch.Tensor, context: Optional[torch.Tensor] = None, y: Optional[torch.Tensor] = None, + control = None, **kwargs, ) -> torch.Tensor: - return super().forward(x, timesteps, context=context, y=y) + return super().forward(x, timesteps, context=context, y=y, control=control) diff --git a/comfy/lora.py b/comfy/lora.py index 037431775..fdc128c09 100644 --- a/comfy/lora.py +++ b/comfy/lora.py @@ -274,4 +274,18 @@ def model_lora_keys_unet(model, key_map={}): key_lora = "lora_transformer_{}".format(k[:-len(".weight")].replace(".", "_")) #OneTrainer lora key_map[key_lora] = to + if isinstance(model, comfy.model_base.AuraFlow): #Diffusers lora AuraFlow + diffusers_keys = comfy.utils.auraflow_to_diffusers(model.model_config.unet_config, output_prefix="diffusion_model.") + for k in diffusers_keys: + if k.endswith(".weight"): + to = diffusers_keys[k] + key_lora = "transformer.{}".format(k[:-len(".weight")]) #simpletrainer and probably regular diffusers lora format + key_map[key_lora] = to + + if isinstance(model, comfy.model_base.HunyuanDiT): + for k in sdk: + if k.startswith("diffusion_model.") and k.endswith(".weight"): + key_lora = k[len("diffusion_model."):-len(".weight")] + key_map["base_model.model.{}".format(key_lora)] = k #official hunyuan lora format + return key_map diff --git a/comfy/model_base.py b/comfy/model_base.py index f45b375de..9d60c1fb4 100644 --- a/comfy/model_base.py +++ b/comfy/model_base.py @@ -6,6 +6,8 @@ from comfy.ldm.cascade.stage_b import StageB from comfy.ldm.modules.encoders.noise_aug_modules import CLIPEmbeddingNoiseAugmentation from comfy.ldm.modules.diffusionmodules.upscaling import ImageConcatWithNoiseAugmentation from comfy.ldm.modules.diffusionmodules.mmdit import OpenAISignatureMMDITWrapper +import comfy.ldm.aura.mmdit +import comfy.ldm.hydit.models import comfy.ldm.audio.dit import comfy.ldm.audio.embedders import comfy.model_management @@ -598,6 +600,17 @@ class SD3(BaseModel): area = input_shape[0] * input_shape[2] * input_shape[3] return (area * 0.3) * (1024 * 1024) +class AuraFlow(BaseModel): + def __init__(self, model_config, model_type=ModelType.FLOW, device=None): + super().__init__(model_config, model_type, device=device, unet_model=comfy.ldm.aura.mmdit.MMDiT) + + def extra_conds(self, **kwargs): + out = super().extra_conds(**kwargs) + cross_attn = kwargs.get("cross_attn", None) + if cross_attn is not None: + out['c_crossattn'] = comfy.conds.CONDRegular(cross_attn) + return out + class StableAudio1(BaseModel): def __init__(self, model_config, seconds_start_embedder_weights, seconds_total_embedder_weights, model_type=ModelType.V_PREDICTION_CONTINUOUS, device=None): @@ -627,3 +640,44 @@ class StableAudio1(BaseModel): cross_attn = torch.cat([cross_attn.to(device), seconds_start_embed.repeat((cross_attn.shape[0], 1, 1)), seconds_total_embed.repeat((cross_attn.shape[0], 1, 1))], dim=1) out['c_crossattn'] = comfy.conds.CONDRegular(cross_attn) return out + + def state_dict_for_saving(self, clip_state_dict=None, vae_state_dict=None, clip_vision_state_dict=None): + sd = super().state_dict_for_saving(clip_state_dict=clip_state_dict, vae_state_dict=vae_state_dict, clip_vision_state_dict=clip_vision_state_dict) + d = {"conditioner.conditioners.seconds_start.": self.seconds_start_embedder.state_dict(), "conditioner.conditioners.seconds_total.": self.seconds_total_embedder.state_dict()} + for k in d: + s = d[k] + for l in s: + sd["{}{}".format(k, l)] = s[l] + return sd + +class HunyuanDiT(BaseModel): + def __init__(self, model_config, model_type=ModelType.V_PREDICTION, device=None): + super().__init__(model_config, model_type, device=device, unet_model=comfy.ldm.hydit.models.HunYuanDiT) + + def extra_conds(self, **kwargs): + out = super().extra_conds(**kwargs) + cross_attn = kwargs.get("cross_attn", None) + if cross_attn is not None: + out['c_crossattn'] = comfy.conds.CONDRegular(cross_attn) + + attention_mask = kwargs.get("attention_mask", None) + if attention_mask is not None: + out['text_embedding_mask'] = comfy.conds.CONDRegular(attention_mask) + + conditioning_mt5xl = kwargs.get("conditioning_mt5xl", None) + if conditioning_mt5xl is not None: + out['encoder_hidden_states_t5'] = comfy.conds.CONDRegular(conditioning_mt5xl) + + attention_mask_mt5xl = kwargs.get("attention_mask_mt5xl", None) + if attention_mask_mt5xl is not None: + out['text_embedding_mask_t5'] = comfy.conds.CONDRegular(attention_mask_mt5xl) + + width = kwargs.get("width", 768) + height = kwargs.get("height", 768) + crop_w = kwargs.get("crop_w", 0) + crop_h = kwargs.get("crop_h", 0) + target_width = kwargs.get("target_width", width) + target_height = kwargs.get("target_height", height) + + out['image_meta_size'] = comfy.conds.CONDRegular(torch.FloatTensor([[height, width, target_height, target_width, 0, 0]])) + return out diff --git a/comfy/model_detection.py b/comfy/model_detection.py index e09dd381a..ea4959370 100644 --- a/comfy/model_detection.py +++ b/comfy/model_detection.py @@ -41,7 +41,9 @@ def detect_unet_config(state_dict, key_prefix): unet_config["in_channels"] = state_dict['{}x_embedder.proj.weight'.format(key_prefix)].shape[1] patch_size = state_dict['{}x_embedder.proj.weight'.format(key_prefix)].shape[2] unet_config["patch_size"] = patch_size - unet_config["out_channels"] = state_dict['{}final_layer.linear.weight'.format(key_prefix)].shape[0] // (patch_size * patch_size) + final_layer = '{}final_layer.linear.weight'.format(key_prefix) + if final_layer in state_dict: + unet_config["out_channels"] = state_dict[final_layer].shape[0] // (patch_size * patch_size) unet_config["depth"] = state_dict['{}x_embedder.proj.weight'.format(key_prefix)].shape[0] // 64 unet_config["input_size"] = None @@ -103,6 +105,32 @@ def detect_unet_config(state_dict, key_prefix): unet_config["audio_model"] = "dit1.0" return unet_config + if '{}double_layers.0.attn.w1q.weight'.format(key_prefix) in state_dict_keys: #aura flow dit + unet_config = {} + unet_config["max_seq"] = state_dict['{}positional_encoding'.format(key_prefix)].shape[1] + unet_config["cond_seq_dim"] = state_dict['{}cond_seq_linear.weight'.format(key_prefix)].shape[1] + double_layers = count_blocks(state_dict_keys, '{}double_layers.'.format(key_prefix) + '{}.') + single_layers = count_blocks(state_dict_keys, '{}single_layers.'.format(key_prefix) + '{}.') + unet_config["n_double_layers"] = double_layers + unet_config["n_layers"] = double_layers + single_layers + return unet_config + + if '{}mlp_t5.0.weight'.format(key_prefix) in state_dict_keys: #Hunyuan DiT + unet_config = {} + unet_config["image_model"] = "hydit" + unet_config["depth"] = count_blocks(state_dict_keys, '{}blocks.'.format(key_prefix) + '{}.') + unet_config["hidden_size"] = state_dict['{}x_embedder.proj.weight'.format(key_prefix)].shape[0] + if unet_config["hidden_size"] == 1408 and unet_config["depth"] == 40: #DiT-g/2 + unet_config["mlp_ratio"] = 4.3637 + if state_dict['{}extra_embedder.0.weight'.format(key_prefix)].shape[1] == 3968: + unet_config["size_cond"] = True + unet_config["use_style_cond"] = True + unet_config["image_model"] = "hydit1" + return unet_config + + if '{}input_blocks.0.0.weight'.format(key_prefix) not in state_dict_keys: + return None + unet_config = { "use_checkpoint": False, "image_size": 32, @@ -237,6 +265,8 @@ def model_config_from_unet_config(unet_config, state_dict=None): def model_config_from_unet(state_dict, unet_key_prefix, use_base_if_no_match=False): unet_config = detect_unet_config(state_dict, unet_key_prefix) + if unet_config is None: + return None model_config = model_config_from_unet_config(unet_config, state_dict) if model_config is None and use_base_if_no_match: return comfy.supported_models_base.BASE(unet_config) @@ -244,11 +274,22 @@ def model_config_from_unet(state_dict, unet_key_prefix, use_base_if_no_match=Fal return model_config def unet_prefix_from_state_dict(state_dict): - if "model.model.postprocess_conv.weight" in state_dict: #audio models - unet_key_prefix = "model.model." + candidates = ["model.diffusion_model.", #ldm/sgm models + "model.model.", #audio models + ] + counts = {k: 0 for k in candidates} + for k in state_dict: + for c in candidates: + if k.startswith(c): + counts[c] += 1 + break + + top = max(counts, key=counts.get) + if counts[top] > 5: + return top else: - unet_key_prefix = "model.diffusion_model." - return unet_key_prefix + return "model." #aura flow and others + def convert_config(unet_config): new_config = unet_config.copy() @@ -435,36 +476,45 @@ def model_config_from_diffusers_unet(state_dict): return None def convert_diffusers_mmdit(state_dict, output_prefix=""): - depth = count_blocks(state_dict, 'transformer_blocks.{}.') - if depth > 0: - out_sd = {} - sd_map = comfy.utils.mmdit_to_diffusers({"depth": depth}, output_prefix=output_prefix) - for k in sd_map: - weight = state_dict.get(k, None) - if weight is not None: - t = sd_map[k] + out_sd = {} - if not isinstance(t, str): - if len(t) > 2: - fun = t[2] - else: - fun = lambda a: a - offset = t[1] - if offset is not None: - old_weight = out_sd.get(t[0], None) - if old_weight is None: - old_weight = torch.empty_like(weight) - old_weight = old_weight.repeat([3] + [1] * (len(old_weight.shape) - 1)) + if 'transformer_blocks.0.attn.add_q_proj.weight' in state_dict: #SD3 + num_blocks = count_blocks(state_dict, 'transformer_blocks.{}.') + depth = state_dict["pos_embed.proj.weight"].shape[0] // 64 + sd_map = comfy.utils.mmdit_to_diffusers({"depth": depth, "num_blocks": num_blocks}, output_prefix=output_prefix) + elif 'joint_transformer_blocks.0.attn.add_k_proj.weight' in state_dict: #AuraFlow + num_joint = count_blocks(state_dict, 'joint_transformer_blocks.{}.') + num_single = count_blocks(state_dict, 'single_transformer_blocks.{}.') + sd_map = comfy.utils.auraflow_to_diffusers({"n_double_layers": num_joint, "n_layers": num_joint + num_single}, output_prefix=output_prefix) + else: + return None - w = old_weight.narrow(offset[0], offset[1], offset[2]) - else: - old_weight = weight - w = weight - w[:] = fun(weight) - t = t[0] - out_sd[t] = old_weight + for k in sd_map: + weight = state_dict.get(k, None) + if weight is not None: + t = sd_map[k] + + if not isinstance(t, str): + if len(t) > 2: + fun = t[2] else: - out_sd[t] = weight - state_dict.pop(k) + fun = lambda a: a + offset = t[1] + if offset is not None: + old_weight = out_sd.get(t[0], None) + if old_weight is None: + old_weight = torch.empty_like(weight) + old_weight = old_weight.repeat([3] + [1] * (len(old_weight.shape) - 1)) + + w = old_weight.narrow(offset[0], offset[1], offset[2]) + else: + old_weight = weight + w = weight + w[:] = fun(weight) + t = t[0] + out_sd[t] = old_weight + else: + out_sd[t] = weight + state_dict.pop(k) return out_sd diff --git a/comfy/model_patcher.py b/comfy/model_patcher.py index b949031e9..efac251ca 100644 --- a/comfy/model_patcher.py +++ b/comfy/model_patcher.py @@ -57,6 +57,12 @@ def set_model_options_post_cfg_function(model_options, post_cfg_function, disabl model_options["disable_cfg1_optimization"] = True return model_options +def set_model_options_pre_cfg_function(model_options, pre_cfg_function, disable_cfg1_optimization=False): + model_options["sampler_pre_cfg_function"] = model_options.get("sampler_pre_cfg_function", []) + [pre_cfg_function] + if disable_cfg1_optimization: + model_options["disable_cfg1_optimization"] = True + return model_options + class ModelPatcher: def __init__(self, model, load_device, offload_device, size=0, current_device=None, weight_inplace_update=False): self.size = size @@ -130,6 +136,9 @@ class ModelPatcher: def set_model_sampler_post_cfg_function(self, post_cfg_function, disable_cfg1_optimization=False): self.model_options = set_model_options_post_cfg_function(self.model_options, post_cfg_function, disable_cfg1_optimization) + def set_model_sampler_pre_cfg_function(self, pre_cfg_function, disable_cfg1_optimization=False): + self.model_options = set_model_options_pre_cfg_function(self.model_options, pre_cfg_function, disable_cfg1_optimization) + def set_model_unet_function_wrapper(self, unet_wrapper_function: UnetWrapperFunction): self.model_options["model_function_wrapper"] = unet_wrapper_function diff --git a/comfy/model_sampling.py b/comfy/model_sampling.py index 6bd3a5d79..25bb7e043 100644 --- a/comfy/model_sampling.py +++ b/comfy/model_sampling.py @@ -59,8 +59,9 @@ class ModelSamplingDiscrete(torch.nn.Module): beta_schedule = sampling_settings.get("beta_schedule", "linear") linear_start = sampling_settings.get("linear_start", 0.00085) linear_end = sampling_settings.get("linear_end", 0.012) + timesteps = sampling_settings.get("timesteps", 1000) - self._register_schedule(given_betas=None, beta_schedule=beta_schedule, timesteps=1000, linear_start=linear_start, linear_end=linear_end, cosine_s=8e-3) + self._register_schedule(given_betas=None, beta_schedule=beta_schedule, timesteps=timesteps, linear_start=linear_start, linear_end=linear_end, cosine_s=8e-3) self.sigma_data = 1.0 def _register_schedule(self, given_betas=None, beta_schedule="linear", timesteps=1000, @@ -190,11 +191,12 @@ class ModelSamplingDiscreteFlow(torch.nn.Module): else: sampling_settings = {} - self.set_parameters(shift=sampling_settings.get("shift", 1.0)) + self.set_parameters(shift=sampling_settings.get("shift", 1.0), multiplier=sampling_settings.get("multiplier", 1000)) - def set_parameters(self, shift=1.0, timesteps=1000): + def set_parameters(self, shift=1.0, timesteps=1000, multiplier=1000): self.shift = shift - ts = self.sigma(torch.arange(1, timesteps + 1, 1)) + self.multiplier = multiplier + ts = self.sigma((torch.arange(1, timesteps + 1, 1) / timesteps) * multiplier) self.register_buffer('sigmas', ts) @property @@ -206,10 +208,10 @@ class ModelSamplingDiscreteFlow(torch.nn.Module): return self.sigmas[-1] def timestep(self, sigma): - return sigma * 1000 + return sigma * self.multiplier def sigma(self, timestep): - return time_snr_shift(self.shift, timestep / 1000) + return time_snr_shift(self.shift, timestep / self.multiplier) def percent_to_sigma(self, percent): if percent <= 0.0: diff --git a/comfy/samplers.py b/comfy/samplers.py index 55b1486b4..3f7633814 100644 --- a/comfy/samplers.py +++ b/comfy/samplers.py @@ -6,6 +6,8 @@ from comfy import model_management import math import logging import comfy.sampler_helpers +import scipy +import numpy def get_area_and_mult(conds, x_in, timestep_in): dims = tuple(x_in.shape[2:]) @@ -275,6 +277,12 @@ def sampling_function(model, x, timestep, uncond, cond, cond_scale, model_option conds = [cond, uncond_] out = calc_cond_batch(model, conds, x, timestep, model_options) + + for fn in model_options.get("sampler_pre_cfg_function", []): + args = {"conds":conds, "conds_out": out, "cond_scale": cond_scale, "timestep": timestep, + "input": x, "sigma": timestep, "model": model, "model_options": model_options} + out = fn(args) + return cfg_function(model, out[0], out[1], cond_scale, x, timestep, model_options=model_options, cond=cond, uncond=uncond_) @@ -305,13 +313,18 @@ def simple_scheduler(model_sampling, steps): def ddim_scheduler(model_sampling, steps): s = model_sampling sigs = [] - ss = max(len(s.sigmas) // steps, 1) x = 1 + if math.isclose(float(s.sigmas[x]), 0, abs_tol=0.00001): + steps += 1 + sigs = [] + else: + sigs = [0.0] + + ss = max(len(s.sigmas) // steps, 1) while x < len(s.sigmas): sigs += [float(s.sigmas[x])] x += ss sigs = sigs[::-1] - sigs += [0.0] return torch.FloatTensor(sigs) def normal_scheduler(model_sampling, steps, sgm=False, floor=False): @@ -319,15 +332,34 @@ def normal_scheduler(model_sampling, steps, sgm=False, floor=False): start = s.timestep(s.sigma_max) end = s.timestep(s.sigma_min) + append_zero = True if sgm: timesteps = torch.linspace(start, end, steps + 1)[:-1] else: + if math.isclose(float(s.sigma(end)), 0, abs_tol=0.00001): + steps += 1 + append_zero = False timesteps = torch.linspace(start, end, steps) sigs = [] for x in range(len(timesteps)): ts = timesteps[x] - sigs.append(s.sigma(ts)) + sigs.append(float(s.sigma(ts))) + + if append_zero: + sigs += [0.0] + + return torch.FloatTensor(sigs) + +# Implemented based on: https://arxiv.org/abs/2407.12173 +def beta_scheduler(model_sampling, steps, alpha=0.6, beta=0.6): + total_timesteps = (len(model_sampling.sigmas) - 1) + ts = 1 - numpy.linspace(0, 1, steps, endpoint=False) + ts = numpy.rint(scipy.stats.beta.ppf(ts, alpha, beta) * total_timesteps) + + sigs = [] + for t in ts: + sigs += [float(model_sampling.sigmas[int(t)])] sigs += [0.0] return torch.FloatTensor(sigs) @@ -537,10 +569,10 @@ class Sampler: sigma = float(sigmas[0]) return math.isclose(max_sigma, sigma, rel_tol=1e-05) or sigma > max_sigma -KSAMPLER_NAMES = ["euler", "euler_ancestral", "heun", "heunpp2","dpm_2", "dpm_2_ancestral", +KSAMPLER_NAMES = ["euler", "euler_cfg_pp", "euler_ancestral", "euler_ancestral_cfg_pp", "heun", "heunpp2","dpm_2", "dpm_2_ancestral", "lms", "dpm_fast", "dpm_adaptive", "dpmpp_2s_ancestral", "dpmpp_sde", "dpmpp_sde_gpu", "dpmpp_2m", "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", "dpmpp_3m_sde_gpu", "ddpm", "lcm", - "ipndm", "ipndm_v"] + "ipndm", "ipndm_v", "deis"] class KSAMPLER(Sampler): def __init__(self, sampler_function, extra_options={}, inpaint_options={}): @@ -697,7 +729,7 @@ def sample(model, noise, positive, negative, cfg, device, sampler, sigmas, model return cfg_guider.sample(noise, latent_image, sampler, sigmas, denoise_mask, callback, disable_pbar, seed) -SCHEDULER_NAMES = ["normal", "karras", "exponential", "sgm_uniform", "simple", "ddim_uniform"] +SCHEDULER_NAMES = ["normal", "karras", "exponential", "sgm_uniform", "simple", "ddim_uniform", "beta"] SAMPLER_NAMES = KSAMPLER_NAMES + ["ddim", "uni_pc", "uni_pc_bh2"] def calculate_sigmas(model_sampling, scheduler_name, steps): @@ -713,6 +745,8 @@ def calculate_sigmas(model_sampling, scheduler_name, steps): sigmas = ddim_scheduler(model_sampling, steps) elif scheduler_name == "sgm_uniform": sigmas = normal_scheduler(model_sampling, steps, sgm=True) + elif scheduler_name == "beta": + sigmas = beta_scheduler(model_sampling, steps) else: logging.error("error invalid scheduler {}".format(scheduler_name)) return sigmas diff --git a/comfy/sd.py b/comfy/sd.py index ea6e9b663..b1d38c4b2 100644 --- a/comfy/sd.py +++ b/comfy/sd.py @@ -19,8 +19,10 @@ from . import model_detection from . import sd1_clip from . import sd2_clip from . import sdxl_clip -from . import sd3_clip -from . import sa_t5 +import comfy.text_encoders.sd3_clip +import comfy.text_encoders.sa_t5 +import comfy.text_encoders.aura_t5 +import comfy.text_encoders.hydit import comfy.model_patcher import comfy.lora @@ -28,36 +30,6 @@ import comfy.t2i_adapter.adapter import comfy.supported_models_base import comfy.taesd.taesd -def load_model_weights(model, sd): - m, u = model.load_state_dict(sd, strict=False) - m = set(m) - unexpected_keys = set(u) - - k = list(sd.keys()) - for x in k: - if x not in unexpected_keys: - w = sd.pop(x) - del w - if len(m) > 0: - logging.warning("missing {}".format(m)) - return model - -def load_clip_weights(model, sd): - k = list(sd.keys()) - for x in k: - if x.startswith("cond_stage_model.transformer.") and not x.startswith("cond_stage_model.transformer.text_model."): - y = x.replace("cond_stage_model.transformer.", "cond_stage_model.transformer.text_model.") - sd[y] = sd.pop(x) - - if 'cond_stage_model.transformer.text_model.embeddings.position_ids' in sd: - ids = sd['cond_stage_model.transformer.text_model.embeddings.position_ids'] - if ids.dtype == torch.float32: - sd['cond_stage_model.transformer.text_model.embeddings.position_ids'] = ids.round() - - sd = comfy.utils.clip_text_transformers_convert(sd, "cond_stage_model.model.", "cond_stage_model.transformer.") - return load_model_weights(model, sd) - - def load_lora_for_models(model, clip, lora, strength_model, strength_clip): key_map = {} if model is not None: @@ -89,7 +61,7 @@ def load_lora_for_models(model, clip, lora, strength_model, strength_clip): class CLIP: - def __init__(self, target=None, embedding_directory=None, no_init=False): + def __init__(self, target=None, embedding_directory=None, no_init=False, tokenizer_data={}): if no_init: return params = target.params.copy() @@ -108,7 +80,7 @@ class CLIP: if not model_management.supports_cast(load_device, dt): load_device = offload_device - self.tokenizer = tokenizer(embedding_directory=embedding_directory) + self.tokenizer = tokenizer(embedding_directory=embedding_directory, tokenizer_data=tokenizer_data) self.patcher = comfy.model_patcher.ModelPatcher(self.cond_stage_model, load_device=load_device, offload_device=offload_device) self.layer_idx = None logging.debug("CLIP model load device: {}, offload device: {}".format(load_device, offload_device)) @@ -130,7 +102,7 @@ class CLIP: def tokenize(self, text, return_word_ids=False): return self.tokenizer.tokenize_with_weights(text, return_word_ids) - def encode_from_tokens(self, tokens, return_pooled=False): + def encode_from_tokens(self, tokens, return_pooled=False, return_dict=False): self.cond_stage_model.reset_clip_options() if self.layer_idx is not None: @@ -140,7 +112,15 @@ class CLIP: self.cond_stage_model.set_clip_options({"projected_pooled": False}) self.load_model() - cond, pooled = self.cond_stage_model.encode_token_weights(tokens) + o = self.cond_stage_model.encode_token_weights(tokens) + cond, pooled = o[:2] + if return_dict: + out = {"cond": cond, "pooled_output": pooled} + if len(o) > 2: + for k in o[2]: + out[k] = o[2][k] + return out + if return_pooled: return cond, pooled return cond @@ -156,7 +136,11 @@ class CLIP: return self.cond_stage_model.load_sd(sd) def get_sd(self): - return self.cond_stage_model.state_dict() + sd_clip = self.cond_stage_model.state_dict() + sd_tokenizer = self.tokenizer.state_dict() + for k in sd_tokenizer: + sd_clip[k] = sd_tokenizer[k] + return sd_clip def load_model(self): model_management.load_model_gpu(self.patcher) @@ -236,7 +220,7 @@ class VAE: self.first_stage_model = AutoencodingEngine(regularizer_config={'target': "comfy.ldm.models.autoencoder.DiagonalGaussianRegularizer"}, encoder_config={'target': "comfy.ldm.modules.diffusionmodules.model.Encoder", 'params': ddconfig}, decoder_config={'target': "comfy.ldm.modules.diffusionmodules.model.Decoder", 'params': ddconfig}) - elif "decoder.layers.0.weight_v" in sd: + elif "decoder.layers.1.layers.0.beta" in sd: self.first_stage_model = AudioOobleckVAE() self.memory_used_encode = lambda shape, dtype: (1000 * shape[2]) * model_management.dtype_size(dtype) self.memory_used_decode = lambda shape, dtype: (1000 * shape[2] * 2048) * model_management.dtype_size(dtype) @@ -402,6 +386,7 @@ class CLIPType(Enum): STABLE_CASCADE = 2 SD3 = 3 STABLE_AUDIO = 4 + HUNYUAN_DIT = 5 def load_clip(ckpt_paths, embedding_directory=None, clip_type=CLIPType.STABLE_DIFFUSION): clip_data = [] @@ -432,25 +417,33 @@ def load_clip(ckpt_paths, embedding_directory=None, clip_type=CLIPType.STABLE_DI clip_target.clip = sd2_clip.SD2ClipModel clip_target.tokenizer = sd2_clip.SD2Tokenizer elif "encoder.block.23.layer.1.DenseReluDense.wi_1.weight" in clip_data[0]: - dtype_t5 = clip_data[0]["encoder.block.23.layer.1.DenseReluDense.wi_1.weight"].dtype - clip_target.clip = sd3_clip.sd3_clip(clip_l=False, clip_g=False, t5=True, dtype_t5=dtype_t5) - clip_target.tokenizer = sd3_clip.SD3Tokenizer + weight = clip_data[0]["encoder.block.23.layer.1.DenseReluDense.wi_1.weight"] + dtype_t5 = weight.dtype + if weight.shape[-1] == 4096: + clip_target.clip = comfy.text_encoders.sd3_clip.sd3_clip(clip_l=False, clip_g=False, t5=True, dtype_t5=dtype_t5) + clip_target.tokenizer = comfy.text_encoders.sd3_clip.SD3Tokenizer + elif weight.shape[-1] == 2048: + clip_target.clip = comfy.text_encoders.aura_t5.AuraT5Model + clip_target.tokenizer = comfy.text_encoders.aura_t5.AuraT5Tokenizer elif "encoder.block.0.layer.0.SelfAttention.k.weight" in clip_data[0]: - clip_target.clip = sa_t5.SAT5Model - clip_target.tokenizer = sa_t5.SAT5Tokenizer + clip_target.clip = comfy.text_encoders.sa_t5.SAT5Model + clip_target.tokenizer = comfy.text_encoders.sa_t5.SAT5Tokenizer else: clip_target.clip = sd1_clip.SD1ClipModel clip_target.tokenizer = sd1_clip.SD1Tokenizer elif len(clip_data) == 2: if clip_type == CLIPType.SD3: - clip_target.clip = sd3_clip.sd3_clip(clip_l=True, clip_g=True, t5=False) - clip_target.tokenizer = sd3_clip.SD3Tokenizer + clip_target.clip = comfy.text_encoders.sd3_clip.sd3_clip(clip_l=True, clip_g=True, t5=False) + clip_target.tokenizer = comfy.text_encoders.sd3_clip.SD3Tokenizer + elif clip_type == CLIPType.HUNYUAN_DIT: + clip_target.clip = comfy.text_encoders.hydit.HyditModel + clip_target.tokenizer = comfy.text_encoders.hydit.HyditTokenizer else: clip_target.clip = sdxl_clip.SDXLClipModel clip_target.tokenizer = sdxl_clip.SDXLTokenizer elif len(clip_data) == 3: - clip_target.clip = sd3_clip.SD3ClipModel - clip_target.tokenizer = sd3_clip.SD3Tokenizer + clip_target.clip = comfy.text_encoders.sd3_clip.SD3ClipModel + clip_target.tokenizer = comfy.text_encoders.sd3_clip.SD3Tokenizer clip = CLIP(clip_target, embedding_directory=embedding_directory) for c in clip_data: @@ -509,13 +502,13 @@ def load_checkpoint_guess_config(ckpt_path, output_vae=True, output_clip=True, o load_device = model_management.get_torch_device() model_config = model_detection.model_config_from_unet(sd, diffusion_model_prefix) + if model_config is None: + raise RuntimeError("ERROR: Could not detect model type of: {}".format(ckpt_path)) + unet_dtype = model_management.unet_dtype(model_params=parameters, supported_dtypes=model_config.supported_inference_dtypes) manual_cast_dtype = model_management.unet_manual_cast(unet_dtype, load_device, model_config.supported_inference_dtypes) model_config.set_inference_dtype(unet_dtype, manual_cast_dtype) - if model_config is None: - raise RuntimeError("ERROR: Could not detect model type of: {}".format(ckpt_path)) - if model_config.clip_vision_prefix is not None: if output_clipvision: clipvision = clip_vision.load_clipvision_from_sd(sd, model_config.clip_vision_prefix, True) @@ -536,7 +529,7 @@ def load_checkpoint_guess_config(ckpt_path, output_vae=True, output_clip=True, o if clip_target is not None: clip_sd = model_config.process_clip_state_dict(sd) if len(clip_sd) > 0: - clip = CLIP(clip_target, embedding_directory=embedding_directory) + clip = CLIP(clip_target, embedding_directory=embedding_directory, tokenizer_data=clip_sd) m, u = clip.load_sd(clip_sd, full_model=True) if len(m) > 0: m_filter = list(filter(lambda a: ".logit_scale" not in a and ".transformer.text_projection.weight" not in a, m)) @@ -563,37 +556,40 @@ def load_checkpoint_guess_config(ckpt_path, output_vae=True, output_clip=True, o return (model_patcher, clip, vae, clipvision) -def load_unet_state_dict(sd): #load unet in diffusers format +def load_unet_state_dict(sd): #load unet in diffusers or regular format + + #Allow loading unets from checkpoint files + diffusion_model_prefix = model_detection.unet_prefix_from_state_dict(sd) + temp_sd = comfy.utils.state_dict_prefix_replace(sd, {diffusion_model_prefix: ""}, filter_keys=True) + if len(temp_sd) > 0: + sd = temp_sd + parameters = comfy.utils.calculate_parameters(sd) unet_dtype = model_management.unet_dtype(model_params=parameters) load_device = model_management.get_torch_device() + model_config = model_detection.model_config_from_unet(sd, "") - if 'transformer_blocks.0.attn.add_q_proj.weight' in sd: #MMDIT SD3 - new_sd = model_detection.convert_diffusers_mmdit(sd, "") - if new_sd is None: - return None - model_config = model_detection.model_config_from_unet(new_sd, "") - if model_config is None: - return None - elif "input_blocks.0.0.weight" in sd or 'clf.1.weight' in sd: #ldm or stable cascade - model_config = model_detection.model_config_from_unet(sd, "") - if model_config is None: - return None + if model_config is not None: new_sd = sd + else: + new_sd = model_detection.convert_diffusers_mmdit(sd, "") + if new_sd is not None: #diffusers mmdit + model_config = model_detection.model_config_from_unet(new_sd, "") + if model_config is None: + return None + else: #diffusers unet + model_config = model_detection.model_config_from_diffusers_unet(sd) + if model_config is None: + return None - else: #diffusers - model_config = model_detection.model_config_from_diffusers_unet(sd) - if model_config is None: - return None + diffusers_keys = comfy.utils.unet_to_diffusers(model_config.unet_config) - diffusers_keys = comfy.utils.unet_to_diffusers(model_config.unet_config) - - new_sd = {} - for k in diffusers_keys: - if k in sd: - new_sd[diffusers_keys[k]] = sd.pop(k) - else: - logging.warning("{} {}".format(diffusers_keys[k], k)) + new_sd = {} + for k in diffusers_keys: + if k in sd: + new_sd[diffusers_keys[k]] = sd.pop(k) + else: + logging.warning("{} {}".format(diffusers_keys[k], k)) offload_device = model_management.unet_offload_device() unet_dtype = model_management.unet_dtype(model_params=parameters, supported_dtypes=model_config.supported_inference_dtypes) @@ -628,4 +624,9 @@ def save_checkpoint(output_path, model, clip=None, vae=None, clip_vision=None, m for k in extra_keys: sd[k] = extra_keys[k] + for k in sd: + t = sd[k] + if not t.is_contiguous(): + sd[k] = t.contiguous() + comfy.utils.save_torch_file(sd, output_path, metadata=metadata) diff --git a/comfy/sd1_clip.py b/comfy/sd1_clip.py index 78e556b56..c7bc1e4dc 100644 --- a/comfy/sd1_clip.py +++ b/comfy/sd1_clip.py @@ -38,7 +38,9 @@ class ClipTokenWeightEncoder: if has_weights or sections == 0: to_encode.append(gen_empty_tokens(self.special_tokens, max_token_len)) - out, pooled = self.encode(to_encode) + o = self.encode(to_encode) + out, pooled = o[:2] + if pooled is not None: first_pooled = pooled[0:1].to(model_management.intermediate_device()) else: @@ -57,8 +59,20 @@ class ClipTokenWeightEncoder: output.append(z) if (len(output) == 0): - return out[-1:].to(model_management.intermediate_device()), first_pooled - return torch.cat(output, dim=-2).to(model_management.intermediate_device()), first_pooled + r = (out[-1:].to(model_management.intermediate_device()), first_pooled) + else: + r = (torch.cat(output, dim=-2).to(model_management.intermediate_device()), first_pooled) + + if len(o) > 2: + extra = {} + for k in o[2]: + v = o[2][k] + if k == "attention_mask": + v = v[:sections].flatten().unsqueeze(dim=0).to(model_management.intermediate_device()) + extra[k] = v + + r = r + (extra,) + return r class SDClipModel(torch.nn.Module, ClipTokenWeightEncoder): """Uses the CLIP transformer encoder for text (from huggingface)""" @@ -70,7 +84,7 @@ class SDClipModel(torch.nn.Module, ClipTokenWeightEncoder): def __init__(self, version="openai/clip-vit-large-patch14", device="cpu", max_length=77, freeze=True, layer="last", layer_idx=None, textmodel_json_config=None, dtype=None, model_class=comfy.clip_model.CLIPTextModel, special_tokens={"start": 49406, "end": 49407, "pad": 49407}, layer_norm_hidden_state=True, enable_attention_masks=False, zero_out_masked=False, - return_projected_pooled=True): # clip-vit-base-patch32 + return_projected_pooled=True, return_attention_masks=False): # clip-vit-base-patch32 super().__init__() assert layer in self.LAYERS @@ -96,6 +110,7 @@ class SDClipModel(torch.nn.Module, ClipTokenWeightEncoder): self.layer_norm_hidden_state = layer_norm_hidden_state self.return_projected_pooled = return_projected_pooled + self.return_attention_masks = return_attention_masks if layer == "hidden": assert layer_idx is not None @@ -169,7 +184,7 @@ class SDClipModel(torch.nn.Module, ClipTokenWeightEncoder): tokens = torch.LongTensor(tokens).to(device) attention_mask = None - if self.enable_attention_masks: + if self.enable_attention_masks or self.zero_out_masked or self.return_attention_masks: attention_mask = torch.zeros_like(tokens) end_token = self.special_tokens.get("end", -1) for x in range(attention_mask.shape[0]): @@ -178,7 +193,11 @@ class SDClipModel(torch.nn.Module, ClipTokenWeightEncoder): if tokens[x, y] == end_token: break - outputs = self.transformer(tokens, attention_mask, intermediate_output=self.layer_idx, final_layer_norm_intermediate=self.layer_norm_hidden_state) + attention_mask_model = None + if self.enable_attention_masks: + attention_mask_model = attention_mask + + outputs = self.transformer(tokens, attention_mask_model, intermediate_output=self.layer_idx, final_layer_norm_intermediate=self.layer_norm_hidden_state) self.transformer.set_input_embeddings(backup_embeds) if self.layer == "last": @@ -186,7 +205,7 @@ class SDClipModel(torch.nn.Module, ClipTokenWeightEncoder): else: z = outputs[1].float() - if self.zero_out_masked and attention_mask is not None: + if self.zero_out_masked: z *= attention_mask.unsqueeze(-1).float() pooled_output = None @@ -196,6 +215,13 @@ class SDClipModel(torch.nn.Module, ClipTokenWeightEncoder): elif outputs[2] is not None: pooled_output = outputs[2].float() + extra = {} + if self.return_attention_masks: + extra["attention_mask"] = attention_mask + + if len(extra) > 0: + return z, pooled_output, extra + return z, pooled_output def encode(self, tokens): @@ -360,7 +386,7 @@ def load_embed(embedding_name, embedding_directory, embedding_size, embed_key=No return embed_out class SDTokenizer: - def __init__(self, tokenizer_path=None, max_length=77, pad_with_end=True, embedding_directory=None, embedding_size=768, embedding_key='clip_l', tokenizer_class=CLIPTokenizer, has_start_token=True, pad_to_max_length=True, min_length=None): + def __init__(self, tokenizer_path=None, max_length=77, pad_with_end=True, embedding_directory=None, embedding_size=768, embedding_key='clip_l', tokenizer_class=CLIPTokenizer, has_start_token=True, pad_to_max_length=True, min_length=None, pad_token=None, tokenizer_data={}): if tokenizer_path is None: tokenizer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "sd1_tokenizer") self.tokenizer = tokenizer_class.from_pretrained(tokenizer_path) @@ -376,6 +402,14 @@ class SDTokenizer: self.tokens_start = 0 self.start_token = None self.end_token = empty[0] + + if pad_token is not None: + self.pad_token = pad_token + elif pad_with_end: + self.pad_token = self.end_token + else: + self.pad_token = 0 + self.pad_with_end = pad_with_end self.pad_to_max_length = pad_to_max_length @@ -408,10 +442,6 @@ class SDTokenizer: Word id values are unique per word and embedding, where the id 0 is reserved for non word tokens. Returned list has the dimensions NxM where M is the input size of CLIP ''' - if self.pad_with_end: - pad_token = self.end_token - else: - pad_token = 0 text = escape_important(text) parsed_weights = token_weights(text, 1.0) @@ -463,7 +493,7 @@ class SDTokenizer: else: batch.append((self.end_token, 1.0, 0)) if self.pad_to_max_length: - batch.extend([(pad_token, 1.0, 0)] * (remaining_length)) + batch.extend([(self.pad_token, 1.0, 0)] * (remaining_length)) #start new batch batch = [] if self.start_token is not None: @@ -476,9 +506,9 @@ class SDTokenizer: #fill last batch batch.append((self.end_token, 1.0, 0)) if self.pad_to_max_length: - batch.extend([(pad_token, 1.0, 0)] * (self.max_length - len(batch))) + batch.extend([(self.pad_token, 1.0, 0)] * (self.max_length - len(batch))) if self.min_length is not None and len(batch) < self.min_length: - batch.extend([(pad_token, 1.0, 0)] * (self.min_length - len(batch))) + batch.extend([(self.pad_token, 1.0, 0)] * (self.min_length - len(batch))) if not return_word_ids: batched_tokens = [[(t, w) for t, w,_ in x] for x in batched_tokens] @@ -489,12 +519,14 @@ class SDTokenizer: def untokenize(self, token_weight_pair): return list(map(lambda a: (a, self.inv_vocab[a[0]]), token_weight_pair)) + def state_dict(self): + return {} class SD1Tokenizer: - def __init__(self, embedding_directory=None, clip_name="l", tokenizer=SDTokenizer): + def __init__(self, embedding_directory=None, tokenizer_data={}, clip_name="l", tokenizer=SDTokenizer): self.clip_name = clip_name self.clip = "clip_{}".format(self.clip_name) - setattr(self, self.clip, tokenizer(embedding_directory=embedding_directory)) + setattr(self, self.clip, tokenizer(embedding_directory=embedding_directory, tokenizer_data=tokenizer_data)) def tokenize_with_weights(self, text:str, return_word_ids=False): out = {} @@ -504,12 +536,20 @@ class SD1Tokenizer: def untokenize(self, token_weight_pair): return getattr(self, self.clip).untokenize(token_weight_pair) + def state_dict(self): + return {} class SD1ClipModel(torch.nn.Module): - def __init__(self, device="cpu", dtype=None, clip_name="l", clip_model=SDClipModel, **kwargs): + def __init__(self, device="cpu", dtype=None, clip_name="l", clip_model=SDClipModel, name=None, **kwargs): super().__init__() - self.clip_name = clip_name - self.clip = "clip_{}".format(self.clip_name) + + if name is not None: + self.clip_name = name + self.clip = "{}".format(self.clip_name) + else: + self.clip_name = clip_name + self.clip = "clip_{}".format(self.clip_name) + setattr(self, self.clip, clip_model(device=device, dtype=dtype, **kwargs)) self.dtypes = set() @@ -524,8 +564,8 @@ class SD1ClipModel(torch.nn.Module): def encode_token_weights(self, token_weight_pairs): token_weight_pairs = token_weight_pairs[self.clip_name] - out, pooled = getattr(self, self.clip).encode_token_weights(token_weight_pairs) - return out, pooled + out = getattr(self, self.clip).encode_token_weights(token_weight_pairs) + return out def load_sd(self, sd): return getattr(self, self.clip).load_sd(sd) diff --git a/comfy/sd2_clip.py b/comfy/sd2_clip.py index d14b44544..8ea8e1cd0 100644 --- a/comfy/sd2_clip.py +++ b/comfy/sd2_clip.py @@ -11,12 +11,12 @@ class SD2ClipHModel(sd1_clip.SDClipModel): super().__init__(device=device, freeze=freeze, layer=layer, layer_idx=layer_idx, textmodel_json_config=textmodel_json_config, dtype=dtype, special_tokens={"start": 49406, "end": 49407, "pad": 0}) class SD2ClipHTokenizer(sd1_clip.SDTokenizer): - def __init__(self, tokenizer_path=None, embedding_directory=None): + def __init__(self, tokenizer_path=None, embedding_directory=None, tokenizer_data={}): super().__init__(tokenizer_path, pad_with_end=False, embedding_directory=embedding_directory, embedding_size=1024) class SD2Tokenizer(sd1_clip.SD1Tokenizer): - def __init__(self, embedding_directory=None): - super().__init__(embedding_directory=embedding_directory, clip_name="h", tokenizer=SD2ClipHTokenizer) + def __init__(self, embedding_directory=None, tokenizer_data={}): + super().__init__(embedding_directory=embedding_directory, tokenizer_data=tokenizer_data, clip_name="h", tokenizer=SD2ClipHTokenizer) class SD2ClipModel(sd1_clip.SD1ClipModel): def __init__(self, device="cpu", dtype=None, **kwargs): diff --git a/comfy/sdxl_clip.py b/comfy/sdxl_clip.py index 1257cba1e..6e6b87d62 100644 --- a/comfy/sdxl_clip.py +++ b/comfy/sdxl_clip.py @@ -16,12 +16,12 @@ class SDXLClipG(sd1_clip.SDClipModel): return super().load_sd(sd) class SDXLClipGTokenizer(sd1_clip.SDTokenizer): - def __init__(self, tokenizer_path=None, embedding_directory=None): + def __init__(self, tokenizer_path=None, embedding_directory=None, tokenizer_data={}): super().__init__(tokenizer_path, pad_with_end=False, embedding_directory=embedding_directory, embedding_size=1280, embedding_key='clip_g') class SDXLTokenizer: - def __init__(self, embedding_directory=None): + def __init__(self, embedding_directory=None, tokenizer_data={}): self.clip_l = sd1_clip.SDTokenizer(embedding_directory=embedding_directory) self.clip_g = SDXLClipGTokenizer(embedding_directory=embedding_directory) @@ -34,6 +34,9 @@ class SDXLTokenizer: def untokenize(self, token_weight_pair): return self.clip_g.untokenize(token_weight_pair) + def state_dict(self): + return {} + class SDXLClipModel(torch.nn.Module): def __init__(self, device="cpu", dtype=None): super().__init__() @@ -68,12 +71,12 @@ class SDXLRefinerClipModel(sd1_clip.SD1ClipModel): class StableCascadeClipGTokenizer(sd1_clip.SDTokenizer): - def __init__(self, tokenizer_path=None, embedding_directory=None): + def __init__(self, tokenizer_path=None, embedding_directory=None, tokenizer_data={}): super().__init__(tokenizer_path, pad_with_end=True, embedding_directory=embedding_directory, embedding_size=1280, embedding_key='clip_g') class StableCascadeTokenizer(sd1_clip.SD1Tokenizer): - def __init__(self, embedding_directory=None): - super().__init__(embedding_directory=embedding_directory, clip_name="g", tokenizer=StableCascadeClipGTokenizer) + def __init__(self, embedding_directory=None, tokenizer_data={}): + super().__init__(embedding_directory=embedding_directory, tokenizer_data=tokenizer_data, clip_name="g", tokenizer=StableCascadeClipGTokenizer) class StableCascadeClipG(sd1_clip.SDClipModel): def __init__(self, device="cpu", max_length=77, freeze=True, layer="hidden", layer_idx=-1, dtype=None): diff --git a/comfy/supported_models.py b/comfy/supported_models.py index 761498dbc..40417eb4d 100644 --- a/comfy/supported_models.py +++ b/comfy/supported_models.py @@ -5,8 +5,10 @@ from . import utils from . import sd1_clip from . import sd2_clip from . import sdxl_clip -from . import sd3_clip -from . import sa_t5 +import comfy.text_encoders.sd3_clip +import comfy.text_encoders.sa_t5 +import comfy.text_encoders.aura_t5 +import comfy.text_encoders.hydit from . import supported_models_base from . import latent_formats @@ -523,7 +525,7 @@ class SD3(supported_models_base.BASE): t5 = True dtype_t5 = state_dict[t5_key].dtype - return supported_models_base.ClipTarget(sd3_clip.SD3Tokenizer, sd3_clip.sd3_clip(clip_l=clip_l, clip_g=clip_g, t5=t5, dtype_t5=dtype_t5)) + return supported_models_base.ClipTarget(comfy.text_encoders.sd3_clip.SD3Tokenizer, comfy.text_encoders.sd3_clip.sd3_clip(clip_l=clip_l, clip_g=clip_g, t5=t5, dtype_t5=dtype_t5)) class StableAudio(supported_models_base.BASE): unet_config = { @@ -543,17 +545,81 @@ class StableAudio(supported_models_base.BASE): seconds_total_sd = utils.state_dict_prefix_replace(state_dict, {"conditioner.conditioners.seconds_total.": ""}, filter_keys=True) return model_base.StableAudio1(self, seconds_start_embedder_weights=seconds_start_sd, seconds_total_embedder_weights=seconds_total_sd, device=device) - def process_unet_state_dict(self, state_dict): for k in list(state_dict.keys()): if k.endswith(".cross_attend_norm.beta") or k.endswith(".ff_norm.beta") or k.endswith(".pre_norm.beta"): #These weights are all zero state_dict.pop(k) return state_dict + def process_unet_state_dict_for_saving(self, state_dict): + replace_prefix = {"": "model.model."} + return utils.state_dict_prefix_replace(state_dict, replace_prefix) + def clip_target(self, state_dict={}): - return supported_models_base.ClipTarget(sa_t5.SAT5Tokenizer, sa_t5.SAT5Model) + return supported_models_base.ClipTarget(comfy.text_encoders.sa_t5.SAT5Tokenizer, comfy.text_encoders.sa_t5.SAT5Model) + +class AuraFlow(supported_models_base.BASE): + unet_config = { + "cond_seq_dim": 2048, + } + + sampling_settings = { + "multiplier": 1.0, + "shift": 1.73, + } + + unet_extra_config = {} + latent_format = latent_formats.SDXL + + vae_key_prefix = ["vae."] + text_encoder_key_prefix = ["text_encoders."] + + def get_model(self, state_dict, prefix="", device=None): + out = model_base.AuraFlow(self, device=device) + return out + + def clip_target(self, state_dict={}): + return supported_models_base.ClipTarget(comfy.text_encoders.aura_t5.AuraT5Tokenizer, comfy.text_encoders.aura_t5.AuraT5Model) + +class HunyuanDiT(supported_models_base.BASE): + unet_config = { + "image_model": "hydit", + } + + unet_extra_config = { + "attn_precision": torch.float32, + } + + sampling_settings = { + "linear_start": 0.00085, + "linear_end": 0.018, + } + + latent_format = latent_formats.SDXL + + vae_key_prefix = ["vae."] + text_encoder_key_prefix = ["text_encoders."] + + def get_model(self, state_dict, prefix="", device=None): + out = model_base.HunyuanDiT(self, device=device) + return out + + def clip_target(self, state_dict={}): + return supported_models_base.ClipTarget(comfy.text_encoders.hydit.HyditTokenizer, comfy.text_encoders.hydit.HyditModel) + +class HunyuanDiT1(HunyuanDiT): + unet_config = { + "image_model": "hydit1", + } + + unet_extra_config = {} + + sampling_settings = { + "linear_start" : 0.00085, + "linear_end" : 0.03, + } -models = [Stable_Zero123, SD15_instructpix2pix, SD15, SD20, SD21UnclipL, SD21UnclipH, SDXL_instructpix2pix, SDXLRefiner, SDXL, SSD1B, KOALA_700M, KOALA_1B, Segmind_Vega, SD_X4Upscaler, Stable_Cascade_C, Stable_Cascade_B, SV3D_u, SV3D_p, SD3, StableAudio] +models = [Stable_Zero123, SD15_instructpix2pix, SD15, SD20, SD21UnclipL, SD21UnclipH, SDXL_instructpix2pix, SDXLRefiner, SDXL, SSD1B, KOALA_700M, KOALA_1B, Segmind_Vega, SD_X4Upscaler, Stable_Cascade_C, Stable_Cascade_B, SV3D_u, SV3D_p, SD3, StableAudio, AuraFlow, HunyuanDiT, HunyuanDiT1] models += [SVD_img2vid] diff --git a/comfy/t2i_adapter/adapter.py b/comfy/t2i_adapter/adapter.py index e9a606b1c..10ea18e32 100644 --- a/comfy/t2i_adapter/adapter.py +++ b/comfy/t2i_adapter/adapter.py @@ -153,7 +153,13 @@ class Adapter(nn.Module): features.append(None) features.append(x) - return features + features = features[::-1] + + if self.xl: + return {"input": features[1:], "middle": features[:1]} + else: + return {"input": features} + class LayerNorm(nn.LayerNorm): @@ -290,4 +296,4 @@ class Adapter_light(nn.Module): features.append(None) features.append(x) - return features + return {"input": features[::-1]} diff --git a/comfy/text_encoders/aura_t5.py b/comfy/text_encoders/aura_t5.py new file mode 100644 index 000000000..8500c7b70 --- /dev/null +++ b/comfy/text_encoders/aura_t5.py @@ -0,0 +1,22 @@ +from comfy import sd1_clip +from .spiece_tokenizer import SPieceTokenizer +import comfy.text_encoders.t5 +import os + +class PT5XlModel(sd1_clip.SDClipModel): + def __init__(self, device="cpu", layer="last", layer_idx=None, dtype=None): + textmodel_json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "t5_pile_config_xl.json") + super().__init__(device=device, layer=layer, layer_idx=layer_idx, textmodel_json_config=textmodel_json_config, dtype=dtype, special_tokens={"end": 2, "pad": 1}, model_class=comfy.text_encoders.t5.T5, enable_attention_masks=True, zero_out_masked=True) + +class PT5XlTokenizer(sd1_clip.SDTokenizer): + def __init__(self, embedding_directory=None, tokenizer_data={}): + tokenizer_path = os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "t5_pile_tokenizer"), "tokenizer.model") + super().__init__(tokenizer_path, pad_with_end=False, embedding_size=2048, embedding_key='pile_t5xl', tokenizer_class=SPieceTokenizer, has_start_token=False, pad_to_max_length=False, max_length=99999999, min_length=256, pad_token=1) + +class AuraT5Tokenizer(sd1_clip.SD1Tokenizer): + def __init__(self, embedding_directory=None, tokenizer_data={}): + super().__init__(embedding_directory=embedding_directory, tokenizer_data=tokenizer_data, clip_name="pile_t5xl", tokenizer=PT5XlTokenizer) + +class AuraT5Model(sd1_clip.SD1ClipModel): + def __init__(self, device="cpu", dtype=None, **kwargs): + super().__init__(device=device, dtype=dtype, name="pile_t5xl", clip_model=PT5XlModel, **kwargs) diff --git a/comfy/text_encoders/bert.py b/comfy/text_encoders/bert.py new file mode 100644 index 000000000..b76e76660 --- /dev/null +++ b/comfy/text_encoders/bert.py @@ -0,0 +1,139 @@ +import torch +from comfy.ldm.modules.attention import optimized_attention_for_device + +class BertAttention(torch.nn.Module): + def __init__(self, embed_dim, heads, dtype, device, operations): + super().__init__() + + self.heads = heads + self.query = operations.Linear(embed_dim, embed_dim, bias=True, dtype=dtype, device=device) + self.key = operations.Linear(embed_dim, embed_dim, bias=True, dtype=dtype, device=device) + self.value = operations.Linear(embed_dim, embed_dim, bias=True, dtype=dtype, device=device) + + + def forward(self, x, mask=None, optimized_attention=None): + q = self.query(x) + k = self.key(x) + v = self.value(x) + + out = optimized_attention(q, k, v, self.heads, mask) + return out + +class BertOutput(torch.nn.Module): + def __init__(self, input_dim, output_dim, layer_norm_eps, dtype, device, operations): + super().__init__() + self.dense = operations.Linear(input_dim, output_dim, dtype=dtype, device=device) + self.LayerNorm = operations.LayerNorm(output_dim, eps=layer_norm_eps, dtype=dtype, device=device) + # self.dropout = nn.Dropout(0.0) + + def forward(self, x, y): + x = self.dense(x) + # hidden_states = self.dropout(hidden_states) + x = self.LayerNorm(x + y) + return x + +class BertAttentionBlock(torch.nn.Module): + def __init__(self, embed_dim, heads, layer_norm_eps, dtype, device, operations): + super().__init__() + self.self = BertAttention(embed_dim, heads, dtype, device, operations) + self.output = BertOutput(embed_dim, embed_dim, layer_norm_eps, dtype, device, operations) + + def forward(self, x, mask, optimized_attention): + y = self.self(x, mask, optimized_attention) + return self.output(y, x) + +class BertIntermediate(torch.nn.Module): + def __init__(self, embed_dim, intermediate_dim, dtype, device, operations): + super().__init__() + self.dense = operations.Linear(embed_dim, intermediate_dim, dtype=dtype, device=device) + + def forward(self, x): + x = self.dense(x) + return torch.nn.functional.gelu(x) + + +class BertBlock(torch.nn.Module): + def __init__(self, embed_dim, intermediate_dim, heads, layer_norm_eps, dtype, device, operations): + super().__init__() + self.attention = BertAttentionBlock(embed_dim, heads, layer_norm_eps, dtype, device, operations) + self.intermediate = BertIntermediate(embed_dim, intermediate_dim, dtype, device, operations) + self.output = BertOutput(intermediate_dim, embed_dim, layer_norm_eps, dtype, device, operations) + + def forward(self, x, mask, optimized_attention): + x = self.attention(x, mask, optimized_attention) + y = self.intermediate(x) + return self.output(y, x) + +class BertEncoder(torch.nn.Module): + def __init__(self, num_layers, embed_dim, intermediate_dim, heads, layer_norm_eps, dtype, device, operations): + super().__init__() + self.layer = torch.nn.ModuleList([BertBlock(embed_dim, intermediate_dim, heads, layer_norm_eps, dtype, device, operations) for i in range(num_layers)]) + + def forward(self, x, mask=None, intermediate_output=None): + optimized_attention = optimized_attention_for_device(x.device, mask=mask is not None, small_input=True) + + if intermediate_output is not None: + if intermediate_output < 0: + intermediate_output = len(self.layer) + intermediate_output + + intermediate = None + for i, l in enumerate(self.layer): + x = l(x, mask, optimized_attention) + if i == intermediate_output: + intermediate = x.clone() + return x, intermediate + +class BertEmbeddings(torch.nn.Module): + def __init__(self, vocab_size, max_position_embeddings, type_vocab_size, pad_token_id, embed_dim, layer_norm_eps, dtype, device, operations): + super().__init__() + self.word_embeddings = torch.nn.Embedding(vocab_size, embed_dim, padding_idx=pad_token_id, dtype=dtype, device=device) + self.position_embeddings = torch.nn.Embedding(max_position_embeddings, embed_dim, dtype=dtype, device=device) + self.token_type_embeddings = torch.nn.Embedding(type_vocab_size, embed_dim, dtype=dtype, device=device) + + self.LayerNorm = operations.LayerNorm(embed_dim, eps=layer_norm_eps, dtype=dtype, device=device) + + def forward(self, input_tokens, token_type_ids=None): + x = self.word_embeddings(input_tokens) + x += self.position_embeddings.weight[:x.shape[1]] + if token_type_ids is not None: + x += self.token_type_embeddings(token_type_ids) + else: + x += self.token_type_embeddings.weight[0] + x = self.LayerNorm(x) + return x + + +class BertModel_(torch.nn.Module): + def __init__(self, config_dict, dtype, device, operations): + super().__init__() + embed_dim = config_dict["hidden_size"] + layer_norm_eps = config_dict["layer_norm_eps"] + + self.embeddings = BertEmbeddings(config_dict["vocab_size"], config_dict["max_position_embeddings"], config_dict["type_vocab_size"], config_dict["pad_token_id"], embed_dim, layer_norm_eps, dtype, device, operations) + self.encoder = BertEncoder(config_dict["num_hidden_layers"], embed_dim, config_dict["intermediate_size"], config_dict["num_attention_heads"], layer_norm_eps, dtype, device, operations) + + def forward(self, input_tokens, attention_mask=None, intermediate_output=None, final_layer_norm_intermediate=True): + x = self.embeddings(input_tokens) + mask = None + if attention_mask is not None: + mask = 1.0 - attention_mask.to(x.dtype).reshape((attention_mask.shape[0], 1, -1, attention_mask.shape[-1])).expand(attention_mask.shape[0], 1, attention_mask.shape[-1], attention_mask.shape[-1]) + mask = mask.masked_fill(mask.to(torch.bool), float("-inf")) + + x, i = self.encoder(x, mask, intermediate_output) + return x, i + + +class BertModel(torch.nn.Module): + def __init__(self, config_dict, dtype, device, operations): + super().__init__() + self.bert = BertModel_(config_dict, dtype, device, operations) + self.num_layers = config_dict["num_hidden_layers"] + + def get_input_embeddings(self): + return self.bert.embeddings.word_embeddings + + def set_input_embeddings(self, embeddings): + self.bert.embeddings.word_embeddings = embeddings + + def forward(self, *args, **kwargs): + return self.bert(*args, **kwargs) diff --git a/comfy/text_encoders/hydit.py b/comfy/text_encoders/hydit.py new file mode 100644 index 000000000..ac0c893bc --- /dev/null +++ b/comfy/text_encoders/hydit.py @@ -0,0 +1,79 @@ +from comfy import sd1_clip +from transformers import BertTokenizer +from .spiece_tokenizer import SPieceTokenizer +from .bert import BertModel +import comfy.text_encoders.t5 +import os +import torch + +class HyditBertModel(sd1_clip.SDClipModel): + def __init__(self, device="cpu", layer="last", layer_idx=None, dtype=None): + textmodel_json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "hydit_clip.json") + super().__init__(device=device, layer=layer, layer_idx=layer_idx, textmodel_json_config=textmodel_json_config, dtype=dtype, special_tokens={"start": 101, "end": 102, "pad": 0}, model_class=BertModel, enable_attention_masks=True, return_attention_masks=True) + +class HyditBertTokenizer(sd1_clip.SDTokenizer): + def __init__(self, embedding_directory=None, tokenizer_data={}): + tokenizer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "hydit_clip_tokenizer") + super().__init__(tokenizer_path, pad_with_end=False, embedding_size=1024, embedding_key='chinese_roberta', tokenizer_class=BertTokenizer, pad_to_max_length=False, max_length=512, min_length=77) + + +class MT5XLModel(sd1_clip.SDClipModel): + def __init__(self, device="cpu", layer="last", layer_idx=None, dtype=None): + textmodel_json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "mt5_config_xl.json") + super().__init__(device=device, layer=layer, layer_idx=layer_idx, textmodel_json_config=textmodel_json_config, dtype=dtype, special_tokens={"end": 1, "pad": 0}, model_class=comfy.text_encoders.t5.T5, enable_attention_masks=True, return_attention_masks=True) + +class MT5XLTokenizer(sd1_clip.SDTokenizer): + def __init__(self, embedding_directory=None, tokenizer_data={}): + #tokenizer_path = os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "mt5_tokenizer"), "spiece.model") + tokenizer = tokenizer_data.get("spiece_model", None) + super().__init__(tokenizer, pad_with_end=False, embedding_size=2048, embedding_key='mt5xl', tokenizer_class=SPieceTokenizer, has_start_token=False, pad_to_max_length=False, max_length=99999999, min_length=256) + + def state_dict(self): + return {"spiece_model": self.tokenizer.serialize_model()} + +class HyditTokenizer: + def __init__(self, embedding_directory=None, tokenizer_data={}): + mt5_tokenizer_data = tokenizer_data.get("mt5xl.spiece_model", None) + self.hydit_clip = HyditBertTokenizer(embedding_directory=embedding_directory) + self.mt5xl = MT5XLTokenizer(tokenizer_data={"spiece_model": mt5_tokenizer_data}, embedding_directory=embedding_directory) + + def tokenize_with_weights(self, text:str, return_word_ids=False): + out = {} + out["hydit_clip"] = self.hydit_clip.tokenize_with_weights(text, return_word_ids) + out["mt5xl"] = self.mt5xl.tokenize_with_weights(text, return_word_ids) + return out + + def untokenize(self, token_weight_pair): + return self.hydit_clip.untokenize(token_weight_pair) + + def state_dict(self): + return {"mt5xl.spiece_model": self.mt5xl.state_dict()["spiece_model"]} + +class HyditModel(torch.nn.Module): + def __init__(self, device="cpu", dtype=None): + super().__init__() + self.hydit_clip = HyditBertModel() + self.mt5xl = MT5XLModel() + + self.dtypes = set() + if dtype is not None: + self.dtypes.add(dtype) + + def encode_token_weights(self, token_weight_pairs): + hydit_out = self.hydit_clip.encode_token_weights(token_weight_pairs["hydit_clip"]) + mt5_out = self.mt5xl.encode_token_weights(token_weight_pairs["mt5xl"]) + return hydit_out[0], hydit_out[1], {"attention_mask": hydit_out[2]["attention_mask"], "conditioning_mt5xl": mt5_out[0], "attention_mask_mt5xl": mt5_out[2]["attention_mask"]} + + def load_sd(self, sd): + if "bert.encoder.layer.0.attention.self.query.weight" in sd: + return self.hydit_clip.load_sd(sd) + else: + return self.mt5xl.load_sd(sd) + + def set_clip_options(self, options): + self.hydit_clip.set_clip_options(options) + self.mt5xl.set_clip_options(options) + + def reset_clip_options(self): + self.hydit_clip.reset_clip_options() + self.mt5xl.reset_clip_options() diff --git a/comfy/text_encoders/hydit_clip.json b/comfy/text_encoders/hydit_clip.json new file mode 100644 index 000000000..c41c7c1ff --- /dev/null +++ b/comfy/text_encoders/hydit_clip.json @@ -0,0 +1,35 @@ +{ + "_name_or_path": "hfl/chinese-roberta-wwm-ext-large", + "architectures": [ + "BertModel" + ], + "attention_probs_dropout_prob": 0.1, + "bos_token_id": 0, + "classifier_dropout": null, + "directionality": "bidi", + "eos_token_id": 2, + "hidden_act": "gelu", + "hidden_dropout_prob": 0.1, + "hidden_size": 1024, + "initializer_range": 0.02, + "intermediate_size": 4096, + "layer_norm_eps": 1e-12, + "max_position_embeddings": 512, + "model_type": "bert", + "num_attention_heads": 16, + "num_hidden_layers": 24, + "output_past": true, + "pad_token_id": 0, + "pooler_fc_size": 768, + "pooler_num_attention_heads": 12, + "pooler_num_fc_layers": 3, + "pooler_size_per_head": 128, + "pooler_type": "first_token_transform", + "position_embedding_type": "absolute", + "torch_dtype": "float32", + "transformers_version": "4.22.1", + "type_vocab_size": 2, + "use_cache": true, + "vocab_size": 47020 +} + diff --git a/comfy/text_encoders/hydit_clip_tokenizer/special_tokens_map.json b/comfy/text_encoders/hydit_clip_tokenizer/special_tokens_map.json new file mode 100644 index 000000000..a8b3208c2 --- /dev/null +++ b/comfy/text_encoders/hydit_clip_tokenizer/special_tokens_map.json @@ -0,0 +1,7 @@ +{ + "cls_token": "[CLS]", + "mask_token": "[MASK]", + "pad_token": "[PAD]", + "sep_token": "[SEP]", + "unk_token": "[UNK]" +} diff --git a/comfy/text_encoders/hydit_clip_tokenizer/tokenizer_config.json b/comfy/text_encoders/hydit_clip_tokenizer/tokenizer_config.json new file mode 100644 index 000000000..a14356073 --- /dev/null +++ b/comfy/text_encoders/hydit_clip_tokenizer/tokenizer_config.json @@ -0,0 +1,16 @@ +{ + "cls_token": "[CLS]", + "do_basic_tokenize": true, + "do_lower_case": true, + "mask_token": "[MASK]", + "name_or_path": "hfl/chinese-roberta-wwm-ext", + "never_split": null, + "pad_token": "[PAD]", + "sep_token": "[SEP]", + "special_tokens_map_file": "/home/chenweifeng/.cache/huggingface/hub/models--hfl--chinese-roberta-wwm-ext/snapshots/5c58d0b8ec1d9014354d691c538661bf00bfdb44/special_tokens_map.json", + "strip_accents": null, + "tokenize_chinese_chars": true, + "tokenizer_class": "BertTokenizer", + "unk_token": "[UNK]", + "model_max_length": 77 +} diff --git a/comfy/text_encoders/hydit_clip_tokenizer/vocab.txt b/comfy/text_encoders/hydit_clip_tokenizer/vocab.txt new file mode 100644 index 000000000..624690680 --- /dev/null +++ b/comfy/text_encoders/hydit_clip_tokenizer/vocab.txt @@ -0,0 +1,47020 @@ +[PAD] +[unused1] +[unused2] +[unused3] +[unused4] +[unused5] +[unused6] +[unused7] +[unused8] +[unused9] +[unused10] +[unused11] +[unused12] +[unused13] +[unused14] +[unused15] +[unused16] +[unused17] +[unused18] +[unused19] +[unused20] +[unused21] +[unused22] +[unused23] +[unused24] +[unused25] +[unused26] +[unused27] +[unused28] +[unused29] +[unused30] +[unused31] +[unused32] +[unused33] +[unused34] +[unused35] +[unused36] +[unused37] +[unused38] +[unused39] +[unused40] +[unused41] +[unused42] +[unused43] +[unused44] +[unused45] +[unused46] +[unused47] +[unused48] +[unused49] +[unused50] +[unused51] +[unused52] +[unused53] +[unused54] +[unused55] +[unused56] +[unused57] +[unused58] +[unused59] +[unused60] +[unused61] +[unused62] +[unused63] +[unused64] +[unused65] +[unused66] +[unused67] +[unused68] +[unused69] +[unused70] +[unused71] +[unused72] +[unused73] +[unused74] +[unused75] +[unused76] +[unused77] +[unused78] +[unused79] +[unused80] +[unused81] +[unused82] +[unused83] +[unused84] +[unused85] +[unused86] +[unused87] +[unused88] +[unused89] +[unused90] +[unused91] +[unused92] +[unused93] +[unused94] +[unused95] +[unused96] +[unused97] +[unused98] +[unused99] +[UNK] +[CLS] +[SEP] +[MASK] + + +! +" +# +$ +% +& +' +( +) +* ++ +, +- +. +/ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +: +; +< += +> +? +@ +[ +\ +] +^ +_ +a +b +c +d +e +f +g +h +i +j +k +l +m +n +o +p +q +r +s +t +u +v +w +x +y +z +{ +| +} +~ +£ +¤ +¥ +§ +© +« +® +° +± +² +³ +µ +· +¹ +º +» +¼ +× +ß +æ +÷ +ø +đ +ŋ +ɔ +ə +ɡ +ʰ +ˇ +ˈ +ˊ +ˋ +ˍ +ː +˙ +˚ +ˢ +α +β +γ +δ +ε +η +θ +ι +κ +λ +μ +ν +ο +π +ρ +ς +σ +τ +υ +φ +χ +ψ +ω +а +б +в +г +д +е +ж +з +и +к +л +м +н +о +п +р +с +т +у +ф +х +ц +ч +ш +ы +ь +я +і +ا +ب +ة +ت +د +ر +س +ع +ل +م +ن +ه +و +ي +۩ +ก +ง +น +ม +ย +ร +อ +า +เ +๑ +་ +ღ +ᄀ +ᄁ +ᄂ +ᄃ +ᄅ +ᄆ +ᄇ +ᄈ +ᄉ +ᄋ +ᄌ +ᄎ +ᄏ +ᄐ +ᄑ +ᄒ +ᅡ +ᅢ +ᅣ +ᅥ +ᅦ +ᅧ +ᅨ +ᅩ +ᅪ +ᅬ +ᅭ +ᅮ +ᅯ +ᅲ +ᅳ +ᅴ +ᅵ +ᆨ +ᆫ +ᆯ +ᆷ +ᆸ +ᆺ +ᆻ +ᆼ +ᗜ +ᵃ +ᵉ +ᵍ +ᵏ +ᵐ +ᵒ +ᵘ +‖ +„ +† +• +‥ +‧ +
 +‰ +′ +″ +‹ +› +※ +‿ +⁄ +ⁱ +⁺ +ⁿ +₁ +₂ +₃ +₄ +€ +℃ +№ +™ +ⅰ +ⅱ +ⅲ +ⅳ +ⅴ +← +↑ +→ +↓ +↔ +↗ +↘ +⇒ +∀ +− +∕ +∙ +√ +∞ +∟ +∠ +∣ +∥ +∩ +∮ +∶ +∼ +∽ +≈ +≒ +≡ +≤ +≥ +≦ +≧ +≪ +≫ +⊙ +⋅ +⋈ +⋯ +⌒ +① +② +③ +④ +⑤ +⑥ +⑦ +⑧ +⑨ +⑩ +⑴ +⑵ +⑶ +⑷ +⑸ +⒈ +⒉ +⒊ +⒋ +ⓒ +ⓔ +ⓘ +─ +━ +│ +┃ +┅ +┆ +┊ +┌ +└ +├ +┣ +═ +║ +╚ +╞ +╠ +╭ +╮ +╯ +╰ +╱ +╳ +▂ +▃ +▅ +▇ +█ +▉ +▋ +▌ +▍ +▎ +■ +□ +▪ +▫ +▬ +▲ +△ +▶ +► +▼ +▽ +◆ +◇ +○ +◎ +● +◕ +◠ +◢ +◤ +☀ +★ +☆ +☕ +☞ +☺ +☼ +♀ +♂ +♠ +♡ +♣ +♥ +♦ +♪ +♫ +♬ +✈ +✔ +✕ +✖ +✦ +✨ +✪ +✰ +✿ +❀ +❤ +➜ +➤ +⦿ +、 +。 +〃 +々 +〇 +〈 +〉 +《 +》 +「 +」 +『 +』 +【 +】 +〓 +〔 +〕 +〖 +〗 +〜 +〝 +〞 +ぁ +あ +ぃ +い +う +ぇ +え +お +か +き +く +け +こ +さ +し +す +せ +そ +た +ち +っ +つ +て +と +な +に +ぬ +ね +の +は +ひ +ふ +へ +ほ +ま +み +む +め +も +ゃ +や +ゅ +ゆ +ょ +よ +ら +り +る +れ +ろ +わ +を +ん +゜ +ゝ +ァ +ア +ィ +イ +ゥ +ウ +ェ +エ +ォ +オ +カ +キ +ク +ケ +コ +サ +シ +ス +セ +ソ +タ +チ +ッ +ツ +テ +ト +ナ +ニ +ヌ +ネ +ノ +ハ +ヒ +フ +ヘ +ホ +マ +ミ +ム +メ +モ +ャ +ヤ +ュ +ユ +ョ +ヨ +ラ +リ +ル +レ +ロ +ワ +ヲ +ン +ヶ +・ +ー +ヽ +ㄅ +ㄆ +ㄇ +ㄉ +ㄋ +ㄌ +ㄍ +ㄎ +ㄏ +ㄒ +ㄚ +ㄛ +ㄞ +ㄟ +ㄢ +ㄤ +ㄥ +ㄧ +ㄨ +ㆍ +㈦ +㊣ +㎡ +㗎 +一 +丁 +七 +万 +丈 +三 +上 +下 +不 +与 +丐 +丑 +专 +且 +丕 +世 +丘 +丙 +业 +丛 +东 +丝 +丞 +丟 +両 +丢 +两 +严 +並 +丧 +丨 +个 +丫 +中 +丰 +串 +临 +丶 +丸 +丹 +为 +主 +丼 +丽 +举 +丿 +乂 +乃 +久 +么 +义 +之 +乌 +乍 +乎 +乏 +乐 +乒 +乓 +乔 +乖 +乗 +乘 +乙 +乜 +九 +乞 +也 +习 +乡 +书 +乩 +买 +乱 +乳 +乾 +亀 +亂 +了 +予 +争 +事 +二 +于 +亏 +云 +互 +五 +井 +亘 +亙 +亚 +些 +亜 +亞 +亟 +亡 +亢 +交 +亥 +亦 +产 +亨 +亩 +享 +京 +亭 +亮 +亲 +亳 +亵 +人 +亿 +什 +仁 +仃 +仄 +仅 +仆 +仇 +今 +介 +仍 +从 +仏 +仑 +仓 +仔 +仕 +他 +仗 +付 +仙 +仝 +仞 +仟 +代 +令 +以 +仨 +仪 +们 +仮 +仰 +仲 +件 +价 +任 +份 +仿 +企 +伉 +伊 +伍 +伎 +伏 +伐 +休 +伕 +众 +优 +伙 +会 +伝 +伞 +伟 +传 +伢 +伤 +伦 +伪 +伫 +伯 +估 +伴 +伶 +伸 +伺 +似 +伽 +佃 +但 +佇 +佈 +位 +低 +住 +佐 +佑 +体 +佔 +何 +佗 +佘 +余 +佚 +佛 +作 +佝 +佞 +佟 +你 +佢 +佣 +佤 +佥 +佩 +佬 +佯 +佰 +佳 +併 +佶 +佻 +佼 +使 +侃 +侄 +來 +侈 +例 +侍 +侏 +侑 +侖 +侗 +供 +依 +侠 +価 +侣 +侥 +侦 +侧 +侨 +侬 +侮 +侯 +侵 +侶 +侷 +便 +係 +促 +俄 +俊 +俎 +俏 +俐 +俑 +俗 +俘 +俚 +保 +俞 +俟 +俠 +信 +俨 +俩 +俪 +俬 +俭 +修 +俯 +俱 +俳 +俸 +俺 +俾 +倆 +倉 +個 +倌 +倍 +倏 +們 +倒 +倔 +倖 +倘 +候 +倚 +倜 +借 +倡 +値 +倦 +倩 +倪 +倫 +倬 +倭 +倶 +债 +值 +倾 +偃 +假 +偈 +偉 +偌 +偎 +偏 +偕 +做 +停 +健 +側 +偵 +偶 +偷 +偻 +偽 +偿 +傀 +傅 +傍 +傑 +傘 +備 +傚 +傢 +傣 +傥 +储 +傩 +催 +傭 +傲 +傳 +債 +傷 +傻 +傾 +僅 +働 +像 +僑 +僕 +僖 +僚 +僥 +僧 +僭 +僮 +僱 +僵 +價 +僻 +儀 +儂 +億 +儆 +儉 +儋 +儒 +儕 +儘 +償 +儡 +優 +儲 +儷 +儼 +儿 +兀 +允 +元 +兄 +充 +兆 +兇 +先 +光 +克 +兌 +免 +児 +兑 +兒 +兔 +兖 +党 +兜 +兢 +入 +內 +全 +兩 +八 +公 +六 +兮 +兰 +共 +兲 +关 +兴 +兵 +其 +具 +典 +兹 +养 +兼 +兽 +冀 +内 +円 +冇 +冈 +冉 +冊 +册 +再 +冏 +冒 +冕 +冗 +写 +军 +农 +冠 +冢 +冤 +冥 +冨 +冪 +冬 +冯 +冰 +冲 +决 +况 +冶 +冷 +冻 +冼 +冽 +冾 +净 +凄 +准 +凇 +凈 +凉 +凋 +凌 +凍 +减 +凑 +凛 +凜 +凝 +几 +凡 +凤 +処 +凪 +凭 +凯 +凰 +凱 +凳 +凶 +凸 +凹 +出 +击 +函 +凿 +刀 +刁 +刃 +分 +切 +刈 +刊 +刍 +刎 +刑 +划 +列 +刘 +则 +刚 +创 +初 +删 +判 +別 +刨 +利 +刪 +别 +刮 +到 +制 +刷 +券 +刹 +刺 +刻 +刽 +剁 +剂 +剃 +則 +剉 +削 +剋 +剌 +前 +剎 +剐 +剑 +剔 +剖 +剛 +剜 +剝 +剣 +剤 +剥 +剧 +剩 +剪 +副 +割 +創 +剷 +剽 +剿 +劃 +劇 +劈 +劉 +劊 +劍 +劏 +劑 +力 +劝 +办 +功 +加 +务 +劣 +动 +助 +努 +劫 +劭 +励 +劲 +劳 +労 +劵 +効 +劾 +势 +勁 +勃 +勇 +勉 +勋 +勐 +勒 +動 +勖 +勘 +務 +勛 +勝 +勞 +募 +勢 +勤 +勧 +勳 +勵 +勸 +勺 +勻 +勾 +勿 +匀 +包 +匆 +匈 +匍 +匐 +匕 +化 +北 +匙 +匝 +匠 +匡 +匣 +匪 +匮 +匯 +匱 +匹 +区 +医 +匾 +匿 +區 +十 +千 +卅 +升 +午 +卉 +半 +卍 +华 +协 +卑 +卒 +卓 +協 +单 +卖 +南 +単 +博 +卜 +卞 +卟 +占 +卡 +卢 +卤 +卦 +卧 +卫 +卮 +卯 +印 +危 +即 +却 +卵 +卷 +卸 +卻 +卿 +厂 +厄 +厅 +历 +厉 +压 +厌 +厕 +厘 +厚 +厝 +原 +厢 +厥 +厦 +厨 +厩 +厭 +厮 +厲 +厳 +去 +县 +叁 +参 +參 +又 +叉 +及 +友 +双 +反 +収 +发 +叔 +取 +受 +变 +叙 +叛 +叟 +叠 +叡 +叢 +口 +古 +句 +另 +叨 +叩 +只 +叫 +召 +叭 +叮 +可 +台 +叱 +史 +右 +叵 +叶 +号 +司 +叹 +叻 +叼 +叽 +吁 +吃 +各 +吆 +合 +吉 +吊 +吋 +同 +名 +后 +吏 +吐 +向 +吒 +吓 +吕 +吖 +吗 +君 +吝 +吞 +吟 +吠 +吡 +否 +吧 +吨 +吩 +含 +听 +吭 +吮 +启 +吱 +吳 +吴 +吵 +吶 +吸 +吹 +吻 +吼 +吽 +吾 +呀 +呂 +呃 +呆 +呈 +告 +呋 +呎 +呐 +呓 +呕 +呗 +员 +呛 +呜 +呢 +呤 +呦 +周 +呱 +呲 +味 +呵 +呷 +呸 +呻 +呼 +命 +咀 +咁 +咂 +咄 +咆 +咋 +和 +咎 +咏 +咐 +咒 +咔 +咕 +咖 +咗 +咘 +咙 +咚 +咛 +咣 +咤 +咦 +咧 +咨 +咩 +咪 +咫 +咬 +咭 +咯 +咱 +咲 +咳 +咸 +咻 +咽 +咿 +哀 +品 +哂 +哄 +哆 +哇 +哈 +哉 +哋 +哌 +响 +哎 +哏 +哐 +哑 +哒 +哔 +哗 +哟 +員 +哥 +哦 +哧 +哨 +哩 +哪 +哭 +哮 +哲 +哺 +哼 +哽 +唁 +唄 +唆 +唇 +唉 +唏 +唐 +唑 +唔 +唠 +唤 +唧 +唬 +售 +唯 +唰 +唱 +唳 +唷 +唸 +唾 +啃 +啄 +商 +啉 +啊 +問 +啓 +啕 +啖 +啜 +啞 +啟 +啡 +啤 +啥 +啦 +啧 +啪 +啫 +啬 +啮 +啰 +啱 +啲 +啵 +啶 +啷 +啸 +啻 +啼 +啾 +喀 +喂 +喃 +善 +喆 +喇 +喉 +喊 +喋 +喎 +喏 +喔 +喘 +喙 +喚 +喜 +喝 +喟 +喧 +喪 +喫 +喬 +單 +喰 +喱 +喲 +喳 +喵 +営 +喷 +喹 +喺 +喻 +喽 +嗅 +嗆 +嗇 +嗎 +嗑 +嗒 +嗓 +嗔 +嗖 +嗚 +嗜 +嗝 +嗟 +嗡 +嗣 +嗤 +嗦 +嗨 +嗪 +嗬 +嗯 +嗰 +嗲 +嗳 +嗶 +嗷 +嗽 +嘀 +嘅 +嘆 +嘈 +嘉 +嘌 +嘍 +嘎 +嘔 +嘖 +嘗 +嘘 +嘚 +嘛 +嘜 +嘞 +嘟 +嘢 +嘣 +嘤 +嘧 +嘩 +嘭 +嘮 +嘯 +嘰 +嘱 +嘲 +嘴 +嘶 +嘸 +嘹 +嘻 +嘿 +噁 +噌 +噎 +噓 +噔 +噗 +噙 +噜 +噠 +噢 +噤 +器 +噩 +噪 +噬 +噱 +噴 +噶 +噸 +噹 +噻 +噼 +嚀 +嚇 +嚎 +嚏 +嚐 +嚓 +嚕 +嚟 +嚣 +嚥 +嚨 +嚮 +嚴 +嚷 +嚼 +囂 +囉 +囊 +囍 +囑 +囔 +囗 +囚 +四 +囝 +回 +囟 +因 +囡 +团 +団 +囤 +囧 +囪 +囫 +园 +困 +囱 +囲 +図 +围 +囹 +固 +国 +图 +囿 +圃 +圄 +圆 +圈 +國 +圍 +圏 +園 +圓 +圖 +團 +圜 +土 +圣 +圧 +在 +圩 +圭 +地 +圳 +场 +圻 +圾 +址 +坂 +均 +坊 +坍 +坎 +坏 +坐 +坑 +块 +坚 +坛 +坝 +坞 +坟 +坠 +坡 +坤 +坦 +坨 +坪 +坯 +坳 +坵 +坷 +垂 +垃 +垄 +型 +垒 +垚 +垛 +垠 +垢 +垣 +垦 +垩 +垫 +垭 +垮 +垵 +埂 +埃 +埋 +城 +埔 +埕 +埗 +域 +埠 +埤 +埵 +執 +埸 +培 +基 +埼 +堀 +堂 +堃 +堅 +堆 +堇 +堑 +堕 +堙 +堡 +堤 +堪 +堯 +堰 +報 +場 +堵 +堺 +堿 +塊 +塌 +塑 +塔 +塗 +塘 +塚 +塞 +塢 +塩 +填 +塬 +塭 +塵 +塾 +墀 +境 +墅 +墉 +墊 +墒 +墓 +増 +墘 +墙 +墜 +增 +墟 +墨 +墩 +墮 +墳 +墻 +墾 +壁 +壅 +壆 +壇 +壊 +壑 +壓 +壕 +壘 +壞 +壟 +壢 +壤 +壩 +士 +壬 +壮 +壯 +声 +売 +壳 +壶 +壹 +壺 +壽 +处 +备 +変 +复 +夏 +夔 +夕 +外 +夙 +多 +夜 +够 +夠 +夢 +夥 +大 +天 +太 +夫 +夭 +央 +夯 +失 +头 +夷 +夸 +夹 +夺 +夾 +奂 +奄 +奇 +奈 +奉 +奋 +奎 +奏 +奐 +契 +奔 +奕 +奖 +套 +奘 +奚 +奠 +奢 +奥 +奧 +奪 +奬 +奮 +女 +奴 +奶 +奸 +她 +好 +如 +妃 +妄 +妆 +妇 +妈 +妊 +妍 +妒 +妓 +妖 +妘 +妙 +妝 +妞 +妣 +妤 +妥 +妨 +妩 +妪 +妮 +妲 +妳 +妹 +妻 +妾 +姆 +姉 +姊 +始 +姍 +姐 +姑 +姒 +姓 +委 +姗 +姚 +姜 +姝 +姣 +姥 +姦 +姨 +姪 +姫 +姬 +姹 +姻 +姿 +威 +娃 +娄 +娅 +娆 +娇 +娉 +娑 +娓 +娘 +娛 +娜 +娟 +娠 +娣 +娥 +娩 +娱 +娲 +娴 +娶 +娼 +婀 +婁 +婆 +婉 +婊 +婕 +婚 +婢 +婦 +婧 +婪 +婭 +婴 +婵 +婶 +婷 +婺 +婿 +媒 +媚 +媛 +媞 +媧 +媲 +媳 +媽 +媾 +嫁 +嫂 +嫉 +嫌 +嫑 +嫔 +嫖 +嫘 +嫚 +嫡 +嫣 +嫦 +嫩 +嫲 +嫵 +嫻 +嬅 +嬉 +嬌 +嬗 +嬛 +嬢 +嬤 +嬪 +嬰 +嬴 +嬷 +嬸 +嬿 +孀 +孃 +子 +孑 +孔 +孕 +孖 +字 +存 +孙 +孚 +孛 +孜 +孝 +孟 +孢 +季 +孤 +学 +孩 +孪 +孫 +孬 +孰 +孱 +孳 +孵 +學 +孺 +孽 +孿 +宁 +它 +宅 +宇 +守 +安 +宋 +完 +宏 +宓 +宕 +宗 +官 +宙 +定 +宛 +宜 +宝 +实 +実 +宠 +审 +客 +宣 +室 +宥 +宦 +宪 +宫 +宮 +宰 +害 +宴 +宵 +家 +宸 +容 +宽 +宾 +宿 +寂 +寄 +寅 +密 +寇 +富 +寐 +寒 +寓 +寛 +寝 +寞 +察 +寡 +寢 +寥 +實 +寧 +寨 +審 +寫 +寬 +寮 +寰 +寵 +寶 +寸 +对 +寺 +寻 +导 +対 +寿 +封 +専 +射 +将 +將 +專 +尉 +尊 +尋 +對 +導 +小 +少 +尔 +尕 +尖 +尘 +尚 +尝 +尤 +尧 +尬 +就 +尴 +尷 +尸 +尹 +尺 +尻 +尼 +尽 +尾 +尿 +局 +屁 +层 +屄 +居 +屆 +屈 +屉 +届 +屋 +屌 +屍 +屎 +屏 +屐 +屑 +展 +屜 +属 +屠 +屡 +屢 +層 +履 +屬 +屯 +山 +屹 +屿 +岀 +岁 +岂 +岌 +岐 +岑 +岔 +岖 +岗 +岘 +岙 +岚 +岛 +岡 +岩 +岫 +岬 +岭 +岱 +岳 +岷 +岸 +峇 +峋 +峒 +峙 +峡 +峤 +峥 +峦 +峨 +峪 +峭 +峯 +峰 +峴 +島 +峻 +峽 +崁 +崂 +崆 +崇 +崎 +崑 +崔 +崖 +崗 +崙 +崛 +崧 +崩 +崭 +崴 +崽 +嵇 +嵊 +嵋 +嵌 +嵐 +嵘 +嵩 +嵬 +嵯 +嶂 +嶄 +嶇 +嶋 +嶙 +嶺 +嶼 +嶽 +巅 +巍 +巒 +巔 +巖 +川 +州 +巡 +巢 +工 +左 +巧 +巨 +巩 +巫 +差 +己 +已 +巳 +巴 +巷 +巻 +巽 +巾 +巿 +币 +市 +布 +帅 +帆 +师 +希 +帐 +帑 +帕 +帖 +帘 +帚 +帛 +帜 +帝 +帥 +带 +帧 +師 +席 +帮 +帯 +帰 +帳 +帶 +帷 +常 +帼 +帽 +幀 +幂 +幄 +幅 +幌 +幔 +幕 +幟 +幡 +幢 +幣 +幫 +干 +平 +年 +并 +幸 +幹 +幺 +幻 +幼 +幽 +幾 +广 +庁 +広 +庄 +庆 +庇 +床 +序 +庐 +库 +应 +底 +庖 +店 +庙 +庚 +府 +庞 +废 +庠 +度 +座 +庫 +庭 +庵 +庶 +康 +庸 +庹 +庾 +廁 +廂 +廃 +廈 +廉 +廊 +廓 +廖 +廚 +廝 +廟 +廠 +廢 +廣 +廬 +廳 +延 +廷 +建 +廿 +开 +弁 +异 +弃 +弄 +弈 +弊 +弋 +式 +弑 +弒 +弓 +弔 +引 +弗 +弘 +弛 +弟 +张 +弥 +弦 +弧 +弩 +弭 +弯 +弱 +張 +強 +弹 +强 +弼 +弾 +彅 +彆 +彈 +彌 +彎 +归 +当 +录 +彗 +彙 +彝 +形 +彤 +彥 +彦 +彧 +彩 +彪 +彫 +彬 +彭 +彰 +影 +彷 +役 +彻 +彼 +彿 +往 +征 +径 +待 +徇 +很 +徉 +徊 +律 +後 +徐 +徑 +徒 +従 +徕 +得 +徘 +徙 +徜 +從 +徠 +御 +徨 +復 +循 +徬 +微 +徳 +徴 +徵 +德 +徹 +徼 +徽 +心 +必 +忆 +忌 +忍 +忏 +忐 +忑 +忒 +忖 +志 +忘 +忙 +応 +忠 +忡 +忤 +忧 +忪 +快 +忱 +念 +忻 +忽 +忿 +怀 +态 +怂 +怅 +怆 +怎 +怏 +怒 +怔 +怕 +怖 +怙 +怜 +思 +怠 +怡 +急 +怦 +性 +怨 +怪 +怯 +怵 +总 +怼 +恁 +恃 +恆 +恋 +恍 +恐 +恒 +恕 +恙 +恚 +恢 +恣 +恤 +恥 +恨 +恩 +恪 +恫 +恬 +恭 +息 +恰 +恳 +恵 +恶 +恸 +恺 +恻 +恼 +恿 +悄 +悅 +悉 +悌 +悍 +悔 +悖 +悚 +悟 +悠 +患 +悦 +您 +悩 +悪 +悬 +悯 +悱 +悲 +悴 +悵 +悶 +悸 +悻 +悼 +悽 +情 +惆 +惇 +惊 +惋 +惑 +惕 +惘 +惚 +惜 +惟 +惠 +惡 +惦 +惧 +惨 +惩 +惫 +惬 +惭 +惮 +惯 +惰 +惱 +想 +惴 +惶 +惹 +惺 +愁 +愆 +愈 +愉 +愍 +意 +愕 +愚 +愛 +愜 +感 +愣 +愤 +愧 +愫 +愷 +愿 +慄 +慈 +態 +慌 +慎 +慑 +慕 +慘 +慚 +慟 +慢 +慣 +慧 +慨 +慫 +慮 +慰 +慳 +慵 +慶 +慷 +慾 +憂 +憊 +憋 +憎 +憐 +憑 +憔 +憚 +憤 +憧 +憨 +憩 +憫 +憬 +憲 +憶 +憾 +懂 +懇 +懈 +應 +懊 +懋 +懑 +懒 +懦 +懲 +懵 +懶 +懷 +懸 +懺 +懼 +懾 +懿 +戀 +戈 +戊 +戌 +戍 +戎 +戏 +成 +我 +戒 +戕 +或 +战 +戚 +戛 +戟 +戡 +戦 +截 +戬 +戮 +戰 +戲 +戳 +戴 +戶 +户 +戸 +戻 +戾 +房 +所 +扁 +扇 +扈 +扉 +手 +才 +扎 +扑 +扒 +打 +扔 +払 +托 +扛 +扣 +扦 +执 +扩 +扪 +扫 +扬 +扭 +扮 +扯 +扰 +扱 +扳 +扶 +批 +扼 +找 +承 +技 +抄 +抉 +把 +抑 +抒 +抓 +投 +抖 +抗 +折 +抚 +抛 +抜 +択 +抟 +抠 +抡 +抢 +护 +报 +抨 +披 +抬 +抱 +抵 +抹 +押 +抽 +抿 +拂 +拄 +担 +拆 +拇 +拈 +拉 +拋 +拌 +拍 +拎 +拐 +拒 +拓 +拔 +拖 +拗 +拘 +拙 +拚 +招 +拜 +拟 +拡 +拢 +拣 +拥 +拦 +拧 +拨 +择 +括 +拭 +拮 +拯 +拱 +拳 +拴 +拷 +拼 +拽 +拾 +拿 +持 +挂 +指 +挈 +按 +挎 +挑 +挖 +挙 +挚 +挛 +挝 +挞 +挟 +挠 +挡 +挣 +挤 +挥 +挨 +挪 +挫 +振 +挲 +挹 +挺 +挽 +挾 +捂 +捅 +捆 +捉 +捋 +捌 +捍 +捎 +捏 +捐 +捕 +捞 +损 +捡 +换 +捣 +捧 +捨 +捩 +据 +捱 +捲 +捶 +捷 +捺 +捻 +掀 +掂 +掃 +掇 +授 +掉 +掌 +掏 +掐 +排 +掖 +掘 +掙 +掛 +掠 +採 +探 +掣 +接 +控 +推 +掩 +措 +掬 +掰 +掲 +掳 +掴 +掷 +掸 +掺 +揀 +揃 +揄 +揆 +揉 +揍 +描 +提 +插 +揖 +揚 +換 +握 +揣 +揩 +揪 +揭 +揮 +援 +揶 +揸 +揹 +揽 +搀 +搁 +搂 +搅 +損 +搏 +搐 +搓 +搔 +搖 +搗 +搜 +搞 +搡 +搪 +搬 +搭 +搵 +搶 +携 +搽 +摀 +摁 +摄 +摆 +摇 +摈 +摊 +摒 +摔 +摘 +摞 +摟 +摧 +摩 +摯 +摳 +摸 +摹 +摺 +摻 +撂 +撃 +撅 +撇 +撈 +撐 +撑 +撒 +撓 +撕 +撚 +撞 +撤 +撥 +撩 +撫 +撬 +播 +撮 +撰 +撲 +撵 +撷 +撸 +撻 +撼 +撿 +擀 +擁 +擂 +擄 +擅 +擇 +擊 +擋 +操 +擎 +擒 +擔 +擘 +據 +擞 +擠 +擡 +擢 +擦 +擬 +擰 +擱 +擲 +擴 +擷 +擺 +擼 +擾 +攀 +攏 +攒 +攔 +攘 +攙 +攜 +攝 +攞 +攢 +攣 +攤 +攥 +攪 +攫 +攬 +支 +收 +攸 +改 +攻 +放 +政 +故 +效 +敌 +敍 +敎 +敏 +救 +敕 +敖 +敗 +敘 +教 +敛 +敝 +敞 +敢 +散 +敦 +敬 +数 +敲 +整 +敵 +敷 +數 +斂 +斃 +文 +斋 +斌 +斎 +斐 +斑 +斓 +斗 +料 +斛 +斜 +斟 +斡 +斤 +斥 +斧 +斩 +斫 +斬 +断 +斯 +新 +斷 +方 +於 +施 +旁 +旃 +旅 +旋 +旌 +旎 +族 +旖 +旗 +无 +既 +日 +旦 +旧 +旨 +早 +旬 +旭 +旮 +旱 +时 +旷 +旺 +旻 +昀 +昂 +昆 +昇 +昉 +昊 +昌 +明 +昏 +易 +昔 +昕 +昙 +星 +映 +春 +昧 +昨 +昭 +是 +昱 +昴 +昵 +昶 +昼 +显 +晁 +時 +晃 +晉 +晋 +晌 +晏 +晒 +晓 +晔 +晕 +晖 +晗 +晚 +晝 +晞 +晟 +晤 +晦 +晨 +晩 +普 +景 +晰 +晴 +晶 +晷 +智 +晾 +暂 +暄 +暇 +暈 +暉 +暌 +暐 +暑 +暖 +暗 +暝 +暢 +暧 +暨 +暫 +暮 +暱 +暴 +暸 +暹 +曄 +曆 +曇 +曉 +曖 +曙 +曜 +曝 +曠 +曦 +曬 +曰 +曲 +曳 +更 +書 +曹 +曼 +曾 +替 +最 +會 +月 +有 +朋 +服 +朐 +朔 +朕 +朗 +望 +朝 +期 +朦 +朧 +木 +未 +末 +本 +札 +朮 +术 +朱 +朴 +朵 +机 +朽 +杀 +杂 +权 +杆 +杈 +杉 +李 +杏 +材 +村 +杓 +杖 +杜 +杞 +束 +杠 +条 +来 +杨 +杭 +杯 +杰 +東 +杳 +杵 +杷 +杼 +松 +板 +极 +构 +枇 +枉 +枋 +析 +枕 +林 +枚 +果 +枝 +枢 +枣 +枪 +枫 +枭 +枯 +枰 +枱 +枳 +架 +枷 +枸 +柄 +柏 +某 +柑 +柒 +染 +柔 +柘 +柚 +柜 +柞 +柠 +柢 +查 +柩 +柬 +柯 +柱 +柳 +柴 +柵 +査 +柿 +栀 +栃 +栄 +栅 +标 +栈 +栉 +栋 +栎 +栏 +树 +栓 +栖 +栗 +校 +栩 +株 +样 +核 +根 +格 +栽 +栾 +桀 +桁 +桂 +桃 +桅 +框 +案 +桉 +桌 +桎 +桐 +桑 +桓 +桔 +桜 +桠 +桡 +桢 +档 +桥 +桦 +桧 +桨 +桩 +桶 +桿 +梁 +梅 +梆 +梏 +梓 +梗 +條 +梟 +梢 +梦 +梧 +梨 +梭 +梯 +械 +梳 +梵 +梶 +检 +棂 +棄 +棉 +棋 +棍 +棒 +棕 +棗 +棘 +棚 +棟 +棠 +棣 +棧 +森 +棱 +棲 +棵 +棹 +棺 +椁 +椅 +椋 +植 +椎 +椒 +検 +椪 +椭 +椰 +椹 +椽 +椿 +楂 +楊 +楓 +楔 +楚 +楝 +楞 +楠 +楣 +楨 +楫 +業 +楮 +極 +楷 +楸 +楹 +楼 +楽 +概 +榄 +榆 +榈 +榉 +榔 +榕 +榖 +榛 +榜 +榨 +榫 +榭 +榮 +榱 +榴 +榷 +榻 +槁 +槃 +構 +槌 +槍 +槎 +槐 +槓 +様 +槛 +槟 +槤 +槭 +槲 +槳 +槻 +槽 +槿 +樁 +樂 +樊 +樑 +樓 +標 +樞 +樟 +模 +樣 +権 +横 +樫 +樯 +樱 +樵 +樸 +樹 +樺 +樽 +樾 +橄 +橇 +橋 +橐 +橘 +橙 +機 +橡 +橢 +橫 +橱 +橹 +橼 +檀 +檄 +檎 +檐 +檔 +檗 +檜 +檢 +檬 +檯 +檳 +檸 +檻 +櫃 +櫚 +櫛 +櫥 +櫸 +櫻 +欄 +權 +欒 +欖 +欠 +次 +欢 +欣 +欧 +欲 +欸 +欺 +欽 +款 +歆 +歇 +歉 +歌 +歎 +歐 +歓 +歙 +歛 +歡 +止 +正 +此 +步 +武 +歧 +歩 +歪 +歯 +歲 +歳 +歴 +歷 +歸 +歹 +死 +歼 +殁 +殃 +殆 +殇 +殉 +殊 +残 +殒 +殓 +殖 +殘 +殞 +殡 +殤 +殭 +殯 +殲 +殴 +段 +殷 +殺 +殼 +殿 +毀 +毁 +毂 +毅 +毆 +毋 +母 +毎 +每 +毒 +毓 +比 +毕 +毗 +毘 +毙 +毛 +毡 +毫 +毯 +毽 +氈 +氏 +氐 +民 +氓 +气 +氖 +気 +氙 +氛 +氟 +氡 +氢 +氣 +氤 +氦 +氧 +氨 +氪 +氫 +氮 +氯 +氰 +氲 +水 +氷 +永 +氹 +氾 +汀 +汁 +求 +汆 +汇 +汉 +汎 +汐 +汕 +汗 +汙 +汛 +汝 +汞 +江 +池 +污 +汤 +汨 +汩 +汪 +汰 +汲 +汴 +汶 +汹 +決 +汽 +汾 +沁 +沂 +沃 +沅 +沈 +沉 +沌 +沏 +沐 +沒 +沓 +沖 +沙 +沛 +沟 +没 +沢 +沣 +沥 +沦 +沧 +沪 +沫 +沭 +沮 +沱 +河 +沸 +油 +治 +沼 +沽 +沾 +沿 +況 +泄 +泉 +泊 +泌 +泓 +法 +泗 +泛 +泞 +泠 +泡 +波 +泣 +泥 +注 +泪 +泫 +泮 +泯 +泰 +泱 +泳 +泵 +泷 +泸 +泻 +泼 +泽 +泾 +洁 +洄 +洋 +洒 +洗 +洙 +洛 +洞 +津 +洩 +洪 +洮 +洱 +洲 +洵 +洶 +洸 +洹 +活 +洼 +洽 +派 +流 +浃 +浄 +浅 +浆 +浇 +浊 +测 +济 +浏 +浑 +浒 +浓 +浔 +浙 +浚 +浜 +浣 +浦 +浩 +浪 +浬 +浮 +浯 +浴 +海 +浸 +涂 +涅 +涇 +消 +涉 +涌 +涎 +涓 +涔 +涕 +涙 +涛 +涝 +涞 +涟 +涠 +涡 +涣 +涤 +润 +涧 +涨 +涩 +涪 +涮 +涯 +液 +涵 +涸 +涼 +涿 +淀 +淄 +淅 +淆 +淇 +淋 +淌 +淑 +淒 +淖 +淘 +淙 +淚 +淞 +淡 +淤 +淦 +淨 +淩 +淪 +淫 +淬 +淮 +深 +淳 +淵 +混 +淹 +淺 +添 +淼 +清 +済 +渉 +渊 +渋 +渍 +渎 +渐 +渔 +渗 +渙 +渚 +減 +渝 +渠 +渡 +渣 +渤 +渥 +渦 +温 +測 +渭 +港 +渲 +渴 +游 +渺 +渾 +湃 +湄 +湊 +湍 +湖 +湘 +湛 +湟 +湧 +湫 +湮 +湯 +湳 +湾 +湿 +満 +溃 +溅 +溉 +溏 +源 +準 +溜 +溝 +溟 +溢 +溥 +溧 +溪 +溫 +溯 +溱 +溴 +溶 +溺 +溼 +滁 +滂 +滄 +滅 +滇 +滋 +滌 +滑 +滓 +滔 +滕 +滙 +滚 +滝 +滞 +滟 +满 +滢 +滤 +滥 +滦 +滨 +滩 +滬 +滯 +滲 +滴 +滷 +滸 +滾 +滿 +漁 +漂 +漆 +漉 +漏 +漓 +演 +漕 +漠 +漢 +漣 +漩 +漪 +漫 +漬 +漯 +漱 +漲 +漳 +漸 +漾 +漿 +潆 +潇 +潋 +潍 +潑 +潔 +潘 +潛 +潜 +潞 +潟 +潢 +潤 +潦 +潧 +潭 +潮 +潰 +潴 +潸 +潺 +潼 +澀 +澄 +澆 +澈 +澍 +澎 +澗 +澜 +澡 +澤 +澧 +澱 +澳 +澹 +激 +濁 +濂 +濃 +濑 +濒 +濕 +濘 +濛 +濟 +濠 +濡 +濤 +濫 +濬 +濮 +濯 +濱 +濺 +濾 +瀅 +瀆 +瀉 +瀋 +瀏 +瀑 +瀕 +瀘 +瀚 +瀛 +瀝 +瀞 +瀟 +瀧 +瀨 +瀬 +瀰 +瀾 +灌 +灏 +灑 +灘 +灝 +灞 +灣 +火 +灬 +灭 +灯 +灰 +灵 +灶 +灸 +灼 +災 +灾 +灿 +炀 +炁 +炅 +炉 +炊 +炎 +炒 +炔 +炕 +炖 +炙 +炜 +炫 +炬 +炭 +炮 +炯 +炳 +炷 +炸 +点 +為 +炼 +炽 +烁 +烂 +烃 +烈 +烊 +烏 +烘 +烙 +烛 +烟 +烤 +烦 +烧 +烨 +烩 +烫 +烬 +热 +烯 +烷 +烹 +烽 +焉 +焊 +焕 +焖 +焗 +焘 +焙 +焚 +焜 +無 +焦 +焯 +焰 +焱 +然 +焼 +煅 +煉 +煊 +煌 +煎 +煒 +煖 +煙 +煜 +煞 +煤 +煥 +煦 +照 +煨 +煩 +煮 +煲 +煸 +煽 +熄 +熊 +熏 +熒 +熔 +熙 +熟 +熠 +熨 +熬 +熱 +熵 +熹 +熾 +燁 +燃 +燄 +燈 +燉 +燊 +燎 +燒 +燔 +燕 +燙 +燜 +營 +燥 +燦 +燧 +燭 +燮 +燴 +燻 +燼 +燿 +爆 +爍 +爐 +爛 +爪 +爬 +爭 +爰 +爱 +爲 +爵 +父 +爷 +爸 +爹 +爺 +爻 +爽 +爾 +牆 +片 +版 +牌 +牍 +牒 +牙 +牛 +牝 +牟 +牠 +牡 +牢 +牦 +牧 +物 +牯 +牲 +牴 +牵 +特 +牺 +牽 +犀 +犁 +犄 +犊 +犍 +犒 +犢 +犧 +犬 +犯 +状 +犷 +犸 +犹 +狀 +狂 +狄 +狈 +狎 +狐 +狒 +狗 +狙 +狞 +狠 +狡 +狩 +独 +狭 +狮 +狰 +狱 +狸 +狹 +狼 +狽 +猎 +猕 +猖 +猗 +猙 +猛 +猜 +猝 +猥 +猩 +猪 +猫 +猬 +献 +猴 +猶 +猷 +猾 +猿 +獄 +獅 +獎 +獐 +獒 +獗 +獠 +獣 +獨 +獭 +獰 +獲 +獵 +獷 +獸 +獺 +獻 +獼 +獾 +玄 +率 +玉 +王 +玑 +玖 +玛 +玟 +玠 +玥 +玩 +玫 +玮 +环 +现 +玲 +玳 +玷 +玺 +玻 +珀 +珂 +珅 +珈 +珉 +珊 +珍 +珏 +珐 +珑 +珙 +珞 +珠 +珣 +珥 +珩 +珪 +班 +珮 +珲 +珺 +現 +球 +琅 +理 +琇 +琉 +琊 +琍 +琏 +琐 +琛 +琢 +琥 +琦 +琨 +琪 +琬 +琮 +琰 +琲 +琳 +琴 +琵 +琶 +琺 +琼 +瑀 +瑁 +瑄 +瑋 +瑕 +瑗 +瑙 +瑚 +瑛 +瑜 +瑞 +瑟 +瑠 +瑣 +瑤 +瑩 +瑪 +瑯 +瑰 +瑶 +瑾 +璀 +璁 +璃 +璇 +璉 +璋 +璎 +璐 +璜 +璞 +璟 +璧 +璨 +環 +璽 +璿 +瓊 +瓏 +瓒 +瓜 +瓢 +瓣 +瓤 +瓦 +瓮 +瓯 +瓴 +瓶 +瓷 +甄 +甌 +甕 +甘 +甙 +甚 +甜 +生 +產 +産 +甥 +甦 +用 +甩 +甫 +甬 +甭 +甯 +田 +由 +甲 +申 +电 +男 +甸 +町 +画 +甾 +畀 +畅 +界 +畏 +畑 +畔 +留 +畜 +畝 +畢 +略 +畦 +番 +畫 +異 +畲 +畳 +畴 +當 +畸 +畹 +畿 +疆 +疇 +疊 +疏 +疑 +疔 +疖 +疗 +疙 +疚 +疝 +疟 +疡 +疣 +疤 +疥 +疫 +疮 +疯 +疱 +疲 +疳 +疵 +疸 +疹 +疼 +疽 +疾 +痂 +病 +症 +痈 +痉 +痊 +痍 +痒 +痔 +痕 +痘 +痙 +痛 +痞 +痠 +痢 +痣 +痤 +痧 +痨 +痪 +痫 +痰 +痱 +痴 +痹 +痺 +痼 +痿 +瘀 +瘁 +瘋 +瘍 +瘓 +瘘 +瘙 +瘟 +瘠 +瘡 +瘢 +瘤 +瘦 +瘧 +瘩 +瘪 +瘫 +瘴 +瘸 +瘾 +療 +癇 +癌 +癒 +癖 +癜 +癞 +癡 +癢 +癣 +癥 +癫 +癬 +癮 +癱 +癲 +癸 +発 +登 +發 +白 +百 +皂 +的 +皆 +皇 +皈 +皋 +皎 +皑 +皓 +皖 +皙 +皚 +皮 +皰 +皱 +皴 +皺 +皿 +盂 +盃 +盅 +盆 +盈 +益 +盎 +盏 +盐 +监 +盒 +盔 +盖 +盗 +盘 +盛 +盜 +盞 +盟 +盡 +監 +盤 +盥 +盧 +盪 +目 +盯 +盱 +盲 +直 +相 +盹 +盼 +盾 +省 +眈 +眉 +看 +県 +眙 +眞 +真 +眠 +眦 +眨 +眩 +眯 +眶 +眷 +眸 +眺 +眼 +眾 +着 +睁 +睇 +睏 +睐 +睑 +睛 +睜 +睞 +睡 +睢 +督 +睥 +睦 +睨 +睪 +睫 +睬 +睹 +睽 +睾 +睿 +瞄 +瞅 +瞇 +瞋 +瞌 +瞎 +瞑 +瞒 +瞓 +瞞 +瞟 +瞠 +瞥 +瞧 +瞩 +瞪 +瞬 +瞭 +瞰 +瞳 +瞻 +瞼 +瞿 +矇 +矍 +矗 +矚 +矛 +矜 +矢 +矣 +知 +矩 +矫 +短 +矮 +矯 +石 +矶 +矽 +矾 +矿 +码 +砂 +砌 +砍 +砒 +研 +砖 +砗 +砚 +砝 +砣 +砥 +砧 +砭 +砰 +砲 +破 +砷 +砸 +砺 +砼 +砾 +础 +硅 +硐 +硒 +硕 +硝 +硫 +硬 +确 +硯 +硼 +碁 +碇 +碉 +碌 +碍 +碎 +碑 +碓 +碗 +碘 +碚 +碛 +碟 +碣 +碧 +碩 +碰 +碱 +碳 +碴 +確 +碼 +碾 +磁 +磅 +磊 +磋 +磐 +磕 +磚 +磡 +磨 +磬 +磯 +磲 +磷 +磺 +礁 +礎 +礙 +礡 +礦 +礪 +礫 +礴 +示 +礼 +社 +祀 +祁 +祂 +祇 +祈 +祉 +祎 +祐 +祕 +祖 +祗 +祚 +祛 +祜 +祝 +神 +祟 +祠 +祢 +祥 +票 +祭 +祯 +祷 +祸 +祺 +祿 +禀 +禁 +禄 +禅 +禍 +禎 +福 +禛 +禦 +禧 +禪 +禮 +禱 +禹 +禺 +离 +禽 +禾 +禿 +秀 +私 +秃 +秆 +秉 +秋 +种 +科 +秒 +秘 +租 +秣 +秤 +秦 +秧 +秩 +秭 +积 +称 +秸 +移 +秽 +稀 +稅 +程 +稍 +税 +稔 +稗 +稚 +稜 +稞 +稟 +稠 +稣 +種 +稱 +稲 +稳 +稷 +稹 +稻 +稼 +稽 +稿 +穀 +穂 +穆 +穌 +積 +穎 +穗 +穢 +穩 +穫 +穴 +究 +穷 +穹 +空 +穿 +突 +窃 +窄 +窈 +窍 +窑 +窒 +窓 +窕 +窖 +窗 +窘 +窜 +窝 +窟 +窠 +窥 +窦 +窨 +窩 +窪 +窮 +窯 +窺 +窿 +竄 +竅 +竇 +竊 +立 +竖 +站 +竜 +竞 +竟 +章 +竣 +童 +竭 +端 +競 +竹 +竺 +竽 +竿 +笃 +笆 +笈 +笋 +笏 +笑 +笔 +笙 +笛 +笞 +笠 +符 +笨 +第 +笹 +笺 +笼 +筆 +等 +筊 +筋 +筍 +筏 +筐 +筑 +筒 +答 +策 +筛 +筝 +筠 +筱 +筲 +筵 +筷 +筹 +签 +简 +箇 +箋 +箍 +箏 +箐 +箔 +箕 +算 +箝 +管 +箩 +箫 +箭 +箱 +箴 +箸 +節 +篁 +範 +篆 +篇 +築 +篑 +篓 +篙 +篝 +篠 +篡 +篤 +篩 +篪 +篮 +篱 +篷 +簇 +簌 +簍 +簡 +簦 +簧 +簪 +簫 +簷 +簸 +簽 +簾 +簿 +籁 +籃 +籌 +籍 +籐 +籟 +籠 +籤 +籬 +籮 +籲 +米 +类 +籼 +籽 +粄 +粉 +粑 +粒 +粕 +粗 +粘 +粟 +粤 +粥 +粧 +粪 +粮 +粱 +粲 +粳 +粵 +粹 +粼 +粽 +精 +粿 +糅 +糊 +糍 +糕 +糖 +糗 +糙 +糜 +糞 +糟 +糠 +糧 +糬 +糯 +糰 +糸 +系 +糾 +紀 +紂 +約 +紅 +紉 +紊 +紋 +納 +紐 +紓 +純 +紗 +紘 +紙 +級 +紛 +紜 +素 +紡 +索 +紧 +紫 +紮 +累 +細 +紳 +紹 +紺 +終 +絃 +組 +絆 +経 +結 +絕 +絞 +絡 +絢 +給 +絨 +絮 +統 +絲 +絳 +絵 +絶 +絹 +綁 +綏 +綑 +經 +継 +続 +綜 +綠 +綢 +綦 +綫 +綬 +維 +綱 +網 +綴 +綵 +綸 +綺 +綻 +綽 +綾 +綿 +緊 +緋 +総 +緑 +緒 +緘 +線 +緝 +緞 +締 +緣 +編 +緩 +緬 +緯 +練 +緹 +緻 +縁 +縄 +縈 +縛 +縝 +縣 +縫 +縮 +縱 +縴 +縷 +總 +績 +繁 +繃 +繆 +繇 +繋 +織 +繕 +繚 +繞 +繡 +繩 +繪 +繫 +繭 +繳 +繹 +繼 +繽 +纂 +續 +纍 +纏 +纓 +纔 +纖 +纜 +纠 +红 +纣 +纤 +约 +级 +纨 +纪 +纫 +纬 +纭 +纯 +纰 +纱 +纲 +纳 +纵 +纶 +纷 +纸 +纹 +纺 +纽 +纾 +线 +绀 +练 +组 +绅 +细 +织 +终 +绊 +绍 +绎 +经 +绑 +绒 +结 +绔 +绕 +绘 +给 +绚 +绛 +络 +绝 +绞 +统 +绡 +绢 +绣 +绥 +绦 +继 +绩 +绪 +绫 +续 +绮 +绯 +绰 +绳 +维 +绵 +绶 +绷 +绸 +绻 +综 +绽 +绾 +绿 +缀 +缄 +缅 +缆 +缇 +缈 +缉 +缎 +缓 +缔 +缕 +编 +缘 +缙 +缚 +缜 +缝 +缠 +缢 +缤 +缥 +缨 +缩 +缪 +缭 +缮 +缰 +缱 +缴 +缸 +缺 +缽 +罂 +罄 +罌 +罐 +网 +罔 +罕 +罗 +罚 +罡 +罢 +罩 +罪 +置 +罰 +署 +罵 +罷 +罹 +羁 +羅 +羈 +羊 +羌 +美 +羔 +羚 +羞 +羟 +羡 +羣 +群 +羥 +羧 +羨 +義 +羯 +羲 +羸 +羹 +羽 +羿 +翁 +翅 +翊 +翌 +翎 +習 +翔 +翘 +翟 +翠 +翡 +翦 +翩 +翰 +翱 +翳 +翹 +翻 +翼 +耀 +老 +考 +耄 +者 +耆 +耋 +而 +耍 +耐 +耒 +耕 +耗 +耘 +耙 +耦 +耨 +耳 +耶 +耷 +耸 +耻 +耽 +耿 +聂 +聆 +聊 +聋 +职 +聒 +联 +聖 +聘 +聚 +聞 +聪 +聯 +聰 +聲 +聳 +聴 +聶 +職 +聽 +聾 +聿 +肃 +肄 +肅 +肆 +肇 +肉 +肋 +肌 +肏 +肓 +肖 +肘 +肚 +肛 +肝 +肠 +股 +肢 +肤 +肥 +肩 +肪 +肮 +肯 +肱 +育 +肴 +肺 +肽 +肾 +肿 +胀 +胁 +胃 +胄 +胆 +背 +胍 +胎 +胖 +胚 +胛 +胜 +胝 +胞 +胡 +胤 +胥 +胧 +胫 +胭 +胯 +胰 +胱 +胳 +胴 +胶 +胸 +胺 +能 +脂 +脅 +脆 +脇 +脈 +脉 +脊 +脍 +脏 +脐 +脑 +脓 +脖 +脘 +脚 +脛 +脣 +脩 +脫 +脯 +脱 +脲 +脳 +脸 +脹 +脾 +腆 +腈 +腊 +腋 +腌 +腎 +腐 +腑 +腓 +腔 +腕 +腥 +腦 +腩 +腫 +腭 +腮 +腰 +腱 +腳 +腴 +腸 +腹 +腺 +腻 +腼 +腾 +腿 +膀 +膈 +膊 +膏 +膑 +膘 +膚 +膛 +膜 +膝 +膠 +膦 +膨 +膩 +膳 +膺 +膻 +膽 +膾 +膿 +臀 +臂 +臃 +臆 +臉 +臊 +臍 +臓 +臘 +臟 +臣 +臥 +臧 +臨 +自 +臬 +臭 +至 +致 +臺 +臻 +臼 +臾 +舀 +舂 +舅 +舆 +與 +興 +舉 +舊 +舌 +舍 +舎 +舐 +舒 +舔 +舖 +舗 +舛 +舜 +舞 +舟 +航 +舫 +般 +舰 +舱 +舵 +舶 +舷 +舸 +船 +舺 +舾 +艇 +艋 +艘 +艙 +艦 +艮 +良 +艰 +艱 +色 +艳 +艷 +艹 +艺 +艾 +节 +芃 +芈 +芊 +芋 +芍 +芎 +芒 +芙 +芜 +芝 +芡 +芥 +芦 +芩 +芪 +芫 +芬 +芭 +芮 +芯 +花 +芳 +芷 +芸 +芹 +芻 +芽 +芾 +苁 +苄 +苇 +苋 +苍 +苏 +苑 +苒 +苓 +苔 +苕 +苗 +苛 +苜 +苞 +苟 +苡 +苣 +若 +苦 +苫 +苯 +英 +苷 +苹 +苻 +茁 +茂 +范 +茄 +茅 +茉 +茎 +茏 +茗 +茜 +茧 +茨 +茫 +茬 +茭 +茯 +茱 +茲 +茴 +茵 +茶 +茸 +茹 +茼 +荀 +荃 +荆 +草 +荊 +荏 +荐 +荒 +荔 +荖 +荘 +荚 +荞 +荟 +荠 +荡 +荣 +荤 +荥 +荧 +荨 +荪 +荫 +药 +荳 +荷 +荸 +荻 +荼 +荽 +莅 +莆 +莉 +莊 +莎 +莒 +莓 +莖 +莘 +莞 +莠 +莢 +莧 +莪 +莫 +莱 +莲 +莴 +获 +莹 +莺 +莽 +莿 +菀 +菁 +菅 +菇 +菈 +菊 +菌 +菏 +菓 +菖 +菘 +菜 +菟 +菠 +菡 +菩 +華 +菱 +菲 +菸 +菽 +萁 +萃 +萄 +萊 +萋 +萌 +萍 +萎 +萘 +萝 +萤 +营 +萦 +萧 +萨 +萩 +萬 +萱 +萵 +萸 +萼 +落 +葆 +葉 +著 +葚 +葛 +葡 +董 +葦 +葩 +葫 +葬 +葭 +葯 +葱 +葳 +葵 +葷 +葺 +蒂 +蒋 +蒐 +蒔 +蒙 +蒜 +蒞 +蒟 +蒡 +蒨 +蒲 +蒸 +蒹 +蒻 +蒼 +蒿 +蓁 +蓄 +蓆 +蓉 +蓋 +蓑 +蓓 +蓖 +蓝 +蓟 +蓦 +蓬 +蓮 +蓼 +蓿 +蔑 +蔓 +蔔 +蔗 +蔘 +蔚 +蔡 +蔣 +蔥 +蔫 +蔬 +蔭 +蔵 +蔷 +蔺 +蔻 +蔼 +蔽 +蕁 +蕃 +蕈 +蕉 +蕊 +蕎 +蕙 +蕤 +蕨 +蕩 +蕪 +蕭 +蕲 +蕴 +蕻 +蕾 +薄 +薅 +薇 +薈 +薊 +薏 +薑 +薔 +薙 +薛 +薦 +薨 +薩 +薪 +薬 +薯 +薰 +薹 +藉 +藍 +藏 +藐 +藓 +藕 +藜 +藝 +藤 +藥 +藩 +藹 +藻 +藿 +蘆 +蘇 +蘊 +蘋 +蘑 +蘚 +蘭 +蘸 +蘼 +蘿 +虎 +虏 +虐 +虑 +虔 +處 +虚 +虛 +虜 +虞 +號 +虢 +虧 +虫 +虬 +虱 +虹 +虻 +虽 +虾 +蚀 +蚁 +蚂 +蚊 +蚌 +蚓 +蚕 +蚜 +蚝 +蚣 +蚤 +蚩 +蚪 +蚯 +蚱 +蚵 +蛀 +蛆 +蛇 +蛊 +蛋 +蛎 +蛐 +蛔 +蛙 +蛛 +蛟 +蛤 +蛭 +蛮 +蛰 +蛳 +蛹 +蛻 +蛾 +蜀 +蜂 +蜃 +蜆 +蜇 +蜈 +蜊 +蜍 +蜒 +蜓 +蜕 +蜗 +蜘 +蜚 +蜜 +蜡 +蜢 +蜥 +蜱 +蜴 +蜷 +蜻 +蜿 +蝇 +蝈 +蝉 +蝌 +蝎 +蝕 +蝗 +蝙 +蝟 +蝠 +蝦 +蝨 +蝴 +蝶 +蝸 +蝼 +螂 +螃 +融 +螞 +螢 +螨 +螯 +螳 +螺 +蟀 +蟄 +蟆 +蟋 +蟎 +蟑 +蟒 +蟠 +蟬 +蟲 +蟹 +蟻 +蟾 +蠅 +蠍 +蠔 +蠕 +蠛 +蠟 +蠡 +蠢 +蠣 +蠱 +蠶 +蠹 +蠻 +血 +衄 +衅 +衆 +行 +衍 +術 +衔 +街 +衙 +衛 +衝 +衞 +衡 +衢 +衣 +补 +表 +衩 +衫 +衬 +衮 +衰 +衲 +衷 +衹 +衾 +衿 +袁 +袂 +袄 +袅 +袈 +袋 +袍 +袒 +袖 +袜 +袞 +袤 +袪 +被 +袭 +袱 +裁 +裂 +装 +裆 +裊 +裏 +裔 +裕 +裘 +裙 +補 +裝 +裟 +裡 +裤 +裨 +裱 +裳 +裴 +裸 +裹 +製 +裾 +褂 +複 +褐 +褒 +褓 +褔 +褚 +褥 +褪 +褫 +褲 +褶 +褻 +襁 +襄 +襟 +襠 +襪 +襬 +襯 +襲 +西 +要 +覃 +覆 +覇 +見 +規 +覓 +視 +覚 +覦 +覧 +親 +覬 +観 +覷 +覺 +覽 +觀 +见 +观 +规 +觅 +视 +览 +觉 +觊 +觎 +觐 +觑 +角 +觞 +解 +觥 +触 +觸 +言 +訂 +計 +訊 +討 +訓 +訕 +訖 +託 +記 +訛 +訝 +訟 +訣 +訥 +訪 +設 +許 +訳 +訴 +訶 +診 +註 +証 +詆 +詐 +詔 +評 +詛 +詞 +詠 +詡 +詢 +詣 +試 +詩 +詫 +詬 +詭 +詮 +詰 +話 +該 +詳 +詹 +詼 +誅 +誇 +誉 +誌 +認 +誓 +誕 +誘 +語 +誠 +誡 +誣 +誤 +誥 +誦 +誨 +說 +説 +読 +誰 +課 +誹 +誼 +調 +諄 +談 +請 +諏 +諒 +論 +諗 +諜 +諡 +諦 +諧 +諫 +諭 +諮 +諱 +諳 +諷 +諸 +諺 +諾 +謀 +謁 +謂 +謄 +謊 +謎 +謐 +謔 +謗 +謙 +講 +謝 +謠 +謨 +謬 +謹 +謾 +譁 +證 +譎 +譏 +識 +譙 +譚 +譜 +警 +譬 +譯 +議 +譲 +譴 +護 +譽 +讀 +變 +讓 +讚 +讞 +计 +订 +认 +讥 +讧 +讨 +让 +讪 +讫 +训 +议 +讯 +记 +讲 +讳 +讴 +讶 +讷 +许 +讹 +论 +讼 +讽 +设 +访 +诀 +证 +诃 +评 +诅 +识 +诈 +诉 +诊 +诋 +词 +诏 +译 +试 +诗 +诘 +诙 +诚 +诛 +话 +诞 +诟 +诠 +诡 +询 +诣 +诤 +该 +详 +诧 +诩 +诫 +诬 +语 +误 +诰 +诱 +诲 +说 +诵 +诶 +请 +诸 +诺 +读 +诽 +课 +诿 +谀 +谁 +调 +谄 +谅 +谆 +谈 +谊 +谋 +谌 +谍 +谎 +谏 +谐 +谑 +谒 +谓 +谔 +谕 +谗 +谘 +谙 +谚 +谛 +谜 +谟 +谢 +谣 +谤 +谥 +谦 +谧 +谨 +谩 +谪 +谬 +谭 +谯 +谱 +谲 +谴 +谶 +谷 +豁 +豆 +豇 +豈 +豉 +豊 +豌 +豎 +豐 +豔 +豚 +象 +豢 +豪 +豫 +豬 +豹 +豺 +貂 +貅 +貌 +貓 +貔 +貘 +貝 +貞 +負 +財 +貢 +貧 +貨 +販 +貪 +貫 +責 +貯 +貰 +貳 +貴 +貶 +買 +貸 +費 +貼 +貽 +貿 +賀 +賁 +賂 +賃 +賄 +資 +賈 +賊 +賑 +賓 +賜 +賞 +賠 +賡 +賢 +賣 +賤 +賦 +質 +賬 +賭 +賴 +賺 +購 +賽 +贅 +贈 +贊 +贍 +贏 +贓 +贖 +贛 +贝 +贞 +负 +贡 +财 +责 +贤 +败 +账 +货 +质 +贩 +贪 +贫 +贬 +购 +贮 +贯 +贰 +贱 +贲 +贴 +贵 +贷 +贸 +费 +贺 +贻 +贼 +贾 +贿 +赁 +赂 +赃 +资 +赅 +赈 +赊 +赋 +赌 +赎 +赏 +赐 +赓 +赔 +赖 +赘 +赚 +赛 +赝 +赞 +赠 +赡 +赢 +赣 +赤 +赦 +赧 +赫 +赭 +走 +赳 +赴 +赵 +赶 +起 +趁 +超 +越 +趋 +趕 +趙 +趟 +趣 +趨 +足 +趴 +趵 +趸 +趺 +趾 +跃 +跄 +跆 +跋 +跌 +跎 +跑 +跖 +跚 +跛 +距 +跟 +跡 +跤 +跨 +跩 +跪 +路 +跳 +践 +跷 +跹 +跺 +跻 +踉 +踊 +踌 +踏 +踐 +踝 +踞 +踟 +踢 +踩 +踪 +踮 +踱 +踴 +踵 +踹 +蹂 +蹄 +蹇 +蹈 +蹉 +蹊 +蹋 +蹑 +蹒 +蹙 +蹟 +蹣 +蹤 +蹦 +蹩 +蹬 +蹭 +蹲 +蹴 +蹶 +蹺 +蹼 +蹿 +躁 +躇 +躉 +躊 +躋 +躍 +躏 +躪 +身 +躬 +躯 +躲 +躺 +軀 +車 +軋 +軌 +軍 +軒 +軟 +転 +軸 +軼 +軽 +軾 +較 +載 +輒 +輓 +輔 +輕 +輛 +輝 +輟 +輩 +輪 +輯 +輸 +輻 +輾 +輿 +轄 +轅 +轆 +轉 +轍 +轎 +轟 +车 +轧 +轨 +轩 +转 +轭 +轮 +软 +轰 +轲 +轴 +轶 +轻 +轼 +载 +轿 +较 +辄 +辅 +辆 +辇 +辈 +辉 +辊 +辍 +辐 +辑 +输 +辕 +辖 +辗 +辘 +辙 +辛 +辜 +辞 +辟 +辣 +辦 +辨 +辩 +辫 +辭 +辮 +辯 +辰 +辱 +農 +边 +辺 +辻 +込 +辽 +达 +迁 +迂 +迄 +迅 +过 +迈 +迎 +运 +近 +返 +还 +这 +进 +远 +违 +连 +迟 +迢 +迤 +迥 +迦 +迩 +迪 +迫 +迭 +述 +迴 +迷 +迸 +迹 +迺 +追 +退 +送 +适 +逃 +逅 +逆 +选 +逊 +逍 +透 +逐 +递 +途 +逕 +逗 +這 +通 +逛 +逝 +逞 +速 +造 +逢 +連 +逮 +週 +進 +逵 +逶 +逸 +逻 +逼 +逾 +遁 +遂 +遅 +遇 +遊 +運 +遍 +過 +遏 +遐 +遑 +遒 +道 +達 +違 +遗 +遙 +遛 +遜 +遞 +遠 +遢 +遣 +遥 +遨 +適 +遭 +遮 +遲 +遴 +遵 +遶 +遷 +選 +遺 +遼 +遽 +避 +邀 +邁 +邂 +邃 +還 +邇 +邈 +邊 +邋 +邏 +邑 +邓 +邕 +邛 +邝 +邢 +那 +邦 +邨 +邪 +邬 +邮 +邯 +邰 +邱 +邳 +邵 +邸 +邹 +邺 +邻 +郁 +郅 +郊 +郎 +郑 +郜 +郝 +郡 +郢 +郤 +郦 +郧 +部 +郫 +郭 +郴 +郵 +郷 +郸 +都 +鄂 +鄉 +鄒 +鄔 +鄙 +鄞 +鄢 +鄧 +鄭 +鄰 +鄱 +鄲 +鄺 +酉 +酊 +酋 +酌 +配 +酐 +酒 +酗 +酚 +酝 +酢 +酣 +酥 +酩 +酪 +酬 +酮 +酯 +酰 +酱 +酵 +酶 +酷 +酸 +酿 +醃 +醇 +醉 +醋 +醍 +醐 +醒 +醚 +醛 +醜 +醞 +醣 +醪 +醫 +醬 +醮 +醯 +醴 +醺 +釀 +釁 +采 +釉 +释 +釋 +里 +重 +野 +量 +釐 +金 +釗 +釘 +釜 +針 +釣 +釦 +釧 +釵 +鈀 +鈉 +鈍 +鈎 +鈔 +鈕 +鈞 +鈣 +鈦 +鈪 +鈴 +鈺 +鈾 +鉀 +鉄 +鉅 +鉉 +鉑 +鉗 +鉚 +鉛 +鉤 +鉴 +鉻 +銀 +銃 +銅 +銑 +銓 +銖 +銘 +銜 +銬 +銭 +銮 +銳 +銷 +銹 +鋁 +鋅 +鋒 +鋤 +鋪 +鋰 +鋸 +鋼 +錄 +錐 +錘 +錚 +錠 +錢 +錦 +錨 +錫 +錮 +錯 +録 +錳 +錶 +鍊 +鍋 +鍍 +鍛 +鍥 +鍰 +鍵 +鍺 +鍾 +鎂 +鎊 +鎌 +鎏 +鎔 +鎖 +鎗 +鎚 +鎧 +鎬 +鎮 +鎳 +鏈 +鏖 +鏗 +鏘 +鏞 +鏟 +鏡 +鏢 +鏤 +鏽 +鐘 +鐮 +鐲 +鐳 +鐵 +鐸 +鐺 +鑄 +鑊 +鑑 +鑒 +鑣 +鑫 +鑰 +鑲 +鑼 +鑽 +鑾 +鑿 +针 +钉 +钊 +钎 +钏 +钒 +钓 +钗 +钙 +钛 +钜 +钝 +钞 +钟 +钠 +钡 +钢 +钣 +钤 +钥 +钦 +钧 +钨 +钩 +钮 +钯 +钰 +钱 +钳 +钴 +钵 +钺 +钻 +钼 +钾 +钿 +铀 +铁 +铂 +铃 +铄 +铅 +铆 +铉 +铎 +铐 +铛 +铜 +铝 +铠 +铡 +铢 +铣 +铤 +铨 +铩 +铬 +铭 +铮 +铰 +铲 +铵 +银 +铸 +铺 +链 +铿 +销 +锁 +锂 +锄 +锅 +锆 +锈 +锉 +锋 +锌 +锏 +锐 +锑 +错 +锚 +锟 +锡 +锢 +锣 +锤 +锥 +锦 +锭 +键 +锯 +锰 +锲 +锵 +锹 +锺 +锻 +镀 +镁 +镂 +镇 +镉 +镌 +镍 +镐 +镑 +镕 +镖 +镗 +镛 +镜 +镣 +镭 +镯 +镰 +镳 +镶 +長 +长 +門 +閃 +閉 +開 +閎 +閏 +閑 +閒 +間 +閔 +閘 +閡 +関 +閣 +閥 +閨 +閩 +閱 +閲 +閹 +閻 +閾 +闆 +闇 +闊 +闌 +闍 +闔 +闕 +闖 +闘 +關 +闡 +闢 +门 +闪 +闫 +闭 +问 +闯 +闰 +闲 +间 +闵 +闷 +闸 +闹 +闺 +闻 +闽 +闾 +阀 +阁 +阂 +阅 +阆 +阇 +阈 +阉 +阎 +阐 +阑 +阔 +阕 +阖 +阙 +阚 +阜 +队 +阡 +阪 +阮 +阱 +防 +阳 +阴 +阵 +阶 +阻 +阿 +陀 +陂 +附 +际 +陆 +陇 +陈 +陋 +陌 +降 +限 +陕 +陛 +陝 +陞 +陟 +陡 +院 +陣 +除 +陨 +险 +陪 +陰 +陲 +陳 +陵 +陶 +陷 +陸 +険 +陽 +隅 +隆 +隈 +隊 +隋 +隍 +階 +随 +隐 +隔 +隕 +隘 +隙 +際 +障 +隠 +隣 +隧 +隨 +險 +隱 +隴 +隶 +隸 +隻 +隼 +隽 +难 +雀 +雁 +雄 +雅 +集 +雇 +雉 +雋 +雌 +雍 +雎 +雏 +雑 +雒 +雕 +雖 +雙 +雛 +雜 +雞 +離 +難 +雨 +雪 +雯 +雰 +雲 +雳 +零 +雷 +雹 +電 +雾 +需 +霁 +霄 +霆 +震 +霈 +霉 +霊 +霍 +霎 +霏 +霑 +霓 +霖 +霜 +霞 +霧 +霭 +霰 +露 +霸 +霹 +霽 +霾 +靂 +靄 +靈 +青 +靓 +靖 +静 +靚 +靛 +靜 +非 +靠 +靡 +面 +靥 +靦 +革 +靳 +靴 +靶 +靼 +鞅 +鞋 +鞍 +鞏 +鞑 +鞘 +鞠 +鞣 +鞦 +鞭 +韆 +韋 +韌 +韓 +韜 +韦 +韧 +韩 +韬 +韭 +音 +韵 +韶 +韻 +響 +頁 +頂 +頃 +項 +順 +須 +頌 +預 +頑 +頒 +頓 +頗 +領 +頜 +頡 +頤 +頫 +頭 +頰 +頷 +頸 +頹 +頻 +頼 +顆 +題 +額 +顎 +顏 +顔 +願 +顛 +類 +顧 +顫 +顯 +顱 +顴 +页 +顶 +顷 +项 +顺 +须 +顼 +顽 +顾 +顿 +颁 +颂 +预 +颅 +领 +颇 +颈 +颉 +颊 +颌 +颍 +颐 +频 +颓 +颔 +颖 +颗 +题 +颚 +颛 +颜 +额 +颞 +颠 +颡 +颢 +颤 +颦 +颧 +風 +颯 +颱 +颳 +颶 +颼 +飄 +飆 +风 +飒 +飓 +飕 +飘 +飙 +飚 +飛 +飞 +食 +飢 +飨 +飩 +飪 +飯 +飲 +飼 +飽 +飾 +餃 +餅 +餉 +養 +餌 +餐 +餒 +餓 +餘 +餚 +餛 +餞 +餡 +館 +餮 +餵 +餾 +饅 +饈 +饋 +饌 +饍 +饑 +饒 +饕 +饗 +饞 +饥 +饨 +饪 +饬 +饭 +饮 +饯 +饰 +饱 +饲 +饴 +饵 +饶 +饷 +饺 +饼 +饽 +饿 +馀 +馁 +馄 +馅 +馆 +馈 +馋 +馍 +馏 +馒 +馔 +首 +馗 +香 +馥 +馨 +馬 +馭 +馮 +馳 +馴 +駁 +駄 +駅 +駆 +駐 +駒 +駕 +駛 +駝 +駭 +駱 +駿 +騁 +騎 +騏 +験 +騙 +騨 +騰 +騷 +驀 +驅 +驊 +驍 +驒 +驕 +驗 +驚 +驛 +驟 +驢 +驥 +马 +驭 +驮 +驯 +驰 +驱 +驳 +驴 +驶 +驷 +驸 +驹 +驻 +驼 +驾 +驿 +骁 +骂 +骄 +骅 +骆 +骇 +骈 +骊 +骋 +验 +骏 +骐 +骑 +骗 +骚 +骛 +骜 +骞 +骠 +骡 +骤 +骥 +骧 +骨 +骯 +骰 +骶 +骷 +骸 +骼 +髂 +髅 +髋 +髏 +髒 +髓 +體 +髖 +高 +髦 +髪 +髮 +髯 +髻 +鬃 +鬆 +鬍 +鬓 +鬚 +鬟 +鬢 +鬣 +鬥 +鬧 +鬱 +鬼 +魁 +魂 +魄 +魅 +魇 +魍 +魏 +魔 +魘 +魚 +魯 +魷 +鮑 +鮨 +鮪 +鮭 +鮮 +鯉 +鯊 +鯖 +鯛 +鯨 +鯰 +鯽 +鰍 +鰓 +鰭 +鰲 +鰻 +鰾 +鱈 +鱉 +鱔 +鱗 +鱷 +鱸 +鱼 +鱿 +鲁 +鲈 +鲍 +鲑 +鲛 +鲜 +鲟 +鲢 +鲤 +鲨 +鲫 +鲱 +鲲 +鲶 +鲷 +鲸 +鳃 +鳄 +鳅 +鳌 +鳍 +鳕 +鳖 +鳗 +鳝 +鳞 +鳥 +鳩 +鳳 +鳴 +鳶 +鴉 +鴕 +鴛 +鴦 +鴨 +鴻 +鴿 +鵑 +鵜 +鵝 +鵡 +鵬 +鵰 +鵲 +鶘 +鶩 +鶯 +鶴 +鷗 +鷲 +鷹 +鷺 +鸚 +鸞 +鸟 +鸠 +鸡 +鸢 +鸣 +鸥 +鸦 +鸨 +鸪 +鸭 +鸯 +鸳 +鸵 +鸽 +鸾 +鸿 +鹂 +鹃 +鹄 +鹅 +鹈 +鹉 +鹊 +鹌 +鹏 +鹑 +鹕 +鹘 +鹜 +鹞 +鹤 +鹦 +鹧 +鹫 +鹭 +鹰 +鹳 +鹵 +鹹 +鹼 +鹽 +鹿 +麂 +麋 +麒 +麓 +麗 +麝 +麟 +麥 +麦 +麩 +麴 +麵 +麸 +麺 +麻 +麼 +麽 +麾 +黃 +黄 +黍 +黎 +黏 +黑 +黒 +黔 +默 +黛 +黜 +黝 +點 +黠 +黨 +黯 +黴 +鼋 +鼎 +鼐 +鼓 +鼠 +鼬 +鼹 +鼻 +鼾 +齁 +齊 +齋 +齐 +齒 +齡 +齢 +齣 +齦 +齿 +龄 +龅 +龈 +龊 +龋 +龌 +龍 +龐 +龔 +龕 +龙 +龚 +龛 +龜 +龟 +︰ +︱ +︶ +︿ +﹁ +﹂ +﹍ +﹏ +﹐ +﹑ +﹒ +﹔ +﹕ +﹖ +﹗ +﹙ +﹚ +﹝ +﹞ +﹡ +﹣ +! +" +# +$ +% +& +' +( +) +* ++ +, +- +. +/ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +: +; +< += +> +? +@ +[ +\ +] +^ +_ +` +a +b +c +d +e +f +g +h +i +j +k +l +m +n +o +p +q +r +s +t +u +v +w +x +y +z +{ +| +} +~ +。 +「 +」 +、 +・ +ッ +ー +イ +ク +シ +ス +ト +ノ +フ +ラ +ル +ン +゙ +゚ + ̄ +¥ +👍 +🔥 +😂 +😎 +... +yam +10 +2017 +12 +11 +2016 +20 +30 +15 +06 +lofter +##s +2015 +by +16 +14 +18 +13 +24 +17 +2014 +21 +##0 +22 +19 +25 +23 +com +100 +00 +05 +2013 +##a +03 +09 +08 +28 +##2 +50 +01 +04 +##1 +27 +02 +2012 +##3 +26 +##e +07 +##8 +##5 +##6 +##4 +##9 +##7 +29 +2011 +40 +##t +2010 +##o +##d +##i +2009 +##n +app +www +the +##m +31 +##c +##l +##y +##r +##g +2008 +60 +http +200 +qq +##p +80 +##f +google +pixnet +90 +cookies +tripadvisor +500 +##er +##k +35 +##h +facebook +2007 +2000 +70 +##b +of +##x +##u +45 +300 +iphone +32 +1000 +2006 +48 +ip +36 +in +38 +3d +##w +##ing +55 +ctrip +##on +##v +33 +##の +to +34 +400 +id +2005 +it +37 +windows +llc +top +99 +42 +39 +000 +led +at +##an +41 +51 +52 +46 +49 +43 +53 +44 +##z +android +58 +and +59 +2004 +56 +vr +##か +5000 +2003 +47 +blogthis +twitter +54 +##le +150 +ok +2018 +57 +75 +cn +no +ios +##in +##mm +##00 +800 +on +te +3000 +65 +2001 +360 +95 +ig +lv +120 +##ng +##を +##us +##に +pc +てす +── +600 +##te +85 +2002 +88 +##ed +html +ncc +wifi +email +64 +blog +is +##10 +##て +mail +online +##al +dvd +##ic +studio +##は +##℃ +##ia +##と +line +vip +72 +##q +98 +##ce +##en +for +##is +##ra +##es +##j +usb +net +cp +1999 +asia +4g +##cm +diy +new +3c +##お +ta +66 +language +vs +apple +tw +86 +web +##ne +ipad +62 +you +##re +101 +68 +##tion +ps +de +bt +pony +atm +##2017 +1998 +67 +##ch +ceo +##or +go +##na +av +pro +cafe +96 +pinterest +97 +63 +pixstyleme3c +##ta +more +said +##2016 +1997 +mp3 +700 +##ll +nba +jun +##20 +92 +tv +1995 +pm +61 +76 +nbsp +250 +##ie +linux +##ma +cd +110 +hd +##17 +78 +##ion +77 +6000 +am +##th +##st +94 +##se +##et +69 +180 +gdp +my +105 +81 +abc +89 +flash +79 +one +93 +1990 +1996 +##ck +gps +##も +##ly +web885 +106 +2020 +91 +##ge +4000 +1500 +xd +boss +isbn +1994 +org +##ry +me +love +##11 +0fork +73 +##12 +3g +##ter +##ar +71 +82 +##la +hotel +130 +1970 +pk +83 +87 +140 +ie +##os +##30 +##el +74 +##50 +seo +cpu +##ml +p2p +84 +may +##る +sun +tue +internet +cc +posted +youtube +##at +##ン +##man +ii +##ル +##15 +abs +nt +pdf +yahoo +ago +1980 +##it +news +mac +104 +##てす +##me +##り +java +1992 +spa +##de +##nt +hk +all +plus +la +1993 +##mb +##16 +##ve +west +##da +160 +air +##い +##ps +から +##to +1989 +logo +htc +php +https +fi +momo +##son +sat +##ke +##80 +ebd +suv +wi +day +apk +##88 +##um +mv +galaxy +wiki +or +brake +##ス +1200 +する +this +1991 +mon +##こ +❤2017 +po +##ない +javascript +life +home +june +##ss +system +900 +##ー +##0 +pp +1988 +world +fb +4k +br +##as +ic +ai +leonardo +safari +##60 +live +free +xx +wed +win7 +kiehl +##co +lg +o2o +##go +us +235 +1949 +mm +しい +vfm +kanye +##90 +##2015 +##id +jr +##ey +123 +rss +##sa +##ro +##am +##no +thu +fri +350 +##sh +##ki +103 +comments +name +##のて +##pe +##ine +max +1987 +8000 +uber +##mi +##ton +wordpress +office +1986 +1985 +##ment +107 +bd +win10 +##ld +##li +gmail +bb +dior +##rs +##ri +##rd +##ます +up +cad +##® +dr +して +read +##21 +をお +##io +##99 +url +1984 +pvc +paypal +show +policy +##40 +##ty +##18 +with +##★ +##01 +txt +102 +##ba +dna +from +post +mini +ar +taiwan +john +##ga +privacy +agoda +##13 +##ny +word +##24 +##22 +##by +##ur +##hz +1982 +##ang +265 +cookie +netscape +108 +##ka +##~ +##ad +house +share +note +ibm +code +hello +nike +sim +survey +##016 +1979 +1950 +wikia +##32 +##017 +5g +cbc +##tor +##kg +1983 +##rt +##14 +campaign +store +2500 +os +##ct +##ts +##° +170 +api +##ns +365 +excel +##な +##ao +##ら +##し +~~ +##nd +university +163 +には +518 +##70 +##ya +##il +##25 +pierre +ipo +0020 +897 +##23 +hotels +##ian +のお +125 +years +6606 +##ers +##26 +high +##day +time +##ay +bug +##line +##く +##す +##be +xp +talk2yam +yamservice +10000 +coco +##dy +sony +##ies +1978 +microsoft +david +people +##ha +1960 +instagram +intel +その +##ot +iso +1981 +##va +115 +##mo +##land +xxx +man +co +ltxsw +##ation +baby +220 +##pa +##ol +1945 +7000 +tag +450 +##ue +msn +##31 +oppo +##ト +##ca +control +##om +st +chrome +##ure +##ん +be +##き +lol +##19 +した +##bo +240 +lady +##100 +##way +##から +4600 +##ko +##do +##un +4s +corporation +168 +##ni +herme +##28 +cp +978 +##up +##06 +ui +##ds +ppt +admin +three +します +bbc +re +128 +##48 +ca +##015 +##35 +hp +##ee +tpp +##た +##ive +×× +root +##cc +##ました +##ble +##ity +adobe +park +114 +et +oled +city +##ex +##ler +##ap +china +##book +20000 +view +##ice +global +##km +your +hong +##mg +out +##ms +ng +ebay +##29 +menu +ubuntu +##cy +rom +##view +open +ktv +do +server +##lo +if +english +##ね +##5 +##oo +1600 +##02 +step1 +kong +club +135 +july +inc +1976 +mr +hi +##net +touch +##ls +##ii +michael +lcd +##05 +##33 +phone +james +step2 +1300 +ios9 +##box +dc +##2 +##ley +samsung +111 +280 +pokemon +css +##ent +##les +いいえ +##1 +s8 +atom +play +bmw +##said +sa +etf +ctrl +♥yoyo♥ +##55 +2025 +##2014 +##66 +adidas +amazon +1958 +##ber +##ner +visa +##77 +##der +1800 +connectivity +##hi +firefox +109 +118 +hr +so +style +mark +pop +ol +skip +1975 +as +##27 +##ir +##61 +190 +mba +##う +##ai +le +##ver +1900 +cafe2017 +lte +super +113 +129 +##ron +amd +like +##☆ +are +##ster +we +##sk +paul +data +international +##ft +longchamp +ssd +good +##ート +##ti +reply +##my +↓↓↓ +apr +star +##ker +source +136 +js +112 +get +force +photo +##one +126 +##2013 +##ow +link +bbs +1972 +goods +##lin +python +119 +##ip +game +##ics +##ません +blue +##● +520 +##45 +page +itunes +##03 +1955 +260 +1968 +gt +gif +618 +##ff +##47 +group +くたさい +about +bar +ganji +##nce +music +lee +not +1977 +1971 +1973 +##per +an +faq +comment +##って +days +##ock +116 +##bs +1974 +1969 +v1 +player +1956 +xbox +sql +fm +f1 +139 +##ah +210 +##lv +##mp +##000 +melody +1957 +##3 +550 +17life +199 +1966 +xml +market +##au +##71 +999 +##04 +what +gl +##95 +##age +tips +##68 +book +##ting +mysql +can +1959 +230 +##ung +wonderland +watch +10℃ +##ction +9000 +mar +mobile +1946 +1962 +article +##db +part +▲top +party +って +1967 +1964 +1948 +##07 +##ore +##op +この +dj +##78 +##38 +010 +main +225 +1965 +##ong +art +320 +ad +134 +020 +##73 +117 +pm2 +japan +228 +##08 +ts +1963 +##ica +der +sm +##36 +2019 +##wa +ct +##7 +##や +##64 +1937 +homemesh +search +##85 +##れは +##tv +##di +macbook +##9 +##くたさい +service +##♥ +type +った +750 +##ier +##si +##75 +##います +##ok +best +##ット +goris +lock +##った +cf +3m +big +##ut +ftp +carol +##vi +10 +1961 +happy +sd +##ac +122 +anti +pe +cnn +iii +1920 +138 +##ラ +1940 +esp +jan +tags +##98 +##51 +august +vol +##86 +154 +##™ +##fs +##れ +##sion +design +ac +##ム +press +jordan +ppp +that +key +check +##6 +##tt +##㎡ +1080p +##lt +power +##42 +1952 +##bc +vivi +##ック +he +133 +121 +jpg +##rry +201 +175 +3500 +1947 +nb +##ted +##rn +しています +1954 +usd +##t00 +master +##ンク +001 +model +##58 +al +##09 +1953 +##34 +ram +goo +ても +##ui +127 +1930 +red +##ary +rpg +item +##pm +##41 +270 +##za +project +##2012 +hot +td +blogabstract +##ger +##62 +650 +##44 +gr2 +##します +##m +black +electronic +nfc +year +asus +また +html5 +cindy +##hd +m3 +132 +esc +##od +booking +##53 +fed +tvb +##81 +##ina +mit +165 +##いる +chan +192 +distribution +next +になる +peter +bios +steam +cm +1941 +にも +pk10 +##ix +##65 +##91 +dec +nasa +##ana +icecat +00z +b1 +will +##46 +li +se +##ji +##み +##ard +oct +##ain +jp +##ze +##bi +cio +##56 +smart +h5 +##39 +##port +curve +vpn +##nm +##dia +utc +##あり +12345678910 +##52 +rmvb +chanel +a4 +miss +##and +##im +media +who +##63 +she +girl +5s +124 +vera +##して +class +vivo +king +##フ +##ei +national +ab +1951 +5cm +888 +145 +ipod +ap +1100 +5mm +211 +ms +2756 +##69 +mp4 +msci +##po +##89 +131 +mg +index +380 +##bit +##out +##zz +##97 +##67 +158 +apec +##8 +photoshop +opec +¥799 +ては +##96 +##tes +##ast +2g +○○ +##ール +¥2899 +##ling +##よ +##ory +1938 +##ical +kitty +content +##43 +step3 +##cn +win8 +155 +vc +1400 +iphone7 +robert +##した +tcl +137 +beauty +##87 +en +dollars +##ys +##oc +step +pay +yy +a1 +##2011 +##lly +##ks +##♪ +1939 +188 +download +1944 +sep +exe +ph +います +school +gb +center +pr +street +##board +uv +##37 +##lan +winrar +##que +##ua +##com +1942 +1936 +480 +gpu +##4 +ettoday +fu +tom +##54 +##ren +##via +149 +##72 +b2b +144 +##79 +##tch +rose +arm +mb +##49 +##ial +##nn +nvidia +step4 +mvp +00㎡ +york +156 +##イ +how +cpi +591 +2765 +gov +kg +joe +##xx +mandy +pa +##ser +copyright +fashion +1935 +don +##け +ecu +##ist +##art +erp +wap +have +##lm +talk +##ek +##ning +##if +ch +##ite +video +1943 +cs +san +iot +look +##84 +##2010 +##ku +october +##ux +trump +##hs +##ide +box +141 +first +##ins +april +##ight +##83 +185 +angel +protected +aa +151 +162 +x1 +m2 +##fe +##× +##ho +size +143 +min +ofo +fun +gomaji +ex +hdmi +food +dns +march +chris +kevin +##のか +##lla +##pp +##ec +ag +ems +6s +720p +##rm +##ham +off +##92 +asp +team +fandom +ed +299 +▌♥ +##ell +info +されています +##82 +sina +4066 +161 +##able +##ctor +330 +399 +315 +dll +rights +ltd +idc +jul +3kg +1927 +142 +ma +surface +##76 +##ク +~~~ +304 +mall +eps +146 +green +##59 +map +space +donald +v2 +sodu +##light +1931 +148 +1700 +まて +310 +reserved +htm +##han +##57 +2d +178 +mod +##ise +##tions +152 +ti +##shi +doc +1933 +icp +055 +wang +##ram +shopping +aug +##pi +##well +now +wam +b2 +からお +##hu +236 +1928 +##gb +266 +f2 +##93 +153 +mix +##ef +##uan +bwl +##plus +##res +core +##ess +tea +5℃ +hktvmall +nhk +##ate +list +##ese +301 +feb +4m +inn +ての +nov +159 +12345 +daniel +##ci +pass +##bet +##nk +coffee +202 +ssl +airbnb +##ute +fbi +woshipm +skype +ea +cg +sp +##fc +##www +yes +edge +alt +007 +##94 +fpga +##ght +##gs +iso9001 +さい +##ile +##wood +##uo +image +lin +icon +american +##em +1932 +set +says +##king +##tive +blogger +##74 +なと +256 +147 +##ox +##zy +##red +##ium +##lf +nokia +claire +##リ +##ding +november +lohas +##500 +##tic +##マ +##cs +##ある +##che +##ire +##gy +##ult +db +january +win +##カ +166 +road +ptt +##ま +##つ +198 +##fa +##mer +anna +pchome +はい +udn +ef +420 +##time +##tte +2030 +##ア +g20 +white +かかります +1929 +308 +garden +eleven +di +##おります +chen +309b +777 +172 +young +cosplay +ちてない +4500 +bat +##123 +##tra +##ては +kindle +npc +steve +etc +##ern +##| +call +xperia +ces +travel +sk +s7 +##ous +1934 +##int +みいたたけます +183 +edu +file +cho +qr +##car +##our +186 +##ant +##d +eric +1914 +rends +##jo +##する +mastercard +##2000 +kb +##min +290 +##ino +vista +##ris +##ud +jack +2400 +##set +169 +pos +1912 +##her +##ou +taipei +しく +205 +beta +##ませんか +232 +##fi +express +255 +body +##ill +aphojoy +user +december +meiki +##ick +tweet +richard +##av +##ᆫ +iphone6 +##dd +ちてすか +views +##mark +321 +pd +##00 +times +##▲ +level +##ash +10g +point +5l +##ome +208 +koreanmall +##ak +george +q2 +206 +wma +tcp +##200 +スタッフ +full +mlb +##lle +##watch +tm +run +179 +911 +smith +business +##und +1919 +color +##tal +222 +171 +##less +moon +4399 +##rl +update +pcb +shop +499 +157 +little +なし +end +##mhz +van +dsp +easy +660 +##house +##key +history +##o +oh +##001 +##hy +##web +oem +let +was +##2009 +##gg +review +##wan +182 +##°c +203 +uc +title +##val +united +233 +2021 +##ons +doi +trivago +overdope +sbs +##ance +##ち +grand +special +573032185 +imf +216 +wx17house +##so +##ーム +audi +##he +london +william +##rp +##ake +science +beach +cfa +amp +ps4 +880 +##800 +##link +##hp +crm +ferragamo +bell +make +##eng +195 +under +zh +photos +2300 +##style +##ント +via +176 +da +##gi +company +i7 +##ray +thomas +370 +ufo +i5 +##max +plc +ben +back +research +8g +173 +mike +##pc +##ッフ +september +189 +##ace +vps +february +167 +pantos +wp +lisa +1921 +★★ +jquery +night +long +offer +##berg +##news +1911 +##いて +ray +fks +wto +せます +over +164 +340 +##all +##rus +1924 +##888 +##works +blogtitle +loftpermalink +##→ +187 +martin +test +ling +km +##め +15000 +fda +v3 +##ja +##ロ +wedding +かある +outlet +family +##ea +をこ +##top +story +##ness +salvatore +##lu +204 +swift +215 +room +している +oracle +##ul +1925 +sam +b2c +week +pi +rock +##のは +##a +##けと +##ean +##300 +##gle +cctv +after +chinese +##back +powered +x2 +##tan +1918 +##nes +##イン +canon +only +181 +##zi +##las +say +##oe +184 +##sd +221 +##bot +##world +##zo +sky +made +top100 +just +1926 +pmi +802 +234 +gap +##vr +177 +les +174 +▲topoct +ball +vogue +vi +ing +ofweek +cos +##list +##ort +▲topmay +##なら +##lon +として +last +##tc +##of +##bus +##gen +real +eva +##コ +a3 +nas +##lie +##ria +##coin +##bt +▲topapr +his +212 +cat +nata +vive +health +⋯⋯ +drive +sir +▲topmar +du +cup +##カー +##ook +##よう +##sy +alex +msg +tour +しました +3ce +##word +193 +ebooks +r8 +block +318 +##より +2200 +nice +pvp +207 +months +1905 +rewards +##ther +1917 +0800 +##xi +##チ +##sc +micro +850 +gg +blogfp +op +1922 +daily +m1 +264 +true +##bb +ml +##tar +##のお +##ky +anthony +196 +253 +##yo +state +218 +##ara +##aa +##rc +##tz +##ston +より +gear +##eo +##ade +ge +see +1923 +##win +##ura +ss +heart +##den +##ita +down +##sm +el +png +2100 +610 +rakuten +whatsapp +bay +dream +add +##use +680 +311 +pad +gucci +mpv +##ode +##fo +island +▲topjun +##▼ +223 +jason +214 +chicago +##❤ +しの +##hone +io +##れる +##ことか +sogo +be2 +##ology +990 +cloud +vcd +##con +2~3 +##ford +##joy +##kb +##こさいます +##rade +but +##ach +docker +##ful +rfid +ul +##ase +hit +ford +##star +580 +##○ +11 +a2 +sdk +reading +edited +##are +cmos +##mc +238 +siri +light +##ella +##ため +bloomberg +##read +pizza +##ison +jimmy +##vm +college +node +journal +ba +18k +##play +245 +##cer +20 +magic +##yu +191 +jump +288 +tt +##ings +asr +##lia +3200 +step5 +network +##cd +mc +いします +1234 +pixstyleme +273 +##600 +2800 +money +★★★★★ +1280 +12 +430 +bl +みの +act +##tus +tokyo +##rial +##life +emba +##ae +saas +tcs +##rk +##wang +summer +##sp +ko +##ving +390 +premium +##その +netflix +##ヒ +uk +mt +##lton +right +frank +two +209 +える +##ple +##cal +021 +##んな +##sen +##ville +hold +nexus +dd +##ius +てお +##mah +##なく +tila +zero +820 +ce +##tin +resort +##ws +charles +old +p10 +5d +report +##360 +##ru +##には +bus +vans +lt +##est +pv +##レ +links +rebecca +##ツ +##dm +azure +##365 +きな +limited +bit +4gb +##mon +1910 +moto +##eam +213 +1913 +var +eos +なとの +226 +blogspot +された +699 +e3 +dos +dm +fc +##ments +##ik +##kw +boy +##bin +##ata +960 +er +##せ +219 +##vin +##tu +##ula +194 +##∥ +station +##ろ +##ature +835 +files +zara +hdr +top10 +nature +950 +magazine +s6 +marriott +##シ +avira +case +##っと +tab +##ran +tony +##home +oculus +im +##ral +jean +saint +cry +307 +rosie +##force +##ini +ice +##bert +のある +##nder +##mber +pet +2600 +##◆ +plurk +▲topdec +##sis +00kg +▲topnov +720 +##ence +tim +##ω +##nc +##ても +##name +log +ips +great +ikea +malaysia +unix +##イト +3600 +##ncy +##nie +12000 +akb48 +##ye +##oid +404 +##chi +##いた +oa +xuehai +##1000 +##orm +##rf +275 +さん +##ware +##リー +980 +ho +##pro +text +##era +560 +bob +227 +##ub +##2008 +8891 +scp +avi +##zen +2022 +mi +wu +museum +qvod +apache +lake +jcb +▲topaug +★★★ +ni +##hr +hill +302 +ne +weibo +490 +ruby +##ーシ +##ヶ +##row +4d +▲topjul +iv +##ish +github +306 +mate +312 +##スト +##lot +##ane +andrew +のハイト +##tina +t1 +rf +ed2k +##vel +##900 +way +final +りの +ns +5a +705 +197 +##メ +sweet +bytes +##ene +▲topjan +231 +##cker +##2007 +##px +100g +topapp +229 +helpapp +rs +low +14k +g4g +care +630 +ldquo +あり +##fork +leave +rm +edition +##gan +##zon +##qq +▲topsep +##google +##ism +gold +224 +explorer +##zer +toyota +category +select +visual +##labels +restaurant +##md +posts +s1 +##ico +もっと +angelababy +123456 +217 +sports +s3 +mbc +1915 +してくたさい +shell +x86 +candy +##new +kbs +face +xl +470 +##here +4a +swissinfo +v8 +▲topfeb +dram +##ual +##vice +3a +##wer +sport +q1 +ios10 +public +int +card +##c +ep +au +rt +##れた +1080 +bill +##mll +kim +30 +460 +wan +##uk +##ミ +x3 +298 +0t +scott +##ming +239 +e5 +##3d +h7n9 +worldcat +brown +##あります +##vo +##led +##580 +##ax +249 +410 +##ert +paris +##~6 +polo +925 +##lr +599 +##ナ +capital +##hing +bank +cv +1g +##chat +##s +##たい +adc +##ule +2m +##e +digital +hotmail +268 +##pad +870 +bbq +quot +##ring +before +wali +##まて +mcu +2k +2b +という +costco +316 +north +333 +switch +##city +##p +philips +##mann +management +panasonic +##cl +##vd +##ping +##rge +alice +##lk +##ましょう +css3 +##ney +vision +alpha +##ular +##400 +##tter +lz +にお +##ありません +mode +gre +1916 +pci +##tm +237 +1~2 +##yan +##そ +について +##let +##キ +work +war +coach +ah +mary +##ᅵ +huang +##pt +a8 +pt +follow +##berry +1895 +##ew +a5 +ghost +##ション +##wn +##og +south +##code +girls +##rid +action +villa +git +r11 +table +games +##cket +error +##anonymoussaid +##ag +here +##ame +##gc +qa +##■ +##lis +gmp +##gin +vmalife +##cher +yu +wedding +##tis +demo +dragon +530 +soho +social +bye +##rant +river +orz +acer +325 +##↑ +##ース +##ats +261 +del +##ven +440 +ups +##ように +##ター +305 +value +macd +yougou +##dn +661 +##ano +ll +##urt +##rent +continue +script +##wen +##ect +paper +263 +319 +shift +##chel +##フト +##cat +258 +x5 +fox +243 +##さん +car +aaa +##blog +loading +##yn +##tp +kuso +799 +si +sns +イカせるテンマ +ヒンクテンマ3 +rmb +vdc +forest +central +prime +help +ultra +##rmb +##ような +241 +square +688 +##しい +のないフロクに +##field +##reen +##ors +##ju +c1 +start +510 +##air +##map +cdn +##wo +cba +stephen +m8 +100km +##get +opera +##base +##ood +vsa +com™ +##aw +##ail +251 +なのて +count +t2 +##ᅡ +##een +2700 +hop +##gp +vsc +tree +##eg +##ose +816 +285 +##ories +##shop +alphago +v4 +1909 +simon +##ᆼ +fluke62max +zip +スホンサー +##sta +louis +cr +bas +##~10 +bc +##yer +hadoop +##ube +##wi +1906 +0755 +hola +##low +place +centre +5v +d3 +##fer +252 +##750 +##media +281 +540 +0l +exchange +262 +series +##ハー +##san +eb +##bank +##k +q3 +##nge +##mail +take +##lp +259 +1888 +client +east +cache +event +vincent +##ールを +きを +##nse +sui +855 +adchoice +##и +##stry +##なたの +246 +##zone +ga +apps +sea +##ab +248 +cisco +##タ +##rner +kymco +##care +dha +##pu +##yi +minkoff +royal +p1 +への +annie +269 +collection +kpi +playstation +257 +になります +866 +bh +##bar +queen +505 +radio +1904 +andy +armani +##xy +manager +iherb +##ery +##share +spring +raid +johnson +1908 +##ob +volvo +hall +##ball +v6 +our +taylor +##hk +bi +242 +##cp +kate +bo +water +technology +##rie +サイトは +277 +##ona +##sl +hpv +303 +gtx +hip +rdquo +jayz +stone +##lex +##rum +namespace +##やり +620 +##ale +##atic +des +##erson +##ql +##ves +##type +enter +##この +##てきます +d2 +##168 +##mix +##bian +との +a9 +jj +ky +##lc +access +movie +##hc +リストに +tower +##ration +##mit +ます +##nch +ua +tel +prefix +##o2 +1907 +##point +1901 +ott +~10 +##http +##ury +baidu +##ink +member +##logy +bigbang +nownews +##js +##shot +##tb +##こと +247 +eba +##tics +##lus +ける +v5 +spark +##ama +there +##ions +god +##lls +##down +hiv +##ress +burberry +day2 +##kv +◆◆ +jeff +related +film +edit +joseph +283 +##ark +cx +32gb +order +g9 +30000 +##ans +##tty +s5 +##bee +かあります +thread +xr +buy +sh +005 +land +spotify +mx +##ari +276 +##verse +×email +sf +why +##ことて +244 +7headlines +nego +sunny +dom +exo +401 +666 +positioning +fit +rgb +##tton +278 +kiss +alexa +adam +lp +みリストを +##g +mp +##ties +##llow +amy +##du +np +002 +institute +271 +##rth +##lar +2345 +590 +##des +sidebar +15 +imax +site +##cky +##kit +##ime +##009 +season +323 +##fun +##ンター +##ひ +gogoro +a7 +pu +lily +fire +twd600 +##ッセーシを +いて +##vis +30ml +##cture +##をお +information +##オ +close +friday +##くれる +yi +nick +てすか +##tta +##tel +6500 +##lock +cbd +economy +254 +かお +267 +tinker +double +375 +8gb +voice +##app +oops +channel +today +985 +##right +raw +xyz +##+ +jim +edm +##cent +7500 +supreme +814 +ds +##its +##asia +dropbox +##てすか +##tti +books +272 +100ml +##tle +##ller +##ken +##more +##boy +sex +309 +##dom +t3 +##ider +##なります +##unch +1903 +810 +feel +5500 +##かった +##put +により +s2 +mo +##gh +men +ka +amoled +div +##tr +##n1 +port +howard +##tags +ken +dnf +##nus +adsense +##а +ide +##へ +buff +thunder +##town +##ique +has +##body +auto +pin +##erry +tee +てした +295 +number +##the +##013 +object +psp +cool +udnbkk +16gb +##mic +miui +##tro +most +r2 +##alk +##nity +1880 +±0 +##いました +428 +s4 +law +version +##oa +n1 +sgs +docomo +##tf +##ack +henry +fc2 +##ded +##sco +##014 +##rite +286 +0mm +linkedin +##ada +##now +wii +##ndy +ucbug +##◎ +sputniknews +legalminer +##ika +##xp +2gb +##bu +q10 +oo +b6 +come +##rman +cheese +ming +maker +##gm +nikon +##fig +ppi +kelly +##ります +jchere +てきます +ted +md +003 +fgo +tech +##tto +dan +soc +##gl +##len +hair +earth +640 +521 +img +##pper +##a1 +##てきる +##ロク +acca +##ition +##ference +suite +##ig +outlook +##mond +##cation +398 +##pr +279 +101vip +358 +##999 +282 +64gb +3800 +345 +airport +##over +284 +##おり +jones +##ith +lab +##su +##いるのて +co2 +town +piece +##llo +no1 +vmware +24h +##qi +focus +reader +##admin +##ora +tb +false +##log +1898 +know +lan +838 +##ces +f4 +##ume +motel +stop +##oper +na +flickr +netcomponents +##af +##─ +pose +williams +local +##ound +##cg +##site +##iko +いお +274 +5m +gsm +con +##ath +1902 +friends +##hip +cell +317 +##rey +780 +cream +##cks +012 +##dp +facebooktwitterpinterestgoogle +sso +324 +shtml +song +swiss +##mw +##キンク +lumia +xdd +string +tiffany +522 +marc +られた +insee +russell +sc +dell +##ations +ok +camera +289 +##vs +##flow +##late +classic +287 +##nter +stay +g1 +mtv +512 +##ever +##lab +##nger +qe +sata +ryan +d1 +50ml +cms +##cing +su +292 +3300 +editor +296 +##nap +security +sunday +association +##ens +##700 +##bra +acg +##かり +sofascore +とは +mkv +##ign +jonathan +gary +build +labels +##oto +tesla +moba +qi +gohappy +general +ajax +1024 +##かる +サイト +society +##test +##urs +wps +fedora +##ich +mozilla +328 +##480 +##dr +usa +urn +##lina +##r +grace +##die +##try +##ader +1250 +##なり +elle +570 +##chen +##ᆯ +price +##ten +uhz +##ough +eq +##hen +states +push +session +balance +wow +506 +##cus +##py +when +##ward +##ep +34e +wong +library +prada +##サイト +##cle +running +##ree +313 +ck +date +q4 +##ctive +##ool +##> +mk +##ira +##163 +388 +die +secret +rq +dota +buffet +は1ヶ +e6 +##ez +pan +368 +ha +##card +##cha +2a +##さ +alan +day3 +eye +f3 +##end +france +keep +adi +rna +tvbs +##ala +solo +nova +##え +##tail +##ょう +support +##ries +##なる +##ved +base +copy +iis +fps +##ways +hero +hgih +profile +fish +mu +ssh +entertainment +chang +##wd +click +cake +##ond +pre +##tom +kic +pixel +##ov +##fl +product +6a +##pd +dear +##gate +es +yumi +audio +##² +##sky +echo +bin +where +##ture +329 +##ape +find +sap +isis +##なと +nand +##101 +##load +##ream +band +a6 +525 +never +##post +festival +50cm +##we +555 +guide +314 +zenfone +##ike +335 +gd +forum +jessica +strong +alexander +##ould +software +allen +##ious +program +360° +else +lohasthree +##gar +することかてきます +please +##れます +rc +##ggle +##ric +bim +50000 +##own +eclipse +355 +brian +3ds +##side +061 +361 +##other +##ける +##tech +##ator +485 +engine +##ged +##t +plaza +##fit +cia +ngo +westbrook +shi +tbs +50mm +##みませんか +sci +291 +reuters +##ily +contextlink +##hn +af +##cil +bridge +very +##cel +1890 +cambridge +##ize +15g +##aid +##data +790 +frm +##head +award +butler +##sun +meta +##mar +america +ps3 +puma +pmid +##すか +lc +670 +kitchen +##lic +オーフン5 +きなしソフトサーヒス +そして +day1 +future +★★★★ +##text +##page +##rris +pm1 +##ket +fans +##っています +1001 +christian +bot +kids +trackback +##hai +c3 +display +##hl +n2 +1896 +idea +さんも +##sent +airmail +##ug +##men +pwm +けます +028 +##lution +369 +852 +awards +schemas +354 +asics +wikipedia +font +##tional +##vy +c2 +293 +##れている +##dget +##ein +っている +contact +pepper +スキル +339 +##~5 +294 +##uel +##ument +730 +##hang +みてす +q5 +##sue +rain +##ndi +wei +swatch +##cept +わせ +331 +popular +##ste +##tag +p2 +501 +trc +1899 +##west +##live +justin +honda +ping +messenger +##rap +v9 +543 +##とは +unity +appqq +はすへて +025 +leo +##tone +##テ +##ass +uniqlo +##010 +502 +her +jane +memory +moneydj +##tical +human +12306 +していると +##m2 +coc +miacare +##mn +tmt +##core +vim +kk +##may +fan +target +use +too +338 +435 +2050 +867 +737 +fast +##2c +services +##ope +omega +energy +##わ +pinkoi +1a +##なから +##rain +jackson +##ement +##シャンルの +374 +366 +そんな +p9 +rd +##ᆨ +1111 +##tier +##vic +zone +##│ +385 +690 +dl +isofix +cpa +m4 +322 +kimi +めて +davis +##lay +lulu +##uck +050 +weeks +qs +##hop +920 +##n +ae +##ear +~5 +eia +405 +##fly +korea +jpeg +boost +##ship +small +##リア +1860 +eur +297 +425 +valley +##iel +simple +##ude +rn +k2 +##ena +されます +non +patrick +しているから +##ナー +feed +5757 +30g +process +well +qqmei +##thing +they +aws +lu +pink +##ters +##kin +または +board +##vertisement +wine +##ien +unicode +##dge +r1 +359 +##tant +いを +##twitter +##3c +cool1 +される +##れて +##l +isp +##012 +standard +45㎡2 +402 +##150 +matt +##fu +326 +##iner +googlemsn +pixnetfacebookyahoo +##ラン +x7 +886 +##uce +メーカー +sao +##ev +##きました +##file +9678 +403 +xddd +shirt +6l +##rio +##hat +3mm +givenchy +ya +bang +##lio +monday +crystal +ロクイン +##abc +336 +head +890 +ubuntuforumwikilinuxpastechat +##vc +##~20 +##rity +cnc +7866 +ipv6 +null +1897 +##ost +yang +imsean +tiger +##fet +##ンス +352 +##= +dji +327 +ji +maria +##come +##んて +foundation +3100 +##beth +##なった +1m +601 +active +##aft +##don +3p +sr +349 +emma +##khz +living +415 +353 +1889 +341 +709 +457 +sas +x6 +##face +pptv +x4 +##mate +han +sophie +##jing +337 +fifa +##mand +other +sale +inwedding +##gn +てきちゃいます +##mmy +##pmlast +bad +nana +nbc +してみてくたさいね +なとはお +##wu +##かあります +##あ +note7 +single +##340 +せからこ +してくたさい♪この +しにはとんとんワークケートを +するとあなたにもっとマッチした +ならワークケートへ +もみつかっちゃうかも +ワークケートの +##bel +window +##dio +##ht +union +age +382 +14 +##ivity +##y +コメント +domain +neo +##isa +##lter +5k +f5 +steven +##cts +powerpoint +tft +self +g2 +ft +##テル +zol +##act +mwc +381 +343 +もう +nbapop +408 +てある +eds +ace +##room +previous +author +tomtom +il +##ets +hu +financial +☆☆☆ +っています +bp +5t +chi +1gb +##hg +fairmont +cross +008 +gay +h2 +function +##けて +356 +also +1b +625 +##ータ +##raph +1894 +3~5 +##ils +i3 +334 +avenue +##host +による +##bon +##tsu +message +navigation +50g +fintech +h6 +##ことを +8cm +##ject +##vas +##firm +credit +##wf +xxxx +form +##nor +##space +huawei +plan +json +sbl +##dc +machine +921 +392 +wish +##120 +##sol +windows7 +edward +##ために +development +washington +##nsis +lo +818 +##sio +##ym +##bor +planet +##~8 +##wt +ieee +gpa +##めて +camp +ann +gm +##tw +##oka +connect +##rss +##work +##atus +wall +chicken +soul +2mm +##times +fa +##ather +##cord +009 +##eep +hitachi +gui +harry +##pan +e1 +disney +##press +##ーション +wind +386 +frigidaire +##tl +liu +hsu +332 +basic +von +ev +いた +てきる +スホンサーサイト +learning +##ull +expedia +archives +change +##wei +santa +cut +ins +6gb +turbo +brand +cf1 +508 +004 +return +747 +##rip +h1 +##nis +##をこ +128gb +##にお +3t +application +しており +emc +rx +##oon +384 +quick +412 +15058 +wilson +wing +chapter +##bug +beyond +##cms +##dar +##oh +zoom +e2 +trip +sb +##nba +rcep +342 +aspx +ci +080 +gc +gnu +める +##count +advanced +dance +dv +##url +##ging +367 +8591 +am09 +shadow +battle +346 +##i +##cia +##という +emily +##のてす +##tation +host +ff +techorz +sars +##mini +##mporary +##ering +nc +4200 +798 +##next +cma +##mbps +##gas +##ift +##dot +##ィ +455 +##~17 +amana +##りの +426 +##ros +ir +00㎡1 +##eet +##ible +##↓ +710 +ˋ▽ˊ +##aka +dcs +iq +##v +l1 +##lor +maggie +##011 +##iu +588 +##~1 +830 +##gt +1tb +articles +create +##burg +##iki +database +fantasy +##rex +##cam +dlc +dean +##you +hard +path +gaming +victoria +maps +cb +##lee +##itor +overchicstoretvhome +systems +##xt +416 +p3 +sarah +760 +##nan +407 +486 +x9 +install +second +626 +##ann +##ph +##rcle +##nic +860 +##nar +ec +##とう +768 +metro +chocolate +##rian +~4 +##table +##しています +skin +##sn +395 +mountain +##0mm +inparadise +6m +7x24 +ib +4800 +##jia +eeworld +creative +g5 +g3 +357 +parker +ecfa +village +からの +18000 +sylvia +サーヒス +hbl +##ques +##onsored +##x2 +##きます +##v4 +##tein +ie6 +383 +##stack +389 +ver +##ads +##baby +sound +bbe +##110 +##lone +##uid +ads +022 +gundam +351 +thinkpad +006 +scrum +match +##ave +mems +##470 +##oy +##なりました +##talk +glass +lamigo +span +##eme +job +##a5 +jay +wade +kde +498 +##lace +ocean +tvg +##covery +##r3 +##ners +##rea +junior +think +##aine +cover +##ision +##sia +↓↓ +##bow +msi +413 +458 +406 +##love +711 +801 +soft +z2 +##pl +456 +1840 +mobil +mind +##uy +427 +nginx +##oi +めた +##rr +6221 +##mple +##sson +##ーシてす +371 +##nts +91tv +comhd +crv3000 +##uard +1868 +397 +deep +lost +field +gallery +##bia +rate +spf +redis +traction +930 +icloud +011 +なら +fe +jose +372 +##tory +into +sohu +fx +899 +379 +kicstart2 +##hia +すく +##~3 +##sit +ra +24 +##walk +##xure +500g +##pact +pacific +xa +natural +carlo +##250 +##walker +1850 +##can +cto +gigi +516 +##サー +pen +##hoo +ob +matlab +##b +##yy +13913459 +##iti +mango +##bbs +sense +c5 +oxford +##ニア +walker +jennifer +##ola +course +##bre +701 +##pus +##rder +lucky +075 +##ぁ +ivy +なお +##nia +sotheby +side +##ugh +joy +##orage +##ush +##bat +##dt +364 +r9 +##2d +##gio +511 +country +wear +##lax +##~7 +##moon +393 +seven +study +411 +348 +lonzo +8k +##ェ +evolution +##イフ +##kk +gs +kd +##レス +arduino +344 +b12 +##lux +arpg +##rdon +cook +##x5 +dark +five +##als +##ida +とても +sign +362 +##ちの +something +20mm +##nda +387 +##posted +fresh +tf +1870 +422 +cam +##mine +##skip +##form +##ssion +education +394 +##tee +dyson +stage +##jie +want +##night +epson +pack +あります +##ppy +テリヘル +##█ +wd +##eh +##rence +left +##lvin +golden +mhz +discovery +##trix +##n2 +loft +##uch +##dra +##sse +speed +~1 +1mdb +sorry +welcome +##urn +wave +gaga +##lmer +teddy +##160 +トラックハック +せよ +611 +##f2016 +378 +rp +##sha +rar +##あなたに +##きた +840 +holiday +##ュー +373 +074 +##vg +##nos +##rail +gartner +gi +6p +##dium +kit +488 +b3 +eco +##ろう +20g +sean +##stone +autocad +nu +##np +f16 +write +029 +m5 +##ias +images +atp +##dk +fsm +504 +1350 +ve +52kb +##xxx +##のに +##cake +414 +unit +lim +ru +1v +##ification +published +angela +16g +analytics +ak +##q +##nel +gmt +##icon +again +##₂ +##bby +ios11 +445 +かこさいます +waze +いてす +##ハ +9985 +##ust +##ティー +framework +##007 +iptv +delete +52sykb +cl +wwdc +027 +30cm +##fw +##ての +1389 +##xon +brandt +##ses +##dragon +tc +vetements +anne +monte +modern +official +##へて +##ere +##nne +##oud +もちろん +50 +etnews +##a2 +##graphy +421 +863 +##ちゃん +444 +##rtex +##てお +l2 +##gma +mount +ccd +たと +archive +morning +tan +ddos +e7 +##ホ +day4 +##ウ +gis +453 +its +495 +factory +bruce +pg +##ito +ってくたさい +guest +cdma +##lling +536 +n3 +しかし +3~4 +mega +eyes +ro +13 +women +dac +church +##jun +singapore +##facebook +6991 +starbucks +##tos +##stin +##shine +zen +##mu +tina +20℃ +1893 +##たけて +503 +465 +request +##gence +qt +##っ +1886 +347 +363 +q7 +##zzi +diary +##tore +409 +##ead +468 +cst +##osa +canada +agent +va +##jiang +##ちは +##ーク +##lam +sg +##nix +##sday +##よって +g6 +##master +bing +##zl +charlie +16 +8mm +nb40 +##ーン +thai +##ルフ +ln284ct +##itz +##2f +bonnie +##food +##lent +originals +##stro +##lts +418 +∟∣ +##bscribe +children +ntd +yesstyle +##かも +hmv +##tment +d5 +2cm +arts +sms +##pn +##я +##いい +topios9 +539 +lifestyle +virtual +##ague +xz +##deo +muji +024 +unt +##nnis +##ᅩ +faq1 +1884 +396 +##ette +fly +64㎡ +はしめまして +441 +curry +##pop +のこ +release +##← +##◆◆ +##cast +073 +ありな +500ml +##ews +5c +##stle +ios7 +##ima +787 +dog +lenovo +##r4 +roger +013 +cbs +vornado +100m +417 +##desk +##クok +##ald +1867 +9595 +2900 +##van +oil +##x +some +break +common +##jy +##lines +g7 +twice +419 +ella +nano +belle +にこ +##mes +##self +##note +jb +##ことかてきます +benz +##との +##ova +451 +save +##wing +##ますのて +kai +りは +##hua +##rect +rainer +##unge +448 +##0m +adsl +##かな +guestname +##uma +##kins +##zu +tokichoi +##price +county +##med +##mus +rmk +391 +address +vm +えて +openload +##group +##hin +##iginal +amg +urban +##oz +jobs +emi +##public +beautiful +##sch +album +##dden +##bell +jerry +works +hostel +miller +##drive +##rmin +##10 +376 +boot +828 +##370 +##fx +##cm~ +1885 +##nome +##ctionary +##oman +##lish +##cr +##hm +433 +##how +432 +francis +xi +c919 +b5 +evernote +##uc +vga +##3000 +coupe +##urg +##cca +##uality +019 +6g +れる +multi +##また +##ett +em +hey +##ani +##tax +##rma +inside +than +740 +leonnhurt +##jin +ict +れた +bird +notes +200mm +くの +##dical +##lli +result +442 +iu +ee +438 +smap +gopro +##last +yin +pure +998 +32g +けた +5kg +##dan +##rame +mama +##oot +bean +marketing +##hur +2l +bella +sync +xuite +##ground +515 +discuz +##getrelax +##ince +##bay +##5s +cj +##イス +gmat +apt +##pass +jing +##rix +c4 +rich +##とても +niusnews +##ello +bag +770 +##eting +##mobile +18 +culture +015 +##のてすか +377 +1020 +area +##ience +616 +details +gp +universal +silver +dit +はお +private +ddd +u11 +kanshu +##ified +fung +##nny +dx +##520 +tai +475 +023 +##fr +##lean +3s +##pin +429 +##rin +25000 +ly +rick +##bility +usb3 +banner +##baru +##gion +metal +dt +vdf +1871 +karl +qualcomm +bear +1010 +oldid +ian +jo +##tors +population +##ernel +1882 +mmorpg +##mv +##bike +603 +##© +ww +friend +##ager +exhibition +##del +##pods +fpx +structure +##free +##tings +kl +##rley +##copyright +##mma +california +3400 +orange +yoga +4l +canmake +honey +##anda +##コメント +595 +nikkie +##ルハイト +dhl +publishing +##mall +##gnet +20cm +513 +##クセス +##┅ +e88 +970 +##dog +fishbase +##! +##" +### +##$ +##% +##& +##' +##( +##) +##* +##+ +##, +##- +##. +##/ +##: +##; +##< +##= +##> +##? +##@ +##[ +##\ +##] +##^ +##_ +##{ +##| +##} +##~ +##£ +##¤ +##¥ +##§ +##« +##± +##³ +##µ +##· +##¹ +##º +##» +##¼ +##ß +##æ +##÷ +##ø +##đ +##ŋ +##ɔ +##ə +##ɡ +##ʰ +##ˇ +##ˈ +##ˊ +##ˋ +##ˍ +##ː +##˙ +##˚ +##ˢ +##α +##β +##γ +##δ +##ε +##η +##θ +##ι +##κ +##λ +##μ +##ν +##ο +##π +##ρ +##ς +##σ +##τ +##υ +##φ +##χ +##ψ +##б +##в +##г +##д +##е +##ж +##з +##к +##л +##м +##н +##о +##п +##р +##с +##т +##у +##ф +##х +##ц +##ч +##ш +##ы +##ь +##і +##ا +##ب +##ة +##ت +##د +##ر +##س +##ع +##ل +##م +##ن +##ه +##و +##ي +##۩ +##ก +##ง +##น +##ม +##ย +##ร +##อ +##า +##เ +##๑ +##་ +##ღ +##ᄀ +##ᄁ +##ᄂ +##ᄃ +##ᄅ +##ᄆ +##ᄇ +##ᄈ +##ᄉ +##ᄋ +##ᄌ +##ᄎ +##ᄏ +##ᄐ +##ᄑ +##ᄒ +##ᅢ +##ᅣ +##ᅥ +##ᅦ +##ᅧ +##ᅨ +##ᅪ +##ᅬ +##ᅭ +##ᅮ +##ᅯ +##ᅲ +##ᅳ +##ᅴ +##ᆷ +##ᆸ +##ᆺ +##ᆻ +##ᗜ +##ᵃ +##ᵉ +##ᵍ +##ᵏ +##ᵐ +##ᵒ +##ᵘ +##‖ +##„ +##† +##• +##‥ +##‧ +##
 +##‰ +##′ +##″ +##‹ +##› +##※ +##‿ +##⁄ +##ⁱ +##⁺ +##ⁿ +##₁ +##₃ +##₄ +##€ +##№ +##ⅰ +##ⅱ +##ⅲ +##ⅳ +##ⅴ +##↔ +##↗ +##↘ +##⇒ +##∀ +##− +##∕ +##∙ +##√ +##∞ +##∟ +##∠ +##∣ +##∩ +##∮ +##∶ +##∼ +##∽ +##≈ +##≒ +##≡ +##≤ +##≥ +##≦ +##≧ +##≪ +##≫ +##⊙ +##⋅ +##⋈ +##⋯ +##⌒ +##① +##② +##③ +##④ +##⑤ +##⑥ +##⑦ +##⑧ +##⑨ +##⑩ +##⑴ +##⑵ +##⑶ +##⑷ +##⑸ +##⒈ +##⒉ +##⒊ +##⒋ +##ⓒ +##ⓔ +##ⓘ +##━ +##┃ +##┆ +##┊ +##┌ +##└ +##├ +##┣ +##═ +##║ +##╚ +##╞ +##╠ +##╭ +##╮ +##╯ +##╰ +##╱ +##╳ +##▂ +##▃ +##▅ +##▇ +##▉ +##▋ +##▌ +##▍ +##▎ +##□ +##▪ +##▫ +##▬ +##△ +##▶ +##► +##▽ +##◇ +##◕ +##◠ +##◢ +##◤ +##☀ +##☕ +##☞ +##☺ +##☼ +##♀ +##♂ +##♠ +##♡ +##♣ +##♦ +##♫ +##♬ +##✈ +##✔ +##✕ +##✖ +##✦ +##✨ +##✪ +##✰ +##✿ +##❀ +##➜ +##➤ +##⦿ +##、 +##。 +##〃 +##々 +##〇 +##〈 +##〉 +##《 +##》 +##「 +##」 +##『 +##』 +##【 +##】 +##〓 +##〔 +##〕 +##〖 +##〗 +##〜 +##〝 +##〞 +##ぃ +##ぇ +##ぬ +##ふ +##ほ +##む +##ゃ +##ゅ +##ゆ +##ょ +##゜ +##ゝ +##ァ +##ゥ +##エ +##ォ +##ケ +##サ +##セ +##ソ +##ッ +##ニ +##ヌ +##ネ +##ノ +##ヘ +##モ +##ャ +##ヤ +##ュ +##ユ +##ョ +##ヨ +##ワ +##ヲ +##・ +##ヽ +##ㄅ +##ㄆ +##ㄇ +##ㄉ +##ㄋ +##ㄌ +##ㄍ +##ㄎ +##ㄏ +##ㄒ +##ㄚ +##ㄛ +##ㄞ +##ㄟ +##ㄢ +##ㄤ +##ㄥ +##ㄧ +##ㄨ +##ㆍ +##㈦ +##㊣ +##㗎 +##一 +##丁 +##七 +##万 +##丈 +##三 +##上 +##下 +##不 +##与 +##丐 +##丑 +##专 +##且 +##丕 +##世 +##丘 +##丙 +##业 +##丛 +##东 +##丝 +##丞 +##丟 +##両 +##丢 +##两 +##严 +##並 +##丧 +##丨 +##个 +##丫 +##中 +##丰 +##串 +##临 +##丶 +##丸 +##丹 +##为 +##主 +##丼 +##丽 +##举 +##丿 +##乂 +##乃 +##久 +##么 +##义 +##之 +##乌 +##乍 +##乎 +##乏 +##乐 +##乒 +##乓 +##乔 +##乖 +##乗 +##乘 +##乙 +##乜 +##九 +##乞 +##也 +##习 +##乡 +##书 +##乩 +##买 +##乱 +##乳 +##乾 +##亀 +##亂 +##了 +##予 +##争 +##事 +##二 +##于 +##亏 +##云 +##互 +##五 +##井 +##亘 +##亙 +##亚 +##些 +##亜 +##亞 +##亟 +##亡 +##亢 +##交 +##亥 +##亦 +##产 +##亨 +##亩 +##享 +##京 +##亭 +##亮 +##亲 +##亳 +##亵 +##人 +##亿 +##什 +##仁 +##仃 +##仄 +##仅 +##仆 +##仇 +##今 +##介 +##仍 +##从 +##仏 +##仑 +##仓 +##仔 +##仕 +##他 +##仗 +##付 +##仙 +##仝 +##仞 +##仟 +##代 +##令 +##以 +##仨 +##仪 +##们 +##仮 +##仰 +##仲 +##件 +##价 +##任 +##份 +##仿 +##企 +##伉 +##伊 +##伍 +##伎 +##伏 +##伐 +##休 +##伕 +##众 +##优 +##伙 +##会 +##伝 +##伞 +##伟 +##传 +##伢 +##伤 +##伦 +##伪 +##伫 +##伯 +##估 +##伴 +##伶 +##伸 +##伺 +##似 +##伽 +##佃 +##但 +##佇 +##佈 +##位 +##低 +##住 +##佐 +##佑 +##体 +##佔 +##何 +##佗 +##佘 +##余 +##佚 +##佛 +##作 +##佝 +##佞 +##佟 +##你 +##佢 +##佣 +##佤 +##佥 +##佩 +##佬 +##佯 +##佰 +##佳 +##併 +##佶 +##佻 +##佼 +##使 +##侃 +##侄 +##來 +##侈 +##例 +##侍 +##侏 +##侑 +##侖 +##侗 +##供 +##依 +##侠 +##価 +##侣 +##侥 +##侦 +##侧 +##侨 +##侬 +##侮 +##侯 +##侵 +##侶 +##侷 +##便 +##係 +##促 +##俄 +##俊 +##俎 +##俏 +##俐 +##俑 +##俗 +##俘 +##俚 +##保 +##俞 +##俟 +##俠 +##信 +##俨 +##俩 +##俪 +##俬 +##俭 +##修 +##俯 +##俱 +##俳 +##俸 +##俺 +##俾 +##倆 +##倉 +##個 +##倌 +##倍 +##倏 +##們 +##倒 +##倔 +##倖 +##倘 +##候 +##倚 +##倜 +##借 +##倡 +##値 +##倦 +##倩 +##倪 +##倫 +##倬 +##倭 +##倶 +##债 +##值 +##倾 +##偃 +##假 +##偈 +##偉 +##偌 +##偎 +##偏 +##偕 +##做 +##停 +##健 +##側 +##偵 +##偶 +##偷 +##偻 +##偽 +##偿 +##傀 +##傅 +##傍 +##傑 +##傘 +##備 +##傚 +##傢 +##傣 +##傥 +##储 +##傩 +##催 +##傭 +##傲 +##傳 +##債 +##傷 +##傻 +##傾 +##僅 +##働 +##像 +##僑 +##僕 +##僖 +##僚 +##僥 +##僧 +##僭 +##僮 +##僱 +##僵 +##價 +##僻 +##儀 +##儂 +##億 +##儆 +##儉 +##儋 +##儒 +##儕 +##儘 +##償 +##儡 +##優 +##儲 +##儷 +##儼 +##儿 +##兀 +##允 +##元 +##兄 +##充 +##兆 +##兇 +##先 +##光 +##克 +##兌 +##免 +##児 +##兑 +##兒 +##兔 +##兖 +##党 +##兜 +##兢 +##入 +##內 +##全 +##兩 +##八 +##公 +##六 +##兮 +##兰 +##共 +##兲 +##关 +##兴 +##兵 +##其 +##具 +##典 +##兹 +##养 +##兼 +##兽 +##冀 +##内 +##円 +##冇 +##冈 +##冉 +##冊 +##册 +##再 +##冏 +##冒 +##冕 +##冗 +##写 +##军 +##农 +##冠 +##冢 +##冤 +##冥 +##冨 +##冪 +##冬 +##冯 +##冰 +##冲 +##决 +##况 +##冶 +##冷 +##冻 +##冼 +##冽 +##冾 +##净 +##凄 +##准 +##凇 +##凈 +##凉 +##凋 +##凌 +##凍 +##减 +##凑 +##凛 +##凜 +##凝 +##几 +##凡 +##凤 +##処 +##凪 +##凭 +##凯 +##凰 +##凱 +##凳 +##凶 +##凸 +##凹 +##出 +##击 +##函 +##凿 +##刀 +##刁 +##刃 +##分 +##切 +##刈 +##刊 +##刍 +##刎 +##刑 +##划 +##列 +##刘 +##则 +##刚 +##创 +##初 +##删 +##判 +##別 +##刨 +##利 +##刪 +##别 +##刮 +##到 +##制 +##刷 +##券 +##刹 +##刺 +##刻 +##刽 +##剁 +##剂 +##剃 +##則 +##剉 +##削 +##剋 +##剌 +##前 +##剎 +##剐 +##剑 +##剔 +##剖 +##剛 +##剜 +##剝 +##剣 +##剤 +##剥 +##剧 +##剩 +##剪 +##副 +##割 +##創 +##剷 +##剽 +##剿 +##劃 +##劇 +##劈 +##劉 +##劊 +##劍 +##劏 +##劑 +##力 +##劝 +##办 +##功 +##加 +##务 +##劣 +##动 +##助 +##努 +##劫 +##劭 +##励 +##劲 +##劳 +##労 +##劵 +##効 +##劾 +##势 +##勁 +##勃 +##勇 +##勉 +##勋 +##勐 +##勒 +##動 +##勖 +##勘 +##務 +##勛 +##勝 +##勞 +##募 +##勢 +##勤 +##勧 +##勳 +##勵 +##勸 +##勺 +##勻 +##勾 +##勿 +##匀 +##包 +##匆 +##匈 +##匍 +##匐 +##匕 +##化 +##北 +##匙 +##匝 +##匠 +##匡 +##匣 +##匪 +##匮 +##匯 +##匱 +##匹 +##区 +##医 +##匾 +##匿 +##區 +##十 +##千 +##卅 +##升 +##午 +##卉 +##半 +##卍 +##华 +##协 +##卑 +##卒 +##卓 +##協 +##单 +##卖 +##南 +##単 +##博 +##卜 +##卞 +##卟 +##占 +##卡 +##卢 +##卤 +##卦 +##卧 +##卫 +##卮 +##卯 +##印 +##危 +##即 +##却 +##卵 +##卷 +##卸 +##卻 +##卿 +##厂 +##厄 +##厅 +##历 +##厉 +##压 +##厌 +##厕 +##厘 +##厚 +##厝 +##原 +##厢 +##厥 +##厦 +##厨 +##厩 +##厭 +##厮 +##厲 +##厳 +##去 +##县 +##叁 +##参 +##參 +##又 +##叉 +##及 +##友 +##双 +##反 +##収 +##发 +##叔 +##取 +##受 +##变 +##叙 +##叛 +##叟 +##叠 +##叡 +##叢 +##口 +##古 +##句 +##另 +##叨 +##叩 +##只 +##叫 +##召 +##叭 +##叮 +##可 +##台 +##叱 +##史 +##右 +##叵 +##叶 +##号 +##司 +##叹 +##叻 +##叼 +##叽 +##吁 +##吃 +##各 +##吆 +##合 +##吉 +##吊 +##吋 +##同 +##名 +##后 +##吏 +##吐 +##向 +##吒 +##吓 +##吕 +##吖 +##吗 +##君 +##吝 +##吞 +##吟 +##吠 +##吡 +##否 +##吧 +##吨 +##吩 +##含 +##听 +##吭 +##吮 +##启 +##吱 +##吳 +##吴 +##吵 +##吶 +##吸 +##吹 +##吻 +##吼 +##吽 +##吾 +##呀 +##呂 +##呃 +##呆 +##呈 +##告 +##呋 +##呎 +##呐 +##呓 +##呕 +##呗 +##员 +##呛 +##呜 +##呢 +##呤 +##呦 +##周 +##呱 +##呲 +##味 +##呵 +##呷 +##呸 +##呻 +##呼 +##命 +##咀 +##咁 +##咂 +##咄 +##咆 +##咋 +##和 +##咎 +##咏 +##咐 +##咒 +##咔 +##咕 +##咖 +##咗 +##咘 +##咙 +##咚 +##咛 +##咣 +##咤 +##咦 +##咧 +##咨 +##咩 +##咪 +##咫 +##咬 +##咭 +##咯 +##咱 +##咲 +##咳 +##咸 +##咻 +##咽 +##咿 +##哀 +##品 +##哂 +##哄 +##哆 +##哇 +##哈 +##哉 +##哋 +##哌 +##响 +##哎 +##哏 +##哐 +##哑 +##哒 +##哔 +##哗 +##哟 +##員 +##哥 +##哦 +##哧 +##哨 +##哩 +##哪 +##哭 +##哮 +##哲 +##哺 +##哼 +##哽 +##唁 +##唄 +##唆 +##唇 +##唉 +##唏 +##唐 +##唑 +##唔 +##唠 +##唤 +##唧 +##唬 +##售 +##唯 +##唰 +##唱 +##唳 +##唷 +##唸 +##唾 +##啃 +##啄 +##商 +##啉 +##啊 +##問 +##啓 +##啕 +##啖 +##啜 +##啞 +##啟 +##啡 +##啤 +##啥 +##啦 +##啧 +##啪 +##啫 +##啬 +##啮 +##啰 +##啱 +##啲 +##啵 +##啶 +##啷 +##啸 +##啻 +##啼 +##啾 +##喀 +##喂 +##喃 +##善 +##喆 +##喇 +##喉 +##喊 +##喋 +##喎 +##喏 +##喔 +##喘 +##喙 +##喚 +##喜 +##喝 +##喟 +##喧 +##喪 +##喫 +##喬 +##單 +##喰 +##喱 +##喲 +##喳 +##喵 +##営 +##喷 +##喹 +##喺 +##喻 +##喽 +##嗅 +##嗆 +##嗇 +##嗎 +##嗑 +##嗒 +##嗓 +##嗔 +##嗖 +##嗚 +##嗜 +##嗝 +##嗟 +##嗡 +##嗣 +##嗤 +##嗦 +##嗨 +##嗪 +##嗬 +##嗯 +##嗰 +##嗲 +##嗳 +##嗶 +##嗷 +##嗽 +##嘀 +##嘅 +##嘆 +##嘈 +##嘉 +##嘌 +##嘍 +##嘎 +##嘔 +##嘖 +##嘗 +##嘘 +##嘚 +##嘛 +##嘜 +##嘞 +##嘟 +##嘢 +##嘣 +##嘤 +##嘧 +##嘩 +##嘭 +##嘮 +##嘯 +##嘰 +##嘱 +##嘲 +##嘴 +##嘶 +##嘸 +##嘹 +##嘻 +##嘿 +##噁 +##噌 +##噎 +##噓 +##噔 +##噗 +##噙 +##噜 +##噠 +##噢 +##噤 +##器 +##噩 +##噪 +##噬 +##噱 +##噴 +##噶 +##噸 +##噹 +##噻 +##噼 +##嚀 +##嚇 +##嚎 +##嚏 +##嚐 +##嚓 +##嚕 +##嚟 +##嚣 +##嚥 +##嚨 +##嚮 +##嚴 +##嚷 +##嚼 +##囂 +##囉 +##囊 +##囍 +##囑 +##囔 +##囗 +##囚 +##四 +##囝 +##回 +##囟 +##因 +##囡 +##团 +##団 +##囤 +##囧 +##囪 +##囫 +##园 +##困 +##囱 +##囲 +##図 +##围 +##囹 +##固 +##国 +##图 +##囿 +##圃 +##圄 +##圆 +##圈 +##國 +##圍 +##圏 +##園 +##圓 +##圖 +##團 +##圜 +##土 +##圣 +##圧 +##在 +##圩 +##圭 +##地 +##圳 +##场 +##圻 +##圾 +##址 +##坂 +##均 +##坊 +##坍 +##坎 +##坏 +##坐 +##坑 +##块 +##坚 +##坛 +##坝 +##坞 +##坟 +##坠 +##坡 +##坤 +##坦 +##坨 +##坪 +##坯 +##坳 +##坵 +##坷 +##垂 +##垃 +##垄 +##型 +##垒 +##垚 +##垛 +##垠 +##垢 +##垣 +##垦 +##垩 +##垫 +##垭 +##垮 +##垵 +##埂 +##埃 +##埋 +##城 +##埔 +##埕 +##埗 +##域 +##埠 +##埤 +##埵 +##執 +##埸 +##培 +##基 +##埼 +##堀 +##堂 +##堃 +##堅 +##堆 +##堇 +##堑 +##堕 +##堙 +##堡 +##堤 +##堪 +##堯 +##堰 +##報 +##場 +##堵 +##堺 +##堿 +##塊 +##塌 +##塑 +##塔 +##塗 +##塘 +##塚 +##塞 +##塢 +##塩 +##填 +##塬 +##塭 +##塵 +##塾 +##墀 +##境 +##墅 +##墉 +##墊 +##墒 +##墓 +##増 +##墘 +##墙 +##墜 +##增 +##墟 +##墨 +##墩 +##墮 +##墳 +##墻 +##墾 +##壁 +##壅 +##壆 +##壇 +##壊 +##壑 +##壓 +##壕 +##壘 +##壞 +##壟 +##壢 +##壤 +##壩 +##士 +##壬 +##壮 +##壯 +##声 +##売 +##壳 +##壶 +##壹 +##壺 +##壽 +##处 +##备 +##変 +##复 +##夏 +##夔 +##夕 +##外 +##夙 +##多 +##夜 +##够 +##夠 +##夢 +##夥 +##大 +##天 +##太 +##夫 +##夭 +##央 +##夯 +##失 +##头 +##夷 +##夸 +##夹 +##夺 +##夾 +##奂 +##奄 +##奇 +##奈 +##奉 +##奋 +##奎 +##奏 +##奐 +##契 +##奔 +##奕 +##奖 +##套 +##奘 +##奚 +##奠 +##奢 +##奥 +##奧 +##奪 +##奬 +##奮 +##女 +##奴 +##奶 +##奸 +##她 +##好 +##如 +##妃 +##妄 +##妆 +##妇 +##妈 +##妊 +##妍 +##妒 +##妓 +##妖 +##妘 +##妙 +##妝 +##妞 +##妣 +##妤 +##妥 +##妨 +##妩 +##妪 +##妮 +##妲 +##妳 +##妹 +##妻 +##妾 +##姆 +##姉 +##姊 +##始 +##姍 +##姐 +##姑 +##姒 +##姓 +##委 +##姗 +##姚 +##姜 +##姝 +##姣 +##姥 +##姦 +##姨 +##姪 +##姫 +##姬 +##姹 +##姻 +##姿 +##威 +##娃 +##娄 +##娅 +##娆 +##娇 +##娉 +##娑 +##娓 +##娘 +##娛 +##娜 +##娟 +##娠 +##娣 +##娥 +##娩 +##娱 +##娲 +##娴 +##娶 +##娼 +##婀 +##婁 +##婆 +##婉 +##婊 +##婕 +##婚 +##婢 +##婦 +##婧 +##婪 +##婭 +##婴 +##婵 +##婶 +##婷 +##婺 +##婿 +##媒 +##媚 +##媛 +##媞 +##媧 +##媲 +##媳 +##媽 +##媾 +##嫁 +##嫂 +##嫉 +##嫌 +##嫑 +##嫔 +##嫖 +##嫘 +##嫚 +##嫡 +##嫣 +##嫦 +##嫩 +##嫲 +##嫵 +##嫻 +##嬅 +##嬉 +##嬌 +##嬗 +##嬛 +##嬢 +##嬤 +##嬪 +##嬰 +##嬴 +##嬷 +##嬸 +##嬿 +##孀 +##孃 +##子 +##孑 +##孔 +##孕 +##孖 +##字 +##存 +##孙 +##孚 +##孛 +##孜 +##孝 +##孟 +##孢 +##季 +##孤 +##学 +##孩 +##孪 +##孫 +##孬 +##孰 +##孱 +##孳 +##孵 +##學 +##孺 +##孽 +##孿 +##宁 +##它 +##宅 +##宇 +##守 +##安 +##宋 +##完 +##宏 +##宓 +##宕 +##宗 +##官 +##宙 +##定 +##宛 +##宜 +##宝 +##实 +##実 +##宠 +##审 +##客 +##宣 +##室 +##宥 +##宦 +##宪 +##宫 +##宮 +##宰 +##害 +##宴 +##宵 +##家 +##宸 +##容 +##宽 +##宾 +##宿 +##寂 +##寄 +##寅 +##密 +##寇 +##富 +##寐 +##寒 +##寓 +##寛 +##寝 +##寞 +##察 +##寡 +##寢 +##寥 +##實 +##寧 +##寨 +##審 +##寫 +##寬 +##寮 +##寰 +##寵 +##寶 +##寸 +##对 +##寺 +##寻 +##导 +##対 +##寿 +##封 +##専 +##射 +##将 +##將 +##專 +##尉 +##尊 +##尋 +##對 +##導 +##小 +##少 +##尔 +##尕 +##尖 +##尘 +##尚 +##尝 +##尤 +##尧 +##尬 +##就 +##尴 +##尷 +##尸 +##尹 +##尺 +##尻 +##尼 +##尽 +##尾 +##尿 +##局 +##屁 +##层 +##屄 +##居 +##屆 +##屈 +##屉 +##届 +##屋 +##屌 +##屍 +##屎 +##屏 +##屐 +##屑 +##展 +##屜 +##属 +##屠 +##屡 +##屢 +##層 +##履 +##屬 +##屯 +##山 +##屹 +##屿 +##岀 +##岁 +##岂 +##岌 +##岐 +##岑 +##岔 +##岖 +##岗 +##岘 +##岙 +##岚 +##岛 +##岡 +##岩 +##岫 +##岬 +##岭 +##岱 +##岳 +##岷 +##岸 +##峇 +##峋 +##峒 +##峙 +##峡 +##峤 +##峥 +##峦 +##峨 +##峪 +##峭 +##峯 +##峰 +##峴 +##島 +##峻 +##峽 +##崁 +##崂 +##崆 +##崇 +##崎 +##崑 +##崔 +##崖 +##崗 +##崙 +##崛 +##崧 +##崩 +##崭 +##崴 +##崽 +##嵇 +##嵊 +##嵋 +##嵌 +##嵐 +##嵘 +##嵩 +##嵬 +##嵯 +##嶂 +##嶄 +##嶇 +##嶋 +##嶙 +##嶺 +##嶼 +##嶽 +##巅 +##巍 +##巒 +##巔 +##巖 +##川 +##州 +##巡 +##巢 +##工 +##左 +##巧 +##巨 +##巩 +##巫 +##差 +##己 +##已 +##巳 +##巴 +##巷 +##巻 +##巽 +##巾 +##巿 +##币 +##市 +##布 +##帅 +##帆 +##师 +##希 +##帐 +##帑 +##帕 +##帖 +##帘 +##帚 +##帛 +##帜 +##帝 +##帥 +##带 +##帧 +##師 +##席 +##帮 +##帯 +##帰 +##帳 +##帶 +##帷 +##常 +##帼 +##帽 +##幀 +##幂 +##幄 +##幅 +##幌 +##幔 +##幕 +##幟 +##幡 +##幢 +##幣 +##幫 +##干 +##平 +##年 +##并 +##幸 +##幹 +##幺 +##幻 +##幼 +##幽 +##幾 +##广 +##庁 +##広 +##庄 +##庆 +##庇 +##床 +##序 +##庐 +##库 +##应 +##底 +##庖 +##店 +##庙 +##庚 +##府 +##庞 +##废 +##庠 +##度 +##座 +##庫 +##庭 +##庵 +##庶 +##康 +##庸 +##庹 +##庾 +##廁 +##廂 +##廃 +##廈 +##廉 +##廊 +##廓 +##廖 +##廚 +##廝 +##廟 +##廠 +##廢 +##廣 +##廬 +##廳 +##延 +##廷 +##建 +##廿 +##开 +##弁 +##异 +##弃 +##弄 +##弈 +##弊 +##弋 +##式 +##弑 +##弒 +##弓 +##弔 +##引 +##弗 +##弘 +##弛 +##弟 +##张 +##弥 +##弦 +##弧 +##弩 +##弭 +##弯 +##弱 +##張 +##強 +##弹 +##强 +##弼 +##弾 +##彅 +##彆 +##彈 +##彌 +##彎 +##归 +##当 +##录 +##彗 +##彙 +##彝 +##形 +##彤 +##彥 +##彦 +##彧 +##彩 +##彪 +##彫 +##彬 +##彭 +##彰 +##影 +##彷 +##役 +##彻 +##彼 +##彿 +##往 +##征 +##径 +##待 +##徇 +##很 +##徉 +##徊 +##律 +##後 +##徐 +##徑 +##徒 +##従 +##徕 +##得 +##徘 +##徙 +##徜 +##從 +##徠 +##御 +##徨 +##復 +##循 +##徬 +##微 +##徳 +##徴 +##徵 +##德 +##徹 +##徼 +##徽 +##心 +##必 +##忆 +##忌 +##忍 +##忏 +##忐 +##忑 +##忒 +##忖 +##志 +##忘 +##忙 +##応 +##忠 +##忡 +##忤 +##忧 +##忪 +##快 +##忱 +##念 +##忻 +##忽 +##忿 +##怀 +##态 +##怂 +##怅 +##怆 +##怎 +##怏 +##怒 +##怔 +##怕 +##怖 +##怙 +##怜 +##思 +##怠 +##怡 +##急 +##怦 +##性 +##怨 +##怪 +##怯 +##怵 +##总 +##怼 +##恁 +##恃 +##恆 +##恋 +##恍 +##恐 +##恒 +##恕 +##恙 +##恚 +##恢 +##恣 +##恤 +##恥 +##恨 +##恩 +##恪 +##恫 +##恬 +##恭 +##息 +##恰 +##恳 +##恵 +##恶 +##恸 +##恺 +##恻 +##恼 +##恿 +##悄 +##悅 +##悉 +##悌 +##悍 +##悔 +##悖 +##悚 +##悟 +##悠 +##患 +##悦 +##您 +##悩 +##悪 +##悬 +##悯 +##悱 +##悲 +##悴 +##悵 +##悶 +##悸 +##悻 +##悼 +##悽 +##情 +##惆 +##惇 +##惊 +##惋 +##惑 +##惕 +##惘 +##惚 +##惜 +##惟 +##惠 +##惡 +##惦 +##惧 +##惨 +##惩 +##惫 +##惬 +##惭 +##惮 +##惯 +##惰 +##惱 +##想 +##惴 +##惶 +##惹 +##惺 +##愁 +##愆 +##愈 +##愉 +##愍 +##意 +##愕 +##愚 +##愛 +##愜 +##感 +##愣 +##愤 +##愧 +##愫 +##愷 +##愿 +##慄 +##慈 +##態 +##慌 +##慎 +##慑 +##慕 +##慘 +##慚 +##慟 +##慢 +##慣 +##慧 +##慨 +##慫 +##慮 +##慰 +##慳 +##慵 +##慶 +##慷 +##慾 +##憂 +##憊 +##憋 +##憎 +##憐 +##憑 +##憔 +##憚 +##憤 +##憧 +##憨 +##憩 +##憫 +##憬 +##憲 +##憶 +##憾 +##懂 +##懇 +##懈 +##應 +##懊 +##懋 +##懑 +##懒 +##懦 +##懲 +##懵 +##懶 +##懷 +##懸 +##懺 +##懼 +##懾 +##懿 +##戀 +##戈 +##戊 +##戌 +##戍 +##戎 +##戏 +##成 +##我 +##戒 +##戕 +##或 +##战 +##戚 +##戛 +##戟 +##戡 +##戦 +##截 +##戬 +##戮 +##戰 +##戲 +##戳 +##戴 +##戶 +##户 +##戸 +##戻 +##戾 +##房 +##所 +##扁 +##扇 +##扈 +##扉 +##手 +##才 +##扎 +##扑 +##扒 +##打 +##扔 +##払 +##托 +##扛 +##扣 +##扦 +##执 +##扩 +##扪 +##扫 +##扬 +##扭 +##扮 +##扯 +##扰 +##扱 +##扳 +##扶 +##批 +##扼 +##找 +##承 +##技 +##抄 +##抉 +##把 +##抑 +##抒 +##抓 +##投 +##抖 +##抗 +##折 +##抚 +##抛 +##抜 +##択 +##抟 +##抠 +##抡 +##抢 +##护 +##报 +##抨 +##披 +##抬 +##抱 +##抵 +##抹 +##押 +##抽 +##抿 +##拂 +##拄 +##担 +##拆 +##拇 +##拈 +##拉 +##拋 +##拌 +##拍 +##拎 +##拐 +##拒 +##拓 +##拔 +##拖 +##拗 +##拘 +##拙 +##拚 +##招 +##拜 +##拟 +##拡 +##拢 +##拣 +##拥 +##拦 +##拧 +##拨 +##择 +##括 +##拭 +##拮 +##拯 +##拱 +##拳 +##拴 +##拷 +##拼 +##拽 +##拾 +##拿 +##持 +##挂 +##指 +##挈 +##按 +##挎 +##挑 +##挖 +##挙 +##挚 +##挛 +##挝 +##挞 +##挟 +##挠 +##挡 +##挣 +##挤 +##挥 +##挨 +##挪 +##挫 +##振 +##挲 +##挹 +##挺 +##挽 +##挾 +##捂 +##捅 +##捆 +##捉 +##捋 +##捌 +##捍 +##捎 +##捏 +##捐 +##捕 +##捞 +##损 +##捡 +##换 +##捣 +##捧 +##捨 +##捩 +##据 +##捱 +##捲 +##捶 +##捷 +##捺 +##捻 +##掀 +##掂 +##掃 +##掇 +##授 +##掉 +##掌 +##掏 +##掐 +##排 +##掖 +##掘 +##掙 +##掛 +##掠 +##採 +##探 +##掣 +##接 +##控 +##推 +##掩 +##措 +##掬 +##掰 +##掲 +##掳 +##掴 +##掷 +##掸 +##掺 +##揀 +##揃 +##揄 +##揆 +##揉 +##揍 +##描 +##提 +##插 +##揖 +##揚 +##換 +##握 +##揣 +##揩 +##揪 +##揭 +##揮 +##援 +##揶 +##揸 +##揹 +##揽 +##搀 +##搁 +##搂 +##搅 +##損 +##搏 +##搐 +##搓 +##搔 +##搖 +##搗 +##搜 +##搞 +##搡 +##搪 +##搬 +##搭 +##搵 +##搶 +##携 +##搽 +##摀 +##摁 +##摄 +##摆 +##摇 +##摈 +##摊 +##摒 +##摔 +##摘 +##摞 +##摟 +##摧 +##摩 +##摯 +##摳 +##摸 +##摹 +##摺 +##摻 +##撂 +##撃 +##撅 +##撇 +##撈 +##撐 +##撑 +##撒 +##撓 +##撕 +##撚 +##撞 +##撤 +##撥 +##撩 +##撫 +##撬 +##播 +##撮 +##撰 +##撲 +##撵 +##撷 +##撸 +##撻 +##撼 +##撿 +##擀 +##擁 +##擂 +##擄 +##擅 +##擇 +##擊 +##擋 +##操 +##擎 +##擒 +##擔 +##擘 +##據 +##擞 +##擠 +##擡 +##擢 +##擦 +##擬 +##擰 +##擱 +##擲 +##擴 +##擷 +##擺 +##擼 +##擾 +##攀 +##攏 +##攒 +##攔 +##攘 +##攙 +##攜 +##攝 +##攞 +##攢 +##攣 +##攤 +##攥 +##攪 +##攫 +##攬 +##支 +##收 +##攸 +##改 +##攻 +##放 +##政 +##故 +##效 +##敌 +##敍 +##敎 +##敏 +##救 +##敕 +##敖 +##敗 +##敘 +##教 +##敛 +##敝 +##敞 +##敢 +##散 +##敦 +##敬 +##数 +##敲 +##整 +##敵 +##敷 +##數 +##斂 +##斃 +##文 +##斋 +##斌 +##斎 +##斐 +##斑 +##斓 +##斗 +##料 +##斛 +##斜 +##斟 +##斡 +##斤 +##斥 +##斧 +##斩 +##斫 +##斬 +##断 +##斯 +##新 +##斷 +##方 +##於 +##施 +##旁 +##旃 +##旅 +##旋 +##旌 +##旎 +##族 +##旖 +##旗 +##无 +##既 +##日 +##旦 +##旧 +##旨 +##早 +##旬 +##旭 +##旮 +##旱 +##时 +##旷 +##旺 +##旻 +##昀 +##昂 +##昆 +##昇 +##昉 +##昊 +##昌 +##明 +##昏 +##易 +##昔 +##昕 +##昙 +##星 +##映 +##春 +##昧 +##昨 +##昭 +##是 +##昱 +##昴 +##昵 +##昶 +##昼 +##显 +##晁 +##時 +##晃 +##晉 +##晋 +##晌 +##晏 +##晒 +##晓 +##晔 +##晕 +##晖 +##晗 +##晚 +##晝 +##晞 +##晟 +##晤 +##晦 +##晨 +##晩 +##普 +##景 +##晰 +##晴 +##晶 +##晷 +##智 +##晾 +##暂 +##暄 +##暇 +##暈 +##暉 +##暌 +##暐 +##暑 +##暖 +##暗 +##暝 +##暢 +##暧 +##暨 +##暫 +##暮 +##暱 +##暴 +##暸 +##暹 +##曄 +##曆 +##曇 +##曉 +##曖 +##曙 +##曜 +##曝 +##曠 +##曦 +##曬 +##曰 +##曲 +##曳 +##更 +##書 +##曹 +##曼 +##曾 +##替 +##最 +##會 +##月 +##有 +##朋 +##服 +##朐 +##朔 +##朕 +##朗 +##望 +##朝 +##期 +##朦 +##朧 +##木 +##未 +##末 +##本 +##札 +##朮 +##术 +##朱 +##朴 +##朵 +##机 +##朽 +##杀 +##杂 +##权 +##杆 +##杈 +##杉 +##李 +##杏 +##材 +##村 +##杓 +##杖 +##杜 +##杞 +##束 +##杠 +##条 +##来 +##杨 +##杭 +##杯 +##杰 +##東 +##杳 +##杵 +##杷 +##杼 +##松 +##板 +##极 +##构 +##枇 +##枉 +##枋 +##析 +##枕 +##林 +##枚 +##果 +##枝 +##枢 +##枣 +##枪 +##枫 +##枭 +##枯 +##枰 +##枱 +##枳 +##架 +##枷 +##枸 +##柄 +##柏 +##某 +##柑 +##柒 +##染 +##柔 +##柘 +##柚 +##柜 +##柞 +##柠 +##柢 +##查 +##柩 +##柬 +##柯 +##柱 +##柳 +##柴 +##柵 +##査 +##柿 +##栀 +##栃 +##栄 +##栅 +##标 +##栈 +##栉 +##栋 +##栎 +##栏 +##树 +##栓 +##栖 +##栗 +##校 +##栩 +##株 +##样 +##核 +##根 +##格 +##栽 +##栾 +##桀 +##桁 +##桂 +##桃 +##桅 +##框 +##案 +##桉 +##桌 +##桎 +##桐 +##桑 +##桓 +##桔 +##桜 +##桠 +##桡 +##桢 +##档 +##桥 +##桦 +##桧 +##桨 +##桩 +##桶 +##桿 +##梁 +##梅 +##梆 +##梏 +##梓 +##梗 +##條 +##梟 +##梢 +##梦 +##梧 +##梨 +##梭 +##梯 +##械 +##梳 +##梵 +##梶 +##检 +##棂 +##棄 +##棉 +##棋 +##棍 +##棒 +##棕 +##棗 +##棘 +##棚 +##棟 +##棠 +##棣 +##棧 +##森 +##棱 +##棲 +##棵 +##棹 +##棺 +##椁 +##椅 +##椋 +##植 +##椎 +##椒 +##検 +##椪 +##椭 +##椰 +##椹 +##椽 +##椿 +##楂 +##楊 +##楓 +##楔 +##楚 +##楝 +##楞 +##楠 +##楣 +##楨 +##楫 +##業 +##楮 +##極 +##楷 +##楸 +##楹 +##楼 +##楽 +##概 +##榄 +##榆 +##榈 +##榉 +##榔 +##榕 +##榖 +##榛 +##榜 +##榨 +##榫 +##榭 +##榮 +##榱 +##榴 +##榷 +##榻 +##槁 +##槃 +##構 +##槌 +##槍 +##槎 +##槐 +##槓 +##様 +##槛 +##槟 +##槤 +##槭 +##槲 +##槳 +##槻 +##槽 +##槿 +##樁 +##樂 +##樊 +##樑 +##樓 +##標 +##樞 +##樟 +##模 +##樣 +##権 +##横 +##樫 +##樯 +##樱 +##樵 +##樸 +##樹 +##樺 +##樽 +##樾 +##橄 +##橇 +##橋 +##橐 +##橘 +##橙 +##機 +##橡 +##橢 +##橫 +##橱 +##橹 +##橼 +##檀 +##檄 +##檎 +##檐 +##檔 +##檗 +##檜 +##檢 +##檬 +##檯 +##檳 +##檸 +##檻 +##櫃 +##櫚 +##櫛 +##櫥 +##櫸 +##櫻 +##欄 +##權 +##欒 +##欖 +##欠 +##次 +##欢 +##欣 +##欧 +##欲 +##欸 +##欺 +##欽 +##款 +##歆 +##歇 +##歉 +##歌 +##歎 +##歐 +##歓 +##歙 +##歛 +##歡 +##止 +##正 +##此 +##步 +##武 +##歧 +##歩 +##歪 +##歯 +##歲 +##歳 +##歴 +##歷 +##歸 +##歹 +##死 +##歼 +##殁 +##殃 +##殆 +##殇 +##殉 +##殊 +##残 +##殒 +##殓 +##殖 +##殘 +##殞 +##殡 +##殤 +##殭 +##殯 +##殲 +##殴 +##段 +##殷 +##殺 +##殼 +##殿 +##毀 +##毁 +##毂 +##毅 +##毆 +##毋 +##母 +##毎 +##每 +##毒 +##毓 +##比 +##毕 +##毗 +##毘 +##毙 +##毛 +##毡 +##毫 +##毯 +##毽 +##氈 +##氏 +##氐 +##民 +##氓 +##气 +##氖 +##気 +##氙 +##氛 +##氟 +##氡 +##氢 +##氣 +##氤 +##氦 +##氧 +##氨 +##氪 +##氫 +##氮 +##氯 +##氰 +##氲 +##水 +##氷 +##永 +##氹 +##氾 +##汀 +##汁 +##求 +##汆 +##汇 +##汉 +##汎 +##汐 +##汕 +##汗 +##汙 +##汛 +##汝 +##汞 +##江 +##池 +##污 +##汤 +##汨 +##汩 +##汪 +##汰 +##汲 +##汴 +##汶 +##汹 +##決 +##汽 +##汾 +##沁 +##沂 +##沃 +##沅 +##沈 +##沉 +##沌 +##沏 +##沐 +##沒 +##沓 +##沖 +##沙 +##沛 +##沟 +##没 +##沢 +##沣 +##沥 +##沦 +##沧 +##沪 +##沫 +##沭 +##沮 +##沱 +##河 +##沸 +##油 +##治 +##沼 +##沽 +##沾 +##沿 +##況 +##泄 +##泉 +##泊 +##泌 +##泓 +##法 +##泗 +##泛 +##泞 +##泠 +##泡 +##波 +##泣 +##泥 +##注 +##泪 +##泫 +##泮 +##泯 +##泰 +##泱 +##泳 +##泵 +##泷 +##泸 +##泻 +##泼 +##泽 +##泾 +##洁 +##洄 +##洋 +##洒 +##洗 +##洙 +##洛 +##洞 +##津 +##洩 +##洪 +##洮 +##洱 +##洲 +##洵 +##洶 +##洸 +##洹 +##活 +##洼 +##洽 +##派 +##流 +##浃 +##浄 +##浅 +##浆 +##浇 +##浊 +##测 +##济 +##浏 +##浑 +##浒 +##浓 +##浔 +##浙 +##浚 +##浜 +##浣 +##浦 +##浩 +##浪 +##浬 +##浮 +##浯 +##浴 +##海 +##浸 +##涂 +##涅 +##涇 +##消 +##涉 +##涌 +##涎 +##涓 +##涔 +##涕 +##涙 +##涛 +##涝 +##涞 +##涟 +##涠 +##涡 +##涣 +##涤 +##润 +##涧 +##涨 +##涩 +##涪 +##涮 +##涯 +##液 +##涵 +##涸 +##涼 +##涿 +##淀 +##淄 +##淅 +##淆 +##淇 +##淋 +##淌 +##淑 +##淒 +##淖 +##淘 +##淙 +##淚 +##淞 +##淡 +##淤 +##淦 +##淨 +##淩 +##淪 +##淫 +##淬 +##淮 +##深 +##淳 +##淵 +##混 +##淹 +##淺 +##添 +##淼 +##清 +##済 +##渉 +##渊 +##渋 +##渍 +##渎 +##渐 +##渔 +##渗 +##渙 +##渚 +##減 +##渝 +##渠 +##渡 +##渣 +##渤 +##渥 +##渦 +##温 +##測 +##渭 +##港 +##渲 +##渴 +##游 +##渺 +##渾 +##湃 +##湄 +##湊 +##湍 +##湖 +##湘 +##湛 +##湟 +##湧 +##湫 +##湮 +##湯 +##湳 +##湾 +##湿 +##満 +##溃 +##溅 +##溉 +##溏 +##源 +##準 +##溜 +##溝 +##溟 +##溢 +##溥 +##溧 +##溪 +##溫 +##溯 +##溱 +##溴 +##溶 +##溺 +##溼 +##滁 +##滂 +##滄 +##滅 +##滇 +##滋 +##滌 +##滑 +##滓 +##滔 +##滕 +##滙 +##滚 +##滝 +##滞 +##滟 +##满 +##滢 +##滤 +##滥 +##滦 +##滨 +##滩 +##滬 +##滯 +##滲 +##滴 +##滷 +##滸 +##滾 +##滿 +##漁 +##漂 +##漆 +##漉 +##漏 +##漓 +##演 +##漕 +##漠 +##漢 +##漣 +##漩 +##漪 +##漫 +##漬 +##漯 +##漱 +##漲 +##漳 +##漸 +##漾 +##漿 +##潆 +##潇 +##潋 +##潍 +##潑 +##潔 +##潘 +##潛 +##潜 +##潞 +##潟 +##潢 +##潤 +##潦 +##潧 +##潭 +##潮 +##潰 +##潴 +##潸 +##潺 +##潼 +##澀 +##澄 +##澆 +##澈 +##澍 +##澎 +##澗 +##澜 +##澡 +##澤 +##澧 +##澱 +##澳 +##澹 +##激 +##濁 +##濂 +##濃 +##濑 +##濒 +##濕 +##濘 +##濛 +##濟 +##濠 +##濡 +##濤 +##濫 +##濬 +##濮 +##濯 +##濱 +##濺 +##濾 +##瀅 +##瀆 +##瀉 +##瀋 +##瀏 +##瀑 +##瀕 +##瀘 +##瀚 +##瀛 +##瀝 +##瀞 +##瀟 +##瀧 +##瀨 +##瀬 +##瀰 +##瀾 +##灌 +##灏 +##灑 +##灘 +##灝 +##灞 +##灣 +##火 +##灬 +##灭 +##灯 +##灰 +##灵 +##灶 +##灸 +##灼 +##災 +##灾 +##灿 +##炀 +##炁 +##炅 +##炉 +##炊 +##炎 +##炒 +##炔 +##炕 +##炖 +##炙 +##炜 +##炫 +##炬 +##炭 +##炮 +##炯 +##炳 +##炷 +##炸 +##点 +##為 +##炼 +##炽 +##烁 +##烂 +##烃 +##烈 +##烊 +##烏 +##烘 +##烙 +##烛 +##烟 +##烤 +##烦 +##烧 +##烨 +##烩 +##烫 +##烬 +##热 +##烯 +##烷 +##烹 +##烽 +##焉 +##焊 +##焕 +##焖 +##焗 +##焘 +##焙 +##焚 +##焜 +##無 +##焦 +##焯 +##焰 +##焱 +##然 +##焼 +##煅 +##煉 +##煊 +##煌 +##煎 +##煒 +##煖 +##煙 +##煜 +##煞 +##煤 +##煥 +##煦 +##照 +##煨 +##煩 +##煮 +##煲 +##煸 +##煽 +##熄 +##熊 +##熏 +##熒 +##熔 +##熙 +##熟 +##熠 +##熨 +##熬 +##熱 +##熵 +##熹 +##熾 +##燁 +##燃 +##燄 +##燈 +##燉 +##燊 +##燎 +##燒 +##燔 +##燕 +##燙 +##燜 +##營 +##燥 +##燦 +##燧 +##燭 +##燮 +##燴 +##燻 +##燼 +##燿 +##爆 +##爍 +##爐 +##爛 +##爪 +##爬 +##爭 +##爰 +##爱 +##爲 +##爵 +##父 +##爷 +##爸 +##爹 +##爺 +##爻 +##爽 +##爾 +##牆 +##片 +##版 +##牌 +##牍 +##牒 +##牙 +##牛 +##牝 +##牟 +##牠 +##牡 +##牢 +##牦 +##牧 +##物 +##牯 +##牲 +##牴 +##牵 +##特 +##牺 +##牽 +##犀 +##犁 +##犄 +##犊 +##犍 +##犒 +##犢 +##犧 +##犬 +##犯 +##状 +##犷 +##犸 +##犹 +##狀 +##狂 +##狄 +##狈 +##狎 +##狐 +##狒 +##狗 +##狙 +##狞 +##狠 +##狡 +##狩 +##独 +##狭 +##狮 +##狰 +##狱 +##狸 +##狹 +##狼 +##狽 +##猎 +##猕 +##猖 +##猗 +##猙 +##猛 +##猜 +##猝 +##猥 +##猩 +##猪 +##猫 +##猬 +##献 +##猴 +##猶 +##猷 +##猾 +##猿 +##獄 +##獅 +##獎 +##獐 +##獒 +##獗 +##獠 +##獣 +##獨 +##獭 +##獰 +##獲 +##獵 +##獷 +##獸 +##獺 +##獻 +##獼 +##獾 +##玄 +##率 +##玉 +##王 +##玑 +##玖 +##玛 +##玟 +##玠 +##玥 +##玩 +##玫 +##玮 +##环 +##现 +##玲 +##玳 +##玷 +##玺 +##玻 +##珀 +##珂 +##珅 +##珈 +##珉 +##珊 +##珍 +##珏 +##珐 +##珑 +##珙 +##珞 +##珠 +##珣 +##珥 +##珩 +##珪 +##班 +##珮 +##珲 +##珺 +##現 +##球 +##琅 +##理 +##琇 +##琉 +##琊 +##琍 +##琏 +##琐 +##琛 +##琢 +##琥 +##琦 +##琨 +##琪 +##琬 +##琮 +##琰 +##琲 +##琳 +##琴 +##琵 +##琶 +##琺 +##琼 +##瑀 +##瑁 +##瑄 +##瑋 +##瑕 +##瑗 +##瑙 +##瑚 +##瑛 +##瑜 +##瑞 +##瑟 +##瑠 +##瑣 +##瑤 +##瑩 +##瑪 +##瑯 +##瑰 +##瑶 +##瑾 +##璀 +##璁 +##璃 +##璇 +##璉 +##璋 +##璎 +##璐 +##璜 +##璞 +##璟 +##璧 +##璨 +##環 +##璽 +##璿 +##瓊 +##瓏 +##瓒 +##瓜 +##瓢 +##瓣 +##瓤 +##瓦 +##瓮 +##瓯 +##瓴 +##瓶 +##瓷 +##甄 +##甌 +##甕 +##甘 +##甙 +##甚 +##甜 +##生 +##產 +##産 +##甥 +##甦 +##用 +##甩 +##甫 +##甬 +##甭 +##甯 +##田 +##由 +##甲 +##申 +##电 +##男 +##甸 +##町 +##画 +##甾 +##畀 +##畅 +##界 +##畏 +##畑 +##畔 +##留 +##畜 +##畝 +##畢 +##略 +##畦 +##番 +##畫 +##異 +##畲 +##畳 +##畴 +##當 +##畸 +##畹 +##畿 +##疆 +##疇 +##疊 +##疏 +##疑 +##疔 +##疖 +##疗 +##疙 +##疚 +##疝 +##疟 +##疡 +##疣 +##疤 +##疥 +##疫 +##疮 +##疯 +##疱 +##疲 +##疳 +##疵 +##疸 +##疹 +##疼 +##疽 +##疾 +##痂 +##病 +##症 +##痈 +##痉 +##痊 +##痍 +##痒 +##痔 +##痕 +##痘 +##痙 +##痛 +##痞 +##痠 +##痢 +##痣 +##痤 +##痧 +##痨 +##痪 +##痫 +##痰 +##痱 +##痴 +##痹 +##痺 +##痼 +##痿 +##瘀 +##瘁 +##瘋 +##瘍 +##瘓 +##瘘 +##瘙 +##瘟 +##瘠 +##瘡 +##瘢 +##瘤 +##瘦 +##瘧 +##瘩 +##瘪 +##瘫 +##瘴 +##瘸 +##瘾 +##療 +##癇 +##癌 +##癒 +##癖 +##癜 +##癞 +##癡 +##癢 +##癣 +##癥 +##癫 +##癬 +##癮 +##癱 +##癲 +##癸 +##発 +##登 +##發 +##白 +##百 +##皂 +##的 +##皆 +##皇 +##皈 +##皋 +##皎 +##皑 +##皓 +##皖 +##皙 +##皚 +##皮 +##皰 +##皱 +##皴 +##皺 +##皿 +##盂 +##盃 +##盅 +##盆 +##盈 +##益 +##盎 +##盏 +##盐 +##监 +##盒 +##盔 +##盖 +##盗 +##盘 +##盛 +##盜 +##盞 +##盟 +##盡 +##監 +##盤 +##盥 +##盧 +##盪 +##目 +##盯 +##盱 +##盲 +##直 +##相 +##盹 +##盼 +##盾 +##省 +##眈 +##眉 +##看 +##県 +##眙 +##眞 +##真 +##眠 +##眦 +##眨 +##眩 +##眯 +##眶 +##眷 +##眸 +##眺 +##眼 +##眾 +##着 +##睁 +##睇 +##睏 +##睐 +##睑 +##睛 +##睜 +##睞 +##睡 +##睢 +##督 +##睥 +##睦 +##睨 +##睪 +##睫 +##睬 +##睹 +##睽 +##睾 +##睿 +##瞄 +##瞅 +##瞇 +##瞋 +##瞌 +##瞎 +##瞑 +##瞒 +##瞓 +##瞞 +##瞟 +##瞠 +##瞥 +##瞧 +##瞩 +##瞪 +##瞬 +##瞭 +##瞰 +##瞳 +##瞻 +##瞼 +##瞿 +##矇 +##矍 +##矗 +##矚 +##矛 +##矜 +##矢 +##矣 +##知 +##矩 +##矫 +##短 +##矮 +##矯 +##石 +##矶 +##矽 +##矾 +##矿 +##码 +##砂 +##砌 +##砍 +##砒 +##研 +##砖 +##砗 +##砚 +##砝 +##砣 +##砥 +##砧 +##砭 +##砰 +##砲 +##破 +##砷 +##砸 +##砺 +##砼 +##砾 +##础 +##硅 +##硐 +##硒 +##硕 +##硝 +##硫 +##硬 +##确 +##硯 +##硼 +##碁 +##碇 +##碉 +##碌 +##碍 +##碎 +##碑 +##碓 +##碗 +##碘 +##碚 +##碛 +##碟 +##碣 +##碧 +##碩 +##碰 +##碱 +##碳 +##碴 +##確 +##碼 +##碾 +##磁 +##磅 +##磊 +##磋 +##磐 +##磕 +##磚 +##磡 +##磨 +##磬 +##磯 +##磲 +##磷 +##磺 +##礁 +##礎 +##礙 +##礡 +##礦 +##礪 +##礫 +##礴 +##示 +##礼 +##社 +##祀 +##祁 +##祂 +##祇 +##祈 +##祉 +##祎 +##祐 +##祕 +##祖 +##祗 +##祚 +##祛 +##祜 +##祝 +##神 +##祟 +##祠 +##祢 +##祥 +##票 +##祭 +##祯 +##祷 +##祸 +##祺 +##祿 +##禀 +##禁 +##禄 +##禅 +##禍 +##禎 +##福 +##禛 +##禦 +##禧 +##禪 +##禮 +##禱 +##禹 +##禺 +##离 +##禽 +##禾 +##禿 +##秀 +##私 +##秃 +##秆 +##秉 +##秋 +##种 +##科 +##秒 +##秘 +##租 +##秣 +##秤 +##秦 +##秧 +##秩 +##秭 +##积 +##称 +##秸 +##移 +##秽 +##稀 +##稅 +##程 +##稍 +##税 +##稔 +##稗 +##稚 +##稜 +##稞 +##稟 +##稠 +##稣 +##種 +##稱 +##稲 +##稳 +##稷 +##稹 +##稻 +##稼 +##稽 +##稿 +##穀 +##穂 +##穆 +##穌 +##積 +##穎 +##穗 +##穢 +##穩 +##穫 +##穴 +##究 +##穷 +##穹 +##空 +##穿 +##突 +##窃 +##窄 +##窈 +##窍 +##窑 +##窒 +##窓 +##窕 +##窖 +##窗 +##窘 +##窜 +##窝 +##窟 +##窠 +##窥 +##窦 +##窨 +##窩 +##窪 +##窮 +##窯 +##窺 +##窿 +##竄 +##竅 +##竇 +##竊 +##立 +##竖 +##站 +##竜 +##竞 +##竟 +##章 +##竣 +##童 +##竭 +##端 +##競 +##竹 +##竺 +##竽 +##竿 +##笃 +##笆 +##笈 +##笋 +##笏 +##笑 +##笔 +##笙 +##笛 +##笞 +##笠 +##符 +##笨 +##第 +##笹 +##笺 +##笼 +##筆 +##等 +##筊 +##筋 +##筍 +##筏 +##筐 +##筑 +##筒 +##答 +##策 +##筛 +##筝 +##筠 +##筱 +##筲 +##筵 +##筷 +##筹 +##签 +##简 +##箇 +##箋 +##箍 +##箏 +##箐 +##箔 +##箕 +##算 +##箝 +##管 +##箩 +##箫 +##箭 +##箱 +##箴 +##箸 +##節 +##篁 +##範 +##篆 +##篇 +##築 +##篑 +##篓 +##篙 +##篝 +##篠 +##篡 +##篤 +##篩 +##篪 +##篮 +##篱 +##篷 +##簇 +##簌 +##簍 +##簡 +##簦 +##簧 +##簪 +##簫 +##簷 +##簸 +##簽 +##簾 +##簿 +##籁 +##籃 +##籌 +##籍 +##籐 +##籟 +##籠 +##籤 +##籬 +##籮 +##籲 +##米 +##类 +##籼 +##籽 +##粄 +##粉 +##粑 +##粒 +##粕 +##粗 +##粘 +##粟 +##粤 +##粥 +##粧 +##粪 +##粮 +##粱 +##粲 +##粳 +##粵 +##粹 +##粼 +##粽 +##精 +##粿 +##糅 +##糊 +##糍 +##糕 +##糖 +##糗 +##糙 +##糜 +##糞 +##糟 +##糠 +##糧 +##糬 +##糯 +##糰 +##糸 +##系 +##糾 +##紀 +##紂 +##約 +##紅 +##紉 +##紊 +##紋 +##納 +##紐 +##紓 +##純 +##紗 +##紘 +##紙 +##級 +##紛 +##紜 +##素 +##紡 +##索 +##紧 +##紫 +##紮 +##累 +##細 +##紳 +##紹 +##紺 +##終 +##絃 +##組 +##絆 +##経 +##結 +##絕 +##絞 +##絡 +##絢 +##給 +##絨 +##絮 +##統 +##絲 +##絳 +##絵 +##絶 +##絹 +##綁 +##綏 +##綑 +##經 +##継 +##続 +##綜 +##綠 +##綢 +##綦 +##綫 +##綬 +##維 +##綱 +##網 +##綴 +##綵 +##綸 +##綺 +##綻 +##綽 +##綾 +##綿 +##緊 +##緋 +##総 +##緑 +##緒 +##緘 +##線 +##緝 +##緞 +##締 +##緣 +##編 +##緩 +##緬 +##緯 +##練 +##緹 +##緻 +##縁 +##縄 +##縈 +##縛 +##縝 +##縣 +##縫 +##縮 +##縱 +##縴 +##縷 +##總 +##績 +##繁 +##繃 +##繆 +##繇 +##繋 +##織 +##繕 +##繚 +##繞 +##繡 +##繩 +##繪 +##繫 +##繭 +##繳 +##繹 +##繼 +##繽 +##纂 +##續 +##纍 +##纏 +##纓 +##纔 +##纖 +##纜 +##纠 +##红 +##纣 +##纤 +##约 +##级 +##纨 +##纪 +##纫 +##纬 +##纭 +##纯 +##纰 +##纱 +##纲 +##纳 +##纵 +##纶 +##纷 +##纸 +##纹 +##纺 +##纽 +##纾 +##线 +##绀 +##练 +##组 +##绅 +##细 +##织 +##终 +##绊 +##绍 +##绎 +##经 +##绑 +##绒 +##结 +##绔 +##绕 +##绘 +##给 +##绚 +##绛 +##络 +##绝 +##绞 +##统 +##绡 +##绢 +##绣 +##绥 +##绦 +##继 +##绩 +##绪 +##绫 +##续 +##绮 +##绯 +##绰 +##绳 +##维 +##绵 +##绶 +##绷 +##绸 +##绻 +##综 +##绽 +##绾 +##绿 +##缀 +##缄 +##缅 +##缆 +##缇 +##缈 +##缉 +##缎 +##缓 +##缔 +##缕 +##编 +##缘 +##缙 +##缚 +##缜 +##缝 +##缠 +##缢 +##缤 +##缥 +##缨 +##缩 +##缪 +##缭 +##缮 +##缰 +##缱 +##缴 +##缸 +##缺 +##缽 +##罂 +##罄 +##罌 +##罐 +##网 +##罔 +##罕 +##罗 +##罚 +##罡 +##罢 +##罩 +##罪 +##置 +##罰 +##署 +##罵 +##罷 +##罹 +##羁 +##羅 +##羈 +##羊 +##羌 +##美 +##羔 +##羚 +##羞 +##羟 +##羡 +##羣 +##群 +##羥 +##羧 +##羨 +##義 +##羯 +##羲 +##羸 +##羹 +##羽 +##羿 +##翁 +##翅 +##翊 +##翌 +##翎 +##習 +##翔 +##翘 +##翟 +##翠 +##翡 +##翦 +##翩 +##翰 +##翱 +##翳 +##翹 +##翻 +##翼 +##耀 +##老 +##考 +##耄 +##者 +##耆 +##耋 +##而 +##耍 +##耐 +##耒 +##耕 +##耗 +##耘 +##耙 +##耦 +##耨 +##耳 +##耶 +##耷 +##耸 +##耻 +##耽 +##耿 +##聂 +##聆 +##聊 +##聋 +##职 +##聒 +##联 +##聖 +##聘 +##聚 +##聞 +##聪 +##聯 +##聰 +##聲 +##聳 +##聴 +##聶 +##職 +##聽 +##聾 +##聿 +##肃 +##肄 +##肅 +##肆 +##肇 +##肉 +##肋 +##肌 +##肏 +##肓 +##肖 +##肘 +##肚 +##肛 +##肝 +##肠 +##股 +##肢 +##肤 +##肥 +##肩 +##肪 +##肮 +##肯 +##肱 +##育 +##肴 +##肺 +##肽 +##肾 +##肿 +##胀 +##胁 +##胃 +##胄 +##胆 +##背 +##胍 +##胎 +##胖 +##胚 +##胛 +##胜 +##胝 +##胞 +##胡 +##胤 +##胥 +##胧 +##胫 +##胭 +##胯 +##胰 +##胱 +##胳 +##胴 +##胶 +##胸 +##胺 +##能 +##脂 +##脅 +##脆 +##脇 +##脈 +##脉 +##脊 +##脍 +##脏 +##脐 +##脑 +##脓 +##脖 +##脘 +##脚 +##脛 +##脣 +##脩 +##脫 +##脯 +##脱 +##脲 +##脳 +##脸 +##脹 +##脾 +##腆 +##腈 +##腊 +##腋 +##腌 +##腎 +##腐 +##腑 +##腓 +##腔 +##腕 +##腥 +##腦 +##腩 +##腫 +##腭 +##腮 +##腰 +##腱 +##腳 +##腴 +##腸 +##腹 +##腺 +##腻 +##腼 +##腾 +##腿 +##膀 +##膈 +##膊 +##膏 +##膑 +##膘 +##膚 +##膛 +##膜 +##膝 +##膠 +##膦 +##膨 +##膩 +##膳 +##膺 +##膻 +##膽 +##膾 +##膿 +##臀 +##臂 +##臃 +##臆 +##臉 +##臊 +##臍 +##臓 +##臘 +##臟 +##臣 +##臥 +##臧 +##臨 +##自 +##臬 +##臭 +##至 +##致 +##臺 +##臻 +##臼 +##臾 +##舀 +##舂 +##舅 +##舆 +##與 +##興 +##舉 +##舊 +##舌 +##舍 +##舎 +##舐 +##舒 +##舔 +##舖 +##舗 +##舛 +##舜 +##舞 +##舟 +##航 +##舫 +##般 +##舰 +##舱 +##舵 +##舶 +##舷 +##舸 +##船 +##舺 +##舾 +##艇 +##艋 +##艘 +##艙 +##艦 +##艮 +##良 +##艰 +##艱 +##色 +##艳 +##艷 +##艹 +##艺 +##艾 +##节 +##芃 +##芈 +##芊 +##芋 +##芍 +##芎 +##芒 +##芙 +##芜 +##芝 +##芡 +##芥 +##芦 +##芩 +##芪 +##芫 +##芬 +##芭 +##芮 +##芯 +##花 +##芳 +##芷 +##芸 +##芹 +##芻 +##芽 +##芾 +##苁 +##苄 +##苇 +##苋 +##苍 +##苏 +##苑 +##苒 +##苓 +##苔 +##苕 +##苗 +##苛 +##苜 +##苞 +##苟 +##苡 +##苣 +##若 +##苦 +##苫 +##苯 +##英 +##苷 +##苹 +##苻 +##茁 +##茂 +##范 +##茄 +##茅 +##茉 +##茎 +##茏 +##茗 +##茜 +##茧 +##茨 +##茫 +##茬 +##茭 +##茯 +##茱 +##茲 +##茴 +##茵 +##茶 +##茸 +##茹 +##茼 +##荀 +##荃 +##荆 +##草 +##荊 +##荏 +##荐 +##荒 +##荔 +##荖 +##荘 +##荚 +##荞 +##荟 +##荠 +##荡 +##荣 +##荤 +##荥 +##荧 +##荨 +##荪 +##荫 +##药 +##荳 +##荷 +##荸 +##荻 +##荼 +##荽 +##莅 +##莆 +##莉 +##莊 +##莎 +##莒 +##莓 +##莖 +##莘 +##莞 +##莠 +##莢 +##莧 +##莪 +##莫 +##莱 +##莲 +##莴 +##获 +##莹 +##莺 +##莽 +##莿 +##菀 +##菁 +##菅 +##菇 +##菈 +##菊 +##菌 +##菏 +##菓 +##菖 +##菘 +##菜 +##菟 +##菠 +##菡 +##菩 +##華 +##菱 +##菲 +##菸 +##菽 +##萁 +##萃 +##萄 +##萊 +##萋 +##萌 +##萍 +##萎 +##萘 +##萝 +##萤 +##营 +##萦 +##萧 +##萨 +##萩 +##萬 +##萱 +##萵 +##萸 +##萼 +##落 +##葆 +##葉 +##著 +##葚 +##葛 +##葡 +##董 +##葦 +##葩 +##葫 +##葬 +##葭 +##葯 +##葱 +##葳 +##葵 +##葷 +##葺 +##蒂 +##蒋 +##蒐 +##蒔 +##蒙 +##蒜 +##蒞 +##蒟 +##蒡 +##蒨 +##蒲 +##蒸 +##蒹 +##蒻 +##蒼 +##蒿 +##蓁 +##蓄 +##蓆 +##蓉 +##蓋 +##蓑 +##蓓 +##蓖 +##蓝 +##蓟 +##蓦 +##蓬 +##蓮 +##蓼 +##蓿 +##蔑 +##蔓 +##蔔 +##蔗 +##蔘 +##蔚 +##蔡 +##蔣 +##蔥 +##蔫 +##蔬 +##蔭 +##蔵 +##蔷 +##蔺 +##蔻 +##蔼 +##蔽 +##蕁 +##蕃 +##蕈 +##蕉 +##蕊 +##蕎 +##蕙 +##蕤 +##蕨 +##蕩 +##蕪 +##蕭 +##蕲 +##蕴 +##蕻 +##蕾 +##薄 +##薅 +##薇 +##薈 +##薊 +##薏 +##薑 +##薔 +##薙 +##薛 +##薦 +##薨 +##薩 +##薪 +##薬 +##薯 +##薰 +##薹 +##藉 +##藍 +##藏 +##藐 +##藓 +##藕 +##藜 +##藝 +##藤 +##藥 +##藩 +##藹 +##藻 +##藿 +##蘆 +##蘇 +##蘊 +##蘋 +##蘑 +##蘚 +##蘭 +##蘸 +##蘼 +##蘿 +##虎 +##虏 +##虐 +##虑 +##虔 +##處 +##虚 +##虛 +##虜 +##虞 +##號 +##虢 +##虧 +##虫 +##虬 +##虱 +##虹 +##虻 +##虽 +##虾 +##蚀 +##蚁 +##蚂 +##蚊 +##蚌 +##蚓 +##蚕 +##蚜 +##蚝 +##蚣 +##蚤 +##蚩 +##蚪 +##蚯 +##蚱 +##蚵 +##蛀 +##蛆 +##蛇 +##蛊 +##蛋 +##蛎 +##蛐 +##蛔 +##蛙 +##蛛 +##蛟 +##蛤 +##蛭 +##蛮 +##蛰 +##蛳 +##蛹 +##蛻 +##蛾 +##蜀 +##蜂 +##蜃 +##蜆 +##蜇 +##蜈 +##蜊 +##蜍 +##蜒 +##蜓 +##蜕 +##蜗 +##蜘 +##蜚 +##蜜 +##蜡 +##蜢 +##蜥 +##蜱 +##蜴 +##蜷 +##蜻 +##蜿 +##蝇 +##蝈 +##蝉 +##蝌 +##蝎 +##蝕 +##蝗 +##蝙 +##蝟 +##蝠 +##蝦 +##蝨 +##蝴 +##蝶 +##蝸 +##蝼 +##螂 +##螃 +##融 +##螞 +##螢 +##螨 +##螯 +##螳 +##螺 +##蟀 +##蟄 +##蟆 +##蟋 +##蟎 +##蟑 +##蟒 +##蟠 +##蟬 +##蟲 +##蟹 +##蟻 +##蟾 +##蠅 +##蠍 +##蠔 +##蠕 +##蠛 +##蠟 +##蠡 +##蠢 +##蠣 +##蠱 +##蠶 +##蠹 +##蠻 +##血 +##衄 +##衅 +##衆 +##行 +##衍 +##術 +##衔 +##街 +##衙 +##衛 +##衝 +##衞 +##衡 +##衢 +##衣 +##补 +##表 +##衩 +##衫 +##衬 +##衮 +##衰 +##衲 +##衷 +##衹 +##衾 +##衿 +##袁 +##袂 +##袄 +##袅 +##袈 +##袋 +##袍 +##袒 +##袖 +##袜 +##袞 +##袤 +##袪 +##被 +##袭 +##袱 +##裁 +##裂 +##装 +##裆 +##裊 +##裏 +##裔 +##裕 +##裘 +##裙 +##補 +##裝 +##裟 +##裡 +##裤 +##裨 +##裱 +##裳 +##裴 +##裸 +##裹 +##製 +##裾 +##褂 +##複 +##褐 +##褒 +##褓 +##褔 +##褚 +##褥 +##褪 +##褫 +##褲 +##褶 +##褻 +##襁 +##襄 +##襟 +##襠 +##襪 +##襬 +##襯 +##襲 +##西 +##要 +##覃 +##覆 +##覇 +##見 +##規 +##覓 +##視 +##覚 +##覦 +##覧 +##親 +##覬 +##観 +##覷 +##覺 +##覽 +##觀 +##见 +##观 +##规 +##觅 +##视 +##览 +##觉 +##觊 +##觎 +##觐 +##觑 +##角 +##觞 +##解 +##觥 +##触 +##觸 +##言 +##訂 +##計 +##訊 +##討 +##訓 +##訕 +##訖 +##託 +##記 +##訛 +##訝 +##訟 +##訣 +##訥 +##訪 +##設 +##許 +##訳 +##訴 +##訶 +##診 +##註 +##証 +##詆 +##詐 +##詔 +##評 +##詛 +##詞 +##詠 +##詡 +##詢 +##詣 +##試 +##詩 +##詫 +##詬 +##詭 +##詮 +##詰 +##話 +##該 +##詳 +##詹 +##詼 +##誅 +##誇 +##誉 +##誌 +##認 +##誓 +##誕 +##誘 +##語 +##誠 +##誡 +##誣 +##誤 +##誥 +##誦 +##誨 +##說 +##説 +##読 +##誰 +##課 +##誹 +##誼 +##調 +##諄 +##談 +##請 +##諏 +##諒 +##論 +##諗 +##諜 +##諡 +##諦 +##諧 +##諫 +##諭 +##諮 +##諱 +##諳 +##諷 +##諸 +##諺 +##諾 +##謀 +##謁 +##謂 +##謄 +##謊 +##謎 +##謐 +##謔 +##謗 +##謙 +##講 +##謝 +##謠 +##謨 +##謬 +##謹 +##謾 +##譁 +##證 +##譎 +##譏 +##識 +##譙 +##譚 +##譜 +##警 +##譬 +##譯 +##議 +##譲 +##譴 +##護 +##譽 +##讀 +##變 +##讓 +##讚 +##讞 +##计 +##订 +##认 +##讥 +##讧 +##讨 +##让 +##讪 +##讫 +##训 +##议 +##讯 +##记 +##讲 +##讳 +##讴 +##讶 +##讷 +##许 +##讹 +##论 +##讼 +##讽 +##设 +##访 +##诀 +##证 +##诃 +##评 +##诅 +##识 +##诈 +##诉 +##诊 +##诋 +##词 +##诏 +##译 +##试 +##诗 +##诘 +##诙 +##诚 +##诛 +##话 +##诞 +##诟 +##诠 +##诡 +##询 +##诣 +##诤 +##该 +##详 +##诧 +##诩 +##诫 +##诬 +##语 +##误 +##诰 +##诱 +##诲 +##说 +##诵 +##诶 +##请 +##诸 +##诺 +##读 +##诽 +##课 +##诿 +##谀 +##谁 +##调 +##谄 +##谅 +##谆 +##谈 +##谊 +##谋 +##谌 +##谍 +##谎 +##谏 +##谐 +##谑 +##谒 +##谓 +##谔 +##谕 +##谗 +##谘 +##谙 +##谚 +##谛 +##谜 +##谟 +##谢 +##谣 +##谤 +##谥 +##谦 +##谧 +##谨 +##谩 +##谪 +##谬 +##谭 +##谯 +##谱 +##谲 +##谴 +##谶 +##谷 +##豁 +##豆 +##豇 +##豈 +##豉 +##豊 +##豌 +##豎 +##豐 +##豔 +##豚 +##象 +##豢 +##豪 +##豫 +##豬 +##豹 +##豺 +##貂 +##貅 +##貌 +##貓 +##貔 +##貘 +##貝 +##貞 +##負 +##財 +##貢 +##貧 +##貨 +##販 +##貪 +##貫 +##責 +##貯 +##貰 +##貳 +##貴 +##貶 +##買 +##貸 +##費 +##貼 +##貽 +##貿 +##賀 +##賁 +##賂 +##賃 +##賄 +##資 +##賈 +##賊 +##賑 +##賓 +##賜 +##賞 +##賠 +##賡 +##賢 +##賣 +##賤 +##賦 +##質 +##賬 +##賭 +##賴 +##賺 +##購 +##賽 +##贅 +##贈 +##贊 +##贍 +##贏 +##贓 +##贖 +##贛 +##贝 +##贞 +##负 +##贡 +##财 +##责 +##贤 +##败 +##账 +##货 +##质 +##贩 +##贪 +##贫 +##贬 +##购 +##贮 +##贯 +##贰 +##贱 +##贲 +##贴 +##贵 +##贷 +##贸 +##费 +##贺 +##贻 +##贼 +##贾 +##贿 +##赁 +##赂 +##赃 +##资 +##赅 +##赈 +##赊 +##赋 +##赌 +##赎 +##赏 +##赐 +##赓 +##赔 +##赖 +##赘 +##赚 +##赛 +##赝 +##赞 +##赠 +##赡 +##赢 +##赣 +##赤 +##赦 +##赧 +##赫 +##赭 +##走 +##赳 +##赴 +##赵 +##赶 +##起 +##趁 +##超 +##越 +##趋 +##趕 +##趙 +##趟 +##趣 +##趨 +##足 +##趴 +##趵 +##趸 +##趺 +##趾 +##跃 +##跄 +##跆 +##跋 +##跌 +##跎 +##跑 +##跖 +##跚 +##跛 +##距 +##跟 +##跡 +##跤 +##跨 +##跩 +##跪 +##路 +##跳 +##践 +##跷 +##跹 +##跺 +##跻 +##踉 +##踊 +##踌 +##踏 +##踐 +##踝 +##踞 +##踟 +##踢 +##踩 +##踪 +##踮 +##踱 +##踴 +##踵 +##踹 +##蹂 +##蹄 +##蹇 +##蹈 +##蹉 +##蹊 +##蹋 +##蹑 +##蹒 +##蹙 +##蹟 +##蹣 +##蹤 +##蹦 +##蹩 +##蹬 +##蹭 +##蹲 +##蹴 +##蹶 +##蹺 +##蹼 +##蹿 +##躁 +##躇 +##躉 +##躊 +##躋 +##躍 +##躏 +##躪 +##身 +##躬 +##躯 +##躲 +##躺 +##軀 +##車 +##軋 +##軌 +##軍 +##軒 +##軟 +##転 +##軸 +##軼 +##軽 +##軾 +##較 +##載 +##輒 +##輓 +##輔 +##輕 +##輛 +##輝 +##輟 +##輩 +##輪 +##輯 +##輸 +##輻 +##輾 +##輿 +##轄 +##轅 +##轆 +##轉 +##轍 +##轎 +##轟 +##车 +##轧 +##轨 +##轩 +##转 +##轭 +##轮 +##软 +##轰 +##轲 +##轴 +##轶 +##轻 +##轼 +##载 +##轿 +##较 +##辄 +##辅 +##辆 +##辇 +##辈 +##辉 +##辊 +##辍 +##辐 +##辑 +##输 +##辕 +##辖 +##辗 +##辘 +##辙 +##辛 +##辜 +##辞 +##辟 +##辣 +##辦 +##辨 +##辩 +##辫 +##辭 +##辮 +##辯 +##辰 +##辱 +##農 +##边 +##辺 +##辻 +##込 +##辽 +##达 +##迁 +##迂 +##迄 +##迅 +##过 +##迈 +##迎 +##运 +##近 +##返 +##还 +##这 +##进 +##远 +##违 +##连 +##迟 +##迢 +##迤 +##迥 +##迦 +##迩 +##迪 +##迫 +##迭 +##述 +##迴 +##迷 +##迸 +##迹 +##迺 +##追 +##退 +##送 +##适 +##逃 +##逅 +##逆 +##选 +##逊 +##逍 +##透 +##逐 +##递 +##途 +##逕 +##逗 +##這 +##通 +##逛 +##逝 +##逞 +##速 +##造 +##逢 +##連 +##逮 +##週 +##進 +##逵 +##逶 +##逸 +##逻 +##逼 +##逾 +##遁 +##遂 +##遅 +##遇 +##遊 +##運 +##遍 +##過 +##遏 +##遐 +##遑 +##遒 +##道 +##達 +##違 +##遗 +##遙 +##遛 +##遜 +##遞 +##遠 +##遢 +##遣 +##遥 +##遨 +##適 +##遭 +##遮 +##遲 +##遴 +##遵 +##遶 +##遷 +##選 +##遺 +##遼 +##遽 +##避 +##邀 +##邁 +##邂 +##邃 +##還 +##邇 +##邈 +##邊 +##邋 +##邏 +##邑 +##邓 +##邕 +##邛 +##邝 +##邢 +##那 +##邦 +##邨 +##邪 +##邬 +##邮 +##邯 +##邰 +##邱 +##邳 +##邵 +##邸 +##邹 +##邺 +##邻 +##郁 +##郅 +##郊 +##郎 +##郑 +##郜 +##郝 +##郡 +##郢 +##郤 +##郦 +##郧 +##部 +##郫 +##郭 +##郴 +##郵 +##郷 +##郸 +##都 +##鄂 +##鄉 +##鄒 +##鄔 +##鄙 +##鄞 +##鄢 +##鄧 +##鄭 +##鄰 +##鄱 +##鄲 +##鄺 +##酉 +##酊 +##酋 +##酌 +##配 +##酐 +##酒 +##酗 +##酚 +##酝 +##酢 +##酣 +##酥 +##酩 +##酪 +##酬 +##酮 +##酯 +##酰 +##酱 +##酵 +##酶 +##酷 +##酸 +##酿 +##醃 +##醇 +##醉 +##醋 +##醍 +##醐 +##醒 +##醚 +##醛 +##醜 +##醞 +##醣 +##醪 +##醫 +##醬 +##醮 +##醯 +##醴 +##醺 +##釀 +##釁 +##采 +##釉 +##释 +##釋 +##里 +##重 +##野 +##量 +##釐 +##金 +##釗 +##釘 +##釜 +##針 +##釣 +##釦 +##釧 +##釵 +##鈀 +##鈉 +##鈍 +##鈎 +##鈔 +##鈕 +##鈞 +##鈣 +##鈦 +##鈪 +##鈴 +##鈺 +##鈾 +##鉀 +##鉄 +##鉅 +##鉉 +##鉑 +##鉗 +##鉚 +##鉛 +##鉤 +##鉴 +##鉻 +##銀 +##銃 +##銅 +##銑 +##銓 +##銖 +##銘 +##銜 +##銬 +##銭 +##銮 +##銳 +##銷 +##銹 +##鋁 +##鋅 +##鋒 +##鋤 +##鋪 +##鋰 +##鋸 +##鋼 +##錄 +##錐 +##錘 +##錚 +##錠 +##錢 +##錦 +##錨 +##錫 +##錮 +##錯 +##録 +##錳 +##錶 +##鍊 +##鍋 +##鍍 +##鍛 +##鍥 +##鍰 +##鍵 +##鍺 +##鍾 +##鎂 +##鎊 +##鎌 +##鎏 +##鎔 +##鎖 +##鎗 +##鎚 +##鎧 +##鎬 +##鎮 +##鎳 +##鏈 +##鏖 +##鏗 +##鏘 +##鏞 +##鏟 +##鏡 +##鏢 +##鏤 +##鏽 +##鐘 +##鐮 +##鐲 +##鐳 +##鐵 +##鐸 +##鐺 +##鑄 +##鑊 +##鑑 +##鑒 +##鑣 +##鑫 +##鑰 +##鑲 +##鑼 +##鑽 +##鑾 +##鑿 +##针 +##钉 +##钊 +##钎 +##钏 +##钒 +##钓 +##钗 +##钙 +##钛 +##钜 +##钝 +##钞 +##钟 +##钠 +##钡 +##钢 +##钣 +##钤 +##钥 +##钦 +##钧 +##钨 +##钩 +##钮 +##钯 +##钰 +##钱 +##钳 +##钴 +##钵 +##钺 +##钻 +##钼 +##钾 +##钿 +##铀 +##铁 +##铂 +##铃 +##铄 +##铅 +##铆 +##铉 +##铎 +##铐 +##铛 +##铜 +##铝 +##铠 +##铡 +##铢 +##铣 +##铤 +##铨 +##铩 +##铬 +##铭 +##铮 +##铰 +##铲 +##铵 +##银 +##铸 +##铺 +##链 +##铿 +##销 +##锁 +##锂 +##锄 +##锅 +##锆 +##锈 +##锉 +##锋 +##锌 +##锏 +##锐 +##锑 +##错 +##锚 +##锟 +##锡 +##锢 +##锣 +##锤 +##锥 +##锦 +##锭 +##键 +##锯 +##锰 +##锲 +##锵 +##锹 +##锺 +##锻 +##镀 +##镁 +##镂 +##镇 +##镉 +##镌 +##镍 +##镐 +##镑 +##镕 +##镖 +##镗 +##镛 +##镜 +##镣 +##镭 +##镯 +##镰 +##镳 +##镶 +##長 +##长 +##門 +##閃 +##閉 +##開 +##閎 +##閏 +##閑 +##閒 +##間 +##閔 +##閘 +##閡 +##関 +##閣 +##閥 +##閨 +##閩 +##閱 +##閲 +##閹 +##閻 +##閾 +##闆 +##闇 +##闊 +##闌 +##闍 +##闔 +##闕 +##闖 +##闘 +##關 +##闡 +##闢 +##门 +##闪 +##闫 +##闭 +##问 +##闯 +##闰 +##闲 +##间 +##闵 +##闷 +##闸 +##闹 +##闺 +##闻 +##闽 +##闾 +##阀 +##阁 +##阂 +##阅 +##阆 +##阇 +##阈 +##阉 +##阎 +##阐 +##阑 +##阔 +##阕 +##阖 +##阙 +##阚 +##阜 +##队 +##阡 +##阪 +##阮 +##阱 +##防 +##阳 +##阴 +##阵 +##阶 +##阻 +##阿 +##陀 +##陂 +##附 +##际 +##陆 +##陇 +##陈 +##陋 +##陌 +##降 +##限 +##陕 +##陛 +##陝 +##陞 +##陟 +##陡 +##院 +##陣 +##除 +##陨 +##险 +##陪 +##陰 +##陲 +##陳 +##陵 +##陶 +##陷 +##陸 +##険 +##陽 +##隅 +##隆 +##隈 +##隊 +##隋 +##隍 +##階 +##随 +##隐 +##隔 +##隕 +##隘 +##隙 +##際 +##障 +##隠 +##隣 +##隧 +##隨 +##險 +##隱 +##隴 +##隶 +##隸 +##隻 +##隼 +##隽 +##难 +##雀 +##雁 +##雄 +##雅 +##集 +##雇 +##雉 +##雋 +##雌 +##雍 +##雎 +##雏 +##雑 +##雒 +##雕 +##雖 +##雙 +##雛 +##雜 +##雞 +##離 +##難 +##雨 +##雪 +##雯 +##雰 +##雲 +##雳 +##零 +##雷 +##雹 +##電 +##雾 +##需 +##霁 +##霄 +##霆 +##震 +##霈 +##霉 +##霊 +##霍 +##霎 +##霏 +##霑 +##霓 +##霖 +##霜 +##霞 +##霧 +##霭 +##霰 +##露 +##霸 +##霹 +##霽 +##霾 +##靂 +##靄 +##靈 +##青 +##靓 +##靖 +##静 +##靚 +##靛 +##靜 +##非 +##靠 +##靡 +##面 +##靥 +##靦 +##革 +##靳 +##靴 +##靶 +##靼 +##鞅 +##鞋 +##鞍 +##鞏 +##鞑 +##鞘 +##鞠 +##鞣 +##鞦 +##鞭 +##韆 +##韋 +##韌 +##韓 +##韜 +##韦 +##韧 +##韩 +##韬 +##韭 +##音 +##韵 +##韶 +##韻 +##響 +##頁 +##頂 +##頃 +##項 +##順 +##須 +##頌 +##預 +##頑 +##頒 +##頓 +##頗 +##領 +##頜 +##頡 +##頤 +##頫 +##頭 +##頰 +##頷 +##頸 +##頹 +##頻 +##頼 +##顆 +##題 +##額 +##顎 +##顏 +##顔 +##願 +##顛 +##類 +##顧 +##顫 +##顯 +##顱 +##顴 +##页 +##顶 +##顷 +##项 +##顺 +##须 +##顼 +##顽 +##顾 +##顿 +##颁 +##颂 +##预 +##颅 +##领 +##颇 +##颈 +##颉 +##颊 +##颌 +##颍 +##颐 +##频 +##颓 +##颔 +##颖 +##颗 +##题 +##颚 +##颛 +##颜 +##额 +##颞 +##颠 +##颡 +##颢 +##颤 +##颦 +##颧 +##風 +##颯 +##颱 +##颳 +##颶 +##颼 +##飄 +##飆 +##风 +##飒 +##飓 +##飕 +##飘 +##飙 +##飚 +##飛 +##飞 +##食 +##飢 +##飨 +##飩 +##飪 +##飯 +##飲 +##飼 +##飽 +##飾 +##餃 +##餅 +##餉 +##養 +##餌 +##餐 +##餒 +##餓 +##餘 +##餚 +##餛 +##餞 +##餡 +##館 +##餮 +##餵 +##餾 +##饅 +##饈 +##饋 +##饌 +##饍 +##饑 +##饒 +##饕 +##饗 +##饞 +##饥 +##饨 +##饪 +##饬 +##饭 +##饮 +##饯 +##饰 +##饱 +##饲 +##饴 +##饵 +##饶 +##饷 +##饺 +##饼 +##饽 +##饿 +##馀 +##馁 +##馄 +##馅 +##馆 +##馈 +##馋 +##馍 +##馏 +##馒 +##馔 +##首 +##馗 +##香 +##馥 +##馨 +##馬 +##馭 +##馮 +##馳 +##馴 +##駁 +##駄 +##駅 +##駆 +##駐 +##駒 +##駕 +##駛 +##駝 +##駭 +##駱 +##駿 +##騁 +##騎 +##騏 +##験 +##騙 +##騨 +##騰 +##騷 +##驀 +##驅 +##驊 +##驍 +##驒 +##驕 +##驗 +##驚 +##驛 +##驟 +##驢 +##驥 +##马 +##驭 +##驮 +##驯 +##驰 +##驱 +##驳 +##驴 +##驶 +##驷 +##驸 +##驹 +##驻 +##驼 +##驾 +##驿 +##骁 +##骂 +##骄 +##骅 +##骆 +##骇 +##骈 +##骊 +##骋 +##验 +##骏 +##骐 +##骑 +##骗 +##骚 +##骛 +##骜 +##骞 +##骠 +##骡 +##骤 +##骥 +##骧 +##骨 +##骯 +##骰 +##骶 +##骷 +##骸 +##骼 +##髂 +##髅 +##髋 +##髏 +##髒 +##髓 +##體 +##髖 +##高 +##髦 +##髪 +##髮 +##髯 +##髻 +##鬃 +##鬆 +##鬍 +##鬓 +##鬚 +##鬟 +##鬢 +##鬣 +##鬥 +##鬧 +##鬱 +##鬼 +##魁 +##魂 +##魄 +##魅 +##魇 +##魍 +##魏 +##魔 +##魘 +##魚 +##魯 +##魷 +##鮑 +##鮨 +##鮪 +##鮭 +##鮮 +##鯉 +##鯊 +##鯖 +##鯛 +##鯨 +##鯰 +##鯽 +##鰍 +##鰓 +##鰭 +##鰲 +##鰻 +##鰾 +##鱈 +##鱉 +##鱔 +##鱗 +##鱷 +##鱸 +##鱼 +##鱿 +##鲁 +##鲈 +##鲍 +##鲑 +##鲛 +##鲜 +##鲟 +##鲢 +##鲤 +##鲨 +##鲫 +##鲱 +##鲲 +##鲶 +##鲷 +##鲸 +##鳃 +##鳄 +##鳅 +##鳌 +##鳍 +##鳕 +##鳖 +##鳗 +##鳝 +##鳞 +##鳥 +##鳩 +##鳳 +##鳴 +##鳶 +##鴉 +##鴕 +##鴛 +##鴦 +##鴨 +##鴻 +##鴿 +##鵑 +##鵜 +##鵝 +##鵡 +##鵬 +##鵰 +##鵲 +##鶘 +##鶩 +##鶯 +##鶴 +##鷗 +##鷲 +##鷹 +##鷺 +##鸚 +##鸞 +##鸟 +##鸠 +##鸡 +##鸢 +##鸣 +##鸥 +##鸦 +##鸨 +##鸪 +##鸭 +##鸯 +##鸳 +##鸵 +##鸽 +##鸾 +##鸿 +##鹂 +##鹃 +##鹄 +##鹅 +##鹈 +##鹉 +##鹊 +##鹌 +##鹏 +##鹑 +##鹕 +##鹘 +##鹜 +##鹞 +##鹤 +##鹦 +##鹧 +##鹫 +##鹭 +##鹰 +##鹳 +##鹵 +##鹹 +##鹼 +##鹽 +##鹿 +##麂 +##麋 +##麒 +##麓 +##麗 +##麝 +##麟 +##麥 +##麦 +##麩 +##麴 +##麵 +##麸 +##麺 +##麻 +##麼 +##麽 +##麾 +##黃 +##黄 +##黍 +##黎 +##黏 +##黑 +##黒 +##黔 +##默 +##黛 +##黜 +##黝 +##點 +##黠 +##黨 +##黯 +##黴 +##鼋 +##鼎 +##鼐 +##鼓 +##鼠 +##鼬 +##鼹 +##鼻 +##鼾 +##齁 +##齊 +##齋 +##齐 +##齒 +##齡 +##齢 +##齣 +##齦 +##齿 +##龄 +##龅 +##龈 +##龊 +##龋 +##龌 +##龍 +##龐 +##龔 +##龕 +##龙 +##龚 +##龛 +##龜 +##龟 +##︰ +##︱ +##︶ +##︿ +##﹁ +##﹂ +##﹍ +##﹏ +##﹐ +##﹑ +##﹒ +##﹔ +##﹕ +##﹖ +##﹗ +##﹙ +##﹚ +##﹝ +##﹞ +##﹡ +##﹣ +##! +##" +### +##$ +##% +##& +##' +##( +##) +##* +##, +##- +##. +##/ +##: +##; +##< +##? +##@ +##[ +##\ +##] +##^ +##_ +##` +##f +##h +##j +##u +##w +##z +##{ +##} +##。 +##「 +##」 +##、 +##・ +##ッ +##ー +##イ +##ク +##シ +##ス +##ト +##ノ +##フ +##ラ +##ル +##ン +##゙ +##゚ +## ̄ +##¥ +##👍 +##🔥 +##😂 +##😎 +[unused0] +[unused100] +[unused101] +[unused102] +[unused103] +[unused104] +[unused105] +[unused106] +[unused107] +[unused108] +[unused109] +[unused110] +[unused111] +[unused112] +[unused113] +[unused114] +[unused115] +[unused116] +[unused117] +[unused118] +[unused119] +[unused120] +[unused121] +[unused122] +[unused123] +[unused124] +[unused125] +[unused126] +[unused127] +[unused128] +[unused129] +[unused130] +[unused131] +[unused132] +[unused133] +[unused134] +[unused135] +[unused136] +[unused137] +[unused138] +[unused139] +[unused140] +[unused141] +[unused142] +[unused143] +[unused144] +[unused145] +[unused146] +[unused147] +[unused148] +[unused149] +[unused150] +[unused151] +[unused152] +[unused153] +[unused154] +[unused155] +[unused156] +[unused157] +[unused158] +[unused159] +[unused160] +[unused161] +[unused162] +[unused163] +[unused164] +[unused165] +[unused166] +[unused167] +[unused168] +[unused169] +[unused170] +[unused171] +[unused172] +[unused173] +[unused174] +[unused175] +[unused176] +[unused177] +[unused178] +[unused179] +[unused180] +[unused181] +[unused182] +[unused183] +[unused184] +[unused185] +[unused186] +[unused187] +[unused188] +[unused189] +[unused190] +[unused191] +[unused192] +[unused193] +[unused194] +[unused195] +[unused196] +[unused197] +[unused198] +[unused199] +[unused200] +[unused201] +[unused202] +[unused203] +[unused204] +[unused205] +[unused206] +[unused207] +[unused208] +[unused209] +[unused210] +[unused211] +[unused212] +[unused213] +[unused214] +[unused215] +[unused216] +[unused217] +[unused218] +[unused219] +[unused220] +[unused221] +[unused222] +[unused223] +[unused224] +[unused225] +[unused226] +[unused227] +[unused228] +[unused229] +[unused230] +[unused231] +[unused232] +[unused233] +[unused234] +[unused235] +[unused236] +[unused237] +[unused238] +[unused239] +[unused240] +[unused241] +[unused242] +[unused243] +[unused244] +[unused245] +[unused246] +[unused247] +[unused248] +[unused249] +[unused250] +[unused251] +[unused252] +[unused253] +[unused254] +[unused255] +[unused256] +[unused257] +[unused258] +[unused259] +[unused260] +[unused261] +[unused262] +[unused263] +[unused264] +[unused265] +[unused266] +[unused267] +[unused268] +[unused269] +[unused270] +[unused271] +[unused272] +[unused273] +[unused274] +[unused275] +[unused276] +[unused277] +[unused278] +[unused279] +[unused280] +[unused281] +[unused282] +[unused283] +[unused284] +[unused285] +[unused286] +[unused287] +[unused288] +[unused289] +[unused290] +[unused291] +[unused292] +[unused293] +[unused294] +[unused295] +[unused296] +[unused297] +[unused298] +[unused299] +[unused300] +[unused301] +[unused302] +[unused303] +[unused304] +[unused305] +[unused306] +[unused307] +[unused308] +[unused309] +[unused310] +[unused311] +[unused312] +[unused313] +[unused314] +[unused315] +[unused316] +[unused317] +[unused318] +[unused319] +[unused320] +[unused321] +[unused322] +[unused323] +[unused324] +[unused325] +[unused326] +[unused327] +[unused328] +[unused329] +[unused330] +[unused331] +[unused332] +[unused333] +[unused334] +[unused335] +[unused336] +[unused337] +[unused338] +[unused339] +[unused340] +[unused341] +[unused342] +[unused343] +[unused344] +[unused345] +[unused346] +[unused347] +[unused348] +[unused349] +[unused350] +[unused351] +[unused352] +[unused353] +[unused354] +[unused355] +[unused356] +[unused357] +[unused358] +[unused359] +[unused360] +[unused361] +[unused362] +[unused363] +[unused364] +[unused365] +[unused366] +[unused367] +[unused368] +[unused369] +[unused370] +[unused371] +[unused372] +[unused373] +[unused374] +[unused375] +[unused376] +[unused377] +[unused378] +[unused379] +[unused380] +[unused381] +[unused382] +[unused383] +[unused384] +[unused385] +[unused386] +[unused387] +[unused388] +[unused389] +[unused390] +[unused391] +[unused392] +[unused393] +[unused394] +[unused395] +[unused396] +[unused397] +[unused398] +[unused399] +[unused400] +[unused401] +[unused402] +[unused403] +[unused404] +[unused405] +[unused406] +[unused407] +[unused408] +[unused409] +[unused410] +[unused411] +[unused412] +[unused413] +[unused414] +[unused415] +[unused416] +[unused417] +[unused418] +[unused419] +[unused420] +[unused421] +[unused422] +[unused423] +[unused424] +[unused425] +[unused426] +[unused427] +[unused428] +[unused429] +[unused430] +[unused431] +[unused432] +[unused433] +[unused434] +[unused435] +[unused436] +[unused437] +[unused438] +[unused439] +[unused440] +[unused441] +[unused442] +[unused443] +[unused444] +[unused445] +[unused446] +[unused447] +[unused448] +[unused449] +[unused450] +[unused451] +[unused452] +[unused453] +[unused454] +[unused455] +[unused456] +[unused457] +[unused458] +[unused459] +[unused460] +[unused461] +[unused462] +[unused463] +[unused464] +[unused465] +[unused466] +[unused467] +[unused468] +[unused469] +[unused470] +[unused471] +[unused472] +[unused473] +[unused474] +[unused475] +[unused476] +[unused477] +[unused478] +[unused479] +[unused480] +[unused481] +[unused482] +[unused483] +[unused484] +[unused485] +[unused486] +[unused487] +[unused488] +[unused489] +[unused490] +[unused491] +[unused492] +[unused493] +[unused494] +[unused495] +[unused496] +[unused497] +[unused498] +[unused499] +[unused500] +[unused501] +[unused502] +[unused503] +[unused504] +[unused505] +[unused506] +[unused507] +[unused508] +[unused509] +[unused510] +[unused511] +[unused512] +[unused513] +[unused514] +[unused515] +[unused516] +[unused517] +[unused518] +[unused519] +[unused520] +[unused521] +[unused522] +[unused523] +[unused524] +[unused525] +[unused526] +[unused527] +[unused528] +[unused529] +[unused530] +[unused531] +[unused532] +[unused533] +[unused534] +[unused535] +[unused536] +[unused537] +[unused538] +[unused539] +[unused540] +[unused541] +[unused542] +[unused543] +[unused544] +[unused545] +[unused546] +[unused547] +[unused548] +[unused549] +[unused550] +[unused551] +[unused552] +[unused553] +[unused554] +[unused555] +[unused556] +[unused557] +[unused558] +[unused559] +[unused560] +[unused561] +[unused562] +[unused563] +[unused564] +[unused565] +[unused566] +[unused567] +[unused568] +[unused569] +[unused570] +[unused571] +[unused572] +[unused573] +[unused574] +[unused575] +[unused576] +[unused577] +[unused578] +[unused579] +[unused580] +[unused581] +[unused582] +[unused583] +[unused584] +[unused585] +[unused586] +[unused587] +[unused588] +[unused589] +[unused590] +[unused591] +[unused592] +[unused593] +[unused594] +[unused595] +[unused596] +[unused597] +[unused598] +[unused599] +[unused600] +[unused601] +[unused602] +[unused603] +[unused604] +[unused605] +[unused606] +[unused607] +[unused608] +[unused609] +[unused610] +[unused611] +[unused612] +[unused613] +[unused614] +[unused615] +[unused616] +[unused617] +[unused618] +[unused619] +[unused620] +[unused621] +[unused622] +[unused623] +[unused624] +[unused625] +[unused626] +[unused627] +[unused628] +[unused629] +[unused630] +[unused631] +[unused632] +[unused633] +[unused634] +[unused635] +[unused636] +[unused637] +[unused638] +[unused639] +[unused640] +[unused641] +[unused642] +[unused643] +[unused644] +[unused645] +[unused646] +[unused647] +[unused648] +[unused649] +[unused650] +[unused651] +[unused652] +[unused653] +[unused654] +[unused655] +[unused656] +[unused657] +[unused658] +[unused659] +[unused660] +[unused661] +[unused662] +[unused663] +[unused664] +[unused665] +[unused666] +[unused667] +[unused668] +[unused669] +[unused670] +[unused671] +[unused672] +[unused673] +[unused674] +[unused675] +[unused676] +[unused677] +[unused678] +[unused679] +[unused680] +[unused681] +[unused682] +[unused683] +[unused684] +[unused685] +[unused686] +[unused687] +[unused688] +[unused689] +[unused690] +[unused691] +[unused692] +[unused693] +[unused694] +[unused695] +[unused696] +[unused697] +[unused698] +[unused699] +[unused700] +[unused701] +[unused702] +[unused703] +[unused704] +[unused705] +[unused706] +[unused707] +[unused708] +[unused709] +[unused710] +[unused711] +[unused712] +[unused713] +[unused714] +[unused715] +[unused716] +[unused717] +[unused718] +[unused719] +[unused720] +[unused721] +[unused722] +[unused723] +[unused724] +[unused725] +[unused726] +[unused727] +[unused728] +[unused729] +[unused730] +[unused731] +[unused732] +[unused733] +[unused734] +[unused735] +[unused736] +[unused737] +[unused738] +[unused739] +[unused740] +[unused741] +[unused742] +[unused743] +[unused744] +[unused745] +[unused746] +[unused747] +[unused748] +[unused749] +[unused750] +[unused751] +[unused752] +[unused753] +[unused754] +[unused755] +[unused756] +[unused757] +[unused758] +[unused759] +[unused760] +[unused761] +[unused762] +[unused763] +[unused764] +[unused765] +[unused766] +[unused767] +[unused768] +[unused769] +[unused770] +[unused771] +[unused772] +[unused773] +[unused774] +[unused775] +[unused776] +[unused777] +[unused778] +[unused779] +[unused780] +[unused781] +[unused782] +[unused783] +[unused784] +[unused785] +[unused786] +[unused787] +[unused788] +[unused789] +[unused790] +[unused791] +[unused792] +[unused793] +[unused794] +[unused795] +[unused796] +[unused797] +[unused798] +[unused799] +[unused800] +[unused801] +[unused802] +[unused803] +[unused804] +[unused805] +[unused806] +[unused807] +[unused808] +[unused809] +[unused810] +[unused811] +[unused812] +[unused813] +[unused814] +[unused815] +[unused816] +[unused817] +[unused818] +[unused819] +[unused820] +[unused821] +[unused822] +[unused823] +[unused824] +[unused825] +[unused826] +[unused827] +[unused828] +[unused829] +[unused830] +[unused831] +[unused832] +[unused833] +[unused834] +[unused835] +[unused836] +[unused837] +[unused838] +[unused839] +[unused840] +[unused841] +[unused842] +[unused843] +[unused844] +[unused845] +[unused846] +[unused847] +[unused848] +[unused849] +[unused850] +[unused851] +[unused852] +[unused853] +[unused854] +[unused855] +[unused856] +[unused857] +[unused858] +[unused859] +[unused860] +[unused861] +[unused862] +[unused863] +[unused864] +[unused865] +[unused866] +[unused867] +[unused868] +[unused869] +[unused870] +[unused871] +[unused872] +[unused873] +[unused874] +[unused875] +[unused876] +[unused877] +[unused878] +[unused879] +[unused880] +[unused881] +[unused882] +[unused883] +[unused884] +[unused885] +[unused886] +[unused887] +[unused888] +[unused889] +[unused890] +[unused891] +[unused892] +[unused893] +[unused894] +[unused895] +[unused896] +[unused897] +[unused898] +[unused899] +[unused900] +[unused901] +[unused902] +[unused903] +[unused904] +[unused905] +[unused906] +[unused907] +[unused908] +[unused909] +[unused910] +[unused911] +[unused912] +[unused913] +[unused914] +[unused915] +[unused916] +[unused917] +[unused918] +[unused919] +[unused920] +[unused921] +[unused922] +[unused923] +[unused924] +[unused925] +[unused926] +[unused927] +[unused928] +[unused929] +[unused930] +[unused931] +[unused932] +[unused933] +[unused934] +[unused935] +[unused936] +[unused937] +[unused938] +[unused939] +[unused940] +[unused941] +[unused942] +[unused943] +[unused944] +[unused945] +[unused946] +[unused947] +[unused948] +[unused949] +[unused950] +[unused951] +[unused952] +[unused953] +[unused954] +[unused955] +[unused956] +[unused957] +[unused958] +[unused959] +[unused960] +[unused961] +[unused962] +[unused963] +[unused964] +[unused965] +[unused966] +[unused967] +[unused968] +[unused969] +[unused970] +[unused971] +[unused972] +[unused973] +[unused974] +[unused975] +[unused976] +[unused977] +[unused978] +[unused979] +[unused980] +[unused981] +[unused982] +[unused983] +[unused984] +[unused985] +[unused986] +[unused987] +[unused988] +[unused989] +[unused990] +[unused991] +[unused992] +[unused993] +` +¡ +¢ +¦ +¨ +ª +¬ +´ +¶ +½ +¾ +¿ +ð +þ +ħ +ı +ł +œ +ƒ +ɐ +ɑ +ɒ +ɕ +ɛ +ɣ +ɨ +ɪ +ɫ +ɬ +ɯ +ɲ +ɴ +ɹ +ɾ +ʀ +ʁ +ʂ +ʃ +ʉ +ʊ +ʋ +ʌ +ʎ +ʐ +ʑ +ʒ +ʔ +ʲ +ʳ +ʷ +ʸ +ʻ +ʼ +ʾ +ʿ +ˡ +ˣ +ˤ +ζ +ξ +щ +ъ +э +ю +ђ +є +ј +љ +њ +ћ +ӏ +ա +բ +գ +դ +ե +թ +ի +լ +կ +հ +մ +յ +ն +ո +պ +ս +վ +տ +ր +ւ +ք +־ +א +ב +ג +ד +ה +ו +ז +ח +ט +י +ך +כ +ל +ם +מ +ן +נ +ס +ע +ף +פ +ץ +צ +ק +ר +ש +ת +، +ء +ث +ج +ح +خ +ذ +ز +ش +ص +ض +ط +ظ +غ +ـ +ف +ق +ك +ى +ٹ +پ +چ +ک +گ +ں +ھ +ہ +ی +ے +अ +आ +उ +ए +क +ख +ग +च +ज +ट +ड +ण +त +थ +द +ध +न +प +ब +भ +म +य +र +ल +व +श +ष +स +ह +ा +ि +ी +ो +। +॥ +ং +অ +আ +ই +উ +এ +ও +ক +খ +গ +চ +ছ +জ +ট +ড +ণ +ত +থ +দ +ধ +ন +প +ব +ভ +ম +য +র +ল +শ +ষ +স +হ +া +ি +ী +ে +க +ச +ட +த +ந +ன +ப +ம +ய +ர +ல +ள +வ +ா +ி +ு +ே +ை +ನ +ರ +ಾ +ක +ය +ර +ල +ව +ා +ต +ท +พ +ล +ว +ส +། +ག +ང +ད +ན +པ +བ +མ +འ +ར +ལ +ས +မ +ა +ბ +გ +დ +ე +ვ +თ +ი +კ +ლ +მ +ნ +ო +რ +ს +ტ +უ +ᄊ +ᴬ +ᴮ +ᴰ +ᴵ +ᴺ +ᵀ +ᵇ +ᵈ +ᵖ +ᵗ +ᵢ +ᵣ +ᵤ +ᵥ +ᶜ +ᶠ +‐ +‑ +‒ +– +— +― +‘ +’ +‚ +“ +” +‡ +… +⁰ +⁴ +⁵ +⁶ +⁷ +⁸ +⁹ +⁻ +₀ +₅ +₆ +₇ +₈ +₉ +₊ +₍ +₎ +ₐ +ₑ +ₒ +ₓ +ₕ +ₖ +ₗ +ₘ +ₙ +ₚ +ₛ +ₜ +₤ +₩ +₱ +₹ +ℓ +ℝ +⅓ +⅔ +↦ +⇄ +⇌ +∂ +∅ +∆ +∇ +∈ +∗ +∘ +∧ +∨ +∪ +⊂ +⊆ +⊕ +⊗ +☉ +♭ +♯ +⟨ +⟩ +ⱼ +⺩ +⺼ +⽥ +亻 +宀 +彳 +忄 +扌 +氵 +疒 +糹 +訁 +辶 +阝 +龸 +fi +fl +had +were +which +him +their +been +would +then +them +could +during +through +between +while +later +around +did +such +being +used +against +many +both +these +known +until +even +didn +because +born +since +still +became +any +including +took +same +each +called +much +however +four +another +found +won +going +away +hand +several +following +released +played +began +district +those +held +own +early +league +government +came +based +thought +looked +along +went +few +father +former +located +got +though +every +century +without +within +building +large +named +started +once +should +built +british +death +moved +door +need +president +wasn +although +due +major +died +third +knew +asked +turned +wanted +together +received +son +served +different +behind +himself +felt +members +football +near +having +saw +mother +army +front +late +hands +put +division +across +told +often +ever +french +six +include +tell +among +species +really +according +half +original +gave +making +enough +opened +must +included +given +german +woman +community +might +million +court +short +round +seen +always +become +sure +almost +director +council +career +things +using +couldn +better +students +married +nothing +worked +others +record +anything +continued +give +military +established +returned +does +written +thing +feet +far +already +championship +western +department +role +various +production +television +produced +working +region +present +period +looking +least +total +england +wife +per +brother +soon +political +taken +created +further +able +reached +joined +upon +done +important +either +appeared +position +ground +lead +election +arms +police +instead +words +moment +someone +announced +less +wrote +past +followed +founded +finally +india +taking +records +considered +northern +toward +european +outside +described +track +playing +heard +professional +australia +miles +yet +trying +blood +southern +maybe +everything +mouth +race +recorded +above +daughter +points +middle +move +tried +elected +closed +ten +minister +chief +person +similar +brought +rest +formed +floor +doing +killed +training +needed +turn +finished +railway +rather +sent +example +ran +term +coming +currently +forces +despite +areas +fact +dead +originally +germany +probably +developed +pulled +stood +signed +songs +child +eventually +met +average +teams +minutes +current +kind +decided +usually +eastern +seemed +episode +bed +added +indian +route +available +throughout +addition +appointed +eight +construction +mean +remained +schools +sometimes +events +possible +australian +forward +debut +seat +performance +committee +features +character +herself +lot +russian +range +hours +sold +quickly +directed +guitar +performed +players +smile +myself +placed +province +towards +wouldn +leading +whole +designed +census +europe +attack +japanese +getting +alone +lower +wide +hospital +believe +changed +sister +gone +hadn +ship +studies +academy +shot +below +involved +kept +largest +especially +beginning +movement +section +female +professor +lord +longer +walked +actually +civil +families +thus +aircraft +completed +includes +captain +fight +vocals +featured +fourth +officer +hear +means +medical +groups +lips +competition +entire +lived +leaving +federal +tournament +passed +independent +kingdom +spent +fine +doesn +reported +fall +raised +itself +replaced +leader +theatre +whose +parents +spanish +canadian +degree +writing +awarded +higher +coast +provided +senior +organization +stopped +onto +countries +parts +conference +interest +saying +allowed +earlier +matter +winning +try +happened +moving +los +breath +nearly +mid +certain +italian +african +standing +fell +artist +shows +deal +mine +industry +everyone +republic +provide +student +primary +owned +older +heavy +1st +makes +attention +anyone +africa +stated +length +ended +fingers +command +staff +foreign +opening +governor +okay +medal +kill +introduced +chest +hell +feeling +success +meet +reason +meeting +novel +trade +buildings +guy +goal +native +husband +previously +entered +producer +operations +takes +covered +forced +roman +complete +successful +texas +cold +traditional +films +clear +approximately +nine +prince +question +tracks +ireland +regional +personal +operation +economic +holding +twenty +additional +hour +regular +historic +places +whom +shook +km² +secretary +prior +scored +units +ask +property +ready +immediately +month +listed +contract +themselves +lines +navy +writer +meant +runs +practice +championships +singer +commission +required +starting +generally +giving +attended +couple +stand +catholic +caught +executive +thinking +chair +quite +shoulder +hope +decision +plays +defeated +municipality +whether +offered +slowly +pain +direction +mission +mostly +noted +individual +managed +lives +plant +helped +except +studied +computer +figure +relationship +issue +significant +loss +smiled +gun +highest +male +bring +goals +mexico +problem +distance +commercial +completely +location +annual +famous +neck +caused +italy +understand +greek +highway +wrong +comes +appearance +issues +musical +companies +castle +income +assembly +bass +initially +parliament +artists +experience +particular +walk +foot +engineering +talking +dropped +boys +stars +remember +carried +train +stadium +angeles +evidence +becoming +assistant +soviet +upper +youth +reach +actor +numerous +nodded +arrived +minute +believed +complex +victory +associated +temple +chance +perhaps +bishop +launched +particularly +retired +subject +prize +contains +yeah +theory +empire +suddenly +waiting +trust +recording +terms +champion +religious +zealand +names +2nd +ancient +corner +represented +legal +justice +cause +watched +brothers +material +changes +simply +response +answer +historical +stories +straight +feature +increased +administration +virginia +activities +cultural +overall +winner +programs +basketball +legs +guard +cast +doctor +flight +results +remains +cost +effect +winter +larger +islands +problems +chairman +grew +commander +isn +failed +selected +hurt +fort +regiment +majority +plans +shown +pretty +irish +characters +directly +scene +likely +operated +allow +matches +looks +houses +fellow +marriage +rules +florida +expected +nearby +congress +peace +recent +wait +subsequently +variety +serving +agreed +poor +attempt +wood +democratic +rural +mile +appears +township +soldiers +##ized +pennsylvania +closer +fighting +claimed +score +physical +filled +genus +specific +sitting +mom +therefore +supported +status +fear +cases +meaning +wales +minor +spain +vice +parish +separate +horse +fifth +remaining +branch +presented +stared +uses +forms +baseball +exactly +choice +discovered +composed +truth +russia +dad +ring +referred +numbers +greater +metres +slightly +direct +increase +responsible +crew +rule +trees +troops +broke +goes +individuals +hundred +weight +creek +sleep +defense +provides +ordered +jewish +safe +judge +whatever +corps +realized +growing +cities +gaze +lies +spread +letter +showed +situation +mayor +transport +watching +workers +extended +expression +normal +chart +multiple +border +mrs +walls +piano +heat +cannot +earned +products +drama +era +authority +seasons +join +grade +difficult +territory +mainly +stations +squadron +stepped +iron +19th +serve +appear +speak +broken +charge +knowledge +kilometres +removed +ships +campus +pushed +britain +leaves +recently +boston +latter +acquired +poland +quality +officers +presence +planned +nations +mass +broadcast +influence +wild +emperor +electric +headed +ability +promoted +yellow +ministry +throat +smaller +politician +latin +spoke +cars +males +lack +acting +seeing +consists +estate +pressure +newspaper +olympics +conditions +beat +elements +walking +vote +needs +carolina +featuring +levels +francisco +purpose +females +dutch +duke +ahead +gas +safety +serious +turning +highly +lieutenant +firm +amount +mixed +proposed +perfect +agreement +affairs +3rd +seconds +contemporary +paid +prison +label +administrative +intended +constructed +academic +teacher +races +formerly +nation +issued +shut +drums +housing +seems +graduated +mentioned +picked +recognized +shortly +protection +picture +notable +elections +1980s +loved +percent +racing +elizabeth +volume +hockey +beside +settled +competed +replied +drew +actress +marine +scotland +steel +glanced +farm +risk +tonight +positive +singles +effects +gray +screen +residents +sides +none +secondary +literature +polish +destroyed +flying +founder +households +lay +reserve +industrial +younger +approach +appearances +ones +finish +powerful +fully +growth +honor +jersey +projects +revealed +infantry +pair +equipment +visit +evening +grant +effort +treatment +buried +republican +primarily +bottom +owner +1970s +israel +gives +remain +spot +produce +champions +accepted +ways +##ally +losing +split +capacity +basis +trial +questions +20th +guess +officially +memorial +naval +initial +##ization +whispered +median +engineer +sydney +columbia +strength +tears +senate +asian +draw +warm +supposed +transferred +leaned +candidate +escape +mountains +potential +activity +seem +traffic +murder +slow +orchestra +haven +agency +taught +website +comedy +unable +storm +planning +albums +rugby +environment +scientific +grabbed +protect +boat +typically +damage +principal +divided +dedicated +ohio +pick +fought +driver +empty +shoulders +sort +thank +berlin +prominent +account +freedom +necessary +efforts +headquarters +follows +alongside +suggested +operating +steps +technical +begin +easily +teeth +speaking +settlement +scale +renamed +enemy +semi +joint +compared +scottish +leadership +analysis +offers +georgia +pieces +captured +animal +deputy +organized +combined +method +challenge +1960s +huge +wants +battalion +sons +rise +crime +types +facilities +telling +platform +sit +1990s +tells +assigned +pull +commonly +alive +letters +concept +conducted +wearing +happen +bought +becomes +holy +gets +defeat +languages +purchased +occurred +titled +declared +applied +sciences +concert +sounds +jazz +brain +painting +fleet +tax +michigan +animals +leaders +episodes +birth +clubs +palace +critical +refused +fair +leg +laughed +returning +surrounding +participated +formation +lifted +pointed +connected +rome +medicine +laid +powers +tall +shared +focused +knowing +yards +entrance +falls +calling +sources +chosen +beneath +resources +yard +nominated +silence +defined +gained +thirty +bodies +adopted +christmas +widely +register +apart +iran +premier +serves +unknown +parties +generation +continues +fields +brigade +quiet +teaching +clothes +impact +weapons +partner +flat +theater +relations +plants +suffered +begins +seats +armed +models +worth +laws +communities +classes +background +knows +thanks +quarter +reaching +humans +carry +killing +format +setting +architecture +disease +railroad +possibly +arthur +thoughts +doors +density +crowd +illinois +stomach +tone +unique +reports +anyway +liberal +vehicle +thick +dry +drug +faced +largely +facility +theme +holds +creation +strange +colonel +revolution +politics +turns +silent +rail +relief +independence +combat +shape +determined +sales +learned +4th +finger +providing +heritage +fiction +situated +designated +allowing +hosted +sight +interview +estimated +reduced +toronto +footballer +keeping +guys +damn +claim +motion +sixth +stayed +rear +receive +handed +twelve +dress +audience +granted +brazil +spirit +##ated +noticed +olympic +representative +tight +trouble +reviews +drink +vampire +missing +roles +ranked +newly +household +finals +critics +phase +massachusetts +pilot +unlike +philadelphia +bright +guns +crown +organizations +roof +respectively +clearly +tongue +marked +circle +bronze +expanded +sexual +supply +yourself +inspired +labour +reference +draft +connection +reasons +driving +jesus +cells +entry +neither +trail +claims +atlantic +orders +labor +nose +afraid +identified +intelligence +calls +cancer +attacked +passing +positions +imperial +grey +swedish +avoid +extra +uncle +covers +allows +surprise +materials +fame +hunter +citizens +figures +environmental +confirmed +shit +titles +performing +difference +acts +attacks +existing +votes +opportunity +nor +entirely +trains +opposite +pakistan +develop +resulted +representatives +actions +reality +pressed +barely +conversation +faculty +northwest +ends +documentary +nuclear +stock +sets +eat +alternative +resulting +creating +surprised +cemetery +drop +finding +cricket +streets +tradition +ride +ear +explained +composer +injury +apartment +municipal +educational +occupied +netherlands +clean +billion +constitution +learn +maximum +classical +lose +opposition +ontario +hills +rolled +ending +drawn +permanent +lewis +sites +chamber +scoring +height +lyrics +staring +officials +snow +oldest +qualified +interior +apparently +succeeded +thousand +dinner +lights +existence +heavily +greatest +conservative +send +bowl +catch +duty +speech +authorities +princess +performances +versions +shall +graduate +pictures +effective +remembered +poetry +desk +crossed +starring +starts +passenger +sharp +acres +ass +weather +falling +rank +fund +supporting +adult +heads +southeast +lane +condition +transfer +prevent +regions +earl +federation +relatively +answered +besides +obtained +portion +reaction +liked +peak +counter +religion +chain +rare +convention +aid +lie +vehicles +perform +squad +wonder +lying +crazy +sword +attempted +centuries +weren +philosophy +interested +sweden +wolf +frequently +abandoned +literary +alliance +task +entitled +threw +promotion +tiny +soccer +visited +achieved +defence +internal +persian +methods +arrested +otherwise +programming +villages +elementary +districts +rooms +criminal +conflict +worry +trained +attempts +waited +signal +truck +subsequent +programme +communist +faith +sector +carrying +laugh +controlled +korean +showing +origin +fuel +evil +brief +identity +darkness +pool +missed +publication +wings +invited +briefly +standards +kissed +ideas +climate +causing +walter +worse +albert +winners +desire +aged +northeast +dangerous +gate +doubt +wooden +poet +rising +funding +communications +communication +violence +copies +prepared +investigation +skills +pulling +containing +ultimately +offices +singing +understanding +tomorrow +christ +ward +pope +stands +5th +flow +studios +aired +commissioned +contained +exist +americans +wrestling +approved +kid +employed +respect +suit +asking +increasing +frame +angry +selling +1950s +thin +finds +temperature +statement +ali +explain +inhabitants +towns +extensive +narrow +flowers +promise +somewhere +closely +bureau +cape +weekly +presidential +legislative +launch +founding +artillery +strike +un +institutions +roll +writers +landing +chose +anymore +attorney +billboard +receiving +agricultural +breaking +sought +dave +admitted +lands +mexican +##bury +specifically +hole +moscow +roads +accident +proved +struck +guards +stuff +slid +expansion +melbourne +opposed +sub +southwest +architect +failure +plane +tank +listen +regarding +wet +introduction +metropolitan +fighter +inch +grown +gene +anger +fixed +khan +domestic +worldwide +chapel +mill +functions +examples +developing +turkey +hits +pocket +antonio +papers +grow +unless +circuit +18th +concerned +attached +journalist +selection +journey +converted +provincial +painted +hearing +aren +bands +negative +aside +wondered +knight +lap +noise +billy +shooting +bedroom +priest +resistance +motor +homes +sounded +giant +scenes +equal +comic +patients +hidden +solid +actual +bringing +afternoon +touched +funds +consisted +marie +canal +treaty +turkish +recognition +residence +cathedral +broad +knees +incident +shaped +fired +norwegian +handle +cheek +contest +represent +representing +birds +advantage +emergency +wrapped +drawing +notice +broadcasting +somehow +bachelor +seventh +collected +registered +establishment +assumed +chemical +personnel +retirement +portuguese +wore +tied +device +threat +progress +advance +##ised +banks +hired +manchester +nfl +teachers +structures +forever +tennis +helping +saturday +applications +junction +incorporated +neighborhood +dressed +ceremony +influenced +hers +stairs +decades +inner +kansas +hung +hoped +gain +scheduled +downtown +engaged +austria +clock +norway +certainly +pale +victor +employees +plate +putting +surrounded +##ists +finishing +blues +tropical +minnesota +consider +philippines +accept +retrieved +concern +anderson +properties +institution +gordon +successfully +vietnam +backing +outstanding +muslim +crossing +folk +producing +usual +demand +occurs +observed +lawyer +educated +pleasure +budget +items +quietly +colorado +philip +typical +##worth +derived +survived +asks +mental +jake +jews +distinguished +sri +extremely +athletic +loud +thousands +worried +transportation +horses +weapon +arena +importance +users +objects +contributed +douglas +aware +senator +johnny +sisters +engines +flag +investment +samuel +shock +capable +clark +row +wheel +refers +familiar +biggest +wins +hate +maintained +drove +hamilton +expressed +injured +underground +churches +wars +tunnel +passes +stupid +agriculture +softly +cabinet +regarded +joining +indiana +dates +spend +behavior +woods +protein +gently +chase +morgan +mention +burning +wake +combination +occur +mirror +leads +indeed +impossible +paintings +covering +soldier +locations +attendance +sell +historian +wisconsin +invasion +argued +painter +diego +changing +egypt +experienced +inches +missouri +grounds +spoken +switzerland +reform +rolling +forget +massive +resigned +burned +tennessee +locked +values +improved +wounded +universe +sick +dating +facing +purchase +##pur +moments +merged +anniversary +coal +brick +understood +causes +dynasty +queensland +establish +stores +crisis +promote +hoping +cards +referee +extension +raise +arizona +improve +colonial +formal +charged +palm +hide +rescue +faces +feelings +candidates +juan +6th +courses +weekend +luke +cash +fallen +delivered +affected +installed +carefully +tries +hollywood +costs +lincoln +responsibility +shore +proper +normally +maryland +assistance +constant +offering +friendly +waters +persons +realize +contain +trophy +partnership +factor +musicians +bound +oregon +indicated +houston +medium +consisting +somewhat +cycle +beer +moore +frederick +gotten +worst +weak +approached +arranged +chin +loan +bond +fifteen +pattern +disappeared +translated +##zed +lip +arab +capture +interests +insurance +shifted +cave +prix +warning +sections +courts +coat +plot +smell +golf +favorite +maintain +knife +voted +degrees +finance +quebec +opinion +translation +manner +ruled +operate +productions +choose +musician +confused +tired +separated +stream +techniques +committed +attend +ranking +kings +throw +passengers +measure +horror +mining +sand +danger +salt +calm +decade +dam +require +runner +rush +associate +greece +rivers +consecutive +matthew +##ski +sighed +sq +documents +closing +tie +accused +islamic +distributed +directors +organisation +7th +breathing +mad +lit +arrival +concrete +taste +composition +shaking +faster +amateur +adjacent +stating +twin +flew +publications +obviously +ridge +storage +carl +pages +concluded +desert +driven +universities +ages +terminal +sequence +borough +constituency +cousin +economics +dreams +margaret +notably +reduce +montreal +17th +ears +saved +vocal +riding +roughly +threatened +meters +meanwhile +landed +compete +repeated +grass +czech +regularly +charges +sudden +appeal +solution +describes +classification +glad +parking +belt +physics +rachel +hungarian +participate +expedition +damaged +gift +childhood +fifty +mathematics +jumped +letting +defensive +mph +testing +hundreds +shoot +owners +matters +smoke +israeli +kentucky +dancing +mounted +grandfather +designs +profit +argentina +truly +lawrence +cole +begun +detroit +willing +branches +smiling +decide +miami +enjoyed +recordings +##dale +poverty +ethnic +arabic +accompanied +fishing +determine +residential +acid +returns +starred +strategy +forty +businesses +equivalent +commonwealth +distinct +ill +seriously +##ped +harris +replace +rio +imagine +formula +ensure +additionally +scheme +conservation +occasionally +purposes +feels +favor +1930s +contrast +hanging +hunt +movies +instruments +victims +danish +christopher +busy +demon +sugar +earliest +colony +studying +duties +belgium +slipped +carter +visible +stages +iraq +commune +forming +continuing +talked +counties +legend +bathroom +option +tail +clay +daughters +afterwards +severe +jaw +visitors +devices +aviation +entering +subjects +temporary +swimming +forth +smooth +bush +operates +rocks +movements +signs +eddie +voices +honorary +memories +dallas +measures +racial +promised +harvard +16th +parliamentary +indicate +benefit +flesh +dublin +louisiana +patient +sleeping +membership +coastal +medieval +wanting +element +scholars +rice +limit +survive +makeup +rating +definitely +collaboration +obvious +baron +birthday +linked +soil +diocese +ncaa +offensive +shouldn +waist +plain +ross +organ +resolution +manufacturing +adding +relative +kennedy +whilst +moth +gardens +crash +heading +partners +credited +carlos +moves +cable +marshall +depending +bottle +represents +rejected +responded +existed +denmark +##ating +treated +graham +routes +talent +commissioner +drugs +secure +tests +reign +restored +photography +contributions +oklahoma +designer +disc +grin +seattle +robin +paused +atlanta +unusual +praised +las +laughing +satellite +hungary +visiting +interesting +factors +deck +poems +norman +##water +stuck +speaker +rifle +premiered +comics +actors +reputation +eliminated +8th +ceiling +prisoners +leather +austin +mississippi +rapidly +admiral +parallel +charlotte +guilty +tools +gender +divisions +fruit +laboratory +nelson +marry +rapid +aunt +tribe +requirements +aspects +suicide +amongst +adams +bone +ukraine +kick +sees +edinburgh +clothing +column +rough +gods +hunting +broadway +gathered +concerns +spending +ty +12th +snapped +requires +solar +bones +cavalry +iowa +drinking +waste +franklin +charity +thompson +stewart +tip +landscape +enjoy +singh +poem +listening +eighth +fred +differences +adapted +bomb +ukrainian +surgery +corporate +masters +anywhere +waves +odd +portugal +orleans +dick +debate +kent +eating +puerto +cleared +expect +cinema +guitarist +blocks +electrical +agree +involving +depth +dying +panel +struggle +peninsula +adults +novels +emerged +vienna +debuted +shoes +tamil +songwriter +meets +prove +beating +instance +heaven +scared +sending +marks +artistic +passage +superior +significantly +retained +##izing +technique +cheeks +warren +maintenance +destroy +extreme +allied +appearing +fill +advice +alabama +qualifying +policies +cleveland +hat +battery +authors +10th +soundtrack +acted +dated +lb +glance +equipped +coalition +funny +outer +ambassador +roy +possibility +couples +campbell +loose +ethan +supplies +gonna +monster +shake +agents +frequency +springs +dogs +practices +gang +plastic +easier +suggests +gulf +blade +exposed +colors +industries +markets +nervous +electoral +charts +legislation +ownership +##idae +appointment +shield +assault +socialist +abbey +monument +license +throne +employment +replacement +charter +suffering +accounts +oak +connecticut +strongly +wright +colour +13th +context +welsh +networks +voiced +gabriel +forehead +manage +schedule +totally +remix +forests +occupation +print +nicholas +brazilian +strategic +vampires +engineers +roots +seek +correct +instrumental +und +alfred +backed +stanley +robinson +traveled +wayne +austrian +achieve +exit +rates +strip +whereas +sing +deeply +adventure +bobby +jamie +careful +components +cap +useful +personality +knee +pushing +hosts +protest +ottoman +symphony +boundary +processes +considering +considerable +tons +cooper +trading +conduct +illegal +revolutionary +definition +harder +jacob +circumstances +destruction +popularity +grip +classified +liverpool +baltimore +flows +seeking +honour +approval +mechanical +till +happening +statue +critic +increasingly +immediate +describe +commerce +stare +indonesia +meat +rounds +boats +baker +orthodox +depression +formally +worn +naked +muttered +sentence +11th +document +criticism +wished +vessel +spiritual +bent +virgin +minimum +murray +lunch +danny +printed +compilation +keyboards +blow +belonged +raising +cutting +pittsburgh +9th +shadows +hated +indigenous +jon +15th +barry +scholar +oliver +stick +susan +meetings +attracted +spell +romantic +ye +demanded +customers +logan +revival +keys +modified +commanded +jeans +upset +phil +detective +hiding +resident +##bly +experiences +diamond +defeating +coverage +lucas +external +parks +franchise +helen +bible +successor +percussion +celebrated +lift +clan +romania +##ied +mills +nobody +achievement +shrugged +fault +rhythm +initiative +breakfast +carbon +lasted +violent +wound +killer +gradually +filmed +°c +processing +remove +criticized +guests +sang +chemistry +legislature +##bridge +uniform +escaped +integrated +proposal +purple +denied +liquid +influential +morris +nights +stones +intense +experimental +twisted +pace +nazi +mitchell +ny +blind +reporter +newspapers +14th +centers +burn +basin +forgotten +surviving +filed +collections +monastery +losses +manual +couch +description +appropriate +merely +missions +sebastian +restoration +replacing +triple +elder +julia +warriors +benjamin +julian +convinced +stronger +amazing +declined +versus +merchant +happens +output +finland +bare +barbara +absence +ignored +dawn +injuries +producers +luis +##ities +kw +admit +expensive +electricity +exception +symbol +ladies +shower +sheriff +characteristics +##je +aimed +button +ratio +effectively +summit +angle +jury +bears +foster +vessels +pants +executed +evans +dozen +advertising +kicked +patrol +competitions +lifetime +principles +athletics +birmingham +sponsored +rob +nomination +acoustic +creature +longest +credits +harbor +dust +josh +territories +milk +infrastructure +completion +thailand +indians +leon +archbishop +assist +pitch +blake +arrangement +girlfriend +serbian +operational +hence +sad +scent +fur +sessions +refer +rarely +exists +1892 +scientists +dirty +penalty +burst +portrait +seed +pole +limits +rival +stable +grave +constitutional +alcohol +arrest +flower +mystery +devil +architectural +relationships +greatly +habitat +##istic +larry +progressive +remote +cotton +preserved +reaches +cited +vast +scholarship +decisions +teach +editions +knocked +eve +searching +partly +participation +animated +fate +excellent +alternate +saints +youngest +climbed +suggest +discussion +staying +choir +lakes +jacket +revenue +nevertheless +peaked +instrument +wondering +annually +managing +neil +1891 +signing +terry +apply +clinical +brooklyn +aim +catherine +fuck +farmers +figured +ninth +pride +hugh +ordinary +involvement +comfortable +shouted +encouraged +representation +sharing +panic +exact +cargo +competing +fat +cried +1920s +occasions +cabin +borders +utah +marcus +##isation +badly +muscles +victorian +transition +warner +bet +permission +slave +terrible +similarly +shares +seth +uefa +possession +medals +benefits +colleges +lowered +perfectly +transit +##kar +publisher +##ened +harrison +deaths +elevation +asleep +machines +sigh +ash +hardly +argument +occasion +parent +decline +contribution +concentration +opportunities +hispanic +guardian +extent +emotions +hips +mason +volumes +bloody +controversy +diameter +steady +mistake +phoenix +identify +violin +departure +richmond +spin +funeral +enemies +1864 +literally +connor +random +sergeant +grab +confusion +1865 +transmission +informed +leaning +sacred +suspended +thinks +gates +portland +luck +agencies +yours +hull +expert +muscle +layer +practical +sculpture +jerusalem +latest +lloyd +statistics +deeper +recommended +warrior +arkansas +mess +supports +greg +eagle +recovered +rated +concerts +rushed +stops +eggs +premiere +keith +delhi +turner +pit +affair +belief +paint +##zing +victim +withdrew +bonus +styles +fled +glasgow +technologies +funded +adaptation +portrayed +cooperation +supporters +judges +bernard +hallway +ralph +graduating +controversial +distant +continental +spider +bite +recognize +intention +mixing +egyptian +bow +tourism +suppose +claiming +dominated +participants +nurse +partially +tape +psychology +essential +touring +duo +voting +civilian +emotional +channels +apparent +hebrew +1887 +tommy +carrier +intersection +beast +hudson +bench +discuss +costa +##ered +detailed +behalf +drivers +unfortunately +obtain +rocky +##dae +siege +friendship +1861 +hang +governments +collins +respond +wildlife +preferred +operator +laura +pregnant +videos +dennis +suspected +boots +instantly +weird +automatic +businessman +alleged +placing +throwing +mood +1862 +perry +venue +jet +remainder +passion +biological +boyfriend +1863 +dirt +buffalo +ron +segment +abuse +genre +thrown +stroke +colored +stress +exercise +displayed +struggled +abroad +dramatic +wonderful +thereafter +madrid +component +widespread +##sed +tale +citizen +todd +vancouver +overseas +forcing +crying +descent +discussed +substantial +ranks +regime +provinces +drum +zane +tribes +proof +researchers +volunteer +manor +silk +milan +donated +allies +venture +principle +delivery +enterprise +bars +traditionally +witch +reminded +copper +pete +inter +colin +grinned +elsewhere +competitive +frequent +scream +tension +texts +submarine +finnish +defending +defend +pat +detail +affiliated +stuart +themes +periods +tool +belgian +ruling +crimes +answers +folded +licensed +demolished +hans +lucy +1881 +lion +traded +photographs +writes +craig +trials +generated +beth +noble +debt +percentage +yorkshire +erected +viewed +grades +confidence +ceased +islam +telephone +retail +chile +m² +roberts +sixteen +commented +hampshire +innocent +dual +pounds +checked +regulations +afghanistan +sung +rico +liberty +assets +bigger +options +angels +relegated +tribute +wells +attending +leaf +romanian +monthly +patterns +gmina +madison +hurricane +rev +##ians +bristol +elite +valuable +disaster +democracy +awareness +germans +freyja +loop +absolutely +paying +populations +maine +sole +prayer +spencer +releases +doorway +bull +lover +midnight +conclusion +thirteen +mediterranean +nhl +proud +sample +##hill +drummer +guinea +murphy +climb +instant +attributed +horn +ain +railways +autumn +ferry +opponent +traveling +secured +corridor +stretched +tales +sheet +trinity +cattle +helps +indicates +manhattan +murdered +fitted +gentle +grandmother +mines +shocked +vegas +produces +caribbean +belong +continuous +desperate +drunk +historically +trio +waved +raf +dealing +nathan +murmured +interrupted +residing +scientist +pioneer +harold +aaron +delta +attempting +minority +believes +chorus +tend +lots +eyed +indoor +load +shots +updated +jail +concerning +connecting +wealth +slaves +arrive +rangers +sufficient +rebuilt +##wick +cardinal +flood +muhammad +whenever +relation +runners +moral +repair +viewers +arriving +revenge +punk +assisted +bath +fairly +breathe +lists +innings +illustrated +whisper +nearest +voters +clinton +ties +ultimate +screamed +beijing +lions +andre +fictional +gathering +comfort +radar +suitable +dismissed +hms +ban +pine +wrist +atmosphere +voivodeship +bid +timber +##ned +giants +cameron +recovery +uss +identical +categories +switched +serbia +laughter +noah +ensemble +therapy +peoples +touching +##off +locally +pearl +platforms +everywhere +ballet +tables +lanka +herbert +outdoor +toured +derek +1883 +spaces +contested +swept +1878 +exclusive +slight +connections +winds +prisoner +collective +bangladesh +tube +publicly +wealthy +isolated +insisted +fortune +ticket +spotted +reportedly +animation +enforcement +tanks +decides +wider +lowest +owen +nod +hitting +gregory +furthermore +magazines +fighters +solutions +pointing +requested +peru +reed +chancellor +knights +mask +worker +eldest +flames +reduction +volunteers +reporting +wire +advisory +endemic +origins +settlers +pursue +knock +consumer +1876 +eu +compound +creatures +mansion +sentenced +ivan +deployed +guitars +frowned +involves +mechanism +kilometers +perspective +shops +terminus +duncan +alien +fist +bridges +##pers +heroes +derby +swallowed +patent +sara +illness +characterized +adventures +slide +hawaii +jurisdiction +organised +adelaide +walks +biology +rogers +swing +tightly +boundaries +prepare +implementation +stolen +certified +colombia +edwards +garage +recalled +rage +harm +nigeria +breast +furniture +pupils +settle +cuba +balls +alaska +21st +linear +thrust +celebration +latino +genetic +terror +##ening +lightning +fee +witness +lodge +establishing +skull +earning +hood +rebellion +sporting +warned +missile +devoted +activist +porch +worship +fourteen +package +decorated +##shire +housed +chess +sailed +doctors +oscar +joan +treat +garcia +harbour +jeremy +traditions +dominant +jacques +##gon +relocated +1879 +amendment +sized +companion +simultaneously +volleyball +spun +acre +increases +stopping +loves +belongs +affect +drafted +tossed +scout +battles +1875 +filming +shoved +munich +tenure +vertical +romance +argue +craft +ranging +opens +honest +tyler +yesterday +muslims +reveal +snake +immigrants +radical +screaming +speakers +firing +saving +belonging +ease +lighting +prefecture +blame +farmer +hungry +grows +rubbed +beam +sur +subsidiary +armenian +dropping +conventional +qualify +spots +sweat +festivals +immigration +physician +discover +exposure +sandy +explanation +isaac +implemented +##fish +hart +initiated +stakes +presents +heights +householder +pleased +tourist +regardless +slip +closest +surely +sultan +brings +riley +preparation +aboard +slammed +baptist +experiment +ongoing +interstate +organic +playoffs +1877 +hindu +tours +tier +plenty +arrangements +talks +trapped +excited +sank +athens +1872 +denver +welfare +suburb +athletes +trick +diverse +belly +exclusively +yelled +conversion +1874 +internationally +computers +conductor +abilities +sensitive +dispute +measured +globe +rocket +prices +amsterdam +flights +tigers +municipalities +emotion +references +explains +airlines +manufactured +archaeological +1873 +interpretation +devon +##ites +settlements +kissing +absolute +improvement +impressed +barcelona +sullivan +jefferson +towers +jesse +julie +grandson +gauge +regard +rings +interviews +trace +raymond +thumb +departments +burns +serial +bulgarian +scores +demonstrated +1866 +kyle +alberta +underneath +romanized +relieved +acquisition +phrase +cliff +reveals +cuts +merger +custom +nee +gilbert +graduation +assessment +difficulty +demands +swung +democrat +commons +1940s +grove +completing +focuses +sum +substitute +bearing +stretch +reception +reflected +essentially +destination +pairs +##ched +survival +resource +##bach +promoting +doubles +messages +tear +##fully +parade +florence +harvey +incumbent +partial +pedro +frozen +procedure +olivia +controls +shelter +personally +temperatures +brisbane +tested +sits +marble +comprehensive +oxygen +leonard +##kov +inaugural +iranian +referring +quarters +attitude +mainstream +lined +mars +dakota +norfolk +unsuccessful +explosion +helicopter +congressional +##sing +inspector +bitch +seal +departed +divine +coaching +examination +punishment +manufacturer +sink +columns +unincorporated +signals +nevada +squeezed +dylan +dining +martial +manuel +eighteen +elevator +brushed +plates +ministers +congregation +slept +specialized +taxes +restricted +negotiations +likes +statistical +arnold +inspiration +execution +bold +intermediate +significance +margin +ruler +wheels +gothic +intellectual +dependent +listened +eligible +buses +widow +syria +earn +cincinnati +collapsed +recipient +secrets +accessible +philippine +maritime +goddess +clerk +surrender +breaks +playoff +ideal +beetle +aspect +soap +regulation +strings +expand +anglo +shorter +crosses +retreat +tough +coins +wallace +directions +pressing +shipping +locomotives +comparison +topics +nephew +distinction +honors +travelled +sierra +ibn +fortress +recognised +carved +1869 +clients +intent +coaches +describing +bread +##ington +beaten +northwestern +merit +collapse +challenges +historians +objective +submitted +virus +attacking +drake +assume +diseases +stem +leeds +farming +glasses +visits +nowhere +fellowship +relevant +carries +restaurants +experiments +constantly +bases +targets +shah +tenth +opponents +verse +territorial +writings +corruption +instruction +inherited +reverse +emphasis +employee +arch +keeps +rabbi +watson +payment +uh +nancy +##tre +venice +fastest +sexy +banned +adrian +properly +ruth +touchdown +dollar +boards +metre +circles +edges +favour +travels +liberation +scattered +firmly +holland +permitted +diesel +kenya +den +originated +demons +resumed +dragged +rider +servant +blinked +extend +torn +##sey +input +meal +everybody +cylinder +kinds +camps +bullet +logic +croatian +evolved +healthy +fool +wise +preserve +pradesh +respective +artificial +gross +corresponding +convicted +cage +caroline +dialogue +##dor +narrative +stranger +mario +christianity +failing +trent +commanding +buddhist +1848 +maurice +focusing +yale +bike +altitude +mouse +revised +##sley +veteran +pulls +theology +crashed +campaigns +legion +##ability +drag +excellence +customer +cancelled +intensity +excuse +liga +participating +contributing +printing +##burn +variable +curious +legacy +renaissance +symptoms +binding +vocalist +dancer +grammar +gospel +democrats +enters +diplomatic +hitler +clouds +mathematical +quit +defended +oriented +##heim +fundamental +hardware +impressive +equally +convince +confederate +guilt +chuck +sliding +magnetic +narrowed +petersburg +bulgaria +otto +phd +skill +hopes +pitcher +reservoir +hearts +automatically +expecting +mysterious +bennett +extensively +imagined +seeds +monitor +fix +##ative +journalism +struggling +signature +ranch +encounter +photographer +observation +protests +influences +calendar +cruz +croatia +locomotive +hughes +naturally +shakespeare +basement +hook +uncredited +faded +theories +approaches +dare +phillips +filling +fury +obama +efficient +arc +deliver +breeding +inducted +leagues +efficiency +axis +montana +eagles +##ked +supplied +instructions +karen +picking +indicating +trap +anchor +practically +christians +tomb +vary +occasional +electronics +lords +readers +newcastle +faint +innovation +collect +situations +engagement +claude +mixture +##feld +peer +tissue +lean +°f +floors +architects +reducing +rope +1859 +ottawa +##har +samples +banking +declaration +proteins +resignation +francois +saudi +advocate +exhibited +armor +twins +divorce +##ras +abraham +reviewed +temporarily +matrix +physically +pulse +curled +difficulties +bengal +usage +##ban +riders +certificate +holes +warsaw +distinctive +mutual +1857 +customs +circular +eugene +removal +loaded +mere +vulnerable +depicted +generations +dame +heir +enormous +lightly +climbing +pitched +lessons +pilots +nepal +preparing +brad +louise +renowned +liam +##ably +shaw +brilliant +bills +##nik +fucking +mainland +pleasant +seized +veterans +jerked +fail +brush +radiation +stored +warmth +southeastern +nate +sin +raced +berkeley +joke +athlete +designation +trunk +roland +qualification +heels +artwork +receives +judicial +reserves +##bed +woke +installation +abu +floating +fake +lesser +excitement +interface +concentrated +addressed +characteristic +amanda +saxophone +monk +releasing +egg +dies +interaction +defender +outbreak +glory +loving +sequel +consciousness +awake +ski +enrolled +handling +rookie +brow +somebody +biography +warfare +amounts +contracts +presentation +fabric +dissolved +challenged +meter +psychological +elevated +rally +accurate +##tha +hospitals +undergraduate +specialist +venezuela +exhibit +shed +nursing +protestant +fluid +structural +footage +jared +consistent +prey +##ska +succession +reflect +exile +lebanon +wiped +suspect +shanghai +resting +integration +preservation +marvel +variant +pirates +sheep +rounded +capita +sailing +colonies +manuscript +deemed +variations +clarke +functional +emerging +boxing +relaxed +curse +azerbaijan +heavyweight +nickname +editorial +rang +grid +tightened +earthquake +flashed +miguel +rushing +##ches +improvements +boxes +brooks +consumption +molecular +felix +societies +repeatedly +variation +aids +civic +graphics +professionals +realm +autonomous +receiver +delayed +workshop +militia +chairs +canyon +harsh +extending +lovely +happiness +##jan +stake +eyebrows +embassy +wellington +hannah +corners +bishops +swear +cloth +contents +namely +commenced +1854 +stanford +nashville +courage +graphic +commitment +garrison +hamlet +clearing +rebels +attraction +literacy +cooking +ruins +temples +jenny +humanity +celebrate +hasn +freight +sixty +rebel +bastard +newton +deer +##ges +##ching +smiles +delaware +singers +approaching +assists +flame +boulevard +barrel +planted +pursuit +consequences +shallow +invitation +rode +depot +ernest +kane +rod +concepts +preston +topic +chambers +striking +blast +arrives +descendants +montgomery +ranges +worlds +chaos +praise +fewer +1855 +sanctuary +mud +programmes +maintaining +harper +bore +handsome +closure +tournaments +nebraska +linda +facade +puts +satisfied +argentine +dale +cork +dome +panama +##yl +1858 +tasks +experts +##ates +feeding +equation +engage +bryan +um +quartet +disbanded +sheffield +blocked +gasped +delay +kisses +connects +##non +sts +poured +creator +publishers +guided +ellis +extinct +hug +gaining +##ord +complicated +poll +clenched +investigate +thereby +quantum +spine +cdp +humor +kills +administered +semifinals +encountered +ignore +commentary +##maker +bother +roosevelt +plains +halfway +flowing +cultures +crack +imprisoned +neighboring +airline +gather +wolves +marathon +transformed +cruise +organisations +punch +exhibitions +numbered +alarm +ratings +daddy +silently +##stein +queens +colours +impression +guidance +tactical +##rat +marshal +della +arrow +rested +feared +tender +owns +bitter +advisor +escort +##ides +spare +farms +grants +dragons +encourage +colleagues +cameras +sucked +pile +spirits +prague +statements +suspension +landmark +fence +torture +recreation +bags +permanently +survivors +pond +spy +predecessor +bombing +coup +protecting +transformation +glow +##lands +dug +priests +andrea +feat +barn +jumping +##ologist +casualties +stern +auckland +pipe +serie +revealing +trevor +mercy +spectrum +consist +governing +collaborated +possessed +epic +comprises +blew +shane +lopez +honored +magical +sacrifice +judgment +perceived +hammer +baronet +tune +das +missionary +sheets +neutral +oral +threatening +attractive +shade +aims +seminary +estates +1856 +michel +wounds +refugees +manufacturers +mercury +syndrome +porter +##iya +##din +hamburg +identification +upstairs +purse +widened +pause +cared +breathed +affiliate +santiago +prevented +celtic +fisher +recruited +byzantine +reconstruction +farther +diet +sake +spite +sensation +blank +separation +##hon +vladimir +armies +anime +accommodate +orbit +cult +sofia +##ify +founders +sustained +disorder +honours +northeastern +mia +crops +violet +threats +blanket +fires +canton +followers +southwestern +prototype +voyage +assignment +altered +moderate +protocol +pistol +questioned +brass +lifting +1852 +math +authored +doug +dimensional +dynamic +1851 +pronounced +grateful +quest +uncomfortable +boom +presidency +stevens +relating +politicians +barrier +quinn +diana +mosque +tribal +palmer +portions +sometime +chester +treasure +bend +millions +reforms +registration +consequently +monitoring +ate +preliminary +brandon +invented +eaten +exterior +intervention +ports +documented +displays +lecture +sally +favourite +vermont +invisible +isle +breed +journalists +relay +speaks +backward +explore +midfielder +actively +stefan +procedures +cannon +blond +kenneth +centered +servants +chains +libraries +malcolm +essex +henri +slavery +##hal +facts +fairy +coached +cassie +cats +washed +cop +announcement +2000s +vinyl +activated +marco +frontier +growled +curriculum +##das +loyal +accomplished +leslie +ritual +kenny +vii +napoleon +hollow +hybrid +jungle +stationed +friedrich +counted +##ulated +platinum +theatrical +seated +col +rubber +glen +diversity +healing +extends +provisions +administrator +columbus +tributary +assured +##uous +prestigious +examined +lectures +grammy +ronald +associations +bailey +allan +essays +flute +believing +consultant +proceedings +travelling +1853 +kerala +yugoslavia +buddy +methodist +burial +centres +batman +discontinued +dock +stockholm +lungs +severely +citing +manga +steal +mumbai +iraqi +robot +celebrity +bride +broadcasts +abolished +pot +joel +overhead +franz +packed +reconnaissance +johann +acknowledged +introduce +handled +doctorate +developments +drinks +alley +palestine +##aki +proceeded +recover +bradley +grain +patch +afford +infection +nationalist +legendary +interchange +virtually +gen +gravity +exploration +amber +vital +wishes +powell +doctrine +elbow +screenplay +##bird +contribute +indonesian +creates +enzyme +kylie +discipline +drops +manila +hunger +layers +suffer +fever +bits +monica +keyboard +manages +##hood +searched +appeals +##bad +testament +grande +reid +##war +beliefs +congo +requiring +casey +1849 +regret +streak +rape +depends +syrian +sprint +pound +tourists +upcoming +pub +tense +##els +practiced +nationwide +guild +motorcycle +liz +##zar +chiefs +desired +elena +precious +absorbed +relatives +booth +pianist +##mal +citizenship +exhausted +wilhelm +##ceae +##hed +noting +quarterback +urge +hectares +##gue +holly +blonde +davies +parked +sustainable +stepping +twentieth +airfield +nest +chip +##nell +shaft +paulo +requirement +paradise +tobacco +trans +renewed +vietnamese +suggesting +catching +holmes +enjoying +trips +colt +holder +butterfly +nerve +reformed +cherry +bowling +trailer +carriage +goodbye +appreciate +toy +joshua +interactive +enabled +involve +##kan +collar +determination +bunch +recall +shorts +superintendent +episcopal +frustration +giovanni +nineteenth +laser +privately +array +circulation +##ovic +armstrong +deals +painful +permit +discrimination +aires +retiring +cottage +horizon +ellen +jamaica +ripped +fernando +chapters +patron +lecturer +behaviour +genes +georgian +export +solomon +rivals +seventeen +rodriguez +princeton +independently +sox +1847 +arguing +entity +casting +hank +criteria +oakland +geographic +milwaukee +reflection +expanding +conquest +dubbed +halt +brave +brunswick +arched +curtis +divorced +predominantly +somerset +streams +ugly +zoo +horrible +curved +buenos +fierce +dictionary +vector +theological +unions +handful +stability +punjab +segments +altar +ignoring +gesture +monsters +pastor +thighs +unexpected +operators +abruptly +coin +compiled +associates +improving +migration +compact +collegiate +quarterfinals +roster +restore +assembled +hurry +oval +##cies +1846 +flags +martha +victories +sharply +##rated +argues +deadly +drawings +symbols +performer +griffin +restrictions +editing +andrews +journals +arabia +compositions +dee +pierce +removing +hindi +casino +runway +civilians +minds +##zation +refuge +rent +retain +potentially +conferences +suburban +conducting +descended +massacre +ammunition +terrain +fork +souls +counts +chelsea +durham +drives +cab +perth +realizing +palestinian +finn +simpson +##dal +betty +moreover +particles +cardinals +tent +evaluation +extraordinary +inscription +wednesday +chloe +maintains +panels +ashley +trucks +##nation +cluster +sunlight +strikes +zhang +dialect +tucked +collecting +##mas +##sville +quoted +evan +franco +aria +buying +cleaning +closet +provision +apollo +clinic +rat +necessarily +##ising +venues +flipped +cent +spreading +trustees +checking +authorized +disappointed +##ado +notion +duration +trumpet +hesitated +topped +brussels +rolls +theoretical +hint +define +aggressive +repeat +wash +peaceful +optical +width +allegedly +mcdonald +strict +##illa +investors +jam +witnesses +sounding +miranda +michelle +hugo +harmony +valid +lynn +glared +nina +headquartered +diving +boarding +gibson +albanian +marsh +routine +dealt +enhanced +intelligent +substance +targeted +enlisted +discovers +spinning +observations +pissed +smoking +capitol +varied +costume +seemingly +indies +compensation +surgeon +thursday +arsenal +westminster +suburbs +rid +anglican +##ridge +knots +foods +alumni +lighter +fraser +whoever +portal +scandal +gavin +advised +instructor +flooding +terrorist +teenage +interim +senses +duck +teen +thesis +abby +eager +overcome +newport +glenn +rises +shame +prompted +priority +forgot +bomber +nicolas +protective +cartoon +katherine +breeze +lonely +trusted +henderson +richardson +relax +palms +remarkable +legends +cricketer +essay +ordained +edmund +rifles +trigger +##uri +##away +sail +alert +1830 +audiences +penn +sussex +siblings +pursued +indianapolis +resist +rosa +consequence +succeed +avoided +1845 +##ulation +inland +##tie +##nna +counsel +profession +chronicle +hurried +##una +eyebrow +eventual +bleeding +innovative +cure +committees +accounting +scope +hardy +heather +tenor +gut +herald +codes +tore +scales +wagon +luxury +tin +prefer +fountain +triangle +bonds +darling +convoy +dried +traced +beings +troy +accidentally +slam +findings +smelled +joey +lawyers +outcome +steep +bosnia +configuration +shifting +toll +brook +performers +lobby +philosophical +construct +shrine +aggregate +cox +phenomenon +savage +insane +solely +reynolds +nationally +holdings +consideration +enable +edgar +fights +relegation +chances +atomic +hub +conjunction +awkward +reactions +currency +finale +kumar +underwent +steering +elaborate +gifts +comprising +melissa +veins +reasonable +sunshine +solve +trails +inhabited +elimination +ethics +huh +ana +molly +consent +apartments +layout +marines +hunters +bulk +##oma +hometown +##wall +##mont +cracked +reads +neighbouring +withdrawn +admission +wingspan +damned +anthology +lancashire +brands +batting +forgive +cuban +awful +##lyn +dimensions +imagination +dante +tracking +desperately +goalkeeper +##yne +groaned +workshops +confident +burton +gerald +milton +circus +uncertain +slope +copenhagen +sophia +fog +philosopher +portraits +accent +cycling +varying +gripped +larvae +garrett +specified +scotia +mature +luther +kurt +rap +##kes +aerial +ferdinand +heated +transported +##shan +safely +nonetheless +##orn +##gal +motors +demanding +##sburg +startled +##brook +ally +generate +caps +ghana +stained +mentions +beds +afterward +##bling +utility +##iro +richards +1837 +conspiracy +conscious +shining +footsteps +observer +cyprus +urged +loyalty +developer +probability +olive +upgraded +gym +miracle +insects +graves +1844 +ourselves +hydrogen +katie +tickets +poets +planes +prevention +witnessed +dense +jin +randy +tang +warehouse +monroe +archived +elderly +investigations +alec +granite +mineral +conflicts +controlling +aboriginal +mechanics +stan +stark +rhode +skirt +est +bombs +respected +##horn +imposed +limestone +deny +nominee +memphis +grabbing +disabled +amusement +frankfurt +corn +referendum +varies +slowed +disk +firms +unconscious +incredible +clue +sue +##zhou +twist +##cio +joins +idaho +chad +developers +computing +destroyer +mortal +tucker +kingston +choices +carson +whitney +geneva +pretend +dimension +staged +plateau +maya +##une +freestyle +rovers +##ids +tristan +classroom +prospect +##hus +honestly +diploma +lied +thermal +auxiliary +feast +unlikely +iata +morocco +pounding +treasury +lithuania +considerably +1841 +dish +1812 +geological +matching +stumbled +destroying +marched +brien +advances +nicole +settling +measuring +directing +##mie +tuesday +bassist +capabilities +stunned +fraud +torpedo +##phone +anton +wisdom +surveillance +ruined +##ulate +lawsuit +healthcare +theorem +halls +trend +aka +horizontal +dozens +acquire +lasting +swim +hawk +gorgeous +fees +vicinity +decrease +adoption +tactics +##ography +pakistani +##ole +draws +##hall +willie +burke +heath +algorithm +integral +powder +elliott +brigadier +jackie +tate +varieties +darker +##cho +lately +cigarette +specimens +adds +##ensis +##inger +exploded +finalist +murders +wilderness +arguments +nicknamed +acceptance +onwards +manufacture +robertson +jets +tampa +enterprises +loudly +composers +nominations +1838 +malta +inquiry +automobile +hosting +viii +rays +tilted +grief +museums +strategies +furious +euro +equality +cohen +poison +surrey +wireless +governed +ridiculous +moses +##esh +vanished +barnes +attract +morrison +istanbul +##iness +absent +rotation +petition +janet +##logical +satisfaction +custody +deliberately +observatory +comedian +surfaces +pinyin +novelist +strictly +canterbury +oslo +monks +embrace +jealous +photograph +continent +dorothy +marina +excess +holden +allegations +explaining +stack +avoiding +lance +storyline +majesty +poorly +spike +bradford +raven +travis +classics +proven +voltage +pillow +fists +butt +1842 +interpreted +1839 +gage +telegraph +lens +promising +expelled +casual +collector +zones +silly +nintendo +##kh +downstairs +chef +suspicious +afl +flies +vacant +uganda +pregnancy +condemned +lutheran +estimates +cheap +decree +saxon +proximity +stripped +idiot +deposits +contrary +presenter +magnus +glacier +offense +edwin +##ori +upright +##long +bolt +##ois +toss +geographical +##izes +environments +delicate +marking +abstract +xavier +nails +windsor +plantation +occurring +equity +saskatchewan +fears +drifted +sequences +vegetation +revolt +##stic +1843 +sooner +fusion +opposing +nato +skating +1836 +secretly +ruin +lease +flora +anxiety +##ological +##mia +bout +taxi +emmy +frost +rainbow +compounds +foundations +rainfall +assassination +nightmare +dominican +achievements +deserve +orlando +intact +armenia +##nte +calgary +valentine +marion +proclaimed +theodore +bells +courtyard +thigh +gonzalez +console +troop +minimal +everyday +supporter +terrorism +buck +openly +presbyterian +activists +carpet +##iers +rubbing +uprising +cute +conceived +legally +##cht +millennium +cello +velocity +rescued +cardiff +1835 +rex +concentrate +senators +beard +rendered +glowing +battalions +scouts +competitors +sculptor +catalogue +arctic +ion +raja +bicycle +glancing +lawn +##woman +gentleman +lighthouse +publish +predicted +calculated +variants +##gne +strain +winston +deceased +touchdowns +brady +caleb +sinking +echoed +crush +hon +blessed +protagonist +hayes +endangered +magnitude +editors +##tine +estimate +responsibilities +##mel +backup +laying +consumed +sealed +zurich +lovers +frustrated +##eau +ahmed +kicking +treasurer +1832 +biblical +refuse +terrified +pump +agrees +genuine +imprisonment +refuses +plymouth +lou +##nen +tara +trembling +antarctic +ton +learns +##tas +crap +crucial +faction +atop +##borough +wrap +lancaster +odds +hopkins +erik +lyon +##eon +bros +snap +locality +empress +crowned +cal +acclaimed +chuckled +clara +sends +mild +towel +wishing +assuming +interviewed +##bal +interactions +eden +cups +helena +indie +beck +##fire +batteries +filipino +wizard +parted +traces +##born +rows +idol +albany +delegates +##ees +##sar +discussions +notre +instructed +belgrade +highways +suggestion +lauren +possess +orientation +alexandria +abdul +beats +salary +reunion +ludwig +alright +wagner +intimate +pockets +slovenia +hugged +brighton +merchants +cruel +stole +trek +slopes +repairs +enrollment +politically +underlying +promotional +counting +boeing +isabella +naming +keen +bacteria +listing +separately +belfast +ussr +lithuanian +anybody +ribs +sphere +martinez +cock +embarrassed +proposals +fragments +nationals +##wski +premises +fin +alpine +matched +freely +bounded +jace +sleeve +pier +populated +evident +##like +frances +flooded +##dle +frightened +pour +trainer +framed +visitor +challenging +pig +wickets +##fold +infected +##pes +arose +reward +ecuador +oblast +vale +shuttle +##usa +bach +rankings +forbidden +cornwall +accordance +salem +consumers +bruno +fantastic +toes +machinery +resolved +julius +remembering +propaganda +iceland +bombardment +tide +contacts +wives +##rah +concerto +macdonald +albania +implement +daisy +tapped +sudan +helmet +mistress +crop +sunk +finest +##craft +hostile +boxer +fr +paths +adjusted +habit +ballot +supervision +soprano +bullets +wicked +sunset +regiments +disappear +lamp +performs +##gia +rabbit +digging +incidents +entries +##cion +dishes +introducing +##ati +##fied +freshman +slot +jill +tackles +baroque +backs +##iest +lone +sponsor +destiny +altogether +convert +##aro +consensus +shapes +demonstration +basically +feminist +auction +artifacts +##bing +strongest +halifax +allmusic +mighty +smallest +precise +alexandra +viola +##los +##ille +manuscripts +##illo +dancers +ari +managers +monuments +blades +barracks +springfield +maiden +consolidated +electron +berry +airing +wheat +nobel +inclusion +blair +payments +geography +bee +eleanor +react +##hurst +afc +manitoba +lineup +fitness +recreational +investments +airborne +disappointment +##dis +edmonton +viewing +renovation +infant +bankruptcy +roses +aftermath +pavilion +carpenter +withdrawal +ladder +discussing +popped +reliable +agreements +rochester +##abad +curves +bombers +rao +reverend +decreased +choosing +stiff +consulting +naples +crawford +tracy +ribbon +cops +crushed +deciding +unified +teenager +accepting +flagship +poles +sanchez +inspection +revived +skilled +induced +exchanged +flee +locals +tragedy +swallow +hanna +demonstrate +##ela +salvador +flown +contestants +civilization +##ines +wanna +rhodes +fletcher +hector +knocking +considers +nash +mechanisms +sensed +mentally +walt +unclear +##eus +renovated +madame +crews +governmental +undertaken +monkey +##ben +##ato +fatal +armored +copa +caves +governance +grasp +perception +certification +froze +damp +tugged +wyoming +##rg +##ero +newman +nerves +curiosity +graph +##ami +withdraw +tunnels +dull +meredith +moss +exhibits +neighbors +communicate +accuracy +explored +raiders +republicans +secular +kat +superman +penny +criticised +freed +conviction +ham +likewise +delegation +gotta +doll +promises +technological +myth +nationality +resolve +convent +sharon +dig +sip +coordinator +entrepreneur +fold +##dine +capability +councillor +synonym +blown +swan +cursed +1815 +jonas +haired +sofa +canvas +keeper +rivalry +##hart +rapper +speedway +swords +postal +maxwell +estonia +potter +recurring +errors +##oni +cognitive +1834 +claws +nadu +roberto +bce +wrestler +ellie +infinite +ink +##tia +presumably +finite +staircase +noel +patricia +nacional +chill +eternal +tu +preventing +prussia +fossil +limbs +##logist +ernst +frog +perez +rene +prussian +##ios +molecules +regulatory +answering +opinions +sworn +lengths +supposedly +hypothesis +upward +habitats +seating +ancestors +drank +yield +synthesis +researcher +modest +##var +mothers +peered +voluntary +homeland +acclaim +##igan +static +valve +luxembourg +alto +carroll +receptor +norton +ambulance +##tian +johnston +catholics +depicting +jointly +elephant +gloria +mentor +badge +ahmad +distinguish +remarked +councils +precisely +allison +advancing +detection +crowded +cooperative +ankle +mercedes +dagger +surrendered +pollution +commit +subway +jeffrey +lesson +sculptures +provider +##fication +membrane +timothy +rectangular +fiscal +heating +teammate +basket +particle +anonymous +deployment +missiles +courthouse +proportion +shoe +sec +complaints +forbes +blacks +abandon +remind +sizes +overwhelming +autobiography +natalie +##awa +risks +contestant +countryside +babies +scorer +invaded +enclosed +proceed +hurling +disorders +##cu +reflecting +continuously +cruiser +graduates +freeway +investigated +ore +deserved +maid +blocking +phillip +jorge +shakes +dove +mann +variables +lacked +burden +accompanying +que +consistently +organizing +provisional +complained +endless +tubes +juice +georges +krishna +mick +thriller +laps +arcade +sage +snail +shannon +laurence +seoul +vacation +presenting +hire +churchill +surprisingly +prohibited +savannah +technically +##oli +##lessly +testimony +suited +speeds +toys +romans +flowering +measurement +talented +kay +settings +charleston +expectations +shattered +achieving +triumph +ceremonies +portsmouth +lanes +mandatory +loser +stretching +cologne +realizes +seventy +cornell +careers +webb +##ulating +americas +budapest +ava +suspicion +yo +conrad +sterling +jessie +rector +##az +1831 +transform +organize +loans +christine +volcanic +warrant +slender +summers +subfamily +newer +danced +dynamics +rhine +proceeds +heinrich +gastropod +commands +sings +facilitate +easter +positioned +responses +expense +fruits +yanked +imported +25th +velvet +vic +primitive +tribune +baldwin +neighbourhood +donna +rip +hay +##uro +1814 +espn +welcomed +##aria +qualifier +glare +highland +timing +##cted +shells +eased +geometry +louder +exciting +slovakia +##iz +savings +prairie +marching +rafael +tonnes +##lled +curtain +preceding +shy +heal +greene +worthy +##pot +detachment +bury +sherman +##eck +reinforced +seeks +bottles +contracted +duchess +outfit +walsh +mickey +geoffrey +archer +squeeze +dawson +eliminate +invention +##enberg +neal +##eth +stance +dealer +coral +maple +retire +simplified +1833 +hid +watts +backwards +jules +##oke +genesis +frames +rebounds +burma +woodland +moist +santos +whispers +drained +subspecies +streaming +ulster +burnt +correspondence +maternal +gerard +denis +stealing +genius +duchy +##oria +inaugurated +momentum +suits +placement +sovereign +clause +thames +##hara +confederation +reservation +sketch +yankees +lets +rotten +charm +hal +verses +commercially +dot +salon +citation +adopt +winnipeg +mist +allocated +cairo +jenkins +interference +objectives +##wind +1820 +portfolio +armoured +sectors +initiatives +integrity +exercises +robe +tap +gazed +##tones +distracted +rulers +favorable +jerome +tended +cart +factories +##eri +diplomat +valued +gravel +charitable +calvin +exploring +shepherd +terrace +pupil +##ural +reflects +##rch +governors +shelf +depths +##nberg +trailed +crest +tackle +##nian +hatred +##kai +clare +makers +ethiopia +longtime +detected +embedded +lacking +slapped +rely +thomson +anticipation +morton +successive +agnes +screenwriter +straightened +philippe +playwright +haunted +licence +iris +intentions +sutton +logical +correctly +##weight +branded +licked +tipped +silva +ricky +narrator +requests +##ents +greeted +supernatural +cow +##wald +lung +refusing +employer +strait +gaelic +liner +##piece +zoe +sabha +##mba +driveway +harvest +prints +bates +reluctantly +threshold +algebra +ira +wherever +coupled +assumption +picks +designers +raids +gentlemen +roller +blowing +leipzig +locks +screw +dressing +strand +##lings +scar +dwarf +depicts +##nu +nods +differ +boris +##eur +yuan +flip +##gie +mob +invested +questioning +applying +shout +##sel +gameplay +blamed +illustrations +bothered +weakness +rehabilitation +##zes +envelope +rumors +miners +leicester +subtle +kerry +ferguson +premiership +bengali +prof +catches +remnants +dana +##rily +shouting +presidents +baltic +ought +ghosts +dances +sailors +shirley +fancy +dominic +##bie +madonna +##rick +bark +buttons +gymnasium +ashes +liver +toby +oath +providence +doyle +evangelical +nixon +cement +carnegie +embarked +hatch +surroundings +guarantee +needing +pirate +essence +filter +crane +hammond +projected +immune +percy +twelfth +regent +doctoral +damon +mikhail +##ichi +critically +elect +realised +abortion +acute +screening +mythology +steadily +frown +nottingham +kirk +wa +minneapolis +##rra +module +algeria +nautical +encounters +surprising +statues +availability +shirts +pie +alma +brows +munster +mack +soup +crater +tornado +sanskrit +cedar +explosive +bordered +dixon +planets +stamp +exam +happily +##bble +carriers +kidnapped +accommodation +emigrated +##met +knockout +correspondent +violation +profits +peaks +lang +specimen +agenda +ancestry +pottery +spelling +equations +obtaining +ki +linking +1825 +debris +asylum +buddhism +##ants +gazette +dental +eligibility +fathers +averaged +zimbabwe +francesco +coloured +hissed +translator +lynch +mandate +humanities +mackenzie +uniforms +##iana +asset +fitting +samantha +genera +rim +beloved +shark +riot +entities +expressions +indo +carmen +slipping +owing +abbot +neighbor +sidney +rats +recommendations +encouraging +squadrons +anticipated +commanders +conquered +donations +diagnosed +divide +##iva +guessed +decoration +vernon +auditorium +revelation +conversations +##kers +##power +herzegovina +dash +alike +protested +lateral +herman +accredited +##gent +freeman +mel +fiji +crow +crimson +##rine +livestock +##pped +humanitarian +bored +oz +whip +##lene +##ali +legitimate +alter +grinning +spelled +anxious +oriental +wesley +##nin +##hole +carnival +controller +detect +##ssa +bowed +educator +kosovo +macedonia +##sin +occupy +mastering +stephanie +janeiro +para +unaware +nurses +noon +hopefully +ranger +combine +sociology +polar +rica +##eer +neill +##sman +holocaust +doubled +lust +1828 +decent +cooling +unveiled +1829 +nsw +homer +chapman +meyer +dive +mae +reagan +expertise +##gled +darwin +brooke +sided +prosecution +investigating +comprised +petroleum +genres +reluctant +differently +trilogy +johns +vegetables +corpse +highlighted +lounge +pension +unsuccessfully +elegant +aided +ivory +beatles +amelia +cain +dubai +immigrant +babe +underwater +combining +mumbled +atlas +horns +accessed +ballad +physicians +homeless +gestured +rpm +freak +louisville +corporations +patriots +prizes +rational +warn +modes +decorative +overnight +din +troubled +phantom +monarch +sheer +##dorf +generals +guidelines +organs +addresses +enhance +curling +parishes +cord +##kie +caesar +deutsche +bavaria +coleman +cyclone +##eria +bacon +petty +##yama +##old +hampton +diagnosis +1824 +throws +complexity +rita +disputed +pablo +marketed +trafficking +##ulus +examine +plague +formats +vault +faithful +##bourne +webster +highlights +##ient +phones +vacuum +sandwich +modeling +##gated +bolivia +clergy +qualities +isabel +##nas +##ars +wears +screams +reunited +annoyed +bra +##ancy +##rate +differential +transmitter +tattoo +container +poker +##och +excessive +resides +cowboys +##tum +augustus +trash +providers +statute +retreated +balcony +reversed +void +storey +preceded +masses +leap +laughs +neighborhoods +wards +schemes +falcon +santo +battlefield +ronnie +lesbian +venus +##dian +beg +sandstone +daylight +punched +gwen +analog +stroked +wwe +acceptable +measurements +toxic +##kel +adequate +surgical +economist +parameters +varsity +##sberg +quantity +##chy +##rton +countess +generating +precision +diamonds +expressway +##ı +1821 +uruguay +talents +galleries +expenses +scanned +colleague +outlets +ryder +lucien +##ila +paramount +syracuse +dim +fangs +gown +sweep +##sie +missionaries +websites +sentences +adviser +val +trademark +spells +##plane +patience +starter +slim +##borg +toe +incredibly +shoots +elliot +nobility +##wyn +cowboy +endorsed +gardner +tendency +persuaded +organisms +emissions +kazakhstan +amused +boring +chips +themed +##hand +constantinople +chasing +systematic +guatemala +borrowed +erin +carey +##hard +highlands +struggles +1810 +##ifying +##ced +exceptions +develops +enlarged +kindergarten +castro +##rina +leigh +zombie +juvenile +##most +consul +sailor +hyde +clarence +intensive +pinned +nasty +useless +jung +clayton +stuffed +exceptional +ix +apostolic +transactions +exempt +swinging +cove +religions +shields +dairy +bypass +pursuing +joyce +bombay +chassis +southampton +chat +interact +redesignated +##pen +nascar +pray +salmon +rigid +regained +malaysian +grim +publicity +constituted +capturing +toilet +delegate +purely +tray +drift +loosely +striker +weakened +trinidad +mitch +itv +defines +transmitted +scarlet +nodding +fitzgerald +narrowly +tooth +standings +virtue +##wara +##cting +chateau +gloves +lid +hurting +conservatory +##pel +sinclair +reopened +sympathy +nigerian +strode +advocated +optional +chronic +discharge +suck +compatible +laurel +stella +fails +wage +dodge +informal +sorts +levi +buddha +villagers +chronicles +heavier +summoned +gateway +eleventh +jewelry +translations +accordingly +seas +##ency +fiber +pyramid +cubic +dragging +##ista +caring +##ops +contacted +lunar +lisbon +patted +1826 +sacramento +theft +madagascar +subtropical +disputes +holidays +piper +willow +mare +cane +newfoundland +benny +companions +dong +raj +observe +roar +charming +plaque +tibetan +fossils +enacted +manning +bubble +tanzania +##eda +##hir +funk +swamp +deputies +cloak +ufc +scenario +par +scratch +metals +anthem +guru +engaging +specially +##boat +dialects +nineteen +cecil +duet +disability +unofficial +##lies +defunct +moonlight +drainage +surname +puzzle +switching +conservatives +mammals +knox +broadcaster +sidewalk +cope +##ried +benson +princes +peterson +##sal +bedford +sharks +eli +wreck +alberto +gasp +archaeology +lgbt +teaches +securities +madness +compromise +waving +coordination +davidson +visions +leased +possibilities +eighty +fernandez +enthusiasm +assassin +sponsorship +reviewer +kingdoms +estonian +laboratories +##fy +##nal +applies +verb +celebrations +##zzo +rowing +lightweight +sadness +submit +balanced +dude +explicitly +metric +magnificent +mound +brett +mohammad +mistakes +irregular +sanders +betrayed +shipped +surge +##enburg +reporters +termed +georg +pity +verbal +bulls +abbreviated +enabling +appealed +sicily +sting +heel +sweetheart +bart +spacecraft +brutal +monarchy +aberdeen +cameo +diane +survivor +clyde +##aries +complaint +##makers +clarinet +delicious +chilean +karnataka +coordinates +1818 +panties +##rst +pretending +dramatically +kiev +tends +distances +catalog +launching +instances +telecommunications +portable +lindsay +vatican +##eim +angles +aliens +marker +stint +screens +bolton +##rne +judy +wool +benedict +plasma +europa +imaging +filmmaker +swiftly +contributor +opted +stamps +apologize +financing +butter +gideon +sophisticated +alignment +avery +chemicals +yearly +speculation +prominence +professionally +immortal +institutional +inception +wrists +identifying +tribunal +derives +gains +papal +preference +linguistic +vince +operative +brewery +##ont +unemployment +boyd +##ured +##outs +albeit +prophet +1813 +##rad +quarterly +asteroid +cleaned +radius +temper +##llen +telugu +jerk +viscount +##ote +glimpse +##aya +yacht +hawaiian +baden +laptop +readily +##gu +monetary +offshore +scots +watches +##yang +##arian +upgrade +needle +lea +encyclopedia +flank +fingertips +delight +teachings +confirm +roth +beaches +midway +winters +##iah +teasing +daytime +beverly +gambling +##backs +regulated +clement +hermann +tricks +knot +##shing +##uring +##vre +detached +ecological +owed +specialty +byron +inventor +bats +stays +screened +unesco +midland +trim +affection +##ander +jess +thoroughly +feedback +chennai +strained +heartbeat +wrapping +overtime +pleaded +##sworth +leisure +oclc +##tate +##ele +feathers +angelo +thirds +nuts +surveys +clever +gill +commentator +##dos +darren +rides +gibraltar +dissolution +dedication +shin +meals +saddle +elvis +reds +chaired +taller +appreciation +functioning +niece +favored +advocacy +robbie +criminals +suffolk +yugoslav +passport +constable +congressman +hastings +##rov +consecrated +sparks +ecclesiastical +confined +##ovich +muller +floyd +nora +1822 +paved +1827 +cumberland +ned +saga +spiral +appreciated +collaborative +treating +similarities +feminine +finishes +##ib +jade +import +##hot +champagne +mice +securing +celebrities +helsinki +attributes +##gos +cousins +phases +ache +lucia +gandhi +submission +vicar +spear +shine +tasmania +biting +detention +constitute +tighter +seasonal +##gus +terrestrial +matthews +effectiveness +parody +philharmonic +##onic +1816 +strangers +encoded +consortium +guaranteed +regards +shifts +tortured +collision +supervisor +inform +broader +insight +theaters +armour +emeritus +blink +incorporates +mapping +handball +flexible +##nta +substantially +generous +thief +carr +loses +1793 +prose +ucla +romeo +generic +metallic +realization +damages +commissioners +zach +default +helicopters +lengthy +stems +partnered +spectators +rogue +indication +penalties +teresa +1801 +sen +##tric +dalton +##wich +irving +photographic +##vey +deaf +peters +excluded +unsure +##vable +patterson +crawled +##zio +resided +whipped +latvia +slower +ecole +pipes +employers +maharashtra +comparable +textile +pageant +##gel +alphabet +binary +irrigation +chartered +choked +antoine +offs +waking +supplement +quantities +demolition +regain +locate +urdu +folks +scary +andreas +whites +##ava +classrooms +mw +aesthetic +publishes +valleys +guides +cubs +johannes +bryant +conventions +affecting +##itt +drain +awesome +isolation +prosecutor +ambitious +apology +captive +downs +atmospheric +lorenzo +aisle +beef +foul +##onia +kidding +composite +disturbed +illusion +natives +##ffer +rockets +riverside +wartime +painters +adolf +melted +uncertainty +simulation +hawks +progressed +meantime +builder +spray +breach +unhappy +regina +russians +determining +tram +1806 +##quin +aging +1823 +garion +rented +mister +diaz +terminated +clip +1817 +depend +nervously +disco +owe +defenders +shiva +notorious +disbelief +shiny +worcester +##gation +##yr +trailing +undertook +islander +belarus +limitations +watershed +fuller +overlooking +utilized +raphael +1819 +synthetic +breakdown +klein +##nate +moaned +memoir +lamb +practicing +##erly +cellular +arrows +exotic +witches +charted +rey +hut +hierarchy +subdivision +freshwater +giuseppe +aloud +reyes +qatar +marty +sideways +utterly +sexually +jude +prayers +mccarthy +softball +blend +damien +##gging +##metric +wholly +erupted +lebanese +negro +revenues +tasted +comparative +teamed +transaction +labeled +maori +sovereignty +parkway +trauma +gran +malay +advancement +descendant +buzz +salvation +inventory +symbolic +##making +antarctica +mps +##bro +mohammed +myanmar +holt +submarines +tones +##lman +locker +patriarch +bangkok +emerson +remarks +predators +kin +afghan +confession +norwich +rental +emerge +advantages +##zel +rca +##hold +shortened +storms +aidan +##matic +autonomy +compliance +##quet +dudley +##osis +1803 +motto +documentation +summary +professors +spectacular +christina +archdiocese +flashing +innocence +remake +##dell +psychic +reef +scare +employ +sticks +meg +gus +leans +accompany +bergen +tomas +doom +wages +pools +##bes +breasts +scholarly +alison +outline +brittany +breakthrough +willis +realistic +##cut +##boro +competitor +##stan +pike +picnic +designing +commercials +washing +villain +skiing +costumes +auburn +halted +executives +logistics +cycles +vowel +applicable +barrett +exclaimed +eurovision +eternity +ramon +##umi +modifications +sweeping +disgust +torch +aviv +ensuring +rude +dusty +sonic +donovan +outskirts +cu +pathway +##band +##gun +disciplines +acids +cadet +paired +sketches +##sive +marriages +folding +peers +slovak +implies +admired +##beck +1880s +leopold +instinct +attained +weston +megan +horace +##ination +dorsal +ingredients +evolutionary +complications +deity +lethal +brushing +levy +deserted +institutes +posthumously +delivering +telescope +coronation +motivated +rapids +luc +flicked +pays +volcano +tanner +weighed +##nica +crowds +frankie +gifted +addressing +granddaughter +winding +##rna +constantine +gomez +##front +landscapes +rudolf +anthropology +slate +werewolf +astronomy +circa +rouge +dreaming +sack +knelt +drowned +naomi +prolific +tracked +freezing +herb +agony +randall +twisting +wendy +deposit +touches +vein +wheeler +##bbled +batted +retaining +tire +presently +compare +specification +daemon +nigel +##grave +merry +recommendation +czechoslovakia +sandra +roma +##sts +lambert +inheritance +sheikh +winchester +cries +examining +##yle +comeback +cuisine +nave +##iv +retrieve +tomatoes +barker +polished +defining +irene +lantern +personalities +begging +tract +swore +1809 +##gic +omaha +brotherhood +haiti +##ots +exeter +##ete +##zia +steele +dumb +pearson +surveyed +elisabeth +trends +fritz +bugs +fraction +calmly +viking +##birds +tug +inserted +unusually +##ield +confronted +distress +crashing +brent +turks +resign +##olo +cambodia +gabe +sauce +##kal +evelyn +extant +clusters +quarry +teenagers +luna +##lers +##ister +affiliation +drill +##ashi +panthers +scenic +libya +anita +strengthen +inscriptions +##cated +lace +sued +judith +riots +##uted +mint +##eta +preparations +midst +dub +challenger +##vich +mock +displaced +wicket +breaths +enables +schmidt +analyst +##lum +highlight +automotive +axe +josef +newark +sufficiently +resembles +50th +##pal +flushed +mum +traits +##ante +commodore +incomplete +warming +titular +ceremonial +ethical +celebrating +eighteenth +cao +lima +medalist +mobility +strips +snakes +miniature +zagreb +barton +escapes +umbrella +automated +doubted +differs +cooled +georgetown +dresden +cooked +fade +wyatt +jacobs +carlton +abundant +stereo +madras +inning +spur +malayalam +begged +osaka +groan +escaping +charging +dose +##aj +bud +papa +communists +advocates +edged +tri +resemble +peaking +necklace +fried +montenegro +saxony +goose +glances +stuttgart +curator +recruit +grocery +sympathetic +##tting +##fort +lotus +randolph +ancestor +##rand +succeeding +jupiter +1798 +macedonian +##heads +hiking +1808 +handing +fischer +##itive +garbage +##pies +prone +singular +papua +inclined +attractions +italia +pouring +motioned +grandma +garnered +jacksonville +corp +ego +ringing +aluminum +##hausen +ordering +##foot +drawer +traders +synagogue +##kawa +resistant +wandering +fragile +fiona +teased +hardcore +soaked +jubilee +decisive +exposition +mercer +poster +valencia +hale +kuwait +1811 +##ises +##wr +##eed +tavern +gamma +johan +##uer +airways +amino +gil +vocational +domains +torres +generator +folklore +outcomes +##keeper +canberra +shooter +fl +beams +confrontation +##gram +aligned +forestry +pipeline +jax +motorway +conception +decay +coffin +##cott +stalin +1805 +escorted +minded +##nam +sitcom +purchasing +twilight +veronica +additions +passive +tensions +straw +frequencies +1804 +refugee +cultivation +##iate +christie +clary +bulletin +crept +disposal +##rich +##zong +processor +crescent +##rol +emphasized +whale +nazis +aurora +dwelling +hauled +sponsors +toledo +ideology +theatres +tessa +cerambycidae +saves +turtle +cone +suspects +kara +rusty +yelling +greeks +mozart +shades +cocked +participant +shire +spit +freeze +necessity +##cos +inmates +nielsen +councillors +loaned +uncommon +omar +peasants +botanical +offspring +daniels +formations +jokes +1794 +pioneers +sigma +licensing +##sus +wheelchair +polite +1807 +liquor +pratt +trustee +##uta +forewings +balloon +kilometre +camping +explicit +casually +shawn +foolish +teammates +nm +hassan +carrie +judged +satisfy +vanessa +knives +selective +flowed +##lice +stressed +eliza +mathematician +cease +cultivated +##roy +commissions +browns +##ania +destroyers +sheridan +meadow +##rius +minerals +##cial +downstream +clash +gram +memoirs +ventures +baha +seymour +archie +midlands +edith +fare +flynn +invite +canceled +tiles +stabbed +boulder +incorporate +amended +camden +facial +mollusk +unreleased +descriptions +grabs +raises +ramp +shiver +##rose +coined +pioneering +tunes +qing +warwick +tops +melanie +giles +##rous +wandered +##inal +annexed +30th +unnamed +##ished +organizational +airplane +normandy +stoke +whistle +blessing +violations +chased +holders +shotgun +##ctic +reactor +##vik +tires +tearing +shores +fortified +mascot +constituencies +columnist +productive +tibet +##rta +lineage +hooked +tapes +judging +cody +##gger +hansen +kashmir +triggered +##eva +solved +cliffs +##tree +resisted +anatomy +protesters +transparent +implied +##iga +injection +mattress +excluding +##mbo +defenses +helpless +devotion +##elli +growl +liberals +weber +phenomena +atoms +plug +##iff +mortality +apprentice +howe +convincing +swimmer +barber +leone +promptly +sodium +def +nowadays +arise +##oning +gloucester +corrected +dignity +norm +erie +##ders +elders +evacuated +compression +##yar +hartford +backpack +reasoning +accepts +24th +wipe +millimetres +marcel +##oda +dodgers +albion +1790 +overwhelmed +aerospace +oaks +1795 +showcase +acknowledge +recovering +nolan +ashe +hurts +geology +fashioned +disappearance +farewell +swollen +shrug +marquis +wimbledon +rue +1792 +commemorate +reduces +experiencing +inevitable +calcutta +##court +murderer +sticking +fisheries +imagery +bloom +##inus +gustav +hesitation +memorable +viral +beans +accidents +tunisia +antenna +spilled +consort +treatments +aye +perimeter +##gard +donation +hostage +migrated +banker +addiction +apex +lil +trout +##ously +conscience +##nova +rams +sands +genome +passionate +troubles +##lets +amid +##ibility +##ret +higgins +exceed +vikings +##vie +payne +##zan +muscular +defendant +sucking +##wal +ibrahim +fuselage +claudia +vfl +europeans +snails +interval +##garh +preparatory +statewide +tasked +lacrosse +viktor +##lation +angola +##hra +flint +implications +employs +teens +patrons +stall +weekends +barriers +scrambled +nucleus +tehran +jenna +parsons +lifelong +robots +displacement +##bles +precipitation +knuckles +clutched +1802 +marrying +ecology +marx +accusations +declare +scars +kolkata +mat +meadows +bermuda +skeleton +finalists +vintage +crawl +coordinate +affects +subjected +orchestral +mistaken +mirrors +dipped +relied +arches +candle +##nick +incorporating +wildly +fond +basilica +owl +fringe +rituals +whispering +stirred +feud +tertiary +slick +goat +honorable +whereby +ricardo +stripes +parachute +adjoining +submerged +synthesizer +##gren +intend +positively +ninety +phi +beaver +partition +fellows +alexis +prohibition +carlisle +bizarre +fraternity +doubts +icy +aquatic +sneak +sonny +combines +airports +crude +supervised +spatial +merge +alfonso +##bic +corrupt +scan +undergo +##ams +disabilities +colombian +comparing +dolphins +perkins +reprinted +unanimous +bounced +hairs +underworld +midwest +semester +bucket +paperback +miniseries +coventry +demise +##leigh +demonstrations +sensor +rotating +yan +##hler +arrange +soils +##idge +hyderabad +labs +brakes +grandchildren +##nde +negotiated +rover +ferrari +continuation +directorate +augusta +stevenson +counterpart +gore +##rda +nursery +rican +ave +collectively +broadly +pastoral +repertoire +asserted +discovering +nordic +styled +fiba +cunningham +harley +middlesex +survives +tumor +tempo +zack +aiming +lok +urgent +##nto +devils +contractor +turin +##wl +bliss +repaired +simmons +moan +astronomical +negotiate +lyric +1890s +lara +bred +clad +angus +pbs +engineered +posed +hernandez +possessions +elbows +psychiatric +strokes +confluence +electorate +lifts +campuses +lava +alps +##ution +##date +physicist +woody +##ographic +##itis +juliet +reformation +sparhawk +complement +suppressed +jewel +##½ +floated +##kas +continuity +sadly +##ische +inability +melting +scanning +paula +flour +judaism +safer +vague +solving +curb +##stown +financially +gable +bees +expired +miserable +cassidy +dominion +1789 +cupped +robbery +facto +amos +warden +resume +tallest +marvin +pounded +declaring +gasoline +##aux +darkened +sophomore +##mere +erection +gossip +televised +risen +dial +##eu +pillars +passages +profound +arabian +ashton +silicon +nail +##lated +##hardt +fleming +firearms +ducked +circuits +blows +waterloo +titans +fireplace +cheshire +financed +activation +algorithms +constituent +catcher +cherokee +partnerships +sexuality +platoon +tragic +vivian +guarded +whiskey +meditation +poetic +##nga +porto +listeners +dominance +kendra +mona +chandler +factions +22nd +salisbury +attitudes +derivative +##ido +##haus +intake +paced +javier +illustrator +barrels +bias +cockpit +burnett +dreamed +ensuing +receptors +someday +hawkins +mattered +##lal +slavic +1799 +jesuit +cameroon +wasted +wax +lowering +victorious +freaking +outright +hancock +librarian +sensing +bald +calcium +myers +tablet +announcing +barack +shipyard +pharmaceutical +greenwich +flush +medley +patches +wolfgang +speeches +acquiring +exams +nikolai +hayden +kannada +reilly +waitress +abdomen +devastated +capped +pseudonym +pharmacy +fulfill +paraguay +1796 +clicked +##trom +archipelago +syndicated +##hman +lumber +orgasm +rejection +clifford +lorraine +advent +mafia +rodney +brock +##used +##elia +cassette +chamberlain +despair +mongolia +sensors +developmental +upstream +##alis +spanning +trombone +basque +seeded +interred +renewable +rhys +leapt +revision +molecule +##ages +chord +vicious +nord +shivered +23rd +arlington +debts +corpus +sunrise +bays +blackburn +centimetres +##uded +shuddered +strangely +gripping +cartoons +isabelle +orbital +##ppa +seals +proving +refusal +strengthened +bust +assisting +baghdad +batsman +portrayal +mara +pushes +spears +og +##cock +reside +nathaniel +brennan +1776 +confirmation +caucus +##worthy +markings +yemen +nobles +ku +lazy +viewer +catalan +encompasses +sawyer +##fall +sparked +substances +patents +braves +arranger +evacuation +sergio +persuade +dover +tolerance +penguin +cum +jockey +insufficient +townships +occupying +declining +plural +processed +projection +puppet +flanders +introduces +liability +##yon +gymnastics +antwerp +hobart +candles +jeep +wes +observers +chaplain +bundle +glorious +##hine +hazel +flung +sol +excavations +dumped +stares +bangalore +triangular +icelandic +intervals +expressing +turbine +##vers +songwriting +crafts +##igo +jasmine +ditch +rite +entertaining +comply +sorrow +wrestlers +basel +emirates +marian +rivera +helpful +##some +caution +downward +networking +##atory +##tered +darted +genocide +emergence +replies +specializing +spokesman +convenient +unlocked +fading +augustine +concentrations +resemblance +elijah +investigator +andhra +##uda +promotes +##rrell +fleeing +simone +announcer +lydia +weaver +residency +modification +##fest +stretches +alternatively +nat +lowe +lacks +##ented +pam +tile +concealed +inferior +abdullah +residences +tissues +vengeance +##ided +moisture +peculiar +groove +bologna +jennings +ninja +oversaw +zombies +pumping +batch +livingston +emerald +installations +1797 +peel +nitrogen +rama +##fying +schooling +strands +responding +werner +lime +casa +accurately +targeting +##rod +underway +##uru +hemisphere +lester +##yard +occupies +griffith +angrily +reorganized +##owing +courtney +deposited +estadio +##ifies +dunn +exiled +##ying +checks +##combe +successes +unexpectedly +blu +assessed +##flower +observing +sacked +spiders +kn +nodes +prosperity +audrey +divisional +broncos +tangled +adjust +feeds +erosion +paolo +surf +directory +snatched +humid +admiralty +screwed +reddish +##nese +modules +trench +lamps +bind +leah +bucks +competes +##nz +transcription +isles +violently +clutching +pga +cyclist +inflation +flats +ragged +unnecessary +##hian +stubborn +coordinated +harriet +baba +disqualified +insect +wolfe +##fies +reinforcements +rocked +duel +winked +embraced +bricks +##raj +hiatus +defeats +pending +brightly +jealousy +##xton +##uki +lena +colorful +##dley +stein +kidney +##shu +underwear +wanderers +##haw +##icus +guardians +m³ +roared +habits +##wise +permits +uranium +punished +disguise +bundesliga +elise +dundee +erotic +partisan +collectors +float +individually +rendering +behavioral +bucharest +ser +hare +valerie +corporal +nutrition +proportional +immense +##kis +pavement +##zie +##eld +sutherland +crouched +1775 +suzuki +trades +endurance +operas +crosby +prayed +priory +rory +socially +gujarat +walton +cube +pasha +privilege +lennon +floods +thorne +waterfall +nipple +scouting +approve +##lov +minorities +voter +dwight +extensions +assure +ballroom +slap +dripping +privileges +rejoined +confessed +demonstrating +patriotic +yell +investor +##uth +pagan +slumped +squares +confront +bert +embarrassment +aston +urging +sweater +starr +yuri +brains +williamson +commuter +mortar +structured +selfish +exports +##jon +cds +##him +unfinished +##rre +mortgage +destinations +##nagar +canoe +solitary +buchanan +delays +magistrate +fk +##pling +motivation +##lier +##vier +recruiting +assess +##mouth +malik +antique +1791 +pius +rahman +reich +tub +zhou +smashed +airs +galway +xii +conditioning +honduras +discharged +dexter +##pf +lionel +debates +lemon +volunteered +dioxide +procession +devi +sic +tremendous +advertisements +colts +transferring +verdict +hanover +decommissioned +utter +relate +pac +racism +beacon +limp +similarity +terra +occurrence +ant +becky +capt +updates +armament +richie +pal +##graph +halloween +mayo +##ssen +##bone +cara +serena +fcc +dolls +obligations +##dling +violated +lafayette +jakarta +exploitation +infamous +iconic +##lah +##park +moody +reginald +dread +spill +crystals +olivier +modeled +bluff +equilibrium +separating +notices +ordnance +extinction +onset +cosmic +attachment +sammy +expose +privy +anchored +##bil +abbott +admits +bending +baritone +emmanuel +policeman +vaughan +winged +climax +dresses +denny +polytechnic +mohamed +burmese +authentic +nikki +genetics +grandparents +homestead +gaza +postponed +metacritic +una +##sby +unstable +dissertation +##cian +curls +obscure +uncovered +bronx +praying +disappearing +##hoe +prehistoric +coke +turret +mutations +nonprofit +pits +monaco +##usion +prominently +dispatched +podium +##mir +uci +##uation +fortifications +birthplace +kendall +##lby +##oll +preacher +rack +goodman +persistent +##ott +countless +jaime +recorder +lexington +persecution +jumps +renewal +wagons +crushing +##holder +decorations +##lake +abundance +wrath +laundry +£1 +garde +jeanne +beetles +peasant +splitting +caste +sergei +##rer +##ema +scripts +##ively +rub +satellites +##vor +inscribed +verlag +scrapped +gale +packages +chick +potato +slogan +kathleen +arabs +##culture +counterparts +reminiscent +choral +##tead +rand +retains +bushes +dane +accomplish +courtesy +closes +##oth +slaughter +hague +krakow +lawson +tailed +elias +ginger +##ttes +canopy +betrayal +rebuilding +turf +##hof +frowning +allegiance +brigades +kicks +rebuild +polls +alias +nationalism +rowan +audition +bowie +fortunately +recognizes +harp +dillon +horrified +##oro +renault +ropes +presumed +rewarded +infrared +wiping +accelerated +illustration +presses +practitioners +badminton +##iard +detained +##tera +recognizing +relates +misery +##sies +##tly +reproduction +piercing +potatoes +thornton +esther +manners +hbo +##aan +ours +bullshit +ernie +perennial +sensitivity +illuminated +rupert +##iss +rfc +nassau +##dock +staggered +socialism +##haven +appointments +nonsense +prestige +sharma +haul +solidarity +##rata +igor +pedestrian +##uit +baxter +tenants +wires +medication +unlimited +guiding +impacts +diabetes +##rama +sasha +pas +clive +extraction +continually +constraints +##bilities +sonata +hunted +sixteenth +chu +planting +quote +mayer +pretended +spat +ceramic +##cci +curtains +pigs +pitching +##dad +latvian +sore +dayton +##sted +patrols +slice +playground +##nted +shone +stool +apparatus +inadequate +mates +treason +##ija +desires +##liga +##croft +somalia +laurent +mir +grape +obliged +chevrolet +thirteenth +stunning +enthusiastic +##ede +accounted +concludes +currents +basil +##kovic +drought +##rica +mai +##aire +shove +posting +##shed +pilgrimage +humorous +packing +fry +pencil +wines +smells +marilyn +aching +newest +clung +bon +neighbours +sanctioned +##pie +mug +##stock +drowning +hydraulic +##vil +hiring +reminder +lilly +investigators +##ncies +sour +##eous +compulsory +packet +##rion +##graphic +##elle +cannes +##inate +depressed +##rit +heroic +importantly +theresa +##tled +conway +saturn +marginal +rae +##xia +corresponds +royce +pact +jasper +explosives +packaging +aluminium +##ttered +denotes +rhythmic +spans +assignments +hereditary +outlined +originating +sundays +lad +reissued +greeting +beatrice +##dic +pillar +marcos +plots +handbook +alcoholic +judiciary +avant +slides +extract +masculine +blur +##eum +homage +trembled +owens +hymn +trey +signaling +socks +accumulated +reacted +attic +theo +lining +angie +distraction +primera +talbot +creativity +billed +##hey +deacon +eduardo +identifies +proposition +dizzy +gunner +hogan +##yam +##pping +##hol +ja +##chan +jensen +reconstructed +##berger +clearance +darius +##nier +abe +harlem +plea +dei +circled +emotionally +notation +fascist +neville +exceeded +upwards +viable +ducks +workforce +racer +limiting +shri +##lson +possesses +kerr +moths +devastating +laden +disturbing +locking +gal +fearing +accreditation +flavor +aide +1870s +mountainous +##baum +melt +##ures +texture +servers +soda +herd +##nium +erect +puzzled +hum +peggy +examinations +gould +testified +geoff +ren +devised +sacks +##law +denial +posters +grunted +cesar +tutor +gerry +offerings +byrne +falcons +combinations +incoming +pardon +rocking +26th +avengers +flared +mankind +seller +uttar +loch +nadia +stroking +exposing +fertile +ancestral +instituted +##has +noises +prophecy +taxation +eminent +vivid +pol +##bol +dart +indirect +multimedia +notebook +upside +displaying +adrenaline +referenced +geometric +##iving +progression +##ddy +blunt +announce +##far +implementing +##lav +aggression +liaison +cooler +cares +headache +plantations +gorge +dots +impulse +thickness +ashamed +averaging +kathy +obligation +precursor +fowler +symmetry +thee +hears +##rai +undergoing +butcher +bowler +##lip +cigarettes +subscription +goodness +##ically +browne +##hos +kyoto +donor +##erty +damaging +friction +drifting +expeditions +hardened +prostitution +fauna +blankets +claw +tossing +snarled +butterflies +recruits +investigative +coated +healed +communal +hai +xiii +academics +boone +psychologist +restless +lahore +stephens +brendan +foreigners +printer +ached +explode +27th +deed +scratched +dared +##pole +cardiac +1780 +okinawa +proto +commando +compelled +oddly +electrons +replica +thanksgiving +##rist +sheila +deliberate +stafford +tidal +representations +hercules +ou +##path +##iated +kidnapping +lenses +##tling +deficit +samoa +mouths +consuming +computational +maze +granting +smirk +razor +fixture +ideals +inviting +aiden +nominal +issuing +julio +pitt +ramsey +docks +##oss +exhaust +##owed +bavarian +draped +anterior +mating +ethiopian +explores +noticing +##nton +discarded +convenience +hoffman +endowment +beasts +cartridge +mormon +paternal +probe +sleeves +interfere +lump +deadline +jenks +bulldogs +scrap +alternating +justified +reproductive +nam +seize +descending +secretariat +kirby +grouped +smash +panther +sedan +tapping +lola +cheer +germanic +unfortunate +##eter +unrelated +##fan +subordinate +##sdale +suzanne +advertisement +##ility +horsepower +##lda +cautiously +discourse +luigi +##mans +##fields +noun +prevalent +mao +schneider +everett +surround +governorate +kira +##avia +westward +##take +misty +rails +sustainability +unused +##rating +packs +toast +unwilling +regulate +thy +suffrage +nile +awe +assam +definitions +travelers +affordable +##rb +conferred +sells +undefeated +beneficial +torso +basal +repeating +remixes +bahrain +cables +fang +##itated +excavated +numbering +statutory +deluxe +##lian +forested +ramirez +derbyshire +zeus +slamming +transfers +astronomer +banana +lottery +berg +histories +bamboo +##uchi +resurrection +posterior +bowls +vaguely +##thi +thou +preserving +tensed +offence +##inas +meyrick +callum +ridden +watt +langdon +tying +lowland +snorted +daring +truman +##hale +##girl +aura +overly +filing +weighing +goa +infections +philanthropist +saunders +eponymous +##owski +latitude +perspectives +reviewing +mets +commandant +radial +##kha +flashlight +reliability +koch +vowels +amazed +ada +elaine +supper +##encies +predator +debated +soviets +cola +##boards +##nah +compartment +crooked +arbitrary +fourteenth +havana +majors +steelers +clips +profitable +ambush +exited +packers +##tile +nude +cracks +fungi +limb +trousers +josie +shelby +tens +frederic +##ος +definite +smoothly +constellation +insult +baton +discs +lingering +##nco +conclusions +lent +staging +becker +grandpa +shaky +##tron +einstein +obstacles +adverse +economically +##moto +mccartney +thor +dismissal +motions +readings +nostrils +treatise +##pace +squeezing +evidently +prolonged +1783 +venezuelan +je +marguerite +beirut +takeover +shareholders +##vent +denise +digit +airplay +norse +##bbling +imaginary +pills +hubert +blaze +vacated +eliminating +vine +mansfield +retrospective +barrow +borne +clutch +bail +forensic +weaving +##nett +##witz +desktop +citadel +promotions +worrying +dorset +subdivided +##iating +manned +expeditionary +pickup +synod +chuckle +barney +##rz +##ffin +functionality +karachi +litigation +meanings +lick +anders +##ffed +execute +curl +oppose +ankles +typhoon +##ache +linguistics +compassion +pressures +grazing +perfection +##iting +immunity +monopoly +muddy +backgrounds +namibia +francesca +monitors +attracting +stunt +tuition +##ии +vegetable +##mates +##quent +mgm +jen +complexes +forts +cellar +bites +seventeenth +royals +flemish +failures +mast +charities +##cular +peruvian +capitals +macmillan +ipswich +outward +frigate +postgraduate +folds +employing +##ouse +concurrently +fiery +##tai +contingent +nightmares +monumental +nicaragua +##kowski +lizard +mal +fielding +gig +reject +harding +##ipe +coastline +##cin +beethoven +humphrey +innovations +##tam +norris +doris +solicitor +obey +niagara +shelves +bourbon +nightclub +specifications +hilton +##ndo +centennial +dispersed +worm +neglected +briggs +kuala +uneasy +##nstein +##bound +##aking +##burgh +awaiting +pronunciation +##bbed +##quest +eh +optimal +zhu +raped +greens +presided +brenda +worries +venetian +marxist +turnout +##lius +refined +braced +sins +grasped +sunderland +nickel +speculated +lowell +cyrillic +communism +fundraising +resembling +colonists +mutant +freddie +usc +##mos +gratitude +##run +mural +##lous +chemist +reminds +28th +steals +tess +pietro +##ingen +promoter +ri +microphone +honoured +rai +sant +##qui +feather +##nson +burlington +kurdish +terrorists +deborah +sickness +##wed +hazard +irritated +desperation +veil +clarity +##rik +jewels +xv +##gged +##ows +##cup +berkshire +unfair +mysteries +orchid +winced +exhaustion +renovations +stranded +obe +infinity +##nies +adapt +redevelopment +thanked +registry +olga +domingo +noir +tudor +ole +commenting +behaviors +##ais +crisp +pauline +probable +stirling +wigan +paralympics +panting +surpassed +##rew +luca +barred +famed +##sters +cassandra +waiter +carolyn +exported +##orted +andres +destructive +deeds +jonah +castles +vacancy +##glass +1788 +orchard +yep +famine +belarusian +sprang +##forth +skinny +##mis +administrators +rotterdam +zambia +zhao +boiler +discoveries +##ride +##physics +lucius +disappointing +outreach +spoon +##frame +qualifications +unanimously +enjoys +regency +##iidae +stade +realism +veterinary +rodgers +dump +alain +chestnut +castile +censorship +rumble +gibbs +communion +reggae +inactivated +logs +loads +##houses +homosexual +##iano +ale +informs +##cas +phrases +plaster +linebacker +ambrose +kaiser +fascinated +limerick +recruitment +forge +mastered +##nding +leinster +rooted +threaten +##strom +borneo +##hes +suggestions +scholarships +propeller +documentaries +patronage +coats +constructing +invest +neurons +comet +entirety +shouts +identities +annoying +unchanged +wary +##antly +##ogy +neat +oversight +##kos +phillies +replay +constance +##kka +incarnation +humble +skies +minus +##acy +smithsonian +guerrilla +jar +cadets +##plate +surplus +audit +##aru +cracking +joanna +louisa +pacing +##lights +intentionally +##iri +diner +nwa +imprint +australians +tong +unprecedented +bunker +naive +specialists +ark +nichols +railing +leaked +pedal +##uka +shrub +longing +roofs +captains +neural +tuned +##ntal +##jet +emission +medina +frantic +codex +definitive +sid +abolition +intensified +stocks +enrique +sustain +genoa +oxide +##written +clues +cha +##gers +tributaries +fragment +venom +##ente +##sca +muffled +vain +sire +laos +##ingly +##hana +hastily +snapping +surfaced +sentiment +motive +##oft +contests +approximate +mesa +luckily +dinosaur +exchanges +propelled +accord +bourne +relieve +tow +masks +offended +##ues +cynthia +##mmer +rains +bartender +zinc +reviewers +lois +##sai +legged +arrogant +rafe +comprise +handicap +blockade +inlet +lagoon +copied +drilling +shelley +petals +##inian +mandarin +obsolete +##inated +onward +arguably +productivity +praising +seldom +busch +discusses +raleigh +shortage +ranged +stanton +encouragement +firstly +conceded +overs +temporal +##uke +cbe +##bos +woo +certainty +pumps +##pton +stalked +##uli +lizzie +periodic +thieves +weaker +gases +shoving +chooses +wc +##chemical +prompting +weights +##kill +robust +flanked +sticky +tuberculosis +##eb +##eal +christchurch +resembled +wallet +reese +inappropriate +pictured +distract +fixing +fiddle +giggled +burger +heirs +hairy +mechanic +torque +obsessed +chiefly +cheng +logging +extracted +meaningful +numb +##vsky +gloucestershire +reminding +unite +##lit +breeds +diminished +clown +glove +1860s +archibald +focal +freelance +sliced +depiction +##yk +organism +switches +sights +stray +crawling +##ril +lever +leningrad +interpretations +loops +anytime +reel +alicia +delighted +##ech +inhaled +xiv +suitcase +bernie +vega +licenses +northampton +exclusion +induction +monasteries +racecourse +homosexuality +##sfield +##rky +dimitri +michele +alternatives +ions +commentators +genuinely +objected +pork +hospitality +fencing +stephan +warships +peripheral +wit +drunken +wrinkled +quentin +spends +departing +chung +numerical +spokesperson +johannesburg +caliber +killers +##udge +assumes +neatly +demographic +abigail +bloc +mounting +##lain +bentley +slightest +xu +recipients +##jk +merlin +##writer +seniors +prisons +blinking +hindwings +flickered +kappa +##hel +80s +strengthening +appealing +brewing +gypsy +mali +lashes +hulk +unpleasant +harassment +bio +treaties +predict +instrumentation +pulp +troupe +boiling +mantle +##ffe +##vn +dividing +handles +verbs +##onal +coconut +senegal +thorough +gum +momentarily +##sto +cocaine +panicked +destined +##turing +teatro +denying +weary +captained +mans +##hawks +wakefield +bollywood +thankfully +cyril +amendments +##bahn +consultation +stud +reflections +kindness +1787 +internally +##ovo +tex +mosaic +distribute +paddy +seeming +##hic +piers +##mura +popularly +winger +kang +sentinel +mccoy +##anza +covenant +##bag +verge +fireworks +suppress +thrilled +dominate +##jar +swansea +reconciliation +stiffened +cue +dorian +##uf +damascus +amor +ida +foremost +##aga +porsche +unseen +dir +##had +##azi +stony +lexi +melodies +##nko +angular +integer +podcast +ants +inherent +jaws +justify +persona +##olved +josephine +##nr +##ressed +customary +flashes +gala +cyrus +glaring +backyard +ariel +physiology +greenland +stir +avon +atletico +finch +methodology +ked +mas +catholicism +townsend +branding +quincy +fits +containers +1777 +ashore +aragon +forearm +poisoning +adopting +conquer +grinding +amnesty +keller +finances +evaluate +forged +lankan +instincts +##uto +guam +bosnian +photographed +workplace +desirable +protector +allocation +intently +encourages +willy +##sten +bodyguard +electro +brighter +bihar +##chev +lasts +opener +amphibious +sal +verde +arte +##cope +captivity +vocabulary +yields +##tted +agreeing +desmond +pioneered +##chus +strap +campaigned +railroads +##ович +emblem +##dre +stormed +##ulous +marijuana +northumberland +##nath +bowen +landmarks +beaumont +##qua +danube +##bler +attorneys +th +flyers +critique +villains +cass +mutation +acc +##0s +colombo +mckay +motif +sampling +concluding +syndicate +##rell +neon +stables +warnings +clint +mourning +wilkinson +##tated +merrill +leopard +evenings +exhaled +emil +sonia +ezra +discrete +stove +farrell +fifteenth +prescribed +superhero +##rier +worms +helm +wren +##duction +expo +##rator +hq +unfamiliar +antony +prevents +acceleration +fiercely +mari +painfully +calculations +cheaper +ign +clifton +irvine +davenport +mozambique +pierced +##evich +wonders +##wig +##cate +##iling +crusade +ware +enzymes +reasonably +mls +##coe +mater +ambition +bunny +eliot +kernel +##fin +asphalt +headmaster +torah +aden +lush +pins +waived +##yas +joao +substrate +enforce +##grad +##ules +alvarez +selections +epidemic +tempted +bremen +translates +ensured +waterfront +29th +forrest +manny +malone +kramer +reigning +simpler +absorption +engraved +##ffy +evaluated +1778 +haze +comforting +crossover +##abe +thorn +##rift +##imo +suppression +fatigue +cutter +wurttemberg +##orf +enforced +hovering +proprietary +samurai +syllable +ascent +lacey +tick +lars +tractor +merchandise +rep +bouncing +defendants +##yre +huntington +##oko +standardized +##hor +##hima +assassinated +predecessors +rainy +liar +assurance +lyrical +##uga +secondly +flattened +parameter +undercover +##mity +bordeaux +punish +ridges +markers +exodus +inactive +hesitate +debbie +nyc +pledge +savoy +nagar +offset +organist +##tium +hesse +marin +converting +##iver +diagram +propulsion +validity +reverted +supportive +ministries +clans +responds +proclamation +##inae +ein +pleading +patriot +birch +islanders +strauss +hates +##dh +brandenburg +concession +1900s +killings +textbook +antiquity +cinematography +wharf +embarrassing +setup +creed +farmland +inequality +centred +signatures +fallon +##ingham +##uts +ceylon +gazing +directive +laurie +##tern +globally +##uated +##dent +allah +excavation +threads +##cross +frantically +icc +utilize +determines +respiratory +thoughtful +receptions +##dicate +merging +chandra +seine +builders +builds +diagnostic +dev +visibility +goddamn +analyses +dhaka +proves +chancel +concurrent +curiously +canadians +pumped +restoring +1850s +turtles +jaguar +sinister +spinal +declan +vows +1784 +glowed +capitalism +swirling +universidad +##lder +##oat +soloist +##genic +##oor +coincidence +beginnings +nissan +dip +resorts +caucasus +combustion +infectious +##eno +pigeon +serpent +##itating +conclude +masked +salad +jew +##gr +surreal +toni +##wc +harmonica +##gins +##etic +##coat +fishermen +intending +bravery +##wave +klaus +titan +wembley +taiwanese +ransom +40th +incorrect +hussein +eyelids +cooke +dramas +utilities +##etta +##print +eisenhower +principally +granada +lana +##rak +openings +concord +##bl +bethany +connie +morality +sega +##mons +##nard +earnings +##kara +##cine +communes +##rel +coma +composing +softened +severed +grapes +nguyen +analyzed +warlord +hubbard +heavenly +behave +slovenian +##hit +##ony +hailed +filmmakers +trance +caldwell +skye +unrest +coward +likelihood +##aging +bern +taliban +honolulu +propose +browser +imagining +cobra +contributes +dukes +instinctively +conan +violinist +##ores +accessories +gradual +##amp +quotes +sioux +##dating +undertake +intercepted +sparkling +compressed +fungus +tombs +haley +imposing +rests +degradation +lincolnshire +retailers +wetlands +tulsa +distributor +dungeon +nun +greenhouse +convey +atlantis +aft +exits +oman +dresser +lyons +##sti +joking +eddy +judgement +omitted +digits +##game +juniors +##rae +cents +stricken +une +##ngo +wizards +weir +breton +nan +technician +fibers +liking +royalty +persia +terribly +magician +##rable +##unt +vance +cafeteria +booker +camille +warmer +##static +consume +cavern +gaps +compass +contemporaries +foyer +soothing +graveyard +maj +plunged +blush +##wear +cascade +demonstrates +ordinance +##nov +boyle +##lana +rockefeller +shaken +banjo +izzy +##ense +breathless +vines +##eman +alterations +chromosome +dwellings +feudal +mole +catalonia +relics +tenant +mandated +##fm +fridge +hats +honesty +patented +raul +heap +cruisers +accusing +enlightenment +infants +wherein +chatham +contractors +affinity +hc +osborne +piston +traps +maturity +##rana +lagos +##zal +peering +##nay +attendant +dealers +protocols +subset +prospects +biographical +##cre +artery +##zers +insignia +nuns +endured +##eration +recommend +schwartz +serbs +berger +cromwell +crossroads +enduring +clasped +grounded +##bine +marseille +twitched +abel +choke +catalyst +moldova +italians +##tist +disastrous +wee +##oured +##nti +wwf +nope +##piration +##asa +expresses +thumbs +##nza +coca +1781 +cheating +##ption +skipped +sensory +heidelberg +spies +satan +dangers +semifinal +bohemia +whitish +confusing +shipbuilding +relies +surgeons +landings +ravi +baku +moor +suffix +alejandro +##yana +litre +upheld +##unk +rajasthan +##rek +coaster +insists +posture +scenarios +etienne +favoured +appoint +transgender +elephants +poked +greenwood +defences +fulfilled +militant +somali +1758 +chalk +potent +##ucci +migrants +wink +assistants +nos +restriction +activism +niger +##ario +colon +shaun +##sat +daphne +##erated +swam +congregations +reprise +considerations +magnet +playable +xvi +overthrow +tobias +knob +chavez +coding +##mers +propped +katrina +orient +newcomer +##suke +temperate +##pool +farmhouse +interrogation +committing +##vert +forthcoming +strawberry +joaquin +macau +ponds +shocking +siberia +##cellular +chant +contributors +##nant +##ologists +sped +absorb +hail +1782 +spared +##hore +barbados +karate +opus +originates +saul +##xie +evergreen +leaped +##rock +correlation +exaggerated +weekday +unification +bump +tracing +brig +afb +pathways +utilizing +disturbance +kneeling +##stad +##guchi +100th +pune +##thy +decreasing +manipulation +miriam +academia +ecosystem +occupational +rbi +##lem +rift +rotary +stacked +incorporation +awakening +generators +guerrero +racist +##omy +cyber +derivatives +culminated +allie +annals +panzer +sainte +pops +zu +austro +##vate +algerian +politely +nicholson +mornings +educate +tastes +thrill +dartmouth +##gating +##jee +regan +differing +concentrating +choreography +divinity +pledged +alexandre +routing +gregor +madeline +##idal +apocalypse +##hora +gunfire +culminating +elves +fined +liang +lam +programmed +tar +guessing +transparency +gabrielle +##gna +cancellation +flexibility +##lining +accession +shea +stronghold +nets +specializes +##rgan +abused +hasan +sgt +exceeding +admiration +supermarket +photographers +specialised +tilt +resonance +hmm +perfume +sami +threatens +garland +botany +guarding +boiled +greet +puppy +russo +supplier +wilmington +vibrant +vijay +##bius +paralympic +grumbled +paige +faa +licking +margins +hurricanes +##gong +fest +grenade +ripping +##uz +counseling +weigh +##sian +needles +wiltshire +edison +costly +##not +fulton +tramway +redesigned +staffordshire +gasping +watkins +sleepy +candidacy +monkeys +timeline +throbbing +##bid +##sos +berth +uzbekistan +vanderbilt +bothering +overturned +ballots +gem +##iger +sunglasses +subscribers +hooker +compelling +ang +exceptionally +saloon +stab +##rdi +carla +terrifying +##vision +coil +##oids +satisfying +vendors +31st +mackay +deities +overlooked +ambient +bahamas +felipe +olympia +whirled +botanist +advertised +tugging +disciples +morales +unionist +rites +foley +morse +motives +creepy +##₀ +soo +##sz +bargain +highness +frightening +turnpike +tory +reorganization +depict +biographer +unopposed +manifesto +##gles +institut +emile +accidental +kapoor +##dam +kilkenny +cortex +lively +romanesque +jain +shan +cannons +##ske +petrol +echoing +amalgamated +disappears +cautious +proposes +sanctions +trenton +flotilla +aus +contempt +tor +canary +cote +theirs +##hun +conceptual +deleted +fascinating +paso +blazing +elf +honourable +hutchinson +##eiro +##outh +##zin +surveyor +amidst +wooded +reissue +intro +##ono +cobb +shelters +newsletter +hanson +brace +encoding +confiscated +dem +caravan +marino +scroll +melodic +cows +imam +##adi +##aneous +northward +searches +biodiversity +cora +roaring +##bers +connell +theologian +halo +compose +pathetic +unmarried +dynamo +az +calculation +toulouse +deserves +humour +nr +forgiveness +tam +undergone +martyr +pamela +myths +whore +counselor +hicks +heavens +battleship +electromagnetic +stellar +establishments +presley +hopped +##chin +temptation +90s +wills +##yuan +nhs +##nya +seminars +##yev +adaptations +gong +asher +lex +indicator +sikh +tobago +cites +goin +##yte +satirical +##gies +characterised +correspond +bubbles +lure +participates +##vid +eruption +skate +therapeutic +1785 +canals +wholesale +defaulted +sac +petit +##zzled +virgil +leak +ravens +portraying +##yx +ghetto +creators +dams +portray +vicente +##rington +fae +namesake +bounty +##arium +joachim +##ota +##iser +aforementioned +axle +snout +depended +dismantled +reuben +##ibly +gallagher +##lau +earnest +##ieu +##iary +inflicted +objections +##llar +asa +gritted +##athy +jericho +##sea +##was +flick +underside +ceramics +undead +substituted +eastward +undoubtedly +wheeled +chimney +##iche +guinness +siding +traitor +baptiste +disguised +inauguration +tipperary +choreographer +perched +warmed +stationary +##ntes +bacterial +##aurus +flores +phosphate +attacker +invaders +alvin +intersects +indirectly +immigrated +businessmen +cornelius +valves +narrated +pill +sober +nationale +monastic +applicants +scenery +##jack +motifs +constitutes +##osh +jurisdictions +tuning +irritation +woven +##uddin +fertility +gao +##erie +antagonist +impatient +glacial +hides +boarded +denominations +interception +##jas +nicola +algebraic +marquess +bahn +parole +buyers +bait +turbines +paperwork +bestowed +natasha +renee +oceans +purchases +vaccine +##tock +fixtures +playhouse +integrate +jai +oswald +intellectuals +booked +nests +mortimer +##isi +obsession +sept +##gler +##sum +scrutiny +simultaneous +squinted +##shin +collects +oven +shankar +penned +remarkably +slips +luggage +spectral +1786 +collaborations +louie +consolidation +##ailed +##ivating +hoover +blackpool +harness +ignition +vest +tails +belmont +mongol +skinner +##nae +visually +mage +derry +##tism +##unce +stevie +transitional +##rdy +redskins +drying +prep +prospective +annoyance +oversee +##loaded +fills +##books +announces +scowled +respects +prasad +mystic +tucson +##vale +revue +springer +bankrupt +1772 +aristotle +habsburg +##geny +dal +natal +nut +pod +chewing +darts +moroccan +walkover +rosario +lenin +punjabi +##ße +grossed +scattering +wired +invasive +hui +polynomial +corridors +wakes +gina +portrays +##cratic +arid +retreating +erich +irwin +sniper +##dha +linen +lindsey +maneuver +butch +shutting +socio +bounce +commemorative +postseason +jeremiah +pines +mystical +beads +abbas +furnace +bidding +consulted +assaulted +empirical +rubble +enclosure +sob +weakly +cancel +polly +yielded +##emann +curly +prediction +battered +70s +vhs +jacqueline +render +sails +barked +detailing +grayson +riga +sloane +raging +##yah +herbs +bravo +##athlon +alloy +giggle +imminent +suffers +assumptions +waltz +##itate +accomplishments +##ited +bathing +remixed +deception +##emia +deepest +##eis +balkan +frogs +##rong +slab +##pate +philosophers +peterborough +grains +imports +dickinson +rwanda +##atics +1774 +dirk +tablets +##rove +clone +##rice +caretaker +hostilities +mclean +##gre +regimental +treasures +norms +impose +tsar +tango +diplomacy +variously +complain +recognise +arrests +1779 +celestial +pulitzer +##dus +libretto +##moor +adele +splash +expectation +lds +confronts +##izer +spontaneous +harmful +wedge +entrepreneurs +buyer +bilingual +translate +rugged +conner +circulated +uae +eaton +##gra +##zzle +lingered +lockheed +vishnu +reelection +alonso +##oom +joints +yankee +headline +cooperate +heinz +laureate +invading +##sford +echoes +scandinavian +##dham +hugging +vitamin +salute +micah +hind +trader +##sper +radioactive +##ndra +militants +poisoned +ratified +remark +campeonato +deprived +wander +prop +##dong +##tani +##eye +chiang +darcy +##oping +mandolin +spice +statesman +babylon +walled +forgetting +afro +##cap +giorgio +buffer +##polis +planetary +##gis +overlap +terminals +kinda +centenary +##bir +arising +manipulate +elm +ke +1770 +##tad +chrysler +mapped +moose +pomeranian +quad +macarthur +assemblies +shoreline +recalls +stratford +##rted +noticeable +##evic +imp +##rita +##sque +accustomed +supplying +tents +disgusted +sipped +filters +khz +reno +selecting +luftwaffe +mcmahon +tyne +masterpiece +carriages +collided +dunes +exercised +flare +remembers +muzzle +heck +##rson +burgess +lunged +middleton +boycott +bilateral +##sity +hazardous +lumpur +multiplayer +spotlight +jackets +goldman +liege +porcelain +rag +waterford +attracts +hopeful +battling +ottomans +kensington +baked +hymns +cheyenne +lattice +levine +borrow +polymer +clashes +michaels +monitored +commitments +denounced +##von +cavity +##oney +hobby +akin +##holders +futures +intricate +cornish +patty +##oned +illegally +dolphin +##lag +barlow +yellowish +maddie +apologized +luton +plagued +##puram +##rds +sway +fanny +łodz +##rino +psi +suspicions +hanged +##eding +initiate +charlton +##por +nak +competent +analytical +annex +wardrobe +reservations +sect +fairfax +hedge +piled +buckingham +uneven +bauer +simplicity +snyder +interpret +accountability +donors +moderately +byrd +continents +##cite +disciple +jamaican +nominees +##uss +mongolian +diver +attackers +eagerly +ideological +pillows +miracles +apartheid +revolver +sulfur +clinics +moran +##enko +ile +katy +rhetoric +##icated +chronology +recycling +##hrer +elongated +mughal +pascal +profiles +vibration +databases +domination +##fare +matthias +digest +rehearsal +polling +weiss +initiation +reeves +clinging +flourished +impress +##hoff +buckley +symposium +rhythms +weed +emphasize +transforming +##taking +##yman +accountant +analyze +flicker +foil +priesthood +voluntarily +decreases +##hya +slater +sv +charting +mcgill +##lde +moreno +besieged +zur +robes +##phic +admitting +deported +turmoil +peyton +earthquakes +##ares +nationalists +beau +clair +brethren +interrupt +welch +curated +galerie +requesting +##ested +impending +steward +viper +##vina +complaining +beautifully +brandy +foam +nl +1660 +alessandro +punches +laced +explanations +##lim +attribute +clit +reggie +discomfort +##cards +smoothed +whales +##cene +adler +countered +duffy +disciplinary +widening +recipe +reliance +conducts +goats +gradient +preaching +##shaw +matilda +quasi +striped +meridian +cannabis +cordoba +certificates +##agh +##tering +graffiti +hangs +pilgrims +repeats +##ych +revive +urine +etat +##hawk +fueled +belts +fuzzy +susceptible +mauritius +salle +sincere +beers +hooks +##cki +arbitration +entrusted +advise +sniffed +seminar +junk +donnell +processors +principality +strapped +celia +mendoza +everton +fortunes +prejudice +starving +reassigned +steamer +##lund +tuck +evenly +foreman +##ffen +dans +envisioned +slit +baseman +liberia +rosemary +##weed +electrified +periodically +potassium +stride +contexts +sperm +slade +mariners +influx +bianca +subcommittee +##rane +spilling +icao +estuary +##nock +delivers +##ulata +isa +mira +bohemian +dessert +##sbury +welcoming +proudly +slowing +##chs +musee +ascension +russ +##vian +waits +##psy +africans +exploit +##morphic +eccentric +crab +peck +entrances +formidable +marketplace +groom +bolted +metabolism +patton +robbins +courier +payload +endure +##ifier +andes +refrigerator +ornate +##uca +ruthless +illegitimate +masonry +strasbourg +bikes +apples +quintet +willingly +niche +bakery +corpses +energetic +##cliffe +##sser +##ards +centimeters +centro +fuscous +cretaceous +rancho +##yde +andrei +telecom +tottenham +oasis +ordination +vulnerability +presiding +corey +penguins +sims +##pis +malawi +piss +correction +##cked +##ffle +##ryn +countdown +detectives +psychiatrist +psychedelic +dinosaurs +blouse +choi +vowed +randomly +##pol +49ers +scrub +blanche +bruins +dusseldorf +##using +unwanted +##ums +dominique +elevations +headlights +om +laguna +##oga +1750 +famously +ignorance +shrewsbury +breuning +che +confederacy +greco +overhaul +##screen +paz +skirts +disagreement +cruelty +jagged +phoebe +shifter +hovered +viruses +##wes +##lined +landlord +squirrel +dashed +ornamental +gag +wally +grange +literal +spurs +undisclosed +proceeding +billie +orphan +spanned +humidity +indy +weighted +presentations +explosions +lucian +##tary +vaughn +hindus +##anga +##hell +psycho +daytona +protects +efficiently +rematch +sly +tandem +##oya +rebranded +impaired +hee +metropolis +peach +godfrey +diaspora +ethnicity +prosperous +gleaming +dar +grossing +playback +##rden +stripe +pistols +##tain +births +labelled +##cating +rudy +alba +##onne +aquarium +hostility +##tase +shudder +sumatra +hardest +lakers +consonant +creeping +demos +homicide +capsule +zeke +liberties +expulsion +pueblo +##comb +trait +transporting +##ddin +##neck +##yna +depart +gregg +mold +ledge +hangar +oldham +playboy +termination +analysts +gmbh +romero +##itic +insist +cradle +filthy +brightness +slash +shootout +deposed +bordering +##truct +microwave +tumbled +sheltered +cathy +werewolves +messy +andersen +convex +clapped +clinched +satire +wasting +edo +rufus +##jak +mont +##etti +poznan +##keeping +restructuring +transverse +##rland +azerbaijani +slovene +gestures +roommate +choking +shear +##quist +vanguard +oblivious +##hiro +disagreed +baptism +##lich +coliseum +##aceae +salvage +societe +cory +locke +relocation +relying +versailles +ahl +swelling +##elo +cheerful +##edes +gin +sarajevo +obstacle +diverted +##nac +messed +thoroughbred +fluttered +utrecht +chewed +acquaintance +assassins +dispatch +mirza +##wart +salzburg +swell +yen +##gee +idle +ligue +samson +##nds +##igh +playful +spawned +##cise +tease +##case +burgundy +stirring +skeptical +interceptions +marathi +##dies +bedrooms +aroused +pinch +##lik +preferences +tattoos +buster +digitally +projecting +rust +##ital +kitten +priorities +addison +pseudo +##guard +dusk +icons +sermon +##psis +##iba +##lift +ju +truce +rink +##dah +##wy +defects +psychiatry +offences +calculate +glucose +##iful +##rized +##unda +francaise +##hari +richest +warwickshire +carly +1763 +purity +redemption +lending +##cious +muse +bruises +cerebral +aero +carving +preface +terminology +invade +monty +anarchist +blurred +##iled +rossi +treats +guts +shu +foothills +ballads +undertaking +premise +cecilia +affiliates +blasted +conditional +wilder +minors +drone +rudolph +buffy +swallowing +horton +attested +rutherford +howell +primetime +livery +penal +##bis +minimize +hydro +wrecked +wrought +palazzo +##gling +cans +vernacular +friedman +nobleman +shale +walnut +danielle +##ection +##tley +sears +##kumar +chords +lend +flipping +streamed +por +dracula +gallons +sacrifices +gamble +orphanage +##iman +mckenzie +##gible +boxers +daly +##balls +##ان +##ific +##rative +##iq +exploited +slated +##uity +circling +hillary +pinched +goldberg +provost +campaigning +piles +ironically +jong +mohan +successors +usaf +##tem +##ught +autobiographical +haute +preserves +##ending +acquitted +comparisons +hydroelectric +gangs +cypriot +torpedoes +rushes +derive +bumps +instability +fiat +pets +##mbe +silas +dye +reckless +settler +##itation +heats +##writing +canonical +maltese +fins +mushroom +stacy +aspen +avid +##kur +##loading +vickers +gaston +hillside +statutes +wilde +gail +kung +sabine +comfortably +motorcycles +##rgo +pneumonia +fetch +##sonic +axel +faintly +parallels +##oop +mclaren +spouse +compton +interdisciplinary +miner +##eni +clamped +##chal +##llah +separates +versa +##mler +scarborough +labrador +##lity +##osing +rutgers +hurdles +como +burt +divers +wichita +cade +coincided +bruised +mla +vineyard +##ili +##brush +notch +mentioning +jase +hearted +kits +doe +##acle +pomerania +##ady +ronan +seizure +pavel +problematic +##zaki +domenico +##ulin +catering +penelope +dependence +parental +emilio +ministerial +atkinson +##bolic +clarkson +chargers +colby +grill +peeked +arises +summon +##aged +fools +##grapher +faculties +qaeda +##vial +garner +refurbished +##hwa +geelong +disasters +nudged +bs +shareholder +lori +algae +reinstated +rot +##ades +##nous +invites +stainless +inclusive +##itude +diocesan +til +##icz +denomination +##xa +benton +floral +registers +##erman +##kell +absurd +brunei +guangzhou +hitter +retaliation +##uled +##eve +blanc +nh +consistency +contamination +##eres +dire +palermo +broadcasters +diaries +inspire +vols +brewer +tightening +mixtape +hormone +##tok +stokes +##color +##dly +##ssi +##ometer +##lington +sanitation +##tility +intercontinental +##adt +¹⁄₂ +cylinders +economies +favourable +unison +croix +gertrude +odyssey +vanity +dangling +##logists +upgrades +dice +middleweight +practitioner +henrik +parlor +orion +angered +lac +blurted +##rri +sensual +intends +swings +angled +##phs +husky +attain +peerage +precinct +textiles +cheltenham +shuffled +dai +confess +tasting +bhutan +##riation +tyrone +segregation +abrupt +ruiz +##rish +smirked +blackwell +confidential +browning +amounted +vase +scarce +fabulous +raided +staple +guyana +unemployed +glider +shay +##tow +carmine +troll +intervene +squash +superstar +cylindrical +len +roadway +researched +handy +##rium +##jana +lao +declares +##rring +##tadt +##elin +##kova +willem +shrubs +napoleonic +realms +skater +volkswagen +##ł +tad +hara +archaeologist +awkwardly +eerie +##kind +wiley +##heimer +titus +organizers +cfl +crusaders +lama +vent +enraged +thankful +occupants +maximilian +##gaard +possessing +textbooks +##oran +collaborator +quaker +##ulo +avalanche +mono +silky +straits +isaiah +mustang +surged +resolutions +potomac +descend +kilograms +plato +strains +saturdays +##olin +bernstein +##ype +holstein +ponytail +belize +conversely +heroine +perpetual +##ylus +charcoal +piedmont +glee +negotiating +backdrop +prologue +##jah +pasadena +climbs +ramos +sunni +##holm +##tner +##tri +anand +deficiency +hertfordshire +stout +##avi +aperture +orioles +##irs +doncaster +intrigued +bombed +coating +otis +##mat +cocktail +##jit +##eto +amir +arousal +sar +##proof +dixie +pots +whereabouts +##fted +drains +bullying +cottages +scripture +coherent +fore +poe +appetite +##uration +sampled +##ators +derrick +rotor +jays +peacock +installment +##rro +advisors +##coming +rodeo +scotch +##mot +##fen +##vant +ensued +rodrigo +dictatorship +martyrs +twenties +towed +incidence +marta +rainforest +sai +scaled +##cles +oceanic +qualifiers +symphonic +mcbride +dislike +generalized +aubrey +colonization +##iation +##lion +##ssing +disliked +lublin +salesman +##ulates +spherical +whatsoever +sweating +avalon +contention +punt +severity +alderman +atari +##dina +##grant +##rop +scarf +seville +vertices +annexation +fairfield +fascination +inspiring +launches +palatinate +regretted +##rca +feral +##iom +elk +nap +olsen +reddy +yong +##leader +##iae +garment +transports +feng +gracie +outrage +viceroy +insides +##esis +breakup +grady +organizer +softer +grimaced +murals +galicia +arranging +vectors +##rsten +##sb +##cens +sloan +##eka +bitten +ara +fender +nausea +bumped +kris +banquet +comrades +detector +persisted +##llan +adjustment +endowed +cinemas +sellers +##uman +peek +epa +kindly +neglect +simpsons +talon +mausoleum +runaway +hangul +lookout +##cic +coughed +acquainted +chloride +quicker +accordion +neolithic +##qa +artemis +coefficient +lenny +pandora +tx +##xed +ecstasy +litter +segunda +chairperson +gemma +hiss +rumor +vow +nasal +antioch +compensate +patiently +transformers +##eded +judo +morrow +penis +posthumous +bandits +husbands +denote +flaming +##any +##phones +langley +yorker +1760 +walters +##kle +gubernatorial +fatty +leroy +outlaw +##nine +unpublished +poole +jakob +##ᵢ +##ₙ +crete +distorted +superiority +##dhi +intercept +crust +mig +claus +crashes +stallion +frontal +armistice +##estinal +elton +aj +encompassing +camel +commemorated +malaria +woodward +calf +cigar +penetrate +##oso +willard +##rno +##uche +illustrate +amusing +convergence +noteworthy +##lma +##rva +journeys +realise +manfred +##sable +##vocation +hearings +fiance +##posed +educators +provoked +adjusting +##cturing +modular +stockton +paterson +vlad +rejects +electors +selena +maureen +##tres +##rce +swirled +##num +proportions +nanny +pawn +naturalist +parma +apostles +awoke +ethel +wen +##bey +monsoon +overview +##inating +mccain +rendition +risky +adorned +##ih +equestrian +germain +nj +conspicuous +confirming +##yoshi +shivering +##imeter +milestone +rumours +flinched +bounds +smacked +token +##bei +lectured +automobiles +##shore +impacted +##iable +nouns +nero +##leaf +ismail +prostitute +trams +bridget +sud +stimulus +impressions +reins +revolves +##gned +giro +honeymoon +##swell +criterion +##sms +##uil +libyan +prefers +##osition +preview +sucks +accusation +bursts +metaphor +diffusion +tolerate +faye +betting +cinematographer +liturgical +specials +bitterly +humboldt +##ckle +flux +rattled +##itzer +archaeologists +odor +authorised +marshes +discretion +##ов +alarmed +archaic +inverse +##leton +explorers +##pine +drummond +tsunami +woodlands +##minate +##tland +booklet +insanity +owning +insert +crafted +calculus +receivers +stung +##eca +##nched +prevailing +travellers +eyeing +lila +graphs +##borne +julien +##won +morale +adaptive +therapist +erica +cw +libertarian +bowman +pitches +vita +##ional +crook +##entation +caledonia +mutiny +##sible +1840s +automation +flock +##pia +ironic +pathology +##imus +remarried +joker +withstand +energies +##att +shropshire +hostages +madeleine +tentatively +conflicting +mateo +recipes +euros +mercenaries +nico +##ndon +albuquerque +augmented +mythical +bel +freud +##child +cough +##lica +freddy +lillian +genetically +nuremberg +calder +bonn +outdoors +paste +suns +urgency +vin +restraint +tyson +##cera +##selle +barrage +bethlehem +kahn +##par +mounts +nippon +barony +happier +ryu +makeshift +sheldon +blushed +castillo +barking +listener +taped +bethel +fluent +headlines +pornography +rum +disclosure +sighing +mace +doubling +gunther +manly +##plex +interventions +physiological +forwards +emerges +##tooth +##gny +compliment +rib +recession +visibly +barge +faults +connector +exquisite +prefect +##rlin +patio +##cured +elevators +italics +pena +wasp +satin +botswana +graceful +respectable +##jima +##rter +##oic +franciscan +generates +##dl +alfredo +disgusting +##olate +##iously +sherwood +warns +cod +promo +cheryl +sino +##escu +twitch +##zhi +brownish +thom +ortiz +##dron +densely +##beat +carmel +reinforce +##bana +anastasia +downhill +vertex +contaminated +remembrance +harmonic +homework +fiancee +gears +olds +angelica +ramsay +quiz +colliery +sevens +##cape +autism +##hil +walkway +##boats +ruben +abnormal +ounce +khmer +##bbe +zachary +bedside +morphology +punching +##olar +sparrow +convinces +hewitt +queer +remastered +rods +mabel +solemn +notified +lyricist +symmetric +##xide +encore +passports +wildcats +##uni +baja +##pac +mildly +##ease +bleed +commodity +mounds +glossy +orchestras +##omo +damian +prelude +ambitions +##vet +awhile +remotely +##aud +asserts +imply +##iques +distinctly +modelling +remedy +##dded +windshield +dani +xiao +##endra +audible +powerplant +invalid +elemental +acquisitions +##hala +immaculate +libby +plata +smuggling +ventilation +denoted +minh +##morphism +differed +dion +kelley +lore +mocking +sabbath +spikes +hygiene +drown +runoff +stylized +tally +liberated +aux +interpreter +righteous +aba +siren +reaper +pearce +millie +##cier +##yra +gaius +##iso +captures +##ttering +dorm +claudio +##sic +benches +knighted +blackness +##ored +discount +fumble +oxidation +routed +novak +perpendicular +spoiled +fracture +splits +pads +topology +##cats +axes +fortunate +offenders +protestants +esteem +broadband +convened +frankly +hound +prototypes +isil +facilitated +keel +##sher +sahara +awaited +bubba +orb +prosecutors +hem +##xing +relaxing +remnant +romney +sorted +slalom +stefano +ulrich +##active +exemption +folder +pauses +foliage +hitchcock +epithet +criticisms +##aca +ballistic +brody +hinduism +chaotic +youths +equals +##pala +pts +thicker +analogous +capitalist +improvised +overseeing +sinatra +ascended +beverage +straightforward +##kon +curran +bois +induce +surveying +emperors +sax +unpopular +cartoonist +fused +##mble +unto +##yuki +localities +##cko +##ln +darlington +slain +academie +lobbying +sediment +puzzles +##grass +defiance +dickens +manifest +tongues +alumnus +arbor +coincide +appalachian +mustafa +examiner +cabaret +traumatic +yves +bracelet +draining +heroin +magnum +baths +odessa +consonants +mitsubishi +##gua +kellan +vaudeville +joked +straps +probation +##ław +ceded +interfaces +##pas +##zawa +blinding +viet +rothschild +museo +huddersfield +tactic +##storm +brackets +dazed +incorrectly +##vu +reg +glazed +fearful +manifold +benefited +irony +stumbling +##rte +willingness +balkans +mei +wraps +##aba +injected +##lea +gu +syed +harmless +##hammer +bray +takeoff +poppy +timor +cardboard +astronaut +purdue +weeping +southbound +cursing +stalls +diagonal +##neer +lamar +bryce +comte +weekdays +harrington +##uba +negatively +##see +lays +grouping +##cken +##henko +affirmed +halle +modernist +##lai +hodges +smelling +aristocratic +baptized +dismiss +justification +oilers +coupling +qin +snack +healer +##qing +gardener +layla +battled +formulated +stephenson +gravitational +##gill +1768 +granny +coordinating +suites +##ioned +monarchs +##cote +##hips +blended +barrister +deposition +fia +mina +policemen +paranoid +##pressed +churchyard +covert +crumpled +creep +abandoning +tr +transmit +conceal +barr +understands +readiness +spire +##cology +##enia +startling +unlock +vida +bowled +slots +##nat +##islav +spaced +trusting +admire +rig +slack +casualty +classmates +##odes +##rar +##rked +amherst +furnished +evolve +foundry +menace +mead +##lein +flu +wesleyan +##kled +monterey +webber +##vos +wil +##mith +##на +bartholomew +justices +restrained +##cke +amenities +mediated +sewage +trenches +mainz +##thus +1800s +##cula +##inski +caine +bonding +converts +spheres +superseded +marianne +crypt +sweaty +ensign +historia +##br +spruce +##ask +forks +thoughtfully +yukon +pamphlet +ames +##uter +karma +##yya +bryn +negotiation +sighs +incapable +##mbre +##ntial +actresses +taft +##mill +luce +prevailed +##amine +1773 +motionless +envoy +testify +investing +sculpted +instructors +provence +kali +cullen +horseback +##while +goodwin +##jos +gaa +norte +##ldon +modify +wavelength +abd +skinned +sprinter +forecast +scheduling +marries +squared +tentative +##chman +boer +##isch +bolts +swap +fisherman +assyrian +impatiently +guthrie +martins +murdoch +tanya +nicely +dolly +lacy +med +syn +decks +fashionable +millionaire +surfing +heaved +tammy +consulate +attendees +routinely +fuse +saxophonist +backseat +malaya +##lord +scowl +tau +##ishly +sighted +steaming +##rks +##holes +##hong +ching +##wife +bless +conserved +jurassic +stacey +zion +chunk +rigorous +blaine +peabody +slayer +dismay +brewers +nz +##jer +det +##glia +glover +postwar +penetration +sylvester +imitation +vertically +airlift +heiress +knoxville +viva +##uin +macon +##rim +##fighter +##gonal +janice +##orescence +##wari +marius +belongings +leicestershire +blanco +inverted +preseason +sanity +sobbing +##due +##elt +##dled +collingwood +regeneration +flickering +shortest +##mount +##osi +feminism +##lat +sherlock +cabinets +fumbled +northbound +precedent +snaps +##mme +researching +##akes +guillaume +insights +manipulated +vapor +neighbour +gangster +frey +stalking +scarcely +callie +barnett +tendencies +doomed +assessing +slung +panchayat +ambiguous +bartlett +##etto +distributing +violating +wolverhampton +##hetic +swami +histoire +##urus +liable +pounder +groin +hussain +larsen +popping +surprises +##atter +vie +curt +##station +mute +relocate +musicals +authorization +richter +##sef +immortality +tna +bombings +deteriorated +yiddish +##acious +robbed +colchester +ao +verified +balancing +apostle +swayed +recognizable +oxfordshire +retention +nottinghamshire +contender +judd +invitational +shrimp +uhf +##icient +cleaner +longitudinal +tanker +##mur +acronym +broker +koppen +sundance +suppliers +##gil +clipped +fuels +petite +##anne +landslide +helene +diversion +populous +landowners +auspices +melville +quantitative +##xes +ferries +nicky +##llus +doo +haunting +roche +carver +downed +unavailable +##pathy +approximation +hiroshima +##hue +garfield +valle +comparatively +keyboardist +traveler +##eit +congestion +calculating +subsidiaries +##bate +serb +modernization +fairies +deepened +ville +averages +##lore +inflammatory +tonga +##itch +co₂ +squads +##hea +gigantic +serum +enjoyment +retailer +verona +35th +cis +##phobic +magna +technicians +##vati +arithmetic +##sport +levin +##dation +amtrak +chow +sienna +##eyer +backstage +entrepreneurship +##otic +learnt +tao +##udy +worcestershire +formulation +baggage +hesitant +bali +sabotage +##kari +barren +enhancing +murmur +pl +freshly +putnam +syntax +aces +medicines +resentment +bandwidth +##sier +grins +chili +guido +##sei +framing +implying +gareth +lissa +genevieve +pertaining +admissions +geo +thorpe +proliferation +sato +bela +analyzing +parting +##gor +awakened +##isman +huddled +secrecy +##kling +hush +gentry +dungeons +##ego +coasts +##utz +sacrificed +##chule +landowner +mutually +prevalence +programmer +adolescent +disrupted +seaside +gee +trusts +vamp +georgie +##nesian +##iol +schedules +sindh +##market +etched +hm +sparse +bey +beaux +scratching +gliding +unidentified +collaborating +gems +jesuits +oro +accumulation +shaping +mbe +anal +##xin +enthusiasts +newscast +##egan +janata +dewey +parkinson +ankara +biennial +towering +inconsistent +##chet +thriving +terminate +cabins +furiously +eats +advocating +donkey +marley +muster +phyllis +leiden +##user +grassland +glittering +iucn +loneliness +memorandum +armenians +##ddle +popularized +rhodesia +60s +lame +##illon +sans +bikini +header +orbits +##finger +##ulator +sharif +spines +biotechnology +strolled +naughty +yates +##wire +fremantle +milo +##mour +abducted +removes +##atin +humming +##chrome +##ester +hume +pivotal +##rates +armand +grams +believers +elector +rte +apron +bis +scraped +##yria +endorsement +initials +##llation +dotted +hints +buzzing +emigration +nearer +indicators +##ulu +coarse +neutron +protectorate +##uze +directional +exploits +pains +loire +1830s +proponents +guggenheim +rabbits +ritchie +hectare +inputs +hutton +##raz +verify +##ako +boilers +longitude +##lev +skeletal +yer +emilia +citrus +compromised +##gau +prescription +paragraph +eduard +cadillac +attire +categorized +kenyan +weddings +charley +##bourg +entertain +monmouth +##lles +nutrients +davey +mesh +incentive +practised +ecosystems +kemp +subdued +overheard +##rya +bodily +maxim +##nius +apprenticeship +ursula +##fight +lodged +rug +silesian +unconstitutional +patel +inspected +coyote +unbeaten +##hak +34th +disruption +convict +parcel +##nham +collier +implicated +mallory +##iac +susannah +winkler +##rber +shia +phelps +sediments +graphical +robotic +##sner +adulthood +mart +smoked +##isto +kathryn +clarified +##aran +divides +convictions +oppression +pausing +burying +##mt +federico +mathias +eileen +##tana +kite +hunched +##acies +##atz +disadvantage +liza +kinetic +greedy +paradox +yokohama +dowager +trunks +ventured +##gement +gupta +vilnius +olaf +##thest +crimean +hopper +##ej +progressively +arturo +mouthed +arrondissement +##fusion +rubin +simulcast +oceania +##orum +##stra +##rred +busiest +intensely +navigator +cary +##vine +##hini +##bies +fife +rowe +rowland +posing +insurgents +shafts +lawsuits +activate +conor +inward +culturally +garlic +##eering +eclectic +##hui +##kee +##nl +furrowed +vargas +meteorological +rendezvous +##aus +culinary +commencement +##dition +quota +##notes +mommy +salaries +overlapping +mule +##iology +##mology +sums +wentworth +##isk +##zione +mainline +subgroup +##illy +hack +plaintiff +verdi +bulb +differentiation +engagements +multinational +supplemented +bertrand +caller +regis +##naire +##sler +##arts +##imated +blossom +propagation +kilometer +viaduct +vineyards +##uate +beckett +optimization +golfer +songwriters +seminal +semitic +thud +volatile +evolving +ridley +##wley +trivial +distributions +scandinavia +jiang +wrestled +insistence +emphasizes +napkin +##ods +adjunct +rhyme +##ricted +##eti +hopeless +surrounds +tremble +32nd +smoky +##ntly +oils +medicinal +padded +steer +wilkes +concessions +hue +uniquely +blinded +landon +##lane +hendrix +commemorating +dex +specify +chicks +##ggio +intercity +morley +##torm +highlighting +##oting +pang +oblique +stalled +##liner +flirting +newborn +1769 +bishopric +shaved +currie +dharma +spartan +##ooped +favorites +smug +novella +sirens +abusive +creations +espana +##lage +paradigm +semiconductor +sheen +##rdo +##yen +##zak +nrl +renew +##pose +##tur +adjutant +marches +norma +##enity +ineffective +weimar +grunt +##gat +lordship +plotting +expenditure +infringement +lbs +refrain +mimi +mistakenly +postmaster +1771 +##bara +ras +motorsports +tito +subjective +##zza +bully +stew +##kaya +prescott +##raphic +##zam +bids +styling +paranormal +reeve +sneaking +exploding +katz +akbar +migrant +syllables +indefinitely +##ogical +destroys +replaces +applause +##phine +pest +##fide +articulated +bertie +##cars +##ptic +courtroom +crowley +aesthetics +cummings +tehsil +hormones +titanic +dangerously +##ibe +stadion +jaenelle +auguste +ciudad +##chu +mysore +partisans +lucan +philipp +##aly +debating +henley +interiors +##rano +##tious +homecoming +beyonce +usher +henrietta +prepares +weeds +ely +plucked +##pire +##dable +luxurious +##aq +artifact +password +pasture +juno +maddy +minsk +##dder +##ologies +##rone +assessments +martian +royalist +1765 +examines +##mani +nino +parry +scooped +relativity +##eli +##uting +##cao +congregational +noisy +traverse +##agawa +strikeouts +nickelodeon +obituary +transylvania +binds +depictions +polk +trolley +##yed +##lard +breeders +##under +dryly +hokkaido +1762 +strengths +stacks +bonaparte +neared +prostitutes +stamped +anaheim +gutierrez +sinai +##zzling +bram +fresno +madhya +proton +##lena +##llum +##phon +reelected +wanda +##anus +##lb +ample +distinguishing +##yler +grasping +sermons +tomato +bland +stimulation +avenues +##eux +spreads +scarlett +fern +pentagon +assert +baird +chesapeake +calmed +distortion +fatalities +##olis +correctional +pricing +##astic +##gina +prom +dammit +ying +collaborate +##chia +welterweight +33rd +pointer +substitution +bonded +umpire +communicating +multitude +paddle +##obe +federally +intimacy +##insky +betray +ssr +##lett +##lves +##therapy +airbus +##tery +functioned +ud +bearer +biomedical +##hire +##nca +condom +brink +ik +##nical +macy +flap +gma +experimented +jelly +lavender +##icles +##ulia +munro +##mian +##tial +rye +##rle +60th +gigs +hottest +rotated +predictions +fuji +bu +##erence +##omi +barangay +##fulness +##sas +clocks +##rwood +##liness +cereal +roe +wight +decker +uttered +babu +onion +forcibly +##df +petra +sarcasm +hartley +peeled +storytelling +##xley +##ysis +##ffa +fibre +kiel +auditor +fig +harald +greenville +##berries +geographically +nell +quartz +##athic +cemeteries +crossings +nah +holloway +reptiles +chun +sichuan +snowy +corrections +##ivo +zheng +ambassadors +blacksmith +fielded +fluids +hardcover +turnover +medications +melvin +academies +##erton +roach +absorbing +spaniards +colton +##founded +outsider +espionage +kelsey +edible +##ulf +dora +establishes +##sham +##tries +contracting +##tania +cinematic +costello +nesting +##uron +connolly +duff +##nology +mma +##mata +fergus +sexes +optics +spectator +woodstock +banning +##hee +##fle +differentiate +outfielder +refinery +gerhard +horde +lair +drastically +##udi +landfall +##cheng +motorsport +odi +##achi +predominant +quay +skins +##ental +edna +harshly +complementary +murdering +##aves +wreckage +ono +outstretched +lennox +munitions +galen +reconcile +scalp +bicycles +gillespie +questionable +rosenberg +guillermo +jarvis +kabul +opium +yd +##twined +abuses +decca +outpost +##cino +sensible +neutrality +ponce +anchorage +atkins +turrets +inadvertently +disagree +libre +vodka +reassuring +weighs +##yal +glide +jumper +ceilings +repertory +outs +stain +##bial +envy +##ucible +smashing +heightened +policing +hyun +mixes +lai +prima +##ples +celeste +##bina +lucrative +intervened +kc +manually +##rned +stature +staffed +bun +bastards +nairobi +priced +##auer +thatcher +##kia +tripped +comune +##ogan +##pled +brasil +incentives +emanuel +hereford +musica +##kim +benedictine +biennale +##lani +eureka +gardiner +rb +knocks +sha +##ael +##elled +##onate +efficacy +ventura +masonic +sanford +maize +leverage +##feit +capacities +santana +##aur +novelty +vanilla +##cter +##tour +benin +##oir +neptune +drafting +tallinn +##cable +humiliation +##boarding +schleswig +fabian +bernardo +liturgy +spectacle +sweeney +pont +routledge +cosmos +ut +hilt +sleek +universally +##eville +##gawa +typed +##dry +favors +allegheny +glaciers +##rly +recalling +aziz +parasite +requiem +auf +##berto +##llin +illumination +##breaker +##issa +festivities +bows +govern +vibe +vp +sprawled +larson +pilgrim +bwf +leaping +##rts +##ssel +alexei +greyhound +hoarse +##dler +##oration +seneca +##cule +gaping +##ulously +##pura +cinnamon +##gens +##rricular +craven +fantasies +houghton +engined +reigned +dictator +supervising +##oris +bogota +commentaries +unnatural +fingernails +spirituality +tighten +canadiens +protesting +intentional +cheers +sparta +##ytic +##iere +##zine +widen +belgarath +controllers +dodd +iaaf +navarre +##ication +defect +squire +steiner +whisky +##mins +inevitably +tome +##gold +chew +##lid +elastic +##aby +streaked +alliances +jailed +regal +##ined +##phy +czechoslovak +narration +absently +##uld +bluegrass +guangdong +quran +criticizing +hose +hari +##liest +##owa +skier +streaks +deploy +##lom +raft +bose +dialed +huff +##eira +haifa +simplest +bursting +endings +sultanate +##titled +franks +whitman +ensures +sven +##ggs +collaborators +forster +organising +banished +napier +injustice +teller +layered +thump +##otti +roc +battleships +evidenced +fugitive +sadie +robotics +##roud +equatorial +geologist +##iza +yielding +##bron +##sr +internationale +mecca +##diment +skyline +toad +uploaded +reflective +undrafted +lal +leafs +bayern +##dai +lakshmi +shortlisted +##stick +##wicz +camouflage +donate +christi +lau +##acio +disclosed +nemesis +1761 +assemble +straining +northamptonshire +tal +##asi +bernardino +premature +heidi +42nd +coefficients +galactic +reproduce +buzzed +sensations +zionist +monsieur +myrtle +archery +strangled +musically +viewpoint +antiquities +bei +trailers +seahawks +cured +pee +preferring +tasmanian +lange +sul +##working +colder +overland +lucivar +massey +gatherings +haitian +##smith +disapproval +flaws +##cco +##enbach +1766 +npr +##icular +boroughs +creole +forums +techno +1755 +dent +abdominal +streetcar +##eson +##stream +procurement +gemini +predictable +##tya +acheron +christoph +feeder +fronts +vendor +bernhard +jammu +tumors +slang +##uber +goaltender +twists +curving +manson +vuelta +mer +peanut +confessions +pouch +unpredictable +allowance +theodor +vascular +##factory +bala +authenticity +metabolic +coughing +nanjing +##cea +pembroke +##bard +splendid +36th +hourly +##ahu +elmer +handel +##ivate +awarding +thrusting +experimentation +##hesion +caressed +entertained +steak +##rangle +biologist +orphans +baroness +oyster +stepfather +##dridge +mirage +reefs +speeding +barons +1764 +inhabit +preached +repealed +##tral +honoring +boogie +captives +administer +johanna +##imate +gel +suspiciously +1767 +sobs +##dington +backbone +hayward +garry +##folding +##nesia +maxi +##oof +##ppe +ellison +galileo +##stand +crimea +frenzy +amour +bumper +matrices +natalia +baking +garth +palestinians +##grove +smack +conveyed +ensembles +gardening +##manship +##rup +##stituting +1640 +harvesting +topography +shifters +dormitory +##carriage +##lston +ist +skulls +##stadt +dolores +jewellery +sarawak +##wai +##zier +fences +christy +confinement +tumbling +credibility +fir +stench +##bria +##plication +##nged +##sam +virtues +##belt +marjorie +pba +##eem +##made +celebrates +schooner +agitated +barley +fulfilling +anthropologist +restrict +novi +regulating +##nent +padres +##rani +##hesive +loyola +tabitha +milky +olson +proprietor +crambidae +guarantees +intercollegiate +ljubljana +hilda +##sko +ignorant +hooded +sardinia +##lidae +##vation +frontman +privileged +witchcraft +jammed +laude +poking +##than +bracket +amazement +yunnan +##erus +maharaja +linnaeus +commissioning +milano +peacefully +##logies +akira +rani +regulator +grasses +##rance +luzon +crows +compiler +gretchen +seaman +edouard +buccaneers +ellington +hamlets +whig +socialists +##anto +directorial +easton +mythological +##kr +##vary +rhineland +semantic +taut +dune +inventions +succeeds +##iter +replication +branched +##pired +prosecuted +kangaroo +penetrated +##avian +middlesbrough +doses +bleak +madam +predatory +relentless +##vili +reluctance +##vir +hailey +crore +silvery +1759 +monstrous +swimmers +transmissions +hawthorn +informing +##eral +toilets +caracas +crouch +##sett +cartel +hadley +##aling +alexia +yvonne +##biology +cinderella +eton +superb +blizzard +stabbing +industrialist +maximus +##orus +groves +maud +clade +oversized +comedic +##bella +rosen +nomadic +fulham +montane +beverages +galaxies +redundant +swarm +##rot +##folia +##llis +buckinghamshire +fen +bearings +bahadur +##rom +gilles +phased +dynamite +faber +benoit +##ount +fractured +tailored +anya +spices +westwood +cairns +auditions +inflammation +steamed +##rocity +##acion +##urne +skyla +thereof +watford +torment +archdeacon +transforms +demeanor +fucked +serge +##sor +mckenna +minas +entertainer +##icide +caress +originate +residue +##sty +1740 +##ilised +##org +beech +##wana +subsidies +##ghton +emptied +gladstone +firefighters +voodoo +het +nightingale +tamara +edmond +ingredient +weaknesses +silhouette +compatibility +withdrawing +hampson +##mona +anguish +giggling +bookstore +southernmost +tilting +##vance +bai +economical +briefcase +dreadful +hinted +projections +shattering +totaling +##rogate +analogue +indicted +periodical +fullback +##dman +haynes +##tenberg +##ffs +##ishment +1745 +thirst +stumble +penang +vigorous +##ddling +##kor +##lium +octave +##ove +##enstein +##inen +##ones +siberian +##uti +cbn +repeal +swaying +##vington +khalid +tanaka +unicorn +otago +plastered +lobe +riddle +##rella +perch +##ishing +croydon +filtered +graeme +tripoli +##ossa +crocodile +##chers +sufi +mined +##tung +inferno +lsu +##phi +swelled +utilizes +£2 +cale +periodicals +styx +hike +informally +coop +lund +##tidae +ala +hen +qui +transformations +disposed +sheath +chickens +##cade +fitzroy +silesia +unacceptable +odisha +1650 +sabrina +spokane +ratios +athena +massage +shen +dilemma +##drum +##riz +##hul +corona +doubtful +niall +##pha +##bino +fines +cite +acknowledging +bangor +ballard +bathurst +##resh +huron +mustered +alzheimer +garments +kinase +tyre +warship +flashback +pulmonary +braun +cheat +kamal +cyclists +constructions +grenades +ndp +traveller +excuses +stomped +signalling +trimmed +futsal +mosques +relevance +##wine +wta +##vah +hoc +##riding +optimistic +##´s +deco +interacting +rejecting +moniker +waterways +##ieri +##oku +mayors +gdansk +outnumbered +pearls +##ended +##hampton +fairs +totals +dominating +notions +stairway +compiling +pursed +commodities +grease +yeast +##jong +carthage +griffiths +residual +amc +contraction +laird +sapphire +##marine +##ivated +amalgamation +dissolve +inclination +lyle +packaged +altitudes +suez +canons +graded +lurched +narrowing +boasts +guise +enrico +##ovsky +rower +scarred +bree +cub +iberian +protagonists +bargaining +proposing +trainers +voyages +fishes +##aea +##ivist +##verance +encryption +artworks +kazan +sabre +cleopatra +hepburn +rotting +supremacy +mecklenburg +##brate +burrows +hazards +outgoing +flair +organizes +##ctions +scorpion +##usions +boo +chevalier +dunedin +slapping +ineligible +pensions +##omic +manufactures +emails +bismarck +weakening +blackish +ding +mcgee +quo +##rling +northernmost +manpower +greed +sampson +clicking +##ange +##horpe +##inations +##roving +torre +##eptive +##moral +symbolism +38th +asshole +meritorious +outfits +splashed +biographies +sprung +astros +##tale +filly +raoul +nw +tokugawa +linden +clubhouse +##apa +tracts +romano +##pio +putin +chained +dickson +gunshot +moe +gunn +rashid +##tails +zipper +##bas +##nea +contrasted +##ply +##udes +plum +pharaoh +##pile +aw +comedies +ingrid +sandwiches +subdivisions +mariana +kamen +hz +delaney +veto +herring +##words +possessive +outlines +##roup +siemens +stairwell +gallantry +messiah +palais +yells +zeppelin +bolivar +##cede +smackdown +mckinley +##mora +##yt +muted +geologic +finely +unitary +avatar +hamas +maynard +rees +bog +contrasting +##rut +liv +chico +disposition +##erate +becca +dmitry +yeshiva +narratives +##lva +##ulton +mercenary +sharpe +tempered +navigate +stealth +amassed +keynes +##lini +untouched +##rrie +havoc +lithium +##fighting +abyss +graf +southward +wolverine +balloons +implements +ngos +transitions +##icum +ambushed +concacaf +dormant +economists +##dim +costing +csi +rana +universite +boulders +verity +##llon +collin +mellon +misses +cypress +fluorescent +lifeless +spence +##ulla +crewe +shepard +pak +revelations +jolly +gibbons +paw +##dro +##quel +freeing +shack +fries +palatine +##hiko +accompaniment +cruising +recycled +##aver +erwin +sorting +synthesizers +dyke +realities +strides +enslaved +wetland +##ghan +competence +gunpowder +grassy +maroon +reactors +objection +##oms +carlson +gearbox +macintosh +radios +shelton +##sho +clergyman +prakash +mongols +trophies +oricon +stimuli +twenty20 +cantonese +cortes +mirrored +##saurus +bhp +cristina +melancholy +##lating +enjoyable +nuevo +##wny +downfall +schumacher +##ind +banging +lausanne +rumbled +paramilitary +reflex +ax +amplitude +migratory +##gall +##ups +midi +barnard +lastly +sherry +##nall +keystone +##kra +carleton +slippery +coloring +foe +socket +otter +##rgos +mats +##tose +consultants +bafta +bison +topping +primal +abandonment +transplant +atoll +hideous +mort +pained +reproduced +tae +howling +##turn +unlawful +billionaire +hotter +poised +lansing +##chang +dinamo +retro +messing +domesday +##mina +blitz +timed +##athing +##kley +ascending +gesturing +##izations +signaled +tis +chinatown +mermaid +savanna +jameson +##aint +catalina +##pet +##hers +cochrane +cy +chatting +##kus +alerted +computation +mused +noelle +majestic +mohawk +campo +octagonal +##sant +##hend +aspiring +##mart +comprehend +iona +paralyzed +shimmering +swindon +rhone +##eley +reputed +configurations +pitchfork +agitation +francais +gillian +lipstick +##ilo +outsiders +pontifical +resisting +bitterness +sewer +rockies +##edd +##ucher +misleading +1756 +exiting +galloway +##nging +risked +##heart +commemoration +schultz +##rka +integrating +##rsa +poses +shrieked +##weiler +guineas +gladys +jerking +owls +goldsmith +nightly +penetrating +##unced +lia +ignited +betsy +##aring +##thorpe +follower +vigorously +##rave +coded +kiran +knit +zoology +tbilisi +##bered +repository +govt +deciduous +dino +growling +##bba +enhancement +unleashed +chanting +pussy +biochemistry +##eric +kettle +repression +toxicity +nrhp +##arth +##kko +##bush +ernesto +commended +outspoken +mca +parchment +kristen +##aton +bisexual +raked +glamour +navajo +conditioned +showcased +##hma +spacious +youthful +##esa +usl +appliances +junta +brest +layne +conglomerate +enchanted +chao +loosened +picasso +circulating +inspect +montevideo +##centric +##kti +piazza +spurred +##aith +bari +freedoms +poultry +stamford +lieu +indigo +sarcastic +bahia +stump +attach +dvds +frankenstein +lille +approx +scriptures +pollen +##script +nmi +overseen +##ivism +tides +proponent +newmarket +inherit +milling +##erland +centralized +##rou +distributors +credentials +drawers +abbreviation +##lco +downing +uncomfortably +ripe +##oes +erase +franchises +populace +##bery +##khar +decomposition +pleas +##tet +daryl +sabah +##wide +fearless +genie +lesions +annette +##ogist +oboe +appendix +nair +dripped +petitioned +maclean +mosquito +parrot +hampered +1648 +operatic +reservoirs +##tham +irrelevant +jolt +summarized +##fp +medallion +##taff +clawed +harlow +narrower +goddard +marcia +bodied +fremont +suarez +altering +tempest +mussolini +porn +##isms +sweetly +oversees +walkers +solitude +grimly +shrines +ich +supervisors +hostess +dietrich +legitimacy +brushes +expressive +##yp +dissipated +##rse +localized +systemic +##nikov +gettysburg +##uaries +dialogues +muttering +housekeeper +sicilian +discouraged +##frey +beamed +kaladin +halftime +kidnap +##amo +##llet +1754 +synonymous +depleted +instituto +insulin +reprised +##opsis +clashed +##ctric +interrupting +radcliffe +insisting +medici +1715 +ejected +playfully +turbulent +starvation +##rini +shipment +rebellious +petersen +verification +merits +##rified +cakes +##charged +1757 +milford +shortages +spying +fidelity +##aker +emitted +storylines +harvested +seismic +##iform +cheung +kilda +theoretically +barbie +lynx +##rgy +##tius +goblin +mata +poisonous +##nburg +reactive +residues +obedience +##евич +conjecture +##rac +hating +sixties +kicker +moaning +motown +##bha +emancipation +neoclassical +##hering +consoles +ebert +professorship +##tures +sustaining +assaults +obeyed +affluent +incurred +tornadoes +##eber +##zow +emphasizing +highlanders +cheated +helmets +##ctus +internship +terence +bony +executions +legislators +berries +peninsular +tinged +##aco +1689 +amplifier +corvette +ribbons +lavish +pennant +##lander +worthless +##chfield +##forms +mariano +pyrenees +expenditures +##icides +chesterfield +mandir +tailor +39th +sergey +nestled +willed +aristocracy +devotees +goodnight +raaf +rumored +weaponry +remy +appropriations +harcourt +burr +riaa +##lence +limitation +unnoticed +guo +soaking +swamps +##tica +collapsing +tatiana +descriptive +brigham +psalm +##chment +maddox +##lization +patti +caliph +##aja +akron +injuring +serra +##ganj +basins +##sari +astonished +launcher +##church +hilary +wilkins +sewing +##sf +stinging +##fia +##ncia +underwood +startup +compilations +vibrations +embankment +jurist +bard +juventus +groundwater +kern +palaces +helium +boca +cramped +marissa +soto +##worm +jae +princely +##ggy +faso +bazaar +warmly +##voking +pairing +##lite +##grate +##nets +wien +freaked +ulysses +rebirth +##alia +mummy +guzman +jimenez +stilled +##nitz +trajectory +tha +woken +archival +professions +##pts +##pta +hilly +shadowy +shrink +##bolt +norwood +glued +migrate +stereotypes +devoid +##pheus +evacuate +horrors +infancy +gotham +knowles +optic +downloaded +sachs +kingsley +parramatta +darryl +mor +##onale +shady +commence +confesses +kan +##meter +##placed +marlborough +roundabout +regents +frigates +##imating +gothenburg +revoked +carvings +clockwise +convertible +intruder +##sche +banged +##ogo +vicky +bourgeois +##mony +dupont +footing +##gum +##real +buckle +yun +penthouse +sane +serviced +stakeholders +neumann +##eers +comb +##gam +catchment +pinning +rallies +typing +##elles +forefront +freiburg +sweetie +giacomo +widowed +goodwill +worshipped +aspirations +midday +##vat +fishery +##trick +bournemouth +turk +hearth +ethanol +guadalajara +murmurs +sl +##uge +afforded +scripted +##hta +wah +##jn +coroner +translucent +memorials +puck +progresses +clumsy +##race +candace +recounted +##slin +##uve +filtering +##mac +howl +strata +heron +leveled +##ays +dubious +##oja +##wheel +citations +exhibiting +##laya +##mics +turkic +##lberg +injunction +##ennial +antibodies +organise +##rigues +cardiovascular +cushion +inverness +##zquez +dia +cocoa +sibling +##tman +##roid +expanse +feasible +tunisian +algiers +##relli +rus +dso +westphalia +bro +tacoma +downloads +##ours +konrad +duran +##hdi +continuum +jett +compares +legislator +secession +##nable +##gues +##zuka +translating +reacher +##gley +##ła +aleppo +##agi +orchards +trapping +linguist +versatile +drumming +postage +calhoun +superiors +##mx +barefoot +leary +##cis +ignacio +alfa +kaplan +##rogen +bratislava +mori +##vot +disturb +haas +cartridges +gilmore +radiated +salford +tunic +hades +##ulsive +archeological +delilah +magistrates +auditioned +brewster +charters +empowerment +blogs +cappella +dynasties +iroquois +whipping +##krishna +raceway +truths +myra +weaken +judah +mcgregor +##horse +mic +refueling +37th +burnley +bosses +markus +premio +query +##gga +dunbar +##economic +darkest +lyndon +sealing +commendation +reappeared +##mun +addicted +ezio +slaughtered +satisfactory +shuffle +##eves +##thic +##uj +fortification +warrington +##otto +resurrected +fargo +mane +##utable +##lei +foreword +ox +##aris +##vern +abrams +hua +##mento +sakura +##alo +sentimental +##skaya +midfield +##eses +sturdy +scrolls +macleod +##kyu +entropy +##lance +mitochondrial +cicero +excelled +thinner +convoys +perceive +##oslav +##urable +systematically +grind +burkina +##tagram +ops +##aman +guantanamo +##cloth +##tite +forcefully +wavy +##jou +pointless +##linger +##tze +layton +portico +superficial +clerical +outlaws +##hism +burials +muir +##inn +creditors +hauling +rattle +##leg +calais +monde +archers +reclaimed +dwell +wexford +hellenic +falsely +remorse +##tek +dough +furnishings +##uttered +gabon +neurological +novice +##igraphy +contemplated +pulpit +nightstand +saratoga +##istan +documenting +pulsing +taluk +##firmed +busted +marital +##rien +disagreements +wasps +##yes +hodge +mcdonnell +mimic +fran +pendant +dhabi +musa +##nington +congratulations +argent +darrell +concussion +losers +regrets +thessaloniki +reversal +donaldson +hardwood +thence +achilles +ritter +##eran +demonic +jurgen +prophets +goethe +eki +classmate +##cking +yank +irrational +##inging +perished +seductive +qur +sourced +##crat +##typic +mustard +ravine +barre +horizontally +characterization +phylogenetic +boise +##dit +##runner +##tower +brutally +intercourse +seduce +##bbing +fay +ferris +ogden +amar +nik +unarmed +##inator +evaluating +kyrgyzstan +sweetness +##lford +##oki +mccormick +meiji +notoriety +stimulate +disrupt +figuring +instructional +mcgrath +##zoo +groundbreaking +##lto +flinch +khorasan +agrarian +bengals +mixer +radiating +##sov +ingram +pitchers +nad +tariff +##cript +tata +##codes +##emi +##ungen +appellate +lehigh +##bled +##giri +brawl +duct +texans +##ciation +##ropolis +skipper +speculative +vomit +doctrines +stresses +davy +graders +whitehead +jozef +timely +cumulative +haryana +paints +appropriately +boon +cactus +##ales +##pid +dow +legions +##pit +perceptions +1730 +picturesque +##yse +periphery +rune +wr +##aha +celtics +sentencing +whoa +##erin +confirms +variance +moines +mathews +spade +rave +fronted +blending +alleging +reared +##paper +grassroots +eroded +##physical +directs +ordeal +##sław +accelerate +hacker +rooftop +##inia +lev +buys +cebu +devote +##lce +specialising +##ulsion +choreographed +repetition +warehouses +##ryl +paisley +tuscany +analogy +sorcerer +hash +huts +shards +descends +exclude +nix +chaplin +ito +vane +##drich +causeway +misconduct +limo +orchestrated +glands +jana +##kot +u2 +##sons +branching +contrasts +scoop +longed +##virus +chattanooga +syrup +cornerstone +##tized +##mind +##iaceae +careless +precedence +frescoes +##uet +chilled +consult +modelled +snatch +peat +##thermal +caucasian +humane +relaxation +spins +temperance +##lbert +occupations +lambda +hybrids +moons +##oese +rolf +societal +yerevan +ness +##ssler +befriended +mechanized +nominate +trough +boasted +cues +seater +##hom +bends +##tangle +conductors +emptiness +eurasian +adriatic +tian +##cie +anxiously +lark +propellers +chichester +jock +##holding +credible +recounts +tori +loyalist +abduction +##hoot +##redo +nepali +##mite +ventral +tempting +##ango +##crats +steered +##wice +javelin +dipping +laborers +prentice +looming +titanium +badges +emir +tensor +##ntation +egyptians +rash +denies +hawthorne +lombard +showers +wehrmacht +dietary +trojan +##reus +welles +executing +horseshoe +lifeboat +##lak +elsa +infirmary +nearing +roberta +boyer +mutter +trillion +joanne +##fine +##oked +sinks +vortex +uruguayan +clasp +sirius +##block +accelerator +prohibit +sunken +byu +chronological +diplomats +ochreous +symmetrical +1644 +maia +##tology +salts +reigns +atrocities +##ия +hess +bared +issn +##vyn +cater +saturated +##cycle +##isse +sable +voyager +dyer +yusuf +##inge +fountains +wolff +##nni +engraving +rollins +atheist +ominous +##ault +herr +chariot +martina +strung +##fell +##farlane +horrific +sahib +gazes +saetan +erased +ptolemy +##olic +flushing +lauderdale +analytic +##ices +navarro +beak +gorilla +herrera +broom +guadalupe +raiding +sykes +bsc +deliveries +1720 +invasions +carmichael +tajikistan +thematic +ecumenical +sentiments +onstage +##rians +##brand +##sume +catastrophic +flanks +molten +##arns +waller +aimee +terminating +##icing +alternately +##oche +nehru +printers +outraged +##eving +empires +template +banners +repetitive +za +##oise +vegetarian +##tell +guiana +opt +cavendish +lucknow +synthesized +##hani +##mada +finalized +##ctable +fictitious +mayoral +unreliable +##enham +embracing +peppers +rbis +##chio +##neo +inhibition +slashed +togo +orderly +embroidered +salty +barron +benito +totaled +##dak +pubs +simulated +caden +devin +tolkien +momma +welding +sesame +##ept +gottingen +hardness +shaman +temeraire +adequately +pediatric +assertion +radicals +composure +cadence +seafood +beaufort +lazarus +mani +warily +cunning +kurdistan +cantata +##kir +ares +##clusive +nape +townland +geared +insulted +flutter +boating +violate +draper +dumping +malmo +##hh +##romatic +firearm +alta +bono +obscured +##clave +exceeds +panorama +unbelievable +##train +preschool +##essed +disconnected +installing +rescuing +secretaries +accessibility +##castle +##ifice +##film +bouts +slug +waterway +mindanao +##buro +##ratic +halves +calming +liter +maternity +adorable +bragg +electrification +mcc +##dote +roxy +schizophrenia +munoz +kaye +whaling +mil +tingling +tolerant +##ago +unconventional +volcanoes +##finder +deportivo +##llie +robson +kaufman +neuroscience +wai +deportation +masovian +scraping +converse +##bh +hacking +bulge +##oun +administratively +yao +mammoth +booster +claremont +hooper +nomenclature +pursuits +mclaughlin +melinda +##sul +catfish +barclay +substrates +taxa +zee +kimberly +packets +padma +##ality +borrowing +ostensibly +solvent +##bri +##genesis +##mist +lukas +shreveport +veracruz +##lou +##wives +cheney +anatolia +hobbs +##zyn +cyclic +radiant +alistair +greenish +siena +dat +independents +##bation +conform +pieter +hyper +applicant +bradshaw +spores +telangana +vinci +inexpensive +nuclei +jang +nme +spd +cradled +receptionist +pow +##rika +fascism +##ifer +experimenting +##ading +##iec +##region +jocelyn +maris +stair +nocturnal +toro +constabulary +elgin +##kker +msc +##giving +##schen +##rase +doherty +doping +sarcastically +batter +maneuvers +##cano +##apple +##gai +##git +intrinsic +##nst +##stor +1753 +showtime +cafes +gasps +lviv +ushered +##thed +fours +restart +astonishment +transmitting +flyer +shrugs +##sau +intriguing +cones +dictated +mushrooms +medial +##kovsky +##elman +escorting +gaped +godfather +##door +##sell +djs +recaptured +timetable +vila +1710 +aerodrome +mortals +scientology +##orne +angelina +mag +convection +unpaid +insertion +intermittent +lego +##nated +endeavor +kota +pereira +##lz +bwv +glamorgan +insults +agatha +fey +##cend +fleetwood +mahogany +protruding +steamship +zeta +##arty +mcguire +suspense +##sphere +advising +urges +##wala +hurriedly +meteor +gilded +inline +arroyo +stalker +##oge +excitedly +revered +##cure +earle +introductory +##break +##ilde +mutants +puff +pulses +reinforcement +##haling +curses +lizards +stalk +correlated +##fixed +fallout +macquarie +##unas +bearded +denton +heaving +##ocation +winery +assign +dortmund +##lkirk +everest +invariant +charismatic +susie +##elling +bled +lesley +telegram +sumner +bk +##ogen +wilcox +needy +colbert +duval +##iferous +##mbled +allotted +attends +imperative +##hita +replacements +hawker +##inda +insurgency +##zee +##eke +casts +##yla +ives +transitioned +##pack +##powering +authoritative +baylor +flex +cringed +plaintiffs +woodrow +##skie +drastic +ape +aroma +unfolded +commotion +preoccupied +theta +routines +lasers +privatization +wand +domino +ek +clenching +nsa +strategically +showered +bile +handkerchief +pere +storing +christophe +insulting +nakamura +romani +asiatic +magdalena +palma +cruises +stripping +konstantin +soaring +##berman +colloquially +forerunner +havilland +incarcerated +parasites +sincerity +##utus +disks +plank +saigon +##ining +corbin +homo +ornaments +powerhouse +##tlement +chong +fastened +feasibility +idf +morphological +usable +##nish +##zuki +aqueduct +jaguars +keepers +##flies +aleksandr +faust +assigns +ewing +bacterium +hurled +tricky +hungarians +integers +wallis +yamaha +##isha +hushed +oblivion +aviator +evangelist +friars +##eller +monograph +ode +##nary +airplanes +labourers +charms +##nee +1661 +hagen +tnt +rudder +fiesta +transcript +dorothea +ska +inhibitor +maccabi +retorted +raining +encompassed +clauses +menacing +1642 +lineman +##gist +vamps +##dick +gloom +##rera +dealings +easing +seekers +##nut +##pment +helens +unmanned +##anu +##isson +basics +##amy +##ckman +adjustments +1688 +brutality +horne +##zell +##mable +aggregator +##thal +rhino +##drick +##vira +counters +##rting +mn +montenegrin +packard +##unciation +##♭ +##kki +reclaim +scholastic +thugs +pulsed +##icia +syriac +quan +saddam +banda +kobe +blaming +buddies +dissent +##lusion +##usia +corbett +jaya +delle +erratic +lexie +##hesis +amiga +hermes +##pressing +##leen +chapels +gospels +jamal +##uating +compute +revolving +warp +##sso +##thes +armory +##eras +##gol +antrim +loki +##kow +##asian +##good +##zano +braid +handwriting +subdistrict +funky +pantheon +##iculate +concurrency +estimation +improper +juliana +##his +newcomers +johnstone +staten +communicated +##oco +##alle +sausage +stormy +##stered +##tters +superfamily +##grade +acidic +collateral +tabloid +##oped +##rza +bladder +austen +##ellant +mcgraw +##hay +hannibal +mein +aquino +lucifer +wo +badger +boar +cher +christensen +greenberg +interruption +##kken +jem +mocked +bottoms +cambridgeshire +##lide +sprawling +##bbly +eastwood +ghent +synth +##buck +advisers +##bah +nominally +hapoel +qu +daggers +estranged +fabricated +towels +vinnie +wcw +misunderstanding +anglia +nothin +unmistakable +##dust +##lova +chilly +marquette +truss +##edge +##erine +reece +##lty +##chemist +##connected +41st +bash +raion +waterfalls +##ump +##main +labyrinth +queue +theorist +##istle +bharatiya +flexed +soundtracks +rooney +leftist +patrolling +wharton +plainly +alleviate +eastman +schuster +topographic +engages +immensely +unbearable +fairchild +1620 +dona +lurking +parisian +oliveira +ia +indictment +hahn +bangladeshi +##aster +##uming +##ential +antonia +expects +indoors +kildare +harlan +##logue +##ogenic +##sities +forgiven +##wat +childish +tavi +##mide +##orra +plausible +grimm +successively +scooted +##bola +##rith +spartans +emery +flatly +epilogue +##wark +flourish +##iny +##tracted +##overs +##oshi +bestseller +distressed +receipt +spitting +hermit +topological +##cot +drilled +subunit +francs +##layer +eel +##fk +##itas +octopus +footprint +petitions +##say +##foil +interfering +leaking +palo +##metry +thistle +valiant +##pic +narayan +mcpherson +##fast +gonzales +##enne +dustin +novgorod +solos +##zman +doin +##patient +##meyer +soluble +ashland +cuffs +carole +pendleton +whistling +vassal +##river +deviation +revisited +constituents +rallied +rotate +loomed +##eil +##nting +amateurs +augsburg +auschwitz +crowns +skeletons +##cona +bonnet +dummy +globalization +simeon +sleeper +mandal +differentiated +##crow +##mare +milne +bundled +exasperated +talmud +owes +segregated +##feng +##uary +dentist +piracy +props +##rang +devlin +##torium +malicious +paws +##laid +dependency +##ergy +##fers +##enna +pistons +rourke +jed +grammatical +tres +maha +wig +ghostly +jayne +##achal +##creen +##ilis +##lins +designate +##with +arrogance +cambodian +clones +showdown +throttle +twain +##ception +lobes +metz +nagoya +braking +##furt +roaming +##minster +amin +crippled +##llary +indifferent +hoffmann +idols +intimidating +1751 +influenza +memo +onions +1748 +bandage +consciously +##landa +##rage +clandestine +observes +swiped +tangle +##ener +##jected +##trum +##bill +##lta +hugs +congresses +josiah +spirited +##dek +humanist +managerial +filmmaking +inmate +rhymes +debuting +grimsby +ur +##laze +duplicate +vigor +republished +bolshevik +refurbishment +antibiotics +martini +methane +newscasts +royale +horizons +levant +iain +visas +##ischen +paler +##around +manifestation +snuck +alf +chop +futile +pedestal +rehab +##kat +bmg +kerman +res +fairbanks +jarrett +abstraction +saharan +##zek +1746 +procedural +clearer +kincaid +sash +luciano +##ffey +crunch +helmut +##vara +revolutionaries +##tute +creamy +leach +##mmon +1747 +permitting +nes +plight +wendell +##lese +contra +clancy +ipa +mach +staples +autopsy +disturbances +nueva +karin +pontiac +##uding +proxy +venerable +haunt +leto +bergman +expands +##helm +wal +##pipe +canning +celine +cords +obesity +##enary +intrusion +planner +##phate +reasoned +sequencing +harrow +##chon +##dora +marred +mcintyre +repay +tarzan +darting +harrisburg +margarita +repulsed +##lding +belinda +hamburger +novo +compliant +runways +bingham +registrar +skyscraper +cuthbert +improvisation +livelihood +##corp +##elial +admiring +##dened +sporadic +believer +casablanca +popcorn +asha +shovel +##bek +##dice +coiled +tangible +##dez +casper +elsie +resin +tenderness +rectory +##ivision +avail +sonar +##mori +boutique +##dier +guerre +bathed +upbringing +vaulted +sandals +blessings +##naut +##utnant +1680 +foxes +pia +corrosion +hesitantly +confederates +crystalline +footprints +shapiro +tirana +valentin +drones +45th +microscope +shipments +texted +inquisition +wry +guernsey +unauthorized +resigning +ripple +schubert +stu +reassure +felony +##ardo +brittle +koreans +##havan +##ives +dun +implicit +tyres +##aldi +##lth +magnolia +##ehan +##puri +##poulos +aggressively +fei +gr +familiarity +##poo +indicative +##trust +fundamentally +jimmie +overrun +anchors +moans +##opus +britannia +armagh +purposely +seizing +##vao +bewildered +mundane +avoidance +cosmopolitan +geometridae +quartermaster +caf +chatter +engulfed +gleam +purge +##icate +juliette +jurisprudence +guerra +revisions +##bn +casimir +brew +##jm +1749 +clapton +cloudy +conde +hermitage +simulations +torches +vincenzo +matteo +##rill +hidalgo +booming +westbound +accomplishment +tentacles +unaffected +##sius +annabelle +flopped +sloping +##litz +dreamer +interceptor +vu +##loh +consecration +copying +messaging +breaker +climates +hospitalized +1752 +torino +afternoons +winfield +witnessing +##teacher +breakers +choirs +sawmill +coldly +##ege +sipping +haste +uninhabited +conical +bibliography +pamphlets +severn +edict +##oca +deux +illnesses +grips +rehearsals +sis +thinkers +tame +##keepers +1690 +acacia +reformer +##osed +##rys +shuffling +##iring +##shima +eastbound +ionic +rhea +flees +littered +##oum +rocker +vomiting +groaning +champ +overwhelmingly +civilizations +paces +sloop +adoptive +##tish +skaters +##vres +aiding +nikola +shriek +##ignon +pharmaceuticals +tuna +calvert +gustavo +stocked +yearbook +##urai +##mana +computed +subsp +riff +hanoi +kelvin +hamid +moors +pastures +summons +jihad +nectar +##ctors +bayou +untitled +pleasing +vastly +republics +intellect +##ulio +##tou +crumbling +stylistic +##ی +consolation +frequented +h₂o +walden +widows +##iens +##ignment +chunks +improves +grit +recited +##dev +snarl +sociological +##arte +##gul +inquired +##held +bruise +clube +consultancy +homogeneous +hornets +multiplication +pasta +prick +savior +##grin +##kou +##phile +yoon +##gara +grimes +vanishing +cheering +reacting +bn +distillery +##quisite +##vity +coe +dockyard +massif +##jord +escorts +voss +##valent +byte +chopped +hawke +illusions +workings +floats +##koto +##vac +kv +annapolis +madden +##onus +alvaro +noctuidae +##cum +##scopic +avenge +steamboat +forte +illustrates +erika +##trip +dew +nationalities +bran +manifested +thirsty +diversified +muscled +reborn +##standing +arson +##lessness +##dran +##logram +##boys +##kushima +##vious +willoughby +##phobia +alsace +dashboard +yuki +##chai +granville +myspace +publicized +tricked +##gang +adjective +##ater +relic +reorganisation +enthusiastically +indications +saxe +##lassified +consolidate +iec +padua +helplessly +ramps +renaming +regulars +pedestrians +accents +convicts +inaccurate +lowers +mana +##pati +barrie +bjp +outta +someplace +berwick +flanking +invoked +marrow +sparsely +excerpts +clothed +rei +##ginal +wept +##straße +##vish +##ptive +membranes +aquitaine +creeks +cutler +sheppard +implementations +##dur +fragrance +budge +concordia +magnesium +marcelo +##antes +gladly +vibrating +##rral +##ggles +montrose +##omba +lew +seamus +1630 +cocky +##ament +##uen +bjorn +##rrick +fielder +fluttering +##lase +methyl +kimberley +mcdowell +reductions +barbed +##jic +##tonic +aeronautical +condensed +distracting +##promising +huffed +##cala +##sle +claudius +invincible +missy +pious +balthazar +##lang +butte +combo +orson +##dication +myriad +1707 +silenced +##fed +##rh +netball +yourselves +##oza +clarify +heller +peg +durban +etudes +offender +roast +blackmail +curvature +##woods +vile +illicit +suriname +##linson +overture +1685 +bubbling +gymnast +tucking +##mming +##ouin +maldives +##bala +gurney +##dda +##eased +##oides +backside +pinto +jars +racehorse +tending +##rdial +baronetcy +wiener +duly +##rke +barbarian +cupping +flawed +##thesis +bertha +pleistocene +puddle +swearing +##nob +##tically +fleeting +prostate +amulet +educating +##mined +##tler +75th +jens +respondents +cavaliers +papacy +raju +##iente +##ulum +##tip +funnel +disneyland +##lley +sociologist +##iam +faulkner +louvre +menon +##dson +##ower +afterlife +mannheim +peptide +referees +comedians +meaningless +##anger +##laise +fabrics +hurley +renal +sleeps +##bour +##icle +breakout +kristin +roadside +animator +clover +disdain +unsafe +redesign +##urity +firth +barnsley +portage +reset +narrows +commandos +expansive +speechless +tubular +essendon +eyelashes +smashwords +##yad +##bang +##claim +craved +sprinted +chet +somme +astor +wrocław +orton +bane +##erving +##uing +mischief +##amps +##sund +scaling +terre +##xious +impairment +offenses +undermine +moi +soy +contiguous +arcadia +inuit +seam +##tops +macbeth +rebelled +##icative +##iot +elaborated +frs +uniformed +##dberg +powerless +priscilla +stimulated +qc +arboretum +frustrating +trieste +bullock +##nified +enriched +glistening +intern +##adia +locus +nouvelle +ollie +ike +lash +starboard +tapestry +headlined +hove +rigged +##vite +pollock +##yme +thrive +clustered +cas +roi +gleamed +olympiad +##lino +pressured +regimes +##hosis +##lick +ripley +##ophone +kickoff +gallon +rockwell +##arable +crusader +glue +revolutions +scrambling +1714 +grover +##jure +englishman +aztec +contemplating +coven +preach +triumphant +tufts +##esian +rotational +##phus +falkland +##brates +strewn +clarissa +rejoin +environmentally +glint +banded +drenched +moat +albanians +johor +rr +maestro +malley +nouveau +shaded +taxonomy +adhere +bunk +airfields +##ritan +1741 +encompass +remington +tran +##erative +amelie +mazda +friar +morals +passions +##zai +breadth +vis +##hae +argus +burnham +caressing +insider +rudd +##imov +##rso +italianate +murderous +textual +wainwright +armada +bam +weave +timer +##taken +##nh +fra +##crest +ardent +salazar +taps +tunis +##ntino +allegro +gland +philanthropic +##chester +implication +##optera +esq +judas +noticeably +wynn +##dara +inched +indexed +crises +villiers +bandit +royalties +patterned +cupboard +interspersed +accessory +isla +kendrick +entourage +stitches +##esthesia +headwaters +##ior +interlude +distraught +draught +1727 +##basket +biased +sy +transient +triad +subgenus +adapting +kidd +shortstop +##umatic +dimly +spiked +mcleod +reprint +nellie +pretoria +windmill +##cek +singled +##mps +reunite +##orous +bankers +outlying +##omp +##ports +##tream +apologies +cosmetics +patsy +##deh +##ocks +##yson +bender +nantes +serene +##nad +lucha +mmm +##cius +##gli +cmll +coinage +nestor +juarez +##rook +smeared +sprayed +twitching +sterile +irina +embodied +juveniles +enveloped +miscellaneous +cancers +dq +gulped +luisa +crested +swat +donegal +ref +##anov +##acker +hearst +mercantile +##lika +doorbell +vicki +##alla +##som +bilbao +psychologists +stryker +sw +horsemen +turkmenistan +wits +##national +anson +mathew +screenings +##umb +rihanna +##agne +##nessy +aisles +##iani +##osphere +hines +kenton +saskatoon +tasha +truncated +##champ +##itan +mildred +advises +fredrik +interpreting +inhibitors +##athi +spectroscopy +##hab +##kong +karim +panda +##oia +##nail +conqueror +kgb +leukemia +##dity +arrivals +cheered +pisa +phosphorus +shielded +##riated +mammal +unitarian +urgently +chopin +sanitary +##mission +spicy +drugged +hinges +##tort +tipping +trier +impoverished +westchester +##caster +epoch +nonstop +##gman +##khov +aromatic +centrally +cerro +##tively +##vio +billions +modulation +sedimentary +facilitating +outrageous +goldstein +##eak +##kt +ld +maitland +penultimate +pollard +##dance +fleets +spaceship +vertebrae +##nig +alcoholism +als +recital +##bham +##omics +##bm +trois +##tropical +commemorates +##meric +marge +##raction +1643 +cosmetic +ravaged +##ige +catastrophe +eng +##shida +albrecht +arterial +bellamy +decor +harmon +##rde +bulbs +synchronized +vito +easiest +shetland +shielding +wnba +##glers +##ssar +##riam +brianna +cumbria +##aceous +##rard +cores +thayer +##nsk +brood +hilltop +luminous +carts +keynote +larkin +logos +##cta +##mund +##quay +lilith +tinted +wrestle +mobilization +##uses +sequential +siam +bloomfield +takahashi +##ieving +presenters +ringo +blazed +witty +##oven +##ignant +devastation +haydn +harmed +newt +therese +##peed +gershwin +molina +rabbis +sudanese +innate +restarted +##sack +##fus +slices +wb +##shah +enroll +hypothetical +hysterical +1743 +fabio +indefinite +warped +exchanging +unsuitable +##sboro +gallo +1603 +bret +cobalt +homemade +##hunter +operatives +##dhar +terraces +durable +latch +pens +whorls +##ctuated +##eaux +billing +ligament +succumbed +##gly +regulators +spawn +##brick +##stead +filmfare +rochelle +##nzo +1725 +circumstance +saber +supplements +##nsky +##tson +crowe +wellesley +carrot +##9th +##movable +primate +drury +sincerely +topical +##mad +##rao +callahan +kyiv +smarter +tits +undo +##yeh +announcements +anthologies +barrio +nebula +##islaus +##shaft +##tyn +bodyguards +assassinate +barns +emmett +scully +##yd +##eland +##tino +##itarian +demoted +gorman +lashed +prized +adventist +writ +##gui +alla +invertebrates +##ausen +1641 +amman +1742 +align +healy +redistribution +##gf +##rize +insulation +##drop +adherents +hezbollah +vitro +ferns +yanking +registering +uppsala +cheerleading +confines +mischievous +tully +##ross +49th +docked +roam +stipulated +pumpkin +##bry +prompt +##ezer +blindly +shuddering +craftsmen +frail +scented +katharine +scramble +shaggy +sponge +helix +zaragoza +43rd +backlash +fontaine +seizures +posse +cowan +nonfiction +telenovela +wwii +hammered +undone +##gpur +encircled +irs +##ivation +artefacts +oneself +searing +smallpox +##belle +##osaurus +shandong +breached +upland +blushing +rankin +infinitely +psyche +tolerated +docking +evicted +##col +unmarked +##lving +gnome +lettering +litres +musique +##oint +benevolent +##jal +blackened +##anna +mccall +racers +tingle +##ocene +##orestation +introductions +radically +##hiff +##باد +1610 +1739 +munchen +plead +##nka +condo +scissors +##sight +##tens +apprehension +##cey +##yin +hallmark +watering +formulas +sequels +##llas +aggravated +bae +commencing +##building +enfield +prohibits +marne +vedic +civilized +euclidean +jagger +beforehand +blasts +dumont +##arney +##nem +conversions +hierarchical +rios +simulator +##dya +##lellan +hedges +oleg +thrusts +shadowed +darby +maximize +1744 +gregorian +##nded +##routed +sham +unspecified +##hog +emory +factual +##smo +fooled +##rger +ortega +wellness +marlon +##oton +##urance +casket +keating +ley +enclave +##ayan +char +influencing +jia +##chenko +ammonia +erebidae +incompatible +violins +cornered +##arat +grooves +astronauts +columbian +rampant +fabrication +kyushu +mahmud +vanish +##dern +mesopotamia +##lete +##rgen +caspian +kenji +pitted +##vered +grimace +roanoke +tchaikovsky +twinned +##analysis +##awan +xinjiang +arias +clemson +kazakh +sizable +1662 +##khand +##vard +plunge +tatum +vittorio +##nden +cholera +##dana +bracing +indifference +projectile +superliga +##chee +realises +upgrading +porte +retribution +##vies +nk +stil +##resses +ama +bureaucracy +blackberry +bosch +testosterone +collapses +greer +##pathic +ioc +fifties +malls +##erved +bao +baskets +adolescents +siegfried +##osity +##tosis +mantra +detecting +existent +fledgling +##cchi +dissatisfied +gan +telecommunication +mingled +sobbed +controversies +outdated +taxis +##raus +fright +slams +##lham +##fect +##tten +detectors +fetal +tanned +##uw +fray +goth +olympian +skipping +mandates +scratches +sheng +unspoken +hyundai +tracey +hotspur +restrictive +##buch +americana +mundo +##bari +burroughs +diva +vulcan +##6th +distinctions +thumping +##ngen +mikey +sheds +fide +rescues +springsteen +vested +valuation +##ece +##ely +pinnacle +rake +sylvie +##edo +almond +quivering +##irus +alteration +faltered +##wad +51st +hydra +ticked +##kato +recommends +##dicated +antigua +arjun +stagecoach +wilfred +trickle +pronouns +##pon +aryan +nighttime +##anian +gall +pea +stitch +##hei +leung +milos +##dini +eritrea +starved +snowfall +kant +parasitic +cot +discus +hana +strikers +appleton +kitchens +##erina +##partisan +##itha +##vius +disclose +metis +##channel +1701 +##vera +fitch +1735 +blooded +##tila +decimal +##tang +##bai +cyclones +eun +bottled +peas +pensacola +basha +bolivian +crabs +boil +lanterns +partridge +roofed +1645 +necks +##phila +opined +patting +##kla +##lland +chuckles +volta +whereupon +##nche +devout +euroleague +suicidal +##dee +inherently +involuntary +knitting +nasser +##hide +puppets +colourful +courageous +southend +stills +miraculous +hodgson +richer +rochdale +ethernet +greta +uniting +prism +umm +##haya +##itical +##utation +deterioration +pointe +prowess +##ropriation +lids +scranton +billings +subcontinent +##koff +##scope +brute +kellogg +psalms +degraded +##vez +stanisław +##ructured +ferreira +pun +astonishing +gunnar +##yat +arya +prc +gottfried +##tight +excursion +##ographer +dina +##quil +##nare +huffington +illustrious +wilbur +verandah +##zard +naacp +##odle +constructive +fjord +kade +##naud +generosity +thrilling +baseline +cayman +frankish +plastics +accommodations +zoological +##fting +cedric +qb +motorized +##dome +##otted +squealed +tackled +canucks +budgets +situ +asthma +dail +gabled +grasslands +whimpered +writhing +judgments +minnie +##carbon +bananas +grille +domes +monique +odin +maguire +markham +tierney +##estra +##chua +libel +poke +speedy +atrium +laval +notwithstanding +##edly +fai +kala +##sur +robb +##sma +listings +luz +supplementary +tianjin +##acing +enzo +jd +ric +scanner +croats +transcribed +arden +##hair +##raphy +##lver +seventies +staggering +alam +horticultural +hs +regression +timbers +blasting +##ounded +montagu +manipulating +##cit +catalytic +1550 +troopers +##meo +condemnation +fitzpatrick +##oire +##roved +inexperienced +1670 +castes +##lative +outing +dubois +flicking +quarrel +ste +learners +1625 +whistled +##class +classify +tariffs +temperament +folly +liszt +##yles +immersed +jordanian +ceasefire +apparel +extras +maru +fished +##bio +harta +stockport +assortment +craftsman +paralysis +transmitters +##cola +blindness +##wk +fatally +proficiency +solemnly +##orno +repairing +amore +groceries +ultraviolet +##chase +schoolhouse +##tua +resurgence +nailed +##otype +ruse +saliva +diagrams +##tructing +albans +rann +thirties +antennas +hilarious +cougars +paddington +stats +##eger +breakaway +reza +authorship +prohibiting +scoffed +##etz +##ttle +conscription +defected +trondheim +##fires +ivanov +keenan +##adan +##ciful +##fb +##slow +locating +##ials +##tford +cadiz +basalt +blankly +interned +rags +rattling +##tick +carpathian +reassured +bum +guildford +iss +staunch +##onga +astronomers +sera +sofie +emergencies +susquehanna +##heard +duc +mastery +vh1 +williamsburg +bayer +buckled +craving +##khan +##rdes +bloomington +##write +alton +barbecue +##bians +justine +##hri +##ndt +delightful +smartphone +newtown +photon +retrieval +peugeot +hissing +##monium +##orough +flavors +lighted +relaunched +tainted +##games +##lysis +anarchy +microscopic +hopping +adept +evade +evie +##beau +inhibit +sinn +adjustable +hurst +intuition +wilton +44th +lawful +lowlands +stockings +thierry +##dalen +##hila +##nai +fates +prank +maison +lobbied +provocative +1724 +utopia +##qual +carbonate +gujarati +purcell +##rford +curtiss +##mei +overgrown +arenas +mediation +swallows +##rnik +respectful +turnbull +##hedron +##hope +alyssa +ozone +##ʻi +ami +gestapo +johansson +snooker +canteen +cuff +declines +empathy +stigma +##ags +##raine +taxpayers +volga +##wright +##copic +lifespan +overcame +tattooed +enactment +giggles +##ador +##camp +barrington +bribe +obligatory +orbiting +peng +##enas +elusive +sucker +##vating +cong +hardship +empowered +anticipating +estrada +cryptic +greasy +detainees +planck +sudbury +plaid +dod +kayla +##ears +##vb +##zd +mortally +##hein +cognition +radha +liechtenstein +meade +richly +argyle +harpsichord +liberalism +trumpets +lauded +tyrant +salsa +tiled +lear +promoters +reused +slicing +trident +##chuk +##gami +##lka +cantor +checkpoint +##points +gaul +leger +mammalian +##tov +##aar +##schaft +doha +frenchman +nirvana +##vino +delgado +headlining +##eron +##iography +jug +tko +1649 +naga +intersections +benfica +nawab +##suka +ashford +gulp +##deck +##vill +##rug +brentford +frazier +pleasures +dunne +potsdam +shenzhen +dentistry +##tec +flanagan +##dorff +##hear +chorale +dinah +prem +quezon +##rogated +relinquished +sutra +terri +##pani +flaps +##rissa +poly +##rnet +homme +aback +##eki +linger +womb +##kson +##lewood +doorstep +orthodoxy +threaded +westfield +##rval +dioceses +fridays +subsided +##gata +loyalists +##biotic +##ettes +letterman +lunatic +prelate +tenderly +invariably +souza +thug +winslow +##otide +furlongs +gogh +jeopardy +##runa +pegasus +##umble +humiliated +standalone +tagged +##roller +freshmen +klan +##bright +attaining +initiating +transatlantic +logged +viz +##uance +1723 +combatants +intervening +stephane +chieftain +despised +grazed +cdc +galveston +godzilla +macro +simulate +##planes +parades +##esses +##ductive +##unes +equator +overdose +##cans +##hosh +##lifting +joshi +epstein +sonora +treacherous +aquatics +manchu +responsive +##sation +supervisory +##christ +##llins +##ibar +##balance +##uso +kimball +karlsruhe +mab +##emy +ignores +phonetic +spaghetti +almighty +danzig +rumbling +tombstone +designations +lured +outset +##felt +supermarkets +grupo +kei +kraft +susanna +##blood +comprehension +genealogy +##aghan +##verted +redding +##ythe +1722 +bowing +##pore +##roi +lest +sharpened +fulbright +valkyrie +sikhs +##unds +swans +bouquet +merritt +##tage +##venting +commuted +redhead +clerks +leasing +cesare +dea +hazy +##vances +fledged +greenfield +servicemen +##gical +armando +blackout +sagged +downloadable +intra +potion +pods +##4th +##mism +attendants +gambia +stale +##ntine +plump +asteroids +rediscovered +buds +flea +hive +##neas +1737 +classifications +debuts +##eles +olympus +scala +##eurs +##gno +##mute +hummed +sigismund +visuals +wiggled +await +pilasters +clench +sulfate +##ances +bellevue +enigma +trainee +snort +##sw +clouded +denim +##rank +churning +hartman +lodges +riches +sima +##missible +accountable +socrates +regulates +mueller +1702 +avoids +solids +himalayas +nutrient +pup +##jevic +squat +fades +nec +##lates +##pina +##rona +##ου +privateer +tequila +##gative +##mpton +hornet +immortals +##dou +asturias +cleansing +dario +##rries +##anta +etymology +servicing +zhejiang +##venor +##nx +horned +erasmus +rayon +relocating +£10 +##bags +escalated +promenade +stubble +2010s +artisans +axial +liquids +mora +sho +yoo +##tsky +bundles +oldies +##nally +notification +bastion +##ths +sparkle +##lved +1728 +leash +pathogen +highs +##hmi +immature +gonzaga +ignatius +mansions +monterrey +sweets +bryson +##loe +polled +regatta +brightest +pei +rosy +squid +hatfield +payroll +addict +meath +cornerback +heaviest +lodging +##mage +capcom +rippled +##sily +barnet +mayhem +ymca +snuggled +rousseau +##cute +blanchard +fragmented +leighton +chromosomes +risking +##strel +##utter +corinne +coyotes +cynical +hiroshi +yeomanry +##ractive +ebook +grading +mandela +plume +agustin +magdalene +##rkin +bea +femme +trafford +##coll +##lun +##tance +52nd +fourier +upton +##mental +camilla +gust +iihf +islamabad +longevity +##kala +feldman +netting +##rization +endeavour +foraging +mfa +orr +##open +greyish +contradiction +graz +##ruff +handicapped +marlene +tweed +oaxaca +spp +campos +miocene +pri +configured +cooks +pluto +cozy +pornographic +##entes +70th +fairness +glided +jonny +lynne +rounding +sired +##emon +##nist +remade +uncover +##mack +complied +lei +newsweek +##jured +##parts +##enting +##pg +finer +guerrillas +athenian +deng +disused +stepmother +accuse +gingerly +seduction +confronting +##going +gora +nostalgia +sabres +virginity +wrenched +##minated +syndication +wielding +eyre +##gnon +##igny +behaved +taxpayer +sweeps +##growth +childless +gallant +##ywood +amplified +geraldine +scrape +##ffi +babylonian +fresco +##rdan +##kney +##position +1718 +restricting +tack +fukuoka +osborn +selector +partnering +##dlow +kia +tak +whitley +gables +##mania +mri +softness +immersion +##bots +##evsky +1713 +chilling +insignificant +pcs +##uis +elites +lina +purported +supplemental +teaming +##americana +##dding +##inton +proficient +rouen +##nage +##rret +niccolo +selects +##bread +fluffy +1621 +gruff +knotted +mukherjee +polgara +thrash +nicholls +secluded +smoothing +thru +corsica +loaf +whitaker +inquiries +##rrier +##kam +indochina +marlins +myles +peking +##tea +extracts +pastry +superhuman +connacht +vogel +##ditional +##het +##udged +##lash +gloss +quarries +refit +teaser +##alic +##gaon +20s +materialized +sling +camped +pickering +tung +tracker +pursuant +##cide +cranes +##cini +##typical +##viere +anhalt +overboard +workout +chores +fares +orphaned +stains +##logie +fenton +surpassing +joyah +triggers +##itte +grandmaster +##lass +##lists +clapping +fraudulent +ledger +nagasaki +##cor +##nosis +##tsa +eucalyptus +tun +##icio +##rney +##tara +dax +heroism +ina +wrexham +onboard +unsigned +##dates +moshe +galley +winnie +droplets +exiles +praises +watered +noodles +##aia +fein +leland +multicultural +stink +bingo +comets +erskine +modernized +canned +constraint +domestically +chemotherapy +featherweight +stifled +##mum +darkly +irresistible +refreshing +hasty +isolate +##oys +kitchener +planners +##wehr +cages +yarn +implant +toulon +elects +childbirth +yue +##lind +rightful +sportsman +junctions +remodeled +specifies +##rgh +##oons +complimented +##urgent +lister +ot +##logic +bequeathed +cheekbones +fontana +gabby +##dial +amadeus +corrugated +maverick +resented +triangles +##hered +##usly +nazareth +tyrol +1675 +assent +poorer +sectional +aegean +##cous +nylon +ghanaian +##egorical +##weig +cushions +forbid +fusiliers +obstruction +somerville +##scia +dime +earrings +elliptical +leyte +oder +polymers +timmy +midtown +piloted +settles +continual +externally +mayfield +##uh +enrichment +henson +keane +persians +1733 +benji +braden +pep +##efe +contenders +pepsi +valet +##isches +##asse +##earing +goofy +stroll +##amen +authoritarian +occurrences +adversary +ahmedabad +tangent +toppled +dorchester +1672 +modernism +marxism +islamist +charlemagne +exponential +racks +brunette +pic +skirmish +##bund +##lad +##powered +##yst +hoisted +messina +shatter +##ctum +jedi +vantage +##music +##neil +clemens +mahmoud +corrupted +authentication +lowry +nils +##washed +omnibus +wounding +jillian +##itors +##opped +serialized +narcotics +handheld +##arm +##plicity +intersecting +stimulating +##onis +crate +fellowships +hemingway +casinos +climatic +fordham +copeland +drip +beatty +leaflets +robber +brothel +madeira +##hedral +sphinx +ultrasound +##vana +valor +forbade +leonid +villas +##aldo +duane +marquez +##cytes +disadvantaged +forearms +kawasaki +reacts +consular +lax +uncles +uphold +##hopper +concepcion +dorsey +lass +##izan +arching +passageway +1708 +researches +tia +internationals +##graphs +##opers +distinguishes +javanese +divert +##uven +plotted +##listic +##rwin +##erik +##tify +affirmative +signifies +validation +##bson +kari +felicity +georgina +zulu +##eros +##rained +##rath +overcoming +argyll +##rbin +1734 +chiba +ratification +windy +earls +parapet +##marks +hunan +pristine +astrid +punta +##gart +brodie +##kota +##oder +malaga +minerva +rouse +##phonic +bellowed +pagoda +portals +reclamation +##gur +##odies +##⁄₄ +parentheses +quoting +allergic +palette +showcases +benefactor +heartland +nonlinear +##tness +bladed +cheerfully +scans +##ety +1666 +girlfriends +pedersen +hiram +sous +##liche +##nator +1683 +##nery +##orio +##umen +bobo +primaries +smiley +##cb +unearthed +uniformly +fis +metadata +1635 +ind +##oted +recoil +##titles +##tura +##ια +hilbert +jamestown +mcmillan +tulane +seychelles +##frid +antics +coli +fated +stucco +##grants +1654 +bulky +accolades +arrays +caledonian +carnage +optimism +puebla +##tative +##cave +enforcing +rotherham +dunlop +aeronautics +chimed +incline +zoning +archduke +hellenistic +##oses +##sions +candi +thong +##ople +magnate +rustic +##rsk +projective +slant +##offs +danes +hollis +vocalists +##ammed +congenital +contend +gesellschaft +##ocating +##pressive +douglass +quieter +##kshi +howled +salim +spontaneously +townsville +buena +southport +##bold +kato +1638 +faerie +stiffly +##vus +##rled +flawless +realising +taboo +##7th +straightening +jena +##hid +cartwright +berber +bertram +soloists +noses +coping +fission +hardin +inca +##cen +1717 +mobilized +vhf +##raf +biscuits +curate +##anial +gaunt +neighbourhoods +1540 +##abas +blanca +bypassed +sockets +behold +coincidentally +##bane +nara +shave +splinter +terrific +##arion +##erian +commonplace +juris +redwood +waistband +boxed +caitlin +fingerprints +jennie +naturalized +##ired +balfour +craters +jody +bungalow +hugely +quilt +glitter +pigeons +undertaker +bulging +constrained +##sil +##akh +assimilation +reworked +##person +persuasion +##pants +felicia +##cliff +##ulent +1732 +explodes +##dun +##inium +##zic +lyman +vulture +hog +overlook +begs +northwards +ow +spoil +##urer +fatima +favorably +accumulate +sargent +sorority +corresponded +dispersal +kochi +toned +##imi +##lita +internacional +newfound +##agger +##lynn +##rigue +booths +peanuts +##eborg +medicare +muriel +nur +##uram +crates +millennia +pajamas +worsened +##breakers +jimi +vanuatu +yawned +##udeau +carousel +##hony +hurdle +##ccus +##mounted +##pod +rv +##eche +airship +ambiguity +compulsion +recapture +##claiming +arthritis +##osomal +1667 +asserting +ngc +sniffing +dade +discontent +glendale +ported +##amina +defamation +rammed +##scent +fling +livingstone +##fleet +875 +apocalyptic +comrade +##lowe +cessna +eine +persecuted +subsistence +demi +hoop +reliefs +coptic +progressing +stemmed +perpetrators +1665 +priestess +##nio +dobson +ebony +rooster +itf +tortricidae +##bbon +##jian +cleanup +##jean +##øy +1721 +eighties +taxonomic +holiness +##hearted +##spar +antilles +showcasing +stabilized +##nb +gia +mascara +michelangelo +dawned +##uria +##vinsky +extinguished +fitz +grotesque +£100 +##fera +##loid +##mous +barges +neue +throbbed +cipher +johnnie +##mpt +outburst +##swick +spearheaded +administrations +heartbreak +pixels +pleasantly +##enay +lombardy +plush +##nsed +bobbie +##hly +reapers +tremor +xiang +minogue +substantive +hitch +barak +##wyl +kwan +##encia +910 +obscene +elegance +indus +surfer +bribery +conserve +##hyllum +##masters +horatio +##fat +apes +rebound +psychotic +##pour +iteration +##mium +##vani +botanic +horribly +antiques +dispose +paxton +##hli +##wg +timeless +1704 +disregard +engraver +hounds +##bau +##version +looted +uno +facilitates +groans +masjid +rutland +antibody +disqualification +decatur +footballers +quake +slacks +48th +rein +scribe +stabilize +commits +exemplary +tho +##hort +##chison +pantry +traversed +##hiti +disrepair +identifiable +vibrated +baccalaureate +csa +interviewing +##iensis +##raße +greaves +wealthiest +classed +jogged +£5 +##atal +illuminating +knicks +respecting +##uno +scrubbed +##iji +##dles +kruger +moods +growls +raider +silvia +chefs +kam +cree +percival +##terol +gunter +counterattack +defiant +henan +ze +##rasia +##riety +equivalence +submissions +##fra +##thor +bautista +mechanically +##heater +cornice +herbal +templar +##mering +outputs +ruining +ligand +renumbered +extravagant +mika +blockbuster +eta +insurrection +##ilia +darkening +ferocious +pianos +strife +kinship +##aer +melee +##anor +##iste +##oue +decidedly +weep +##jad +##missive +##ppel +puget +unease +##gnant +1629 +hammering +kassel +wessex +##lga +bromwich +egan +paranoia +utilization +##atable +##idad +contradictory +provoke +##ols +##ouring +##tangled +knesset +##very +##lette +plumbing +##sden +greensboro +occult +sniff +zev +beaming +gamer +haggard +mahal +##olt +##pins +mendes +utmost +briefing +gunnery +##gut +##pher +##zh +##rok +1679 +khalifa +sonya +##boot +principals +urbana +wiring +##liffe +##minating +##rrado +dahl +nyu +skepticism +townspeople +ithaca +lobster +somethin +##fur +##arina +##−1 +freighter +zimmerman +biceps +contractual +##herton +amend +hurrying +subconscious +##anal +meng +clermont +spawning +##eia +##lub +dignitaries +impetus +snacks +spotting +twigs +##bilis +##cz +##ouk +libertadores +nic +skylar +##aina +gustave +asean +##anum +dieter +legislatures +flirt +bromley +trolls +umar +##bbies +##tyle +blah +parc +bridgeport +crank +negligence +##nction +46th +constantin +molded +bandages +seriousness +00pm +siegel +carpets +compartments +upbeat +statehood +##dner +##edging +marko +platt +##hane +paving +##iy +1738 +abbess +impatience +limousine +nbl +lucille +mojo +nightfall +robbers +##nais +karel +brisk +calves +replicate +ascribed +telescopes +##olf +intimidated +ballast +specialization +aerodynamic +caliphate +visionary +##arded +epsilon +##aday +##onte +aggregation +auditory +boosted +reunification +kathmandu +loco +robyn +acknowledges +appointing +humanoid +newell +redeveloped +restraints +##tained +barbarians +chopper +1609 +italiana +##lez +##lho +investigates +wrestlemania +##anies +##bib +##falls +creaked +dragoons +gravely +minions +stupidity +volley +##harat +##week +musik +##eries +##uously +fungal +massimo +semantics +malvern +##ahl +##pee +discourage +embryo +imperialism +1910s +profoundly +##ddled +jiangsu +sparkled +stat +##holz +sweatshirt +tobin +##iction +sneered +##cheon +##oit +brit +causal +smyth +##neuve +diffuse +perrin +silvio +##ipes +##recht +detonated +iqbal +selma +##nism +##zumi +roasted +##riders +tay +##ados +##mament +##mut +##rud +completes +nipples +flavour +hirsch +##laus +calderon +sneakers +moravian +##ksha +1622 +##imeters +bodo +##isance +##pre +##ronia +anatomical +excerpt +##lke +dh +kunst +##tablished +##scoe +biomass +panted +unharmed +gael +housemates +montpellier +coa +rodents +tonic +hickory +singleton +##taro +1719 +aldo +breaststroke +dempsey +och +rocco +##cuit +merton +dissemination +midsummer +serials +##idi +haji +polynomials +enoch +prematurely +shutter +taunton +£3 +##grating +##inates +archangel +harassed +##asco +archway +dazzling +##ecin +1736 +sumo +wat +##kovich +1086 +honneur +##ently +##nostic +##ttal +##idon +1605 +1716 +rents +##gnan +hires +##ikh +##dant +howie +##rons +handler +retracted +shocks +1632 +arun +duluth +kepler +trumpeter +##lary +peeking +seasoned +trooper +##mara +laszlo +##iciencies +##rti +heterosexual +##inatory +indira +jogging +##inga +##lism +beit +dissatisfaction +malice +##ately +nedra +peeling +##rgeon +47th +stadiums +vertigo +##ains +iced +restroom +##plify +##tub +illustrating +pear +##chner +##sibility +inorganic +rappers +receipts +watery +##kura +lucinda +##oulos +reintroduced +##8th +##tched +gracefully +saxons +nutritional +wastewater +rained +favourites +bedrock +fisted +hallways +likeness +upscale +##lateral +1580 +blinds +prequel +##pps +##tama +deter +humiliating +restraining +tn +vents +1659 +laundering +recess +rosary +tractors +coulter +federer +##ifiers +##plin +persistence +##quitable +geschichte +pendulum +quakers +##beam +bassett +pictorial +koln +##sitor +drills +reciprocal +shooters +##cton +##tees +converge +pip +dmitri +donnelly +yamamoto +aqua +azores +demographics +hypnotic +spitfire +suspend +wryly +roderick +##rran +sebastien +##asurable +mavericks +##fles +himalayan +prodigy +##iance +transvaal +demonstrators +handcuffs +dodged +mcnamara +sublime +1726 +crazed +##efined +##till +ivo +pondered +reconciled +shrill +sava +##duk +bal +heresy +jaipur +goran +##nished +lux +shelly +whitehall +##hre +israelis +peacekeeping +##wled +1703 +demetrius +ousted +##arians +##zos +beale +anwar +backstroke +raged +shrinking +cremated +##yck +benign +towing +wadi +darmstadt +landfill +parana +soothe +colleen +sidewalks +mayfair +tumble +hepatitis +ferrer +superstructure +##gingly +##urse +##wee +anthropological +translators +##mies +closeness +hooves +##pw +mondays +##roll +##vita +landscaping +##urized +purification +sock +thorns +thwarted +jalan +tiberius +##taka +saline +##rito +confidently +khyber +sculptors +##ij +brahms +hammersmith +inspectors +battista +fivb +fragmentation +hackney +##uls +arresting +exercising +antoinette +bedfordshire +##zily +dyed +##hema +1656 +racetrack +variability +##tique +1655 +austrians +deteriorating +madman +theorists +aix +lehman +weathered +1731 +decreed +eruptions +1729 +flaw +quinlan +sorbonne +flutes +nunez +1711 +adored +downwards +fable +rasped +1712 +moritz +mouthful +renegade +shivers +stunts +dysfunction +restrain +translit +pancakes +##avio +##cision +##tray +vial +##lden +bain +##maid +##oxide +chihuahua +malacca +vimes +##rba +##rnier +1664 +donnie +plaques +##ually +bangs +floppy +huntsville +loretta +nikolay +##otte +eater +handgun +ubiquitous +##hett +eras +zodiac +1634 +##omorphic +1820s +##zog +cochran +##bula +##lithic +warring +##rada +dalai +excused +blazers +mcconnell +reeling +este +##abi +geese +hoax +taxon +##bla +guitarists +condemning +hunts +inversion +moffat +taekwondo +##lvis +1624 +stammered +##rest +##rzy +sousa +fundraiser +marylebone +navigable +uptown +cabbage +daniela +salman +shitty +whimper +##kian +##utive +programmers +protections +##rmi +##rued +forceful +##enes +fuss +##tao +##wash +brat +oppressive +reykjavik +spartak +ticking +##inkles +##kiewicz +adolph +horst +maui +protege +straighten +cpc +landau +concourse +clements +resultant +##ando +imaginative +joo +reactivated +##rem +##ffled +##uising +consultative +##guide +flop +kaitlyn +mergers +parenting +somber +##vron +supervise +vidhan +##imum +courtship +exemplified +harmonies +medallist +refining +##rrow +##ка +amara +##hum +goalscorer +sited +overshadowed +rohan +displeasure +secretive +multiplied +osman +##orth +engravings +padre +##kali +##veda +miniatures +mis +##yala +clap +pali +rook +##cana +1692 +57th +antennae +astro +oskar +1628 +bulldog +crotch +hackett +yucatan +##sure +amplifiers +brno +ferrara +migrating +##gree +thanking +turing +##eza +mccann +ting +andersson +onslaught +gaines +ganga +incense +standardization +##mation +sentai +scuba +stuffing +turquoise +waivers +alloys +##vitt +regaining +vaults +##clops +##gizing +digger +furry +memorabilia +probing +##iad +payton +rec +deutschland +filippo +opaque +seamen +zenith +afrikaans +##filtration +disciplined +inspirational +##merie +banco +confuse +grafton +tod +##dgets +championed +simi +anomaly +biplane +##ceptive +electrode +##para +1697 +cleavage +crossbow +swirl +informant +##lars +##osta +afi +bonfire +spec +##oux +lakeside +slump +##culus +##lais +##qvist +##rrigan +1016 +facades +borg +inwardly +cervical +pointedly +stabilization +##odon +chests +1699 +hacked +ctv +orthogonal +suzy +##lastic +gaulle +jacobite +rearview +##erted +ashby +##drik +##igate +##mise +##zbek +affectionately +canine +disperse +latham +##istles +##ivar +spielberg +##orin +##idium +ezekiel +cid +##sg +durga +middletown +##cina +customized +frontiers +harden +##etano +##zzy +1604 +bolsheviks +coloration +yoko +##bedo +briefs +slabs +debra +liquidation +plumage +##oin +blossoms +dementia +subsidy +1611 +proctor +relational +jerseys +parochial +ter +##ici +esa +peshawar +cavalier +loren +idiots +shamrock +1646 +dutton +malabar +mustache +##endez +##ocytes +referencing +terminates +marche +yarmouth +##sop +acton +mated +seton +subtly +baptised +beige +extremes +jolted +kristina +telecast +##actic +safeguard +waldo +##baldi +##bular +endeavors +sloppy +subterranean +##ensburg +##itung +delicately +pigment +tq +##scu +1626 +collisions +coveted +herds +##personal +##meister +##nberger +chopra +##ricting +abnormalities +defective +galician +lucie +##dilly +alligator +likened +##genase +burundi +clears +complexion +derelict +deafening +diablo +fingered +champaign +dogg +enlist +isotope +labeling +mrna +##erre +brilliance +marvelous +##ayo +1652 +crawley +ether +footed +dwellers +deserts +hamish +rubs +warlock +skimmed +##lizer +buick +embark +heraldic +irregularities +##ajan +kiara +##kulam +##ieg +antigen +kowalski +##lge +oakley +visitation +##mbit +vt +##suit +1570 +murderers +##miento +##rites +chimneys +##sling +condemn +custer +exchequer +havre +##ghi +fluctuations +##rations +dfb +hendricks +vaccines +##tarian +nietzsche +biking +juicy +##duced +brooding +scrolling +selangor +##ragan +annum +boomed +seminole +sugarcane +##dna +departmental +dismissing +innsbruck +arteries +ashok +batavia +daze +kun +overtook +##rga +##tlan +beheaded +gaddafi +holm +electronically +faulty +galilee +fractures +kobayashi +##lized +gunmen +magma +aramaic +mala +eastenders +inference +messengers +bf +##qu +bathrooms +##vere +1658 +flashbacks +ideally +misunderstood +##jali +##weather +mendez +##grounds +uncanny +##iii +1709 +friendships +##nbc +sacrament +accommodated +reiterated +logistical +pebbles +thumped +##escence +administering +decrees +drafts +##flight +##cased +##tula +futuristic +picket +intimidation +winthrop +##fahan +interfered +afar +francoise +morally +uta +cochin +croft +dwarfs +##bruck +##dents +##nami +biker +##hner +##meral +##isen +##ometric +##pres +##ан +brightened +meek +parcels +securely +gunners +##jhl +##zko +agile +hysteria +##lten +##rcus +bukit +champs +chevy +cuckoo +leith +sadler +theologians +welded +##section +1663 +plurality +xander +##rooms +##formed +shredded +temps +intimately +pau +tormented +##lok +##stellar +1618 +charred +essen +##mmel +alarms +spraying +ascot +blooms +twinkle +##abia +##apes +internment +obsidian +##chaft +snoop +##dav +##ooping +malibu +##tension +quiver +##itia +hays +mcintosh +travers +walsall +##ffie +1623 +beverley +schwarz +plunging +structurally +rosenthal +vikram +##tsk +ghz +##onda +##tiv +chalmers +groningen +pew +reckon +unicef +##rvis +55th +##gni +1651 +sulawesi +avila +cai +metaphysical +screwing +turbulence +##mberg +augusto +samba +56th +baffled +momentary +toxin +##urian +##wani +aachen +condoms +dali +steppe +##oed +##year +adolescence +dauphin +electrically +inaccessible +microscopy +nikita +##ega +atv +##enter +##oles +##oteric +accountants +punishments +wrongly +bribes +adventurous +clinch +flinders +southland +##hem +##kata +gough +##ciency +lads +soared +##ה +undergoes +deformation +outlawed +rubbish +##arus +##mussen +##nidae +##rzburg +arcs +##ingdon +##tituted +1695 +wheelbase +wheeling +bombardier +campground +zebra +##lices +##oj +##bain +lullaby +##ecure +donetsk +wylie +grenada +##arding +##ης +squinting +eireann +opposes +##andra +maximal +runes +##broken +##cuting +##iface +##ror +##rosis +additive +britney +adultery +triggering +##drome +detrimental +aarhus +containment +jc +swapped +vichy +##ioms +madly +##oric +##rag +brant +##ckey +1560 +1612 +broughton +rustling +##stems +##uder +asbestos +mentoring +##nivorous +finley +leaps +##isan +apical +pry +slits +substitutes +##dict +intuitive +fantasia +insistent +unreasonable +##igen +##vna +domed +hannover +margot +ponder +##zziness +impromptu +jian +rampage +stemming +##eft +andrey +gerais +whichever +amnesia +appropriated +anzac +clicks +modifying +ultimatum +cambrian +maids +verve +yellowstone +##mbs +conservatoire +##scribe +adherence +dinners +spectra +imperfect +mysteriously +sidekick +tatar +tuba +##aks +##ifolia +distrust +##athan +##zle +ronin +zac +##pse +celaena +instrumentalist +scents +skopje +##mbling +comical +compensated +vidal +condor +intersect +jingle +wavelengths +##urrent +mcqueen +##izzly +carp +weasel +militias +postdoctoral +eugen +gunslinger +##ɛ +faux +hospice +##for +appalled +derivation +dwarves +##elis +dilapidated +##folk +astoria +philology +##lwyn +##otho +##saka +inducing +philanthropy +##bf +##itative +geek +markedly +##yce +bessie +indices +##flict +frowns +resolving +weightlifting +tugs +cleric +contentious +1653 +mania +rms +##miya +##reate +##ruck +##tucket +bien +eels +marek +##ayton +##cence +discreet +unofficially +##ife +leaks +##bber +1705 +dung +compressor +hillsborough +pandit +shillings +distal +##skin +##tat +nosed +##nir +mangrove +undeveloped +##idia +textures +##inho +##rise +irritating +nay +amazingly +bancroft +apologetic +compassionate +kata +symphonies +##lovic +airspace +##lch +gifford +precautions +fulfillment +sevilla +vulgar +martinique +##urities +looting +piccolo +tidy +##dermott +quadrant +armchair +incomes +mathematicians +stampede +nilsson +##inking +##scan +foo +quarterfinal +##ostal +shang +shouldered +squirrels +##owe +vinegar +##bner +##rchy +##systems +delaying +##trics +ars +dwyer +rhapsody +sponsoring +##gration +bipolar +cinder +starters +##olio +##urst +signage +##nty +aground +figurative +mons +acquaintances +duets +erroneously +soyuz +elliptic +recreated +##cultural +##quette +##ssed +##tma +##zcz +moderator +scares +##itaire +##stones +##udence +juniper +sighting +##just +##nsen +britten +calabria +ry +bop +cramer +forsyth +stillness +airmen +gathers +unfit +##umber +##upt +taunting +seeker +streamlined +##bution +holster +schumann +tread +vox +##gano +##onzo +strive +dil +reforming +covent +newbury +predicting +##orro +decorate +tre +##puted +andover +asahi +dept +dunkirk +gills +##tori +buren +huskies +##stis +##stov +abstracts +bets +loosen +##opa +1682 +yearning +##glio +##sir +berman +effortlessly +enamel +napoli +persist +##peration +##uez +attache +elisa +invitations +##kic +accelerating +reindeer +boardwalk +clutches +nelly +polka +##kei +adamant +huey +lough +unbroken +adventurer +embroidery +inspecting +stanza +##ducted +naia +taluka +##pone +##roids +chases +deprivation +florian +##ppet +earthly +##lib +##ssee +colossal +foreigner +vet +freaks +patrice +rosewood +triassic +upstate +##pkins +dominates +ata +chants +ks +vo +##bley +##raya +##rmed +agra +infiltrate +##ailing +##ilation +##tzer +##uppe +##werk +binoculars +enthusiast +fujian +squeak +##avs +abolitionist +almeida +boredom +hampstead +marsden +rations +##ands +inflated +bonuses +rosalie +patna +##rco +detachments +penitentiary +54th +flourishing +woolf +##dion +##etched +papyrus +##lster +##nsor +##toy +bobbed +dismounted +endelle +inhuman +motorola +wince +wreath +##ticus +hideout +inspections +sanjay +disgrace +infused +pudding +stalks +##urbed +arsenic +leases +##hyl +##rrard +collarbone +##waite +##wil +dowry +##bant +##edance +genealogical +nitrate +salamanca +scandals +thyroid +necessitated +##` +##¡ +##¢ +##¦ +##¨ +##ª +##¬ +##´ +##¶ +##¾ +##¿ +##ð +##þ +##ħ +##œ +##ƒ +##ɐ +##ɑ +##ɒ +##ɕ +##ɣ +##ɨ +##ɪ +##ɫ +##ɬ +##ɯ +##ɲ +##ɴ +##ɹ +##ɾ +##ʀ +##ʁ +##ʂ +##ʃ +##ʉ +##ʊ +##ʋ +##ʌ +##ʎ +##ʐ +##ʑ +##ʒ +##ʔ +##ʲ +##ʳ +##ʷ +##ʸ +##ʻ +##ʼ +##ʾ +##ʿ +##ˡ +##ˣ +##ˤ +##ζ +##ξ +##щ +##ъ +##э +##ю +##ђ +##є +##ј +##љ +##њ +##ћ +##ӏ +##ա +##բ +##գ +##դ +##ե +##թ +##ի +##լ +##կ +##հ +##մ +##յ +##ն +##ո +##պ +##ս +##վ +##տ +##ր +##ւ +##ք +##־ +##א +##ב +##ג +##ד +##ו +##ז +##ח +##ט +##י +##ך +##כ +##ל +##ם +##מ +##ן +##נ +##ס +##ע +##ף +##פ +##ץ +##צ +##ק +##ר +##ש +##ת +##، +##ء +##ث +##ج +##ح +##خ +##ذ +##ز +##ش +##ص +##ض +##ط +##ظ +##غ +##ـ +##ف +##ق +##ك +##ى +##ٹ +##پ +##چ +##ک +##گ +##ں +##ھ +##ہ +##ے +##अ +##आ +##उ +##ए +##क +##ख +##ग +##च +##ज +##ट +##ड +##ण +##त +##थ +##द +##ध +##न +##प +##ब +##भ +##म +##य +##र +##ल +##व +##श +##ष +##स +##ह +##ा +##ि +##ी +##ो +##। +##॥ +##ং +##অ +##আ +##ই +##উ +##এ +##ও +##ক +##খ +##গ +##চ +##ছ +##জ +##ট +##ড +##ণ +##ত +##থ +##দ +##ধ +##ন +##প +##ব +##ভ +##ম +##য +##র +##ল +##শ +##ষ +##স +##হ +##া +##ি +##ী +##ে +##க +##ச +##ட +##த +##ந +##ன +##ப +##ம +##ய +##ர +##ல +##ள +##வ +##ா +##ி +##ு +##ே +##ை +##ನ +##ರ +##ಾ +##ක +##ය +##ර +##ල +##ව +##ා +##ต +##ท +##พ +##ล +##ว +##ส +##། +##ག +##ང +##ད +##ན +##པ +##བ +##མ +##འ +##ར +##ལ +##ས +##မ +##ა +##ბ +##გ +##დ +##ე +##ვ +##თ +##ი +##კ +##ლ +##მ +##ნ +##ო +##რ +##ს +##ტ +##უ +##ᄊ +##ᴬ +##ᴮ +##ᴰ +##ᴵ +##ᴺ +##ᵀ +##ᵇ +##ᵈ +##ᵖ +##ᵗ +##ᵣ +##ᵤ +##ᵥ +##ᶜ +##ᶠ +##‐ +##‑ +##‒ +##– +##— +##― +##‘ +##’ +##‚ +##“ +##” +##‡ +##… +##⁰ +##⁴ +##⁵ +##⁶ +##⁷ +##⁸ +##⁹ +##⁻ +##₅ +##₆ +##₇ +##₈ +##₉ +##₊ +##₍ +##₎ +##ₐ +##ₑ +##ₒ +##ₓ +##ₕ +##ₖ +##ₗ +##ₘ +##ₚ +##ₛ +##ₜ +##₤ +##₩ +##₱ +##₹ +##ℓ +##ℝ +##⅓ +##⅔ +##↦ +##⇄ +##⇌ +##∂ +##∅ +##∆ +##∇ +##∈ +##∗ +##∘ +##∧ +##∨ +##∪ +##⊂ +##⊆ +##⊕ +##⊗ +##☉ +##♯ +##⟨ +##⟩ +##ⱼ +##⺩ +##⺼ +##⽥ +##亻 +##宀 +##彳 +##忄 +##扌 +##氵 +##疒 +##糹 +##訁 +##辶 +##阝 +##龸 +##fi +##fl diff --git a/comfy/text_encoders/mt5_config_xl.json b/comfy/text_encoders/mt5_config_xl.json new file mode 100644 index 000000000..092fefd6e --- /dev/null +++ b/comfy/text_encoders/mt5_config_xl.json @@ -0,0 +1,22 @@ +{ + "d_ff": 5120, + "d_kv": 64, + "d_model": 2048, + "decoder_start_token_id": 0, + "dropout_rate": 0.1, + "eos_token_id": 1, + "dense_act_fn": "gelu_pytorch_tanh", + "initializer_factor": 1.0, + "is_encoder_decoder": true, + "is_gated_act": true, + "layer_norm_epsilon": 1e-06, + "model_type": "mt5", + "num_decoder_layers": 24, + "num_heads": 32, + "num_layers": 24, + "output_past": true, + "pad_token_id": 0, + "relative_attention_num_buckets": 32, + "tie_word_embeddings": false, + "vocab_size": 250112 +} diff --git a/comfy/sa_t5.py b/comfy/text_encoders/sa_t5.py similarity index 67% rename from comfy/sa_t5.py rename to comfy/text_encoders/sa_t5.py index 37be5287e..189f8c181 100644 --- a/comfy/sa_t5.py +++ b/comfy/text_encoders/sa_t5.py @@ -1,22 +1,22 @@ from comfy import sd1_clip from transformers import T5TokenizerFast -import comfy.t5 +import comfy.text_encoders.t5 import os class T5BaseModel(sd1_clip.SDClipModel): def __init__(self, device="cpu", layer="last", layer_idx=None, dtype=None): textmodel_json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "t5_config_base.json") - super().__init__(device=device, layer=layer, layer_idx=layer_idx, textmodel_json_config=textmodel_json_config, dtype=dtype, special_tokens={"end": 1, "pad": 0}, model_class=comfy.t5.T5, enable_attention_masks=True, zero_out_masked=True) + super().__init__(device=device, layer=layer, layer_idx=layer_idx, textmodel_json_config=textmodel_json_config, dtype=dtype, special_tokens={"end": 1, "pad": 0}, model_class=comfy.text_encoders.t5.T5, enable_attention_masks=True, zero_out_masked=True) class T5BaseTokenizer(sd1_clip.SDTokenizer): - def __init__(self, embedding_directory=None): + def __init__(self, embedding_directory=None, tokenizer_data={}): tokenizer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "t5_tokenizer") super().__init__(tokenizer_path, pad_with_end=False, embedding_size=768, embedding_key='t5base', tokenizer_class=T5TokenizerFast, has_start_token=False, pad_to_max_length=False, max_length=99999999, min_length=128) class SAT5Tokenizer(sd1_clip.SD1Tokenizer): - def __init__(self, embedding_directory=None): - super().__init__(embedding_directory=embedding_directory, clip_name="t5base", tokenizer=T5BaseTokenizer) + def __init__(self, embedding_directory=None, tokenizer_data={}): + super().__init__(embedding_directory=embedding_directory, tokenizer_data=tokenizer_data, clip_name="t5base", tokenizer=T5BaseTokenizer) class SAT5Model(sd1_clip.SD1ClipModel): def __init__(self, device="cpu", dtype=None, **kwargs): - super().__init__(device=device, dtype=dtype, clip_name="t5base", clip_model=T5BaseModel, **kwargs) + super().__init__(device=device, dtype=dtype, name="t5base", clip_model=T5BaseModel, **kwargs) diff --git a/comfy/sd3_clip.py b/comfy/text_encoders/sd3_clip.py similarity index 90% rename from comfy/sd3_clip.py rename to comfy/text_encoders/sd3_clip.py index 0713eb285..b01fad221 100644 --- a/comfy/sd3_clip.py +++ b/comfy/text_encoders/sd3_clip.py @@ -1,7 +1,7 @@ from comfy import sd1_clip from comfy import sdxl_clip from transformers import T5TokenizerFast -import comfy.t5 +import comfy.text_encoders.t5 import torch import os import comfy.model_management @@ -10,25 +10,16 @@ import logging class T5XXLModel(sd1_clip.SDClipModel): def __init__(self, device="cpu", layer="last", layer_idx=None, dtype=None): textmodel_json_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), "t5_config_xxl.json") - super().__init__(device=device, layer=layer, layer_idx=layer_idx, textmodel_json_config=textmodel_json_config, dtype=dtype, special_tokens={"end": 1, "pad": 0}, model_class=comfy.t5.T5) + super().__init__(device=device, layer=layer, layer_idx=layer_idx, textmodel_json_config=textmodel_json_config, dtype=dtype, special_tokens={"end": 1, "pad": 0}, model_class=comfy.text_encoders.t5.T5) class T5XXLTokenizer(sd1_clip.SDTokenizer): - def __init__(self, embedding_directory=None): + def __init__(self, embedding_directory=None, tokenizer_data={}): tokenizer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "t5_tokenizer") super().__init__(tokenizer_path, pad_with_end=False, embedding_size=4096, embedding_key='t5xxl', tokenizer_class=T5TokenizerFast, has_start_token=False, pad_to_max_length=False, max_length=99999999, min_length=77) -class SDT5XXLTokenizer(sd1_clip.SD1Tokenizer): - def __init__(self, embedding_directory=None): - super().__init__(embedding_directory=embedding_directory, clip_name="t5xxl", tokenizer=T5XXLTokenizer) - -class SDT5XXLModel(sd1_clip.SD1ClipModel): - def __init__(self, device="cpu", dtype=None, **kwargs): - super().__init__(device=device, dtype=dtype, clip_name="t5xxl", clip_model=T5XXLModel, **kwargs) - - class SD3Tokenizer: - def __init__(self, embedding_directory=None): + def __init__(self, embedding_directory=None, tokenizer_data={}): self.clip_l = sd1_clip.SDTokenizer(embedding_directory=embedding_directory) self.clip_g = sdxl_clip.SDXLClipGTokenizer(embedding_directory=embedding_directory) self.t5xxl = T5XXLTokenizer(embedding_directory=embedding_directory) @@ -43,6 +34,9 @@ class SD3Tokenizer: def untokenize(self, token_weight_pair): return self.clip_g.untokenize(token_weight_pair) + def state_dict(self): + return {} + class SD3ClipModel(torch.nn.Module): def __init__(self, clip_l=True, clip_g=True, t5=True, dtype_t5=None, device="cpu", dtype=None): super().__init__() diff --git a/comfy/text_encoders/spiece_tokenizer.py b/comfy/text_encoders/spiece_tokenizer.py new file mode 100644 index 000000000..73739553d --- /dev/null +++ b/comfy/text_encoders/spiece_tokenizer.py @@ -0,0 +1,32 @@ +import os +import torch + +class SPieceTokenizer: + add_eos = True + + @staticmethod + def from_pretrained(path): + return SPieceTokenizer(path) + + def __init__(self, tokenizer_path): + import sentencepiece + if torch.is_tensor(tokenizer_path): + tokenizer_path = tokenizer_path.numpy().tobytes() + + if isinstance(tokenizer_path, bytes): + self.tokenizer = sentencepiece.SentencePieceProcessor(model_proto=tokenizer_path, add_eos=self.add_eos) + else: + self.tokenizer = sentencepiece.SentencePieceProcessor(model_file=tokenizer_path, add_eos=self.add_eos) + + def get_vocab(self): + out = {} + for i in range(self.tokenizer.get_piece_size()): + out[self.tokenizer.id_to_piece(i)] = i + return out + + def __call__(self, string): + out = self.tokenizer.encode(string) + return {"input_ids": out} + + def serialize_model(self): + return torch.ByteTensor(list(self.tokenizer.serialized_model_proto())) diff --git a/comfy/t5.py b/comfy/text_encoders/t5.py similarity index 90% rename from comfy/t5.py rename to comfy/text_encoders/t5.py index 06dfe4766..ba628478d 100644 --- a/comfy/t5.py +++ b/comfy/text_encoders/t5.py @@ -13,29 +13,36 @@ class T5LayerNorm(torch.nn.Module): x = x * torch.rsqrt(variance + self.variance_epsilon) return self.weight.to(device=x.device, dtype=x.dtype) * x +activations = { + "gelu_pytorch_tanh": lambda a: torch.nn.functional.gelu(a, approximate="tanh"), + "relu": torch.nn.functional.relu, +} + class T5DenseActDense(torch.nn.Module): - def __init__(self, model_dim, ff_dim, dtype, device, operations): + def __init__(self, model_dim, ff_dim, ff_activation, dtype, device, operations): super().__init__() self.wi = operations.Linear(model_dim, ff_dim, bias=False, dtype=dtype, device=device) self.wo = operations.Linear(ff_dim, model_dim, bias=False, dtype=dtype, device=device) # self.dropout = nn.Dropout(config.dropout_rate) + self.act = activations[ff_activation] def forward(self, x): - x = torch.nn.functional.relu(self.wi(x)) + x = self.act(self.wi(x)) # x = self.dropout(x) x = self.wo(x) return x class T5DenseGatedActDense(torch.nn.Module): - def __init__(self, model_dim, ff_dim, dtype, device, operations): + def __init__(self, model_dim, ff_dim, ff_activation, dtype, device, operations): super().__init__() self.wi_0 = operations.Linear(model_dim, ff_dim, bias=False, dtype=dtype, device=device) self.wi_1 = operations.Linear(model_dim, ff_dim, bias=False, dtype=dtype, device=device) self.wo = operations.Linear(ff_dim, model_dim, bias=False, dtype=dtype, device=device) # self.dropout = nn.Dropout(config.dropout_rate) + self.act = activations[ff_activation] def forward(self, x): - hidden_gelu = torch.nn.functional.gelu(self.wi_0(x), approximate="tanh") + hidden_gelu = self.act(self.wi_0(x)) hidden_linear = self.wi_1(x) x = hidden_gelu * hidden_linear # x = self.dropout(x) @@ -43,12 +50,12 @@ class T5DenseGatedActDense(torch.nn.Module): return x class T5LayerFF(torch.nn.Module): - def __init__(self, model_dim, ff_dim, ff_activation, dtype, device, operations): + def __init__(self, model_dim, ff_dim, ff_activation, gated_act, dtype, device, operations): super().__init__() - if ff_activation == "gelu_pytorch_tanh": - self.DenseReluDense = T5DenseGatedActDense(model_dim, ff_dim, dtype, device, operations) - elif ff_activation == "relu": - self.DenseReluDense = T5DenseActDense(model_dim, ff_dim, dtype, device, operations) + if gated_act: + self.DenseReluDense = T5DenseGatedActDense(model_dim, ff_dim, ff_activation, dtype, device, operations) + else: + self.DenseReluDense = T5DenseActDense(model_dim, ff_dim, ff_activation, dtype, device, operations) self.layer_norm = T5LayerNorm(model_dim, dtype=dtype, device=device, operations=operations) # self.dropout = nn.Dropout(config.dropout_rate) @@ -171,11 +178,11 @@ class T5LayerSelfAttention(torch.nn.Module): return x, past_bias class T5Block(torch.nn.Module): - def __init__(self, model_dim, inner_dim, ff_dim, ff_activation, num_heads, relative_attention_bias, dtype, device, operations): + def __init__(self, model_dim, inner_dim, ff_dim, ff_activation, gated_act, num_heads, relative_attention_bias, dtype, device, operations): super().__init__() self.layer = torch.nn.ModuleList() self.layer.append(T5LayerSelfAttention(model_dim, inner_dim, ff_dim, num_heads, relative_attention_bias, dtype, device, operations)) - self.layer.append(T5LayerFF(model_dim, ff_dim, ff_activation, dtype, device, operations)) + self.layer.append(T5LayerFF(model_dim, ff_dim, ff_activation, gated_act, dtype, device, operations)) def forward(self, x, mask=None, past_bias=None, optimized_attention=None): x, past_bias = self.layer[0](x, mask, past_bias, optimized_attention) @@ -183,11 +190,11 @@ class T5Block(torch.nn.Module): return x, past_bias class T5Stack(torch.nn.Module): - def __init__(self, num_layers, model_dim, inner_dim, ff_dim, ff_activation, num_heads, dtype, device, operations): + def __init__(self, num_layers, model_dim, inner_dim, ff_dim, ff_activation, gated_act, num_heads, relative_attention, dtype, device, operations): super().__init__() self.block = torch.nn.ModuleList( - [T5Block(model_dim, inner_dim, ff_dim, ff_activation, num_heads, relative_attention_bias=(i == 0), dtype=dtype, device=device, operations=operations) for i in range(num_layers)] + [T5Block(model_dim, inner_dim, ff_dim, ff_activation, gated_act, num_heads, relative_attention_bias=((not relative_attention) or (i == 0)), dtype=dtype, device=device, operations=operations) for i in range(num_layers)] ) self.final_layer_norm = T5LayerNorm(model_dim, dtype=dtype, device=device, operations=operations) # self.dropout = nn.Dropout(config.dropout_rate) @@ -216,7 +223,7 @@ class T5(torch.nn.Module): self.num_layers = config_dict["num_layers"] model_dim = config_dict["d_model"] - self.encoder = T5Stack(self.num_layers, model_dim, model_dim, config_dict["d_ff"], config_dict["dense_act_fn"], config_dict["num_heads"], dtype, device, operations) + self.encoder = T5Stack(self.num_layers, model_dim, model_dim, config_dict["d_ff"], config_dict["dense_act_fn"], config_dict["is_gated_act"], config_dict["num_heads"], config_dict["model_type"] != "umt5", dtype, device, operations) self.dtype = dtype self.shared = torch.nn.Embedding(config_dict["vocab_size"], model_dim, device=device) diff --git a/comfy/t5_config_base.json b/comfy/text_encoders/t5_config_base.json similarity index 94% rename from comfy/t5_config_base.json rename to comfy/text_encoders/t5_config_base.json index facd85ef3..71f68327c 100644 --- a/comfy/t5_config_base.json +++ b/comfy/text_encoders/t5_config_base.json @@ -8,6 +8,7 @@ "dense_act_fn": "relu", "initializer_factor": 1.0, "is_encoder_decoder": true, + "is_gated_act": false, "layer_norm_epsilon": 1e-06, "model_type": "t5", "num_decoder_layers": 12, diff --git a/comfy/t5_config_xxl.json b/comfy/text_encoders/t5_config_xxl.json similarity index 95% rename from comfy/t5_config_xxl.json rename to comfy/text_encoders/t5_config_xxl.json index bf4feadcf..28283b51a 100644 --- a/comfy/t5_config_xxl.json +++ b/comfy/text_encoders/t5_config_xxl.json @@ -8,6 +8,7 @@ "dense_act_fn": "gelu_pytorch_tanh", "initializer_factor": 1.0, "is_encoder_decoder": true, + "is_gated_act": true, "layer_norm_epsilon": 1e-06, "model_type": "t5", "num_decoder_layers": 24, diff --git a/comfy/text_encoders/t5_pile_config_xl.json b/comfy/text_encoders/t5_pile_config_xl.json new file mode 100644 index 000000000..ee4e03f97 --- /dev/null +++ b/comfy/text_encoders/t5_pile_config_xl.json @@ -0,0 +1,22 @@ +{ + "d_ff": 5120, + "d_kv": 64, + "d_model": 2048, + "decoder_start_token_id": 0, + "dropout_rate": 0.1, + "eos_token_id": 2, + "dense_act_fn": "gelu_pytorch_tanh", + "initializer_factor": 1.0, + "is_encoder_decoder": true, + "is_gated_act": true, + "layer_norm_epsilon": 1e-06, + "model_type": "umt5", + "num_decoder_layers": 24, + "num_heads": 32, + "num_layers": 24, + "output_past": true, + "pad_token_id": 1, + "relative_attention_num_buckets": 32, + "tie_word_embeddings": false, + "vocab_size": 32128 +} diff --git a/comfy/text_encoders/t5_pile_tokenizer/tokenizer.model b/comfy/text_encoders/t5_pile_tokenizer/tokenizer.model new file mode 100644 index 000000000..22bccbcb4 Binary files /dev/null and b/comfy/text_encoders/t5_pile_tokenizer/tokenizer.model differ diff --git a/comfy/t5_tokenizer/special_tokens_map.json b/comfy/text_encoders/t5_tokenizer/special_tokens_map.json similarity index 100% rename from comfy/t5_tokenizer/special_tokens_map.json rename to comfy/text_encoders/t5_tokenizer/special_tokens_map.json diff --git a/comfy/t5_tokenizer/tokenizer.json b/comfy/text_encoders/t5_tokenizer/tokenizer.json similarity index 100% rename from comfy/t5_tokenizer/tokenizer.json rename to comfy/text_encoders/t5_tokenizer/tokenizer.json diff --git a/comfy/t5_tokenizer/tokenizer_config.json b/comfy/text_encoders/t5_tokenizer/tokenizer_config.json similarity index 100% rename from comfy/t5_tokenizer/tokenizer_config.json rename to comfy/text_encoders/t5_tokenizer/tokenizer_config.json diff --git a/comfy/utils.py b/comfy/utils.py index ed6c58a64..1e4b5ef88 100644 --- a/comfy/utils.py +++ b/comfy/utils.py @@ -298,7 +298,8 @@ def mmdit_to_diffusers(mmdit_config, output_prefix=""): key_map = {} depth = mmdit_config.get("depth", 0) - for i in range(depth): + num_blocks = mmdit_config.get("num_blocks", depth) + for i in range(num_blocks): block_from = "transformer_blocks.{}".format(i) block_to = "{}joint_blocks.{}".format(output_prefix, i) @@ -331,6 +332,76 @@ def mmdit_to_diffusers(mmdit_config, output_prefix=""): return key_map + +def auraflow_to_diffusers(mmdit_config, output_prefix=""): + n_double_layers = mmdit_config.get("n_double_layers", 0) + n_layers = mmdit_config.get("n_layers", 0) + + key_map = {} + for i in range(n_layers): + if i < n_double_layers: + index = i + prefix_from = "joint_transformer_blocks" + prefix_to = "{}double_layers".format(output_prefix) + block_map = { + "attn.to_q.weight": "attn.w2q.weight", + "attn.to_k.weight": "attn.w2k.weight", + "attn.to_v.weight": "attn.w2v.weight", + "attn.to_out.0.weight": "attn.w2o.weight", + "attn.add_q_proj.weight": "attn.w1q.weight", + "attn.add_k_proj.weight": "attn.w1k.weight", + "attn.add_v_proj.weight": "attn.w1v.weight", + "attn.to_add_out.weight": "attn.w1o.weight", + "ff.linear_1.weight": "mlpX.c_fc1.weight", + "ff.linear_2.weight": "mlpX.c_fc2.weight", + "ff.out_projection.weight": "mlpX.c_proj.weight", + "ff_context.linear_1.weight": "mlpC.c_fc1.weight", + "ff_context.linear_2.weight": "mlpC.c_fc2.weight", + "ff_context.out_projection.weight": "mlpC.c_proj.weight", + "norm1.linear.weight": "modX.1.weight", + "norm1_context.linear.weight": "modC.1.weight", + } + else: + index = i - n_double_layers + prefix_from = "single_transformer_blocks" + prefix_to = "{}single_layers".format(output_prefix) + + block_map = { + "attn.to_q.weight": "attn.w1q.weight", + "attn.to_k.weight": "attn.w1k.weight", + "attn.to_v.weight": "attn.w1v.weight", + "attn.to_out.0.weight": "attn.w1o.weight", + "norm1.linear.weight": "modCX.1.weight", + "ff.linear_1.weight": "mlp.c_fc1.weight", + "ff.linear_2.weight": "mlp.c_fc2.weight", + "ff.out_projection.weight": "mlp.c_proj.weight" + } + + for k in block_map: + key_map["{}.{}.{}".format(prefix_from, index, k)] = "{}.{}.{}".format(prefix_to, index, block_map[k]) + + MAP_BASIC = { + ("positional_encoding", "pos_embed.pos_embed"), + ("register_tokens", "register_tokens"), + ("t_embedder.mlp.0.weight", "time_step_proj.linear_1.weight"), + ("t_embedder.mlp.0.bias", "time_step_proj.linear_1.bias"), + ("t_embedder.mlp.2.weight", "time_step_proj.linear_2.weight"), + ("t_embedder.mlp.2.bias", "time_step_proj.linear_2.bias"), + ("cond_seq_linear.weight", "context_embedder.weight"), + ("init_x_linear.weight", "pos_embed.proj.weight"), + ("init_x_linear.bias", "pos_embed.proj.bias"), + ("final_linear.weight", "proj_out.weight"), + ("modF.1.weight", "norm_out.linear.weight", swap_scale_shift), + } + + for k in MAP_BASIC: + if len(k) > 2: + key_map[k[1]] = ("{}{}".format(output_prefix, k[0]), None, k[2]) + else: + key_map[k[1]] = "{}{}".format(output_prefix, k[0]) + + return key_map + def repeat_to_batch_size(tensor, batch_size, dim=0): if tensor.shape[dim] > batch_size: return tensor.narrow(dim, 0, batch_size) diff --git a/comfy_extras/nodes_advanced_samplers.py b/comfy_extras/nodes_advanced_samplers.py index 7aa89c644..820c250ef 100644 --- a/comfy_extras/nodes_advanced_samplers.py +++ b/comfy_extras/nodes_advanced_samplers.py @@ -60,7 +60,7 @@ from comfy.k_diffusion.sampling import to_d import comfy.model_patcher @torch.no_grad() -def sample_euler_cfgpp(model, x, sigmas, extra_args=None, callback=None, disable=None): +def sample_euler_pp(model, x, sigmas, extra_args=None, callback=None, disable=None): extra_args = {} if extra_args is None else extra_args temp = [0] @@ -75,37 +75,14 @@ def sample_euler_cfgpp(model, x, sigmas, extra_args=None, callback=None, disable for i in trange(len(sigmas) - 1, disable=disable): sigma_hat = sigmas[i] denoised = model(x, sigma_hat * s_in, **extra_args) - d = to_d(x, sigma_hat, temp[0]) + d = to_d(x - denoised + temp[0], sigmas[i], denoised) if callback is not None: callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigma_hat, 'denoised': denoised}) dt = sigmas[i + 1] - sigma_hat - x = denoised + sigmas[i + 1] * d - return x - -@torch.no_grad() -def sample_euler_cfgpp_alt(model, x, sigmas, extra_args=None, callback=None, disable=None): - extra_args = {} if extra_args is None else extra_args - - temp = [0] - def post_cfg_function(args): - temp[0] = args["uncond_denoised"] - return args["denoised"] - - model_options = extra_args.get("model_options", {}).copy() - extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function(model_options, post_cfg_function, disable_cfg1_optimization=True) - - s_in = x.new_ones([x.shape[0]]) - for i in trange(len(sigmas) - 1, disable=disable): - sigma_hat = sigmas[i] - denoised = model(x, sigma_hat * s_in, **extra_args) - d = to_d(x - denoised + temp[0], sigma_hat, denoised) - if callback is not None: - callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigma_hat, 'denoised': denoised}) - dt = sigmas[i + 1] - sigma_hat - # Euler method x = x + d * dt return x + class SamplerEulerCFGpp: @classmethod def INPUT_TYPES(s): @@ -119,10 +96,10 @@ class SamplerEulerCFGpp: FUNCTION = "get_sampler" def get_sampler(self, version): - if version == "regular": - sampler = comfy.samplers.KSAMPLER(sample_euler_cfgpp) + if version == "alternative": + sampler = comfy.samplers.KSAMPLER(sample_euler_pp) else: - sampler = comfy.samplers.KSAMPLER(sample_euler_cfgpp_alt) + sampler = comfy.samplers.ksampler("euler_cfg_pp") return (sampler, ) NODE_CLASS_MAPPINGS = { diff --git a/comfy_extras/nodes_audio.py b/comfy_extras/nodes_audio.py index 5f4bd3540..6f0e26365 100644 --- a/comfy_extras/nodes_audio.py +++ b/comfy_extras/nodes_audio.py @@ -3,6 +3,11 @@ import torch import comfy.model_management import folder_paths import os +import io +import json +import struct +import random +from comfy.cli_args import args class EmptyLatentAudio: def __init__(self): @@ -10,15 +15,16 @@ class EmptyLatentAudio: @classmethod def INPUT_TYPES(s): - return {"required": {}} + return {"required": {"seconds": ("FLOAT", {"default": 47.6, "min": 1.0, "max": 1000.0, "step": 0.1})}} RETURN_TYPES = ("LATENT",) FUNCTION = "generate" - CATEGORY = "_for_testing/audio" + CATEGORY = "latent/audio" - def generate(self): + def generate(self, seconds): batch_size = 1 - latent = torch.zeros([batch_size, 64, 1024], device=self.device) + length = round((seconds * 44100 / 2048) / 2) * 2 + latent = torch.zeros([batch_size, 64, length], device=self.device) return ({"samples":latent, "type": "audio"}, ) class VAEEncodeAudio: @@ -28,10 +34,16 @@ class VAEEncodeAudio: RETURN_TYPES = ("LATENT",) FUNCTION = "encode" - CATEGORY = "_for_testing/audio" + CATEGORY = "latent/audio" def encode(self, vae, audio): - t = vae.encode(audio["waveform"].movedim(1, -1)) + sample_rate = audio["sample_rate"] + if 44100 != sample_rate: + waveform = torchaudio.functional.resample(audio["waveform"], sample_rate, 44100) + else: + waveform = audio["waveform"] + + t = vae.encode(waveform.movedim(1, -1)) return ({"samples":t}, ) class VAEDecodeAudio: @@ -41,18 +53,72 @@ class VAEDecodeAudio: RETURN_TYPES = ("AUDIO",) FUNCTION = "decode" - CATEGORY = "_for_testing/audio" + CATEGORY = "latent/audio" def decode(self, vae, samples): audio = vae.decode(samples["samples"]).movedim(-1, 1) return ({"waveform": audio, "sample_rate": 44100}, ) + +def create_vorbis_comment_block(comment_dict, last_block): + vendor_string = b'ComfyUI' + vendor_length = len(vendor_string) + + comments = [] + for key, value in comment_dict.items(): + comment = f"{key}={value}".encode('utf-8') + comments.append(struct.pack('I', len(comment_data))[1:] + comment_data + + return comment_block + +def insert_or_replace_vorbis_comment(flac_io, comment_dict): + if len(comment_dict) == 0: + return flac_io + + flac_io.seek(4) + + blocks = [] + last_block = False + + while not last_block: + header = flac_io.read(4) + last_block = (header[0] & 0x80) != 0 + block_type = header[0] & 0x7F + block_length = struct.unpack('>I', b'\x00' + header[1:])[0] + block_data = flac_io.read(block_length) + + if block_type == 4 or block_type == 1: + pass + else: + header = bytes([(header[0] & (~0x80))]) + header[1:] + blocks.append(header + block_data) + + blocks.append(create_vorbis_comment_block(comment_dict, last_block=True)) + + new_flac_io = io.BytesIO() + new_flac_io.write(b'fLaC') + for block in blocks: + new_flac_io.write(block) + + new_flac_io.write(flac_io.read()) + return new_flac_io + + class SaveAudio: def __init__(self): self.output_dir = folder_paths.get_output_directory() self.type = "output" self.prefix_append = "" - self.compress_level = 4 @classmethod def INPUT_TYPES(s): @@ -66,17 +132,33 @@ class SaveAudio: OUTPUT_NODE = True - CATEGORY = "_for_testing/audio" + CATEGORY = "audio" def save_audio(self, audio, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None): filename_prefix += self.prefix_append full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir) results = list() - for (batch_number, waveform) in enumerate(audio["waveform"]): - #TODO: metadata + + metadata = {} + if not args.disable_metadata: + if prompt is not None: + metadata["prompt"] = json.dumps(prompt) + if extra_pnginfo is not None: + for x in extra_pnginfo: + metadata[x] = json.dumps(extra_pnginfo[x]) + + for (batch_number, waveform) in enumerate(audio["waveform"].cpu()): filename_with_batch_num = filename.replace("%batch_num%", str(batch_number)) file = f"{filename_with_batch_num}_{counter:05}_.flac" - torchaudio.save(os.path.join(full_output_folder, file), waveform, audio["sample_rate"], format="FLAC") + + buff = io.BytesIO() + torchaudio.save(buff, waveform, audio["sample_rate"], format="FLAC") + + buff = insert_or_replace_vorbis_comment(buff, metadata) + + with open(os.path.join(full_output_folder, file), 'wb') as f: + f.write(buff.getbuffer()) + results.append({ "filename": file, "subfolder": subfolder, @@ -86,14 +168,34 @@ class SaveAudio: return { "ui": { "audio": results } } +class PreviewAudio(SaveAudio): + def __init__(self): + self.output_dir = folder_paths.get_temp_directory() + self.type = "temp" + self.prefix_append = "_temp_" + ''.join(random.choice("abcdefghijklmnopqrstupvxyz") for x in range(5)) + + @classmethod + def INPUT_TYPES(s): + return {"required": + {"audio": ("AUDIO", ), }, + "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}, + } + class LoadAudio: + SUPPORTED_FORMATS = ('.wav', '.mp3', '.ogg', '.flac', '.aiff', '.aif') + @classmethod def INPUT_TYPES(s): input_dir = folder_paths.get_input_directory() - files = [f for f in os.listdir(input_dir) if os.path.isfile(os.path.join(input_dir, f))] - return {"required": {"audio": [sorted(files), ]}, } + files = [ + f for f in os.listdir(input_dir) + if (os.path.isfile(os.path.join(input_dir, f)) + and f.endswith(LoadAudio.SUPPORTED_FORMATS) + ) + ] + return {"required": {"audio": (sorted(files), {"audio_upload": True})}} - CATEGORY = "_for_testing/audio" + CATEGORY = "audio" RETURN_TYPES = ("AUDIO", ) FUNCTION = "load" @@ -101,7 +203,6 @@ class LoadAudio: def load(self, audio): audio_path = folder_paths.get_annotated_filepath(audio) waveform, sample_rate = torchaudio.load(audio_path) - multiplier = 1.0 audio = {"waveform": waveform.unsqueeze(0), "sample_rate": sample_rate} return (audio, ) @@ -125,4 +226,5 @@ NODE_CLASS_MAPPINGS = { "VAEDecodeAudio": VAEDecodeAudio, "SaveAudio": SaveAudio, "LoadAudio": LoadAudio, + "PreviewAudio": PreviewAudio, } diff --git a/comfy_extras/nodes_controlnet.py b/comfy_extras/nodes_controlnet.py new file mode 100644 index 000000000..0773c8a5b --- /dev/null +++ b/comfy_extras/nodes_controlnet.py @@ -0,0 +1,27 @@ +from comfy.cldm.control_types import UNION_CONTROLNET_TYPES + +class SetUnionControlNetType: + @classmethod + def INPUT_TYPES(s): + return {"required": {"control_net": ("CONTROL_NET", ), + "type": (["auto"] + list(UNION_CONTROLNET_TYPES.keys()),) + }} + + CATEGORY = "conditioning/controlnet" + RETURN_TYPES = ("CONTROL_NET",) + + FUNCTION = "set_controlnet_type" + + def set_controlnet_type(self, control_net, type): + control_net = control_net.copy() + type_number = UNION_CONTROLNET_TYPES.get(type, -1) + if type_number >= 0: + control_net.set_extra_arg("control_type", [type_number]) + else: + control_net.set_extra_arg("control_type", []) + + return (control_net,) + +NODE_CLASS_MAPPINGS = { + "SetUnionControlNetType": SetUnionControlNetType, +} diff --git a/comfy_extras/nodes_custom_sampler.py b/comfy_extras/nodes_custom_sampler.py index 69f1b9418..b7ab88c27 100644 --- a/comfy_extras/nodes_custom_sampler.py +++ b/comfy_extras/nodes_custom_sampler.py @@ -111,6 +111,25 @@ class SDTurboScheduler: sigmas = torch.cat([sigmas, sigmas.new_zeros([1])]) return (sigmas, ) +class BetaSamplingScheduler: + @classmethod + def INPUT_TYPES(s): + return {"required": + {"model": ("MODEL",), + "steps": ("INT", {"default": 20, "min": 1, "max": 10000}), + "alpha": ("FLOAT", {"default": 0.6, "min": 0.0, "max": 50.0, "step":0.01, "round": False}), + "beta": ("FLOAT", {"default": 0.6, "min": 0.0, "max": 50.0, "step":0.01, "round": False}), + } + } + RETURN_TYPES = ("SIGMAS",) + CATEGORY = "sampling/custom_sampling/schedulers" + + FUNCTION = "get_sigmas" + + def get_sigmas(self, model, steps, alpha, beta): + sigmas = comfy.samplers.beta_scheduler(model.get_model_object("model_sampling"), steps, alpha=alpha, beta=beta) + return (sigmas, ) + class VPScheduler: @classmethod def INPUT_TYPES(s): @@ -293,6 +312,25 @@ class SamplerEulerAncestral: sampler = comfy.samplers.ksampler("euler_ancestral", {"eta": eta, "s_noise": s_noise}) return (sampler, ) +class SamplerEulerAncestralCFGPP: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "eta": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step":0.01, "round": False}), + "s_noise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step":0.01, "round": False}), + }} + RETURN_TYPES = ("SAMPLER",) + CATEGORY = "sampling/custom_sampling/samplers" + + FUNCTION = "get_sampler" + + def get_sampler(self, eta, s_noise): + sampler = comfy.samplers.ksampler( + "euler_ancestral_cfg_pp", + {"eta": eta, "s_noise": s_noise}) + return (sampler, ) + class SamplerLMS: @classmethod def INPUT_TYPES(s): @@ -619,9 +657,11 @@ NODE_CLASS_MAPPINGS = { "ExponentialScheduler": ExponentialScheduler, "PolyexponentialScheduler": PolyexponentialScheduler, "VPScheduler": VPScheduler, + "BetaSamplingScheduler": BetaSamplingScheduler, "SDTurboScheduler": SDTurboScheduler, "KSamplerSelect": KSamplerSelect, "SamplerEulerAncestral": SamplerEulerAncestral, + "SamplerEulerAncestralCFGPP": SamplerEulerAncestralCFGPP, "SamplerLMS": SamplerLMS, "SamplerDPMPP_3M_SDE": SamplerDPMPP_3M_SDE, "SamplerDPMPP_2M_SDE": SamplerDPMPP_2M_SDE, @@ -639,3 +679,7 @@ NODE_CLASS_MAPPINGS = { "AddNoise": AddNoise, "SamplerCustomAdvanced": SamplerCustomAdvanced, } + +NODE_DISPLAY_NAME_MAPPINGS = { + "SamplerEulerAncestralCFGPP": "SamplerEulerAncestralCFG++", +} \ No newline at end of file diff --git a/comfy_extras/nodes_freelunch.py b/comfy_extras/nodes_freelunch.py index c5ebcf26f..e3ac58447 100644 --- a/comfy_extras/nodes_freelunch.py +++ b/comfy_extras/nodes_freelunch.py @@ -34,7 +34,7 @@ class FreeU: RETURN_TYPES = ("MODEL",) FUNCTION = "patch" - CATEGORY = "model_patches" + CATEGORY = "model_patches/unet" def patch(self, model, b1, b2, s1, s2): model_channels = model.model.model_config.unet_config["model_channels"] @@ -73,7 +73,7 @@ class FreeU_V2: RETURN_TYPES = ("MODEL",) FUNCTION = "patch" - CATEGORY = "model_patches" + CATEGORY = "model_patches/unet" def patch(self, model, b1, b2, s1, s2): model_channels = model.model.model_config.unet_config["model_channels"] diff --git a/comfy_extras/nodes_hunyuan.py b/comfy_extras/nodes_hunyuan.py new file mode 100644 index 000000000..a3ac8cb06 --- /dev/null +++ b/comfy_extras/nodes_hunyuan.py @@ -0,0 +1,24 @@ +class CLIPTextEncodeHunyuanDiT: + @classmethod + def INPUT_TYPES(s): + return {"required": { + "clip": ("CLIP", ), + "bert": ("STRING", {"multiline": True, "dynamicPrompts": True}), + "mt5xl": ("STRING", {"multiline": True, "dynamicPrompts": True}), + }} + RETURN_TYPES = ("CONDITIONING",) + FUNCTION = "encode" + + CATEGORY = "advanced/conditioning" + + def encode(self, clip, bert, mt5xl): + tokens = clip.tokenize(bert) + tokens["mt5xl"] = clip.tokenize(mt5xl)["mt5xl"] + + output = clip.encode_from_tokens(tokens, return_pooled=True, return_dict=True) + cond = output.pop("cond") + return ([[cond, output]], ) + +NODE_CLASS_MAPPINGS = { + "CLIPTextEncodeHunyuanDiT": CLIPTextEncodeHunyuanDiT, +} diff --git a/comfy_extras/nodes_hypertile.py b/comfy_extras/nodes_hypertile.py index ae55d23dd..227133f39 100644 --- a/comfy_extras/nodes_hypertile.py +++ b/comfy_extras/nodes_hypertile.py @@ -32,7 +32,7 @@ class HyperTile: RETURN_TYPES = ("MODEL",) FUNCTION = "patch" - CATEGORY = "model_patches" + CATEGORY = "model_patches/unet" def patch(self, model, tile_size, swap_size, max_depth, scale_depth): model_channels = model.model.model_config.unet_config["model_channels"] diff --git a/comfy_extras/nodes_model_advanced.py b/comfy_extras/nodes_model_advanced.py index 97559cf56..22ba9547b 100644 --- a/comfy_extras/nodes_model_advanced.py +++ b/comfy_extras/nodes_model_advanced.py @@ -144,7 +144,7 @@ class ModelSamplingSD3: CATEGORY = "advanced/model" - def patch(self, model, shift): + def patch(self, model, shift, multiplier=1000): m = model.clone() sampling_base = comfy.model_sampling.ModelSamplingDiscreteFlow @@ -154,10 +154,22 @@ class ModelSamplingSD3: pass model_sampling = ModelSamplingAdvanced(model.model.model_config) - model_sampling.set_parameters(shift=shift) + model_sampling.set_parameters(shift=shift, multiplier=multiplier) m.add_object_patch("model_sampling", model_sampling) return (m, ) +class ModelSamplingAuraFlow(ModelSamplingSD3): + @classmethod + def INPUT_TYPES(s): + return {"required": { "model": ("MODEL",), + "shift": ("FLOAT", {"default": 1.73, "min": 0.0, "max": 100.0, "step":0.01}), + }} + + FUNCTION = "patch_aura" + + def patch_aura(self, model, shift): + return self.patch(model, shift, multiplier=1.0) + class ModelSamplingContinuousEDM: @classmethod def INPUT_TYPES(s): @@ -271,5 +283,6 @@ NODE_CLASS_MAPPINGS = { "ModelSamplingContinuousV": ModelSamplingContinuousV, "ModelSamplingStableCascade": ModelSamplingStableCascade, "ModelSamplingSD3": ModelSamplingSD3, + "ModelSamplingAuraFlow": ModelSamplingAuraFlow, "RescaleCFG": RescaleCFG, } diff --git a/comfy_extras/nodes_pag.py b/comfy_extras/nodes_pag.py index 63f43fd62..aec78bd8a 100644 --- a/comfy_extras/nodes_pag.py +++ b/comfy_extras/nodes_pag.py @@ -19,7 +19,7 @@ class PerturbedAttentionGuidance: RETURN_TYPES = ("MODEL",) FUNCTION = "patch" - CATEGORY = "_for_testing" + CATEGORY = "model_patches/unet" def patch(self, model, scale): unet_block = "middle" diff --git a/comfy_extras/nodes_sd3.py b/comfy_extras/nodes_sd3.py index d0303aec5..0aafa2426 100644 --- a/comfy_extras/nodes_sd3.py +++ b/comfy_extras/nodes_sd3.py @@ -80,8 +80,23 @@ class CLIPTextEncodeSD3: return ([[cond, {"pooled_output": pooled}]], ) +class ControlNetApplySD3(nodes.ControlNetApplyAdvanced): + @classmethod + def INPUT_TYPES(s): + return {"required": {"positive": ("CONDITIONING", ), + "negative": ("CONDITIONING", ), + "control_net": ("CONTROL_NET", ), + "vae": ("VAE", ), + "image": ("IMAGE", ), + "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}), + "start_percent": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}), + "end_percent": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}) + }} + CATEGORY = "conditioning/controlnet" + NODE_CLASS_MAPPINGS = { "TripleCLIPLoader": TripleCLIPLoader, "EmptySD3LatentImage": EmptySD3LatentImage, "CLIPTextEncodeSD3": CLIPTextEncodeSD3, + "ControlNetApplySD3": ControlNetApplySD3, } diff --git a/custom_nodes/example_node.py.example b/custom_nodes/example_node.py.example index f06632593..72ca3688c 100644 --- a/custom_nodes/example_node.py.example +++ b/custom_nodes/example_node.py.example @@ -12,9 +12,9 @@ class Example: Attributes ---------- RETURN_TYPES (`tuple`): - The type of each element in the output tulple. + The type of each element in the output tuple. RETURN_NAMES (`tuple`): - Optional: The name of each output in the output tulple. + Optional: The name of each output in the output tuple. FUNCTION (`str`): The name of the entry-point method. For example, if `FUNCTION = "execute"` then it will run Example().execute() OUTPUT_NODE ([`bool`]): @@ -44,7 +44,7 @@ class Example: * Key field_name (`string`): Name of a entry-point method's argument * Value field_config (`tuple`): + First value is a string indicate the type of field or a list for selection. - + Secound value is a config for type "INT", "STRING" or "FLOAT". + + Second value is a config for type "INT", "STRING" or "FLOAT". """ return { "required": { @@ -61,7 +61,7 @@ class Example: "min": 0.0, "max": 10.0, "step": 0.01, - "round": 0.001, #The value represeting the precision to round to, will be set to the step value by default. Can be set to False to disable rounding. + "round": 0.001, #The value representing the precision to round to, will be set to the step value by default. Can be set to False to disable rounding. "display": "number"}), "print_to_screen": (["enable", "disable"],), "string_field": ("STRING", { @@ -106,6 +106,16 @@ class Example: # Set the web directory, any .js file in that directory will be loaded by the frontend as a frontend extension # WEB_DIRECTORY = "./somejs" + +# Add custom API routes, using router +from aiohttp import web +from server import PromptServer + +@PromptServer.instance.routes.get("/hello") +async def get_hello(request): + return web.json_response("hello") + + # A dictionary that contains all nodes you want to export with their names # NOTE: names should be globally unique NODE_CLASS_MAPPINGS = { diff --git a/execution.py b/execution.py index 76225a962..0a2e62e7e 100644 --- a/execution.py +++ b/execution.py @@ -3,6 +3,7 @@ import copy import logging import threading import heapq +import time import traceback import inspect from typing import List, Literal, NamedTuple, Optional @@ -247,6 +248,8 @@ def recursive_output_delete_if_changed(prompt, old_prompt, outputs, current_item to_delete = True elif unique_id not in old_prompt: to_delete = True + elif class_type != old_prompt[unique_id]['class_type']: + to_delete = True elif inputs == old_prompt[unique_id]['inputs']: for x in inputs: input_data = inputs[x] @@ -281,7 +284,11 @@ class PromptExecutor: self.success = True self.old_prompt = {} - def add_message(self, event, data, broadcast: bool): + def add_message(self, event, data: dict, broadcast: bool): + data = { + **data, + "timestamp": int(time.time() * 1000), + } self.status_messages.append((event, data)) if self.server.client_id is not None or broadcast: self.server.send_sync(event, data, self.server.client_id) @@ -392,6 +399,9 @@ class PromptExecutor: if self.success is not True: self.handle_execution_error(prompt_id, prompt, current_outputs, executed, error, ex) break + else: + # Only execute when the while-loop ends without break + self.add_message("execution_success", { "prompt_id": prompt_id }, broadcast=False) for x in executed: self.old_prompt[x] = copy.deepcopy(prompt[x]) diff --git a/fix_torch.py b/fix_torch.py new file mode 100644 index 000000000..e350f5c7d --- /dev/null +++ b/fix_torch.py @@ -0,0 +1,24 @@ +import importlib.util +import shutil +import os +import ctypes +import logging + + +torch_spec = importlib.util.find_spec("torch") +for folder in torch_spec.submodule_search_locations: + lib_folder = os.path.join(folder, "lib") + test_file = os.path.join(lib_folder, "fbgemm.dll") + dest = os.path.join(lib_folder, "libomp140.x86_64.dll") + if os.path.exists(dest): + break + + with open(test_file, 'rb') as f: + contents = f.read() + if b"libomp140.x86_64.dll" not in contents: + break + try: + mydll = ctypes.cdll.LoadLibrary(test_file) + except FileNotFoundError as e: + logging.warning("Detected pytorch version with libomp issue, patching.") + shutil.copyfile(os.path.join(lib_folder, "libiomp5md.dll"), dest) diff --git a/folder_paths.py b/folder_paths.py index 234b73409..2baf8ce1c 100644 --- a/folder_paths.py +++ b/folder_paths.py @@ -1,10 +1,13 @@ import os import time import logging +from typing import Set, List, Dict, Tuple -supported_pt_extensions = set(['.ckpt', '.pt', '.bin', '.pth', '.safetensors', '.pkl']) +supported_pt_extensions: Set[str] = set(['.ckpt', '.pt', '.bin', '.pth', '.safetensors', '.pkl']) -folder_names_and_paths = {} +SupportedFileExtensionsType = Set[str] +ScanPathType = List[str] +folder_names_and_paths: Dict[str, Tuple[ScanPathType, SupportedFileExtensionsType]] = {} base_path = os.path.dirname(os.path.realpath(__file__)) models_dir = os.path.join(base_path, "models") @@ -26,7 +29,7 @@ folder_names_and_paths["gligen"] = ([os.path.join(models_dir, "gligen")], suppor folder_names_and_paths["upscale_models"] = ([os.path.join(models_dir, "upscale_models")], supported_pt_extensions) -folder_names_and_paths["custom_nodes"] = ([os.path.join(base_path, "custom_nodes")], []) +folder_names_and_paths["custom_nodes"] = ([os.path.join(base_path, "custom_nodes")], set()) folder_names_and_paths["hypernetworks"] = ([os.path.join(models_dir, "hypernetworks")], supported_pt_extensions) diff --git a/main.py b/main.py index a374f2b12..479643b84 100644 --- a/main.py +++ b/main.py @@ -5,6 +5,8 @@ import os import importlib.util import folder_paths import time +from comfy.cli_args import args + def execute_prestartup_script(): def execute_script(script_path): @@ -18,6 +20,9 @@ def execute_prestartup_script(): print(f"Failed to execute startup-script: {script_path} / {e}") return False + if args.disable_all_custom_nodes: + return + node_paths = folder_paths.get_folder_paths("custom_nodes") for custom_node_path in node_paths: possible_modules = os.listdir(custom_node_path) @@ -53,7 +58,6 @@ import shutil import threading import gc -from comfy.cli_args import args import logging if os.name == "nt": @@ -70,13 +74,19 @@ if __name__ == "__main__": import cuda_malloc +if args.windows_standalone_build: + try: + import fix_torch + except: + pass + import comfy.utils import yaml import execution import server from server import BinaryEventTypes -from nodes import init_custom_nodes +import nodes import comfy.model_management def cuda_malloc_warning(): @@ -214,7 +224,7 @@ if __name__ == "__main__": for config_path in itertools.chain(*args.extra_model_paths_config): load_extra_path_config(config_path) - init_custom_nodes() + nodes.init_extra_nodes(init_custom_nodes=not args.disable_all_custom_nodes) cuda_malloc_warning() diff --git a/node_helpers.py b/node_helpers.py index 43b9e829f..fee628790 100644 --- a/node_helpers.py +++ b/node_helpers.py @@ -1,3 +1,7 @@ +import hashlib + +from comfy.cli_args import args + from PIL import ImageFile, UnidentifiedImageError def conditioning_set_values(conditioning, values={}): @@ -22,3 +26,12 @@ def pillow(fn, arg): if prev_value is not None: ImageFile.LOAD_TRUNCATED_IMAGES = prev_value return x + +def hasher(): + hashfuncs = { + "md5": hashlib.md5, + "sha1": hashlib.sha1, + "sha256": hashlib.sha256, + "sha512": hashlib.sha512 + } + return hashfuncs[args.default_hashing_function] diff --git a/nodes.py b/nodes.py index 99645b81c..dc66dd3ef 100644 --- a/nodes.py +++ b/nodes.py @@ -55,8 +55,9 @@ class CLIPTextEncode: def encode(self, clip, text): tokens = clip.tokenize(text) - cond, pooled = clip.encode_from_tokens(tokens, return_pooled=True) - return ([[cond, {"pooled_output": pooled}]], ) + output = clip.encode_from_tokens(tokens, return_pooled=True, return_dict=True) + cond = output.pop("cond") + return ([[cond, output]], ) class ConditioningCombine: @classmethod @@ -232,8 +233,9 @@ class ConditioningZeroOut: c = [] for t in conditioning: d = t[1].copy() - if "pooled_output" in d: - d["pooled_output"] = torch.zeros_like(d["pooled_output"]) + pooled_output = d.get("pooled_output", None) + if pooled_output is not None: + d["pooled_output"] = torch.zeros_like(pooled_output) n = [torch.zeros_like(t[0]), d] c.append(n) return (c, ) @@ -746,7 +748,7 @@ class ControlNetApply: RETURN_TYPES = ("CONDITIONING",) FUNCTION = "apply_controlnet" - CATEGORY = "conditioning" + CATEGORY = "conditioning/controlnet" def apply_controlnet(self, conditioning, control_net, image, strength): if strength == 0: @@ -781,9 +783,9 @@ class ControlNetApplyAdvanced: RETURN_NAMES = ("positive", "negative") FUNCTION = "apply_controlnet" - CATEGORY = "conditioning" + CATEGORY = "conditioning/controlnet" - def apply_controlnet(self, positive, negative, control_net, image, strength, start_percent, end_percent): + def apply_controlnet(self, positive, negative, control_net, image, strength, start_percent, end_percent, vae=None): if strength == 0: return (positive, negative) @@ -800,7 +802,7 @@ class ControlNetApplyAdvanced: if prev_cnet in cnets: c_net = cnets[prev_cnet] else: - c_net = control_net.copy().set_cond_hint(control_hint, strength, (start_percent, end_percent)) + c_net = control_net.copy().set_cond_hint(control_hint, strength, (start_percent, end_percent), vae) c_net.set_previous_controlnet(prev_cnet) cnets[prev_cnet] = c_net @@ -1887,7 +1889,30 @@ NODE_DISPLAY_NAME_MAPPINGS = { EXTENSION_WEB_DIRS = {} -def load_custom_node(module_path, ignore=set()): + +def get_module_name(module_path: str) -> str: + """ + Returns the module name based on the given module path. + Examples: + get_module_name("C:/Users/username/ComfyUI/custom_nodes/my_custom_node.py") -> "my_custom_node" + get_module_name("C:/Users/username/ComfyUI/custom_nodes/my_custom_node") -> "my_custom_node" + get_module_name("C:/Users/username/ComfyUI/custom_nodes/my_custom_node/") -> "my_custom_node" + get_module_name("C:/Users/username/ComfyUI/custom_nodes/my_custom_node/__init__.py") -> "my_custom_node" + get_module_name("C:/Users/username/ComfyUI/custom_nodes/my_custom_node/__init__") -> "my_custom_node" + get_module_name("C:/Users/username/ComfyUI/custom_nodes/my_custom_node/__init__/") -> "my_custom_node" + get_module_name("C:/Users/username/ComfyUI/custom_nodes/my_custom_node.disabled") -> "custom_nodes + Args: + module_path (str): The path of the module. + Returns: + str: The module name. + """ + base_path = os.path.basename(module_path) + if os.path.isfile(module_path): + base_path = os.path.splitext(base_path)[0] + return base_path + + +def load_custom_node(module_path: str, ignore=set(), module_parent="custom_nodes") -> bool: module_name = os.path.basename(module_path) if os.path.isfile(module_path): sp = os.path.splitext(module_path) @@ -1911,9 +1936,10 @@ def load_custom_node(module_path, ignore=set()): EXTENSION_WEB_DIRS[module_name] = web_dir if hasattr(module, "NODE_CLASS_MAPPINGS") and getattr(module, "NODE_CLASS_MAPPINGS") is not None: - for name in module.NODE_CLASS_MAPPINGS: + for name, node_cls in module.NODE_CLASS_MAPPINGS.items(): if name not in ignore: - NODE_CLASS_MAPPINGS[name] = module.NODE_CLASS_MAPPINGS[name] + NODE_CLASS_MAPPINGS[name] = node_cls + node_cls.RELATIVE_PYTHON_MODULE = "{}.{}".format(module_parent, get_module_name(module_path)) if hasattr(module, "NODE_DISPLAY_NAME_MAPPINGS") and getattr(module, "NODE_DISPLAY_NAME_MAPPINGS") is not None: NODE_DISPLAY_NAME_MAPPINGS.update(module.NODE_DISPLAY_NAME_MAPPINGS) return True @@ -1925,7 +1951,16 @@ def load_custom_node(module_path, ignore=set()): logging.warning(f"Cannot import {module_path} module for custom nodes: {e}") return False -def load_custom_nodes(): +def init_external_custom_nodes(): + """ + Initializes the external custom nodes. + + This function loads custom nodes from the specified folder paths and imports them into the application. + It measures the import times for each custom node and logs the results. + + Returns: + None + """ base_node_names = set(NODE_CLASS_MAPPINGS.keys()) node_paths = folder_paths.get_folder_paths("custom_nodes") node_import_times = [] @@ -1939,7 +1974,7 @@ def load_custom_nodes(): if os.path.isfile(module_path) and os.path.splitext(module_path)[1] != ".py": continue if module_path.endswith(".disabled"): continue time_before = time.perf_counter() - success = load_custom_node(module_path, base_node_names) + success = load_custom_node(module_path, base_node_names, module_parent="custom_nodes") node_import_times.append((time.perf_counter() - time_before, module_path, success)) if len(node_import_times) > 0: @@ -1952,7 +1987,16 @@ def load_custom_nodes(): logging.info("{:6.1f} seconds{}: {}".format(n[0], import_message, n[1])) logging.info("") -def init_custom_nodes(): +def init_builtin_extra_nodes(): + """ + Initializes the built-in extra nodes in ComfyUI. + + This function loads the extra node files located in the "comfy_extras" directory and imports them into ComfyUI. + If any of the extra node files fail to import, a warning message is logged. + + Returns: + None + """ extras_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras") extras_files = [ "nodes_latent.py", @@ -1992,14 +2036,25 @@ def init_custom_nodes(): "nodes_audio.py", "nodes_sd3.py", "nodes_gits.py", + "nodes_controlnet.py", + "nodes_hunyuan.py", ] import_failed = [] for node_file in extras_files: - if not load_custom_node(os.path.join(extras_dir, node_file)): + if not load_custom_node(os.path.join(extras_dir, node_file), module_parent="comfy_extras"): import_failed.append(node_file) - load_custom_nodes() + return import_failed + + +def init_extra_nodes(init_custom_nodes=True): + import_failed = init_builtin_extra_nodes() + + if init_custom_nodes: + init_external_custom_nodes() + else: + logging.info("Skipping loading of custom nodes") if len(import_failed) > 0: logging.warning("WARNING: some comfy_extras/ nodes did not import correctly. This may be because they are missing some dependencies.\n") diff --git a/pytest.ini b/pytest.ini index b5a68e0f1..8b7a747e7 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,5 +1,8 @@ [pytest] markers = inference: mark as inference test (deselect with '-m "not inference"') -testpaths = tests -addopts = -s \ No newline at end of file +testpaths = + tests + tests-unit +addopts = -s +pythonpath = . diff --git a/requirements.txt b/requirements.txt index 108958d2f..4c2c0b2b2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,9 @@ torchsde torchvision torchaudio einops -transformers>=4.25.1 +transformers>=4.28.1 +tokenizers>=0.13.3 +sentencepiece safetensors>=0.4.2 aiohttp pyyaml diff --git a/server.py b/server.py index 30ea90c6c..23ca2fd33 100644 --- a/server.py +++ b/server.py @@ -12,6 +12,7 @@ import json import glob import struct import ssl +import hashlib from PIL import Image, ImageOps from PIL.PngImagePlugin import PngInfo from io import BytesIO @@ -24,9 +25,11 @@ import mimetypes from comfy.cli_args import args import comfy.utils import comfy.model_management - +import node_helpers +from app.frontend_management import FrontendManager from app.user_manager import UserManager + class BinaryEventTypes: PREVIEW_IMAGE = 1 UNENCODED_PREVIEW_IMAGE = 2 @@ -82,8 +85,12 @@ class PromptServer(): max_upload_size = round(args.max_upload_size * 1024 * 1024) self.app = web.Application(client_max_size=max_upload_size, middlewares=middlewares) self.sockets = dict() - self.web_root = os.path.join(os.path.dirname( - os.path.realpath(__file__)), "web") + self.web_root = ( + FrontendManager.init_frontend(args.front_end_version) + if args.front_end_root is None + else args.front_end_root + ) + logging.info(f"[Prompt Server] web root: {self.web_root}") routes = web.RouteTableDef() self.routes = routes self.last_node_id = None @@ -110,7 +117,7 @@ class PromptServer(): # On reconnect if we are the currently executing client send the current node if self.client_id == sid and self.last_node_id is not None: await self.send("executing", { "node": self.last_node_id }, sid) - + async for msg in ws: if msg.type == aiohttp.WSMsgType.ERROR: logging.warning('ws connection closed with exception %s' % ws.exception()) @@ -131,9 +138,9 @@ class PromptServer(): async def get_extensions(request): files = glob.glob(os.path.join( glob.escape(self.web_root), 'extensions/**/*.js'), recursive=True) - + extensions = list(map(lambda f: "/" + os.path.relpath(f, self.web_root).replace("\\", "/"), files)) - + for name, dir in nodes.EXTENSION_WEB_DIRS.items(): files = glob.glob(os.path.join(glob.escape(dir), '**/*.js'), recursive=True) extensions.extend(list(map(lambda f: "/extensions/" + urllib.parse.quote( @@ -154,9 +161,25 @@ class PromptServer(): return type_dir, dir_type + def compare_image_hash(filepath, image): + hasher = node_helpers.hasher() + + # function to compare hashes of two images to see if it already exists, fix to #3465 + if os.path.exists(filepath): + a = hasher() + b = hasher() + with open(filepath, "rb") as f: + a.update(f.read()) + b.update(image.file.read()) + image.file.seek(0) + f.close() + return a.hexdigest() == b.hexdigest() + return False + def image_upload(post, image_save_function=None): image = post.get("image") overwrite = post.get("overwrite") + image_is_duplicate = False image_upload_type = post.get("type") upload_dir, image_upload_type = get_dir_by_type(image_upload_type) @@ -183,15 +206,19 @@ class PromptServer(): else: i = 1 while os.path.exists(filepath): + if compare_image_hash(filepath, image): #compare hash to prevent saving of duplicates with same name, fix for #3465 + image_is_duplicate = True + break filename = f"{split[0]} ({i}){split[1]}" filepath = os.path.join(full_output_folder, filename) i += 1 - if image_save_function is not None: - image_save_function(image, post, filepath) - else: - with open(filepath, "wb") as f: - f.write(image.file.read()) + if not image_is_duplicate: + if image_save_function is not None: + image_save_function(image, post, filepath) + else: + with open(filepath, "wb") as f: + f.write(image.file.read()) return web.json_response({"name" : filename, "subfolder": subfolder, "type": image_upload_type}) else: @@ -397,6 +424,7 @@ class PromptServer(): info['name'] = node_class info['display_name'] = nodes.NODE_DISPLAY_NAME_MAPPINGS[node_class] if node_class in nodes.NODE_DISPLAY_NAME_MAPPINGS.keys() else node_class info['description'] = obj_class.DESCRIPTION if hasattr(obj_class,'DESCRIPTION') else '' + info['python_module'] = getattr(obj_class, "RELATIVE_PYTHON_MODULE", "nodes") info['category'] = 'sd' if hasattr(obj_class, 'OUTPUT_NODE') and obj_class.OUTPUT_NODE == True: info['output_node'] = True diff --git a/tests-ui/utils/setup.js b/tests-ui/utils/setup.js index e46258943..3a6d69b72 100644 --- a/tests-ui/utils/setup.js +++ b/tests-ui/utils/setup.js @@ -72,6 +72,7 @@ export function mockApi(config = {}) { storeUserData: jest.fn((file, data) => { userData[file] = data; }), + listUserData: jest.fn(() => []) }; jest.mock("../../web/scripts/api", () => ({ get api() { diff --git a/tests-unit/README.md b/tests-unit/README.md new file mode 100644 index 000000000..94abd9853 --- /dev/null +++ b/tests-unit/README.md @@ -0,0 +1,8 @@ +# Pytest Unit Tests + +## Install test dependencies + +`pip install -r tests-units/requirements.txt` + +## Run tests +`pytest tests-units/` diff --git a/tests-unit/app_test/__init__.py b/tests-unit/app_test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests-unit/app_test/frontend_manager_test.py b/tests-unit/app_test/frontend_manager_test.py new file mode 100644 index 000000000..637869cfb --- /dev/null +++ b/tests-unit/app_test/frontend_manager_test.py @@ -0,0 +1,100 @@ +import argparse +import pytest +from requests.exceptions import HTTPError + +from app.frontend_management import ( + FrontendManager, + FrontEndProvider, + Release, +) +from comfy.cli_args import DEFAULT_VERSION_STRING + + +@pytest.fixture +def mock_releases(): + return [ + Release( + id=1, + tag_name="1.0.0", + name="Release 1.0.0", + prerelease=False, + created_at="2022-01-01T00:00:00Z", + published_at="2022-01-01T00:00:00Z", + body="Release notes for 1.0.0", + assets=[{"name": "dist.zip", "url": "https://example.com/dist.zip"}], + ), + Release( + id=2, + tag_name="2.0.0", + name="Release 2.0.0", + prerelease=False, + created_at="2022-02-01T00:00:00Z", + published_at="2022-02-01T00:00:00Z", + body="Release notes for 2.0.0", + assets=[{"name": "dist.zip", "url": "https://example.com/dist.zip"}], + ), + ] + + +@pytest.fixture +def mock_provider(mock_releases): + provider = FrontEndProvider( + owner="test-owner", + repo="test-repo", + ) + provider.all_releases = mock_releases + provider.latest_release = mock_releases[1] + FrontendManager.PROVIDERS = [provider] + return provider + + +def test_get_release(mock_provider, mock_releases): + version = "1.0.0" + release = mock_provider.get_release(version) + assert release == mock_releases[0] + + +def test_get_release_latest(mock_provider, mock_releases): + version = "latest" + release = mock_provider.get_release(version) + assert release == mock_releases[1] + + +def test_get_release_invalid_version(mock_provider): + version = "invalid" + with pytest.raises(ValueError): + mock_provider.get_release(version) + + +def test_init_frontend_default(): + version_string = DEFAULT_VERSION_STRING + frontend_path = FrontendManager.init_frontend(version_string) + assert frontend_path == FrontendManager.DEFAULT_FRONTEND_PATH + + +def test_init_frontend_invalid_version(): + version_string = "test-owner/test-repo@1.100.99" + with pytest.raises(HTTPError): + FrontendManager.init_frontend_unsafe(version_string) + + +def test_init_frontend_invalid_provider(): + version_string = "invalid/invalid@latest" + with pytest.raises(HTTPError): + FrontendManager.init_frontend_unsafe(version_string) + + +def test_parse_version_string(): + version_string = "owner/repo@1.0.0" + repo_owner, repo_name, version = FrontendManager.parse_version_string( + version_string + ) + assert repo_owner == "owner" + assert repo_name == "repo" + assert version == "1.0.0" + + +def test_parse_version_string_invalid(): + version_string = "invalid" + with pytest.raises(argparse.ArgumentTypeError): + FrontendManager.parse_version_string(version_string) diff --git a/tests-unit/requirements.txt b/tests-unit/requirements.txt new file mode 100644 index 000000000..0587502f8 --- /dev/null +++ b/tests-unit/requirements.txt @@ -0,0 +1 @@ +pytest>=7.8.0 diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index 02546782f..245f3b93e 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -63,6 +63,10 @@ const colorPalettes = { "border-color": "#4e4e4e", "tr-even-bg-color": "#222", "tr-odd-bg-color": "#353535", + "content-bg": "#4e4e4e", + "content-fg": "#fff", + "content-hover-bg": "#222", + "content-hover-fg": "#fff" } }, }, @@ -120,6 +124,10 @@ const colorPalettes = { "border-color": "#888", "tr-even-bg-color": "#f9f9f9", "tr-odd-bg-color": "#fff", + "content-bg": "#e0e0e0", + "content-fg": "#222", + "content-hover-bg": "#adadad", + "content-hover-fg": "#222" } }, }, @@ -176,6 +184,10 @@ const colorPalettes = { "border-color": "#657b83", // Base00 "tr-even-bg-color": "#002b36", "tr-odd-bg-color": "#073642", + "content-bg": "#657b83", + "content-fg": "#fdf6e3", + "content-hover-bg": "#002b36", + "content-hover-fg": "#fdf6e3" } }, }, @@ -244,7 +256,11 @@ const colorPalettes = { "error-text": "#ff4444", "border-color": "#6e7581", "tr-even-bg-color": "#2b2f38", - "tr-odd-bg-color": "#242730" + "tr-odd-bg-color": "#242730", + "content-bg": "#6e7581", + "content-fg": "#fff", + "content-hover-bg": "#2b2f38", + "content-hover-fg": "#fff" } }, }, @@ -313,7 +329,11 @@ const colorPalettes = { "error-text": "#ff4444", "border-color": "#545d70", "tr-even-bg-color": "#2e3440", - "tr-odd-bg-color": "#161b22" + "tr-odd-bg-color": "#161b22", + "content-bg": "#545d70", + "content-fg": "#e5eaf0", + "content-hover-bg": "#2e3440", + "content-hover-fg": "#e5eaf0" } }, }, @@ -382,7 +402,11 @@ const colorPalettes = { "error-text": "#ff4444", "border-color": "#30363d", "tr-even-bg-color": "#161b22", - "tr-odd-bg-color": "#13171d" + "tr-odd-bg-color": "#13171d", + "content-bg": "#30363d", + "content-fg": "#e5eaf0", + "content-hover-bg": "#161b22", + "content-hover-fg": "#e5eaf0" } }, } diff --git a/web/extensions/core/groupNode.js b/web/extensions/core/groupNode.js index 0b0763d1d..9a2238908 100644 --- a/web/extensions/core/groupNode.js +++ b/web/extensions/core/groupNode.js @@ -1278,4 +1278,4 @@ const ext = { } }; -app.registerExtension(ext); +app.registerExtension(ext); \ No newline at end of file diff --git a/web/extensions/core/undoRedo.js b/web/extensions/core/undoRedo.js deleted file mode 100644 index 900eed2a7..000000000 --- a/web/extensions/core/undoRedo.js +++ /dev/null @@ -1,177 +0,0 @@ -import { app } from "../../scripts/app.js"; -import { api } from "../../scripts/api.js" - -const MAX_HISTORY = 50; - -let undo = []; -let redo = []; -let activeState = null; -let isOurLoad = false; -function checkState() { - const currentState = app.graph.serialize(); - if (!graphEqual(activeState, currentState)) { - undo.push(activeState); - if (undo.length > MAX_HISTORY) { - undo.shift(); - } - activeState = clone(currentState); - redo.length = 0; - api.dispatchEvent(new CustomEvent("graphChanged", { detail: activeState })); - } -} - -const loadGraphData = app.loadGraphData; -app.loadGraphData = async function () { - const v = await loadGraphData.apply(this, arguments); - if (isOurLoad) { - isOurLoad = false; - } else { - checkState(); - } - return v; -}; - -function clone(obj) { - try { - if (typeof structuredClone !== "undefined") { - return structuredClone(obj); - } - } catch (error) { - // structuredClone is stricter than using JSON.parse/stringify so fallback to that - } - - return JSON.parse(JSON.stringify(obj)); -} - -function graphEqual(a, b, root = true) { - if (a === b) return true; - - if (typeof a == "object" && a && typeof b == "object" && b) { - const keys = Object.getOwnPropertyNames(a); - - if (keys.length != Object.getOwnPropertyNames(b).length) { - return false; - } - - for (const key of keys) { - let av = a[key]; - let bv = b[key]; - if (root && key === "nodes") { - // Nodes need to be sorted as the order changes when selecting nodes - av = [...av].sort((a, b) => a.id - b.id); - bv = [...bv].sort((a, b) => a.id - b.id); - } - if (!graphEqual(av, bv, false)) { - return false; - } - } - - return true; - } - - return false; -} - -const undoRedo = async (e) => { - const updateState = async (source, target) => { - const prevState = source.pop(); - if (prevState) { - target.push(activeState); - isOurLoad = true; - await app.loadGraphData(prevState, false); - activeState = prevState; - } - } - if (e.ctrlKey || e.metaKey) { - if (e.key === "y") { - updateState(redo, undo); - return true; - } else if (e.key === "z") { - updateState(undo, redo); - return true; - } - } -}; - -const bindInput = (activeEl) => { - if (activeEl && activeEl.tagName !== "CANVAS" && activeEl.tagName !== "BODY") { - for (const evt of ["change", "input", "blur"]) { - if (`on${evt}` in activeEl) { - const listener = () => { - checkState(); - activeEl.removeEventListener(evt, listener); - }; - activeEl.addEventListener(evt, listener); - return true; - } - } - } -}; - -let keyIgnored = false; -window.addEventListener( - "keydown", - (e) => { - requestAnimationFrame(async () => { - let activeEl; - // If we are auto queue in change mode then we do want to trigger on inputs - if (!app.ui.autoQueueEnabled || app.ui.autoQueueMode === "instant") { - activeEl = document.activeElement; - if (activeEl?.tagName === "INPUT" || activeEl?.type === "textarea") { - // Ignore events on inputs, they have their native history - return; - } - } - - keyIgnored = e.key === "Control" || e.key === "Shift" || e.key === "Alt" || e.key === "Meta"; - if (keyIgnored) return; - - // Check if this is a ctrl+z ctrl+y - if (await undoRedo(e)) return; - - // If our active element is some type of input then handle changes after they're done - if (bindInput(activeEl)) return; - checkState(); - }); - }, - true -); - -window.addEventListener("keyup", (e) => { - if (keyIgnored) { - keyIgnored = false; - checkState(); - } -}); - -// Handle clicking DOM elements (e.g. widgets) -window.addEventListener("mouseup", () => { - checkState(); -}); - -// Handle prompt queue event for dynamic widget changes -api.addEventListener("promptQueued", () => { - checkState(); -}); - -// Handle litegraph clicks -const processMouseUp = LGraphCanvas.prototype.processMouseUp; -LGraphCanvas.prototype.processMouseUp = function (e) { - const v = processMouseUp.apply(this, arguments); - checkState(); - return v; -}; -const processMouseDown = LGraphCanvas.prototype.processMouseDown; -LGraphCanvas.prototype.processMouseDown = function (e) { - const v = processMouseDown.apply(this, arguments); - checkState(); - return v; -}; - -// Handle litegraph context menu for COMBO widgets -const close = LiteGraph.ContextMenu.prototype.close; -LiteGraph.ContextMenu.prototype.close = function(e) { - const v = close.apply(this, arguments); - checkState(); - return v; -} \ No newline at end of file diff --git a/web/extensions/core/uploadAudio.js b/web/extensions/core/uploadAudio.js new file mode 100644 index 000000000..9dfa029bf --- /dev/null +++ b/web/extensions/core/uploadAudio.js @@ -0,0 +1,186 @@ +import { app } from "../../scripts/app.js" +import { api } from "../../scripts/api.js" + +function splitFilePath(path) { + const folder_separator = path.lastIndexOf("/") + if (folder_separator === -1) { + return ["", path] + } + return [ + path.substring(0, folder_separator), + path.substring(folder_separator + 1) + ] +} + +function getResourceURL(subfolder, filename, type = "input") { + const params = [ + "filename=" + encodeURIComponent(filename), + "type=" + type, + "subfolder=" + subfolder, + app.getRandParam().substring(1) + ].join("&") + + return `/view?${params}` +} + +async function uploadFile( + audioWidget, + audioUIWidget, + file, + updateNode, + pasted = false +) { + try { + // Wrap file in formdata so it includes filename + const body = new FormData() + body.append("image", file) + if (pasted) body.append("subfolder", "pasted") + const resp = await api.fetchApi("/upload/image", { + method: "POST", + body + }) + + if (resp.status === 200) { + const data = await resp.json() + // Add the file to the dropdown list and update the widget value + let path = data.name + if (data.subfolder) path = data.subfolder + "/" + path + + if (!audioWidget.options.values.includes(path)) { + audioWidget.options.values.push(path) + } + + if (updateNode) { + audioUIWidget.element.src = api.apiURL( + getResourceURL(...splitFilePath(path)) + ) + audioWidget.value = path + } + } else { + alert(resp.status + " - " + resp.statusText) + } + } catch (error) { + alert(error) + } +} + +// AudioWidget MUST be registered first, as AUDIOUPLOAD depends on AUDIO_UI to be +// present. +app.registerExtension({ + name: "Comfy.AudioWidget", + async beforeRegisterNodeDef(nodeType, nodeData) { + if (["LoadAudio", "SaveAudio", "PreviewAudio"].includes(nodeType.comfyClass)) { + nodeData.input.required.audioUI = ["AUDIO_UI"] + } + }, + getCustomWidgets() { + return { + AUDIO_UI(node, inputName) { + const audio = document.createElement("audio") + audio.controls = true + audio.classList.add("comfy-audio") + audio.setAttribute("name", "media") + + const audioUIWidget = node.addDOMWidget( + inputName, + /* name=*/ "audioUI", + audio + ) + // @ts-ignore + // TODO: Sort out the DOMWidget type. + audioUIWidget.serialize = false + + const isOutputNode = node.constructor.nodeData.output_node + if (isOutputNode) { + // Hide the audio widget when there is no audio initially. + audioUIWidget.element.classList.add("empty-audio-widget") + // Populate the audio widget UI on node execution. + const onExecuted = node.onExecuted + node.onExecuted = function(message) { + onExecuted?.apply(this, arguments) + const audios = message.audio + if (!audios) return + const audio = audios[0] + audioUIWidget.element.src = api.apiURL( + getResourceURL(audio.subfolder, audio.filename, audio.type) + ) + audioUIWidget.element.classList.remove("empty-audio-widget") + } + } + return { widget: audioUIWidget } + } + } + }, + onNodeOutputsUpdated(nodeOutputs) { + for (const [nodeId, output] of Object.entries(nodeOutputs)) { + const node = app.graph.getNodeById(Number.parseInt(nodeId)); + if ("audio" in output) { + const audioUIWidget = node.widgets.find((w) => w.name === "audioUI"); + const audio = output.audio[0]; + audioUIWidget.element.src = api.apiURL(getResourceURL(audio.subfolder, audio.filename, audio.type)); + audioUIWidget.element.classList.remove("empty-audio-widget"); + } + } + }, +}) + +app.registerExtension({ + name: "Comfy.UploadAudio", + async beforeRegisterNodeDef(nodeType, nodeData) { + if (nodeData?.input?.required?.audio?.[1]?.audio_upload === true) { + nodeData.input.required.upload = ["AUDIOUPLOAD"] + } + }, + getCustomWidgets() { + return { + AUDIOUPLOAD(node, inputName) { + // The widget that allows user to select file. + const audioWidget = node.widgets.find(w => w.name === "audio") + const audioUIWidget = node.widgets.find(w => w.name === "audioUI") + + const onAudioWidgetUpdate = () => { + audioUIWidget.element.src = api.apiURL( + getResourceURL(...splitFilePath(audioWidget.value)) + ) + } + // Initially load default audio file to audioUIWidget. + if (audioWidget.value) { + onAudioWidgetUpdate() + } + audioWidget.callback = onAudioWidgetUpdate + + // Load saved audio file widget values if restoring from workflow + const onGraphConfigured = node.onGraphConfigured; + node.onGraphConfigured = function() { + onGraphConfigured?.apply(this, arguments) + if (audioWidget.value) { + onAudioWidgetUpdate() + } + } + + const fileInput = document.createElement("input") + fileInput.type = "file" + fileInput.accept = "audio/*" + fileInput.style.display = "none" + fileInput.onchange = () => { + if (fileInput.files.length) { + uploadFile(audioWidget, audioUIWidget, fileInput.files[0], true) + } + } + // The widget to pop up the upload dialog. + const uploadWidget = node.addWidget( + "button", + inputName, + /* value=*/ "", + () => { + fileInput.click() + } + ) + uploadWidget.label = "choose file to upload" + uploadWidget.serialize = false + + return { widget: uploadWidget } + } + } + } +}) diff --git a/web/fonts/materialdesignicons-webfont.woff2 b/web/fonts/materialdesignicons-webfont.woff2 new file mode 100644 index 000000000..8c69b85f6 Binary files /dev/null and b/web/fonts/materialdesignicons-webfont.woff2 differ diff --git a/web/index.html b/web/index.html index 094db9d15..5ebf03c01 100644 --- a/web/index.html +++ b/web/index.html @@ -5,6 +5,7 @@ ComfyUI + diff --git a/web/jsconfig.json b/web/jsconfig.json index b65fa2746..cd55a0cc7 100644 --- a/web/jsconfig.json +++ b/web/jsconfig.json @@ -4,7 +4,9 @@ "paths": { "/*": ["./*"] }, - "lib": ["DOM", "ES2022"] + "lib": ["DOM", "ES2022", "DOM.Iterable"], + "target": "ES2015", + "module": "es2020" }, "include": ["."] } diff --git a/web/lib/materialdesignicons.min.css b/web/lib/materialdesignicons.min.css new file mode 100644 index 000000000..459ce9ea8 --- /dev/null +++ b/web/lib/materialdesignicons.min.css @@ -0,0 +1,3 @@ +@font-face{font-family:"Material Design Icons";src:url("../fonts/materialdesignicons-webfont.eot?v=7.4.47");src:url("../fonts/materialdesignicons-webfont.eot?#iefix&v=7.4.47") format("embedded-opentype"),url("../fonts/materialdesignicons-webfont.woff2?v=7.4.47") format("woff2"),url("../fonts/materialdesignicons-webfont.woff?v=7.4.47") format("woff"),url("../fonts/materialdesignicons-webfont.ttf?v=7.4.47") format("truetype");font-weight:normal;font-style:normal}.mdi:before,.mdi-set{display:inline-block;font:normal normal normal 24px/1 "Material Design Icons";font-size:inherit;text-rendering:auto;line-height:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.mdi-ab-testing::before{content:"\F01C9"}.mdi-abacus::before{content:"\F16E0"}.mdi-abjad-arabic::before{content:"\F1328"}.mdi-abjad-hebrew::before{content:"\F1329"}.mdi-abugida-devanagari::before{content:"\F132A"}.mdi-abugida-thai::before{content:"\F132B"}.mdi-access-point::before{content:"\F0003"}.mdi-access-point-check::before{content:"\F1538"}.mdi-access-point-minus::before{content:"\F1539"}.mdi-access-point-network::before{content:"\F0002"}.mdi-access-point-network-off::before{content:"\F0BE1"}.mdi-access-point-off::before{content:"\F1511"}.mdi-access-point-plus::before{content:"\F153A"}.mdi-access-point-remove::before{content:"\F153B"}.mdi-account::before{content:"\F0004"}.mdi-account-alert::before{content:"\F0005"}.mdi-account-alert-outline::before{content:"\F0B50"}.mdi-account-arrow-down::before{content:"\F1868"}.mdi-account-arrow-down-outline::before{content:"\F1869"}.mdi-account-arrow-left::before{content:"\F0B51"}.mdi-account-arrow-left-outline::before{content:"\F0B52"}.mdi-account-arrow-right::before{content:"\F0B53"}.mdi-account-arrow-right-outline::before{content:"\F0B54"}.mdi-account-arrow-up::before{content:"\F1867"}.mdi-account-arrow-up-outline::before{content:"\F186A"}.mdi-account-badge::before{content:"\F1B0A"}.mdi-account-badge-outline::before{content:"\F1B0B"}.mdi-account-box::before{content:"\F0006"}.mdi-account-box-edit-outline::before{content:"\F1CC8"}.mdi-account-box-minus-outline::before{content:"\F1CC9"}.mdi-account-box-multiple::before{content:"\F0934"}.mdi-account-box-multiple-outline::before{content:"\F100A"}.mdi-account-box-outline::before{content:"\F0007"}.mdi-account-box-plus-outline::before{content:"\F1CCA"}.mdi-account-cancel::before{content:"\F12DF"}.mdi-account-cancel-outline::before{content:"\F12E0"}.mdi-account-card::before{content:"\F1BA4"}.mdi-account-card-outline::before{content:"\F1BA5"}.mdi-account-cash::before{content:"\F1097"}.mdi-account-cash-outline::before{content:"\F1098"}.mdi-account-check::before{content:"\F0008"}.mdi-account-check-outline::before{content:"\F0BE2"}.mdi-account-child::before{content:"\F0A89"}.mdi-account-child-circle::before{content:"\F0A8A"}.mdi-account-child-outline::before{content:"\F10C8"}.mdi-account-circle::before{content:"\F0009"}.mdi-account-circle-outline::before{content:"\F0B55"}.mdi-account-clock::before{content:"\F0B56"}.mdi-account-clock-outline::before{content:"\F0B57"}.mdi-account-cog::before{content:"\F1370"}.mdi-account-cog-outline::before{content:"\F1371"}.mdi-account-convert::before{content:"\F000A"}.mdi-account-convert-outline::before{content:"\F1301"}.mdi-account-cowboy-hat::before{content:"\F0E9B"}.mdi-account-cowboy-hat-outline::before{content:"\F17F3"}.mdi-account-credit-card::before{content:"\F1BA6"}.mdi-account-credit-card-outline::before{content:"\F1BA7"}.mdi-account-details::before{content:"\F0631"}.mdi-account-details-outline::before{content:"\F1372"}.mdi-account-edit::before{content:"\F06BC"}.mdi-account-edit-outline::before{content:"\F0FFB"}.mdi-account-eye::before{content:"\F0420"}.mdi-account-eye-outline::before{content:"\F127B"}.mdi-account-file::before{content:"\F1CA7"}.mdi-account-file-outline::before{content:"\F1CA8"}.mdi-account-file-text::before{content:"\F1CA9"}.mdi-account-file-text-outline::before{content:"\F1CAA"}.mdi-account-filter::before{content:"\F0936"}.mdi-account-filter-outline::before{content:"\F0F9D"}.mdi-account-group::before{content:"\F0849"}.mdi-account-group-outline::before{content:"\F0B58"}.mdi-account-hard-hat::before{content:"\F05B5"}.mdi-account-hard-hat-outline::before{content:"\F1A1F"}.mdi-account-heart::before{content:"\F0899"}.mdi-account-heart-outline::before{content:"\F0BE3"}.mdi-account-injury::before{content:"\F1815"}.mdi-account-injury-outline::before{content:"\F1816"}.mdi-account-key::before{content:"\F000B"}.mdi-account-key-outline::before{content:"\F0BE4"}.mdi-account-lock::before{content:"\F115E"}.mdi-account-lock-open::before{content:"\F1960"}.mdi-account-lock-open-outline::before{content:"\F1961"}.mdi-account-lock-outline::before{content:"\F115F"}.mdi-account-minus::before{content:"\F000D"}.mdi-account-minus-outline::before{content:"\F0AEC"}.mdi-account-multiple::before{content:"\F000E"}.mdi-account-multiple-check::before{content:"\F08C5"}.mdi-account-multiple-check-outline::before{content:"\F11FE"}.mdi-account-multiple-minus::before{content:"\F05D3"}.mdi-account-multiple-minus-outline::before{content:"\F0BE5"}.mdi-account-multiple-outline::before{content:"\F000F"}.mdi-account-multiple-plus::before{content:"\F0010"}.mdi-account-multiple-plus-outline::before{content:"\F0800"}.mdi-account-multiple-remove::before{content:"\F120A"}.mdi-account-multiple-remove-outline::before{content:"\F120B"}.mdi-account-music::before{content:"\F0803"}.mdi-account-music-outline::before{content:"\F0CE9"}.mdi-account-network::before{content:"\F0011"}.mdi-account-network-off::before{content:"\F1AF1"}.mdi-account-network-off-outline::before{content:"\F1AF2"}.mdi-account-network-outline::before{content:"\F0BE6"}.mdi-account-off::before{content:"\F0012"}.mdi-account-off-outline::before{content:"\F0BE7"}.mdi-account-outline::before{content:"\F0013"}.mdi-account-plus::before{content:"\F0014"}.mdi-account-plus-outline::before{content:"\F0801"}.mdi-account-question::before{content:"\F0B59"}.mdi-account-question-outline::before{content:"\F0B5A"}.mdi-account-reactivate::before{content:"\F152B"}.mdi-account-reactivate-outline::before{content:"\F152C"}.mdi-account-remove::before{content:"\F0015"}.mdi-account-remove-outline::before{content:"\F0AED"}.mdi-account-school::before{content:"\F1A20"}.mdi-account-school-outline::before{content:"\F1A21"}.mdi-account-search::before{content:"\F0016"}.mdi-account-search-outline::before{content:"\F0935"}.mdi-account-settings::before{content:"\F0630"}.mdi-account-settings-outline::before{content:"\F10C9"}.mdi-account-star::before{content:"\F0017"}.mdi-account-star-outline::before{content:"\F0BE8"}.mdi-account-supervisor::before{content:"\F0A8B"}.mdi-account-supervisor-circle::before{content:"\F0A8C"}.mdi-account-supervisor-circle-outline::before{content:"\F14EC"}.mdi-account-supervisor-outline::before{content:"\F112D"}.mdi-account-switch::before{content:"\F0019"}.mdi-account-switch-outline::before{content:"\F04CB"}.mdi-account-sync::before{content:"\F191B"}.mdi-account-sync-outline::before{content:"\F191C"}.mdi-account-tag::before{content:"\F1C1B"}.mdi-account-tag-outline::before{content:"\F1C1C"}.mdi-account-tie::before{content:"\F0CE3"}.mdi-account-tie-hat::before{content:"\F1898"}.mdi-account-tie-hat-outline::before{content:"\F1899"}.mdi-account-tie-outline::before{content:"\F10CA"}.mdi-account-tie-voice::before{content:"\F1308"}.mdi-account-tie-voice-off::before{content:"\F130A"}.mdi-account-tie-voice-off-outline::before{content:"\F130B"}.mdi-account-tie-voice-outline::before{content:"\F1309"}.mdi-account-tie-woman::before{content:"\F1A8C"}.mdi-account-voice::before{content:"\F05CB"}.mdi-account-voice-off::before{content:"\F0ED4"}.mdi-account-wrench::before{content:"\F189A"}.mdi-account-wrench-outline::before{content:"\F189B"}.mdi-adjust::before{content:"\F001A"}.mdi-advertisements::before{content:"\F192A"}.mdi-advertisements-off::before{content:"\F192B"}.mdi-air-conditioner::before{content:"\F001B"}.mdi-air-filter::before{content:"\F0D43"}.mdi-air-horn::before{content:"\F0DAC"}.mdi-air-humidifier::before{content:"\F1099"}.mdi-air-humidifier-off::before{content:"\F1466"}.mdi-air-purifier::before{content:"\F0D44"}.mdi-air-purifier-off::before{content:"\F1B57"}.mdi-airbag::before{content:"\F0BE9"}.mdi-airballoon::before{content:"\F001C"}.mdi-airballoon-outline::before{content:"\F100B"}.mdi-airplane::before{content:"\F001D"}.mdi-airplane-alert::before{content:"\F187A"}.mdi-airplane-check::before{content:"\F187B"}.mdi-airplane-clock::before{content:"\F187C"}.mdi-airplane-cog::before{content:"\F187D"}.mdi-airplane-edit::before{content:"\F187E"}.mdi-airplane-landing::before{content:"\F05D4"}.mdi-airplane-marker::before{content:"\F187F"}.mdi-airplane-minus::before{content:"\F1880"}.mdi-airplane-off::before{content:"\F001E"}.mdi-airplane-plus::before{content:"\F1881"}.mdi-airplane-remove::before{content:"\F1882"}.mdi-airplane-search::before{content:"\F1883"}.mdi-airplane-settings::before{content:"\F1884"}.mdi-airplane-takeoff::before{content:"\F05D5"}.mdi-airport::before{content:"\F084B"}.mdi-alarm::before{content:"\F0020"}.mdi-alarm-bell::before{content:"\F078E"}.mdi-alarm-check::before{content:"\F0021"}.mdi-alarm-light::before{content:"\F078F"}.mdi-alarm-light-off::before{content:"\F171E"}.mdi-alarm-light-off-outline::before{content:"\F171F"}.mdi-alarm-light-outline::before{content:"\F0BEA"}.mdi-alarm-multiple::before{content:"\F0022"}.mdi-alarm-note::before{content:"\F0E71"}.mdi-alarm-note-off::before{content:"\F0E72"}.mdi-alarm-off::before{content:"\F0023"}.mdi-alarm-panel::before{content:"\F15C4"}.mdi-alarm-panel-outline::before{content:"\F15C5"}.mdi-alarm-plus::before{content:"\F0024"}.mdi-alarm-snooze::before{content:"\F068E"}.mdi-album::before{content:"\F0025"}.mdi-alert::before{content:"\F0026"}.mdi-alert-box::before{content:"\F0027"}.mdi-alert-box-outline::before{content:"\F0CE4"}.mdi-alert-circle::before{content:"\F0028"}.mdi-alert-circle-check::before{content:"\F11ED"}.mdi-alert-circle-check-outline::before{content:"\F11EE"}.mdi-alert-circle-outline::before{content:"\F05D6"}.mdi-alert-decagram::before{content:"\F06BD"}.mdi-alert-decagram-outline::before{content:"\F0CE5"}.mdi-alert-minus::before{content:"\F14BB"}.mdi-alert-minus-outline::before{content:"\F14BE"}.mdi-alert-octagon::before{content:"\F0029"}.mdi-alert-octagon-outline::before{content:"\F0CE6"}.mdi-alert-octagram::before{content:"\F0767"}.mdi-alert-octagram-outline::before{content:"\F0CE7"}.mdi-alert-outline::before{content:"\F002A"}.mdi-alert-plus::before{content:"\F14BA"}.mdi-alert-plus-outline::before{content:"\F14BD"}.mdi-alert-remove::before{content:"\F14BC"}.mdi-alert-remove-outline::before{content:"\F14BF"}.mdi-alert-rhombus::before{content:"\F11CE"}.mdi-alert-rhombus-outline::before{content:"\F11CF"}.mdi-alien::before{content:"\F089A"}.mdi-alien-outline::before{content:"\F10CB"}.mdi-align-horizontal-center::before{content:"\F11C3"}.mdi-align-horizontal-distribute::before{content:"\F1962"}.mdi-align-horizontal-left::before{content:"\F11C2"}.mdi-align-horizontal-right::before{content:"\F11C4"}.mdi-align-vertical-bottom::before{content:"\F11C5"}.mdi-align-vertical-center::before{content:"\F11C6"}.mdi-align-vertical-distribute::before{content:"\F1963"}.mdi-align-vertical-top::before{content:"\F11C7"}.mdi-all-inclusive::before{content:"\F06BE"}.mdi-all-inclusive-box::before{content:"\F188D"}.mdi-all-inclusive-box-outline::before{content:"\F188E"}.mdi-allergy::before{content:"\F1258"}.mdi-alpha::before{content:"\F002B"}.mdi-alpha-a::before{content:"\F0AEE"}.mdi-alpha-a-box::before{content:"\F0B08"}.mdi-alpha-a-box-outline::before{content:"\F0BEB"}.mdi-alpha-a-circle::before{content:"\F0BEC"}.mdi-alpha-a-circle-outline::before{content:"\F0BED"}.mdi-alpha-b::before{content:"\F0AEF"}.mdi-alpha-b-box::before{content:"\F0B09"}.mdi-alpha-b-box-outline::before{content:"\F0BEE"}.mdi-alpha-b-circle::before{content:"\F0BEF"}.mdi-alpha-b-circle-outline::before{content:"\F0BF0"}.mdi-alpha-c::before{content:"\F0AF0"}.mdi-alpha-c-box::before{content:"\F0B0A"}.mdi-alpha-c-box-outline::before{content:"\F0BF1"}.mdi-alpha-c-circle::before{content:"\F0BF2"}.mdi-alpha-c-circle-outline::before{content:"\F0BF3"}.mdi-alpha-d::before{content:"\F0AF1"}.mdi-alpha-d-box::before{content:"\F0B0B"}.mdi-alpha-d-box-outline::before{content:"\F0BF4"}.mdi-alpha-d-circle::before{content:"\F0BF5"}.mdi-alpha-d-circle-outline::before{content:"\F0BF6"}.mdi-alpha-e::before{content:"\F0AF2"}.mdi-alpha-e-box::before{content:"\F0B0C"}.mdi-alpha-e-box-outline::before{content:"\F0BF7"}.mdi-alpha-e-circle::before{content:"\F0BF8"}.mdi-alpha-e-circle-outline::before{content:"\F0BF9"}.mdi-alpha-f::before{content:"\F0AF3"}.mdi-alpha-f-box::before{content:"\F0B0D"}.mdi-alpha-f-box-outline::before{content:"\F0BFA"}.mdi-alpha-f-circle::before{content:"\F0BFB"}.mdi-alpha-f-circle-outline::before{content:"\F0BFC"}.mdi-alpha-g::before{content:"\F0AF4"}.mdi-alpha-g-box::before{content:"\F0B0E"}.mdi-alpha-g-box-outline::before{content:"\F0BFD"}.mdi-alpha-g-circle::before{content:"\F0BFE"}.mdi-alpha-g-circle-outline::before{content:"\F0BFF"}.mdi-alpha-h::before{content:"\F0AF5"}.mdi-alpha-h-box::before{content:"\F0B0F"}.mdi-alpha-h-box-outline::before{content:"\F0C00"}.mdi-alpha-h-circle::before{content:"\F0C01"}.mdi-alpha-h-circle-outline::before{content:"\F0C02"}.mdi-alpha-i::before{content:"\F0AF6"}.mdi-alpha-i-box::before{content:"\F0B10"}.mdi-alpha-i-box-outline::before{content:"\F0C03"}.mdi-alpha-i-circle::before{content:"\F0C04"}.mdi-alpha-i-circle-outline::before{content:"\F0C05"}.mdi-alpha-j::before{content:"\F0AF7"}.mdi-alpha-j-box::before{content:"\F0B11"}.mdi-alpha-j-box-outline::before{content:"\F0C06"}.mdi-alpha-j-circle::before{content:"\F0C07"}.mdi-alpha-j-circle-outline::before{content:"\F0C08"}.mdi-alpha-k::before{content:"\F0AF8"}.mdi-alpha-k-box::before{content:"\F0B12"}.mdi-alpha-k-box-outline::before{content:"\F0C09"}.mdi-alpha-k-circle::before{content:"\F0C0A"}.mdi-alpha-k-circle-outline::before{content:"\F0C0B"}.mdi-alpha-l::before{content:"\F0AF9"}.mdi-alpha-l-box::before{content:"\F0B13"}.mdi-alpha-l-box-outline::before{content:"\F0C0C"}.mdi-alpha-l-circle::before{content:"\F0C0D"}.mdi-alpha-l-circle-outline::before{content:"\F0C0E"}.mdi-alpha-m::before{content:"\F0AFA"}.mdi-alpha-m-box::before{content:"\F0B14"}.mdi-alpha-m-box-outline::before{content:"\F0C0F"}.mdi-alpha-m-circle::before{content:"\F0C10"}.mdi-alpha-m-circle-outline::before{content:"\F0C11"}.mdi-alpha-n::before{content:"\F0AFB"}.mdi-alpha-n-box::before{content:"\F0B15"}.mdi-alpha-n-box-outline::before{content:"\F0C12"}.mdi-alpha-n-circle::before{content:"\F0C13"}.mdi-alpha-n-circle-outline::before{content:"\F0C14"}.mdi-alpha-o::before{content:"\F0AFC"}.mdi-alpha-o-box::before{content:"\F0B16"}.mdi-alpha-o-box-outline::before{content:"\F0C15"}.mdi-alpha-o-circle::before{content:"\F0C16"}.mdi-alpha-o-circle-outline::before{content:"\F0C17"}.mdi-alpha-p::before{content:"\F0AFD"}.mdi-alpha-p-box::before{content:"\F0B17"}.mdi-alpha-p-box-outline::before{content:"\F0C18"}.mdi-alpha-p-circle::before{content:"\F0C19"}.mdi-alpha-p-circle-outline::before{content:"\F0C1A"}.mdi-alpha-q::before{content:"\F0AFE"}.mdi-alpha-q-box::before{content:"\F0B18"}.mdi-alpha-q-box-outline::before{content:"\F0C1B"}.mdi-alpha-q-circle::before{content:"\F0C1C"}.mdi-alpha-q-circle-outline::before{content:"\F0C1D"}.mdi-alpha-r::before{content:"\F0AFF"}.mdi-alpha-r-box::before{content:"\F0B19"}.mdi-alpha-r-box-outline::before{content:"\F0C1E"}.mdi-alpha-r-circle::before{content:"\F0C1F"}.mdi-alpha-r-circle-outline::before{content:"\F0C20"}.mdi-alpha-s::before{content:"\F0B00"}.mdi-alpha-s-box::before{content:"\F0B1A"}.mdi-alpha-s-box-outline::before{content:"\F0C21"}.mdi-alpha-s-circle::before{content:"\F0C22"}.mdi-alpha-s-circle-outline::before{content:"\F0C23"}.mdi-alpha-t::before{content:"\F0B01"}.mdi-alpha-t-box::before{content:"\F0B1B"}.mdi-alpha-t-box-outline::before{content:"\F0C24"}.mdi-alpha-t-circle::before{content:"\F0C25"}.mdi-alpha-t-circle-outline::before{content:"\F0C26"}.mdi-alpha-u::before{content:"\F0B02"}.mdi-alpha-u-box::before{content:"\F0B1C"}.mdi-alpha-u-box-outline::before{content:"\F0C27"}.mdi-alpha-u-circle::before{content:"\F0C28"}.mdi-alpha-u-circle-outline::before{content:"\F0C29"}.mdi-alpha-v::before{content:"\F0B03"}.mdi-alpha-v-box::before{content:"\F0B1D"}.mdi-alpha-v-box-outline::before{content:"\F0C2A"}.mdi-alpha-v-circle::before{content:"\F0C2B"}.mdi-alpha-v-circle-outline::before{content:"\F0C2C"}.mdi-alpha-w::before{content:"\F0B04"}.mdi-alpha-w-box::before{content:"\F0B1E"}.mdi-alpha-w-box-outline::before{content:"\F0C2D"}.mdi-alpha-w-circle::before{content:"\F0C2E"}.mdi-alpha-w-circle-outline::before{content:"\F0C2F"}.mdi-alpha-x::before{content:"\F0B05"}.mdi-alpha-x-box::before{content:"\F0B1F"}.mdi-alpha-x-box-outline::before{content:"\F0C30"}.mdi-alpha-x-circle::before{content:"\F0C31"}.mdi-alpha-x-circle-outline::before{content:"\F0C32"}.mdi-alpha-y::before{content:"\F0B06"}.mdi-alpha-y-box::before{content:"\F0B20"}.mdi-alpha-y-box-outline::before{content:"\F0C33"}.mdi-alpha-y-circle::before{content:"\F0C34"}.mdi-alpha-y-circle-outline::before{content:"\F0C35"}.mdi-alpha-z::before{content:"\F0B07"}.mdi-alpha-z-box::before{content:"\F0B21"}.mdi-alpha-z-box-outline::before{content:"\F0C36"}.mdi-alpha-z-circle::before{content:"\F0C37"}.mdi-alpha-z-circle-outline::before{content:"\F0C38"}.mdi-alphabet-aurebesh::before{content:"\F132C"}.mdi-alphabet-cyrillic::before{content:"\F132D"}.mdi-alphabet-greek::before{content:"\F132E"}.mdi-alphabet-latin::before{content:"\F132F"}.mdi-alphabet-piqad::before{content:"\F1330"}.mdi-alphabet-tengwar::before{content:"\F1337"}.mdi-alphabetical::before{content:"\F002C"}.mdi-alphabetical-off::before{content:"\F100C"}.mdi-alphabetical-variant::before{content:"\F100D"}.mdi-alphabetical-variant-off::before{content:"\F100E"}.mdi-altimeter::before{content:"\F05D7"}.mdi-ambulance::before{content:"\F002F"}.mdi-ammunition::before{content:"\F0CE8"}.mdi-ampersand::before{content:"\F0A8D"}.mdi-amplifier::before{content:"\F0030"}.mdi-amplifier-off::before{content:"\F11B5"}.mdi-anchor::before{content:"\F0031"}.mdi-android::before{content:"\F0032"}.mdi-android-studio::before{content:"\F0034"}.mdi-angle-acute::before{content:"\F0937"}.mdi-angle-obtuse::before{content:"\F0938"}.mdi-angle-right::before{content:"\F0939"}.mdi-angular::before{content:"\F06B2"}.mdi-angularjs::before{content:"\F06BF"}.mdi-animation::before{content:"\F05D8"}.mdi-animation-outline::before{content:"\F0A8F"}.mdi-animation-play::before{content:"\F093A"}.mdi-animation-play-outline::before{content:"\F0A90"}.mdi-ansible::before{content:"\F109A"}.mdi-antenna::before{content:"\F1119"}.mdi-anvil::before{content:"\F089B"}.mdi-apache-kafka::before{content:"\F100F"}.mdi-api::before{content:"\F109B"}.mdi-api-off::before{content:"\F1257"}.mdi-apple::before{content:"\F0035"}.mdi-apple-finder::before{content:"\F0036"}.mdi-apple-icloud::before{content:"\F0038"}.mdi-apple-ios::before{content:"\F0037"}.mdi-apple-keyboard-caps::before{content:"\F0632"}.mdi-apple-keyboard-command::before{content:"\F0633"}.mdi-apple-keyboard-control::before{content:"\F0634"}.mdi-apple-keyboard-option::before{content:"\F0635"}.mdi-apple-keyboard-shift::before{content:"\F0636"}.mdi-apple-safari::before{content:"\F0039"}.mdi-application::before{content:"\F08C6"}.mdi-application-array::before{content:"\F10F5"}.mdi-application-array-outline::before{content:"\F10F6"}.mdi-application-braces::before{content:"\F10F7"}.mdi-application-braces-outline::before{content:"\F10F8"}.mdi-application-brackets::before{content:"\F0C8B"}.mdi-application-brackets-outline::before{content:"\F0C8C"}.mdi-application-cog::before{content:"\F0675"}.mdi-application-cog-outline::before{content:"\F1577"}.mdi-application-edit::before{content:"\F00AE"}.mdi-application-edit-outline::before{content:"\F0619"}.mdi-application-export::before{content:"\F0DAD"}.mdi-application-import::before{content:"\F0DAE"}.mdi-application-outline::before{content:"\F0614"}.mdi-application-parentheses::before{content:"\F10F9"}.mdi-application-parentheses-outline::before{content:"\F10FA"}.mdi-application-settings::before{content:"\F0B60"}.mdi-application-settings-outline::before{content:"\F1555"}.mdi-application-variable::before{content:"\F10FB"}.mdi-application-variable-outline::before{content:"\F10FC"}.mdi-approximately-equal::before{content:"\F0F9E"}.mdi-approximately-equal-box::before{content:"\F0F9F"}.mdi-apps::before{content:"\F003B"}.mdi-apps-box::before{content:"\F0D46"}.mdi-arch::before{content:"\F08C7"}.mdi-archive::before{content:"\F003C"}.mdi-archive-alert::before{content:"\F14FD"}.mdi-archive-alert-outline::before{content:"\F14FE"}.mdi-archive-arrow-down::before{content:"\F1259"}.mdi-archive-arrow-down-outline::before{content:"\F125A"}.mdi-archive-arrow-up::before{content:"\F125B"}.mdi-archive-arrow-up-outline::before{content:"\F125C"}.mdi-archive-cancel::before{content:"\F174B"}.mdi-archive-cancel-outline::before{content:"\F174C"}.mdi-archive-check::before{content:"\F174D"}.mdi-archive-check-outline::before{content:"\F174E"}.mdi-archive-clock::before{content:"\F174F"}.mdi-archive-clock-outline::before{content:"\F1750"}.mdi-archive-cog::before{content:"\F1751"}.mdi-archive-cog-outline::before{content:"\F1752"}.mdi-archive-edit::before{content:"\F1753"}.mdi-archive-edit-outline::before{content:"\F1754"}.mdi-archive-eye::before{content:"\F1755"}.mdi-archive-eye-outline::before{content:"\F1756"}.mdi-archive-lock::before{content:"\F1757"}.mdi-archive-lock-open::before{content:"\F1758"}.mdi-archive-lock-open-outline::before{content:"\F1759"}.mdi-archive-lock-outline::before{content:"\F175A"}.mdi-archive-marker::before{content:"\F175B"}.mdi-archive-marker-outline::before{content:"\F175C"}.mdi-archive-minus::before{content:"\F175D"}.mdi-archive-minus-outline::before{content:"\F175E"}.mdi-archive-music::before{content:"\F175F"}.mdi-archive-music-outline::before{content:"\F1760"}.mdi-archive-off::before{content:"\F1761"}.mdi-archive-off-outline::before{content:"\F1762"}.mdi-archive-outline::before{content:"\F120E"}.mdi-archive-plus::before{content:"\F1763"}.mdi-archive-plus-outline::before{content:"\F1764"}.mdi-archive-refresh::before{content:"\F1765"}.mdi-archive-refresh-outline::before{content:"\F1766"}.mdi-archive-remove::before{content:"\F1767"}.mdi-archive-remove-outline::before{content:"\F1768"}.mdi-archive-search::before{content:"\F1769"}.mdi-archive-search-outline::before{content:"\F176A"}.mdi-archive-settings::before{content:"\F176B"}.mdi-archive-settings-outline::before{content:"\F176C"}.mdi-archive-star::before{content:"\F176D"}.mdi-archive-star-outline::before{content:"\F176E"}.mdi-archive-sync::before{content:"\F176F"}.mdi-archive-sync-outline::before{content:"\F1770"}.mdi-arm-flex::before{content:"\F0FD7"}.mdi-arm-flex-outline::before{content:"\F0FD6"}.mdi-arrange-bring-forward::before{content:"\F003D"}.mdi-arrange-bring-to-front::before{content:"\F003E"}.mdi-arrange-send-backward::before{content:"\F003F"}.mdi-arrange-send-to-back::before{content:"\F0040"}.mdi-arrow-all::before{content:"\F0041"}.mdi-arrow-bottom-left::before{content:"\F0042"}.mdi-arrow-bottom-left-bold-box::before{content:"\F1964"}.mdi-arrow-bottom-left-bold-box-outline::before{content:"\F1965"}.mdi-arrow-bottom-left-bold-outline::before{content:"\F09B7"}.mdi-arrow-bottom-left-thick::before{content:"\F09B8"}.mdi-arrow-bottom-left-thin::before{content:"\F19B6"}.mdi-arrow-bottom-left-thin-circle-outline::before{content:"\F1596"}.mdi-arrow-bottom-right::before{content:"\F0043"}.mdi-arrow-bottom-right-bold-box::before{content:"\F1966"}.mdi-arrow-bottom-right-bold-box-outline::before{content:"\F1967"}.mdi-arrow-bottom-right-bold-outline::before{content:"\F09B9"}.mdi-arrow-bottom-right-thick::before{content:"\F09BA"}.mdi-arrow-bottom-right-thin::before{content:"\F19B7"}.mdi-arrow-bottom-right-thin-circle-outline::before{content:"\F1595"}.mdi-arrow-collapse::before{content:"\F0615"}.mdi-arrow-collapse-all::before{content:"\F0044"}.mdi-arrow-collapse-down::before{content:"\F0792"}.mdi-arrow-collapse-horizontal::before{content:"\F084C"}.mdi-arrow-collapse-left::before{content:"\F0793"}.mdi-arrow-collapse-right::before{content:"\F0794"}.mdi-arrow-collapse-up::before{content:"\F0795"}.mdi-arrow-collapse-vertical::before{content:"\F084D"}.mdi-arrow-decision::before{content:"\F09BB"}.mdi-arrow-decision-auto::before{content:"\F09BC"}.mdi-arrow-decision-auto-outline::before{content:"\F09BD"}.mdi-arrow-decision-outline::before{content:"\F09BE"}.mdi-arrow-down::before{content:"\F0045"}.mdi-arrow-down-bold::before{content:"\F072E"}.mdi-arrow-down-bold-box::before{content:"\F072F"}.mdi-arrow-down-bold-box-outline::before{content:"\F0730"}.mdi-arrow-down-bold-circle::before{content:"\F0047"}.mdi-arrow-down-bold-circle-outline::before{content:"\F0048"}.mdi-arrow-down-bold-hexagon-outline::before{content:"\F0049"}.mdi-arrow-down-bold-outline::before{content:"\F09BF"}.mdi-arrow-down-box::before{content:"\F06C0"}.mdi-arrow-down-circle::before{content:"\F0CDB"}.mdi-arrow-down-circle-outline::before{content:"\F0CDC"}.mdi-arrow-down-drop-circle::before{content:"\F004A"}.mdi-arrow-down-drop-circle-outline::before{content:"\F004B"}.mdi-arrow-down-left::before{content:"\F17A1"}.mdi-arrow-down-left-bold::before{content:"\F17A2"}.mdi-arrow-down-right::before{content:"\F17A3"}.mdi-arrow-down-right-bold::before{content:"\F17A4"}.mdi-arrow-down-thick::before{content:"\F0046"}.mdi-arrow-down-thin::before{content:"\F19B3"}.mdi-arrow-down-thin-circle-outline::before{content:"\F1599"}.mdi-arrow-expand::before{content:"\F0616"}.mdi-arrow-expand-all::before{content:"\F004C"}.mdi-arrow-expand-down::before{content:"\F0796"}.mdi-arrow-expand-horizontal::before{content:"\F084E"}.mdi-arrow-expand-left::before{content:"\F0797"}.mdi-arrow-expand-right::before{content:"\F0798"}.mdi-arrow-expand-up::before{content:"\F0799"}.mdi-arrow-expand-vertical::before{content:"\F084F"}.mdi-arrow-horizontal-lock::before{content:"\F115B"}.mdi-arrow-left::before{content:"\F004D"}.mdi-arrow-left-bold::before{content:"\F0731"}.mdi-arrow-left-bold-box::before{content:"\F0732"}.mdi-arrow-left-bold-box-outline::before{content:"\F0733"}.mdi-arrow-left-bold-circle::before{content:"\F004F"}.mdi-arrow-left-bold-circle-outline::before{content:"\F0050"}.mdi-arrow-left-bold-hexagon-outline::before{content:"\F0051"}.mdi-arrow-left-bold-outline::before{content:"\F09C0"}.mdi-arrow-left-bottom::before{content:"\F17A5"}.mdi-arrow-left-bottom-bold::before{content:"\F17A6"}.mdi-arrow-left-box::before{content:"\F06C1"}.mdi-arrow-left-circle::before{content:"\F0CDD"}.mdi-arrow-left-circle-outline::before{content:"\F0CDE"}.mdi-arrow-left-drop-circle::before{content:"\F0052"}.mdi-arrow-left-drop-circle-outline::before{content:"\F0053"}.mdi-arrow-left-right::before{content:"\F0E73"}.mdi-arrow-left-right-bold::before{content:"\F0E74"}.mdi-arrow-left-right-bold-outline::before{content:"\F09C1"}.mdi-arrow-left-thick::before{content:"\F004E"}.mdi-arrow-left-thin::before{content:"\F19B1"}.mdi-arrow-left-thin-circle-outline::before{content:"\F159A"}.mdi-arrow-left-top::before{content:"\F17A7"}.mdi-arrow-left-top-bold::before{content:"\F17A8"}.mdi-arrow-oscillating::before{content:"\F1C91"}.mdi-arrow-oscillating-off::before{content:"\F1C92"}.mdi-arrow-projectile::before{content:"\F1840"}.mdi-arrow-projectile-multiple::before{content:"\F183F"}.mdi-arrow-right::before{content:"\F0054"}.mdi-arrow-right-bold::before{content:"\F0734"}.mdi-arrow-right-bold-box::before{content:"\F0735"}.mdi-arrow-right-bold-box-outline::before{content:"\F0736"}.mdi-arrow-right-bold-circle::before{content:"\F0056"}.mdi-arrow-right-bold-circle-outline::before{content:"\F0057"}.mdi-arrow-right-bold-hexagon-outline::before{content:"\F0058"}.mdi-arrow-right-bold-outline::before{content:"\F09C2"}.mdi-arrow-right-bottom::before{content:"\F17A9"}.mdi-arrow-right-bottom-bold::before{content:"\F17AA"}.mdi-arrow-right-box::before{content:"\F06C2"}.mdi-arrow-right-circle::before{content:"\F0CDF"}.mdi-arrow-right-circle-outline::before{content:"\F0CE0"}.mdi-arrow-right-drop-circle::before{content:"\F0059"}.mdi-arrow-right-drop-circle-outline::before{content:"\F005A"}.mdi-arrow-right-thick::before{content:"\F0055"}.mdi-arrow-right-thin::before{content:"\F19B0"}.mdi-arrow-right-thin-circle-outline::before{content:"\F1598"}.mdi-arrow-right-top::before{content:"\F17AB"}.mdi-arrow-right-top-bold::before{content:"\F17AC"}.mdi-arrow-split-horizontal::before{content:"\F093B"}.mdi-arrow-split-vertical::before{content:"\F093C"}.mdi-arrow-top-left::before{content:"\F005B"}.mdi-arrow-top-left-bold-box::before{content:"\F1968"}.mdi-arrow-top-left-bold-box-outline::before{content:"\F1969"}.mdi-arrow-top-left-bold-outline::before{content:"\F09C3"}.mdi-arrow-top-left-bottom-right::before{content:"\F0E75"}.mdi-arrow-top-left-bottom-right-bold::before{content:"\F0E76"}.mdi-arrow-top-left-thick::before{content:"\F09C4"}.mdi-arrow-top-left-thin::before{content:"\F19B5"}.mdi-arrow-top-left-thin-circle-outline::before{content:"\F1593"}.mdi-arrow-top-right::before{content:"\F005C"}.mdi-arrow-top-right-bold-box::before{content:"\F196A"}.mdi-arrow-top-right-bold-box-outline::before{content:"\F196B"}.mdi-arrow-top-right-bold-outline::before{content:"\F09C5"}.mdi-arrow-top-right-bottom-left::before{content:"\F0E77"}.mdi-arrow-top-right-bottom-left-bold::before{content:"\F0E78"}.mdi-arrow-top-right-thick::before{content:"\F09C6"}.mdi-arrow-top-right-thin::before{content:"\F19B4"}.mdi-arrow-top-right-thin-circle-outline::before{content:"\F1594"}.mdi-arrow-u-down-left::before{content:"\F17AD"}.mdi-arrow-u-down-left-bold::before{content:"\F17AE"}.mdi-arrow-u-down-right::before{content:"\F17AF"}.mdi-arrow-u-down-right-bold::before{content:"\F17B0"}.mdi-arrow-u-left-bottom::before{content:"\F17B1"}.mdi-arrow-u-left-bottom-bold::before{content:"\F17B2"}.mdi-arrow-u-left-top::before{content:"\F17B3"}.mdi-arrow-u-left-top-bold::before{content:"\F17B4"}.mdi-arrow-u-right-bottom::before{content:"\F17B5"}.mdi-arrow-u-right-bottom-bold::before{content:"\F17B6"}.mdi-arrow-u-right-top::before{content:"\F17B7"}.mdi-arrow-u-right-top-bold::before{content:"\F17B8"}.mdi-arrow-u-up-left::before{content:"\F17B9"}.mdi-arrow-u-up-left-bold::before{content:"\F17BA"}.mdi-arrow-u-up-right::before{content:"\F17BB"}.mdi-arrow-u-up-right-bold::before{content:"\F17BC"}.mdi-arrow-up::before{content:"\F005D"}.mdi-arrow-up-bold::before{content:"\F0737"}.mdi-arrow-up-bold-box::before{content:"\F0738"}.mdi-arrow-up-bold-box-outline::before{content:"\F0739"}.mdi-arrow-up-bold-circle::before{content:"\F005F"}.mdi-arrow-up-bold-circle-outline::before{content:"\F0060"}.mdi-arrow-up-bold-hexagon-outline::before{content:"\F0061"}.mdi-arrow-up-bold-outline::before{content:"\F09C7"}.mdi-arrow-up-box::before{content:"\F06C3"}.mdi-arrow-up-circle::before{content:"\F0CE1"}.mdi-arrow-up-circle-outline::before{content:"\F0CE2"}.mdi-arrow-up-down::before{content:"\F0E79"}.mdi-arrow-up-down-bold::before{content:"\F0E7A"}.mdi-arrow-up-down-bold-outline::before{content:"\F09C8"}.mdi-arrow-up-drop-circle::before{content:"\F0062"}.mdi-arrow-up-drop-circle-outline::before{content:"\F0063"}.mdi-arrow-up-left::before{content:"\F17BD"}.mdi-arrow-up-left-bold::before{content:"\F17BE"}.mdi-arrow-up-right::before{content:"\F17BF"}.mdi-arrow-up-right-bold::before{content:"\F17C0"}.mdi-arrow-up-thick::before{content:"\F005E"}.mdi-arrow-up-thin::before{content:"\F19B2"}.mdi-arrow-up-thin-circle-outline::before{content:"\F1597"}.mdi-arrow-vertical-lock::before{content:"\F115C"}.mdi-artboard::before{content:"\F1B9A"}.mdi-artstation::before{content:"\F0B5B"}.mdi-aspect-ratio::before{content:"\F0A24"}.mdi-assistant::before{content:"\F0064"}.mdi-asterisk::before{content:"\F06C4"}.mdi-asterisk-circle-outline::before{content:"\F1A27"}.mdi-at::before{content:"\F0065"}.mdi-atlassian::before{content:"\F0804"}.mdi-atm::before{content:"\F0D47"}.mdi-atom::before{content:"\F0768"}.mdi-atom-variant::before{content:"\F0E7B"}.mdi-attachment::before{content:"\F0066"}.mdi-attachment-check::before{content:"\F1AC1"}.mdi-attachment-lock::before{content:"\F19C4"}.mdi-attachment-minus::before{content:"\F1AC2"}.mdi-attachment-off::before{content:"\F1AC3"}.mdi-attachment-plus::before{content:"\F1AC4"}.mdi-attachment-remove::before{content:"\F1AC5"}.mdi-atv::before{content:"\F1B70"}.mdi-audio-input-rca::before{content:"\F186B"}.mdi-audio-input-stereo-minijack::before{content:"\F186C"}.mdi-audio-input-xlr::before{content:"\F186D"}.mdi-audio-video::before{content:"\F093D"}.mdi-audio-video-off::before{content:"\F11B6"}.mdi-augmented-reality::before{content:"\F0850"}.mdi-aurora::before{content:"\F1BB9"}.mdi-auto-download::before{content:"\F137E"}.mdi-auto-fix::before{content:"\F0068"}.mdi-auto-mode::before{content:"\F1C20"}.mdi-auto-upload::before{content:"\F0069"}.mdi-autorenew::before{content:"\F006A"}.mdi-autorenew-off::before{content:"\F19E7"}.mdi-av-timer::before{content:"\F006B"}.mdi-awning::before{content:"\F1B87"}.mdi-awning-outline::before{content:"\F1B88"}.mdi-aws::before{content:"\F0E0F"}.mdi-axe::before{content:"\F08C8"}.mdi-axe-battle::before{content:"\F1842"}.mdi-axis::before{content:"\F0D48"}.mdi-axis-arrow::before{content:"\F0D49"}.mdi-axis-arrow-info::before{content:"\F140E"}.mdi-axis-arrow-lock::before{content:"\F0D4A"}.mdi-axis-lock::before{content:"\F0D4B"}.mdi-axis-x-arrow::before{content:"\F0D4C"}.mdi-axis-x-arrow-lock::before{content:"\F0D4D"}.mdi-axis-x-rotate-clockwise::before{content:"\F0D4E"}.mdi-axis-x-rotate-counterclockwise::before{content:"\F0D4F"}.mdi-axis-x-y-arrow-lock::before{content:"\F0D50"}.mdi-axis-y-arrow::before{content:"\F0D51"}.mdi-axis-y-arrow-lock::before{content:"\F0D52"}.mdi-axis-y-rotate-clockwise::before{content:"\F0D53"}.mdi-axis-y-rotate-counterclockwise::before{content:"\F0D54"}.mdi-axis-z-arrow::before{content:"\F0D55"}.mdi-axis-z-arrow-lock::before{content:"\F0D56"}.mdi-axis-z-rotate-clockwise::before{content:"\F0D57"}.mdi-axis-z-rotate-counterclockwise::before{content:"\F0D58"}.mdi-babel::before{content:"\F0A25"}.mdi-baby::before{content:"\F006C"}.mdi-baby-bottle::before{content:"\F0F39"}.mdi-baby-bottle-outline::before{content:"\F0F3A"}.mdi-baby-buggy::before{content:"\F13E0"}.mdi-baby-buggy-off::before{content:"\F1AF3"}.mdi-baby-carriage::before{content:"\F068F"}.mdi-baby-carriage-off::before{content:"\F0FA0"}.mdi-baby-face::before{content:"\F0E7C"}.mdi-baby-face-outline::before{content:"\F0E7D"}.mdi-backburger::before{content:"\F006D"}.mdi-backspace::before{content:"\F006E"}.mdi-backspace-outline::before{content:"\F0B5C"}.mdi-backspace-reverse::before{content:"\F0E7E"}.mdi-backspace-reverse-outline::before{content:"\F0E7F"}.mdi-backup-restore::before{content:"\F006F"}.mdi-bacteria::before{content:"\F0ED5"}.mdi-bacteria-outline::before{content:"\F0ED6"}.mdi-badge-account::before{content:"\F0DA7"}.mdi-badge-account-alert::before{content:"\F0DA8"}.mdi-badge-account-alert-outline::before{content:"\F0DA9"}.mdi-badge-account-horizontal::before{content:"\F0E0D"}.mdi-badge-account-horizontal-outline::before{content:"\F0E0E"}.mdi-badge-account-outline::before{content:"\F0DAA"}.mdi-badminton::before{content:"\F0851"}.mdi-bag-carry-on::before{content:"\F0F3B"}.mdi-bag-carry-on-check::before{content:"\F0D65"}.mdi-bag-carry-on-off::before{content:"\F0F3C"}.mdi-bag-checked::before{content:"\F0F3D"}.mdi-bag-personal::before{content:"\F0E10"}.mdi-bag-personal-off::before{content:"\F0E11"}.mdi-bag-personal-off-outline::before{content:"\F0E12"}.mdi-bag-personal-outline::before{content:"\F0E13"}.mdi-bag-personal-plus::before{content:"\F1CA4"}.mdi-bag-personal-plus-outline::before{content:"\F1CA5"}.mdi-bag-personal-tag::before{content:"\F1B0C"}.mdi-bag-personal-tag-outline::before{content:"\F1B0D"}.mdi-bag-suitcase::before{content:"\F158B"}.mdi-bag-suitcase-off::before{content:"\F158D"}.mdi-bag-suitcase-off-outline::before{content:"\F158E"}.mdi-bag-suitcase-outline::before{content:"\F158C"}.mdi-baguette::before{content:"\F0F3E"}.mdi-balcony::before{content:"\F1817"}.mdi-balloon::before{content:"\F0A26"}.mdi-ballot::before{content:"\F09C9"}.mdi-ballot-outline::before{content:"\F09CA"}.mdi-ballot-recount::before{content:"\F0C39"}.mdi-ballot-recount-outline::before{content:"\F0C3A"}.mdi-bandage::before{content:"\F0DAF"}.mdi-bank::before{content:"\F0070"}.mdi-bank-check::before{content:"\F1655"}.mdi-bank-circle::before{content:"\F1C03"}.mdi-bank-circle-outline::before{content:"\F1C04"}.mdi-bank-minus::before{content:"\F0DB0"}.mdi-bank-off::before{content:"\F1656"}.mdi-bank-off-outline::before{content:"\F1657"}.mdi-bank-outline::before{content:"\F0E80"}.mdi-bank-plus::before{content:"\F0DB1"}.mdi-bank-remove::before{content:"\F0DB2"}.mdi-bank-transfer::before{content:"\F0A27"}.mdi-bank-transfer-in::before{content:"\F0A28"}.mdi-bank-transfer-out::before{content:"\F0A29"}.mdi-barcode::before{content:"\F0071"}.mdi-barcode-off::before{content:"\F1236"}.mdi-barcode-scan::before{content:"\F0072"}.mdi-barley::before{content:"\F0073"}.mdi-barley-off::before{content:"\F0B5D"}.mdi-barn::before{content:"\F0B5E"}.mdi-barrel::before{content:"\F0074"}.mdi-barrel-outline::before{content:"\F1A28"}.mdi-baseball::before{content:"\F0852"}.mdi-baseball-bat::before{content:"\F0853"}.mdi-baseball-diamond::before{content:"\F15EC"}.mdi-baseball-diamond-outline::before{content:"\F15ED"}.mdi-baseball-outline::before{content:"\F1C5A"}.mdi-bash::before{content:"\F1183"}.mdi-basket::before{content:"\F0076"}.mdi-basket-check::before{content:"\F18E5"}.mdi-basket-check-outline::before{content:"\F18E6"}.mdi-basket-fill::before{content:"\F0077"}.mdi-basket-minus::before{content:"\F1523"}.mdi-basket-minus-outline::before{content:"\F1524"}.mdi-basket-off::before{content:"\F1525"}.mdi-basket-off-outline::before{content:"\F1526"}.mdi-basket-outline::before{content:"\F1181"}.mdi-basket-plus::before{content:"\F1527"}.mdi-basket-plus-outline::before{content:"\F1528"}.mdi-basket-remove::before{content:"\F1529"}.mdi-basket-remove-outline::before{content:"\F152A"}.mdi-basket-unfill::before{content:"\F0078"}.mdi-basketball::before{content:"\F0806"}.mdi-basketball-hoop::before{content:"\F0C3B"}.mdi-basketball-hoop-outline::before{content:"\F0C3C"}.mdi-bat::before{content:"\F0B5F"}.mdi-bathtub::before{content:"\F1818"}.mdi-bathtub-outline::before{content:"\F1819"}.mdi-battery::before{content:"\F0079"}.mdi-battery-10::before{content:"\F007A"}.mdi-battery-10-bluetooth::before{content:"\F093E"}.mdi-battery-20::before{content:"\F007B"}.mdi-battery-20-bluetooth::before{content:"\F093F"}.mdi-battery-30::before{content:"\F007C"}.mdi-battery-30-bluetooth::before{content:"\F0940"}.mdi-battery-40::before{content:"\F007D"}.mdi-battery-40-bluetooth::before{content:"\F0941"}.mdi-battery-50::before{content:"\F007E"}.mdi-battery-50-bluetooth::before{content:"\F0942"}.mdi-battery-60::before{content:"\F007F"}.mdi-battery-60-bluetooth::before{content:"\F0943"}.mdi-battery-70::before{content:"\F0080"}.mdi-battery-70-bluetooth::before{content:"\F0944"}.mdi-battery-80::before{content:"\F0081"}.mdi-battery-80-bluetooth::before{content:"\F0945"}.mdi-battery-90::before{content:"\F0082"}.mdi-battery-90-bluetooth::before{content:"\F0946"}.mdi-battery-alert::before{content:"\F0083"}.mdi-battery-alert-bluetooth::before{content:"\F0947"}.mdi-battery-alert-variant::before{content:"\F10CC"}.mdi-battery-alert-variant-outline::before{content:"\F10CD"}.mdi-battery-arrow-down::before{content:"\F17DE"}.mdi-battery-arrow-down-outline::before{content:"\F17DF"}.mdi-battery-arrow-up::before{content:"\F17E0"}.mdi-battery-arrow-up-outline::before{content:"\F17E1"}.mdi-battery-bluetooth::before{content:"\F0948"}.mdi-battery-bluetooth-variant::before{content:"\F0949"}.mdi-battery-charging::before{content:"\F0084"}.mdi-battery-charging-10::before{content:"\F089C"}.mdi-battery-charging-100::before{content:"\F0085"}.mdi-battery-charging-20::before{content:"\F0086"}.mdi-battery-charging-30::before{content:"\F0087"}.mdi-battery-charging-40::before{content:"\F0088"}.mdi-battery-charging-50::before{content:"\F089D"}.mdi-battery-charging-60::before{content:"\F0089"}.mdi-battery-charging-70::before{content:"\F089E"}.mdi-battery-charging-80::before{content:"\F008A"}.mdi-battery-charging-90::before{content:"\F008B"}.mdi-battery-charging-high::before{content:"\F12A6"}.mdi-battery-charging-low::before{content:"\F12A4"}.mdi-battery-charging-medium::before{content:"\F12A5"}.mdi-battery-charging-outline::before{content:"\F089F"}.mdi-battery-charging-wireless::before{content:"\F0807"}.mdi-battery-charging-wireless-10::before{content:"\F0808"}.mdi-battery-charging-wireless-20::before{content:"\F0809"}.mdi-battery-charging-wireless-30::before{content:"\F080A"}.mdi-battery-charging-wireless-40::before{content:"\F080B"}.mdi-battery-charging-wireless-50::before{content:"\F080C"}.mdi-battery-charging-wireless-60::before{content:"\F080D"}.mdi-battery-charging-wireless-70::before{content:"\F080E"}.mdi-battery-charging-wireless-80::before{content:"\F080F"}.mdi-battery-charging-wireless-90::before{content:"\F0810"}.mdi-battery-charging-wireless-alert::before{content:"\F0811"}.mdi-battery-charging-wireless-outline::before{content:"\F0812"}.mdi-battery-check::before{content:"\F17E2"}.mdi-battery-check-outline::before{content:"\F17E3"}.mdi-battery-clock::before{content:"\F19E5"}.mdi-battery-clock-outline::before{content:"\F19E6"}.mdi-battery-heart::before{content:"\F120F"}.mdi-battery-heart-outline::before{content:"\F1210"}.mdi-battery-heart-variant::before{content:"\F1211"}.mdi-battery-high::before{content:"\F12A3"}.mdi-battery-lock::before{content:"\F179C"}.mdi-battery-lock-open::before{content:"\F179D"}.mdi-battery-low::before{content:"\F12A1"}.mdi-battery-medium::before{content:"\F12A2"}.mdi-battery-minus::before{content:"\F17E4"}.mdi-battery-minus-outline::before{content:"\F17E5"}.mdi-battery-minus-variant::before{content:"\F008C"}.mdi-battery-negative::before{content:"\F008D"}.mdi-battery-off::before{content:"\F125D"}.mdi-battery-off-outline::before{content:"\F125E"}.mdi-battery-outline::before{content:"\F008E"}.mdi-battery-plus::before{content:"\F17E6"}.mdi-battery-plus-outline::before{content:"\F17E7"}.mdi-battery-plus-variant::before{content:"\F008F"}.mdi-battery-positive::before{content:"\F0090"}.mdi-battery-remove::before{content:"\F17E8"}.mdi-battery-remove-outline::before{content:"\F17E9"}.mdi-battery-sync::before{content:"\F1834"}.mdi-battery-sync-outline::before{content:"\F1835"}.mdi-battery-unknown::before{content:"\F0091"}.mdi-battery-unknown-bluetooth::before{content:"\F094A"}.mdi-beach::before{content:"\F0092"}.mdi-beaker::before{content:"\F0CEA"}.mdi-beaker-alert::before{content:"\F1229"}.mdi-beaker-alert-outline::before{content:"\F122A"}.mdi-beaker-check::before{content:"\F122B"}.mdi-beaker-check-outline::before{content:"\F122C"}.mdi-beaker-minus::before{content:"\F122D"}.mdi-beaker-minus-outline::before{content:"\F122E"}.mdi-beaker-outline::before{content:"\F0690"}.mdi-beaker-plus::before{content:"\F122F"}.mdi-beaker-plus-outline::before{content:"\F1230"}.mdi-beaker-question::before{content:"\F1231"}.mdi-beaker-question-outline::before{content:"\F1232"}.mdi-beaker-remove::before{content:"\F1233"}.mdi-beaker-remove-outline::before{content:"\F1234"}.mdi-bed::before{content:"\F02E3"}.mdi-bed-clock::before{content:"\F1B94"}.mdi-bed-double::before{content:"\F0FD4"}.mdi-bed-double-outline::before{content:"\F0FD3"}.mdi-bed-empty::before{content:"\F08A0"}.mdi-bed-king::before{content:"\F0FD2"}.mdi-bed-king-outline::before{content:"\F0FD1"}.mdi-bed-outline::before{content:"\F0099"}.mdi-bed-queen::before{content:"\F0FD0"}.mdi-bed-queen-outline::before{content:"\F0FDB"}.mdi-bed-single::before{content:"\F106D"}.mdi-bed-single-outline::before{content:"\F106E"}.mdi-bee::before{content:"\F0FA1"}.mdi-bee-flower::before{content:"\F0FA2"}.mdi-beehive-off-outline::before{content:"\F13ED"}.mdi-beehive-outline::before{content:"\F10CE"}.mdi-beekeeper::before{content:"\F14E2"}.mdi-beer::before{content:"\F0098"}.mdi-beer-outline::before{content:"\F130C"}.mdi-bell::before{content:"\F009A"}.mdi-bell-alert::before{content:"\F0D59"}.mdi-bell-alert-outline::before{content:"\F0E81"}.mdi-bell-badge::before{content:"\F116B"}.mdi-bell-badge-outline::before{content:"\F0178"}.mdi-bell-cancel::before{content:"\F13E7"}.mdi-bell-cancel-outline::before{content:"\F13E8"}.mdi-bell-check::before{content:"\F11E5"}.mdi-bell-check-outline::before{content:"\F11E6"}.mdi-bell-circle::before{content:"\F0D5A"}.mdi-bell-circle-outline::before{content:"\F0D5B"}.mdi-bell-cog::before{content:"\F1A29"}.mdi-bell-cog-outline::before{content:"\F1A2A"}.mdi-bell-minus::before{content:"\F13E9"}.mdi-bell-minus-outline::before{content:"\F13EA"}.mdi-bell-off::before{content:"\F009B"}.mdi-bell-off-outline::before{content:"\F0A91"}.mdi-bell-outline::before{content:"\F009C"}.mdi-bell-plus::before{content:"\F009D"}.mdi-bell-plus-outline::before{content:"\F0A92"}.mdi-bell-remove::before{content:"\F13EB"}.mdi-bell-remove-outline::before{content:"\F13EC"}.mdi-bell-ring::before{content:"\F009E"}.mdi-bell-ring-outline::before{content:"\F009F"}.mdi-bell-sleep::before{content:"\F00A0"}.mdi-bell-sleep-outline::before{content:"\F0A93"}.mdi-bench::before{content:"\F1C21"}.mdi-bench-back::before{content:"\F1C22"}.mdi-beta::before{content:"\F00A1"}.mdi-betamax::before{content:"\F09CB"}.mdi-biathlon::before{content:"\F0E14"}.mdi-bicycle::before{content:"\F109C"}.mdi-bicycle-basket::before{content:"\F1235"}.mdi-bicycle-cargo::before{content:"\F189C"}.mdi-bicycle-electric::before{content:"\F15B4"}.mdi-bicycle-penny-farthing::before{content:"\F15E9"}.mdi-bike::before{content:"\F00A3"}.mdi-bike-fast::before{content:"\F111F"}.mdi-bike-pedal::before{content:"\F1C23"}.mdi-bike-pedal-clipless::before{content:"\F1C24"}.mdi-bike-pedal-mountain::before{content:"\F1C25"}.mdi-billboard::before{content:"\F1010"}.mdi-billiards::before{content:"\F0B61"}.mdi-billiards-rack::before{content:"\F0B62"}.mdi-binoculars::before{content:"\F00A5"}.mdi-bio::before{content:"\F00A6"}.mdi-biohazard::before{content:"\F00A7"}.mdi-bird::before{content:"\F15C6"}.mdi-bitbucket::before{content:"\F00A8"}.mdi-bitcoin::before{content:"\F0813"}.mdi-black-mesa::before{content:"\F00A9"}.mdi-blender::before{content:"\F0CEB"}.mdi-blender-outline::before{content:"\F181A"}.mdi-blender-software::before{content:"\F00AB"}.mdi-blinds::before{content:"\F00AC"}.mdi-blinds-horizontal::before{content:"\F1A2B"}.mdi-blinds-horizontal-closed::before{content:"\F1A2C"}.mdi-blinds-open::before{content:"\F1011"}.mdi-blinds-vertical::before{content:"\F1A2D"}.mdi-blinds-vertical-closed::before{content:"\F1A2E"}.mdi-block-helper::before{content:"\F00AD"}.mdi-blood-bag::before{content:"\F0CEC"}.mdi-bluetooth::before{content:"\F00AF"}.mdi-bluetooth-audio::before{content:"\F00B0"}.mdi-bluetooth-connect::before{content:"\F00B1"}.mdi-bluetooth-off::before{content:"\F00B2"}.mdi-bluetooth-settings::before{content:"\F00B3"}.mdi-bluetooth-transfer::before{content:"\F00B4"}.mdi-blur::before{content:"\F00B5"}.mdi-blur-linear::before{content:"\F00B6"}.mdi-blur-off::before{content:"\F00B7"}.mdi-blur-radial::before{content:"\F00B8"}.mdi-bolt::before{content:"\F0DB3"}.mdi-bomb::before{content:"\F0691"}.mdi-bomb-off::before{content:"\F06C5"}.mdi-bone::before{content:"\F00B9"}.mdi-bone-off::before{content:"\F19E0"}.mdi-book::before{content:"\F00BA"}.mdi-book-account::before{content:"\F13AD"}.mdi-book-account-outline::before{content:"\F13AE"}.mdi-book-alert::before{content:"\F167C"}.mdi-book-alert-outline::before{content:"\F167D"}.mdi-book-alphabet::before{content:"\F061D"}.mdi-book-arrow-down::before{content:"\F167E"}.mdi-book-arrow-down-outline::before{content:"\F167F"}.mdi-book-arrow-left::before{content:"\F1680"}.mdi-book-arrow-left-outline::before{content:"\F1681"}.mdi-book-arrow-right::before{content:"\F1682"}.mdi-book-arrow-right-outline::before{content:"\F1683"}.mdi-book-arrow-up::before{content:"\F1684"}.mdi-book-arrow-up-outline::before{content:"\F1685"}.mdi-book-cancel::before{content:"\F1686"}.mdi-book-cancel-outline::before{content:"\F1687"}.mdi-book-check::before{content:"\F14F3"}.mdi-book-check-outline::before{content:"\F14F4"}.mdi-book-clock::before{content:"\F1688"}.mdi-book-clock-outline::before{content:"\F1689"}.mdi-book-cog::before{content:"\F168A"}.mdi-book-cog-outline::before{content:"\F168B"}.mdi-book-cross::before{content:"\F00A2"}.mdi-book-edit::before{content:"\F168C"}.mdi-book-edit-outline::before{content:"\F168D"}.mdi-book-education::before{content:"\F16C9"}.mdi-book-education-outline::before{content:"\F16CA"}.mdi-book-heart::before{content:"\F1A1D"}.mdi-book-heart-outline::before{content:"\F1A1E"}.mdi-book-information-variant::before{content:"\F106F"}.mdi-book-lock::before{content:"\F079A"}.mdi-book-lock-open::before{content:"\F079B"}.mdi-book-lock-open-outline::before{content:"\F168E"}.mdi-book-lock-outline::before{content:"\F168F"}.mdi-book-marker::before{content:"\F1690"}.mdi-book-marker-outline::before{content:"\F1691"}.mdi-book-minus::before{content:"\F05D9"}.mdi-book-minus-multiple::before{content:"\F0A94"}.mdi-book-minus-multiple-outline::before{content:"\F090B"}.mdi-book-minus-outline::before{content:"\F1692"}.mdi-book-multiple::before{content:"\F00BB"}.mdi-book-multiple-outline::before{content:"\F0436"}.mdi-book-music::before{content:"\F0067"}.mdi-book-music-outline::before{content:"\F1693"}.mdi-book-off::before{content:"\F1694"}.mdi-book-off-outline::before{content:"\F1695"}.mdi-book-open::before{content:"\F00BD"}.mdi-book-open-blank-variant::before{content:"\F00BE"}.mdi-book-open-blank-variant-outline::before{content:"\F1CCB"}.mdi-book-open-outline::before{content:"\F0B63"}.mdi-book-open-page-variant::before{content:"\F05DA"}.mdi-book-open-page-variant-outline::before{content:"\F15D6"}.mdi-book-open-variant::before{content:"\F14F7"}.mdi-book-open-variant-outline::before{content:"\F1CCC"}.mdi-book-outline::before{content:"\F0B64"}.mdi-book-play::before{content:"\F0E82"}.mdi-book-play-outline::before{content:"\F0E83"}.mdi-book-plus::before{content:"\F05DB"}.mdi-book-plus-multiple::before{content:"\F0A95"}.mdi-book-plus-multiple-outline::before{content:"\F0ADE"}.mdi-book-plus-outline::before{content:"\F1696"}.mdi-book-refresh::before{content:"\F1697"}.mdi-book-refresh-outline::before{content:"\F1698"}.mdi-book-remove::before{content:"\F0A97"}.mdi-book-remove-multiple::before{content:"\F0A96"}.mdi-book-remove-multiple-outline::before{content:"\F04CA"}.mdi-book-remove-outline::before{content:"\F1699"}.mdi-book-search::before{content:"\F0E84"}.mdi-book-search-outline::before{content:"\F0E85"}.mdi-book-settings::before{content:"\F169A"}.mdi-book-settings-outline::before{content:"\F169B"}.mdi-book-sync::before{content:"\F169C"}.mdi-book-sync-outline::before{content:"\F16C8"}.mdi-book-variant::before{content:"\F00BF"}.mdi-bookmark::before{content:"\F00C0"}.mdi-bookmark-box::before{content:"\F1B75"}.mdi-bookmark-box-multiple::before{content:"\F196C"}.mdi-bookmark-box-multiple-outline::before{content:"\F196D"}.mdi-bookmark-box-outline::before{content:"\F1B76"}.mdi-bookmark-check::before{content:"\F00C1"}.mdi-bookmark-check-outline::before{content:"\F137B"}.mdi-bookmark-minus::before{content:"\F09CC"}.mdi-bookmark-minus-outline::before{content:"\F09CD"}.mdi-bookmark-multiple::before{content:"\F0E15"}.mdi-bookmark-multiple-outline::before{content:"\F0E16"}.mdi-bookmark-music::before{content:"\F00C2"}.mdi-bookmark-music-outline::before{content:"\F1379"}.mdi-bookmark-off::before{content:"\F09CE"}.mdi-bookmark-off-outline::before{content:"\F09CF"}.mdi-bookmark-outline::before{content:"\F00C3"}.mdi-bookmark-plus::before{content:"\F00C5"}.mdi-bookmark-plus-outline::before{content:"\F00C4"}.mdi-bookmark-remove::before{content:"\F00C6"}.mdi-bookmark-remove-outline::before{content:"\F137A"}.mdi-bookshelf::before{content:"\F125F"}.mdi-boom-gate::before{content:"\F0E86"}.mdi-boom-gate-alert::before{content:"\F0E87"}.mdi-boom-gate-alert-outline::before{content:"\F0E88"}.mdi-boom-gate-arrow-down::before{content:"\F0E89"}.mdi-boom-gate-arrow-down-outline::before{content:"\F0E8A"}.mdi-boom-gate-arrow-up::before{content:"\F0E8C"}.mdi-boom-gate-arrow-up-outline::before{content:"\F0E8D"}.mdi-boom-gate-outline::before{content:"\F0E8B"}.mdi-boom-gate-up::before{content:"\F17F9"}.mdi-boom-gate-up-outline::before{content:"\F17FA"}.mdi-boombox::before{content:"\F05DC"}.mdi-boomerang::before{content:"\F10CF"}.mdi-bootstrap::before{content:"\F06C6"}.mdi-border-all::before{content:"\F00C7"}.mdi-border-all-variant::before{content:"\F08A1"}.mdi-border-bottom::before{content:"\F00C8"}.mdi-border-bottom-variant::before{content:"\F08A2"}.mdi-border-color::before{content:"\F00C9"}.mdi-border-horizontal::before{content:"\F00CA"}.mdi-border-inside::before{content:"\F00CB"}.mdi-border-left::before{content:"\F00CC"}.mdi-border-left-variant::before{content:"\F08A3"}.mdi-border-none::before{content:"\F00CD"}.mdi-border-none-variant::before{content:"\F08A4"}.mdi-border-outside::before{content:"\F00CE"}.mdi-border-radius::before{content:"\F1AF4"}.mdi-border-right::before{content:"\F00CF"}.mdi-border-right-variant::before{content:"\F08A5"}.mdi-border-style::before{content:"\F00D0"}.mdi-border-top::before{content:"\F00D1"}.mdi-border-top-variant::before{content:"\F08A6"}.mdi-border-vertical::before{content:"\F00D2"}.mdi-bottle-soda::before{content:"\F1070"}.mdi-bottle-soda-classic::before{content:"\F1071"}.mdi-bottle-soda-classic-outline::before{content:"\F1363"}.mdi-bottle-soda-outline::before{content:"\F1072"}.mdi-bottle-tonic::before{content:"\F112E"}.mdi-bottle-tonic-outline::before{content:"\F112F"}.mdi-bottle-tonic-plus::before{content:"\F1130"}.mdi-bottle-tonic-plus-outline::before{content:"\F1131"}.mdi-bottle-tonic-skull::before{content:"\F1132"}.mdi-bottle-tonic-skull-outline::before{content:"\F1133"}.mdi-bottle-wine::before{content:"\F0854"}.mdi-bottle-wine-outline::before{content:"\F1310"}.mdi-bow-arrow::before{content:"\F1841"}.mdi-bow-tie::before{content:"\F0678"}.mdi-bowl::before{content:"\F028E"}.mdi-bowl-mix::before{content:"\F0617"}.mdi-bowl-mix-outline::before{content:"\F02E4"}.mdi-bowl-outline::before{content:"\F02A9"}.mdi-bowling::before{content:"\F00D3"}.mdi-box::before{content:"\F00D4"}.mdi-box-cutter::before{content:"\F00D5"}.mdi-box-cutter-off::before{content:"\F0B4A"}.mdi-box-shadow::before{content:"\F0637"}.mdi-boxing-glove::before{content:"\F0B65"}.mdi-braille::before{content:"\F09D0"}.mdi-brain::before{content:"\F09D1"}.mdi-bread-slice::before{content:"\F0CEE"}.mdi-bread-slice-outline::before{content:"\F0CEF"}.mdi-bridge::before{content:"\F0618"}.mdi-briefcase::before{content:"\F00D6"}.mdi-briefcase-account::before{content:"\F0CF0"}.mdi-briefcase-account-outline::before{content:"\F0CF1"}.mdi-briefcase-arrow-left-right::before{content:"\F1A8D"}.mdi-briefcase-arrow-left-right-outline::before{content:"\F1A8E"}.mdi-briefcase-arrow-up-down::before{content:"\F1A8F"}.mdi-briefcase-arrow-up-down-outline::before{content:"\F1A90"}.mdi-briefcase-check::before{content:"\F00D7"}.mdi-briefcase-check-outline::before{content:"\F131E"}.mdi-briefcase-clock::before{content:"\F10D0"}.mdi-briefcase-clock-outline::before{content:"\F10D1"}.mdi-briefcase-download::before{content:"\F00D8"}.mdi-briefcase-download-outline::before{content:"\F0C3D"}.mdi-briefcase-edit::before{content:"\F0A98"}.mdi-briefcase-edit-outline::before{content:"\F0C3E"}.mdi-briefcase-eye::before{content:"\F17D9"}.mdi-briefcase-eye-outline::before{content:"\F17DA"}.mdi-briefcase-minus::before{content:"\F0A2A"}.mdi-briefcase-minus-outline::before{content:"\F0C3F"}.mdi-briefcase-off::before{content:"\F1658"}.mdi-briefcase-off-outline::before{content:"\F1659"}.mdi-briefcase-outline::before{content:"\F0814"}.mdi-briefcase-plus::before{content:"\F0A2B"}.mdi-briefcase-plus-outline::before{content:"\F0C40"}.mdi-briefcase-remove::before{content:"\F0A2C"}.mdi-briefcase-remove-outline::before{content:"\F0C41"}.mdi-briefcase-search::before{content:"\F0A2D"}.mdi-briefcase-search-outline::before{content:"\F0C42"}.mdi-briefcase-upload::before{content:"\F00D9"}.mdi-briefcase-upload-outline::before{content:"\F0C43"}.mdi-briefcase-variant::before{content:"\F1494"}.mdi-briefcase-variant-off::before{content:"\F165A"}.mdi-briefcase-variant-off-outline::before{content:"\F165B"}.mdi-briefcase-variant-outline::before{content:"\F1495"}.mdi-brightness-1::before{content:"\F00DA"}.mdi-brightness-2::before{content:"\F00DB"}.mdi-brightness-3::before{content:"\F00DC"}.mdi-brightness-4::before{content:"\F00DD"}.mdi-brightness-5::before{content:"\F00DE"}.mdi-brightness-6::before{content:"\F00DF"}.mdi-brightness-7::before{content:"\F00E0"}.mdi-brightness-auto::before{content:"\F00E1"}.mdi-brightness-percent::before{content:"\F0CF2"}.mdi-broadcast::before{content:"\F1720"}.mdi-broadcast-off::before{content:"\F1721"}.mdi-broom::before{content:"\F00E2"}.mdi-brush::before{content:"\F00E3"}.mdi-brush-off::before{content:"\F1771"}.mdi-brush-outline::before{content:"\F1A0D"}.mdi-brush-variant::before{content:"\F1813"}.mdi-bucket::before{content:"\F1415"}.mdi-bucket-outline::before{content:"\F1416"}.mdi-buffet::before{content:"\F0578"}.mdi-bug::before{content:"\F00E4"}.mdi-bug-check::before{content:"\F0A2E"}.mdi-bug-check-outline::before{content:"\F0A2F"}.mdi-bug-outline::before{content:"\F0A30"}.mdi-bug-pause::before{content:"\F1AF5"}.mdi-bug-pause-outline::before{content:"\F1AF6"}.mdi-bug-play::before{content:"\F1AF7"}.mdi-bug-play-outline::before{content:"\F1AF8"}.mdi-bug-stop::before{content:"\F1AF9"}.mdi-bug-stop-outline::before{content:"\F1AFA"}.mdi-bugle::before{content:"\F0DB4"}.mdi-bulkhead-light::before{content:"\F1A2F"}.mdi-bulldozer::before{content:"\F0B22"}.mdi-bullet::before{content:"\F0CF3"}.mdi-bulletin-board::before{content:"\F00E5"}.mdi-bullhorn::before{content:"\F00E6"}.mdi-bullhorn-outline::before{content:"\F0B23"}.mdi-bullhorn-variant::before{content:"\F196E"}.mdi-bullhorn-variant-outline::before{content:"\F196F"}.mdi-bullseye::before{content:"\F05DD"}.mdi-bullseye-arrow::before{content:"\F08C9"}.mdi-bulma::before{content:"\F12E7"}.mdi-bunk-bed::before{content:"\F1302"}.mdi-bunk-bed-outline::before{content:"\F0097"}.mdi-bus::before{content:"\F00E7"}.mdi-bus-alert::before{content:"\F0A99"}.mdi-bus-articulated-end::before{content:"\F079C"}.mdi-bus-articulated-front::before{content:"\F079D"}.mdi-bus-clock::before{content:"\F08CA"}.mdi-bus-double-decker::before{content:"\F079E"}.mdi-bus-electric::before{content:"\F191D"}.mdi-bus-marker::before{content:"\F1212"}.mdi-bus-multiple::before{content:"\F0F3F"}.mdi-bus-school::before{content:"\F079F"}.mdi-bus-side::before{content:"\F07A0"}.mdi-bus-sign::before{content:"\F1CC1"}.mdi-bus-stop::before{content:"\F1012"}.mdi-bus-stop-covered::before{content:"\F1013"}.mdi-bus-stop-uncovered::before{content:"\F1014"}.mdi-bus-wrench::before{content:"\F1CC2"}.mdi-butterfly::before{content:"\F1589"}.mdi-butterfly-outline::before{content:"\F158A"}.mdi-button-cursor::before{content:"\F1B4F"}.mdi-button-pointer::before{content:"\F1B50"}.mdi-cabin-a-frame::before{content:"\F188C"}.mdi-cable-data::before{content:"\F1394"}.mdi-cached::before{content:"\F00E8"}.mdi-cactus::before{content:"\F0DB5"}.mdi-cake::before{content:"\F00E9"}.mdi-cake-layered::before{content:"\F00EA"}.mdi-cake-variant::before{content:"\F00EB"}.mdi-cake-variant-outline::before{content:"\F17F0"}.mdi-calculator::before{content:"\F00EC"}.mdi-calculator-variant::before{content:"\F0A9A"}.mdi-calculator-variant-outline::before{content:"\F15A6"}.mdi-calendar::before{content:"\F00ED"}.mdi-calendar-account::before{content:"\F0ED7"}.mdi-calendar-account-outline::before{content:"\F0ED8"}.mdi-calendar-alert::before{content:"\F0A31"}.mdi-calendar-alert-outline::before{content:"\F1B62"}.mdi-calendar-arrow-left::before{content:"\F1134"}.mdi-calendar-arrow-right::before{content:"\F1135"}.mdi-calendar-badge::before{content:"\F1B9D"}.mdi-calendar-badge-outline::before{content:"\F1B9E"}.mdi-calendar-blank::before{content:"\F00EE"}.mdi-calendar-blank-multiple::before{content:"\F1073"}.mdi-calendar-blank-outline::before{content:"\F0B66"}.mdi-calendar-check::before{content:"\F00EF"}.mdi-calendar-check-outline::before{content:"\F0C44"}.mdi-calendar-clock::before{content:"\F00F0"}.mdi-calendar-clock-outline::before{content:"\F16E1"}.mdi-calendar-collapse-horizontal::before{content:"\F189D"}.mdi-calendar-collapse-horizontal-outline::before{content:"\F1B63"}.mdi-calendar-cursor::before{content:"\F157B"}.mdi-calendar-cursor-outline::before{content:"\F1B64"}.mdi-calendar-edit::before{content:"\F08A7"}.mdi-calendar-edit-outline::before{content:"\F1B65"}.mdi-calendar-end::before{content:"\F166C"}.mdi-calendar-end-outline::before{content:"\F1B66"}.mdi-calendar-expand-horizontal::before{content:"\F189E"}.mdi-calendar-expand-horizontal-outline::before{content:"\F1B67"}.mdi-calendar-export::before{content:"\F0B24"}.mdi-calendar-export-outline::before{content:"\F1B68"}.mdi-calendar-filter::before{content:"\F1A32"}.mdi-calendar-filter-outline::before{content:"\F1A33"}.mdi-calendar-heart::before{content:"\F09D2"}.mdi-calendar-heart-outline::before{content:"\F1B69"}.mdi-calendar-import::before{content:"\F0B25"}.mdi-calendar-import-outline::before{content:"\F1B6A"}.mdi-calendar-lock::before{content:"\F1641"}.mdi-calendar-lock-open::before{content:"\F1B5B"}.mdi-calendar-lock-open-outline::before{content:"\F1B5C"}.mdi-calendar-lock-outline::before{content:"\F1642"}.mdi-calendar-minus::before{content:"\F0D5C"}.mdi-calendar-minus-outline::before{content:"\F1B6B"}.mdi-calendar-month::before{content:"\F0E17"}.mdi-calendar-month-outline::before{content:"\F0E18"}.mdi-calendar-multiple::before{content:"\F00F1"}.mdi-calendar-multiple-check::before{content:"\F00F2"}.mdi-calendar-multiselect::before{content:"\F0A32"}.mdi-calendar-multiselect-outline::before{content:"\F1B55"}.mdi-calendar-outline::before{content:"\F0B67"}.mdi-calendar-plus::before{content:"\F00F3"}.mdi-calendar-plus-outline::before{content:"\F1B6C"}.mdi-calendar-question::before{content:"\F0692"}.mdi-calendar-question-outline::before{content:"\F1B6D"}.mdi-calendar-range::before{content:"\F0679"}.mdi-calendar-range-outline::before{content:"\F0B68"}.mdi-calendar-refresh::before{content:"\F01E1"}.mdi-calendar-refresh-outline::before{content:"\F0203"}.mdi-calendar-remove::before{content:"\F00F4"}.mdi-calendar-remove-outline::before{content:"\F0C45"}.mdi-calendar-search::before{content:"\F094C"}.mdi-calendar-search-outline::before{content:"\F1B6E"}.mdi-calendar-star::before{content:"\F09D3"}.mdi-calendar-star-four-points::before{content:"\F1C1F"}.mdi-calendar-star-outline::before{content:"\F1B53"}.mdi-calendar-start::before{content:"\F166D"}.mdi-calendar-start-outline::before{content:"\F1B6F"}.mdi-calendar-sync::before{content:"\F0E8E"}.mdi-calendar-sync-outline::before{content:"\F0E8F"}.mdi-calendar-text::before{content:"\F00F5"}.mdi-calendar-text-outline::before{content:"\F0C46"}.mdi-calendar-today::before{content:"\F00F6"}.mdi-calendar-today-outline::before{content:"\F1A30"}.mdi-calendar-week::before{content:"\F0A33"}.mdi-calendar-week-begin::before{content:"\F0A34"}.mdi-calendar-week-begin-outline::before{content:"\F1A31"}.mdi-calendar-week-outline::before{content:"\F1A34"}.mdi-calendar-weekend::before{content:"\F0ED9"}.mdi-calendar-weekend-outline::before{content:"\F0EDA"}.mdi-call-made::before{content:"\F00F7"}.mdi-call-merge::before{content:"\F00F8"}.mdi-call-missed::before{content:"\F00F9"}.mdi-call-received::before{content:"\F00FA"}.mdi-call-split::before{content:"\F00FB"}.mdi-camcorder::before{content:"\F00FC"}.mdi-camcorder-off::before{content:"\F00FF"}.mdi-camera::before{content:"\F0100"}.mdi-camera-account::before{content:"\F08CB"}.mdi-camera-burst::before{content:"\F0693"}.mdi-camera-control::before{content:"\F0B69"}.mdi-camera-document::before{content:"\F1871"}.mdi-camera-document-off::before{content:"\F1872"}.mdi-camera-enhance::before{content:"\F0101"}.mdi-camera-enhance-outline::before{content:"\F0B6A"}.mdi-camera-flip::before{content:"\F15D9"}.mdi-camera-flip-outline::before{content:"\F15DA"}.mdi-camera-front::before{content:"\F0102"}.mdi-camera-front-variant::before{content:"\F0103"}.mdi-camera-gopro::before{content:"\F07A1"}.mdi-camera-image::before{content:"\F08CC"}.mdi-camera-iris::before{content:"\F0104"}.mdi-camera-lock::before{content:"\F1A14"}.mdi-camera-lock-open::before{content:"\F1C0D"}.mdi-camera-lock-open-outline::before{content:"\F1C0E"}.mdi-camera-lock-outline::before{content:"\F1A15"}.mdi-camera-marker::before{content:"\F19A7"}.mdi-camera-marker-outline::before{content:"\F19A8"}.mdi-camera-metering-center::before{content:"\F07A2"}.mdi-camera-metering-matrix::before{content:"\F07A3"}.mdi-camera-metering-partial::before{content:"\F07A4"}.mdi-camera-metering-spot::before{content:"\F07A5"}.mdi-camera-off::before{content:"\F05DF"}.mdi-camera-off-outline::before{content:"\F19BF"}.mdi-camera-outline::before{content:"\F0D5D"}.mdi-camera-party-mode::before{content:"\F0105"}.mdi-camera-plus::before{content:"\F0EDB"}.mdi-camera-plus-outline::before{content:"\F0EDC"}.mdi-camera-rear::before{content:"\F0106"}.mdi-camera-rear-variant::before{content:"\F0107"}.mdi-camera-retake::before{content:"\F0E19"}.mdi-camera-retake-outline::before{content:"\F0E1A"}.mdi-camera-switch::before{content:"\F0108"}.mdi-camera-switch-outline::before{content:"\F084A"}.mdi-camera-timer::before{content:"\F0109"}.mdi-camera-wireless::before{content:"\F0DB6"}.mdi-camera-wireless-outline::before{content:"\F0DB7"}.mdi-campfire::before{content:"\F0EDD"}.mdi-cancel::before{content:"\F073A"}.mdi-candelabra::before{content:"\F17D2"}.mdi-candelabra-fire::before{content:"\F17D3"}.mdi-candle::before{content:"\F05E2"}.mdi-candy::before{content:"\F1970"}.mdi-candy-off::before{content:"\F1971"}.mdi-candy-off-outline::before{content:"\F1972"}.mdi-candy-outline::before{content:"\F1973"}.mdi-candycane::before{content:"\F010A"}.mdi-cannabis::before{content:"\F07A6"}.mdi-cannabis-off::before{content:"\F166E"}.mdi-caps-lock::before{content:"\F0A9B"}.mdi-car::before{content:"\F010B"}.mdi-car-2-plus::before{content:"\F1015"}.mdi-car-3-plus::before{content:"\F1016"}.mdi-car-arrow-left::before{content:"\F13B2"}.mdi-car-arrow-right::before{content:"\F13B3"}.mdi-car-back::before{content:"\F0E1B"}.mdi-car-battery::before{content:"\F010C"}.mdi-car-brake-abs::before{content:"\F0C47"}.mdi-car-brake-alert::before{content:"\F0C48"}.mdi-car-brake-fluid-level::before{content:"\F1909"}.mdi-car-brake-hold::before{content:"\F0D5E"}.mdi-car-brake-low-pressure::before{content:"\F190A"}.mdi-car-brake-parking::before{content:"\F0D5F"}.mdi-car-brake-retarder::before{content:"\F1017"}.mdi-car-brake-temperature::before{content:"\F190B"}.mdi-car-brake-worn-linings::before{content:"\F190C"}.mdi-car-child-seat::before{content:"\F0FA3"}.mdi-car-clock::before{content:"\F1974"}.mdi-car-clutch::before{content:"\F1018"}.mdi-car-cog::before{content:"\F13CC"}.mdi-car-connected::before{content:"\F010D"}.mdi-car-convertible::before{content:"\F07A7"}.mdi-car-coolant-level::before{content:"\F1019"}.mdi-car-cruise-control::before{content:"\F0D60"}.mdi-car-defrost-front::before{content:"\F0D61"}.mdi-car-defrost-rear::before{content:"\F0D62"}.mdi-car-door::before{content:"\F0B6B"}.mdi-car-door-lock::before{content:"\F109D"}.mdi-car-door-lock-open::before{content:"\F1C81"}.mdi-car-electric::before{content:"\F0B6C"}.mdi-car-electric-outline::before{content:"\F15B5"}.mdi-car-emergency::before{content:"\F160F"}.mdi-car-esp::before{content:"\F0C49"}.mdi-car-estate::before{content:"\F07A8"}.mdi-car-hatchback::before{content:"\F07A9"}.mdi-car-info::before{content:"\F11BE"}.mdi-car-key::before{content:"\F0B6D"}.mdi-car-lifted-pickup::before{content:"\F152D"}.mdi-car-light-alert::before{content:"\F190D"}.mdi-car-light-dimmed::before{content:"\F0C4A"}.mdi-car-light-fog::before{content:"\F0C4B"}.mdi-car-light-high::before{content:"\F0C4C"}.mdi-car-limousine::before{content:"\F08CD"}.mdi-car-multiple::before{content:"\F0B6E"}.mdi-car-off::before{content:"\F0E1C"}.mdi-car-outline::before{content:"\F14ED"}.mdi-car-parking-lights::before{content:"\F0D63"}.mdi-car-pickup::before{content:"\F07AA"}.mdi-car-search::before{content:"\F1B8D"}.mdi-car-search-outline::before{content:"\F1B8E"}.mdi-car-seat::before{content:"\F0FA4"}.mdi-car-seat-cooler::before{content:"\F0FA5"}.mdi-car-seat-heater::before{content:"\F0FA6"}.mdi-car-select::before{content:"\F1879"}.mdi-car-settings::before{content:"\F13CD"}.mdi-car-shift-pattern::before{content:"\F0F40"}.mdi-car-side::before{content:"\F07AB"}.mdi-car-speed-limiter::before{content:"\F190E"}.mdi-car-sports::before{content:"\F07AC"}.mdi-car-tire-alert::before{content:"\F0C4D"}.mdi-car-traction-control::before{content:"\F0D64"}.mdi-car-turbocharger::before{content:"\F101A"}.mdi-car-wash::before{content:"\F010E"}.mdi-car-windshield::before{content:"\F101B"}.mdi-car-windshield-outline::before{content:"\F101C"}.mdi-car-wireless::before{content:"\F1878"}.mdi-car-wrench::before{content:"\F1814"}.mdi-carabiner::before{content:"\F14C0"}.mdi-caravan::before{content:"\F07AD"}.mdi-card::before{content:"\F0B6F"}.mdi-card-account-details::before{content:"\F05D2"}.mdi-card-account-details-outline::before{content:"\F0DAB"}.mdi-card-account-details-star::before{content:"\F02A3"}.mdi-card-account-details-star-outline::before{content:"\F06DB"}.mdi-card-account-mail::before{content:"\F018E"}.mdi-card-account-mail-outline::before{content:"\F0E98"}.mdi-card-account-phone::before{content:"\F0E99"}.mdi-card-account-phone-outline::before{content:"\F0E9A"}.mdi-card-bulleted::before{content:"\F0B70"}.mdi-card-bulleted-off::before{content:"\F0B71"}.mdi-card-bulleted-off-outline::before{content:"\F0B72"}.mdi-card-bulleted-outline::before{content:"\F0B73"}.mdi-card-bulleted-settings::before{content:"\F0B74"}.mdi-card-bulleted-settings-outline::before{content:"\F0B75"}.mdi-card-minus::before{content:"\F1600"}.mdi-card-minus-outline::before{content:"\F1601"}.mdi-card-multiple::before{content:"\F17F1"}.mdi-card-multiple-outline::before{content:"\F17F2"}.mdi-card-off::before{content:"\F1602"}.mdi-card-off-outline::before{content:"\F1603"}.mdi-card-outline::before{content:"\F0B76"}.mdi-card-plus::before{content:"\F11FF"}.mdi-card-plus-outline::before{content:"\F1200"}.mdi-card-remove::before{content:"\F1604"}.mdi-card-remove-outline::before{content:"\F1605"}.mdi-card-search::before{content:"\F1074"}.mdi-card-search-outline::before{content:"\F1075"}.mdi-card-text::before{content:"\F0B77"}.mdi-card-text-outline::before{content:"\F0B78"}.mdi-cards::before{content:"\F0638"}.mdi-cards-club::before{content:"\F08CE"}.mdi-cards-club-outline::before{content:"\F189F"}.mdi-cards-diamond::before{content:"\F08CF"}.mdi-cards-diamond-outline::before{content:"\F101D"}.mdi-cards-heart::before{content:"\F08D0"}.mdi-cards-heart-outline::before{content:"\F18A0"}.mdi-cards-outline::before{content:"\F0639"}.mdi-cards-playing::before{content:"\F18A1"}.mdi-cards-playing-club::before{content:"\F18A2"}.mdi-cards-playing-club-multiple::before{content:"\F18A3"}.mdi-cards-playing-club-multiple-outline::before{content:"\F18A4"}.mdi-cards-playing-club-outline::before{content:"\F18A5"}.mdi-cards-playing-diamond::before{content:"\F18A6"}.mdi-cards-playing-diamond-multiple::before{content:"\F18A7"}.mdi-cards-playing-diamond-multiple-outline::before{content:"\F18A8"}.mdi-cards-playing-diamond-outline::before{content:"\F18A9"}.mdi-cards-playing-heart::before{content:"\F18AA"}.mdi-cards-playing-heart-multiple::before{content:"\F18AB"}.mdi-cards-playing-heart-multiple-outline::before{content:"\F18AC"}.mdi-cards-playing-heart-outline::before{content:"\F18AD"}.mdi-cards-playing-outline::before{content:"\F063A"}.mdi-cards-playing-spade::before{content:"\F18AE"}.mdi-cards-playing-spade-multiple::before{content:"\F18AF"}.mdi-cards-playing-spade-multiple-outline::before{content:"\F18B0"}.mdi-cards-playing-spade-outline::before{content:"\F18B1"}.mdi-cards-spade::before{content:"\F08D1"}.mdi-cards-spade-outline::before{content:"\F18B2"}.mdi-cards-variant::before{content:"\F06C7"}.mdi-carrot::before{content:"\F010F"}.mdi-cart::before{content:"\F0110"}.mdi-cart-arrow-down::before{content:"\F0D66"}.mdi-cart-arrow-right::before{content:"\F0C4E"}.mdi-cart-arrow-up::before{content:"\F0D67"}.mdi-cart-check::before{content:"\F15EA"}.mdi-cart-heart::before{content:"\F18E0"}.mdi-cart-minus::before{content:"\F0D68"}.mdi-cart-off::before{content:"\F066B"}.mdi-cart-outline::before{content:"\F0111"}.mdi-cart-percent::before{content:"\F1BAE"}.mdi-cart-plus::before{content:"\F0112"}.mdi-cart-remove::before{content:"\F0D69"}.mdi-cart-variant::before{content:"\F15EB"}.mdi-case-sensitive-alt::before{content:"\F0113"}.mdi-cash::before{content:"\F0114"}.mdi-cash-100::before{content:"\F0115"}.mdi-cash-check::before{content:"\F14EE"}.mdi-cash-clock::before{content:"\F1A91"}.mdi-cash-edit::before{content:"\F1CAB"}.mdi-cash-fast::before{content:"\F185C"}.mdi-cash-lock::before{content:"\F14EA"}.mdi-cash-lock-open::before{content:"\F14EB"}.mdi-cash-marker::before{content:"\F0DB8"}.mdi-cash-minus::before{content:"\F1260"}.mdi-cash-multiple::before{content:"\F0116"}.mdi-cash-off::before{content:"\F1C79"}.mdi-cash-plus::before{content:"\F1261"}.mdi-cash-refund::before{content:"\F0A9C"}.mdi-cash-register::before{content:"\F0CF4"}.mdi-cash-remove::before{content:"\F1262"}.mdi-cash-sync::before{content:"\F1A92"}.mdi-cassette::before{content:"\F09D4"}.mdi-cast::before{content:"\F0118"}.mdi-cast-audio::before{content:"\F101E"}.mdi-cast-audio-variant::before{content:"\F1749"}.mdi-cast-connected::before{content:"\F0119"}.mdi-cast-education::before{content:"\F0E1D"}.mdi-cast-off::before{content:"\F078A"}.mdi-cast-variant::before{content:"\F001F"}.mdi-castle::before{content:"\F011A"}.mdi-cat::before{content:"\F011B"}.mdi-cctv::before{content:"\F07AE"}.mdi-cctv-off::before{content:"\F185F"}.mdi-ceiling-fan::before{content:"\F1797"}.mdi-ceiling-fan-light::before{content:"\F1798"}.mdi-ceiling-light::before{content:"\F0769"}.mdi-ceiling-light-multiple::before{content:"\F18DD"}.mdi-ceiling-light-multiple-outline::before{content:"\F18DE"}.mdi-ceiling-light-outline::before{content:"\F17C7"}.mdi-cellphone::before{content:"\F011C"}.mdi-cellphone-arrow-down::before{content:"\F09D5"}.mdi-cellphone-arrow-down-variant::before{content:"\F19C5"}.mdi-cellphone-basic::before{content:"\F011E"}.mdi-cellphone-charging::before{content:"\F1397"}.mdi-cellphone-check::before{content:"\F17FD"}.mdi-cellphone-cog::before{content:"\F0951"}.mdi-cellphone-dock::before{content:"\F011F"}.mdi-cellphone-information::before{content:"\F0F41"}.mdi-cellphone-key::before{content:"\F094E"}.mdi-cellphone-link::before{content:"\F0121"}.mdi-cellphone-link-off::before{content:"\F0122"}.mdi-cellphone-lock::before{content:"\F094F"}.mdi-cellphone-marker::before{content:"\F183A"}.mdi-cellphone-message::before{content:"\F08D3"}.mdi-cellphone-message-off::before{content:"\F10D2"}.mdi-cellphone-nfc::before{content:"\F0E90"}.mdi-cellphone-nfc-off::before{content:"\F12D8"}.mdi-cellphone-off::before{content:"\F0950"}.mdi-cellphone-play::before{content:"\F101F"}.mdi-cellphone-remove::before{content:"\F094D"}.mdi-cellphone-screenshot::before{content:"\F0A35"}.mdi-cellphone-settings::before{content:"\F0123"}.mdi-cellphone-sound::before{content:"\F0952"}.mdi-cellphone-text::before{content:"\F08D2"}.mdi-cellphone-wireless::before{content:"\F0815"}.mdi-centos::before{content:"\F111A"}.mdi-certificate::before{content:"\F0124"}.mdi-certificate-outline::before{content:"\F1188"}.mdi-chair-rolling::before{content:"\F0F48"}.mdi-chair-school::before{content:"\F0125"}.mdi-chandelier::before{content:"\F1793"}.mdi-charity::before{content:"\F0C4F"}.mdi-charity-search::before{content:"\F1C82"}.mdi-chart-arc::before{content:"\F0126"}.mdi-chart-areaspline::before{content:"\F0127"}.mdi-chart-areaspline-variant::before{content:"\F0E91"}.mdi-chart-bar::before{content:"\F0128"}.mdi-chart-bar-stacked::before{content:"\F076A"}.mdi-chart-bell-curve::before{content:"\F0C50"}.mdi-chart-bell-curve-cumulative::before{content:"\F0FA7"}.mdi-chart-box::before{content:"\F154D"}.mdi-chart-box-multiple::before{content:"\F1CCD"}.mdi-chart-box-multiple-outline::before{content:"\F1CCE"}.mdi-chart-box-outline::before{content:"\F154E"}.mdi-chart-box-plus-outline::before{content:"\F154F"}.mdi-chart-bubble::before{content:"\F05E3"}.mdi-chart-donut::before{content:"\F07AF"}.mdi-chart-donut-variant::before{content:"\F07B0"}.mdi-chart-gantt::before{content:"\F066C"}.mdi-chart-histogram::before{content:"\F0129"}.mdi-chart-line::before{content:"\F012A"}.mdi-chart-line-stacked::before{content:"\F076B"}.mdi-chart-line-variant::before{content:"\F07B1"}.mdi-chart-multiline::before{content:"\F08D4"}.mdi-chart-multiple::before{content:"\F1213"}.mdi-chart-pie::before{content:"\F012B"}.mdi-chart-pie-outline::before{content:"\F1BDF"}.mdi-chart-ppf::before{content:"\F1380"}.mdi-chart-sankey::before{content:"\F11DF"}.mdi-chart-sankey-variant::before{content:"\F11E0"}.mdi-chart-scatter-plot::before{content:"\F0E92"}.mdi-chart-scatter-plot-hexbin::before{content:"\F066D"}.mdi-chart-timeline::before{content:"\F066E"}.mdi-chart-timeline-variant::before{content:"\F0E93"}.mdi-chart-timeline-variant-shimmer::before{content:"\F15B6"}.mdi-chart-tree::before{content:"\F0E94"}.mdi-chart-waterfall::before{content:"\F1918"}.mdi-chat::before{content:"\F0B79"}.mdi-chat-alert::before{content:"\F0B7A"}.mdi-chat-alert-outline::before{content:"\F12C9"}.mdi-chat-minus::before{content:"\F1410"}.mdi-chat-minus-outline::before{content:"\F1413"}.mdi-chat-outline::before{content:"\F0EDE"}.mdi-chat-plus::before{content:"\F140F"}.mdi-chat-plus-outline::before{content:"\F1412"}.mdi-chat-processing::before{content:"\F0B7B"}.mdi-chat-processing-outline::before{content:"\F12CA"}.mdi-chat-question::before{content:"\F1738"}.mdi-chat-question-outline::before{content:"\F1739"}.mdi-chat-remove::before{content:"\F1411"}.mdi-chat-remove-outline::before{content:"\F1414"}.mdi-chat-sleep::before{content:"\F12D1"}.mdi-chat-sleep-outline::before{content:"\F12D2"}.mdi-check::before{content:"\F012C"}.mdi-check-all::before{content:"\F012D"}.mdi-check-bold::before{content:"\F0E1E"}.mdi-check-circle::before{content:"\F05E0"}.mdi-check-circle-outline::before{content:"\F05E1"}.mdi-check-decagram::before{content:"\F0791"}.mdi-check-decagram-outline::before{content:"\F1740"}.mdi-check-network::before{content:"\F0C53"}.mdi-check-network-outline::before{content:"\F0C54"}.mdi-check-outline::before{content:"\F0855"}.mdi-check-underline::before{content:"\F0E1F"}.mdi-check-underline-circle::before{content:"\F0E20"}.mdi-check-underline-circle-outline::before{content:"\F0E21"}.mdi-checkbook::before{content:"\F0A9D"}.mdi-checkbook-arrow-left::before{content:"\F1C1D"}.mdi-checkbook-arrow-right::before{content:"\F1C1E"}.mdi-checkbox-blank::before{content:"\F012E"}.mdi-checkbox-blank-badge::before{content:"\F1176"}.mdi-checkbox-blank-badge-outline::before{content:"\F0117"}.mdi-checkbox-blank-circle::before{content:"\F012F"}.mdi-checkbox-blank-circle-outline::before{content:"\F0130"}.mdi-checkbox-blank-off::before{content:"\F12EC"}.mdi-checkbox-blank-off-outline::before{content:"\F12ED"}.mdi-checkbox-blank-outline::before{content:"\F0131"}.mdi-checkbox-intermediate::before{content:"\F0856"}.mdi-checkbox-intermediate-variant::before{content:"\F1B54"}.mdi-checkbox-marked::before{content:"\F0132"}.mdi-checkbox-marked-circle::before{content:"\F0133"}.mdi-checkbox-marked-circle-auto-outline::before{content:"\F1C26"}.mdi-checkbox-marked-circle-minus-outline::before{content:"\F1C27"}.mdi-checkbox-marked-circle-outline::before{content:"\F0134"}.mdi-checkbox-marked-circle-plus-outline::before{content:"\F1927"}.mdi-checkbox-marked-outline::before{content:"\F0135"}.mdi-checkbox-multiple-blank::before{content:"\F0136"}.mdi-checkbox-multiple-blank-circle::before{content:"\F063B"}.mdi-checkbox-multiple-blank-circle-outline::before{content:"\F063C"}.mdi-checkbox-multiple-blank-outline::before{content:"\F0137"}.mdi-checkbox-multiple-marked::before{content:"\F0138"}.mdi-checkbox-multiple-marked-circle::before{content:"\F063D"}.mdi-checkbox-multiple-marked-circle-outline::before{content:"\F063E"}.mdi-checkbox-multiple-marked-outline::before{content:"\F0139"}.mdi-checkbox-multiple-outline::before{content:"\F0C51"}.mdi-checkbox-outline::before{content:"\F0C52"}.mdi-checkerboard::before{content:"\F013A"}.mdi-checkerboard-minus::before{content:"\F1202"}.mdi-checkerboard-plus::before{content:"\F1201"}.mdi-checkerboard-remove::before{content:"\F1203"}.mdi-cheese::before{content:"\F12B9"}.mdi-cheese-off::before{content:"\F13EE"}.mdi-chef-hat::before{content:"\F0B7C"}.mdi-chemical-weapon::before{content:"\F013B"}.mdi-chess-bishop::before{content:"\F085C"}.mdi-chess-king::before{content:"\F0857"}.mdi-chess-knight::before{content:"\F0858"}.mdi-chess-pawn::before{content:"\F0859"}.mdi-chess-queen::before{content:"\F085A"}.mdi-chess-rook::before{content:"\F085B"}.mdi-chevron-double-down::before{content:"\F013C"}.mdi-chevron-double-left::before{content:"\F013D"}.mdi-chevron-double-right::before{content:"\F013E"}.mdi-chevron-double-up::before{content:"\F013F"}.mdi-chevron-down::before{content:"\F0140"}.mdi-chevron-down-box::before{content:"\F09D6"}.mdi-chevron-down-box-outline::before{content:"\F09D7"}.mdi-chevron-down-circle::before{content:"\F0B26"}.mdi-chevron-down-circle-outline::before{content:"\F0B27"}.mdi-chevron-left::before{content:"\F0141"}.mdi-chevron-left-box::before{content:"\F09D8"}.mdi-chevron-left-box-outline::before{content:"\F09D9"}.mdi-chevron-left-circle::before{content:"\F0B28"}.mdi-chevron-left-circle-outline::before{content:"\F0B29"}.mdi-chevron-right::before{content:"\F0142"}.mdi-chevron-right-box::before{content:"\F09DA"}.mdi-chevron-right-box-outline::before{content:"\F09DB"}.mdi-chevron-right-circle::before{content:"\F0B2A"}.mdi-chevron-right-circle-outline::before{content:"\F0B2B"}.mdi-chevron-triple-down::before{content:"\F0DB9"}.mdi-chevron-triple-left::before{content:"\F0DBA"}.mdi-chevron-triple-right::before{content:"\F0DBB"}.mdi-chevron-triple-up::before{content:"\F0DBC"}.mdi-chevron-up::before{content:"\F0143"}.mdi-chevron-up-box::before{content:"\F09DC"}.mdi-chevron-up-box-outline::before{content:"\F09DD"}.mdi-chevron-up-circle::before{content:"\F0B2C"}.mdi-chevron-up-circle-outline::before{content:"\F0B2D"}.mdi-chili-alert::before{content:"\F17EA"}.mdi-chili-alert-outline::before{content:"\F17EB"}.mdi-chili-hot::before{content:"\F07B2"}.mdi-chili-hot-outline::before{content:"\F17EC"}.mdi-chili-medium::before{content:"\F07B3"}.mdi-chili-medium-outline::before{content:"\F17ED"}.mdi-chili-mild::before{content:"\F07B4"}.mdi-chili-mild-outline::before{content:"\F17EE"}.mdi-chili-off::before{content:"\F1467"}.mdi-chili-off-outline::before{content:"\F17EF"}.mdi-chip::before{content:"\F061A"}.mdi-church::before{content:"\F0144"}.mdi-church-outline::before{content:"\F1B02"}.mdi-cigar::before{content:"\F1189"}.mdi-cigar-off::before{content:"\F141B"}.mdi-circle::before{content:"\F0765"}.mdi-circle-box::before{content:"\F15DC"}.mdi-circle-box-outline::before{content:"\F15DD"}.mdi-circle-double::before{content:"\F0E95"}.mdi-circle-edit-outline::before{content:"\F08D5"}.mdi-circle-expand::before{content:"\F0E96"}.mdi-circle-half::before{content:"\F1395"}.mdi-circle-half-full::before{content:"\F1396"}.mdi-circle-medium::before{content:"\F09DE"}.mdi-circle-multiple::before{content:"\F0B38"}.mdi-circle-multiple-outline::before{content:"\F0695"}.mdi-circle-off-outline::before{content:"\F10D3"}.mdi-circle-opacity::before{content:"\F1853"}.mdi-circle-outline::before{content:"\F0766"}.mdi-circle-slice-1::before{content:"\F0A9E"}.mdi-circle-slice-2::before{content:"\F0A9F"}.mdi-circle-slice-3::before{content:"\F0AA0"}.mdi-circle-slice-4::before{content:"\F0AA1"}.mdi-circle-slice-5::before{content:"\F0AA2"}.mdi-circle-slice-6::before{content:"\F0AA3"}.mdi-circle-slice-7::before{content:"\F0AA4"}.mdi-circle-slice-8::before{content:"\F0AA5"}.mdi-circle-small::before{content:"\F09DF"}.mdi-circular-saw::before{content:"\F0E22"}.mdi-city::before{content:"\F0146"}.mdi-city-switch::before{content:"\F1C28"}.mdi-city-variant::before{content:"\F0A36"}.mdi-city-variant-outline::before{content:"\F0A37"}.mdi-clipboard::before{content:"\F0147"}.mdi-clipboard-account::before{content:"\F0148"}.mdi-clipboard-account-outline::before{content:"\F0C55"}.mdi-clipboard-alert::before{content:"\F0149"}.mdi-clipboard-alert-outline::before{content:"\F0CF7"}.mdi-clipboard-arrow-down::before{content:"\F014A"}.mdi-clipboard-arrow-down-outline::before{content:"\F0C56"}.mdi-clipboard-arrow-left::before{content:"\F014B"}.mdi-clipboard-arrow-left-outline::before{content:"\F0CF8"}.mdi-clipboard-arrow-right::before{content:"\F0CF9"}.mdi-clipboard-arrow-right-outline::before{content:"\F0CFA"}.mdi-clipboard-arrow-up::before{content:"\F0C57"}.mdi-clipboard-arrow-up-outline::before{content:"\F0C58"}.mdi-clipboard-check::before{content:"\F014E"}.mdi-clipboard-check-multiple::before{content:"\F1263"}.mdi-clipboard-check-multiple-outline::before{content:"\F1264"}.mdi-clipboard-check-outline::before{content:"\F08A8"}.mdi-clipboard-clock::before{content:"\F16E2"}.mdi-clipboard-clock-outline::before{content:"\F16E3"}.mdi-clipboard-edit::before{content:"\F14E5"}.mdi-clipboard-edit-outline::before{content:"\F14E6"}.mdi-clipboard-file::before{content:"\F1265"}.mdi-clipboard-file-outline::before{content:"\F1266"}.mdi-clipboard-flow::before{content:"\F06C8"}.mdi-clipboard-flow-outline::before{content:"\F1117"}.mdi-clipboard-list::before{content:"\F10D4"}.mdi-clipboard-list-outline::before{content:"\F10D5"}.mdi-clipboard-minus::before{content:"\F1618"}.mdi-clipboard-minus-outline::before{content:"\F1619"}.mdi-clipboard-multiple::before{content:"\F1267"}.mdi-clipboard-multiple-outline::before{content:"\F1268"}.mdi-clipboard-off::before{content:"\F161A"}.mdi-clipboard-off-outline::before{content:"\F161B"}.mdi-clipboard-outline::before{content:"\F014C"}.mdi-clipboard-play::before{content:"\F0C59"}.mdi-clipboard-play-multiple::before{content:"\F1269"}.mdi-clipboard-play-multiple-outline::before{content:"\F126A"}.mdi-clipboard-play-outline::before{content:"\F0C5A"}.mdi-clipboard-plus::before{content:"\F0751"}.mdi-clipboard-plus-outline::before{content:"\F131F"}.mdi-clipboard-pulse::before{content:"\F085D"}.mdi-clipboard-pulse-outline::before{content:"\F085E"}.mdi-clipboard-remove::before{content:"\F161C"}.mdi-clipboard-remove-outline::before{content:"\F161D"}.mdi-clipboard-search::before{content:"\F161E"}.mdi-clipboard-search-outline::before{content:"\F161F"}.mdi-clipboard-text::before{content:"\F014D"}.mdi-clipboard-text-clock::before{content:"\F18F9"}.mdi-clipboard-text-clock-outline::before{content:"\F18FA"}.mdi-clipboard-text-multiple::before{content:"\F126B"}.mdi-clipboard-text-multiple-outline::before{content:"\F126C"}.mdi-clipboard-text-off::before{content:"\F1620"}.mdi-clipboard-text-off-outline::before{content:"\F1621"}.mdi-clipboard-text-outline::before{content:"\F0A38"}.mdi-clipboard-text-play::before{content:"\F0C5B"}.mdi-clipboard-text-play-outline::before{content:"\F0C5C"}.mdi-clipboard-text-search::before{content:"\F1622"}.mdi-clipboard-text-search-outline::before{content:"\F1623"}.mdi-clippy::before{content:"\F014F"}.mdi-clock::before{content:"\F0954"}.mdi-clock-alert::before{content:"\F0955"}.mdi-clock-alert-outline::before{content:"\F05CE"}.mdi-clock-check::before{content:"\F0FA8"}.mdi-clock-check-outline::before{content:"\F0FA9"}.mdi-clock-digital::before{content:"\F0E97"}.mdi-clock-edit::before{content:"\F19BA"}.mdi-clock-edit-outline::before{content:"\F19BB"}.mdi-clock-end::before{content:"\F0151"}.mdi-clock-fast::before{content:"\F0152"}.mdi-clock-in::before{content:"\F0153"}.mdi-clock-minus::before{content:"\F1863"}.mdi-clock-minus-outline::before{content:"\F1864"}.mdi-clock-out::before{content:"\F0154"}.mdi-clock-outline::before{content:"\F0150"}.mdi-clock-plus::before{content:"\F1861"}.mdi-clock-plus-outline::before{content:"\F1862"}.mdi-clock-remove::before{content:"\F1865"}.mdi-clock-remove-outline::before{content:"\F1866"}.mdi-clock-star-four-points::before{content:"\F1C29"}.mdi-clock-star-four-points-outline::before{content:"\F1C2A"}.mdi-clock-start::before{content:"\F0155"}.mdi-clock-time-eight::before{content:"\F1446"}.mdi-clock-time-eight-outline::before{content:"\F1452"}.mdi-clock-time-eleven::before{content:"\F1449"}.mdi-clock-time-eleven-outline::before{content:"\F1455"}.mdi-clock-time-five::before{content:"\F1443"}.mdi-clock-time-five-outline::before{content:"\F144F"}.mdi-clock-time-four::before{content:"\F1442"}.mdi-clock-time-four-outline::before{content:"\F144E"}.mdi-clock-time-nine::before{content:"\F1447"}.mdi-clock-time-nine-outline::before{content:"\F1453"}.mdi-clock-time-one::before{content:"\F143F"}.mdi-clock-time-one-outline::before{content:"\F144B"}.mdi-clock-time-seven::before{content:"\F1445"}.mdi-clock-time-seven-outline::before{content:"\F1451"}.mdi-clock-time-six::before{content:"\F1444"}.mdi-clock-time-six-outline::before{content:"\F1450"}.mdi-clock-time-ten::before{content:"\F1448"}.mdi-clock-time-ten-outline::before{content:"\F1454"}.mdi-clock-time-three::before{content:"\F1441"}.mdi-clock-time-three-outline::before{content:"\F144D"}.mdi-clock-time-twelve::before{content:"\F144A"}.mdi-clock-time-twelve-outline::before{content:"\F1456"}.mdi-clock-time-two::before{content:"\F1440"}.mdi-clock-time-two-outline::before{content:"\F144C"}.mdi-close::before{content:"\F0156"}.mdi-close-box::before{content:"\F0157"}.mdi-close-box-multiple::before{content:"\F0C5D"}.mdi-close-box-multiple-outline::before{content:"\F0C5E"}.mdi-close-box-outline::before{content:"\F0158"}.mdi-close-circle::before{content:"\F0159"}.mdi-close-circle-multiple::before{content:"\F062A"}.mdi-close-circle-multiple-outline::before{content:"\F0883"}.mdi-close-circle-outline::before{content:"\F015A"}.mdi-close-network::before{content:"\F015B"}.mdi-close-network-outline::before{content:"\F0C5F"}.mdi-close-octagon::before{content:"\F015C"}.mdi-close-octagon-outline::before{content:"\F015D"}.mdi-close-outline::before{content:"\F06C9"}.mdi-close-thick::before{content:"\F1398"}.mdi-closed-caption::before{content:"\F015E"}.mdi-closed-caption-outline::before{content:"\F0DBD"}.mdi-cloud::before{content:"\F015F"}.mdi-cloud-alert::before{content:"\F09E0"}.mdi-cloud-alert-outline::before{content:"\F1BE0"}.mdi-cloud-arrow-down::before{content:"\F1BE1"}.mdi-cloud-arrow-down-outline::before{content:"\F1BE2"}.mdi-cloud-arrow-left::before{content:"\F1BE3"}.mdi-cloud-arrow-left-outline::before{content:"\F1BE4"}.mdi-cloud-arrow-right::before{content:"\F1BE5"}.mdi-cloud-arrow-right-outline::before{content:"\F1BE6"}.mdi-cloud-arrow-up::before{content:"\F1BE7"}.mdi-cloud-arrow-up-outline::before{content:"\F1BE8"}.mdi-cloud-braces::before{content:"\F07B5"}.mdi-cloud-cancel::before{content:"\F1BE9"}.mdi-cloud-cancel-outline::before{content:"\F1BEA"}.mdi-cloud-check::before{content:"\F1BEB"}.mdi-cloud-check-outline::before{content:"\F1BEC"}.mdi-cloud-check-variant::before{content:"\F0160"}.mdi-cloud-check-variant-outline::before{content:"\F12CC"}.mdi-cloud-circle::before{content:"\F0161"}.mdi-cloud-circle-outline::before{content:"\F1BED"}.mdi-cloud-clock::before{content:"\F1BEE"}.mdi-cloud-clock-outline::before{content:"\F1BEF"}.mdi-cloud-cog::before{content:"\F1BF0"}.mdi-cloud-cog-outline::before{content:"\F1BF1"}.mdi-cloud-download::before{content:"\F0162"}.mdi-cloud-download-outline::before{content:"\F0B7D"}.mdi-cloud-key::before{content:"\F1CA1"}.mdi-cloud-key-outline::before{content:"\F1CA2"}.mdi-cloud-lock::before{content:"\F11F1"}.mdi-cloud-lock-open::before{content:"\F1BF2"}.mdi-cloud-lock-open-outline::before{content:"\F1BF3"}.mdi-cloud-lock-outline::before{content:"\F11F2"}.mdi-cloud-minus::before{content:"\F1BF4"}.mdi-cloud-minus-outline::before{content:"\F1BF5"}.mdi-cloud-off::before{content:"\F1BF6"}.mdi-cloud-off-outline::before{content:"\F0164"}.mdi-cloud-outline::before{content:"\F0163"}.mdi-cloud-percent::before{content:"\F1A35"}.mdi-cloud-percent-outline::before{content:"\F1A36"}.mdi-cloud-plus::before{content:"\F1BF7"}.mdi-cloud-plus-outline::before{content:"\F1BF8"}.mdi-cloud-print::before{content:"\F0165"}.mdi-cloud-print-outline::before{content:"\F0166"}.mdi-cloud-question::before{content:"\F0A39"}.mdi-cloud-question-outline::before{content:"\F1BF9"}.mdi-cloud-refresh::before{content:"\F1BFA"}.mdi-cloud-refresh-outline::before{content:"\F1BFB"}.mdi-cloud-refresh-variant::before{content:"\F052A"}.mdi-cloud-refresh-variant-outline::before{content:"\F1BFC"}.mdi-cloud-remove::before{content:"\F1BFD"}.mdi-cloud-remove-outline::before{content:"\F1BFE"}.mdi-cloud-search::before{content:"\F0956"}.mdi-cloud-search-outline::before{content:"\F0957"}.mdi-cloud-sync::before{content:"\F063F"}.mdi-cloud-sync-outline::before{content:"\F12D6"}.mdi-cloud-tags::before{content:"\F07B6"}.mdi-cloud-upload::before{content:"\F0167"}.mdi-cloud-upload-outline::before{content:"\F0B7E"}.mdi-clouds::before{content:"\F1B95"}.mdi-clover::before{content:"\F0816"}.mdi-clover-outline::before{content:"\F1C62"}.mdi-coach-lamp::before{content:"\F1020"}.mdi-coach-lamp-variant::before{content:"\F1A37"}.mdi-coat-rack::before{content:"\F109E"}.mdi-code-array::before{content:"\F0168"}.mdi-code-block-braces::before{content:"\F1C83"}.mdi-code-block-brackets::before{content:"\F1C84"}.mdi-code-block-parentheses::before{content:"\F1C85"}.mdi-code-block-tags::before{content:"\F1C86"}.mdi-code-braces::before{content:"\F0169"}.mdi-code-braces-box::before{content:"\F10D6"}.mdi-code-brackets::before{content:"\F016A"}.mdi-code-equal::before{content:"\F016B"}.mdi-code-greater-than::before{content:"\F016C"}.mdi-code-greater-than-or-equal::before{content:"\F016D"}.mdi-code-json::before{content:"\F0626"}.mdi-code-less-than::before{content:"\F016E"}.mdi-code-less-than-or-equal::before{content:"\F016F"}.mdi-code-not-equal::before{content:"\F0170"}.mdi-code-not-equal-variant::before{content:"\F0171"}.mdi-code-parentheses::before{content:"\F0172"}.mdi-code-parentheses-box::before{content:"\F10D7"}.mdi-code-string::before{content:"\F0173"}.mdi-code-tags::before{content:"\F0174"}.mdi-code-tags-check::before{content:"\F0694"}.mdi-codepen::before{content:"\F0175"}.mdi-coffee::before{content:"\F0176"}.mdi-coffee-maker::before{content:"\F109F"}.mdi-coffee-maker-check::before{content:"\F1931"}.mdi-coffee-maker-check-outline::before{content:"\F1932"}.mdi-coffee-maker-outline::before{content:"\F181B"}.mdi-coffee-off::before{content:"\F0FAA"}.mdi-coffee-off-outline::before{content:"\F0FAB"}.mdi-coffee-outline::before{content:"\F06CA"}.mdi-coffee-to-go::before{content:"\F0177"}.mdi-coffee-to-go-outline::before{content:"\F130E"}.mdi-coffin::before{content:"\F0B7F"}.mdi-cog::before{content:"\F0493"}.mdi-cog-box::before{content:"\F0494"}.mdi-cog-clockwise::before{content:"\F11DD"}.mdi-cog-counterclockwise::before{content:"\F11DE"}.mdi-cog-off::before{content:"\F13CE"}.mdi-cog-off-outline::before{content:"\F13CF"}.mdi-cog-outline::before{content:"\F08BB"}.mdi-cog-pause::before{content:"\F1933"}.mdi-cog-pause-outline::before{content:"\F1934"}.mdi-cog-play::before{content:"\F1935"}.mdi-cog-play-outline::before{content:"\F1936"}.mdi-cog-refresh::before{content:"\F145E"}.mdi-cog-refresh-outline::before{content:"\F145F"}.mdi-cog-stop::before{content:"\F1937"}.mdi-cog-stop-outline::before{content:"\F1938"}.mdi-cog-sync::before{content:"\F1460"}.mdi-cog-sync-outline::before{content:"\F1461"}.mdi-cog-transfer::before{content:"\F105B"}.mdi-cog-transfer-outline::before{content:"\F105C"}.mdi-cogs::before{content:"\F08D6"}.mdi-collage::before{content:"\F0640"}.mdi-collapse-all::before{content:"\F0AA6"}.mdi-collapse-all-outline::before{content:"\F0AA7"}.mdi-color-helper::before{content:"\F0179"}.mdi-comma::before{content:"\F0E23"}.mdi-comma-box::before{content:"\F0E2B"}.mdi-comma-box-outline::before{content:"\F0E24"}.mdi-comma-circle::before{content:"\F0E25"}.mdi-comma-circle-outline::before{content:"\F0E26"}.mdi-comment::before{content:"\F017A"}.mdi-comment-account::before{content:"\F017B"}.mdi-comment-account-outline::before{content:"\F017C"}.mdi-comment-alert::before{content:"\F017D"}.mdi-comment-alert-outline::before{content:"\F017E"}.mdi-comment-arrow-left::before{content:"\F09E1"}.mdi-comment-arrow-left-outline::before{content:"\F09E2"}.mdi-comment-arrow-right::before{content:"\F09E3"}.mdi-comment-arrow-right-outline::before{content:"\F09E4"}.mdi-comment-bookmark::before{content:"\F15AE"}.mdi-comment-bookmark-outline::before{content:"\F15AF"}.mdi-comment-check::before{content:"\F017F"}.mdi-comment-check-outline::before{content:"\F0180"}.mdi-comment-edit::before{content:"\F11BF"}.mdi-comment-edit-outline::before{content:"\F12C4"}.mdi-comment-eye::before{content:"\F0A3A"}.mdi-comment-eye-outline::before{content:"\F0A3B"}.mdi-comment-flash::before{content:"\F15B0"}.mdi-comment-flash-outline::before{content:"\F15B1"}.mdi-comment-minus::before{content:"\F15DF"}.mdi-comment-minus-outline::before{content:"\F15E0"}.mdi-comment-multiple::before{content:"\F085F"}.mdi-comment-multiple-outline::before{content:"\F0181"}.mdi-comment-off::before{content:"\F15E1"}.mdi-comment-off-outline::before{content:"\F15E2"}.mdi-comment-outline::before{content:"\F0182"}.mdi-comment-plus::before{content:"\F09E5"}.mdi-comment-plus-outline::before{content:"\F0183"}.mdi-comment-processing::before{content:"\F0184"}.mdi-comment-processing-outline::before{content:"\F0185"}.mdi-comment-question::before{content:"\F0817"}.mdi-comment-question-outline::before{content:"\F0186"}.mdi-comment-quote::before{content:"\F1021"}.mdi-comment-quote-outline::before{content:"\F1022"}.mdi-comment-remove::before{content:"\F05DE"}.mdi-comment-remove-outline::before{content:"\F0187"}.mdi-comment-search::before{content:"\F0A3C"}.mdi-comment-search-outline::before{content:"\F0A3D"}.mdi-comment-text::before{content:"\F0188"}.mdi-comment-text-multiple::before{content:"\F0860"}.mdi-comment-text-multiple-outline::before{content:"\F0861"}.mdi-comment-text-outline::before{content:"\F0189"}.mdi-compare::before{content:"\F018A"}.mdi-compare-horizontal::before{content:"\F1492"}.mdi-compare-remove::before{content:"\F18B3"}.mdi-compare-vertical::before{content:"\F1493"}.mdi-compass::before{content:"\F018B"}.mdi-compass-off::before{content:"\F0B80"}.mdi-compass-off-outline::before{content:"\F0B81"}.mdi-compass-outline::before{content:"\F018C"}.mdi-compass-rose::before{content:"\F1382"}.mdi-compost::before{content:"\F1A38"}.mdi-cone::before{content:"\F194C"}.mdi-cone-off::before{content:"\F194D"}.mdi-connection::before{content:"\F1616"}.mdi-console::before{content:"\F018D"}.mdi-console-line::before{content:"\F07B7"}.mdi-console-network::before{content:"\F08A9"}.mdi-console-network-outline::before{content:"\F0C60"}.mdi-consolidate::before{content:"\F10D8"}.mdi-contactless-payment::before{content:"\F0D6A"}.mdi-contactless-payment-circle::before{content:"\F0321"}.mdi-contactless-payment-circle-outline::before{content:"\F0408"}.mdi-contacts::before{content:"\F06CB"}.mdi-contacts-outline::before{content:"\F05B8"}.mdi-contain::before{content:"\F0A3E"}.mdi-contain-end::before{content:"\F0A3F"}.mdi-contain-start::before{content:"\F0A40"}.mdi-content-copy::before{content:"\F018F"}.mdi-content-cut::before{content:"\F0190"}.mdi-content-duplicate::before{content:"\F0191"}.mdi-content-paste::before{content:"\F0192"}.mdi-content-save::before{content:"\F0193"}.mdi-content-save-alert::before{content:"\F0F42"}.mdi-content-save-alert-outline::before{content:"\F0F43"}.mdi-content-save-all::before{content:"\F0194"}.mdi-content-save-all-outline::before{content:"\F0F44"}.mdi-content-save-check::before{content:"\F18EA"}.mdi-content-save-check-outline::before{content:"\F18EB"}.mdi-content-save-cog::before{content:"\F145B"}.mdi-content-save-cog-outline::before{content:"\F145C"}.mdi-content-save-edit::before{content:"\F0CFB"}.mdi-content-save-edit-outline::before{content:"\F0CFC"}.mdi-content-save-minus::before{content:"\F1B43"}.mdi-content-save-minus-outline::before{content:"\F1B44"}.mdi-content-save-move::before{content:"\F0E27"}.mdi-content-save-move-outline::before{content:"\F0E28"}.mdi-content-save-off::before{content:"\F1643"}.mdi-content-save-off-outline::before{content:"\F1644"}.mdi-content-save-outline::before{content:"\F0818"}.mdi-content-save-plus::before{content:"\F1B41"}.mdi-content-save-plus-outline::before{content:"\F1B42"}.mdi-content-save-settings::before{content:"\F061B"}.mdi-content-save-settings-outline::before{content:"\F0B2E"}.mdi-contrast::before{content:"\F0195"}.mdi-contrast-box::before{content:"\F0196"}.mdi-contrast-circle::before{content:"\F0197"}.mdi-controller::before{content:"\F02B4"}.mdi-controller-classic::before{content:"\F0B82"}.mdi-controller-classic-outline::before{content:"\F0B83"}.mdi-controller-off::before{content:"\F02B5"}.mdi-cookie::before{content:"\F0198"}.mdi-cookie-alert::before{content:"\F16D0"}.mdi-cookie-alert-outline::before{content:"\F16D1"}.mdi-cookie-check::before{content:"\F16D2"}.mdi-cookie-check-outline::before{content:"\F16D3"}.mdi-cookie-clock::before{content:"\F16E4"}.mdi-cookie-clock-outline::before{content:"\F16E5"}.mdi-cookie-cog::before{content:"\F16D4"}.mdi-cookie-cog-outline::before{content:"\F16D5"}.mdi-cookie-edit::before{content:"\F16E6"}.mdi-cookie-edit-outline::before{content:"\F16E7"}.mdi-cookie-lock::before{content:"\F16E8"}.mdi-cookie-lock-outline::before{content:"\F16E9"}.mdi-cookie-minus::before{content:"\F16DA"}.mdi-cookie-minus-outline::before{content:"\F16DB"}.mdi-cookie-off::before{content:"\F16EA"}.mdi-cookie-off-outline::before{content:"\F16EB"}.mdi-cookie-outline::before{content:"\F16DE"}.mdi-cookie-plus::before{content:"\F16D6"}.mdi-cookie-plus-outline::before{content:"\F16D7"}.mdi-cookie-refresh::before{content:"\F16EC"}.mdi-cookie-refresh-outline::before{content:"\F16ED"}.mdi-cookie-remove::before{content:"\F16D8"}.mdi-cookie-remove-outline::before{content:"\F16D9"}.mdi-cookie-settings::before{content:"\F16DC"}.mdi-cookie-settings-outline::before{content:"\F16DD"}.mdi-coolant-temperature::before{content:"\F03C8"}.mdi-copyleft::before{content:"\F1939"}.mdi-copyright::before{content:"\F05E6"}.mdi-cordova::before{content:"\F0958"}.mdi-corn::before{content:"\F07B8"}.mdi-corn-off::before{content:"\F13EF"}.mdi-cosine-wave::before{content:"\F1479"}.mdi-counter::before{content:"\F0199"}.mdi-countertop::before{content:"\F181C"}.mdi-countertop-outline::before{content:"\F181D"}.mdi-cow::before{content:"\F019A"}.mdi-cow-off::before{content:"\F18FC"}.mdi-cpu-32-bit::before{content:"\F0EDF"}.mdi-cpu-64-bit::before{content:"\F0EE0"}.mdi-cradle::before{content:"\F198B"}.mdi-cradle-outline::before{content:"\F1991"}.mdi-crane::before{content:"\F0862"}.mdi-creation::before{content:"\F0674"}.mdi-creation-outline::before{content:"\F1C2B"}.mdi-creative-commons::before{content:"\F0D6B"}.mdi-credit-card::before{content:"\F0FEF"}.mdi-credit-card-check::before{content:"\F13D0"}.mdi-credit-card-check-outline::before{content:"\F13D1"}.mdi-credit-card-chip::before{content:"\F190F"}.mdi-credit-card-chip-outline::before{content:"\F1910"}.mdi-credit-card-clock::before{content:"\F0EE1"}.mdi-credit-card-clock-outline::before{content:"\F0EE2"}.mdi-credit-card-edit::before{content:"\F17D7"}.mdi-credit-card-edit-outline::before{content:"\F17D8"}.mdi-credit-card-fast::before{content:"\F1911"}.mdi-credit-card-fast-outline::before{content:"\F1912"}.mdi-credit-card-lock::before{content:"\F18E7"}.mdi-credit-card-lock-outline::before{content:"\F18E8"}.mdi-credit-card-marker::before{content:"\F06A8"}.mdi-credit-card-marker-outline::before{content:"\F0DBE"}.mdi-credit-card-minus::before{content:"\F0FAC"}.mdi-credit-card-minus-outline::before{content:"\F0FAD"}.mdi-credit-card-multiple::before{content:"\F0FF0"}.mdi-credit-card-multiple-outline::before{content:"\F019C"}.mdi-credit-card-off::before{content:"\F0FF1"}.mdi-credit-card-off-outline::before{content:"\F05E4"}.mdi-credit-card-outline::before{content:"\F019B"}.mdi-credit-card-plus::before{content:"\F0FF2"}.mdi-credit-card-plus-outline::before{content:"\F0676"}.mdi-credit-card-refresh::before{content:"\F1645"}.mdi-credit-card-refresh-outline::before{content:"\F1646"}.mdi-credit-card-refund::before{content:"\F0FF3"}.mdi-credit-card-refund-outline::before{content:"\F0AA8"}.mdi-credit-card-remove::before{content:"\F0FAE"}.mdi-credit-card-remove-outline::before{content:"\F0FAF"}.mdi-credit-card-scan::before{content:"\F0FF4"}.mdi-credit-card-scan-outline::before{content:"\F019D"}.mdi-credit-card-search::before{content:"\F1647"}.mdi-credit-card-search-outline::before{content:"\F1648"}.mdi-credit-card-settings::before{content:"\F0FF5"}.mdi-credit-card-settings-outline::before{content:"\F08D7"}.mdi-credit-card-sync::before{content:"\F1649"}.mdi-credit-card-sync-outline::before{content:"\F164A"}.mdi-credit-card-wireless::before{content:"\F0802"}.mdi-credit-card-wireless-off::before{content:"\F057A"}.mdi-credit-card-wireless-off-outline::before{content:"\F057B"}.mdi-credit-card-wireless-outline::before{content:"\F0D6C"}.mdi-cricket::before{content:"\F0D6D"}.mdi-crop::before{content:"\F019E"}.mdi-crop-free::before{content:"\F019F"}.mdi-crop-landscape::before{content:"\F01A0"}.mdi-crop-portrait::before{content:"\F01A1"}.mdi-crop-rotate::before{content:"\F0696"}.mdi-crop-square::before{content:"\F01A2"}.mdi-cross::before{content:"\F0953"}.mdi-cross-bolnisi::before{content:"\F0CED"}.mdi-cross-celtic::before{content:"\F0CF5"}.mdi-cross-outline::before{content:"\F0CF6"}.mdi-crosshairs::before{content:"\F01A3"}.mdi-crosshairs-gps::before{content:"\F01A4"}.mdi-crosshairs-off::before{content:"\F0F45"}.mdi-crosshairs-question::before{content:"\F1136"}.mdi-crowd::before{content:"\F1975"}.mdi-crown::before{content:"\F01A5"}.mdi-crown-circle::before{content:"\F17DC"}.mdi-crown-circle-outline::before{content:"\F17DD"}.mdi-crown-outline::before{content:"\F11D0"}.mdi-cryengine::before{content:"\F0959"}.mdi-crystal-ball::before{content:"\F0B2F"}.mdi-cube::before{content:"\F01A6"}.mdi-cube-off::before{content:"\F141C"}.mdi-cube-off-outline::before{content:"\F141D"}.mdi-cube-outline::before{content:"\F01A7"}.mdi-cube-scan::before{content:"\F0B84"}.mdi-cube-send::before{content:"\F01A8"}.mdi-cube-unfolded::before{content:"\F01A9"}.mdi-cup::before{content:"\F01AA"}.mdi-cup-off::before{content:"\F05E5"}.mdi-cup-off-outline::before{content:"\F137D"}.mdi-cup-outline::before{content:"\F130F"}.mdi-cup-water::before{content:"\F01AB"}.mdi-cupboard::before{content:"\F0F46"}.mdi-cupboard-outline::before{content:"\F0F47"}.mdi-cupcake::before{content:"\F095A"}.mdi-curling::before{content:"\F0863"}.mdi-currency-bdt::before{content:"\F0864"}.mdi-currency-brl::before{content:"\F0B85"}.mdi-currency-btc::before{content:"\F01AC"}.mdi-currency-cny::before{content:"\F07BA"}.mdi-currency-eth::before{content:"\F07BB"}.mdi-currency-eur::before{content:"\F01AD"}.mdi-currency-eur-off::before{content:"\F1315"}.mdi-currency-fra::before{content:"\F1A39"}.mdi-currency-gbp::before{content:"\F01AE"}.mdi-currency-ils::before{content:"\F0C61"}.mdi-currency-inr::before{content:"\F01AF"}.mdi-currency-jpy::before{content:"\F07BC"}.mdi-currency-krw::before{content:"\F07BD"}.mdi-currency-kzt::before{content:"\F0865"}.mdi-currency-mnt::before{content:"\F1512"}.mdi-currency-ngn::before{content:"\F01B0"}.mdi-currency-php::before{content:"\F09E6"}.mdi-currency-rial::before{content:"\F0E9C"}.mdi-currency-rub::before{content:"\F01B1"}.mdi-currency-rupee::before{content:"\F1976"}.mdi-currency-sign::before{content:"\F07BE"}.mdi-currency-thb::before{content:"\F1C05"}.mdi-currency-try::before{content:"\F01B2"}.mdi-currency-twd::before{content:"\F07BF"}.mdi-currency-uah::before{content:"\F1B9B"}.mdi-currency-usd::before{content:"\F01C1"}.mdi-currency-usd-off::before{content:"\F067A"}.mdi-current-ac::before{content:"\F1480"}.mdi-current-dc::before{content:"\F095C"}.mdi-cursor-default::before{content:"\F01C0"}.mdi-cursor-default-click::before{content:"\F0CFD"}.mdi-cursor-default-click-outline::before{content:"\F0CFE"}.mdi-cursor-default-gesture::before{content:"\F1127"}.mdi-cursor-default-gesture-outline::before{content:"\F1128"}.mdi-cursor-default-outline::before{content:"\F01BF"}.mdi-cursor-move::before{content:"\F01BE"}.mdi-cursor-pointer::before{content:"\F01BD"}.mdi-cursor-text::before{content:"\F05E7"}.mdi-curtains::before{content:"\F1846"}.mdi-curtains-closed::before{content:"\F1847"}.mdi-cylinder::before{content:"\F194E"}.mdi-cylinder-off::before{content:"\F194F"}.mdi-dance-ballroom::before{content:"\F15FB"}.mdi-dance-pole::before{content:"\F1578"}.mdi-data-matrix::before{content:"\F153C"}.mdi-data-matrix-edit::before{content:"\F153D"}.mdi-data-matrix-minus::before{content:"\F153E"}.mdi-data-matrix-plus::before{content:"\F153F"}.mdi-data-matrix-remove::before{content:"\F1540"}.mdi-data-matrix-scan::before{content:"\F1541"}.mdi-database::before{content:"\F01BC"}.mdi-database-alert::before{content:"\F163A"}.mdi-database-alert-outline::before{content:"\F1624"}.mdi-database-arrow-down::before{content:"\F163B"}.mdi-database-arrow-down-outline::before{content:"\F1625"}.mdi-database-arrow-left::before{content:"\F163C"}.mdi-database-arrow-left-outline::before{content:"\F1626"}.mdi-database-arrow-right::before{content:"\F163D"}.mdi-database-arrow-right-outline::before{content:"\F1627"}.mdi-database-arrow-up::before{content:"\F163E"}.mdi-database-arrow-up-outline::before{content:"\F1628"}.mdi-database-check::before{content:"\F0AA9"}.mdi-database-check-outline::before{content:"\F1629"}.mdi-database-clock::before{content:"\F163F"}.mdi-database-clock-outline::before{content:"\F162A"}.mdi-database-cog::before{content:"\F164B"}.mdi-database-cog-outline::before{content:"\F164C"}.mdi-database-edit::before{content:"\F0B86"}.mdi-database-edit-outline::before{content:"\F162B"}.mdi-database-export::before{content:"\F095E"}.mdi-database-export-outline::before{content:"\F162C"}.mdi-database-eye::before{content:"\F191F"}.mdi-database-eye-off::before{content:"\F1920"}.mdi-database-eye-off-outline::before{content:"\F1921"}.mdi-database-eye-outline::before{content:"\F1922"}.mdi-database-import::before{content:"\F095D"}.mdi-database-import-outline::before{content:"\F162D"}.mdi-database-lock::before{content:"\F0AAA"}.mdi-database-lock-outline::before{content:"\F162E"}.mdi-database-marker::before{content:"\F12F6"}.mdi-database-marker-outline::before{content:"\F162F"}.mdi-database-minus::before{content:"\F01BB"}.mdi-database-minus-outline::before{content:"\F1630"}.mdi-database-off::before{content:"\F1640"}.mdi-database-off-outline::before{content:"\F1631"}.mdi-database-outline::before{content:"\F1632"}.mdi-database-plus::before{content:"\F01BA"}.mdi-database-plus-outline::before{content:"\F1633"}.mdi-database-refresh::before{content:"\F05C2"}.mdi-database-refresh-outline::before{content:"\F1634"}.mdi-database-remove::before{content:"\F0D00"}.mdi-database-remove-outline::before{content:"\F1635"}.mdi-database-search::before{content:"\F0866"}.mdi-database-search-outline::before{content:"\F1636"}.mdi-database-settings::before{content:"\F0D01"}.mdi-database-settings-outline::before{content:"\F1637"}.mdi-database-sync::before{content:"\F0CFF"}.mdi-database-sync-outline::before{content:"\F1638"}.mdi-death-star::before{content:"\F08D8"}.mdi-death-star-variant::before{content:"\F08D9"}.mdi-deathly-hallows::before{content:"\F0B87"}.mdi-debian::before{content:"\F08DA"}.mdi-debug-step-into::before{content:"\F01B9"}.mdi-debug-step-out::before{content:"\F01B8"}.mdi-debug-step-over::before{content:"\F01B7"}.mdi-decagram::before{content:"\F076C"}.mdi-decagram-outline::before{content:"\F076D"}.mdi-decimal::before{content:"\F10A1"}.mdi-decimal-comma::before{content:"\F10A2"}.mdi-decimal-comma-decrease::before{content:"\F10A3"}.mdi-decimal-comma-increase::before{content:"\F10A4"}.mdi-decimal-decrease::before{content:"\F01B6"}.mdi-decimal-increase::before{content:"\F01B5"}.mdi-delete::before{content:"\F01B4"}.mdi-delete-alert::before{content:"\F10A5"}.mdi-delete-alert-outline::before{content:"\F10A6"}.mdi-delete-circle::before{content:"\F0683"}.mdi-delete-circle-outline::before{content:"\F0B88"}.mdi-delete-clock::before{content:"\F1556"}.mdi-delete-clock-outline::before{content:"\F1557"}.mdi-delete-empty::before{content:"\F06CC"}.mdi-delete-empty-outline::before{content:"\F0E9D"}.mdi-delete-forever::before{content:"\F05E8"}.mdi-delete-forever-outline::before{content:"\F0B89"}.mdi-delete-off::before{content:"\F10A7"}.mdi-delete-off-outline::before{content:"\F10A8"}.mdi-delete-outline::before{content:"\F09E7"}.mdi-delete-restore::before{content:"\F0819"}.mdi-delete-sweep::before{content:"\F05E9"}.mdi-delete-sweep-outline::before{content:"\F0C62"}.mdi-delete-variant::before{content:"\F01B3"}.mdi-delta::before{content:"\F01C2"}.mdi-desk::before{content:"\F1239"}.mdi-desk-lamp::before{content:"\F095F"}.mdi-desk-lamp-off::before{content:"\F1B1F"}.mdi-desk-lamp-on::before{content:"\F1B20"}.mdi-deskphone::before{content:"\F01C3"}.mdi-desktop-classic::before{content:"\F07C0"}.mdi-desktop-tower::before{content:"\F01C5"}.mdi-desktop-tower-monitor::before{content:"\F0AAB"}.mdi-details::before{content:"\F01C6"}.mdi-dev-to::before{content:"\F0D6E"}.mdi-developer-board::before{content:"\F0697"}.mdi-deviantart::before{content:"\F01C7"}.mdi-devices::before{content:"\F0FB0"}.mdi-dharmachakra::before{content:"\F094B"}.mdi-diabetes::before{content:"\F1126"}.mdi-dialpad::before{content:"\F061C"}.mdi-diameter::before{content:"\F0C63"}.mdi-diameter-outline::before{content:"\F0C64"}.mdi-diameter-variant::before{content:"\F0C65"}.mdi-diamond::before{content:"\F0B8A"}.mdi-diamond-outline::before{content:"\F0B8B"}.mdi-diamond-stone::before{content:"\F01C8"}.mdi-diaper-outline::before{content:"\F1CCF"}.mdi-dice-1::before{content:"\F01CA"}.mdi-dice-1-outline::before{content:"\F114A"}.mdi-dice-2::before{content:"\F01CB"}.mdi-dice-2-outline::before{content:"\F114B"}.mdi-dice-3::before{content:"\F01CC"}.mdi-dice-3-outline::before{content:"\F114C"}.mdi-dice-4::before{content:"\F01CD"}.mdi-dice-4-outline::before{content:"\F114D"}.mdi-dice-5::before{content:"\F01CE"}.mdi-dice-5-outline::before{content:"\F114E"}.mdi-dice-6::before{content:"\F01CF"}.mdi-dice-6-outline::before{content:"\F114F"}.mdi-dice-d10::before{content:"\F1153"}.mdi-dice-d10-outline::before{content:"\F076F"}.mdi-dice-d12::before{content:"\F1154"}.mdi-dice-d12-outline::before{content:"\F0867"}.mdi-dice-d20::before{content:"\F1155"}.mdi-dice-d20-outline::before{content:"\F05EA"}.mdi-dice-d4::before{content:"\F1150"}.mdi-dice-d4-outline::before{content:"\F05EB"}.mdi-dice-d6::before{content:"\F1151"}.mdi-dice-d6-outline::before{content:"\F05ED"}.mdi-dice-d8::before{content:"\F1152"}.mdi-dice-d8-outline::before{content:"\F05EC"}.mdi-dice-multiple::before{content:"\F076E"}.mdi-dice-multiple-outline::before{content:"\F1156"}.mdi-digital-ocean::before{content:"\F1237"}.mdi-dip-switch::before{content:"\F07C1"}.mdi-directions::before{content:"\F01D0"}.mdi-directions-fork::before{content:"\F0641"}.mdi-disc::before{content:"\F05EE"}.mdi-disc-alert::before{content:"\F01D1"}.mdi-disc-player::before{content:"\F0960"}.mdi-dishwasher::before{content:"\F0AAC"}.mdi-dishwasher-alert::before{content:"\F11B8"}.mdi-dishwasher-off::before{content:"\F11B9"}.mdi-disqus::before{content:"\F01D2"}.mdi-distribute-horizontal-center::before{content:"\F11C9"}.mdi-distribute-horizontal-left::before{content:"\F11C8"}.mdi-distribute-horizontal-right::before{content:"\F11CA"}.mdi-distribute-vertical-bottom::before{content:"\F11CB"}.mdi-distribute-vertical-center::before{content:"\F11CC"}.mdi-distribute-vertical-top::before{content:"\F11CD"}.mdi-diversify::before{content:"\F1877"}.mdi-diving::before{content:"\F1977"}.mdi-diving-flippers::before{content:"\F0DBF"}.mdi-diving-helmet::before{content:"\F0DC0"}.mdi-diving-scuba::before{content:"\F1B77"}.mdi-diving-scuba-flag::before{content:"\F0DC2"}.mdi-diving-scuba-mask::before{content:"\F0DC1"}.mdi-diving-scuba-tank::before{content:"\F0DC3"}.mdi-diving-scuba-tank-multiple::before{content:"\F0DC4"}.mdi-diving-snorkel::before{content:"\F0DC5"}.mdi-division::before{content:"\F01D4"}.mdi-division-box::before{content:"\F01D5"}.mdi-dlna::before{content:"\F0A41"}.mdi-dna::before{content:"\F0684"}.mdi-dns::before{content:"\F01D6"}.mdi-dns-outline::before{content:"\F0B8C"}.mdi-dock-bottom::before{content:"\F10A9"}.mdi-dock-left::before{content:"\F10AA"}.mdi-dock-right::before{content:"\F10AB"}.mdi-dock-top::before{content:"\F1513"}.mdi-dock-window::before{content:"\F10AC"}.mdi-docker::before{content:"\F0868"}.mdi-doctor::before{content:"\F0A42"}.mdi-dog::before{content:"\F0A43"}.mdi-dog-service::before{content:"\F0AAD"}.mdi-dog-side::before{content:"\F0A44"}.mdi-dog-side-off::before{content:"\F16EE"}.mdi-dolby::before{content:"\F06B3"}.mdi-dolly::before{content:"\F0E9E"}.mdi-dolphin::before{content:"\F18B4"}.mdi-domain::before{content:"\F01D7"}.mdi-domain-off::before{content:"\F0D6F"}.mdi-domain-plus::before{content:"\F10AD"}.mdi-domain-remove::before{content:"\F10AE"}.mdi-domain-switch::before{content:"\F1C2C"}.mdi-dome-light::before{content:"\F141E"}.mdi-domino-mask::before{content:"\F1023"}.mdi-donkey::before{content:"\F07C2"}.mdi-door::before{content:"\F081A"}.mdi-door-closed::before{content:"\F081B"}.mdi-door-closed-cancel::before{content:"\F1C93"}.mdi-door-closed-lock::before{content:"\F10AF"}.mdi-door-open::before{content:"\F081C"}.mdi-door-sliding::before{content:"\F181E"}.mdi-door-sliding-lock::before{content:"\F181F"}.mdi-door-sliding-open::before{content:"\F1820"}.mdi-doorbell::before{content:"\F12E6"}.mdi-doorbell-video::before{content:"\F0869"}.mdi-dot-net::before{content:"\F0AAE"}.mdi-dots-circle::before{content:"\F1978"}.mdi-dots-grid::before{content:"\F15FC"}.mdi-dots-hexagon::before{content:"\F15FF"}.mdi-dots-horizontal::before{content:"\F01D8"}.mdi-dots-horizontal-circle::before{content:"\F07C3"}.mdi-dots-horizontal-circle-outline::before{content:"\F0B8D"}.mdi-dots-square::before{content:"\F15FD"}.mdi-dots-triangle::before{content:"\F15FE"}.mdi-dots-vertical::before{content:"\F01D9"}.mdi-dots-vertical-circle::before{content:"\F07C4"}.mdi-dots-vertical-circle-outline::before{content:"\F0B8E"}.mdi-download::before{content:"\F01DA"}.mdi-download-box::before{content:"\F1462"}.mdi-download-box-outline::before{content:"\F1463"}.mdi-download-circle::before{content:"\F1464"}.mdi-download-circle-outline::before{content:"\F1465"}.mdi-download-lock::before{content:"\F1320"}.mdi-download-lock-outline::before{content:"\F1321"}.mdi-download-multiple::before{content:"\F09E9"}.mdi-download-multiple-outline::before{content:"\F1CD0"}.mdi-download-network::before{content:"\F06F4"}.mdi-download-network-outline::before{content:"\F0C66"}.mdi-download-off::before{content:"\F10B0"}.mdi-download-off-outline::before{content:"\F10B1"}.mdi-download-outline::before{content:"\F0B8F"}.mdi-drag::before{content:"\F01DB"}.mdi-drag-horizontal::before{content:"\F01DC"}.mdi-drag-horizontal-variant::before{content:"\F12F0"}.mdi-drag-variant::before{content:"\F0B90"}.mdi-drag-vertical::before{content:"\F01DD"}.mdi-drag-vertical-variant::before{content:"\F12F1"}.mdi-drama-masks::before{content:"\F0D02"}.mdi-draw::before{content:"\F0F49"}.mdi-draw-pen::before{content:"\F19B9"}.mdi-drawing::before{content:"\F01DE"}.mdi-drawing-box::before{content:"\F01DF"}.mdi-dresser::before{content:"\F0F4A"}.mdi-dresser-outline::before{content:"\F0F4B"}.mdi-drone::before{content:"\F01E2"}.mdi-dropbox::before{content:"\F01E3"}.mdi-drupal::before{content:"\F01E4"}.mdi-duck::before{content:"\F01E5"}.mdi-dumbbell::before{content:"\F01E6"}.mdi-dump-truck::before{content:"\F0C67"}.mdi-ear-hearing::before{content:"\F07C5"}.mdi-ear-hearing-loop::before{content:"\F1AEE"}.mdi-ear-hearing-off::before{content:"\F0A45"}.mdi-earbuds::before{content:"\F184F"}.mdi-earbuds-off::before{content:"\F1850"}.mdi-earbuds-off-outline::before{content:"\F1851"}.mdi-earbuds-outline::before{content:"\F1852"}.mdi-earth::before{content:"\F01E7"}.mdi-earth-arrow-down::before{content:"\F1C87"}.mdi-earth-arrow-left::before{content:"\F1C88"}.mdi-earth-arrow-right::before{content:"\F1311"}.mdi-earth-arrow-up::before{content:"\F1C89"}.mdi-earth-box::before{content:"\F06CD"}.mdi-earth-box-minus::before{content:"\F1407"}.mdi-earth-box-off::before{content:"\F06CE"}.mdi-earth-box-plus::before{content:"\F1406"}.mdi-earth-box-remove::before{content:"\F1408"}.mdi-earth-minus::before{content:"\F1404"}.mdi-earth-off::before{content:"\F01E8"}.mdi-earth-plus::before{content:"\F1403"}.mdi-earth-remove::before{content:"\F1405"}.mdi-egg::before{content:"\F0AAF"}.mdi-egg-easter::before{content:"\F0AB0"}.mdi-egg-fried::before{content:"\F184A"}.mdi-egg-off::before{content:"\F13F0"}.mdi-egg-off-outline::before{content:"\F13F1"}.mdi-egg-outline::before{content:"\F13F2"}.mdi-eiffel-tower::before{content:"\F156B"}.mdi-eight-track::before{content:"\F09EA"}.mdi-eject::before{content:"\F01EA"}.mdi-eject-circle::before{content:"\F1B23"}.mdi-eject-circle-outline::before{content:"\F1B24"}.mdi-eject-outline::before{content:"\F0B91"}.mdi-electric-switch::before{content:"\F0E9F"}.mdi-electric-switch-closed::before{content:"\F10D9"}.mdi-electron-framework::before{content:"\F1024"}.mdi-elephant::before{content:"\F07C6"}.mdi-elevation-decline::before{content:"\F01EB"}.mdi-elevation-rise::before{content:"\F01EC"}.mdi-elevator::before{content:"\F01ED"}.mdi-elevator-down::before{content:"\F12C2"}.mdi-elevator-passenger::before{content:"\F1381"}.mdi-elevator-passenger-off::before{content:"\F1979"}.mdi-elevator-passenger-off-outline::before{content:"\F197A"}.mdi-elevator-passenger-outline::before{content:"\F197B"}.mdi-elevator-up::before{content:"\F12C1"}.mdi-ellipse::before{content:"\F0EA0"}.mdi-ellipse-outline::before{content:"\F0EA1"}.mdi-email::before{content:"\F01EE"}.mdi-email-alert::before{content:"\F06CF"}.mdi-email-alert-outline::before{content:"\F0D42"}.mdi-email-arrow-left::before{content:"\F10DA"}.mdi-email-arrow-left-outline::before{content:"\F10DB"}.mdi-email-arrow-right::before{content:"\F10DC"}.mdi-email-arrow-right-outline::before{content:"\F10DD"}.mdi-email-box::before{content:"\F0D03"}.mdi-email-check::before{content:"\F0AB1"}.mdi-email-check-outline::before{content:"\F0AB2"}.mdi-email-edit::before{content:"\F0EE3"}.mdi-email-edit-outline::before{content:"\F0EE4"}.mdi-email-fast::before{content:"\F186F"}.mdi-email-fast-outline::before{content:"\F1870"}.mdi-email-heart-outline::before{content:"\F1C5B"}.mdi-email-lock::before{content:"\F01F1"}.mdi-email-lock-outline::before{content:"\F1B61"}.mdi-email-mark-as-unread::before{content:"\F0B92"}.mdi-email-minus::before{content:"\F0EE5"}.mdi-email-minus-outline::before{content:"\F0EE6"}.mdi-email-multiple::before{content:"\F0EE7"}.mdi-email-multiple-outline::before{content:"\F0EE8"}.mdi-email-newsletter::before{content:"\F0FB1"}.mdi-email-off::before{content:"\F13E3"}.mdi-email-off-outline::before{content:"\F13E4"}.mdi-email-open::before{content:"\F01EF"}.mdi-email-open-heart-outline::before{content:"\F1C5C"}.mdi-email-open-multiple::before{content:"\F0EE9"}.mdi-email-open-multiple-outline::before{content:"\F0EEA"}.mdi-email-open-outline::before{content:"\F05EF"}.mdi-email-outline::before{content:"\F01F0"}.mdi-email-plus::before{content:"\F09EB"}.mdi-email-plus-outline::before{content:"\F09EC"}.mdi-email-remove::before{content:"\F1661"}.mdi-email-remove-outline::before{content:"\F1662"}.mdi-email-seal::before{content:"\F195B"}.mdi-email-seal-outline::before{content:"\F195C"}.mdi-email-search::before{content:"\F0961"}.mdi-email-search-outline::before{content:"\F0962"}.mdi-email-sync::before{content:"\F12C7"}.mdi-email-sync-outline::before{content:"\F12C8"}.mdi-email-variant::before{content:"\F05F0"}.mdi-ember::before{content:"\F0B30"}.mdi-emby::before{content:"\F06B4"}.mdi-emoticon::before{content:"\F0C68"}.mdi-emoticon-angry::before{content:"\F0C69"}.mdi-emoticon-angry-outline::before{content:"\F0C6A"}.mdi-emoticon-confused::before{content:"\F10DE"}.mdi-emoticon-confused-outline::before{content:"\F10DF"}.mdi-emoticon-cool::before{content:"\F0C6B"}.mdi-emoticon-cool-outline::before{content:"\F01F3"}.mdi-emoticon-cry::before{content:"\F0C6C"}.mdi-emoticon-cry-outline::before{content:"\F0C6D"}.mdi-emoticon-dead::before{content:"\F0C6E"}.mdi-emoticon-dead-outline::before{content:"\F069B"}.mdi-emoticon-devil::before{content:"\F0C6F"}.mdi-emoticon-devil-outline::before{content:"\F01F4"}.mdi-emoticon-excited::before{content:"\F0C70"}.mdi-emoticon-excited-outline::before{content:"\F069C"}.mdi-emoticon-frown::before{content:"\F0F4C"}.mdi-emoticon-frown-outline::before{content:"\F0F4D"}.mdi-emoticon-happy::before{content:"\F0C71"}.mdi-emoticon-happy-outline::before{content:"\F01F5"}.mdi-emoticon-kiss::before{content:"\F0C72"}.mdi-emoticon-kiss-outline::before{content:"\F0C73"}.mdi-emoticon-lol::before{content:"\F1214"}.mdi-emoticon-lol-outline::before{content:"\F1215"}.mdi-emoticon-minus::before{content:"\F1CB2"}.mdi-emoticon-minus-outline::before{content:"\F1CB3"}.mdi-emoticon-neutral::before{content:"\F0C74"}.mdi-emoticon-neutral-outline::before{content:"\F01F6"}.mdi-emoticon-outline::before{content:"\F01F2"}.mdi-emoticon-plus::before{content:"\F1CB4"}.mdi-emoticon-plus-outline::before{content:"\F1CB5"}.mdi-emoticon-poop::before{content:"\F01F7"}.mdi-emoticon-poop-outline::before{content:"\F0C75"}.mdi-emoticon-remove::before{content:"\F1CB6"}.mdi-emoticon-remove-outline::before{content:"\F1CB7"}.mdi-emoticon-sad::before{content:"\F0C76"}.mdi-emoticon-sad-outline::before{content:"\F01F8"}.mdi-emoticon-sick::before{content:"\F157C"}.mdi-emoticon-sick-outline::before{content:"\F157D"}.mdi-emoticon-tongue::before{content:"\F01F9"}.mdi-emoticon-tongue-outline::before{content:"\F0C77"}.mdi-emoticon-wink::before{content:"\F0C78"}.mdi-emoticon-wink-outline::before{content:"\F0C79"}.mdi-engine::before{content:"\F01FA"}.mdi-engine-off::before{content:"\F0A46"}.mdi-engine-off-outline::before{content:"\F0A47"}.mdi-engine-outline::before{content:"\F01FB"}.mdi-epsilon::before{content:"\F10E0"}.mdi-equal::before{content:"\F01FC"}.mdi-equal-box::before{content:"\F01FD"}.mdi-equalizer::before{content:"\F0EA2"}.mdi-equalizer-outline::before{content:"\F0EA3"}.mdi-eraser::before{content:"\F01FE"}.mdi-eraser-variant::before{content:"\F0642"}.mdi-escalator::before{content:"\F01FF"}.mdi-escalator-box::before{content:"\F1399"}.mdi-escalator-down::before{content:"\F12C0"}.mdi-escalator-up::before{content:"\F12BF"}.mdi-eslint::before{content:"\F0C7A"}.mdi-et::before{content:"\F0AB3"}.mdi-ethereum::before{content:"\F086A"}.mdi-ethernet::before{content:"\F0200"}.mdi-ethernet-cable::before{content:"\F0201"}.mdi-ethernet-cable-off::before{content:"\F0202"}.mdi-ethernet-off::before{content:"\F1CD1"}.mdi-ev-plug-ccs1::before{content:"\F1519"}.mdi-ev-plug-ccs2::before{content:"\F151A"}.mdi-ev-plug-chademo::before{content:"\F151B"}.mdi-ev-plug-tesla::before{content:"\F151C"}.mdi-ev-plug-type1::before{content:"\F151D"}.mdi-ev-plug-type2::before{content:"\F151E"}.mdi-ev-station::before{content:"\F05F1"}.mdi-evernote::before{content:"\F0204"}.mdi-excavator::before{content:"\F1025"}.mdi-exclamation::before{content:"\F0205"}.mdi-exclamation-thick::before{content:"\F1238"}.mdi-exit-run::before{content:"\F0A48"}.mdi-exit-to-app::before{content:"\F0206"}.mdi-expand-all::before{content:"\F0AB4"}.mdi-expand-all-outline::before{content:"\F0AB5"}.mdi-expansion-card::before{content:"\F08AE"}.mdi-expansion-card-variant::before{content:"\F0FB2"}.mdi-exponent::before{content:"\F0963"}.mdi-exponent-box::before{content:"\F0964"}.mdi-export::before{content:"\F0207"}.mdi-export-variant::before{content:"\F0B93"}.mdi-eye::before{content:"\F0208"}.mdi-eye-arrow-left::before{content:"\F18FD"}.mdi-eye-arrow-left-outline::before{content:"\F18FE"}.mdi-eye-arrow-right::before{content:"\F18FF"}.mdi-eye-arrow-right-outline::before{content:"\F1900"}.mdi-eye-check::before{content:"\F0D04"}.mdi-eye-check-outline::before{content:"\F0D05"}.mdi-eye-circle::before{content:"\F0B94"}.mdi-eye-circle-outline::before{content:"\F0B95"}.mdi-eye-closed::before{content:"\F1CA3"}.mdi-eye-lock::before{content:"\F1C06"}.mdi-eye-lock-open::before{content:"\F1C07"}.mdi-eye-lock-open-outline::before{content:"\F1C08"}.mdi-eye-lock-outline::before{content:"\F1C09"}.mdi-eye-minus::before{content:"\F1026"}.mdi-eye-minus-outline::before{content:"\F1027"}.mdi-eye-off::before{content:"\F0209"}.mdi-eye-off-outline::before{content:"\F06D1"}.mdi-eye-outline::before{content:"\F06D0"}.mdi-eye-plus::before{content:"\F086B"}.mdi-eye-plus-outline::before{content:"\F086C"}.mdi-eye-refresh::before{content:"\F197C"}.mdi-eye-refresh-outline::before{content:"\F197D"}.mdi-eye-remove::before{content:"\F15E3"}.mdi-eye-remove-outline::before{content:"\F15E4"}.mdi-eye-settings::before{content:"\F086D"}.mdi-eye-settings-outline::before{content:"\F086E"}.mdi-eyedropper::before{content:"\F020A"}.mdi-eyedropper-minus::before{content:"\F13DD"}.mdi-eyedropper-off::before{content:"\F13DF"}.mdi-eyedropper-plus::before{content:"\F13DC"}.mdi-eyedropper-remove::before{content:"\F13DE"}.mdi-eyedropper-variant::before{content:"\F020B"}.mdi-face-agent::before{content:"\F0D70"}.mdi-face-man::before{content:"\F0643"}.mdi-face-man-outline::before{content:"\F0B96"}.mdi-face-man-profile::before{content:"\F0644"}.mdi-face-man-shimmer::before{content:"\F15CC"}.mdi-face-man-shimmer-outline::before{content:"\F15CD"}.mdi-face-mask::before{content:"\F1586"}.mdi-face-mask-outline::before{content:"\F1587"}.mdi-face-recognition::before{content:"\F0C7B"}.mdi-face-woman::before{content:"\F1077"}.mdi-face-woman-outline::before{content:"\F1078"}.mdi-face-woman-profile::before{content:"\F1076"}.mdi-face-woman-shimmer::before{content:"\F15CE"}.mdi-face-woman-shimmer-outline::before{content:"\F15CF"}.mdi-facebook::before{content:"\F020C"}.mdi-facebook-gaming::before{content:"\F07DD"}.mdi-facebook-messenger::before{content:"\F020E"}.mdi-facebook-workplace::before{content:"\F0B31"}.mdi-factory::before{content:"\F020F"}.mdi-family-tree::before{content:"\F160E"}.mdi-fan::before{content:"\F0210"}.mdi-fan-alert::before{content:"\F146C"}.mdi-fan-auto::before{content:"\F171D"}.mdi-fan-chevron-down::before{content:"\F146D"}.mdi-fan-chevron-up::before{content:"\F146E"}.mdi-fan-clock::before{content:"\F1A3A"}.mdi-fan-minus::before{content:"\F1470"}.mdi-fan-off::before{content:"\F081D"}.mdi-fan-plus::before{content:"\F146F"}.mdi-fan-remove::before{content:"\F1471"}.mdi-fan-speed-1::before{content:"\F1472"}.mdi-fan-speed-2::before{content:"\F1473"}.mdi-fan-speed-3::before{content:"\F1474"}.mdi-fast-forward::before{content:"\F0211"}.mdi-fast-forward-10::before{content:"\F0D71"}.mdi-fast-forward-15::before{content:"\F193A"}.mdi-fast-forward-30::before{content:"\F0D06"}.mdi-fast-forward-45::before{content:"\F1B12"}.mdi-fast-forward-5::before{content:"\F11F8"}.mdi-fast-forward-60::before{content:"\F160B"}.mdi-fast-forward-outline::before{content:"\F06D2"}.mdi-faucet::before{content:"\F1B29"}.mdi-faucet-variant::before{content:"\F1B2A"}.mdi-fax::before{content:"\F0212"}.mdi-feather::before{content:"\F06D3"}.mdi-feature-search::before{content:"\F0A49"}.mdi-feature-search-outline::before{content:"\F0A4A"}.mdi-fedora::before{content:"\F08DB"}.mdi-fence::before{content:"\F179A"}.mdi-fence-electric::before{content:"\F17F6"}.mdi-fencing::before{content:"\F14C1"}.mdi-ferris-wheel::before{content:"\F0EA4"}.mdi-ferry::before{content:"\F0213"}.mdi-file::before{content:"\F0214"}.mdi-file-account::before{content:"\F073B"}.mdi-file-account-outline::before{content:"\F1028"}.mdi-file-alert::before{content:"\F0A4B"}.mdi-file-alert-outline::before{content:"\F0A4C"}.mdi-file-arrow-left-right::before{content:"\F1A93"}.mdi-file-arrow-left-right-outline::before{content:"\F1A94"}.mdi-file-arrow-up-down::before{content:"\F1A95"}.mdi-file-arrow-up-down-outline::before{content:"\F1A96"}.mdi-file-cabinet::before{content:"\F0AB6"}.mdi-file-cad::before{content:"\F0EEB"}.mdi-file-cad-box::before{content:"\F0EEC"}.mdi-file-cancel::before{content:"\F0DC6"}.mdi-file-cancel-outline::before{content:"\F0DC7"}.mdi-file-certificate::before{content:"\F1186"}.mdi-file-certificate-outline::before{content:"\F1187"}.mdi-file-chart::before{content:"\F0215"}.mdi-file-chart-check::before{content:"\F19C6"}.mdi-file-chart-check-outline::before{content:"\F19C7"}.mdi-file-chart-outline::before{content:"\F1029"}.mdi-file-check::before{content:"\F0216"}.mdi-file-check-outline::before{content:"\F0E29"}.mdi-file-clock::before{content:"\F12E1"}.mdi-file-clock-outline::before{content:"\F12E2"}.mdi-file-cloud::before{content:"\F0217"}.mdi-file-cloud-outline::before{content:"\F102A"}.mdi-file-code::before{content:"\F022E"}.mdi-file-code-outline::before{content:"\F102B"}.mdi-file-cog::before{content:"\F107B"}.mdi-file-cog-outline::before{content:"\F107C"}.mdi-file-compare::before{content:"\F08AA"}.mdi-file-delimited::before{content:"\F0218"}.mdi-file-delimited-outline::before{content:"\F0EA5"}.mdi-file-document::before{content:"\F0219"}.mdi-file-document-alert::before{content:"\F1A97"}.mdi-file-document-alert-outline::before{content:"\F1A98"}.mdi-file-document-arrow-right::before{content:"\F1C0F"}.mdi-file-document-arrow-right-outline::before{content:"\F1C10"}.mdi-file-document-check::before{content:"\F1A99"}.mdi-file-document-check-outline::before{content:"\F1A9A"}.mdi-file-document-edit::before{content:"\F0DC8"}.mdi-file-document-edit-outline::before{content:"\F0DC9"}.mdi-file-document-minus::before{content:"\F1A9B"}.mdi-file-document-minus-outline::before{content:"\F1A9C"}.mdi-file-document-multiple::before{content:"\F1517"}.mdi-file-document-multiple-outline::before{content:"\F1518"}.mdi-file-document-outline::before{content:"\F09EE"}.mdi-file-document-plus::before{content:"\F1A9D"}.mdi-file-document-plus-outline::before{content:"\F1A9E"}.mdi-file-document-refresh::before{content:"\F1C7A"}.mdi-file-document-refresh-outline::before{content:"\F1C7B"}.mdi-file-document-remove::before{content:"\F1A9F"}.mdi-file-document-remove-outline::before{content:"\F1AA0"}.mdi-file-download::before{content:"\F0965"}.mdi-file-download-outline::before{content:"\F0966"}.mdi-file-edit::before{content:"\F11E7"}.mdi-file-edit-outline::before{content:"\F11E8"}.mdi-file-excel::before{content:"\F021B"}.mdi-file-excel-box::before{content:"\F021C"}.mdi-file-excel-box-outline::before{content:"\F102C"}.mdi-file-excel-outline::before{content:"\F102D"}.mdi-file-export::before{content:"\F021D"}.mdi-file-export-outline::before{content:"\F102E"}.mdi-file-eye::before{content:"\F0DCA"}.mdi-file-eye-outline::before{content:"\F0DCB"}.mdi-file-find::before{content:"\F021E"}.mdi-file-find-outline::before{content:"\F0B97"}.mdi-file-gif-box::before{content:"\F0D78"}.mdi-file-hidden::before{content:"\F0613"}.mdi-file-image::before{content:"\F021F"}.mdi-file-image-marker::before{content:"\F1772"}.mdi-file-image-marker-outline::before{content:"\F1773"}.mdi-file-image-minus::before{content:"\F193B"}.mdi-file-image-minus-outline::before{content:"\F193C"}.mdi-file-image-outline::before{content:"\F0EB0"}.mdi-file-image-plus::before{content:"\F193D"}.mdi-file-image-plus-outline::before{content:"\F193E"}.mdi-file-image-remove::before{content:"\F193F"}.mdi-file-image-remove-outline::before{content:"\F1940"}.mdi-file-import::before{content:"\F0220"}.mdi-file-import-outline::before{content:"\F102F"}.mdi-file-jpg-box::before{content:"\F0225"}.mdi-file-key::before{content:"\F1184"}.mdi-file-key-outline::before{content:"\F1185"}.mdi-file-link::before{content:"\F1177"}.mdi-file-link-outline::before{content:"\F1178"}.mdi-file-lock::before{content:"\F0221"}.mdi-file-lock-open::before{content:"\F19C8"}.mdi-file-lock-open-outline::before{content:"\F19C9"}.mdi-file-lock-outline::before{content:"\F1030"}.mdi-file-marker::before{content:"\F1774"}.mdi-file-marker-outline::before{content:"\F1775"}.mdi-file-minus::before{content:"\F1AA1"}.mdi-file-minus-outline::before{content:"\F1AA2"}.mdi-file-move::before{content:"\F0AB9"}.mdi-file-move-outline::before{content:"\F1031"}.mdi-file-multiple::before{content:"\F0222"}.mdi-file-multiple-outline::before{content:"\F1032"}.mdi-file-music::before{content:"\F0223"}.mdi-file-music-outline::before{content:"\F0E2A"}.mdi-file-outline::before{content:"\F0224"}.mdi-file-pdf-box::before{content:"\F0226"}.mdi-file-percent::before{content:"\F081E"}.mdi-file-percent-outline::before{content:"\F1033"}.mdi-file-phone::before{content:"\F1179"}.mdi-file-phone-outline::before{content:"\F117A"}.mdi-file-plus::before{content:"\F0752"}.mdi-file-plus-outline::before{content:"\F0EED"}.mdi-file-png-box::before{content:"\F0E2D"}.mdi-file-powerpoint::before{content:"\F0227"}.mdi-file-powerpoint-box::before{content:"\F0228"}.mdi-file-powerpoint-box-outline::before{content:"\F1034"}.mdi-file-powerpoint-outline::before{content:"\F1035"}.mdi-file-presentation-box::before{content:"\F0229"}.mdi-file-question::before{content:"\F086F"}.mdi-file-question-outline::before{content:"\F1036"}.mdi-file-refresh::before{content:"\F0918"}.mdi-file-refresh-outline::before{content:"\F0541"}.mdi-file-remove::before{content:"\F0B98"}.mdi-file-remove-outline::before{content:"\F1037"}.mdi-file-replace::before{content:"\F0B32"}.mdi-file-replace-outline::before{content:"\F0B33"}.mdi-file-restore::before{content:"\F0670"}.mdi-file-restore-outline::before{content:"\F1038"}.mdi-file-rotate-left::before{content:"\F1A3B"}.mdi-file-rotate-left-outline::before{content:"\F1A3C"}.mdi-file-rotate-right::before{content:"\F1A3D"}.mdi-file-rotate-right-outline::before{content:"\F1A3E"}.mdi-file-search::before{content:"\F0C7C"}.mdi-file-search-outline::before{content:"\F0C7D"}.mdi-file-send::before{content:"\F022A"}.mdi-file-send-outline::before{content:"\F1039"}.mdi-file-settings::before{content:"\F1079"}.mdi-file-settings-outline::before{content:"\F107A"}.mdi-file-sign::before{content:"\F19C3"}.mdi-file-star::before{content:"\F103A"}.mdi-file-star-four-points::before{content:"\F1C2D"}.mdi-file-star-four-points-outline::before{content:"\F1C2E"}.mdi-file-star-outline::before{content:"\F103B"}.mdi-file-swap::before{content:"\F0FB4"}.mdi-file-swap-outline::before{content:"\F0FB5"}.mdi-file-sync::before{content:"\F1216"}.mdi-file-sync-outline::before{content:"\F1217"}.mdi-file-table::before{content:"\F0C7E"}.mdi-file-table-box::before{content:"\F10E1"}.mdi-file-table-box-multiple::before{content:"\F10E2"}.mdi-file-table-box-multiple-outline::before{content:"\F10E3"}.mdi-file-table-box-outline::before{content:"\F10E4"}.mdi-file-table-outline::before{content:"\F0C7F"}.mdi-file-tree::before{content:"\F0645"}.mdi-file-tree-outline::before{content:"\F13D2"}.mdi-file-undo::before{content:"\F08DC"}.mdi-file-undo-outline::before{content:"\F103C"}.mdi-file-upload::before{content:"\F0A4D"}.mdi-file-upload-outline::before{content:"\F0A4E"}.mdi-file-video::before{content:"\F022B"}.mdi-file-video-outline::before{content:"\F0E2C"}.mdi-file-word::before{content:"\F022C"}.mdi-file-word-box::before{content:"\F022D"}.mdi-file-word-box-outline::before{content:"\F103D"}.mdi-file-word-outline::before{content:"\F103E"}.mdi-file-xml-box::before{content:"\F1B4B"}.mdi-film::before{content:"\F022F"}.mdi-filmstrip::before{content:"\F0230"}.mdi-filmstrip-box::before{content:"\F0332"}.mdi-filmstrip-box-multiple::before{content:"\F0D18"}.mdi-filmstrip-off::before{content:"\F0231"}.mdi-filter::before{content:"\F0232"}.mdi-filter-check::before{content:"\F18EC"}.mdi-filter-check-outline::before{content:"\F18ED"}.mdi-filter-cog::before{content:"\F1AA3"}.mdi-filter-cog-outline::before{content:"\F1AA4"}.mdi-filter-menu::before{content:"\F10E5"}.mdi-filter-menu-outline::before{content:"\F10E6"}.mdi-filter-minus::before{content:"\F0EEE"}.mdi-filter-minus-outline::before{content:"\F0EEF"}.mdi-filter-multiple::before{content:"\F1A3F"}.mdi-filter-multiple-outline::before{content:"\F1A40"}.mdi-filter-off::before{content:"\F14EF"}.mdi-filter-off-outline::before{content:"\F14F0"}.mdi-filter-outline::before{content:"\F0233"}.mdi-filter-plus::before{content:"\F0EF0"}.mdi-filter-plus-outline::before{content:"\F0EF1"}.mdi-filter-remove::before{content:"\F0234"}.mdi-filter-remove-outline::before{content:"\F0235"}.mdi-filter-settings::before{content:"\F1AA5"}.mdi-filter-settings-outline::before{content:"\F1AA6"}.mdi-filter-variant::before{content:"\F0236"}.mdi-filter-variant-minus::before{content:"\F1112"}.mdi-filter-variant-plus::before{content:"\F1113"}.mdi-filter-variant-remove::before{content:"\F103F"}.mdi-finance::before{content:"\F081F"}.mdi-find-replace::before{content:"\F06D4"}.mdi-fingerprint::before{content:"\F0237"}.mdi-fingerprint-off::before{content:"\F0EB1"}.mdi-fire::before{content:"\F0238"}.mdi-fire-alert::before{content:"\F15D7"}.mdi-fire-circle::before{content:"\F1807"}.mdi-fire-extinguisher::before{content:"\F0EF2"}.mdi-fire-hydrant::before{content:"\F1137"}.mdi-fire-hydrant-alert::before{content:"\F1138"}.mdi-fire-hydrant-off::before{content:"\F1139"}.mdi-fire-off::before{content:"\F1722"}.mdi-fire-station::before{content:"\F1CC3"}.mdi-fire-truck::before{content:"\F08AB"}.mdi-firebase::before{content:"\F0967"}.mdi-firefox::before{content:"\F0239"}.mdi-fireplace::before{content:"\F0E2E"}.mdi-fireplace-off::before{content:"\F0E2F"}.mdi-firewire::before{content:"\F05BE"}.mdi-firework::before{content:"\F0E30"}.mdi-firework-off::before{content:"\F1723"}.mdi-fish::before{content:"\F023A"}.mdi-fish-off::before{content:"\F13F3"}.mdi-fishbowl::before{content:"\F0EF3"}.mdi-fishbowl-outline::before{content:"\F0EF4"}.mdi-fit-to-page::before{content:"\F0EF5"}.mdi-fit-to-page-outline::before{content:"\F0EF6"}.mdi-fit-to-screen::before{content:"\F18F4"}.mdi-fit-to-screen-outline::before{content:"\F18F5"}.mdi-flag::before{content:"\F023B"}.mdi-flag-checkered::before{content:"\F023C"}.mdi-flag-minus::before{content:"\F0B99"}.mdi-flag-minus-outline::before{content:"\F10B2"}.mdi-flag-off::before{content:"\F18EE"}.mdi-flag-off-outline::before{content:"\F18EF"}.mdi-flag-outline::before{content:"\F023D"}.mdi-flag-plus::before{content:"\F0B9A"}.mdi-flag-plus-outline::before{content:"\F10B3"}.mdi-flag-remove::before{content:"\F0B9B"}.mdi-flag-remove-outline::before{content:"\F10B4"}.mdi-flag-triangle::before{content:"\F023F"}.mdi-flag-variant::before{content:"\F0240"}.mdi-flag-variant-minus::before{content:"\F1BB4"}.mdi-flag-variant-minus-outline::before{content:"\F1BB5"}.mdi-flag-variant-off::before{content:"\F1BB0"}.mdi-flag-variant-off-outline::before{content:"\F1BB1"}.mdi-flag-variant-outline::before{content:"\F023E"}.mdi-flag-variant-plus::before{content:"\F1BB2"}.mdi-flag-variant-plus-outline::before{content:"\F1BB3"}.mdi-flag-variant-remove::before{content:"\F1BB6"}.mdi-flag-variant-remove-outline::before{content:"\F1BB7"}.mdi-flare::before{content:"\F0D72"}.mdi-flash::before{content:"\F0241"}.mdi-flash-alert::before{content:"\F0EF7"}.mdi-flash-alert-outline::before{content:"\F0EF8"}.mdi-flash-auto::before{content:"\F0242"}.mdi-flash-off::before{content:"\F0243"}.mdi-flash-off-outline::before{content:"\F1B45"}.mdi-flash-outline::before{content:"\F06D5"}.mdi-flash-red-eye::before{content:"\F067B"}.mdi-flash-triangle::before{content:"\F1B1D"}.mdi-flash-triangle-outline::before{content:"\F1B1E"}.mdi-flashlight::before{content:"\F0244"}.mdi-flashlight-off::before{content:"\F0245"}.mdi-flask::before{content:"\F0093"}.mdi-flask-empty::before{content:"\F0094"}.mdi-flask-empty-minus::before{content:"\F123A"}.mdi-flask-empty-minus-outline::before{content:"\F123B"}.mdi-flask-empty-off::before{content:"\F13F4"}.mdi-flask-empty-off-outline::before{content:"\F13F5"}.mdi-flask-empty-outline::before{content:"\F0095"}.mdi-flask-empty-plus::before{content:"\F123C"}.mdi-flask-empty-plus-outline::before{content:"\F123D"}.mdi-flask-empty-remove::before{content:"\F123E"}.mdi-flask-empty-remove-outline::before{content:"\F123F"}.mdi-flask-minus::before{content:"\F1240"}.mdi-flask-minus-outline::before{content:"\F1241"}.mdi-flask-off::before{content:"\F13F6"}.mdi-flask-off-outline::before{content:"\F13F7"}.mdi-flask-outline::before{content:"\F0096"}.mdi-flask-plus::before{content:"\F1242"}.mdi-flask-plus-outline::before{content:"\F1243"}.mdi-flask-remove::before{content:"\F1244"}.mdi-flask-remove-outline::before{content:"\F1245"}.mdi-flask-round-bottom::before{content:"\F124B"}.mdi-flask-round-bottom-empty::before{content:"\F124C"}.mdi-flask-round-bottom-empty-outline::before{content:"\F124D"}.mdi-flask-round-bottom-outline::before{content:"\F124E"}.mdi-fleur-de-lis::before{content:"\F1303"}.mdi-flip-horizontal::before{content:"\F10E7"}.mdi-flip-to-back::before{content:"\F0247"}.mdi-flip-to-front::before{content:"\F0248"}.mdi-flip-vertical::before{content:"\F10E8"}.mdi-floor-lamp::before{content:"\F08DD"}.mdi-floor-lamp-dual::before{content:"\F1040"}.mdi-floor-lamp-dual-outline::before{content:"\F17CE"}.mdi-floor-lamp-outline::before{content:"\F17C8"}.mdi-floor-lamp-torchiere::before{content:"\F1747"}.mdi-floor-lamp-torchiere-outline::before{content:"\F17D6"}.mdi-floor-lamp-torchiere-variant::before{content:"\F1041"}.mdi-floor-lamp-torchiere-variant-outline::before{content:"\F17CF"}.mdi-floor-plan::before{content:"\F0821"}.mdi-floppy::before{content:"\F0249"}.mdi-floppy-variant::before{content:"\F09EF"}.mdi-flower::before{content:"\F024A"}.mdi-flower-outline::before{content:"\F09F0"}.mdi-flower-pollen::before{content:"\F1885"}.mdi-flower-pollen-outline::before{content:"\F1886"}.mdi-flower-poppy::before{content:"\F0D08"}.mdi-flower-tulip::before{content:"\F09F1"}.mdi-flower-tulip-outline::before{content:"\F09F2"}.mdi-focus-auto::before{content:"\F0F4E"}.mdi-focus-field::before{content:"\F0F4F"}.mdi-focus-field-horizontal::before{content:"\F0F50"}.mdi-focus-field-vertical::before{content:"\F0F51"}.mdi-folder::before{content:"\F024B"}.mdi-folder-account::before{content:"\F024C"}.mdi-folder-account-outline::before{content:"\F0B9C"}.mdi-folder-alert::before{content:"\F0DCC"}.mdi-folder-alert-outline::before{content:"\F0DCD"}.mdi-folder-arrow-down::before{content:"\F19E8"}.mdi-folder-arrow-down-outline::before{content:"\F19E9"}.mdi-folder-arrow-left::before{content:"\F19EA"}.mdi-folder-arrow-left-outline::before{content:"\F19EB"}.mdi-folder-arrow-left-right::before{content:"\F19EC"}.mdi-folder-arrow-left-right-outline::before{content:"\F19ED"}.mdi-folder-arrow-right::before{content:"\F19EE"}.mdi-folder-arrow-right-outline::before{content:"\F19EF"}.mdi-folder-arrow-up::before{content:"\F19F0"}.mdi-folder-arrow-up-down::before{content:"\F19F1"}.mdi-folder-arrow-up-down-outline::before{content:"\F19F2"}.mdi-folder-arrow-up-outline::before{content:"\F19F3"}.mdi-folder-cancel::before{content:"\F19F4"}.mdi-folder-cancel-outline::before{content:"\F19F5"}.mdi-folder-check::before{content:"\F197E"}.mdi-folder-check-outline::before{content:"\F197F"}.mdi-folder-clock::before{content:"\F0ABA"}.mdi-folder-clock-outline::before{content:"\F0ABB"}.mdi-folder-cog::before{content:"\F107F"}.mdi-folder-cog-outline::before{content:"\F1080"}.mdi-folder-download::before{content:"\F024D"}.mdi-folder-download-outline::before{content:"\F10E9"}.mdi-folder-edit::before{content:"\F08DE"}.mdi-folder-edit-outline::before{content:"\F0DCE"}.mdi-folder-eye::before{content:"\F178A"}.mdi-folder-eye-outline::before{content:"\F178B"}.mdi-folder-file::before{content:"\F19F6"}.mdi-folder-file-outline::before{content:"\F19F7"}.mdi-folder-google-drive::before{content:"\F024E"}.mdi-folder-heart::before{content:"\F10EA"}.mdi-folder-heart-outline::before{content:"\F10EB"}.mdi-folder-hidden::before{content:"\F179E"}.mdi-folder-home::before{content:"\F10B5"}.mdi-folder-home-outline::before{content:"\F10B6"}.mdi-folder-image::before{content:"\F024F"}.mdi-folder-information::before{content:"\F10B7"}.mdi-folder-information-outline::before{content:"\F10B8"}.mdi-folder-key::before{content:"\F08AC"}.mdi-folder-key-network::before{content:"\F08AD"}.mdi-folder-key-network-outline::before{content:"\F0C80"}.mdi-folder-key-outline::before{content:"\F10EC"}.mdi-folder-lock::before{content:"\F0250"}.mdi-folder-lock-open::before{content:"\F0251"}.mdi-folder-lock-open-outline::before{content:"\F1AA7"}.mdi-folder-lock-outline::before{content:"\F1AA8"}.mdi-folder-marker::before{content:"\F126D"}.mdi-folder-marker-outline::before{content:"\F126E"}.mdi-folder-minus::before{content:"\F1B49"}.mdi-folder-minus-outline::before{content:"\F1B4A"}.mdi-folder-move::before{content:"\F0252"}.mdi-folder-move-outline::before{content:"\F1246"}.mdi-folder-multiple::before{content:"\F0253"}.mdi-folder-multiple-image::before{content:"\F0254"}.mdi-folder-multiple-outline::before{content:"\F0255"}.mdi-folder-multiple-plus::before{content:"\F147E"}.mdi-folder-multiple-plus-outline::before{content:"\F147F"}.mdi-folder-music::before{content:"\F1359"}.mdi-folder-music-outline::before{content:"\F135A"}.mdi-folder-network::before{content:"\F0870"}.mdi-folder-network-outline::before{content:"\F0C81"}.mdi-folder-off::before{content:"\F19F8"}.mdi-folder-off-outline::before{content:"\F19F9"}.mdi-folder-open::before{content:"\F0770"}.mdi-folder-open-outline::before{content:"\F0DCF"}.mdi-folder-outline::before{content:"\F0256"}.mdi-folder-play::before{content:"\F19FA"}.mdi-folder-play-outline::before{content:"\F19FB"}.mdi-folder-plus::before{content:"\F0257"}.mdi-folder-plus-outline::before{content:"\F0B9D"}.mdi-folder-pound::before{content:"\F0D09"}.mdi-folder-pound-outline::before{content:"\F0D0A"}.mdi-folder-question::before{content:"\F19CA"}.mdi-folder-question-outline::before{content:"\F19CB"}.mdi-folder-refresh::before{content:"\F0749"}.mdi-folder-refresh-outline::before{content:"\F0542"}.mdi-folder-remove::before{content:"\F0258"}.mdi-folder-remove-outline::before{content:"\F0B9E"}.mdi-folder-search::before{content:"\F0968"}.mdi-folder-search-outline::before{content:"\F0969"}.mdi-folder-settings::before{content:"\F107D"}.mdi-folder-settings-outline::before{content:"\F107E"}.mdi-folder-star::before{content:"\F069D"}.mdi-folder-star-multiple::before{content:"\F13D3"}.mdi-folder-star-multiple-outline::before{content:"\F13D4"}.mdi-folder-star-outline::before{content:"\F0B9F"}.mdi-folder-swap::before{content:"\F0FB6"}.mdi-folder-swap-outline::before{content:"\F0FB7"}.mdi-folder-sync::before{content:"\F0D0B"}.mdi-folder-sync-outline::before{content:"\F0D0C"}.mdi-folder-table::before{content:"\F12E3"}.mdi-folder-table-outline::before{content:"\F12E4"}.mdi-folder-text::before{content:"\F0C82"}.mdi-folder-text-outline::before{content:"\F0C83"}.mdi-folder-upload::before{content:"\F0259"}.mdi-folder-upload-outline::before{content:"\F10ED"}.mdi-folder-wrench::before{content:"\F19FC"}.mdi-folder-wrench-outline::before{content:"\F19FD"}.mdi-folder-zip::before{content:"\F06EB"}.mdi-folder-zip-outline::before{content:"\F07B9"}.mdi-font-awesome::before{content:"\F003A"}.mdi-food::before{content:"\F025A"}.mdi-food-apple::before{content:"\F025B"}.mdi-food-apple-outline::before{content:"\F0C84"}.mdi-food-croissant::before{content:"\F07C8"}.mdi-food-drumstick::before{content:"\F141F"}.mdi-food-drumstick-off::before{content:"\F1468"}.mdi-food-drumstick-off-outline::before{content:"\F1469"}.mdi-food-drumstick-outline::before{content:"\F1420"}.mdi-food-fork-drink::before{content:"\F05F2"}.mdi-food-halal::before{content:"\F1572"}.mdi-food-hot-dog::before{content:"\F184B"}.mdi-food-kosher::before{content:"\F1573"}.mdi-food-off::before{content:"\F05F3"}.mdi-food-off-outline::before{content:"\F1915"}.mdi-food-outline::before{content:"\F1916"}.mdi-food-steak::before{content:"\F146A"}.mdi-food-steak-off::before{content:"\F146B"}.mdi-food-takeout-box::before{content:"\F1836"}.mdi-food-takeout-box-outline::before{content:"\F1837"}.mdi-food-turkey::before{content:"\F171C"}.mdi-food-variant::before{content:"\F025C"}.mdi-food-variant-off::before{content:"\F13E5"}.mdi-foot-print::before{content:"\F0F52"}.mdi-football::before{content:"\F025D"}.mdi-football-australian::before{content:"\F025E"}.mdi-football-helmet::before{content:"\F025F"}.mdi-forest::before{content:"\F1897"}.mdi-forest-outline::before{content:"\F1C63"}.mdi-forklift::before{content:"\F07C9"}.mdi-form-dropdown::before{content:"\F1400"}.mdi-form-select::before{content:"\F1401"}.mdi-form-textarea::before{content:"\F1095"}.mdi-form-textbox::before{content:"\F060E"}.mdi-form-textbox-lock::before{content:"\F135D"}.mdi-form-textbox-password::before{content:"\F07F5"}.mdi-format-align-bottom::before{content:"\F0753"}.mdi-format-align-center::before{content:"\F0260"}.mdi-format-align-justify::before{content:"\F0261"}.mdi-format-align-left::before{content:"\F0262"}.mdi-format-align-middle::before{content:"\F0754"}.mdi-format-align-right::before{content:"\F0263"}.mdi-format-align-top::before{content:"\F0755"}.mdi-format-annotation-minus::before{content:"\F0ABC"}.mdi-format-annotation-plus::before{content:"\F0646"}.mdi-format-bold::before{content:"\F0264"}.mdi-format-clear::before{content:"\F0265"}.mdi-format-color-fill::before{content:"\F0266"}.mdi-format-color-highlight::before{content:"\F0E31"}.mdi-format-color-marker-cancel::before{content:"\F1313"}.mdi-format-color-text::before{content:"\F069E"}.mdi-format-columns::before{content:"\F08DF"}.mdi-format-float-center::before{content:"\F0267"}.mdi-format-float-left::before{content:"\F0268"}.mdi-format-float-none::before{content:"\F0269"}.mdi-format-float-right::before{content:"\F026A"}.mdi-format-font::before{content:"\F06D6"}.mdi-format-font-size-decrease::before{content:"\F09F3"}.mdi-format-font-size-increase::before{content:"\F09F4"}.mdi-format-header-1::before{content:"\F026B"}.mdi-format-header-2::before{content:"\F026C"}.mdi-format-header-3::before{content:"\F026D"}.mdi-format-header-4::before{content:"\F026E"}.mdi-format-header-5::before{content:"\F026F"}.mdi-format-header-6::before{content:"\F0270"}.mdi-format-header-decrease::before{content:"\F0271"}.mdi-format-header-equal::before{content:"\F0272"}.mdi-format-header-increase::before{content:"\F0273"}.mdi-format-header-pound::before{content:"\F0274"}.mdi-format-horizontal-align-center::before{content:"\F061E"}.mdi-format-horizontal-align-left::before{content:"\F061F"}.mdi-format-horizontal-align-right::before{content:"\F0620"}.mdi-format-indent-decrease::before{content:"\F0275"}.mdi-format-indent-increase::before{content:"\F0276"}.mdi-format-italic::before{content:"\F0277"}.mdi-format-letter-case::before{content:"\F0B34"}.mdi-format-letter-case-lower::before{content:"\F0B35"}.mdi-format-letter-case-upper::before{content:"\F0B36"}.mdi-format-letter-ends-with::before{content:"\F0FB8"}.mdi-format-letter-matches::before{content:"\F0FB9"}.mdi-format-letter-spacing::before{content:"\F1956"}.mdi-format-letter-spacing-variant::before{content:"\F1AFB"}.mdi-format-letter-starts-with::before{content:"\F0FBA"}.mdi-format-line-height::before{content:"\F1AFC"}.mdi-format-line-spacing::before{content:"\F0278"}.mdi-format-line-style::before{content:"\F05C8"}.mdi-format-line-weight::before{content:"\F05C9"}.mdi-format-list-bulleted::before{content:"\F0279"}.mdi-format-list-bulleted-square::before{content:"\F0DD0"}.mdi-format-list-bulleted-triangle::before{content:"\F0EB2"}.mdi-format-list-bulleted-type::before{content:"\F027A"}.mdi-format-list-checkbox::before{content:"\F096A"}.mdi-format-list-checks::before{content:"\F0756"}.mdi-format-list-group::before{content:"\F1860"}.mdi-format-list-group-plus::before{content:"\F1B56"}.mdi-format-list-numbered::before{content:"\F027B"}.mdi-format-list-numbered-rtl::before{content:"\F0D0D"}.mdi-format-list-text::before{content:"\F126F"}.mdi-format-overline::before{content:"\F0EB3"}.mdi-format-page-break::before{content:"\F06D7"}.mdi-format-page-split::before{content:"\F1917"}.mdi-format-paint::before{content:"\F027C"}.mdi-format-paragraph::before{content:"\F027D"}.mdi-format-paragraph-spacing::before{content:"\F1AFD"}.mdi-format-pilcrow::before{content:"\F06D8"}.mdi-format-pilcrow-arrow-left::before{content:"\F0286"}.mdi-format-pilcrow-arrow-right::before{content:"\F0285"}.mdi-format-quote-close::before{content:"\F027E"}.mdi-format-quote-close-outline::before{content:"\F11A8"}.mdi-format-quote-open::before{content:"\F0757"}.mdi-format-quote-open-outline::before{content:"\F11A7"}.mdi-format-rotate-90::before{content:"\F06AA"}.mdi-format-section::before{content:"\F069F"}.mdi-format-size::before{content:"\F027F"}.mdi-format-strikethrough::before{content:"\F0280"}.mdi-format-strikethrough-variant::before{content:"\F0281"}.mdi-format-subscript::before{content:"\F0282"}.mdi-format-superscript::before{content:"\F0283"}.mdi-format-text::before{content:"\F0284"}.mdi-format-text-rotation-angle-down::before{content:"\F0FBB"}.mdi-format-text-rotation-angle-up::before{content:"\F0FBC"}.mdi-format-text-rotation-down::before{content:"\F0D73"}.mdi-format-text-rotation-down-vertical::before{content:"\F0FBD"}.mdi-format-text-rotation-none::before{content:"\F0D74"}.mdi-format-text-rotation-up::before{content:"\F0FBE"}.mdi-format-text-rotation-vertical::before{content:"\F0FBF"}.mdi-format-text-variant::before{content:"\F0E32"}.mdi-format-text-variant-outline::before{content:"\F150F"}.mdi-format-text-wrapping-clip::before{content:"\F0D0E"}.mdi-format-text-wrapping-overflow::before{content:"\F0D0F"}.mdi-format-text-wrapping-wrap::before{content:"\F0D10"}.mdi-format-textbox::before{content:"\F0D11"}.mdi-format-title::before{content:"\F05F4"}.mdi-format-underline::before{content:"\F0287"}.mdi-format-underline-wavy::before{content:"\F18E9"}.mdi-format-vertical-align-bottom::before{content:"\F0621"}.mdi-format-vertical-align-center::before{content:"\F0622"}.mdi-format-vertical-align-top::before{content:"\F0623"}.mdi-format-wrap-inline::before{content:"\F0288"}.mdi-format-wrap-square::before{content:"\F0289"}.mdi-format-wrap-tight::before{content:"\F028A"}.mdi-format-wrap-top-bottom::before{content:"\F028B"}.mdi-forum::before{content:"\F028C"}.mdi-forum-minus::before{content:"\F1AA9"}.mdi-forum-minus-outline::before{content:"\F1AAA"}.mdi-forum-outline::before{content:"\F0822"}.mdi-forum-plus::before{content:"\F1AAB"}.mdi-forum-plus-outline::before{content:"\F1AAC"}.mdi-forum-remove::before{content:"\F1AAD"}.mdi-forum-remove-outline::before{content:"\F1AAE"}.mdi-forward::before{content:"\F028D"}.mdi-forwardburger::before{content:"\F0D75"}.mdi-fountain::before{content:"\F096B"}.mdi-fountain-pen::before{content:"\F0D12"}.mdi-fountain-pen-tip::before{content:"\F0D13"}.mdi-fraction-one-half::before{content:"\F1992"}.mdi-freebsd::before{content:"\F08E0"}.mdi-french-fries::before{content:"\F1957"}.mdi-frequently-asked-questions::before{content:"\F0EB4"}.mdi-fridge::before{content:"\F0290"}.mdi-fridge-alert::before{content:"\F11B1"}.mdi-fridge-alert-outline::before{content:"\F11B2"}.mdi-fridge-bottom::before{content:"\F0292"}.mdi-fridge-industrial::before{content:"\F15EE"}.mdi-fridge-industrial-alert::before{content:"\F15EF"}.mdi-fridge-industrial-alert-outline::before{content:"\F15F0"}.mdi-fridge-industrial-off::before{content:"\F15F1"}.mdi-fridge-industrial-off-outline::before{content:"\F15F2"}.mdi-fridge-industrial-outline::before{content:"\F15F3"}.mdi-fridge-off::before{content:"\F11AF"}.mdi-fridge-off-outline::before{content:"\F11B0"}.mdi-fridge-outline::before{content:"\F028F"}.mdi-fridge-top::before{content:"\F0291"}.mdi-fridge-variant::before{content:"\F15F4"}.mdi-fridge-variant-alert::before{content:"\F15F5"}.mdi-fridge-variant-alert-outline::before{content:"\F15F6"}.mdi-fridge-variant-off::before{content:"\F15F7"}.mdi-fridge-variant-off-outline::before{content:"\F15F8"}.mdi-fridge-variant-outline::before{content:"\F15F9"}.mdi-fruit-cherries::before{content:"\F1042"}.mdi-fruit-cherries-off::before{content:"\F13F8"}.mdi-fruit-citrus::before{content:"\F1043"}.mdi-fruit-citrus-off::before{content:"\F13F9"}.mdi-fruit-grapes::before{content:"\F1044"}.mdi-fruit-grapes-outline::before{content:"\F1045"}.mdi-fruit-pear::before{content:"\F1A0E"}.mdi-fruit-pineapple::before{content:"\F1046"}.mdi-fruit-watermelon::before{content:"\F1047"}.mdi-fuel::before{content:"\F07CA"}.mdi-fuel-cell::before{content:"\F18B5"}.mdi-fullscreen::before{content:"\F0293"}.mdi-fullscreen-exit::before{content:"\F0294"}.mdi-function::before{content:"\F0295"}.mdi-function-variant::before{content:"\F0871"}.mdi-furigana-horizontal::before{content:"\F1081"}.mdi-furigana-vertical::before{content:"\F1082"}.mdi-fuse::before{content:"\F0C85"}.mdi-fuse-alert::before{content:"\F142D"}.mdi-fuse-blade::before{content:"\F0C86"}.mdi-fuse-off::before{content:"\F142C"}.mdi-gamepad::before{content:"\F0296"}.mdi-gamepad-circle::before{content:"\F0E33"}.mdi-gamepad-circle-down::before{content:"\F0E34"}.mdi-gamepad-circle-left::before{content:"\F0E35"}.mdi-gamepad-circle-outline::before{content:"\F0E36"}.mdi-gamepad-circle-right::before{content:"\F0E37"}.mdi-gamepad-circle-up::before{content:"\F0E38"}.mdi-gamepad-down::before{content:"\F0E39"}.mdi-gamepad-left::before{content:"\F0E3A"}.mdi-gamepad-outline::before{content:"\F1919"}.mdi-gamepad-right::before{content:"\F0E3B"}.mdi-gamepad-round::before{content:"\F0E3C"}.mdi-gamepad-round-down::before{content:"\F0E3D"}.mdi-gamepad-round-left::before{content:"\F0E3E"}.mdi-gamepad-round-outline::before{content:"\F0E3F"}.mdi-gamepad-round-right::before{content:"\F0E40"}.mdi-gamepad-round-up::before{content:"\F0E41"}.mdi-gamepad-square::before{content:"\F0EB5"}.mdi-gamepad-square-outline::before{content:"\F0EB6"}.mdi-gamepad-up::before{content:"\F0E42"}.mdi-gamepad-variant::before{content:"\F0297"}.mdi-gamepad-variant-outline::before{content:"\F0EB7"}.mdi-gamma::before{content:"\F10EE"}.mdi-gantry-crane::before{content:"\F0DD1"}.mdi-garage::before{content:"\F06D9"}.mdi-garage-alert::before{content:"\F0872"}.mdi-garage-alert-variant::before{content:"\F12D5"}.mdi-garage-lock::before{content:"\F17FB"}.mdi-garage-open::before{content:"\F06DA"}.mdi-garage-open-variant::before{content:"\F12D4"}.mdi-garage-variant::before{content:"\F12D3"}.mdi-garage-variant-lock::before{content:"\F17FC"}.mdi-gas-burner::before{content:"\F1A1B"}.mdi-gas-cylinder::before{content:"\F0647"}.mdi-gas-station::before{content:"\F0298"}.mdi-gas-station-in-use::before{content:"\F1CC4"}.mdi-gas-station-in-use-outline::before{content:"\F1CC5"}.mdi-gas-station-off::before{content:"\F1409"}.mdi-gas-station-off-outline::before{content:"\F140A"}.mdi-gas-station-outline::before{content:"\F0EB8"}.mdi-gate::before{content:"\F0299"}.mdi-gate-alert::before{content:"\F17F8"}.mdi-gate-and::before{content:"\F08E1"}.mdi-gate-arrow-left::before{content:"\F17F7"}.mdi-gate-arrow-right::before{content:"\F1169"}.mdi-gate-buffer::before{content:"\F1AFE"}.mdi-gate-nand::before{content:"\F08E2"}.mdi-gate-nor::before{content:"\F08E3"}.mdi-gate-not::before{content:"\F08E4"}.mdi-gate-open::before{content:"\F116A"}.mdi-gate-or::before{content:"\F08E5"}.mdi-gate-xnor::before{content:"\F08E6"}.mdi-gate-xor::before{content:"\F08E7"}.mdi-gatsby::before{content:"\F0E43"}.mdi-gauge::before{content:"\F029A"}.mdi-gauge-empty::before{content:"\F0873"}.mdi-gauge-full::before{content:"\F0874"}.mdi-gauge-low::before{content:"\F0875"}.mdi-gavel::before{content:"\F029B"}.mdi-gender-female::before{content:"\F029C"}.mdi-gender-male::before{content:"\F029D"}.mdi-gender-male-female::before{content:"\F029E"}.mdi-gender-male-female-variant::before{content:"\F113F"}.mdi-gender-non-binary::before{content:"\F1140"}.mdi-gender-transgender::before{content:"\F029F"}.mdi-generator-mobile::before{content:"\F1C8A"}.mdi-generator-portable::before{content:"\F1C8B"}.mdi-generator-stationary::before{content:"\F1C8C"}.mdi-gentoo::before{content:"\F08E8"}.mdi-gesture::before{content:"\F07CB"}.mdi-gesture-double-tap::before{content:"\F073C"}.mdi-gesture-pinch::before{content:"\F0ABD"}.mdi-gesture-spread::before{content:"\F0ABE"}.mdi-gesture-swipe::before{content:"\F0D76"}.mdi-gesture-swipe-down::before{content:"\F073D"}.mdi-gesture-swipe-horizontal::before{content:"\F0ABF"}.mdi-gesture-swipe-left::before{content:"\F073E"}.mdi-gesture-swipe-right::before{content:"\F073F"}.mdi-gesture-swipe-up::before{content:"\F0740"}.mdi-gesture-swipe-vertical::before{content:"\F0AC0"}.mdi-gesture-tap::before{content:"\F0741"}.mdi-gesture-tap-box::before{content:"\F12A9"}.mdi-gesture-tap-button::before{content:"\F12A8"}.mdi-gesture-tap-hold::before{content:"\F0D77"}.mdi-gesture-two-double-tap::before{content:"\F0742"}.mdi-gesture-two-tap::before{content:"\F0743"}.mdi-ghost::before{content:"\F02A0"}.mdi-ghost-off::before{content:"\F09F5"}.mdi-ghost-off-outline::before{content:"\F165C"}.mdi-ghost-outline::before{content:"\F165D"}.mdi-gift::before{content:"\F0E44"}.mdi-gift-off::before{content:"\F16EF"}.mdi-gift-off-outline::before{content:"\F16F0"}.mdi-gift-open::before{content:"\F16F1"}.mdi-gift-open-outline::before{content:"\F16F2"}.mdi-gift-outline::before{content:"\F02A1"}.mdi-git::before{content:"\F02A2"}.mdi-github::before{content:"\F02A4"}.mdi-gitlab::before{content:"\F0BA0"}.mdi-glass-cocktail::before{content:"\F0356"}.mdi-glass-cocktail-off::before{content:"\F15E6"}.mdi-glass-flute::before{content:"\F02A5"}.mdi-glass-fragile::before{content:"\F1873"}.mdi-glass-mug::before{content:"\F02A6"}.mdi-glass-mug-off::before{content:"\F15E7"}.mdi-glass-mug-variant::before{content:"\F1116"}.mdi-glass-mug-variant-off::before{content:"\F15E8"}.mdi-glass-pint-outline::before{content:"\F130D"}.mdi-glass-stange::before{content:"\F02A7"}.mdi-glass-tulip::before{content:"\F02A8"}.mdi-glass-wine::before{content:"\F0876"}.mdi-glasses::before{content:"\F02AA"}.mdi-globe-light::before{content:"\F066F"}.mdi-globe-light-outline::before{content:"\F12D7"}.mdi-globe-model::before{content:"\F08E9"}.mdi-gmail::before{content:"\F02AB"}.mdi-gnome::before{content:"\F02AC"}.mdi-go-kart::before{content:"\F0D79"}.mdi-go-kart-track::before{content:"\F0D7A"}.mdi-gog::before{content:"\F0BA1"}.mdi-gold::before{content:"\F124F"}.mdi-golf::before{content:"\F0823"}.mdi-golf-cart::before{content:"\F11A4"}.mdi-golf-tee::before{content:"\F1083"}.mdi-gondola::before{content:"\F0686"}.mdi-goodreads::before{content:"\F0D7B"}.mdi-google::before{content:"\F02AD"}.mdi-google-ads::before{content:"\F0C87"}.mdi-google-analytics::before{content:"\F07CC"}.mdi-google-assistant::before{content:"\F07CD"}.mdi-google-cardboard::before{content:"\F02AE"}.mdi-google-chrome::before{content:"\F02AF"}.mdi-google-circles::before{content:"\F02B0"}.mdi-google-circles-communities::before{content:"\F02B1"}.mdi-google-circles-extended::before{content:"\F02B2"}.mdi-google-circles-group::before{content:"\F02B3"}.mdi-google-classroom::before{content:"\F02C0"}.mdi-google-cloud::before{content:"\F11F6"}.mdi-google-downasaur::before{content:"\F1362"}.mdi-google-drive::before{content:"\F02B6"}.mdi-google-earth::before{content:"\F02B7"}.mdi-google-fit::before{content:"\F096C"}.mdi-google-glass::before{content:"\F02B8"}.mdi-google-hangouts::before{content:"\F02C9"}.mdi-google-keep::before{content:"\F06DC"}.mdi-google-lens::before{content:"\F09F6"}.mdi-google-maps::before{content:"\F05F5"}.mdi-google-my-business::before{content:"\F1048"}.mdi-google-nearby::before{content:"\F02B9"}.mdi-google-play::before{content:"\F02BC"}.mdi-google-plus::before{content:"\F02BD"}.mdi-google-podcast::before{content:"\F0EB9"}.mdi-google-spreadsheet::before{content:"\F09F7"}.mdi-google-street-view::before{content:"\F0C88"}.mdi-google-translate::before{content:"\F02BF"}.mdi-gradient-horizontal::before{content:"\F174A"}.mdi-gradient-vertical::before{content:"\F06A0"}.mdi-grain::before{content:"\F0D7C"}.mdi-graph::before{content:"\F1049"}.mdi-graph-outline::before{content:"\F104A"}.mdi-graphql::before{content:"\F0877"}.mdi-grass::before{content:"\F1510"}.mdi-grave-stone::before{content:"\F0BA2"}.mdi-grease-pencil::before{content:"\F0648"}.mdi-greater-than::before{content:"\F096D"}.mdi-greater-than-or-equal::before{content:"\F096E"}.mdi-greenhouse::before{content:"\F002D"}.mdi-grid::before{content:"\F02C1"}.mdi-grid-large::before{content:"\F0758"}.mdi-grid-off::before{content:"\F02C2"}.mdi-grill::before{content:"\F0E45"}.mdi-grill-outline::before{content:"\F118A"}.mdi-group::before{content:"\F02C3"}.mdi-guitar-acoustic::before{content:"\F0771"}.mdi-guitar-electric::before{content:"\F02C4"}.mdi-guitar-pick::before{content:"\F02C5"}.mdi-guitar-pick-outline::before{content:"\F02C6"}.mdi-guy-fawkes-mask::before{content:"\F0825"}.mdi-gymnastics::before{content:"\F1A41"}.mdi-hail::before{content:"\F0AC1"}.mdi-hair-dryer::before{content:"\F10EF"}.mdi-hair-dryer-outline::before{content:"\F10F0"}.mdi-halloween::before{content:"\F0BA3"}.mdi-hamburger::before{content:"\F0685"}.mdi-hamburger-check::before{content:"\F1776"}.mdi-hamburger-minus::before{content:"\F1777"}.mdi-hamburger-off::before{content:"\F1778"}.mdi-hamburger-plus::before{content:"\F1779"}.mdi-hamburger-remove::before{content:"\F177A"}.mdi-hammer::before{content:"\F08EA"}.mdi-hammer-screwdriver::before{content:"\F1322"}.mdi-hammer-sickle::before{content:"\F1887"}.mdi-hammer-wrench::before{content:"\F1323"}.mdi-hand-back-left::before{content:"\F0E46"}.mdi-hand-back-left-off::before{content:"\F1830"}.mdi-hand-back-left-off-outline::before{content:"\F1832"}.mdi-hand-back-left-outline::before{content:"\F182C"}.mdi-hand-back-right::before{content:"\F0E47"}.mdi-hand-back-right-off::before{content:"\F1831"}.mdi-hand-back-right-off-outline::before{content:"\F1833"}.mdi-hand-back-right-outline::before{content:"\F182D"}.mdi-hand-clap::before{content:"\F194B"}.mdi-hand-clap-off::before{content:"\F1A42"}.mdi-hand-coin::before{content:"\F188F"}.mdi-hand-coin-outline::before{content:"\F1890"}.mdi-hand-cycle::before{content:"\F1B9C"}.mdi-hand-extended::before{content:"\F18B6"}.mdi-hand-extended-outline::before{content:"\F18B7"}.mdi-hand-front-left::before{content:"\F182B"}.mdi-hand-front-left-outline::before{content:"\F182E"}.mdi-hand-front-right::before{content:"\F0A4F"}.mdi-hand-front-right-outline::before{content:"\F182F"}.mdi-hand-heart::before{content:"\F10F1"}.mdi-hand-heart-outline::before{content:"\F157E"}.mdi-hand-okay::before{content:"\F0A50"}.mdi-hand-peace::before{content:"\F0A51"}.mdi-hand-peace-variant::before{content:"\F0A52"}.mdi-hand-pointing-down::before{content:"\F0A53"}.mdi-hand-pointing-left::before{content:"\F0A54"}.mdi-hand-pointing-right::before{content:"\F02C7"}.mdi-hand-pointing-up::before{content:"\F0A55"}.mdi-hand-saw::before{content:"\F0E48"}.mdi-hand-wash::before{content:"\F157F"}.mdi-hand-wash-outline::before{content:"\F1580"}.mdi-hand-water::before{content:"\F139F"}.mdi-hand-wave::before{content:"\F1821"}.mdi-hand-wave-outline::before{content:"\F1822"}.mdi-handball::before{content:"\F0F53"}.mdi-handcuffs::before{content:"\F113E"}.mdi-hands-pray::before{content:"\F0579"}.mdi-handshake::before{content:"\F1218"}.mdi-handshake-outline::before{content:"\F15A1"}.mdi-hanger::before{content:"\F02C8"}.mdi-hard-hat::before{content:"\F096F"}.mdi-harddisk::before{content:"\F02CA"}.mdi-harddisk-plus::before{content:"\F104B"}.mdi-harddisk-remove::before{content:"\F104C"}.mdi-hat-fedora::before{content:"\F0BA4"}.mdi-hazard-lights::before{content:"\F0C89"}.mdi-hdmi-port::before{content:"\F1BB8"}.mdi-hdr::before{content:"\F0D7D"}.mdi-hdr-off::before{content:"\F0D7E"}.mdi-head::before{content:"\F135E"}.mdi-head-alert::before{content:"\F1338"}.mdi-head-alert-outline::before{content:"\F1339"}.mdi-head-check::before{content:"\F133A"}.mdi-head-check-outline::before{content:"\F133B"}.mdi-head-cog::before{content:"\F133C"}.mdi-head-cog-outline::before{content:"\F133D"}.mdi-head-dots-horizontal::before{content:"\F133E"}.mdi-head-dots-horizontal-outline::before{content:"\F133F"}.mdi-head-flash::before{content:"\F1340"}.mdi-head-flash-outline::before{content:"\F1341"}.mdi-head-heart::before{content:"\F1342"}.mdi-head-heart-outline::before{content:"\F1343"}.mdi-head-lightbulb::before{content:"\F1344"}.mdi-head-lightbulb-outline::before{content:"\F1345"}.mdi-head-minus::before{content:"\F1346"}.mdi-head-minus-outline::before{content:"\F1347"}.mdi-head-outline::before{content:"\F135F"}.mdi-head-plus::before{content:"\F1348"}.mdi-head-plus-outline::before{content:"\F1349"}.mdi-head-question::before{content:"\F134A"}.mdi-head-question-outline::before{content:"\F134B"}.mdi-head-remove::before{content:"\F134C"}.mdi-head-remove-outline::before{content:"\F134D"}.mdi-head-snowflake::before{content:"\F134E"}.mdi-head-snowflake-outline::before{content:"\F134F"}.mdi-head-sync::before{content:"\F1350"}.mdi-head-sync-outline::before{content:"\F1351"}.mdi-headphones::before{content:"\F02CB"}.mdi-headphones-bluetooth::before{content:"\F0970"}.mdi-headphones-box::before{content:"\F02CC"}.mdi-headphones-off::before{content:"\F07CE"}.mdi-headphones-settings::before{content:"\F02CD"}.mdi-headset::before{content:"\F02CE"}.mdi-headset-dock::before{content:"\F02CF"}.mdi-headset-off::before{content:"\F02D0"}.mdi-heart::before{content:"\F02D1"}.mdi-heart-box::before{content:"\F02D2"}.mdi-heart-box-outline::before{content:"\F02D3"}.mdi-heart-broken::before{content:"\F02D4"}.mdi-heart-broken-outline::before{content:"\F0D14"}.mdi-heart-circle::before{content:"\F0971"}.mdi-heart-circle-outline::before{content:"\F0972"}.mdi-heart-cog::before{content:"\F1663"}.mdi-heart-cog-outline::before{content:"\F1664"}.mdi-heart-flash::before{content:"\F0EF9"}.mdi-heart-half::before{content:"\F06DF"}.mdi-heart-half-full::before{content:"\F06DE"}.mdi-heart-half-outline::before{content:"\F06E0"}.mdi-heart-minus::before{content:"\F142F"}.mdi-heart-minus-outline::before{content:"\F1432"}.mdi-heart-multiple::before{content:"\F0A56"}.mdi-heart-multiple-outline::before{content:"\F0A57"}.mdi-heart-off::before{content:"\F0759"}.mdi-heart-off-outline::before{content:"\F1434"}.mdi-heart-outline::before{content:"\F02D5"}.mdi-heart-plus::before{content:"\F142E"}.mdi-heart-plus-outline::before{content:"\F1431"}.mdi-heart-pulse::before{content:"\F05F6"}.mdi-heart-remove::before{content:"\F1430"}.mdi-heart-remove-outline::before{content:"\F1433"}.mdi-heart-search::before{content:"\F1C8D"}.mdi-heart-settings::before{content:"\F1665"}.mdi-heart-settings-outline::before{content:"\F1666"}.mdi-heat-pump::before{content:"\F1A43"}.mdi-heat-pump-outline::before{content:"\F1A44"}.mdi-heat-wave::before{content:"\F1A45"}.mdi-heating-coil::before{content:"\F1AAF"}.mdi-helicopter::before{content:"\F0AC2"}.mdi-help::before{content:"\F02D6"}.mdi-help-box::before{content:"\F078B"}.mdi-help-box-multiple::before{content:"\F1C0A"}.mdi-help-box-multiple-outline::before{content:"\F1C0B"}.mdi-help-box-outline::before{content:"\F1C0C"}.mdi-help-circle::before{content:"\F02D7"}.mdi-help-circle-outline::before{content:"\F0625"}.mdi-help-network::before{content:"\F06F5"}.mdi-help-network-outline::before{content:"\F0C8A"}.mdi-help-rhombus::before{content:"\F0BA5"}.mdi-help-rhombus-outline::before{content:"\F0BA6"}.mdi-hexadecimal::before{content:"\F12A7"}.mdi-hexagon::before{content:"\F02D8"}.mdi-hexagon-multiple::before{content:"\F06E1"}.mdi-hexagon-multiple-outline::before{content:"\F10F2"}.mdi-hexagon-outline::before{content:"\F02D9"}.mdi-hexagon-slice-1::before{content:"\F0AC3"}.mdi-hexagon-slice-2::before{content:"\F0AC4"}.mdi-hexagon-slice-3::before{content:"\F0AC5"}.mdi-hexagon-slice-4::before{content:"\F0AC6"}.mdi-hexagon-slice-5::before{content:"\F0AC7"}.mdi-hexagon-slice-6::before{content:"\F0AC8"}.mdi-hexagram::before{content:"\F0AC9"}.mdi-hexagram-outline::before{content:"\F0ACA"}.mdi-high-definition::before{content:"\F07CF"}.mdi-high-definition-box::before{content:"\F0878"}.mdi-highway::before{content:"\F05F7"}.mdi-hiking::before{content:"\F0D7F"}.mdi-history::before{content:"\F02DA"}.mdi-hockey-puck::before{content:"\F0879"}.mdi-hockey-sticks::before{content:"\F087A"}.mdi-hololens::before{content:"\F02DB"}.mdi-home::before{content:"\F02DC"}.mdi-home-account::before{content:"\F0826"}.mdi-home-alert::before{content:"\F087B"}.mdi-home-alert-outline::before{content:"\F15D0"}.mdi-home-analytics::before{content:"\F0EBA"}.mdi-home-assistant::before{content:"\F07D0"}.mdi-home-automation::before{content:"\F07D1"}.mdi-home-battery::before{content:"\F1901"}.mdi-home-battery-outline::before{content:"\F1902"}.mdi-home-circle::before{content:"\F07D2"}.mdi-home-circle-outline::before{content:"\F104D"}.mdi-home-city::before{content:"\F0D15"}.mdi-home-city-outline::before{content:"\F0D16"}.mdi-home-clock::before{content:"\F1A12"}.mdi-home-clock-outline::before{content:"\F1A13"}.mdi-home-edit::before{content:"\F1159"}.mdi-home-edit-outline::before{content:"\F115A"}.mdi-home-export-outline::before{content:"\F0F9B"}.mdi-home-flood::before{content:"\F0EFA"}.mdi-home-floor-0::before{content:"\F0DD2"}.mdi-home-floor-1::before{content:"\F0D80"}.mdi-home-floor-2::before{content:"\F0D81"}.mdi-home-floor-3::before{content:"\F0D82"}.mdi-home-floor-a::before{content:"\F0D83"}.mdi-home-floor-b::before{content:"\F0D84"}.mdi-home-floor-g::before{content:"\F0D85"}.mdi-home-floor-l::before{content:"\F0D86"}.mdi-home-floor-negative-1::before{content:"\F0DD3"}.mdi-home-group::before{content:"\F0DD4"}.mdi-home-group-minus::before{content:"\F19C1"}.mdi-home-group-plus::before{content:"\F19C0"}.mdi-home-group-remove::before{content:"\F19C2"}.mdi-home-heart::before{content:"\F0827"}.mdi-home-import-outline::before{content:"\F0F9C"}.mdi-home-lightbulb::before{content:"\F1251"}.mdi-home-lightbulb-outline::before{content:"\F1252"}.mdi-home-lightning-bolt::before{content:"\F1903"}.mdi-home-lightning-bolt-outline::before{content:"\F1904"}.mdi-home-lock::before{content:"\F08EB"}.mdi-home-lock-open::before{content:"\F08EC"}.mdi-home-map-marker::before{content:"\F05F8"}.mdi-home-minus::before{content:"\F0974"}.mdi-home-minus-outline::before{content:"\F13D5"}.mdi-home-modern::before{content:"\F02DD"}.mdi-home-off::before{content:"\F1A46"}.mdi-home-off-outline::before{content:"\F1A47"}.mdi-home-outline::before{content:"\F06A1"}.mdi-home-percent::before{content:"\F1C7C"}.mdi-home-percent-outline::before{content:"\F1C7D"}.mdi-home-plus::before{content:"\F0975"}.mdi-home-plus-outline::before{content:"\F13D6"}.mdi-home-remove::before{content:"\F1247"}.mdi-home-remove-outline::before{content:"\F13D7"}.mdi-home-roof::before{content:"\F112B"}.mdi-home-search::before{content:"\F13B0"}.mdi-home-search-outline::before{content:"\F13B1"}.mdi-home-silo::before{content:"\F1BA0"}.mdi-home-silo-outline::before{content:"\F1BA1"}.mdi-home-sound-in::before{content:"\F1C2F"}.mdi-home-sound-in-outline::before{content:"\F1C30"}.mdi-home-sound-out::before{content:"\F1C31"}.mdi-home-sound-out-outline::before{content:"\F1C32"}.mdi-home-switch::before{content:"\F1794"}.mdi-home-switch-outline::before{content:"\F1795"}.mdi-home-thermometer::before{content:"\F0F54"}.mdi-home-thermometer-outline::before{content:"\F0F55"}.mdi-home-variant::before{content:"\F02DE"}.mdi-home-variant-outline::before{content:"\F0BA7"}.mdi-hook::before{content:"\F06E2"}.mdi-hook-off::before{content:"\F06E3"}.mdi-hoop-house::before{content:"\F0E56"}.mdi-hops::before{content:"\F02DF"}.mdi-horizontal-rotate-clockwise::before{content:"\F10F3"}.mdi-horizontal-rotate-counterclockwise::before{content:"\F10F4"}.mdi-horse::before{content:"\F15BF"}.mdi-horse-human::before{content:"\F15C0"}.mdi-horse-variant::before{content:"\F15C1"}.mdi-horse-variant-fast::before{content:"\F186E"}.mdi-horseshoe::before{content:"\F0A58"}.mdi-hospital::before{content:"\F0FF6"}.mdi-hospital-box::before{content:"\F02E0"}.mdi-hospital-box-outline::before{content:"\F0FF7"}.mdi-hospital-building::before{content:"\F02E1"}.mdi-hospital-marker::before{content:"\F02E2"}.mdi-hot-tub::before{content:"\F0828"}.mdi-hours-12::before{content:"\F1C94"}.mdi-hours-24::before{content:"\F1478"}.mdi-hub::before{content:"\F1C95"}.mdi-hub-outline::before{content:"\F1C96"}.mdi-hubspot::before{content:"\F0D17"}.mdi-hulu::before{content:"\F0829"}.mdi-human::before{content:"\F02E6"}.mdi-human-baby-changing-table::before{content:"\F138B"}.mdi-human-cane::before{content:"\F1581"}.mdi-human-capacity-decrease::before{content:"\F159B"}.mdi-human-capacity-increase::before{content:"\F159C"}.mdi-human-child::before{content:"\F02E7"}.mdi-human-dolly::before{content:"\F1980"}.mdi-human-edit::before{content:"\F14E8"}.mdi-human-female::before{content:"\F0649"}.mdi-human-female-boy::before{content:"\F0A59"}.mdi-human-female-dance::before{content:"\F15C9"}.mdi-human-female-female::before{content:"\F0A5A"}.mdi-human-female-female-child::before{content:"\F1C8E"}.mdi-human-female-girl::before{content:"\F0A5B"}.mdi-human-greeting::before{content:"\F17C4"}.mdi-human-greeting-proximity::before{content:"\F159D"}.mdi-human-greeting-variant::before{content:"\F064A"}.mdi-human-handsdown::before{content:"\F064B"}.mdi-human-handsup::before{content:"\F064C"}.mdi-human-male::before{content:"\F064D"}.mdi-human-male-board::before{content:"\F0890"}.mdi-human-male-board-poll::before{content:"\F0846"}.mdi-human-male-boy::before{content:"\F0A5C"}.mdi-human-male-child::before{content:"\F138C"}.mdi-human-male-female::before{content:"\F02E8"}.mdi-human-male-female-child::before{content:"\F1823"}.mdi-human-male-girl::before{content:"\F0A5D"}.mdi-human-male-height::before{content:"\F0EFB"}.mdi-human-male-height-variant::before{content:"\F0EFC"}.mdi-human-male-male::before{content:"\F0A5E"}.mdi-human-male-male-child::before{content:"\F1C8F"}.mdi-human-non-binary::before{content:"\F1848"}.mdi-human-pregnant::before{content:"\F05CF"}.mdi-human-queue::before{content:"\F1571"}.mdi-human-scooter::before{content:"\F11E9"}.mdi-human-walker::before{content:"\F1B71"}.mdi-human-wheelchair::before{content:"\F138D"}.mdi-human-white-cane::before{content:"\F1981"}.mdi-humble-bundle::before{content:"\F0744"}.mdi-hvac::before{content:"\F1352"}.mdi-hvac-off::before{content:"\F159E"}.mdi-hydraulic-oil-level::before{content:"\F1324"}.mdi-hydraulic-oil-temperature::before{content:"\F1325"}.mdi-hydro-power::before{content:"\F12E5"}.mdi-hydrogen-station::before{content:"\F1894"}.mdi-ice-cream::before{content:"\F082A"}.mdi-ice-cream-off::before{content:"\F0E52"}.mdi-ice-pop::before{content:"\F0EFD"}.mdi-id-card::before{content:"\F0FC0"}.mdi-identifier::before{content:"\F0EFE"}.mdi-ideogram-cjk::before{content:"\F1331"}.mdi-ideogram-cjk-variant::before{content:"\F1332"}.mdi-image::before{content:"\F02E9"}.mdi-image-album::before{content:"\F02EA"}.mdi-image-area::before{content:"\F02EB"}.mdi-image-area-close::before{content:"\F02EC"}.mdi-image-auto-adjust::before{content:"\F0FC1"}.mdi-image-broken::before{content:"\F02ED"}.mdi-image-broken-variant::before{content:"\F02EE"}.mdi-image-check::before{content:"\F1B25"}.mdi-image-check-outline::before{content:"\F1B26"}.mdi-image-edit::before{content:"\F11E3"}.mdi-image-edit-outline::before{content:"\F11E4"}.mdi-image-filter-black-white::before{content:"\F02F0"}.mdi-image-filter-center-focus::before{content:"\F02F1"}.mdi-image-filter-center-focus-strong::before{content:"\F0EFF"}.mdi-image-filter-center-focus-strong-outline::before{content:"\F0F00"}.mdi-image-filter-center-focus-weak::before{content:"\F02F2"}.mdi-image-filter-drama::before{content:"\F02F3"}.mdi-image-filter-drama-outline::before{content:"\F1BFF"}.mdi-image-filter-frames::before{content:"\F02F4"}.mdi-image-filter-hdr::before{content:"\F02F5"}.mdi-image-filter-hdr-outline::before{content:"\F1C64"}.mdi-image-filter-none::before{content:"\F02F6"}.mdi-image-filter-tilt-shift::before{content:"\F02F7"}.mdi-image-filter-vintage::before{content:"\F02F8"}.mdi-image-frame::before{content:"\F0E49"}.mdi-image-lock::before{content:"\F1AB0"}.mdi-image-lock-outline::before{content:"\F1AB1"}.mdi-image-marker::before{content:"\F177B"}.mdi-image-marker-outline::before{content:"\F177C"}.mdi-image-minus::before{content:"\F1419"}.mdi-image-minus-outline::before{content:"\F1B47"}.mdi-image-move::before{content:"\F09F8"}.mdi-image-multiple::before{content:"\F02F9"}.mdi-image-multiple-outline::before{content:"\F02EF"}.mdi-image-off::before{content:"\F082B"}.mdi-image-off-outline::before{content:"\F11D1"}.mdi-image-outline::before{content:"\F0976"}.mdi-image-plus::before{content:"\F087C"}.mdi-image-plus-outline::before{content:"\F1B46"}.mdi-image-refresh::before{content:"\F19FE"}.mdi-image-refresh-outline::before{content:"\F19FF"}.mdi-image-remove::before{content:"\F1418"}.mdi-image-remove-outline::before{content:"\F1B48"}.mdi-image-search::before{content:"\F0977"}.mdi-image-search-outline::before{content:"\F0978"}.mdi-image-size-select-actual::before{content:"\F0C8D"}.mdi-image-size-select-large::before{content:"\F0C8E"}.mdi-image-size-select-small::before{content:"\F0C8F"}.mdi-image-sync::before{content:"\F1A00"}.mdi-image-sync-outline::before{content:"\F1A01"}.mdi-image-text::before{content:"\F160D"}.mdi-import::before{content:"\F02FA"}.mdi-inbox::before{content:"\F0687"}.mdi-inbox-arrow-down::before{content:"\F02FB"}.mdi-inbox-arrow-down-outline::before{content:"\F1270"}.mdi-inbox-arrow-up::before{content:"\F03D1"}.mdi-inbox-arrow-up-outline::before{content:"\F1271"}.mdi-inbox-full::before{content:"\F1272"}.mdi-inbox-full-outline::before{content:"\F1273"}.mdi-inbox-multiple::before{content:"\F08B0"}.mdi-inbox-multiple-outline::before{content:"\F0BA8"}.mdi-inbox-outline::before{content:"\F1274"}.mdi-inbox-remove::before{content:"\F159F"}.mdi-inbox-remove-outline::before{content:"\F15A0"}.mdi-incognito::before{content:"\F05F9"}.mdi-incognito-circle::before{content:"\F1421"}.mdi-incognito-circle-off::before{content:"\F1422"}.mdi-incognito-off::before{content:"\F0075"}.mdi-induction::before{content:"\F184C"}.mdi-infinity::before{content:"\F06E4"}.mdi-information::before{content:"\F02FC"}.mdi-information-box::before{content:"\F1C65"}.mdi-information-box-outline::before{content:"\F1C66"}.mdi-information-off::before{content:"\F178C"}.mdi-information-off-outline::before{content:"\F178D"}.mdi-information-outline::before{content:"\F02FD"}.mdi-information-slab-box::before{content:"\F1C67"}.mdi-information-slab-box-outline::before{content:"\F1C68"}.mdi-information-slab-circle::before{content:"\F1C69"}.mdi-information-slab-circle-outline::before{content:"\F1C6A"}.mdi-information-slab-symbol::before{content:"\F1C6B"}.mdi-information-symbol::before{content:"\F1C6C"}.mdi-information-variant::before{content:"\F064E"}.mdi-information-variant-box::before{content:"\F1C6D"}.mdi-information-variant-box-outline::before{content:"\F1C6E"}.mdi-information-variant-circle::before{content:"\F1C6F"}.mdi-information-variant-circle-outline::before{content:"\F1C70"}.mdi-instagram::before{content:"\F02FE"}.mdi-instrument-triangle::before{content:"\F104E"}.mdi-integrated-circuit-chip::before{content:"\F1913"}.mdi-invert-colors::before{content:"\F0301"}.mdi-invert-colors-off::before{content:"\F0E4A"}.mdi-invoice::before{content:"\F1CD2"}.mdi-invoice-arrow-left::before{content:"\F1CD3"}.mdi-invoice-arrow-left-outline::before{content:"\F1CD4"}.mdi-invoice-arrow-right::before{content:"\F1CD5"}.mdi-invoice-arrow-right-outline::before{content:"\F1CD6"}.mdi-invoice-check::before{content:"\F1CD7"}.mdi-invoice-check-outline::before{content:"\F1CD8"}.mdi-invoice-clock::before{content:"\F1CD9"}.mdi-invoice-clock-outline::before{content:"\F1CDA"}.mdi-invoice-edit::before{content:"\F1CDB"}.mdi-invoice-edit-outline::before{content:"\F1CDC"}.mdi-invoice-export-outline::before{content:"\F1CDD"}.mdi-invoice-fast::before{content:"\F1CDE"}.mdi-invoice-fast-outline::before{content:"\F1CDF"}.mdi-invoice-import::before{content:"\F1CE0"}.mdi-invoice-import-outline::before{content:"\F1CE1"}.mdi-invoice-list::before{content:"\F1CE2"}.mdi-invoice-list-outline::before{content:"\F1CE3"}.mdi-invoice-minus::before{content:"\F1CE4"}.mdi-invoice-minus-outline::before{content:"\F1CE5"}.mdi-invoice-multiple::before{content:"\F1CE6"}.mdi-invoice-multiple-outline::before{content:"\F1CE7"}.mdi-invoice-outline::before{content:"\F1CE8"}.mdi-invoice-plus::before{content:"\F1CE9"}.mdi-invoice-plus-outline::before{content:"\F1CEA"}.mdi-invoice-remove::before{content:"\F1CEB"}.mdi-invoice-remove-outline::before{content:"\F1CEC"}.mdi-invoice-send::before{content:"\F1CED"}.mdi-invoice-send-outline::before{content:"\F1CEE"}.mdi-invoice-text::before{content:"\F1CEF"}.mdi-invoice-text-arrow-left::before{content:"\F1CF0"}.mdi-invoice-text-arrow-left-outline::before{content:"\F1CF1"}.mdi-invoice-text-arrow-right::before{content:"\F1CF2"}.mdi-invoice-text-arrow-right-outline::before{content:"\F1CF3"}.mdi-invoice-text-check::before{content:"\F1CF4"}.mdi-invoice-text-check-outline::before{content:"\F1CF5"}.mdi-invoice-text-clock::before{content:"\F1CF6"}.mdi-invoice-text-clock-outline::before{content:"\F1CF7"}.mdi-invoice-text-edit::before{content:"\F1CF8"}.mdi-invoice-text-edit-outline::before{content:"\F1CF9"}.mdi-invoice-text-fast::before{content:"\F1CFA"}.mdi-invoice-text-fast-outline::before{content:"\F1CFB"}.mdi-invoice-text-minus::before{content:"\F1CFC"}.mdi-invoice-text-minus-outline::before{content:"\F1CFD"}.mdi-invoice-text-multiple::before{content:"\F1CFE"}.mdi-invoice-text-multiple-outline::before{content:"\F1CFF"}.mdi-invoice-text-outline::before{content:"\F1D00"}.mdi-invoice-text-plus::before{content:"\F1D01"}.mdi-invoice-text-plus-outline::before{content:"\F1D02"}.mdi-invoice-text-remove::before{content:"\F1D03"}.mdi-invoice-text-remove-outline::before{content:"\F1D04"}.mdi-invoice-text-send::before{content:"\F1D05"}.mdi-invoice-text-send-outline::before{content:"\F1D06"}.mdi-iobroker::before{content:"\F12E8"}.mdi-ip::before{content:"\F0A5F"}.mdi-ip-network::before{content:"\F0A60"}.mdi-ip-network-outline::before{content:"\F0C90"}.mdi-ip-outline::before{content:"\F1982"}.mdi-ipod::before{content:"\F0C91"}.mdi-iron::before{content:"\F1824"}.mdi-iron-board::before{content:"\F1838"}.mdi-iron-outline::before{content:"\F1825"}.mdi-island::before{content:"\F104F"}.mdi-island-variant::before{content:"\F1CC6"}.mdi-iv-bag::before{content:"\F10B9"}.mdi-jabber::before{content:"\F0DD5"}.mdi-jeepney::before{content:"\F0302"}.mdi-jellyfish::before{content:"\F0F01"}.mdi-jellyfish-outline::before{content:"\F0F02"}.mdi-jira::before{content:"\F0303"}.mdi-jquery::before{content:"\F087D"}.mdi-jsfiddle::before{content:"\F0304"}.mdi-jump-rope::before{content:"\F12FF"}.mdi-kabaddi::before{content:"\F0D87"}.mdi-kangaroo::before{content:"\F1558"}.mdi-karate::before{content:"\F082C"}.mdi-kayaking::before{content:"\F08AF"}.mdi-keg::before{content:"\F0305"}.mdi-kettle::before{content:"\F05FA"}.mdi-kettle-alert::before{content:"\F1317"}.mdi-kettle-alert-outline::before{content:"\F1318"}.mdi-kettle-off::before{content:"\F131B"}.mdi-kettle-off-outline::before{content:"\F131C"}.mdi-kettle-outline::before{content:"\F0F56"}.mdi-kettle-pour-over::before{content:"\F173C"}.mdi-kettle-steam::before{content:"\F1319"}.mdi-kettle-steam-outline::before{content:"\F131A"}.mdi-kettlebell::before{content:"\F1300"}.mdi-key::before{content:"\F0306"}.mdi-key-alert::before{content:"\F1983"}.mdi-key-alert-outline::before{content:"\F1984"}.mdi-key-arrow-right::before{content:"\F1312"}.mdi-key-chain::before{content:"\F1574"}.mdi-key-chain-variant::before{content:"\F1575"}.mdi-key-change::before{content:"\F0307"}.mdi-key-link::before{content:"\F119F"}.mdi-key-minus::before{content:"\F0308"}.mdi-key-outline::before{content:"\F0DD6"}.mdi-key-plus::before{content:"\F0309"}.mdi-key-remove::before{content:"\F030A"}.mdi-key-star::before{content:"\F119E"}.mdi-key-variant::before{content:"\F030B"}.mdi-key-wireless::before{content:"\F0FC2"}.mdi-keyboard::before{content:"\F030C"}.mdi-keyboard-backspace::before{content:"\F030D"}.mdi-keyboard-caps::before{content:"\F030E"}.mdi-keyboard-close::before{content:"\F030F"}.mdi-keyboard-close-outline::before{content:"\F1C00"}.mdi-keyboard-esc::before{content:"\F12B7"}.mdi-keyboard-f1::before{content:"\F12AB"}.mdi-keyboard-f10::before{content:"\F12B4"}.mdi-keyboard-f11::before{content:"\F12B5"}.mdi-keyboard-f12::before{content:"\F12B6"}.mdi-keyboard-f2::before{content:"\F12AC"}.mdi-keyboard-f3::before{content:"\F12AD"}.mdi-keyboard-f4::before{content:"\F12AE"}.mdi-keyboard-f5::before{content:"\F12AF"}.mdi-keyboard-f6::before{content:"\F12B0"}.mdi-keyboard-f7::before{content:"\F12B1"}.mdi-keyboard-f8::before{content:"\F12B2"}.mdi-keyboard-f9::before{content:"\F12B3"}.mdi-keyboard-off::before{content:"\F0310"}.mdi-keyboard-off-outline::before{content:"\F0E4B"}.mdi-keyboard-outline::before{content:"\F097B"}.mdi-keyboard-return::before{content:"\F0311"}.mdi-keyboard-settings::before{content:"\F09F9"}.mdi-keyboard-settings-outline::before{content:"\F09FA"}.mdi-keyboard-space::before{content:"\F1050"}.mdi-keyboard-tab::before{content:"\F0312"}.mdi-keyboard-tab-reverse::before{content:"\F0325"}.mdi-keyboard-variant::before{content:"\F0313"}.mdi-khanda::before{content:"\F10FD"}.mdi-kickstarter::before{content:"\F0745"}.mdi-kite::before{content:"\F1985"}.mdi-kite-outline::before{content:"\F1986"}.mdi-kitesurfing::before{content:"\F1744"}.mdi-klingon::before{content:"\F135B"}.mdi-knife::before{content:"\F09FB"}.mdi-knife-military::before{content:"\F09FC"}.mdi-knob::before{content:"\F1B96"}.mdi-koala::before{content:"\F173F"}.mdi-kodi::before{content:"\F0314"}.mdi-kubernetes::before{content:"\F10FE"}.mdi-label::before{content:"\F0315"}.mdi-label-multiple::before{content:"\F1375"}.mdi-label-multiple-outline::before{content:"\F1376"}.mdi-label-off::before{content:"\F0ACB"}.mdi-label-off-outline::before{content:"\F0ACC"}.mdi-label-outline::before{content:"\F0316"}.mdi-label-percent::before{content:"\F12EA"}.mdi-label-percent-outline::before{content:"\F12EB"}.mdi-label-variant::before{content:"\F0ACD"}.mdi-label-variant-outline::before{content:"\F0ACE"}.mdi-ladder::before{content:"\F15A2"}.mdi-ladybug::before{content:"\F082D"}.mdi-lambda::before{content:"\F0627"}.mdi-lamp::before{content:"\F06B5"}.mdi-lamp-outline::before{content:"\F17D0"}.mdi-lamps::before{content:"\F1576"}.mdi-lamps-outline::before{content:"\F17D1"}.mdi-lan::before{content:"\F0317"}.mdi-lan-check::before{content:"\F12AA"}.mdi-lan-connect::before{content:"\F0318"}.mdi-lan-disconnect::before{content:"\F0319"}.mdi-lan-pending::before{content:"\F031A"}.mdi-land-fields::before{content:"\F1AB2"}.mdi-land-plots::before{content:"\F1AB3"}.mdi-land-plots-circle::before{content:"\F1AB4"}.mdi-land-plots-circle-variant::before{content:"\F1AB5"}.mdi-land-plots-marker::before{content:"\F1C5D"}.mdi-land-rows-horizontal::before{content:"\F1AB6"}.mdi-land-rows-vertical::before{content:"\F1AB7"}.mdi-landslide::before{content:"\F1A48"}.mdi-landslide-outline::before{content:"\F1A49"}.mdi-language-c::before{content:"\F0671"}.mdi-language-cpp::before{content:"\F0672"}.mdi-language-csharp::before{content:"\F031B"}.mdi-language-css3::before{content:"\F031C"}.mdi-language-fortran::before{content:"\F121A"}.mdi-language-go::before{content:"\F07D3"}.mdi-language-haskell::before{content:"\F0C92"}.mdi-language-html5::before{content:"\F031D"}.mdi-language-java::before{content:"\F0B37"}.mdi-language-javascript::before{content:"\F031E"}.mdi-language-kotlin::before{content:"\F1219"}.mdi-language-lua::before{content:"\F08B1"}.mdi-language-markdown::before{content:"\F0354"}.mdi-language-markdown-outline::before{content:"\F0F5B"}.mdi-language-php::before{content:"\F031F"}.mdi-language-python::before{content:"\F0320"}.mdi-language-r::before{content:"\F07D4"}.mdi-language-ruby::before{content:"\F0D2D"}.mdi-language-ruby-on-rails::before{content:"\F0ACF"}.mdi-language-rust::before{content:"\F1617"}.mdi-language-swift::before{content:"\F06E5"}.mdi-language-typescript::before{content:"\F06E6"}.mdi-language-xaml::before{content:"\F0673"}.mdi-laptop::before{content:"\F0322"}.mdi-laptop-account::before{content:"\F1A4A"}.mdi-laptop-off::before{content:"\F06E7"}.mdi-laravel::before{content:"\F0AD0"}.mdi-laser-pointer::before{content:"\F1484"}.mdi-lasso::before{content:"\F0F03"}.mdi-lastpass::before{content:"\F0446"}.mdi-latitude::before{content:"\F0F57"}.mdi-launch::before{content:"\F0327"}.mdi-lava-lamp::before{content:"\F07D5"}.mdi-layers::before{content:"\F0328"}.mdi-layers-edit::before{content:"\F1892"}.mdi-layers-minus::before{content:"\F0E4C"}.mdi-layers-off::before{content:"\F0329"}.mdi-layers-off-outline::before{content:"\F09FD"}.mdi-layers-outline::before{content:"\F09FE"}.mdi-layers-plus::before{content:"\F0E4D"}.mdi-layers-remove::before{content:"\F0E4E"}.mdi-layers-search::before{content:"\F1206"}.mdi-layers-search-outline::before{content:"\F1207"}.mdi-layers-triple::before{content:"\F0F58"}.mdi-layers-triple-outline::before{content:"\F0F59"}.mdi-lead-pencil::before{content:"\F064F"}.mdi-leaf::before{content:"\F032A"}.mdi-leaf-circle::before{content:"\F1905"}.mdi-leaf-circle-outline::before{content:"\F1906"}.mdi-leaf-maple::before{content:"\F0C93"}.mdi-leaf-maple-off::before{content:"\F12DA"}.mdi-leaf-off::before{content:"\F12D9"}.mdi-leak::before{content:"\F0DD7"}.mdi-leak-off::before{content:"\F0DD8"}.mdi-lectern::before{content:"\F1AF0"}.mdi-led-off::before{content:"\F032B"}.mdi-led-on::before{content:"\F032C"}.mdi-led-outline::before{content:"\F032D"}.mdi-led-strip::before{content:"\F07D6"}.mdi-led-strip-variant::before{content:"\F1051"}.mdi-led-strip-variant-off::before{content:"\F1A4B"}.mdi-led-variant-off::before{content:"\F032E"}.mdi-led-variant-on::before{content:"\F032F"}.mdi-led-variant-outline::before{content:"\F0330"}.mdi-leek::before{content:"\F117D"}.mdi-less-than::before{content:"\F097C"}.mdi-less-than-or-equal::before{content:"\F097D"}.mdi-library::before{content:"\F0331"}.mdi-library-outline::before{content:"\F1A22"}.mdi-library-shelves::before{content:"\F0BA9"}.mdi-license::before{content:"\F0FC3"}.mdi-lifebuoy::before{content:"\F087E"}.mdi-light-flood-down::before{content:"\F1987"}.mdi-light-flood-up::before{content:"\F1988"}.mdi-light-recessed::before{content:"\F179B"}.mdi-light-switch::before{content:"\F097E"}.mdi-light-switch-off::before{content:"\F1A24"}.mdi-lightbulb::before{content:"\F0335"}.mdi-lightbulb-alert::before{content:"\F19E1"}.mdi-lightbulb-alert-outline::before{content:"\F19E2"}.mdi-lightbulb-auto::before{content:"\F1800"}.mdi-lightbulb-auto-outline::before{content:"\F1801"}.mdi-lightbulb-cfl::before{content:"\F1208"}.mdi-lightbulb-cfl-off::before{content:"\F1209"}.mdi-lightbulb-cfl-spiral::before{content:"\F1275"}.mdi-lightbulb-cfl-spiral-off::before{content:"\F12C3"}.mdi-lightbulb-fluorescent-tube::before{content:"\F1804"}.mdi-lightbulb-fluorescent-tube-outline::before{content:"\F1805"}.mdi-lightbulb-group::before{content:"\F1253"}.mdi-lightbulb-group-off::before{content:"\F12CD"}.mdi-lightbulb-group-off-outline::before{content:"\F12CE"}.mdi-lightbulb-group-outline::before{content:"\F1254"}.mdi-lightbulb-multiple::before{content:"\F1255"}.mdi-lightbulb-multiple-off::before{content:"\F12CF"}.mdi-lightbulb-multiple-off-outline::before{content:"\F12D0"}.mdi-lightbulb-multiple-outline::before{content:"\F1256"}.mdi-lightbulb-night::before{content:"\F1A4C"}.mdi-lightbulb-night-outline::before{content:"\F1A4D"}.mdi-lightbulb-off::before{content:"\F0E4F"}.mdi-lightbulb-off-outline::before{content:"\F0E50"}.mdi-lightbulb-on::before{content:"\F06E8"}.mdi-lightbulb-on-10::before{content:"\F1A4E"}.mdi-lightbulb-on-20::before{content:"\F1A4F"}.mdi-lightbulb-on-30::before{content:"\F1A50"}.mdi-lightbulb-on-40::before{content:"\F1A51"}.mdi-lightbulb-on-50::before{content:"\F1A52"}.mdi-lightbulb-on-60::before{content:"\F1A53"}.mdi-lightbulb-on-70::before{content:"\F1A54"}.mdi-lightbulb-on-80::before{content:"\F1A55"}.mdi-lightbulb-on-90::before{content:"\F1A56"}.mdi-lightbulb-on-outline::before{content:"\F06E9"}.mdi-lightbulb-outline::before{content:"\F0336"}.mdi-lightbulb-question::before{content:"\F19E3"}.mdi-lightbulb-question-outline::before{content:"\F19E4"}.mdi-lightbulb-spot::before{content:"\F17F4"}.mdi-lightbulb-spot-off::before{content:"\F17F5"}.mdi-lightbulb-variant::before{content:"\F1802"}.mdi-lightbulb-variant-outline::before{content:"\F1803"}.mdi-lighthouse::before{content:"\F09FF"}.mdi-lighthouse-on::before{content:"\F0A00"}.mdi-lightning-bolt::before{content:"\F140B"}.mdi-lightning-bolt-circle::before{content:"\F0820"}.mdi-lightning-bolt-outline::before{content:"\F140C"}.mdi-line-scan::before{content:"\F0624"}.mdi-lingerie::before{content:"\F1476"}.mdi-link::before{content:"\F0337"}.mdi-link-box::before{content:"\F0D1A"}.mdi-link-box-outline::before{content:"\F0D1B"}.mdi-link-box-variant::before{content:"\F0D1C"}.mdi-link-box-variant-outline::before{content:"\F0D1D"}.mdi-link-circle::before{content:"\F1CAC"}.mdi-link-circle-outline::before{content:"\F1CAD"}.mdi-link-edit::before{content:"\F1CAE"}.mdi-link-lock::before{content:"\F10BA"}.mdi-link-off::before{content:"\F0338"}.mdi-link-plus::before{content:"\F0C94"}.mdi-link-variant::before{content:"\F0339"}.mdi-link-variant-minus::before{content:"\F10FF"}.mdi-link-variant-off::before{content:"\F033A"}.mdi-link-variant-plus::before{content:"\F1100"}.mdi-link-variant-remove::before{content:"\F1101"}.mdi-linkedin::before{content:"\F033B"}.mdi-linux::before{content:"\F033D"}.mdi-linux-mint::before{content:"\F08ED"}.mdi-lipstick::before{content:"\F13B5"}.mdi-liquid-spot::before{content:"\F1826"}.mdi-liquor::before{content:"\F191E"}.mdi-list-box::before{content:"\F1B7B"}.mdi-list-box-outline::before{content:"\F1B7C"}.mdi-list-status::before{content:"\F15AB"}.mdi-litecoin::before{content:"\F0A61"}.mdi-loading::before{content:"\F0772"}.mdi-location-enter::before{content:"\F0FC4"}.mdi-location-exit::before{content:"\F0FC5"}.mdi-lock::before{content:"\F033E"}.mdi-lock-alert::before{content:"\F08EE"}.mdi-lock-alert-outline::before{content:"\F15D1"}.mdi-lock-check::before{content:"\F139A"}.mdi-lock-check-outline::before{content:"\F16A8"}.mdi-lock-clock::before{content:"\F097F"}.mdi-lock-minus::before{content:"\F16A9"}.mdi-lock-minus-outline::before{content:"\F16AA"}.mdi-lock-off::before{content:"\F1671"}.mdi-lock-off-outline::before{content:"\F1672"}.mdi-lock-open::before{content:"\F033F"}.mdi-lock-open-alert::before{content:"\F139B"}.mdi-lock-open-alert-outline::before{content:"\F15D2"}.mdi-lock-open-check::before{content:"\F139C"}.mdi-lock-open-check-outline::before{content:"\F16AB"}.mdi-lock-open-minus::before{content:"\F16AC"}.mdi-lock-open-minus-outline::before{content:"\F16AD"}.mdi-lock-open-outline::before{content:"\F0340"}.mdi-lock-open-plus::before{content:"\F16AE"}.mdi-lock-open-plus-outline::before{content:"\F16AF"}.mdi-lock-open-remove::before{content:"\F16B0"}.mdi-lock-open-remove-outline::before{content:"\F16B1"}.mdi-lock-open-variant::before{content:"\F0FC6"}.mdi-lock-open-variant-outline::before{content:"\F0FC7"}.mdi-lock-outline::before{content:"\F0341"}.mdi-lock-pattern::before{content:"\F06EA"}.mdi-lock-percent::before{content:"\F1C12"}.mdi-lock-percent-open::before{content:"\F1C13"}.mdi-lock-percent-open-outline::before{content:"\F1C14"}.mdi-lock-percent-open-variant::before{content:"\F1C15"}.mdi-lock-percent-open-variant-outline::before{content:"\F1C16"}.mdi-lock-percent-outline::before{content:"\F1C17"}.mdi-lock-plus::before{content:"\F05FB"}.mdi-lock-plus-outline::before{content:"\F16B2"}.mdi-lock-question::before{content:"\F08EF"}.mdi-lock-remove::before{content:"\F16B3"}.mdi-lock-remove-outline::before{content:"\F16B4"}.mdi-lock-reset::before{content:"\F0773"}.mdi-lock-smart::before{content:"\F08B2"}.mdi-locker::before{content:"\F07D7"}.mdi-locker-multiple::before{content:"\F07D8"}.mdi-login::before{content:"\F0342"}.mdi-login-variant::before{content:"\F05FC"}.mdi-logout::before{content:"\F0343"}.mdi-logout-variant::before{content:"\F05FD"}.mdi-longitude::before{content:"\F0F5A"}.mdi-looks::before{content:"\F0344"}.mdi-lotion::before{content:"\F1582"}.mdi-lotion-outline::before{content:"\F1583"}.mdi-lotion-plus::before{content:"\F1584"}.mdi-lotion-plus-outline::before{content:"\F1585"}.mdi-loupe::before{content:"\F0345"}.mdi-lumx::before{content:"\F0346"}.mdi-lungs::before{content:"\F1084"}.mdi-mace::before{content:"\F1843"}.mdi-magazine-pistol::before{content:"\F0324"}.mdi-magazine-rifle::before{content:"\F0323"}.mdi-magic-staff::before{content:"\F1844"}.mdi-magnet::before{content:"\F0347"}.mdi-magnet-on::before{content:"\F0348"}.mdi-magnify::before{content:"\F0349"}.mdi-magnify-close::before{content:"\F0980"}.mdi-magnify-expand::before{content:"\F1874"}.mdi-magnify-minus::before{content:"\F034A"}.mdi-magnify-minus-cursor::before{content:"\F0A62"}.mdi-magnify-minus-outline::before{content:"\F06EC"}.mdi-magnify-plus::before{content:"\F034B"}.mdi-magnify-plus-cursor::before{content:"\F0A63"}.mdi-magnify-plus-outline::before{content:"\F06ED"}.mdi-magnify-remove-cursor::before{content:"\F120C"}.mdi-magnify-remove-outline::before{content:"\F120D"}.mdi-magnify-scan::before{content:"\F1276"}.mdi-mail::before{content:"\F0EBB"}.mdi-mailbox::before{content:"\F06EE"}.mdi-mailbox-open::before{content:"\F0D88"}.mdi-mailbox-open-outline::before{content:"\F0D89"}.mdi-mailbox-open-up::before{content:"\F0D8A"}.mdi-mailbox-open-up-outline::before{content:"\F0D8B"}.mdi-mailbox-outline::before{content:"\F0D8C"}.mdi-mailbox-up::before{content:"\F0D8D"}.mdi-mailbox-up-outline::before{content:"\F0D8E"}.mdi-manjaro::before{content:"\F160A"}.mdi-map::before{content:"\F034D"}.mdi-map-check::before{content:"\F0EBC"}.mdi-map-check-outline::before{content:"\F0EBD"}.mdi-map-clock::before{content:"\F0D1E"}.mdi-map-clock-outline::before{content:"\F0D1F"}.mdi-map-legend::before{content:"\F0A01"}.mdi-map-marker::before{content:"\F034E"}.mdi-map-marker-account::before{content:"\F18E3"}.mdi-map-marker-account-outline::before{content:"\F18E4"}.mdi-map-marker-alert::before{content:"\F0F05"}.mdi-map-marker-alert-outline::before{content:"\F0F06"}.mdi-map-marker-check::before{content:"\F0C95"}.mdi-map-marker-check-outline::before{content:"\F12FB"}.mdi-map-marker-circle::before{content:"\F034F"}.mdi-map-marker-distance::before{content:"\F08F0"}.mdi-map-marker-down::before{content:"\F1102"}.mdi-map-marker-left::before{content:"\F12DB"}.mdi-map-marker-left-outline::before{content:"\F12DD"}.mdi-map-marker-minus::before{content:"\F0650"}.mdi-map-marker-minus-outline::before{content:"\F12F9"}.mdi-map-marker-multiple::before{content:"\F0350"}.mdi-map-marker-multiple-outline::before{content:"\F1277"}.mdi-map-marker-off::before{content:"\F0351"}.mdi-map-marker-off-outline::before{content:"\F12FD"}.mdi-map-marker-outline::before{content:"\F07D9"}.mdi-map-marker-path::before{content:"\F0D20"}.mdi-map-marker-plus::before{content:"\F0651"}.mdi-map-marker-plus-outline::before{content:"\F12F8"}.mdi-map-marker-question::before{content:"\F0F07"}.mdi-map-marker-question-outline::before{content:"\F0F08"}.mdi-map-marker-radius::before{content:"\F0352"}.mdi-map-marker-radius-outline::before{content:"\F12FC"}.mdi-map-marker-remove::before{content:"\F0F09"}.mdi-map-marker-remove-outline::before{content:"\F12FA"}.mdi-map-marker-remove-variant::before{content:"\F0F0A"}.mdi-map-marker-right::before{content:"\F12DC"}.mdi-map-marker-right-outline::before{content:"\F12DE"}.mdi-map-marker-star::before{content:"\F1608"}.mdi-map-marker-star-outline::before{content:"\F1609"}.mdi-map-marker-up::before{content:"\F1103"}.mdi-map-minus::before{content:"\F0981"}.mdi-map-outline::before{content:"\F0982"}.mdi-map-plus::before{content:"\F0983"}.mdi-map-search::before{content:"\F0984"}.mdi-map-search-outline::before{content:"\F0985"}.mdi-mapbox::before{content:"\F0BAA"}.mdi-margin::before{content:"\F0353"}.mdi-marker::before{content:"\F0652"}.mdi-marker-cancel::before{content:"\F0DD9"}.mdi-marker-check::before{content:"\F0355"}.mdi-mastodon::before{content:"\F0AD1"}.mdi-material-design::before{content:"\F0986"}.mdi-material-ui::before{content:"\F0357"}.mdi-math-compass::before{content:"\F0358"}.mdi-math-cos::before{content:"\F0C96"}.mdi-math-integral::before{content:"\F0FC8"}.mdi-math-integral-box::before{content:"\F0FC9"}.mdi-math-log::before{content:"\F1085"}.mdi-math-norm::before{content:"\F0FCA"}.mdi-math-norm-box::before{content:"\F0FCB"}.mdi-math-sin::before{content:"\F0C97"}.mdi-math-tan::before{content:"\F0C98"}.mdi-matrix::before{content:"\F0628"}.mdi-medal::before{content:"\F0987"}.mdi-medal-outline::before{content:"\F1326"}.mdi-medical-bag::before{content:"\F06EF"}.mdi-medical-cotton-swab::before{content:"\F1AB8"}.mdi-medication::before{content:"\F1B14"}.mdi-medication-outline::before{content:"\F1B15"}.mdi-meditation::before{content:"\F117B"}.mdi-memory::before{content:"\F035B"}.mdi-memory-arrow-down::before{content:"\F1CA6"}.mdi-menorah::before{content:"\F17D4"}.mdi-menorah-fire::before{content:"\F17D5"}.mdi-menu::before{content:"\F035C"}.mdi-menu-close::before{content:"\F1C90"}.mdi-menu-down::before{content:"\F035D"}.mdi-menu-down-outline::before{content:"\F06B6"}.mdi-menu-left::before{content:"\F035E"}.mdi-menu-left-outline::before{content:"\F0A02"}.mdi-menu-open::before{content:"\F0BAB"}.mdi-menu-right::before{content:"\F035F"}.mdi-menu-right-outline::before{content:"\F0A03"}.mdi-menu-swap::before{content:"\F0A64"}.mdi-menu-swap-outline::before{content:"\F0A65"}.mdi-menu-up::before{content:"\F0360"}.mdi-menu-up-outline::before{content:"\F06B7"}.mdi-merge::before{content:"\F0F5C"}.mdi-message::before{content:"\F0361"}.mdi-message-alert::before{content:"\F0362"}.mdi-message-alert-outline::before{content:"\F0A04"}.mdi-message-arrow-left::before{content:"\F12F2"}.mdi-message-arrow-left-outline::before{content:"\F12F3"}.mdi-message-arrow-right::before{content:"\F12F4"}.mdi-message-arrow-right-outline::before{content:"\F12F5"}.mdi-message-badge::before{content:"\F1941"}.mdi-message-badge-outline::before{content:"\F1942"}.mdi-message-bookmark::before{content:"\F15AC"}.mdi-message-bookmark-outline::before{content:"\F15AD"}.mdi-message-bulleted::before{content:"\F06A2"}.mdi-message-bulleted-off::before{content:"\F06A3"}.mdi-message-check::before{content:"\F1B8A"}.mdi-message-check-outline::before{content:"\F1B8B"}.mdi-message-cog::before{content:"\F06F1"}.mdi-message-cog-outline::before{content:"\F1172"}.mdi-message-draw::before{content:"\F0363"}.mdi-message-fast::before{content:"\F19CC"}.mdi-message-fast-outline::before{content:"\F19CD"}.mdi-message-flash::before{content:"\F15A9"}.mdi-message-flash-outline::before{content:"\F15AA"}.mdi-message-image::before{content:"\F0364"}.mdi-message-image-outline::before{content:"\F116C"}.mdi-message-lock::before{content:"\F0FCC"}.mdi-message-lock-outline::before{content:"\F116D"}.mdi-message-minus::before{content:"\F116E"}.mdi-message-minus-outline::before{content:"\F116F"}.mdi-message-off::before{content:"\F164D"}.mdi-message-off-outline::before{content:"\F164E"}.mdi-message-outline::before{content:"\F0365"}.mdi-message-plus::before{content:"\F0653"}.mdi-message-plus-outline::before{content:"\F10BB"}.mdi-message-processing::before{content:"\F0366"}.mdi-message-processing-outline::before{content:"\F1170"}.mdi-message-question::before{content:"\F173A"}.mdi-message-question-outline::before{content:"\F173B"}.mdi-message-reply::before{content:"\F0367"}.mdi-message-reply-outline::before{content:"\F173D"}.mdi-message-reply-text::before{content:"\F0368"}.mdi-message-reply-text-outline::before{content:"\F173E"}.mdi-message-settings::before{content:"\F06F0"}.mdi-message-settings-outline::before{content:"\F1171"}.mdi-message-star::before{content:"\F069A"}.mdi-message-star-outline::before{content:"\F1250"}.mdi-message-text::before{content:"\F0369"}.mdi-message-text-clock::before{content:"\F1173"}.mdi-message-text-clock-outline::before{content:"\F1174"}.mdi-message-text-fast::before{content:"\F19CE"}.mdi-message-text-fast-outline::before{content:"\F19CF"}.mdi-message-text-lock::before{content:"\F0FCD"}.mdi-message-text-lock-outline::before{content:"\F1175"}.mdi-message-text-outline::before{content:"\F036A"}.mdi-message-video::before{content:"\F036B"}.mdi-meteor::before{content:"\F0629"}.mdi-meter-electric::before{content:"\F1A57"}.mdi-meter-electric-outline::before{content:"\F1A58"}.mdi-meter-gas::before{content:"\F1A59"}.mdi-meter-gas-outline::before{content:"\F1A5A"}.mdi-metronome::before{content:"\F07DA"}.mdi-metronome-tick::before{content:"\F07DB"}.mdi-micro-sd::before{content:"\F07DC"}.mdi-microphone::before{content:"\F036C"}.mdi-microphone-message::before{content:"\F050A"}.mdi-microphone-message-off::before{content:"\F050B"}.mdi-microphone-minus::before{content:"\F08B3"}.mdi-microphone-off::before{content:"\F036D"}.mdi-microphone-outline::before{content:"\F036E"}.mdi-microphone-plus::before{content:"\F08B4"}.mdi-microphone-question::before{content:"\F1989"}.mdi-microphone-question-outline::before{content:"\F198A"}.mdi-microphone-settings::before{content:"\F036F"}.mdi-microphone-variant::before{content:"\F0370"}.mdi-microphone-variant-off::before{content:"\F0371"}.mdi-microscope::before{content:"\F0654"}.mdi-microsoft::before{content:"\F0372"}.mdi-microsoft-access::before{content:"\F138E"}.mdi-microsoft-azure::before{content:"\F0805"}.mdi-microsoft-azure-devops::before{content:"\F0FD5"}.mdi-microsoft-bing::before{content:"\F00A4"}.mdi-microsoft-dynamics-365::before{content:"\F0988"}.mdi-microsoft-edge::before{content:"\F01E9"}.mdi-microsoft-excel::before{content:"\F138F"}.mdi-microsoft-internet-explorer::before{content:"\F0300"}.mdi-microsoft-office::before{content:"\F03C6"}.mdi-microsoft-onedrive::before{content:"\F03CA"}.mdi-microsoft-onenote::before{content:"\F0747"}.mdi-microsoft-outlook::before{content:"\F0D22"}.mdi-microsoft-powerpoint::before{content:"\F1390"}.mdi-microsoft-sharepoint::before{content:"\F1391"}.mdi-microsoft-teams::before{content:"\F02BB"}.mdi-microsoft-visual-studio::before{content:"\F0610"}.mdi-microsoft-visual-studio-code::before{content:"\F0A1E"}.mdi-microsoft-windows::before{content:"\F05B3"}.mdi-microsoft-windows-classic::before{content:"\F0A21"}.mdi-microsoft-word::before{content:"\F1392"}.mdi-microsoft-xbox::before{content:"\F05B9"}.mdi-microsoft-xbox-controller::before{content:"\F05BA"}.mdi-microsoft-xbox-controller-battery-alert::before{content:"\F074B"}.mdi-microsoft-xbox-controller-battery-charging::before{content:"\F0A22"}.mdi-microsoft-xbox-controller-battery-empty::before{content:"\F074C"}.mdi-microsoft-xbox-controller-battery-full::before{content:"\F074D"}.mdi-microsoft-xbox-controller-battery-low::before{content:"\F074E"}.mdi-microsoft-xbox-controller-battery-medium::before{content:"\F074F"}.mdi-microsoft-xbox-controller-battery-unknown::before{content:"\F0750"}.mdi-microsoft-xbox-controller-menu::before{content:"\F0E6F"}.mdi-microsoft-xbox-controller-off::before{content:"\F05BB"}.mdi-microsoft-xbox-controller-view::before{content:"\F0E70"}.mdi-microwave::before{content:"\F0C99"}.mdi-microwave-off::before{content:"\F1423"}.mdi-middleware::before{content:"\F0F5D"}.mdi-middleware-outline::before{content:"\F0F5E"}.mdi-midi::before{content:"\F08F1"}.mdi-midi-port::before{content:"\F08F2"}.mdi-mine::before{content:"\F0DDA"}.mdi-minecraft::before{content:"\F0373"}.mdi-mini-sd::before{content:"\F0A05"}.mdi-minidisc::before{content:"\F0A06"}.mdi-minus::before{content:"\F0374"}.mdi-minus-box::before{content:"\F0375"}.mdi-minus-box-multiple::before{content:"\F1141"}.mdi-minus-box-multiple-outline::before{content:"\F1142"}.mdi-minus-box-outline::before{content:"\F06F2"}.mdi-minus-circle::before{content:"\F0376"}.mdi-minus-circle-multiple::before{content:"\F035A"}.mdi-minus-circle-multiple-outline::before{content:"\F0AD3"}.mdi-minus-circle-off::before{content:"\F1459"}.mdi-minus-circle-off-outline::before{content:"\F145A"}.mdi-minus-circle-outline::before{content:"\F0377"}.mdi-minus-network::before{content:"\F0378"}.mdi-minus-network-outline::before{content:"\F0C9A"}.mdi-minus-thick::before{content:"\F1639"}.mdi-mirror::before{content:"\F11FD"}.mdi-mirror-rectangle::before{content:"\F179F"}.mdi-mirror-variant::before{content:"\F17A0"}.mdi-mixed-martial-arts::before{content:"\F0D8F"}.mdi-mixed-reality::before{content:"\F087F"}.mdi-molecule::before{content:"\F0BAC"}.mdi-molecule-co::before{content:"\F12FE"}.mdi-molecule-co2::before{content:"\F07E4"}.mdi-monitor::before{content:"\F0379"}.mdi-monitor-account::before{content:"\F1A5B"}.mdi-monitor-arrow-down::before{content:"\F19D0"}.mdi-monitor-arrow-down-variant::before{content:"\F19D1"}.mdi-monitor-cellphone::before{content:"\F0989"}.mdi-monitor-cellphone-star::before{content:"\F098A"}.mdi-monitor-dashboard::before{content:"\F0A07"}.mdi-monitor-edit::before{content:"\F12C6"}.mdi-monitor-eye::before{content:"\F13B4"}.mdi-monitor-lock::before{content:"\F0DDB"}.mdi-monitor-multiple::before{content:"\F037A"}.mdi-monitor-off::before{content:"\F0D90"}.mdi-monitor-screenshot::before{content:"\F0E51"}.mdi-monitor-share::before{content:"\F1483"}.mdi-monitor-shimmer::before{content:"\F1104"}.mdi-monitor-small::before{content:"\F1876"}.mdi-monitor-speaker::before{content:"\F0F5F"}.mdi-monitor-speaker-off::before{content:"\F0F60"}.mdi-monitor-star::before{content:"\F0DDC"}.mdi-monitor-vertical::before{content:"\F1C33"}.mdi-moon-first-quarter::before{content:"\F0F61"}.mdi-moon-full::before{content:"\F0F62"}.mdi-moon-last-quarter::before{content:"\F0F63"}.mdi-moon-new::before{content:"\F0F64"}.mdi-moon-waning-crescent::before{content:"\F0F65"}.mdi-moon-waning-gibbous::before{content:"\F0F66"}.mdi-moon-waxing-crescent::before{content:"\F0F67"}.mdi-moon-waxing-gibbous::before{content:"\F0F68"}.mdi-moped::before{content:"\F1086"}.mdi-moped-electric::before{content:"\F15B7"}.mdi-moped-electric-outline::before{content:"\F15B8"}.mdi-moped-outline::before{content:"\F15B9"}.mdi-more::before{content:"\F037B"}.mdi-mortar-pestle::before{content:"\F1748"}.mdi-mortar-pestle-plus::before{content:"\F03F1"}.mdi-mosque::before{content:"\F0D45"}.mdi-mosque-outline::before{content:"\F1827"}.mdi-mother-heart::before{content:"\F1314"}.mdi-mother-nurse::before{content:"\F0D21"}.mdi-motion::before{content:"\F15B2"}.mdi-motion-outline::before{content:"\F15B3"}.mdi-motion-pause::before{content:"\F1590"}.mdi-motion-pause-outline::before{content:"\F1592"}.mdi-motion-play::before{content:"\F158F"}.mdi-motion-play-outline::before{content:"\F1591"}.mdi-motion-sensor::before{content:"\F0D91"}.mdi-motion-sensor-off::before{content:"\F1435"}.mdi-motorbike::before{content:"\F037C"}.mdi-motorbike-electric::before{content:"\F15BA"}.mdi-motorbike-off::before{content:"\F1B16"}.mdi-mouse::before{content:"\F037D"}.mdi-mouse-bluetooth::before{content:"\F098B"}.mdi-mouse-left-click::before{content:"\F1D07"}.mdi-mouse-left-click-outline::before{content:"\F1D08"}.mdi-mouse-move-down::before{content:"\F1550"}.mdi-mouse-move-up::before{content:"\F1551"}.mdi-mouse-move-vertical::before{content:"\F1552"}.mdi-mouse-off::before{content:"\F037E"}.mdi-mouse-outline::before{content:"\F1D09"}.mdi-mouse-right-click::before{content:"\F1D0A"}.mdi-mouse-right-click-outline::before{content:"\F1D0B"}.mdi-mouse-scroll-wheel::before{content:"\F1D0C"}.mdi-mouse-variant::before{content:"\F037F"}.mdi-mouse-variant-off::before{content:"\F0380"}.mdi-move-resize::before{content:"\F0655"}.mdi-move-resize-variant::before{content:"\F0656"}.mdi-movie::before{content:"\F0381"}.mdi-movie-check::before{content:"\F16F3"}.mdi-movie-check-outline::before{content:"\F16F4"}.mdi-movie-cog::before{content:"\F16F5"}.mdi-movie-cog-outline::before{content:"\F16F6"}.mdi-movie-edit::before{content:"\F1122"}.mdi-movie-edit-outline::before{content:"\F1123"}.mdi-movie-filter::before{content:"\F1124"}.mdi-movie-filter-outline::before{content:"\F1125"}.mdi-movie-minus::before{content:"\F16F7"}.mdi-movie-minus-outline::before{content:"\F16F8"}.mdi-movie-off::before{content:"\F16F9"}.mdi-movie-off-outline::before{content:"\F16FA"}.mdi-movie-open::before{content:"\F0FCE"}.mdi-movie-open-check::before{content:"\F16FB"}.mdi-movie-open-check-outline::before{content:"\F16FC"}.mdi-movie-open-cog::before{content:"\F16FD"}.mdi-movie-open-cog-outline::before{content:"\F16FE"}.mdi-movie-open-edit::before{content:"\F16FF"}.mdi-movie-open-edit-outline::before{content:"\F1700"}.mdi-movie-open-minus::before{content:"\F1701"}.mdi-movie-open-minus-outline::before{content:"\F1702"}.mdi-movie-open-off::before{content:"\F1703"}.mdi-movie-open-off-outline::before{content:"\F1704"}.mdi-movie-open-outline::before{content:"\F0FCF"}.mdi-movie-open-play::before{content:"\F1705"}.mdi-movie-open-play-outline::before{content:"\F1706"}.mdi-movie-open-plus::before{content:"\F1707"}.mdi-movie-open-plus-outline::before{content:"\F1708"}.mdi-movie-open-remove::before{content:"\F1709"}.mdi-movie-open-remove-outline::before{content:"\F170A"}.mdi-movie-open-settings::before{content:"\F170B"}.mdi-movie-open-settings-outline::before{content:"\F170C"}.mdi-movie-open-star::before{content:"\F170D"}.mdi-movie-open-star-outline::before{content:"\F170E"}.mdi-movie-outline::before{content:"\F0DDD"}.mdi-movie-play::before{content:"\F170F"}.mdi-movie-play-outline::before{content:"\F1710"}.mdi-movie-plus::before{content:"\F1711"}.mdi-movie-plus-outline::before{content:"\F1712"}.mdi-movie-remove::before{content:"\F1713"}.mdi-movie-remove-outline::before{content:"\F1714"}.mdi-movie-roll::before{content:"\F07DE"}.mdi-movie-search::before{content:"\F11D2"}.mdi-movie-search-outline::before{content:"\F11D3"}.mdi-movie-settings::before{content:"\F1715"}.mdi-movie-settings-outline::before{content:"\F1716"}.mdi-movie-star::before{content:"\F1717"}.mdi-movie-star-outline::before{content:"\F1718"}.mdi-mower::before{content:"\F166F"}.mdi-mower-bag::before{content:"\F1670"}.mdi-mower-bag-on::before{content:"\F1B60"}.mdi-mower-on::before{content:"\F1B5F"}.mdi-muffin::before{content:"\F098C"}.mdi-multicast::before{content:"\F1893"}.mdi-multimedia::before{content:"\F1B97"}.mdi-multiplication::before{content:"\F0382"}.mdi-multiplication-box::before{content:"\F0383"}.mdi-mushroom::before{content:"\F07DF"}.mdi-mushroom-off::before{content:"\F13FA"}.mdi-mushroom-off-outline::before{content:"\F13FB"}.mdi-mushroom-outline::before{content:"\F07E0"}.mdi-music::before{content:"\F075A"}.mdi-music-accidental-double-flat::before{content:"\F0F69"}.mdi-music-accidental-double-sharp::before{content:"\F0F6A"}.mdi-music-accidental-flat::before{content:"\F0F6B"}.mdi-music-accidental-natural::before{content:"\F0F6C"}.mdi-music-accidental-sharp::before{content:"\F0F6D"}.mdi-music-box::before{content:"\F0384"}.mdi-music-box-multiple::before{content:"\F0333"}.mdi-music-box-multiple-outline::before{content:"\F0F04"}.mdi-music-box-outline::before{content:"\F0385"}.mdi-music-circle::before{content:"\F0386"}.mdi-music-circle-outline::before{content:"\F0AD4"}.mdi-music-clef-alto::before{content:"\F0F6E"}.mdi-music-clef-bass::before{content:"\F0F6F"}.mdi-music-clef-treble::before{content:"\F0F70"}.mdi-music-note::before{content:"\F0387"}.mdi-music-note-bluetooth::before{content:"\F05FE"}.mdi-music-note-bluetooth-off::before{content:"\F05FF"}.mdi-music-note-eighth::before{content:"\F0388"}.mdi-music-note-eighth-dotted::before{content:"\F0F71"}.mdi-music-note-half::before{content:"\F0389"}.mdi-music-note-half-dotted::before{content:"\F0F72"}.mdi-music-note-minus::before{content:"\F1B89"}.mdi-music-note-off::before{content:"\F038A"}.mdi-music-note-off-outline::before{content:"\F0F73"}.mdi-music-note-outline::before{content:"\F0F74"}.mdi-music-note-plus::before{content:"\F0DDE"}.mdi-music-note-quarter::before{content:"\F038B"}.mdi-music-note-quarter-dotted::before{content:"\F0F75"}.mdi-music-note-sixteenth::before{content:"\F038C"}.mdi-music-note-sixteenth-dotted::before{content:"\F0F76"}.mdi-music-note-whole::before{content:"\F038D"}.mdi-music-note-whole-dotted::before{content:"\F0F77"}.mdi-music-off::before{content:"\F075B"}.mdi-music-rest-eighth::before{content:"\F0F78"}.mdi-music-rest-half::before{content:"\F0F79"}.mdi-music-rest-quarter::before{content:"\F0F7A"}.mdi-music-rest-sixteenth::before{content:"\F0F7B"}.mdi-music-rest-whole::before{content:"\F0F7C"}.mdi-mustache::before{content:"\F15DE"}.mdi-nail::before{content:"\F0DDF"}.mdi-nas::before{content:"\F08F3"}.mdi-nativescript::before{content:"\F0880"}.mdi-nature::before{content:"\F038E"}.mdi-nature-outline::before{content:"\F1C71"}.mdi-nature-people::before{content:"\F038F"}.mdi-nature-people-outline::before{content:"\F1C72"}.mdi-navigation::before{content:"\F0390"}.mdi-navigation-outline::before{content:"\F1607"}.mdi-navigation-variant::before{content:"\F18F0"}.mdi-navigation-variant-outline::before{content:"\F18F1"}.mdi-near-me::before{content:"\F05CD"}.mdi-necklace::before{content:"\F0F0B"}.mdi-needle::before{content:"\F0391"}.mdi-needle-off::before{content:"\F19D2"}.mdi-netflix::before{content:"\F0746"}.mdi-network::before{content:"\F06F3"}.mdi-network-off::before{content:"\F0C9B"}.mdi-network-off-outline::before{content:"\F0C9C"}.mdi-network-outline::before{content:"\F0C9D"}.mdi-network-pos::before{content:"\F1ACB"}.mdi-network-strength-1::before{content:"\F08F4"}.mdi-network-strength-1-alert::before{content:"\F08F5"}.mdi-network-strength-2::before{content:"\F08F6"}.mdi-network-strength-2-alert::before{content:"\F08F7"}.mdi-network-strength-3::before{content:"\F08F8"}.mdi-network-strength-3-alert::before{content:"\F08F9"}.mdi-network-strength-4::before{content:"\F08FA"}.mdi-network-strength-4-alert::before{content:"\F08FB"}.mdi-network-strength-4-cog::before{content:"\F191A"}.mdi-network-strength-off::before{content:"\F08FC"}.mdi-network-strength-off-outline::before{content:"\F08FD"}.mdi-network-strength-outline::before{content:"\F08FE"}.mdi-new-box::before{content:"\F0394"}.mdi-newspaper::before{content:"\F0395"}.mdi-newspaper-check::before{content:"\F1943"}.mdi-newspaper-minus::before{content:"\F0F0C"}.mdi-newspaper-plus::before{content:"\F0F0D"}.mdi-newspaper-remove::before{content:"\F1944"}.mdi-newspaper-variant::before{content:"\F1001"}.mdi-newspaper-variant-multiple::before{content:"\F1002"}.mdi-newspaper-variant-multiple-outline::before{content:"\F1003"}.mdi-newspaper-variant-outline::before{content:"\F1004"}.mdi-nfc::before{content:"\F0396"}.mdi-nfc-search-variant::before{content:"\F0E53"}.mdi-nfc-tap::before{content:"\F0397"}.mdi-nfc-variant::before{content:"\F0398"}.mdi-nfc-variant-off::before{content:"\F0E54"}.mdi-ninja::before{content:"\F0774"}.mdi-nintendo-game-boy::before{content:"\F1393"}.mdi-nintendo-switch::before{content:"\F07E1"}.mdi-nintendo-wii::before{content:"\F05AB"}.mdi-nintendo-wiiu::before{content:"\F072D"}.mdi-nix::before{content:"\F1105"}.mdi-nodejs::before{content:"\F0399"}.mdi-noodles::before{content:"\F117E"}.mdi-not-equal::before{content:"\F098D"}.mdi-not-equal-variant::before{content:"\F098E"}.mdi-note::before{content:"\F039A"}.mdi-note-alert::before{content:"\F177D"}.mdi-note-alert-outline::before{content:"\F177E"}.mdi-note-check::before{content:"\F177F"}.mdi-note-check-outline::before{content:"\F1780"}.mdi-note-edit::before{content:"\F1781"}.mdi-note-edit-outline::before{content:"\F1782"}.mdi-note-minus::before{content:"\F164F"}.mdi-note-minus-outline::before{content:"\F1650"}.mdi-note-multiple::before{content:"\F06B8"}.mdi-note-multiple-outline::before{content:"\F06B9"}.mdi-note-off::before{content:"\F1783"}.mdi-note-off-outline::before{content:"\F1784"}.mdi-note-outline::before{content:"\F039B"}.mdi-note-plus::before{content:"\F039C"}.mdi-note-plus-outline::before{content:"\F039D"}.mdi-note-remove::before{content:"\F1651"}.mdi-note-remove-outline::before{content:"\F1652"}.mdi-note-search::before{content:"\F1653"}.mdi-note-search-outline::before{content:"\F1654"}.mdi-note-text::before{content:"\F039E"}.mdi-note-text-outline::before{content:"\F11D7"}.mdi-notebook::before{content:"\F082E"}.mdi-notebook-check::before{content:"\F14F5"}.mdi-notebook-check-outline::before{content:"\F14F6"}.mdi-notebook-edit::before{content:"\F14E7"}.mdi-notebook-edit-outline::before{content:"\F14E9"}.mdi-notebook-heart::before{content:"\F1A0B"}.mdi-notebook-heart-outline::before{content:"\F1A0C"}.mdi-notebook-minus::before{content:"\F1610"}.mdi-notebook-minus-outline::before{content:"\F1611"}.mdi-notebook-multiple::before{content:"\F0E55"}.mdi-notebook-outline::before{content:"\F0EBF"}.mdi-notebook-plus::before{content:"\F1612"}.mdi-notebook-plus-outline::before{content:"\F1613"}.mdi-notebook-remove::before{content:"\F1614"}.mdi-notebook-remove-outline::before{content:"\F1615"}.mdi-notification-clear-all::before{content:"\F039F"}.mdi-npm::before{content:"\F06F7"}.mdi-nuke::before{content:"\F06A4"}.mdi-null::before{content:"\F07E2"}.mdi-numeric::before{content:"\F03A0"}.mdi-numeric-0::before{content:"\F0B39"}.mdi-numeric-0-box::before{content:"\F03A1"}.mdi-numeric-0-box-multiple::before{content:"\F0F0E"}.mdi-numeric-0-box-multiple-outline::before{content:"\F03A2"}.mdi-numeric-0-box-outline::before{content:"\F03A3"}.mdi-numeric-0-circle::before{content:"\F0C9E"}.mdi-numeric-0-circle-outline::before{content:"\F0C9F"}.mdi-numeric-1::before{content:"\F0B3A"}.mdi-numeric-1-box::before{content:"\F03A4"}.mdi-numeric-1-box-multiple::before{content:"\F0F0F"}.mdi-numeric-1-box-multiple-outline::before{content:"\F03A5"}.mdi-numeric-1-box-outline::before{content:"\F03A6"}.mdi-numeric-1-circle::before{content:"\F0CA0"}.mdi-numeric-1-circle-outline::before{content:"\F0CA1"}.mdi-numeric-10::before{content:"\F0FE9"}.mdi-numeric-10-box::before{content:"\F0F7D"}.mdi-numeric-10-box-multiple::before{content:"\F0FEA"}.mdi-numeric-10-box-multiple-outline::before{content:"\F0FEB"}.mdi-numeric-10-box-outline::before{content:"\F0F7E"}.mdi-numeric-10-circle::before{content:"\F0FEC"}.mdi-numeric-10-circle-outline::before{content:"\F0FED"}.mdi-numeric-2::before{content:"\F0B3B"}.mdi-numeric-2-box::before{content:"\F03A7"}.mdi-numeric-2-box-multiple::before{content:"\F0F10"}.mdi-numeric-2-box-multiple-outline::before{content:"\F03A8"}.mdi-numeric-2-box-outline::before{content:"\F03A9"}.mdi-numeric-2-circle::before{content:"\F0CA2"}.mdi-numeric-2-circle-outline::before{content:"\F0CA3"}.mdi-numeric-3::before{content:"\F0B3C"}.mdi-numeric-3-box::before{content:"\F03AA"}.mdi-numeric-3-box-multiple::before{content:"\F0F11"}.mdi-numeric-3-box-multiple-outline::before{content:"\F03AB"}.mdi-numeric-3-box-outline::before{content:"\F03AC"}.mdi-numeric-3-circle::before{content:"\F0CA4"}.mdi-numeric-3-circle-outline::before{content:"\F0CA5"}.mdi-numeric-4::before{content:"\F0B3D"}.mdi-numeric-4-box::before{content:"\F03AD"}.mdi-numeric-4-box-multiple::before{content:"\F0F12"}.mdi-numeric-4-box-multiple-outline::before{content:"\F03B2"}.mdi-numeric-4-box-outline::before{content:"\F03AE"}.mdi-numeric-4-circle::before{content:"\F0CA6"}.mdi-numeric-4-circle-outline::before{content:"\F0CA7"}.mdi-numeric-5::before{content:"\F0B3E"}.mdi-numeric-5-box::before{content:"\F03B1"}.mdi-numeric-5-box-multiple::before{content:"\F0F13"}.mdi-numeric-5-box-multiple-outline::before{content:"\F03AF"}.mdi-numeric-5-box-outline::before{content:"\F03B0"}.mdi-numeric-5-circle::before{content:"\F0CA8"}.mdi-numeric-5-circle-outline::before{content:"\F0CA9"}.mdi-numeric-6::before{content:"\F0B3F"}.mdi-numeric-6-box::before{content:"\F03B3"}.mdi-numeric-6-box-multiple::before{content:"\F0F14"}.mdi-numeric-6-box-multiple-outline::before{content:"\F03B4"}.mdi-numeric-6-box-outline::before{content:"\F03B5"}.mdi-numeric-6-circle::before{content:"\F0CAA"}.mdi-numeric-6-circle-outline::before{content:"\F0CAB"}.mdi-numeric-7::before{content:"\F0B40"}.mdi-numeric-7-box::before{content:"\F03B6"}.mdi-numeric-7-box-multiple::before{content:"\F0F15"}.mdi-numeric-7-box-multiple-outline::before{content:"\F03B7"}.mdi-numeric-7-box-outline::before{content:"\F03B8"}.mdi-numeric-7-circle::before{content:"\F0CAC"}.mdi-numeric-7-circle-outline::before{content:"\F0CAD"}.mdi-numeric-8::before{content:"\F0B41"}.mdi-numeric-8-box::before{content:"\F03B9"}.mdi-numeric-8-box-multiple::before{content:"\F0F16"}.mdi-numeric-8-box-multiple-outline::before{content:"\F03BA"}.mdi-numeric-8-box-outline::before{content:"\F03BB"}.mdi-numeric-8-circle::before{content:"\F0CAE"}.mdi-numeric-8-circle-outline::before{content:"\F0CAF"}.mdi-numeric-9::before{content:"\F0B42"}.mdi-numeric-9-box::before{content:"\F03BC"}.mdi-numeric-9-box-multiple::before{content:"\F0F17"}.mdi-numeric-9-box-multiple-outline::before{content:"\F03BD"}.mdi-numeric-9-box-outline::before{content:"\F03BE"}.mdi-numeric-9-circle::before{content:"\F0CB0"}.mdi-numeric-9-circle-outline::before{content:"\F0CB1"}.mdi-numeric-9-plus::before{content:"\F0FEE"}.mdi-numeric-9-plus-box::before{content:"\F03BF"}.mdi-numeric-9-plus-box-multiple::before{content:"\F0F18"}.mdi-numeric-9-plus-box-multiple-outline::before{content:"\F03C0"}.mdi-numeric-9-plus-box-outline::before{content:"\F03C1"}.mdi-numeric-9-plus-circle::before{content:"\F0CB2"}.mdi-numeric-9-plus-circle-outline::before{content:"\F0CB3"}.mdi-numeric-negative-1::before{content:"\F1052"}.mdi-numeric-off::before{content:"\F19D3"}.mdi-numeric-positive-1::before{content:"\F15CB"}.mdi-nut::before{content:"\F06F8"}.mdi-nutrition::before{content:"\F03C2"}.mdi-nuxt::before{content:"\F1106"}.mdi-oar::before{content:"\F067C"}.mdi-ocarina::before{content:"\F0DE0"}.mdi-oci::before{content:"\F12E9"}.mdi-ocr::before{content:"\F113A"}.mdi-octagon::before{content:"\F03C3"}.mdi-octagon-outline::before{content:"\F03C4"}.mdi-octagram::before{content:"\F06F9"}.mdi-octagram-edit::before{content:"\F1C34"}.mdi-octagram-edit-outline::before{content:"\F1C35"}.mdi-octagram-minus::before{content:"\F1C36"}.mdi-octagram-minus-outline::before{content:"\F1C37"}.mdi-octagram-outline::before{content:"\F0775"}.mdi-octagram-plus::before{content:"\F1C38"}.mdi-octagram-plus-outline::before{content:"\F1C39"}.mdi-octahedron::before{content:"\F1950"}.mdi-octahedron-off::before{content:"\F1951"}.mdi-odnoklassniki::before{content:"\F03C5"}.mdi-offer::before{content:"\F121B"}.mdi-office-building::before{content:"\F0991"}.mdi-office-building-cog::before{content:"\F1949"}.mdi-office-building-cog-outline::before{content:"\F194A"}.mdi-office-building-marker::before{content:"\F1520"}.mdi-office-building-marker-outline::before{content:"\F1521"}.mdi-office-building-minus::before{content:"\F1BAA"}.mdi-office-building-minus-outline::before{content:"\F1BAB"}.mdi-office-building-outline::before{content:"\F151F"}.mdi-office-building-plus::before{content:"\F1BA8"}.mdi-office-building-plus-outline::before{content:"\F1BA9"}.mdi-office-building-remove::before{content:"\F1BAC"}.mdi-office-building-remove-outline::before{content:"\F1BAD"}.mdi-oil::before{content:"\F03C7"}.mdi-oil-lamp::before{content:"\F0F19"}.mdi-oil-level::before{content:"\F1053"}.mdi-oil-temperature::before{content:"\F0FF8"}.mdi-om::before{content:"\F0973"}.mdi-omega::before{content:"\F03C9"}.mdi-one-up::before{content:"\F0BAD"}.mdi-onepassword::before{content:"\F0881"}.mdi-opacity::before{content:"\F05CC"}.mdi-open-in-app::before{content:"\F03CB"}.mdi-open-in-new::before{content:"\F03CC"}.mdi-open-source-initiative::before{content:"\F0BAE"}.mdi-openid::before{content:"\F03CD"}.mdi-opera::before{content:"\F03CE"}.mdi-orbit::before{content:"\F0018"}.mdi-orbit-variant::before{content:"\F15DB"}.mdi-order-alphabetical-ascending::before{content:"\F020D"}.mdi-order-alphabetical-descending::before{content:"\F0D07"}.mdi-order-bool-ascending::before{content:"\F02BE"}.mdi-order-bool-ascending-variant::before{content:"\F098F"}.mdi-order-bool-descending::before{content:"\F1384"}.mdi-order-bool-descending-variant::before{content:"\F0990"}.mdi-order-numeric-ascending::before{content:"\F0545"}.mdi-order-numeric-descending::before{content:"\F0546"}.mdi-origin::before{content:"\F0B43"}.mdi-ornament::before{content:"\F03CF"}.mdi-ornament-variant::before{content:"\F03D0"}.mdi-outdoor-lamp::before{content:"\F1054"}.mdi-overscan::before{content:"\F1005"}.mdi-owl::before{content:"\F03D2"}.mdi-pac-man::before{content:"\F0BAF"}.mdi-package::before{content:"\F03D3"}.mdi-package-check::before{content:"\F1B51"}.mdi-package-down::before{content:"\F03D4"}.mdi-package-up::before{content:"\F03D5"}.mdi-package-variant::before{content:"\F03D6"}.mdi-package-variant-closed::before{content:"\F03D7"}.mdi-package-variant-closed-check::before{content:"\F1B52"}.mdi-package-variant-closed-minus::before{content:"\F19D4"}.mdi-package-variant-closed-plus::before{content:"\F19D5"}.mdi-package-variant-closed-remove::before{content:"\F19D6"}.mdi-package-variant-minus::before{content:"\F19D7"}.mdi-package-variant-plus::before{content:"\F19D8"}.mdi-package-variant-remove::before{content:"\F19D9"}.mdi-page-first::before{content:"\F0600"}.mdi-page-last::before{content:"\F0601"}.mdi-page-layout-body::before{content:"\F06FA"}.mdi-page-layout-footer::before{content:"\F06FB"}.mdi-page-layout-header::before{content:"\F06FC"}.mdi-page-layout-header-footer::before{content:"\F0F7F"}.mdi-page-layout-sidebar-left::before{content:"\F06FD"}.mdi-page-layout-sidebar-right::before{content:"\F06FE"}.mdi-page-next::before{content:"\F0BB0"}.mdi-page-next-outline::before{content:"\F0BB1"}.mdi-page-previous::before{content:"\F0BB2"}.mdi-page-previous-outline::before{content:"\F0BB3"}.mdi-pail::before{content:"\F1417"}.mdi-pail-minus::before{content:"\F1437"}.mdi-pail-minus-outline::before{content:"\F143C"}.mdi-pail-off::before{content:"\F1439"}.mdi-pail-off-outline::before{content:"\F143E"}.mdi-pail-outline::before{content:"\F143A"}.mdi-pail-plus::before{content:"\F1436"}.mdi-pail-plus-outline::before{content:"\F143B"}.mdi-pail-remove::before{content:"\F1438"}.mdi-pail-remove-outline::before{content:"\F143D"}.mdi-palette::before{content:"\F03D8"}.mdi-palette-advanced::before{content:"\F03D9"}.mdi-palette-outline::before{content:"\F0E0C"}.mdi-palette-swatch::before{content:"\F08B5"}.mdi-palette-swatch-outline::before{content:"\F135C"}.mdi-palette-swatch-variant::before{content:"\F195A"}.mdi-palm-tree::before{content:"\F1055"}.mdi-pan::before{content:"\F0BB4"}.mdi-pan-bottom-left::before{content:"\F0BB5"}.mdi-pan-bottom-right::before{content:"\F0BB6"}.mdi-pan-down::before{content:"\F0BB7"}.mdi-pan-horizontal::before{content:"\F0BB8"}.mdi-pan-left::before{content:"\F0BB9"}.mdi-pan-right::before{content:"\F0BBA"}.mdi-pan-top-left::before{content:"\F0BBB"}.mdi-pan-top-right::before{content:"\F0BBC"}.mdi-pan-up::before{content:"\F0BBD"}.mdi-pan-vertical::before{content:"\F0BBE"}.mdi-panda::before{content:"\F03DA"}.mdi-pandora::before{content:"\F03DB"}.mdi-panorama::before{content:"\F03DC"}.mdi-panorama-fisheye::before{content:"\F03DD"}.mdi-panorama-horizontal::before{content:"\F1928"}.mdi-panorama-horizontal-outline::before{content:"\F03DE"}.mdi-panorama-outline::before{content:"\F198C"}.mdi-panorama-sphere::before{content:"\F198D"}.mdi-panorama-sphere-outline::before{content:"\F198E"}.mdi-panorama-variant::before{content:"\F198F"}.mdi-panorama-variant-outline::before{content:"\F1990"}.mdi-panorama-vertical::before{content:"\F1929"}.mdi-panorama-vertical-outline::before{content:"\F03DF"}.mdi-panorama-wide-angle::before{content:"\F195F"}.mdi-panorama-wide-angle-outline::before{content:"\F03E0"}.mdi-paper-cut-vertical::before{content:"\F03E1"}.mdi-paper-roll::before{content:"\F1157"}.mdi-paper-roll-outline::before{content:"\F1158"}.mdi-paperclip::before{content:"\F03E2"}.mdi-paperclip-check::before{content:"\F1AC6"}.mdi-paperclip-lock::before{content:"\F19DA"}.mdi-paperclip-minus::before{content:"\F1AC7"}.mdi-paperclip-off::before{content:"\F1AC8"}.mdi-paperclip-plus::before{content:"\F1AC9"}.mdi-paperclip-remove::before{content:"\F1ACA"}.mdi-parachute::before{content:"\F0CB4"}.mdi-parachute-outline::before{content:"\F0CB5"}.mdi-paragliding::before{content:"\F1745"}.mdi-parking::before{content:"\F03E3"}.mdi-party-popper::before{content:"\F1056"}.mdi-passport::before{content:"\F07E3"}.mdi-passport-alert::before{content:"\F1CB8"}.mdi-passport-biometric::before{content:"\F0DE1"}.mdi-passport-cancel::before{content:"\F1CB9"}.mdi-passport-check::before{content:"\F1CBA"}.mdi-passport-minus::before{content:"\F1CBB"}.mdi-passport-plus::before{content:"\F1CBC"}.mdi-passport-remove::before{content:"\F1CBD"}.mdi-pasta::before{content:"\F1160"}.mdi-patio-heater::before{content:"\F0F80"}.mdi-patreon::before{content:"\F0882"}.mdi-pause::before{content:"\F03E4"}.mdi-pause-box::before{content:"\F00BC"}.mdi-pause-box-outline::before{content:"\F1B7A"}.mdi-pause-circle::before{content:"\F03E5"}.mdi-pause-circle-outline::before{content:"\F03E6"}.mdi-pause-octagon::before{content:"\F03E7"}.mdi-pause-octagon-outline::before{content:"\F03E8"}.mdi-paw::before{content:"\F03E9"}.mdi-paw-off::before{content:"\F0657"}.mdi-paw-off-outline::before{content:"\F1676"}.mdi-paw-outline::before{content:"\F1675"}.mdi-peace::before{content:"\F0884"}.mdi-peanut::before{content:"\F0FFC"}.mdi-peanut-off::before{content:"\F0FFD"}.mdi-peanut-off-outline::before{content:"\F0FFF"}.mdi-peanut-outline::before{content:"\F0FFE"}.mdi-pen::before{content:"\F03EA"}.mdi-pen-lock::before{content:"\F0DE2"}.mdi-pen-minus::before{content:"\F0DE3"}.mdi-pen-off::before{content:"\F0DE4"}.mdi-pen-plus::before{content:"\F0DE5"}.mdi-pen-remove::before{content:"\F0DE6"}.mdi-pencil::before{content:"\F03EB"}.mdi-pencil-box::before{content:"\F03EC"}.mdi-pencil-box-multiple::before{content:"\F1144"}.mdi-pencil-box-multiple-outline::before{content:"\F1145"}.mdi-pencil-box-outline::before{content:"\F03ED"}.mdi-pencil-circle::before{content:"\F06FF"}.mdi-pencil-circle-outline::before{content:"\F0776"}.mdi-pencil-lock::before{content:"\F03EE"}.mdi-pencil-lock-outline::before{content:"\F0DE7"}.mdi-pencil-minus::before{content:"\F0DE8"}.mdi-pencil-minus-outline::before{content:"\F0DE9"}.mdi-pencil-off::before{content:"\F03EF"}.mdi-pencil-off-outline::before{content:"\F0DEA"}.mdi-pencil-outline::before{content:"\F0CB6"}.mdi-pencil-plus::before{content:"\F0DEB"}.mdi-pencil-plus-outline::before{content:"\F0DEC"}.mdi-pencil-remove::before{content:"\F0DED"}.mdi-pencil-remove-outline::before{content:"\F0DEE"}.mdi-pencil-ruler::before{content:"\F1353"}.mdi-pencil-ruler-outline::before{content:"\F1C11"}.mdi-penguin::before{content:"\F0EC0"}.mdi-pentagon::before{content:"\F0701"}.mdi-pentagon-outline::before{content:"\F0700"}.mdi-pentagram::before{content:"\F1667"}.mdi-percent::before{content:"\F03F0"}.mdi-percent-box::before{content:"\F1A02"}.mdi-percent-box-outline::before{content:"\F1A03"}.mdi-percent-circle::before{content:"\F1A04"}.mdi-percent-circle-outline::before{content:"\F1A05"}.mdi-percent-outline::before{content:"\F1278"}.mdi-periodic-table::before{content:"\F08B6"}.mdi-perspective-less::before{content:"\F0D23"}.mdi-perspective-more::before{content:"\F0D24"}.mdi-ph::before{content:"\F17C5"}.mdi-phone::before{content:"\F03F2"}.mdi-phone-alert::before{content:"\F0F1A"}.mdi-phone-alert-outline::before{content:"\F118E"}.mdi-phone-bluetooth::before{content:"\F03F3"}.mdi-phone-bluetooth-outline::before{content:"\F118F"}.mdi-phone-cancel::before{content:"\F10BC"}.mdi-phone-cancel-outline::before{content:"\F1190"}.mdi-phone-check::before{content:"\F11A9"}.mdi-phone-check-outline::before{content:"\F11AA"}.mdi-phone-classic::before{content:"\F0602"}.mdi-phone-classic-off::before{content:"\F1279"}.mdi-phone-clock::before{content:"\F19DB"}.mdi-phone-dial::before{content:"\F1559"}.mdi-phone-dial-outline::before{content:"\F155A"}.mdi-phone-forward::before{content:"\F03F4"}.mdi-phone-forward-outline::before{content:"\F1191"}.mdi-phone-hangup::before{content:"\F03F5"}.mdi-phone-hangup-outline::before{content:"\F1192"}.mdi-phone-in-talk::before{content:"\F03F6"}.mdi-phone-in-talk-outline::before{content:"\F1182"}.mdi-phone-incoming::before{content:"\F03F7"}.mdi-phone-incoming-outgoing::before{content:"\F1B3F"}.mdi-phone-incoming-outgoing-outline::before{content:"\F1B40"}.mdi-phone-incoming-outline::before{content:"\F1193"}.mdi-phone-lock::before{content:"\F03F8"}.mdi-phone-lock-outline::before{content:"\F1194"}.mdi-phone-log::before{content:"\F03F9"}.mdi-phone-log-outline::before{content:"\F1195"}.mdi-phone-message::before{content:"\F1196"}.mdi-phone-message-outline::before{content:"\F1197"}.mdi-phone-minus::before{content:"\F0658"}.mdi-phone-minus-outline::before{content:"\F1198"}.mdi-phone-missed::before{content:"\F03FA"}.mdi-phone-missed-outline::before{content:"\F11A5"}.mdi-phone-off::before{content:"\F0DEF"}.mdi-phone-off-outline::before{content:"\F11A6"}.mdi-phone-outgoing::before{content:"\F03FB"}.mdi-phone-outgoing-outline::before{content:"\F1199"}.mdi-phone-outline::before{content:"\F0DF0"}.mdi-phone-paused::before{content:"\F03FC"}.mdi-phone-paused-outline::before{content:"\F119A"}.mdi-phone-plus::before{content:"\F0659"}.mdi-phone-plus-outline::before{content:"\F119B"}.mdi-phone-refresh::before{content:"\F1993"}.mdi-phone-refresh-outline::before{content:"\F1994"}.mdi-phone-remove::before{content:"\F152F"}.mdi-phone-remove-outline::before{content:"\F1530"}.mdi-phone-return::before{content:"\F082F"}.mdi-phone-return-outline::before{content:"\F119C"}.mdi-phone-ring::before{content:"\F11AB"}.mdi-phone-ring-outline::before{content:"\F11AC"}.mdi-phone-rotate-landscape::before{content:"\F0885"}.mdi-phone-rotate-portrait::before{content:"\F0886"}.mdi-phone-settings::before{content:"\F03FD"}.mdi-phone-settings-outline::before{content:"\F119D"}.mdi-phone-sync::before{content:"\F1995"}.mdi-phone-sync-outline::before{content:"\F1996"}.mdi-phone-voip::before{content:"\F03FE"}.mdi-pi::before{content:"\F03FF"}.mdi-pi-box::before{content:"\F0400"}.mdi-pi-hole::before{content:"\F0DF1"}.mdi-piano::before{content:"\F067D"}.mdi-piano-off::before{content:"\F0698"}.mdi-pickaxe::before{content:"\F08B7"}.mdi-picture-in-picture-bottom-right::before{content:"\F0E57"}.mdi-picture-in-picture-bottom-right-outline::before{content:"\F0E58"}.mdi-picture-in-picture-top-right::before{content:"\F0E59"}.mdi-picture-in-picture-top-right-outline::before{content:"\F0E5A"}.mdi-pier::before{content:"\F0887"}.mdi-pier-crane::before{content:"\F0888"}.mdi-pig::before{content:"\F0401"}.mdi-pig-variant::before{content:"\F1006"}.mdi-pig-variant-outline::before{content:"\F1678"}.mdi-piggy-bank::before{content:"\F1007"}.mdi-piggy-bank-outline::before{content:"\F1679"}.mdi-pill::before{content:"\F0402"}.mdi-pill-multiple::before{content:"\F1B4C"}.mdi-pill-off::before{content:"\F1A5C"}.mdi-pillar::before{content:"\F0702"}.mdi-pin::before{content:"\F0403"}.mdi-pin-off::before{content:"\F0404"}.mdi-pin-off-outline::before{content:"\F0930"}.mdi-pin-outline::before{content:"\F0931"}.mdi-pine-tree::before{content:"\F0405"}.mdi-pine-tree-box::before{content:"\F0406"}.mdi-pine-tree-fire::before{content:"\F141A"}.mdi-pine-tree-variant::before{content:"\F1C73"}.mdi-pine-tree-variant-outline::before{content:"\F1C74"}.mdi-pinterest::before{content:"\F0407"}.mdi-pinwheel::before{content:"\F0AD5"}.mdi-pinwheel-outline::before{content:"\F0AD6"}.mdi-pipe::before{content:"\F07E5"}.mdi-pipe-disconnected::before{content:"\F07E6"}.mdi-pipe-leak::before{content:"\F0889"}.mdi-pipe-valve::before{content:"\F184D"}.mdi-pipe-wrench::before{content:"\F1354"}.mdi-pirate::before{content:"\F0A08"}.mdi-pistol::before{content:"\F0703"}.mdi-piston::before{content:"\F088A"}.mdi-pitchfork::before{content:"\F1553"}.mdi-pizza::before{content:"\F0409"}.mdi-plane-car::before{content:"\F1AFF"}.mdi-plane-train::before{content:"\F1B00"}.mdi-play::before{content:"\F040A"}.mdi-play-box::before{content:"\F127A"}.mdi-play-box-edit-outline::before{content:"\F1C3A"}.mdi-play-box-lock::before{content:"\F1A16"}.mdi-play-box-lock-open::before{content:"\F1A17"}.mdi-play-box-lock-open-outline::before{content:"\F1A18"}.mdi-play-box-lock-outline::before{content:"\F1A19"}.mdi-play-box-multiple::before{content:"\F0D19"}.mdi-play-box-multiple-outline::before{content:"\F13E6"}.mdi-play-box-outline::before{content:"\F040B"}.mdi-play-circle::before{content:"\F040C"}.mdi-play-circle-outline::before{content:"\F040D"}.mdi-play-network::before{content:"\F088B"}.mdi-play-network-outline::before{content:"\F0CB7"}.mdi-play-outline::before{content:"\F0F1B"}.mdi-play-pause::before{content:"\F040E"}.mdi-play-protected-content::before{content:"\F040F"}.mdi-play-speed::before{content:"\F08FF"}.mdi-playlist-check::before{content:"\F05C7"}.mdi-playlist-edit::before{content:"\F0900"}.mdi-playlist-minus::before{content:"\F0410"}.mdi-playlist-music::before{content:"\F0CB8"}.mdi-playlist-music-outline::before{content:"\F0CB9"}.mdi-playlist-play::before{content:"\F0411"}.mdi-playlist-plus::before{content:"\F0412"}.mdi-playlist-remove::before{content:"\F0413"}.mdi-playlist-star::before{content:"\F0DF2"}.mdi-plex::before{content:"\F06BA"}.mdi-pliers::before{content:"\F19A4"}.mdi-plus::before{content:"\F0415"}.mdi-plus-box::before{content:"\F0416"}.mdi-plus-box-multiple::before{content:"\F0334"}.mdi-plus-box-multiple-outline::before{content:"\F1143"}.mdi-plus-box-outline::before{content:"\F0704"}.mdi-plus-circle::before{content:"\F0417"}.mdi-plus-circle-multiple::before{content:"\F034C"}.mdi-plus-circle-multiple-outline::before{content:"\F0418"}.mdi-plus-circle-outline::before{content:"\F0419"}.mdi-plus-lock::before{content:"\F1A5D"}.mdi-plus-lock-open::before{content:"\F1A5E"}.mdi-plus-minus::before{content:"\F0992"}.mdi-plus-minus-box::before{content:"\F0993"}.mdi-plus-minus-variant::before{content:"\F14C9"}.mdi-plus-network::before{content:"\F041A"}.mdi-plus-network-outline::before{content:"\F0CBA"}.mdi-plus-outline::before{content:"\F0705"}.mdi-plus-thick::before{content:"\F11EC"}.mdi-pocket::before{content:"\F1CBE"}.mdi-podcast::before{content:"\F0994"}.mdi-podium::before{content:"\F0D25"}.mdi-podium-bronze::before{content:"\F0D26"}.mdi-podium-gold::before{content:"\F0D27"}.mdi-podium-silver::before{content:"\F0D28"}.mdi-point-of-sale::before{content:"\F0D92"}.mdi-pokeball::before{content:"\F041D"}.mdi-pokemon-go::before{content:"\F0A09"}.mdi-poker-chip::before{content:"\F0830"}.mdi-polaroid::before{content:"\F041E"}.mdi-police-badge::before{content:"\F1167"}.mdi-police-badge-outline::before{content:"\F1168"}.mdi-police-station::before{content:"\F1839"}.mdi-poll::before{content:"\F041F"}.mdi-polo::before{content:"\F14C3"}.mdi-polymer::before{content:"\F0421"}.mdi-pool::before{content:"\F0606"}.mdi-pool-thermometer::before{content:"\F1A5F"}.mdi-popcorn::before{content:"\F0422"}.mdi-post::before{content:"\F1008"}.mdi-post-lamp::before{content:"\F1A60"}.mdi-post-outline::before{content:"\F1009"}.mdi-postage-stamp::before{content:"\F0CBB"}.mdi-pot::before{content:"\F02E5"}.mdi-pot-mix::before{content:"\F065B"}.mdi-pot-mix-outline::before{content:"\F0677"}.mdi-pot-outline::before{content:"\F02FF"}.mdi-pot-steam::before{content:"\F065A"}.mdi-pot-steam-outline::before{content:"\F0326"}.mdi-pound::before{content:"\F0423"}.mdi-pound-box::before{content:"\F0424"}.mdi-pound-box-outline::before{content:"\F117F"}.mdi-power::before{content:"\F0425"}.mdi-power-cycle::before{content:"\F0901"}.mdi-power-off::before{content:"\F0902"}.mdi-power-on::before{content:"\F0903"}.mdi-power-plug::before{content:"\F06A5"}.mdi-power-plug-battery::before{content:"\F1C3B"}.mdi-power-plug-battery-outline::before{content:"\F1C3C"}.mdi-power-plug-off::before{content:"\F06A6"}.mdi-power-plug-off-outline::before{content:"\F1424"}.mdi-power-plug-outline::before{content:"\F1425"}.mdi-power-settings::before{content:"\F0426"}.mdi-power-sleep::before{content:"\F0904"}.mdi-power-socket::before{content:"\F0427"}.mdi-power-socket-au::before{content:"\F0905"}.mdi-power-socket-ch::before{content:"\F0FB3"}.mdi-power-socket-de::before{content:"\F1107"}.mdi-power-socket-eu::before{content:"\F07E7"}.mdi-power-socket-fr::before{content:"\F1108"}.mdi-power-socket-it::before{content:"\F14FF"}.mdi-power-socket-jp::before{content:"\F1109"}.mdi-power-socket-uk::before{content:"\F07E8"}.mdi-power-socket-us::before{content:"\F07E9"}.mdi-power-standby::before{content:"\F0906"}.mdi-powershell::before{content:"\F0A0A"}.mdi-prescription::before{content:"\F0706"}.mdi-presentation::before{content:"\F0428"}.mdi-presentation-play::before{content:"\F0429"}.mdi-pretzel::before{content:"\F1562"}.mdi-printer::before{content:"\F042A"}.mdi-printer-3d::before{content:"\F042B"}.mdi-printer-3d-nozzle::before{content:"\F0E5B"}.mdi-printer-3d-nozzle-alert::before{content:"\F11C0"}.mdi-printer-3d-nozzle-alert-outline::before{content:"\F11C1"}.mdi-printer-3d-nozzle-heat::before{content:"\F18B8"}.mdi-printer-3d-nozzle-heat-outline::before{content:"\F18B9"}.mdi-printer-3d-nozzle-off::before{content:"\F1B19"}.mdi-printer-3d-nozzle-off-outline::before{content:"\F1B1A"}.mdi-printer-3d-nozzle-outline::before{content:"\F0E5C"}.mdi-printer-3d-off::before{content:"\F1B0E"}.mdi-printer-alert::before{content:"\F042C"}.mdi-printer-check::before{content:"\F1146"}.mdi-printer-eye::before{content:"\F1458"}.mdi-printer-off::before{content:"\F0E5D"}.mdi-printer-off-outline::before{content:"\F1785"}.mdi-printer-outline::before{content:"\F1786"}.mdi-printer-pos::before{content:"\F1057"}.mdi-printer-pos-alert::before{content:"\F1BBC"}.mdi-printer-pos-alert-outline::before{content:"\F1BBD"}.mdi-printer-pos-cancel::before{content:"\F1BBE"}.mdi-printer-pos-cancel-outline::before{content:"\F1BBF"}.mdi-printer-pos-check::before{content:"\F1BC0"}.mdi-printer-pos-check-outline::before{content:"\F1BC1"}.mdi-printer-pos-cog::before{content:"\F1BC2"}.mdi-printer-pos-cog-outline::before{content:"\F1BC3"}.mdi-printer-pos-edit::before{content:"\F1BC4"}.mdi-printer-pos-edit-outline::before{content:"\F1BC5"}.mdi-printer-pos-minus::before{content:"\F1BC6"}.mdi-printer-pos-minus-outline::before{content:"\F1BC7"}.mdi-printer-pos-network::before{content:"\F1BC8"}.mdi-printer-pos-network-outline::before{content:"\F1BC9"}.mdi-printer-pos-off::before{content:"\F1BCA"}.mdi-printer-pos-off-outline::before{content:"\F1BCB"}.mdi-printer-pos-outline::before{content:"\F1BCC"}.mdi-printer-pos-pause::before{content:"\F1BCD"}.mdi-printer-pos-pause-outline::before{content:"\F1BCE"}.mdi-printer-pos-play::before{content:"\F1BCF"}.mdi-printer-pos-play-outline::before{content:"\F1BD0"}.mdi-printer-pos-plus::before{content:"\F1BD1"}.mdi-printer-pos-plus-outline::before{content:"\F1BD2"}.mdi-printer-pos-refresh::before{content:"\F1BD3"}.mdi-printer-pos-refresh-outline::before{content:"\F1BD4"}.mdi-printer-pos-remove::before{content:"\F1BD5"}.mdi-printer-pos-remove-outline::before{content:"\F1BD6"}.mdi-printer-pos-star::before{content:"\F1BD7"}.mdi-printer-pos-star-outline::before{content:"\F1BD8"}.mdi-printer-pos-stop::before{content:"\F1BD9"}.mdi-printer-pos-stop-outline::before{content:"\F1BDA"}.mdi-printer-pos-sync::before{content:"\F1BDB"}.mdi-printer-pos-sync-outline::before{content:"\F1BDC"}.mdi-printer-pos-wrench::before{content:"\F1BDD"}.mdi-printer-pos-wrench-outline::before{content:"\F1BDE"}.mdi-printer-search::before{content:"\F1457"}.mdi-printer-settings::before{content:"\F0707"}.mdi-printer-wireless::before{content:"\F0A0B"}.mdi-priority-high::before{content:"\F0603"}.mdi-priority-low::before{content:"\F0604"}.mdi-professional-hexagon::before{content:"\F042D"}.mdi-progress-alert::before{content:"\F0CBC"}.mdi-progress-check::before{content:"\F0995"}.mdi-progress-clock::before{content:"\F0996"}.mdi-progress-close::before{content:"\F110A"}.mdi-progress-download::before{content:"\F0997"}.mdi-progress-helper::before{content:"\F1BA2"}.mdi-progress-pencil::before{content:"\F1787"}.mdi-progress-question::before{content:"\F1522"}.mdi-progress-star::before{content:"\F1788"}.mdi-progress-star-four-points::before{content:"\F1C3D"}.mdi-progress-tag::before{content:"\F1D0D"}.mdi-progress-upload::before{content:"\F0998"}.mdi-progress-wrench::before{content:"\F0CBD"}.mdi-projector::before{content:"\F042E"}.mdi-projector-off::before{content:"\F1A23"}.mdi-projector-screen::before{content:"\F042F"}.mdi-projector-screen-off::before{content:"\F180D"}.mdi-projector-screen-off-outline::before{content:"\F180E"}.mdi-projector-screen-outline::before{content:"\F1724"}.mdi-projector-screen-variant::before{content:"\F180F"}.mdi-projector-screen-variant-off::before{content:"\F1810"}.mdi-projector-screen-variant-off-outline::before{content:"\F1811"}.mdi-projector-screen-variant-outline::before{content:"\F1812"}.mdi-propane-tank::before{content:"\F1357"}.mdi-propane-tank-outline::before{content:"\F1358"}.mdi-protocol::before{content:"\F0FD8"}.mdi-publish::before{content:"\F06A7"}.mdi-publish-off::before{content:"\F1945"}.mdi-pulse::before{content:"\F0430"}.mdi-pump::before{content:"\F1402"}.mdi-pump-off::before{content:"\F1B22"}.mdi-pumpkin::before{content:"\F0BBF"}.mdi-purse::before{content:"\F0F1C"}.mdi-purse-outline::before{content:"\F0F1D"}.mdi-puzzle::before{content:"\F0431"}.mdi-puzzle-check::before{content:"\F1426"}.mdi-puzzle-check-outline::before{content:"\F1427"}.mdi-puzzle-edit::before{content:"\F14D3"}.mdi-puzzle-edit-outline::before{content:"\F14D9"}.mdi-puzzle-heart::before{content:"\F14D4"}.mdi-puzzle-heart-outline::before{content:"\F14DA"}.mdi-puzzle-minus::before{content:"\F14D1"}.mdi-puzzle-minus-outline::before{content:"\F14D7"}.mdi-puzzle-outline::before{content:"\F0A66"}.mdi-puzzle-plus::before{content:"\F14D0"}.mdi-puzzle-plus-outline::before{content:"\F14D6"}.mdi-puzzle-remove::before{content:"\F14D2"}.mdi-puzzle-remove-outline::before{content:"\F14D8"}.mdi-puzzle-star::before{content:"\F14D5"}.mdi-puzzle-star-outline::before{content:"\F14DB"}.mdi-pyramid::before{content:"\F1952"}.mdi-pyramid-off::before{content:"\F1953"}.mdi-qi::before{content:"\F0999"}.mdi-qqchat::before{content:"\F0605"}.mdi-qrcode::before{content:"\F0432"}.mdi-qrcode-edit::before{content:"\F08B8"}.mdi-qrcode-minus::before{content:"\F118C"}.mdi-qrcode-plus::before{content:"\F118B"}.mdi-qrcode-remove::before{content:"\F118D"}.mdi-qrcode-scan::before{content:"\F0433"}.mdi-quadcopter::before{content:"\F0434"}.mdi-quality-high::before{content:"\F0435"}.mdi-quality-low::before{content:"\F0A0C"}.mdi-quality-medium::before{content:"\F0A0D"}.mdi-queue-first-in-last-out::before{content:"\F1CAF"}.mdi-quora::before{content:"\F0D29"}.mdi-rabbit::before{content:"\F0907"}.mdi-rabbit-variant::before{content:"\F1A61"}.mdi-rabbit-variant-outline::before{content:"\F1A62"}.mdi-racing-helmet::before{content:"\F0D93"}.mdi-racquetball::before{content:"\F0D94"}.mdi-radar::before{content:"\F0437"}.mdi-radiator::before{content:"\F0438"}.mdi-radiator-disabled::before{content:"\F0AD7"}.mdi-radiator-off::before{content:"\F0AD8"}.mdi-radio::before{content:"\F0439"}.mdi-radio-am::before{content:"\F0CBE"}.mdi-radio-fm::before{content:"\F0CBF"}.mdi-radio-handheld::before{content:"\F043A"}.mdi-radio-off::before{content:"\F121C"}.mdi-radio-tower::before{content:"\F043B"}.mdi-radioactive::before{content:"\F043C"}.mdi-radioactive-circle::before{content:"\F185D"}.mdi-radioactive-circle-outline::before{content:"\F185E"}.mdi-radioactive-off::before{content:"\F0EC1"}.mdi-radiobox-blank::before{content:"\F043D"}.mdi-radiobox-indeterminate-variant::before{content:"\F1C5E"}.mdi-radiobox-marked::before{content:"\F043E"}.mdi-radiology-box::before{content:"\F14C5"}.mdi-radiology-box-outline::before{content:"\F14C6"}.mdi-radius::before{content:"\F0CC0"}.mdi-radius-outline::before{content:"\F0CC1"}.mdi-railroad-light::before{content:"\F0F1E"}.mdi-rake::before{content:"\F1544"}.mdi-raspberry-pi::before{content:"\F043F"}.mdi-raw::before{content:"\F1A0F"}.mdi-raw-off::before{content:"\F1A10"}.mdi-ray-end::before{content:"\F0440"}.mdi-ray-end-arrow::before{content:"\F0441"}.mdi-ray-start::before{content:"\F0442"}.mdi-ray-start-arrow::before{content:"\F0443"}.mdi-ray-start-end::before{content:"\F0444"}.mdi-ray-start-vertex-end::before{content:"\F15D8"}.mdi-ray-vertex::before{content:"\F0445"}.mdi-razor-double-edge::before{content:"\F1997"}.mdi-razor-single-edge::before{content:"\F1998"}.mdi-react::before{content:"\F0708"}.mdi-read::before{content:"\F0447"}.mdi-receipt::before{content:"\F0824"}.mdi-receipt-clock::before{content:"\F1C3E"}.mdi-receipt-clock-outline::before{content:"\F1C3F"}.mdi-receipt-outline::before{content:"\F04F7"}.mdi-receipt-send::before{content:"\F1C40"}.mdi-receipt-send-outline::before{content:"\F1C41"}.mdi-receipt-text::before{content:"\F0449"}.mdi-receipt-text-arrow-left::before{content:"\F1C42"}.mdi-receipt-text-arrow-left-outline::before{content:"\F1C43"}.mdi-receipt-text-arrow-right::before{content:"\F1C44"}.mdi-receipt-text-arrow-right-outline::before{content:"\F1C45"}.mdi-receipt-text-check::before{content:"\F1A63"}.mdi-receipt-text-check-outline::before{content:"\F1A64"}.mdi-receipt-text-clock::before{content:"\F1C46"}.mdi-receipt-text-clock-outline::before{content:"\F1C47"}.mdi-receipt-text-edit::before{content:"\F1C48"}.mdi-receipt-text-edit-outline::before{content:"\F1C49"}.mdi-receipt-text-minus::before{content:"\F1A65"}.mdi-receipt-text-minus-outline::before{content:"\F1A66"}.mdi-receipt-text-outline::before{content:"\F19DC"}.mdi-receipt-text-plus::before{content:"\F1A67"}.mdi-receipt-text-plus-outline::before{content:"\F1A68"}.mdi-receipt-text-remove::before{content:"\F1A69"}.mdi-receipt-text-remove-outline::before{content:"\F1A6A"}.mdi-receipt-text-send::before{content:"\F1C4A"}.mdi-receipt-text-send-outline::before{content:"\F1C4B"}.mdi-record::before{content:"\F044A"}.mdi-record-circle::before{content:"\F0EC2"}.mdi-record-circle-outline::before{content:"\F0EC3"}.mdi-record-player::before{content:"\F099A"}.mdi-record-rec::before{content:"\F044B"}.mdi-rectangle::before{content:"\F0E5E"}.mdi-rectangle-outline::before{content:"\F0E5F"}.mdi-recycle::before{content:"\F044C"}.mdi-recycle-variant::before{content:"\F139D"}.mdi-reddit::before{content:"\F044D"}.mdi-redhat::before{content:"\F111B"}.mdi-redo::before{content:"\F044E"}.mdi-redo-variant::before{content:"\F044F"}.mdi-reflect-horizontal::before{content:"\F0A0E"}.mdi-reflect-vertical::before{content:"\F0A0F"}.mdi-refresh::before{content:"\F0450"}.mdi-refresh-auto::before{content:"\F18F2"}.mdi-refresh-circle::before{content:"\F1377"}.mdi-regex::before{content:"\F0451"}.mdi-registered-trademark::before{content:"\F0A67"}.mdi-reiterate::before{content:"\F1588"}.mdi-relation-many-to-many::before{content:"\F1496"}.mdi-relation-many-to-one::before{content:"\F1497"}.mdi-relation-many-to-one-or-many::before{content:"\F1498"}.mdi-relation-many-to-only-one::before{content:"\F1499"}.mdi-relation-many-to-zero-or-many::before{content:"\F149A"}.mdi-relation-many-to-zero-or-one::before{content:"\F149B"}.mdi-relation-one-or-many-to-many::before{content:"\F149C"}.mdi-relation-one-or-many-to-one::before{content:"\F149D"}.mdi-relation-one-or-many-to-one-or-many::before{content:"\F149E"}.mdi-relation-one-or-many-to-only-one::before{content:"\F149F"}.mdi-relation-one-or-many-to-zero-or-many::before{content:"\F14A0"}.mdi-relation-one-or-many-to-zero-or-one::before{content:"\F14A1"}.mdi-relation-one-to-many::before{content:"\F14A2"}.mdi-relation-one-to-one::before{content:"\F14A3"}.mdi-relation-one-to-one-or-many::before{content:"\F14A4"}.mdi-relation-one-to-only-one::before{content:"\F14A5"}.mdi-relation-one-to-zero-or-many::before{content:"\F14A6"}.mdi-relation-one-to-zero-or-one::before{content:"\F14A7"}.mdi-relation-only-one-to-many::before{content:"\F14A8"}.mdi-relation-only-one-to-one::before{content:"\F14A9"}.mdi-relation-only-one-to-one-or-many::before{content:"\F14AA"}.mdi-relation-only-one-to-only-one::before{content:"\F14AB"}.mdi-relation-only-one-to-zero-or-many::before{content:"\F14AC"}.mdi-relation-only-one-to-zero-or-one::before{content:"\F14AD"}.mdi-relation-zero-or-many-to-many::before{content:"\F14AE"}.mdi-relation-zero-or-many-to-one::before{content:"\F14AF"}.mdi-relation-zero-or-many-to-one-or-many::before{content:"\F14B0"}.mdi-relation-zero-or-many-to-only-one::before{content:"\F14B1"}.mdi-relation-zero-or-many-to-zero-or-many::before{content:"\F14B2"}.mdi-relation-zero-or-many-to-zero-or-one::before{content:"\F14B3"}.mdi-relation-zero-or-one-to-many::before{content:"\F14B4"}.mdi-relation-zero-or-one-to-one::before{content:"\F14B5"}.mdi-relation-zero-or-one-to-one-or-many::before{content:"\F14B6"}.mdi-relation-zero-or-one-to-only-one::before{content:"\F14B7"}.mdi-relation-zero-or-one-to-zero-or-many::before{content:"\F14B8"}.mdi-relation-zero-or-one-to-zero-or-one::before{content:"\F14B9"}.mdi-relative-scale::before{content:"\F0452"}.mdi-reload::before{content:"\F0453"}.mdi-reload-alert::before{content:"\F110B"}.mdi-reminder::before{content:"\F088C"}.mdi-remote::before{content:"\F0454"}.mdi-remote-desktop::before{content:"\F08B9"}.mdi-remote-off::before{content:"\F0EC4"}.mdi-remote-tv::before{content:"\F0EC5"}.mdi-remote-tv-off::before{content:"\F0EC6"}.mdi-rename::before{content:"\F1C18"}.mdi-rename-box::before{content:"\F0455"}.mdi-rename-box-outline::before{content:"\F1C19"}.mdi-rename-outline::before{content:"\F1C1A"}.mdi-reorder-horizontal::before{content:"\F0688"}.mdi-reorder-vertical::before{content:"\F0689"}.mdi-repeat::before{content:"\F0456"}.mdi-repeat-off::before{content:"\F0457"}.mdi-repeat-once::before{content:"\F0458"}.mdi-repeat-variant::before{content:"\F0547"}.mdi-replay::before{content:"\F0459"}.mdi-reply::before{content:"\F045A"}.mdi-reply-all::before{content:"\F045B"}.mdi-reply-all-outline::before{content:"\F0F1F"}.mdi-reply-circle::before{content:"\F11AE"}.mdi-reply-outline::before{content:"\F0F20"}.mdi-reproduction::before{content:"\F045C"}.mdi-resistor::before{content:"\F0B44"}.mdi-resistor-nodes::before{content:"\F0B45"}.mdi-resize::before{content:"\F0A68"}.mdi-resize-bottom-right::before{content:"\F045D"}.mdi-responsive::before{content:"\F045E"}.mdi-restart::before{content:"\F0709"}.mdi-restart-alert::before{content:"\F110C"}.mdi-restart-off::before{content:"\F0D95"}.mdi-restore::before{content:"\F099B"}.mdi-restore-alert::before{content:"\F110D"}.mdi-rewind::before{content:"\F045F"}.mdi-rewind-10::before{content:"\F0D2A"}.mdi-rewind-15::before{content:"\F1946"}.mdi-rewind-30::before{content:"\F0D96"}.mdi-rewind-45::before{content:"\F1B13"}.mdi-rewind-5::before{content:"\F11F9"}.mdi-rewind-60::before{content:"\F160C"}.mdi-rewind-outline::before{content:"\F070A"}.mdi-rhombus::before{content:"\F070B"}.mdi-rhombus-medium::before{content:"\F0A10"}.mdi-rhombus-medium-outline::before{content:"\F14DC"}.mdi-rhombus-outline::before{content:"\F070C"}.mdi-rhombus-split::before{content:"\F0A11"}.mdi-rhombus-split-outline::before{content:"\F14DD"}.mdi-ribbon::before{content:"\F0460"}.mdi-rice::before{content:"\F07EA"}.mdi-rickshaw::before{content:"\F15BB"}.mdi-rickshaw-electric::before{content:"\F15BC"}.mdi-ring::before{content:"\F07EB"}.mdi-rivet::before{content:"\F0E60"}.mdi-road::before{content:"\F0461"}.mdi-road-variant::before{content:"\F0462"}.mdi-robber::before{content:"\F1058"}.mdi-robot::before{content:"\F06A9"}.mdi-robot-angry::before{content:"\F169D"}.mdi-robot-angry-outline::before{content:"\F169E"}.mdi-robot-confused::before{content:"\F169F"}.mdi-robot-confused-outline::before{content:"\F16A0"}.mdi-robot-dead::before{content:"\F16A1"}.mdi-robot-dead-outline::before{content:"\F16A2"}.mdi-robot-excited::before{content:"\F16A3"}.mdi-robot-excited-outline::before{content:"\F16A4"}.mdi-robot-happy::before{content:"\F1719"}.mdi-robot-happy-outline::before{content:"\F171A"}.mdi-robot-industrial::before{content:"\F0B46"}.mdi-robot-industrial-outline::before{content:"\F1A1A"}.mdi-robot-love::before{content:"\F16A5"}.mdi-robot-love-outline::before{content:"\F16A6"}.mdi-robot-mower::before{content:"\F11F7"}.mdi-robot-mower-outline::before{content:"\F11F3"}.mdi-robot-off::before{content:"\F16A7"}.mdi-robot-off-outline::before{content:"\F167B"}.mdi-robot-outline::before{content:"\F167A"}.mdi-robot-vacuum::before{content:"\F070D"}.mdi-robot-vacuum-alert::before{content:"\F1B5D"}.mdi-robot-vacuum-off::before{content:"\F1C01"}.mdi-robot-vacuum-variant::before{content:"\F0908"}.mdi-robot-vacuum-variant-alert::before{content:"\F1B5E"}.mdi-robot-vacuum-variant-off::before{content:"\F1C02"}.mdi-rocket::before{content:"\F0463"}.mdi-rocket-launch::before{content:"\F14DE"}.mdi-rocket-launch-outline::before{content:"\F14DF"}.mdi-rocket-outline::before{content:"\F13AF"}.mdi-rodent::before{content:"\F1327"}.mdi-roller-shade::before{content:"\F1A6B"}.mdi-roller-shade-closed::before{content:"\F1A6C"}.mdi-roller-skate::before{content:"\F0D2B"}.mdi-roller-skate-off::before{content:"\F0145"}.mdi-rollerblade::before{content:"\F0D2C"}.mdi-rollerblade-off::before{content:"\F002E"}.mdi-rollupjs::before{content:"\F0BC0"}.mdi-rolodex::before{content:"\F1AB9"}.mdi-rolodex-outline::before{content:"\F1ABA"}.mdi-roman-numeral-1::before{content:"\F1088"}.mdi-roman-numeral-10::before{content:"\F1091"}.mdi-roman-numeral-2::before{content:"\F1089"}.mdi-roman-numeral-3::before{content:"\F108A"}.mdi-roman-numeral-4::before{content:"\F108B"}.mdi-roman-numeral-5::before{content:"\F108C"}.mdi-roman-numeral-6::before{content:"\F108D"}.mdi-roman-numeral-7::before{content:"\F108E"}.mdi-roman-numeral-8::before{content:"\F108F"}.mdi-roman-numeral-9::before{content:"\F1090"}.mdi-room-service::before{content:"\F088D"}.mdi-room-service-outline::before{content:"\F0D97"}.mdi-rotate-360::before{content:"\F1999"}.mdi-rotate-3d::before{content:"\F0EC7"}.mdi-rotate-3d-variant::before{content:"\F0464"}.mdi-rotate-left::before{content:"\F0465"}.mdi-rotate-left-variant::before{content:"\F0466"}.mdi-rotate-orbit::before{content:"\F0D98"}.mdi-rotate-right::before{content:"\F0467"}.mdi-rotate-right-variant::before{content:"\F0468"}.mdi-rounded-corner::before{content:"\F0607"}.mdi-router::before{content:"\F11E2"}.mdi-router-network::before{content:"\F1087"}.mdi-router-network-wireless::before{content:"\F1C97"}.mdi-router-wireless::before{content:"\F0469"}.mdi-router-wireless-off::before{content:"\F15A3"}.mdi-router-wireless-settings::before{content:"\F0A69"}.mdi-routes::before{content:"\F046A"}.mdi-routes-clock::before{content:"\F1059"}.mdi-rowing::before{content:"\F0608"}.mdi-rss::before{content:"\F046B"}.mdi-rss-box::before{content:"\F046C"}.mdi-rss-off::before{content:"\F0F21"}.mdi-rug::before{content:"\F1475"}.mdi-rugby::before{content:"\F0D99"}.mdi-ruler::before{content:"\F046D"}.mdi-ruler-square::before{content:"\F0CC2"}.mdi-ruler-square-compass::before{content:"\F0EBE"}.mdi-run::before{content:"\F070E"}.mdi-run-fast::before{content:"\F046E"}.mdi-rv-truck::before{content:"\F11D4"}.mdi-sack::before{content:"\F0D2E"}.mdi-sack-outline::before{content:"\F1C4C"}.mdi-sack-percent::before{content:"\F0D2F"}.mdi-safe::before{content:"\F0A6A"}.mdi-safe-square::before{content:"\F127C"}.mdi-safe-square-outline::before{content:"\F127D"}.mdi-safety-goggles::before{content:"\F0D30"}.mdi-sail-boat::before{content:"\F0EC8"}.mdi-sail-boat-sink::before{content:"\F1AEF"}.mdi-sale::before{content:"\F046F"}.mdi-sale-outline::before{content:"\F1A06"}.mdi-salesforce::before{content:"\F088E"}.mdi-sass::before{content:"\F07EC"}.mdi-satellite::before{content:"\F0470"}.mdi-satellite-uplink::before{content:"\F0909"}.mdi-satellite-variant::before{content:"\F0471"}.mdi-sausage::before{content:"\F08BA"}.mdi-sausage-off::before{content:"\F1789"}.mdi-saw-blade::before{content:"\F0E61"}.mdi-sawtooth-wave::before{content:"\F147A"}.mdi-saxophone::before{content:"\F0609"}.mdi-scale::before{content:"\F0472"}.mdi-scale-balance::before{content:"\F05D1"}.mdi-scale-bathroom::before{content:"\F0473"}.mdi-scale-off::before{content:"\F105A"}.mdi-scale-unbalanced::before{content:"\F19B8"}.mdi-scan-helper::before{content:"\F13D8"}.mdi-scanner::before{content:"\F06AB"}.mdi-scanner-off::before{content:"\F090A"}.mdi-scatter-plot::before{content:"\F0EC9"}.mdi-scatter-plot-outline::before{content:"\F0ECA"}.mdi-scent::before{content:"\F1958"}.mdi-scent-off::before{content:"\F1959"}.mdi-school::before{content:"\F0474"}.mdi-school-outline::before{content:"\F1180"}.mdi-scissors-cutting::before{content:"\F0A6B"}.mdi-scooter::before{content:"\F15BD"}.mdi-scooter-electric::before{content:"\F15BE"}.mdi-scoreboard::before{content:"\F127E"}.mdi-scoreboard-outline::before{content:"\F127F"}.mdi-screen-rotation::before{content:"\F0475"}.mdi-screen-rotation-lock::before{content:"\F0478"}.mdi-screw-flat-top::before{content:"\F0DF3"}.mdi-screw-lag::before{content:"\F0DF4"}.mdi-screw-machine-flat-top::before{content:"\F0DF5"}.mdi-screw-machine-round-top::before{content:"\F0DF6"}.mdi-screw-round-top::before{content:"\F0DF7"}.mdi-screwdriver::before{content:"\F0476"}.mdi-script::before{content:"\F0BC1"}.mdi-script-outline::before{content:"\F0477"}.mdi-script-text::before{content:"\F0BC2"}.mdi-script-text-key::before{content:"\F1725"}.mdi-script-text-key-outline::before{content:"\F1726"}.mdi-script-text-outline::before{content:"\F0BC3"}.mdi-script-text-play::before{content:"\F1727"}.mdi-script-text-play-outline::before{content:"\F1728"}.mdi-sd::before{content:"\F0479"}.mdi-seal::before{content:"\F047A"}.mdi-seal-variant::before{content:"\F0FD9"}.mdi-search-web::before{content:"\F070F"}.mdi-seat::before{content:"\F0CC3"}.mdi-seat-flat::before{content:"\F047B"}.mdi-seat-flat-angled::before{content:"\F047C"}.mdi-seat-individual-suite::before{content:"\F047D"}.mdi-seat-legroom-extra::before{content:"\F047E"}.mdi-seat-legroom-normal::before{content:"\F047F"}.mdi-seat-legroom-reduced::before{content:"\F0480"}.mdi-seat-outline::before{content:"\F0CC4"}.mdi-seat-passenger::before{content:"\F1249"}.mdi-seat-recline-extra::before{content:"\F0481"}.mdi-seat-recline-normal::before{content:"\F0482"}.mdi-seatbelt::before{content:"\F0CC5"}.mdi-security::before{content:"\F0483"}.mdi-security-network::before{content:"\F0484"}.mdi-seed::before{content:"\F0E62"}.mdi-seed-off::before{content:"\F13FD"}.mdi-seed-off-outline::before{content:"\F13FE"}.mdi-seed-outline::before{content:"\F0E63"}.mdi-seed-plus::before{content:"\F1A6D"}.mdi-seed-plus-outline::before{content:"\F1A6E"}.mdi-seesaw::before{content:"\F15A4"}.mdi-segment::before{content:"\F0ECB"}.mdi-select::before{content:"\F0485"}.mdi-select-all::before{content:"\F0486"}.mdi-select-arrow-down::before{content:"\F1B59"}.mdi-select-arrow-up::before{content:"\F1B58"}.mdi-select-color::before{content:"\F0D31"}.mdi-select-compare::before{content:"\F0AD9"}.mdi-select-drag::before{content:"\F0A6C"}.mdi-select-group::before{content:"\F0F82"}.mdi-select-inverse::before{content:"\F0487"}.mdi-select-marker::before{content:"\F1280"}.mdi-select-multiple::before{content:"\F1281"}.mdi-select-multiple-marker::before{content:"\F1282"}.mdi-select-off::before{content:"\F0488"}.mdi-select-place::before{content:"\F0FDA"}.mdi-select-remove::before{content:"\F17C1"}.mdi-select-search::before{content:"\F1204"}.mdi-selection::before{content:"\F0489"}.mdi-selection-drag::before{content:"\F0A6D"}.mdi-selection-ellipse::before{content:"\F0D32"}.mdi-selection-ellipse-arrow-inside::before{content:"\F0F22"}.mdi-selection-ellipse-remove::before{content:"\F17C2"}.mdi-selection-marker::before{content:"\F1283"}.mdi-selection-multiple::before{content:"\F1285"}.mdi-selection-multiple-marker::before{content:"\F1284"}.mdi-selection-off::before{content:"\F0777"}.mdi-selection-remove::before{content:"\F17C3"}.mdi-selection-search::before{content:"\F1205"}.mdi-semantic-web::before{content:"\F1316"}.mdi-send::before{content:"\F048A"}.mdi-send-check::before{content:"\F1161"}.mdi-send-check-outline::before{content:"\F1162"}.mdi-send-circle::before{content:"\F0DF8"}.mdi-send-circle-outline::before{content:"\F0DF9"}.mdi-send-clock::before{content:"\F1163"}.mdi-send-clock-outline::before{content:"\F1164"}.mdi-send-lock::before{content:"\F07ED"}.mdi-send-lock-outline::before{content:"\F1166"}.mdi-send-outline::before{content:"\F1165"}.mdi-send-variant::before{content:"\F1C4D"}.mdi-send-variant-clock::before{content:"\F1C7E"}.mdi-send-variant-clock-outline::before{content:"\F1C7F"}.mdi-send-variant-outline::before{content:"\F1C4E"}.mdi-serial-port::before{content:"\F065C"}.mdi-server::before{content:"\F048B"}.mdi-server-minus::before{content:"\F048C"}.mdi-server-minus-outline::before{content:"\F1C98"}.mdi-server-network::before{content:"\F048D"}.mdi-server-network-off::before{content:"\F048E"}.mdi-server-network-outline::before{content:"\F1C99"}.mdi-server-off::before{content:"\F048F"}.mdi-server-outline::before{content:"\F1C9A"}.mdi-server-plus::before{content:"\F0490"}.mdi-server-plus-outline::before{content:"\F1C9B"}.mdi-server-remove::before{content:"\F0491"}.mdi-server-security::before{content:"\F0492"}.mdi-set-all::before{content:"\F0778"}.mdi-set-center::before{content:"\F0779"}.mdi-set-center-right::before{content:"\F077A"}.mdi-set-left::before{content:"\F077B"}.mdi-set-left-center::before{content:"\F077C"}.mdi-set-left-right::before{content:"\F077D"}.mdi-set-merge::before{content:"\F14E0"}.mdi-set-none::before{content:"\F077E"}.mdi-set-right::before{content:"\F077F"}.mdi-set-split::before{content:"\F14E1"}.mdi-set-square::before{content:"\F145D"}.mdi-set-top-box::before{content:"\F099F"}.mdi-settings-helper::before{content:"\F0A6E"}.mdi-shaker::before{content:"\F110E"}.mdi-shaker-outline::before{content:"\F110F"}.mdi-shape::before{content:"\F0831"}.mdi-shape-circle-plus::before{content:"\F065D"}.mdi-shape-outline::before{content:"\F0832"}.mdi-shape-oval-plus::before{content:"\F11FA"}.mdi-shape-plus::before{content:"\F0495"}.mdi-shape-plus-outline::before{content:"\F1C4F"}.mdi-shape-polygon-plus::before{content:"\F065E"}.mdi-shape-rectangle-plus::before{content:"\F065F"}.mdi-shape-square-plus::before{content:"\F0660"}.mdi-shape-square-rounded-plus::before{content:"\F14FA"}.mdi-share::before{content:"\F0496"}.mdi-share-all::before{content:"\F11F4"}.mdi-share-all-outline::before{content:"\F11F5"}.mdi-share-circle::before{content:"\F11AD"}.mdi-share-off::before{content:"\F0F23"}.mdi-share-off-outline::before{content:"\F0F24"}.mdi-share-outline::before{content:"\F0932"}.mdi-share-variant::before{content:"\F0497"}.mdi-share-variant-outline::before{content:"\F1514"}.mdi-shark::before{content:"\F18BA"}.mdi-shark-fin::before{content:"\F1673"}.mdi-shark-fin-outline::before{content:"\F1674"}.mdi-shark-off::before{content:"\F18BB"}.mdi-sheep::before{content:"\F0CC6"}.mdi-shield::before{content:"\F0498"}.mdi-shield-account::before{content:"\F088F"}.mdi-shield-account-outline::before{content:"\F0A12"}.mdi-shield-account-variant::before{content:"\F15A7"}.mdi-shield-account-variant-outline::before{content:"\F15A8"}.mdi-shield-airplane::before{content:"\F06BB"}.mdi-shield-airplane-outline::before{content:"\F0CC7"}.mdi-shield-alert::before{content:"\F0ECC"}.mdi-shield-alert-outline::before{content:"\F0ECD"}.mdi-shield-bug::before{content:"\F13DA"}.mdi-shield-bug-outline::before{content:"\F13DB"}.mdi-shield-car::before{content:"\F0F83"}.mdi-shield-check::before{content:"\F0565"}.mdi-shield-check-outline::before{content:"\F0CC8"}.mdi-shield-cross::before{content:"\F0CC9"}.mdi-shield-cross-outline::before{content:"\F0CCA"}.mdi-shield-crown::before{content:"\F18BC"}.mdi-shield-crown-outline::before{content:"\F18BD"}.mdi-shield-edit::before{content:"\F11A0"}.mdi-shield-edit-outline::before{content:"\F11A1"}.mdi-shield-half::before{content:"\F1360"}.mdi-shield-half-full::before{content:"\F0780"}.mdi-shield-home::before{content:"\F068A"}.mdi-shield-home-outline::before{content:"\F0CCB"}.mdi-shield-key::before{content:"\F0BC4"}.mdi-shield-key-outline::before{content:"\F0BC5"}.mdi-shield-link-variant::before{content:"\F0D33"}.mdi-shield-link-variant-outline::before{content:"\F0D34"}.mdi-shield-lock::before{content:"\F099D"}.mdi-shield-lock-open::before{content:"\F199A"}.mdi-shield-lock-open-outline::before{content:"\F199B"}.mdi-shield-lock-outline::before{content:"\F0CCC"}.mdi-shield-moon::before{content:"\F1828"}.mdi-shield-moon-outline::before{content:"\F1829"}.mdi-shield-off::before{content:"\F099E"}.mdi-shield-off-outline::before{content:"\F099C"}.mdi-shield-outline::before{content:"\F0499"}.mdi-shield-plus::before{content:"\F0ADA"}.mdi-shield-plus-outline::before{content:"\F0ADB"}.mdi-shield-refresh::before{content:"\F00AA"}.mdi-shield-refresh-outline::before{content:"\F01E0"}.mdi-shield-remove::before{content:"\F0ADC"}.mdi-shield-remove-outline::before{content:"\F0ADD"}.mdi-shield-search::before{content:"\F0D9A"}.mdi-shield-star::before{content:"\F113B"}.mdi-shield-star-outline::before{content:"\F113C"}.mdi-shield-sun::before{content:"\F105D"}.mdi-shield-sun-outline::before{content:"\F105E"}.mdi-shield-sword::before{content:"\F18BE"}.mdi-shield-sword-outline::before{content:"\F18BF"}.mdi-shield-sync::before{content:"\F11A2"}.mdi-shield-sync-outline::before{content:"\F11A3"}.mdi-shimmer::before{content:"\F1545"}.mdi-ship-wheel::before{content:"\F0833"}.mdi-shipping-pallet::before{content:"\F184E"}.mdi-shoe-ballet::before{content:"\F15CA"}.mdi-shoe-cleat::before{content:"\F15C7"}.mdi-shoe-formal::before{content:"\F0B47"}.mdi-shoe-heel::before{content:"\F0B48"}.mdi-shoe-print::before{content:"\F0DFA"}.mdi-shoe-sneaker::before{content:"\F15C8"}.mdi-shopping::before{content:"\F049A"}.mdi-shopping-music::before{content:"\F049B"}.mdi-shopping-outline::before{content:"\F11D5"}.mdi-shopping-search::before{content:"\F0F84"}.mdi-shopping-search-outline::before{content:"\F1A6F"}.mdi-shore::before{content:"\F14F9"}.mdi-shovel::before{content:"\F0710"}.mdi-shovel-off::before{content:"\F0711"}.mdi-shower::before{content:"\F09A0"}.mdi-shower-head::before{content:"\F09A1"}.mdi-shredder::before{content:"\F049C"}.mdi-shuffle::before{content:"\F049D"}.mdi-shuffle-disabled::before{content:"\F049E"}.mdi-shuffle-variant::before{content:"\F049F"}.mdi-shuriken::before{content:"\F137F"}.mdi-sickle::before{content:"\F18C0"}.mdi-sigma::before{content:"\F04A0"}.mdi-sigma-lower::before{content:"\F062B"}.mdi-sign-caution::before{content:"\F04A1"}.mdi-sign-direction::before{content:"\F0781"}.mdi-sign-direction-minus::before{content:"\F1000"}.mdi-sign-direction-plus::before{content:"\F0FDC"}.mdi-sign-direction-remove::before{content:"\F0FDD"}.mdi-sign-language::before{content:"\F1B4D"}.mdi-sign-language-outline::before{content:"\F1B4E"}.mdi-sign-pole::before{content:"\F14F8"}.mdi-sign-real-estate::before{content:"\F1118"}.mdi-sign-text::before{content:"\F0782"}.mdi-sign-yield::before{content:"\F1BAF"}.mdi-signal::before{content:"\F04A2"}.mdi-signal-2g::before{content:"\F0712"}.mdi-signal-3g::before{content:"\F0713"}.mdi-signal-4g::before{content:"\F0714"}.mdi-signal-5g::before{content:"\F0A6F"}.mdi-signal-cellular-1::before{content:"\F08BC"}.mdi-signal-cellular-2::before{content:"\F08BD"}.mdi-signal-cellular-3::before{content:"\F08BE"}.mdi-signal-cellular-outline::before{content:"\F08BF"}.mdi-signal-distance-variant::before{content:"\F0E64"}.mdi-signal-hspa::before{content:"\F0715"}.mdi-signal-hspa-plus::before{content:"\F0716"}.mdi-signal-off::before{content:"\F0783"}.mdi-signal-variant::before{content:"\F060A"}.mdi-signature::before{content:"\F0DFB"}.mdi-signature-freehand::before{content:"\F0DFC"}.mdi-signature-image::before{content:"\F0DFD"}.mdi-signature-text::before{content:"\F0DFE"}.mdi-silo::before{content:"\F1B9F"}.mdi-silo-outline::before{content:"\F0B49"}.mdi-silverware::before{content:"\F04A3"}.mdi-silverware-clean::before{content:"\F0FDE"}.mdi-silverware-fork::before{content:"\F04A4"}.mdi-silverware-fork-knife::before{content:"\F0A70"}.mdi-silverware-spoon::before{content:"\F04A5"}.mdi-silverware-variant::before{content:"\F04A6"}.mdi-sim::before{content:"\F04A7"}.mdi-sim-alert::before{content:"\F04A8"}.mdi-sim-alert-outline::before{content:"\F15D3"}.mdi-sim-off::before{content:"\F04A9"}.mdi-sim-off-outline::before{content:"\F15D4"}.mdi-sim-outline::before{content:"\F15D5"}.mdi-simple-icons::before{content:"\F131D"}.mdi-sina-weibo::before{content:"\F0ADF"}.mdi-sine-wave::before{content:"\F095B"}.mdi-sitemap::before{content:"\F04AA"}.mdi-sitemap-outline::before{content:"\F199C"}.mdi-size-l::before{content:"\F13A6"}.mdi-size-m::before{content:"\F13A5"}.mdi-size-s::before{content:"\F13A4"}.mdi-size-xl::before{content:"\F13A7"}.mdi-size-xs::before{content:"\F13A3"}.mdi-size-xxl::before{content:"\F13A8"}.mdi-size-xxs::before{content:"\F13A2"}.mdi-size-xxxl::before{content:"\F13A9"}.mdi-skate::before{content:"\F0D35"}.mdi-skate-off::before{content:"\F0699"}.mdi-skateboard::before{content:"\F14C2"}.mdi-skateboarding::before{content:"\F0501"}.mdi-skew-less::before{content:"\F0D36"}.mdi-skew-more::before{content:"\F0D37"}.mdi-ski::before{content:"\F1304"}.mdi-ski-cross-country::before{content:"\F1305"}.mdi-ski-water::before{content:"\F1306"}.mdi-skip-backward::before{content:"\F04AB"}.mdi-skip-backward-outline::before{content:"\F0F25"}.mdi-skip-forward::before{content:"\F04AC"}.mdi-skip-forward-outline::before{content:"\F0F26"}.mdi-skip-next::before{content:"\F04AD"}.mdi-skip-next-circle::before{content:"\F0661"}.mdi-skip-next-circle-outline::before{content:"\F0662"}.mdi-skip-next-outline::before{content:"\F0F27"}.mdi-skip-previous::before{content:"\F04AE"}.mdi-skip-previous-circle::before{content:"\F0663"}.mdi-skip-previous-circle-outline::before{content:"\F0664"}.mdi-skip-previous-outline::before{content:"\F0F28"}.mdi-skull::before{content:"\F068C"}.mdi-skull-crossbones::before{content:"\F0BC6"}.mdi-skull-crossbones-outline::before{content:"\F0BC7"}.mdi-skull-outline::before{content:"\F0BC8"}.mdi-skull-scan::before{content:"\F14C7"}.mdi-skull-scan-outline::before{content:"\F14C8"}.mdi-skype::before{content:"\F04AF"}.mdi-skype-business::before{content:"\F04B0"}.mdi-slack::before{content:"\F04B1"}.mdi-slash-forward::before{content:"\F0FDF"}.mdi-slash-forward-box::before{content:"\F0FE0"}.mdi-sledding::before{content:"\F041B"}.mdi-sleep::before{content:"\F04B2"}.mdi-sleep-off::before{content:"\F04B3"}.mdi-slide::before{content:"\F15A5"}.mdi-slope-downhill::before{content:"\F0DFF"}.mdi-slope-uphill::before{content:"\F0E00"}.mdi-slot-machine::before{content:"\F1114"}.mdi-slot-machine-outline::before{content:"\F1115"}.mdi-smart-card::before{content:"\F10BD"}.mdi-smart-card-off::before{content:"\F18F7"}.mdi-smart-card-off-outline::before{content:"\F18F8"}.mdi-smart-card-outline::before{content:"\F10BE"}.mdi-smart-card-reader::before{content:"\F10BF"}.mdi-smart-card-reader-outline::before{content:"\F10C0"}.mdi-smog::before{content:"\F0A71"}.mdi-smoke::before{content:"\F1799"}.mdi-smoke-detector::before{content:"\F0392"}.mdi-smoke-detector-alert::before{content:"\F192E"}.mdi-smoke-detector-alert-outline::before{content:"\F192F"}.mdi-smoke-detector-off::before{content:"\F1809"}.mdi-smoke-detector-off-outline::before{content:"\F180A"}.mdi-smoke-detector-outline::before{content:"\F1808"}.mdi-smoke-detector-variant::before{content:"\F180B"}.mdi-smoke-detector-variant-alert::before{content:"\F1930"}.mdi-smoke-detector-variant-off::before{content:"\F180C"}.mdi-smoking::before{content:"\F04B4"}.mdi-smoking-off::before{content:"\F04B5"}.mdi-smoking-pipe::before{content:"\F140D"}.mdi-smoking-pipe-off::before{content:"\F1428"}.mdi-snail::before{content:"\F1677"}.mdi-snake::before{content:"\F150E"}.mdi-snapchat::before{content:"\F04B6"}.mdi-snowboard::before{content:"\F1307"}.mdi-snowflake::before{content:"\F0717"}.mdi-snowflake-alert::before{content:"\F0F29"}.mdi-snowflake-check::before{content:"\F1A70"}.mdi-snowflake-melt::before{content:"\F12CB"}.mdi-snowflake-off::before{content:"\F14E3"}.mdi-snowflake-thermometer::before{content:"\F1A71"}.mdi-snowflake-variant::before{content:"\F0F2A"}.mdi-snowman::before{content:"\F04B7"}.mdi-snowmobile::before{content:"\F06DD"}.mdi-snowshoeing::before{content:"\F1A72"}.mdi-soccer::before{content:"\F04B8"}.mdi-soccer-field::before{content:"\F0834"}.mdi-social-distance-2-meters::before{content:"\F1579"}.mdi-social-distance-6-feet::before{content:"\F157A"}.mdi-sofa::before{content:"\F04B9"}.mdi-sofa-outline::before{content:"\F156D"}.mdi-sofa-single::before{content:"\F156E"}.mdi-sofa-single-outline::before{content:"\F156F"}.mdi-solar-panel::before{content:"\F0D9B"}.mdi-solar-panel-large::before{content:"\F0D9C"}.mdi-solar-power::before{content:"\F0A72"}.mdi-solar-power-variant::before{content:"\F1A73"}.mdi-solar-power-variant-outline::before{content:"\F1A74"}.mdi-soldering-iron::before{content:"\F1092"}.mdi-solid::before{content:"\F068D"}.mdi-sony-playstation::before{content:"\F0414"}.mdi-sort::before{content:"\F04BA"}.mdi-sort-alphabetical-ascending::before{content:"\F05BD"}.mdi-sort-alphabetical-ascending-variant::before{content:"\F1148"}.mdi-sort-alphabetical-descending::before{content:"\F05BF"}.mdi-sort-alphabetical-descending-variant::before{content:"\F1149"}.mdi-sort-alphabetical-variant::before{content:"\F04BB"}.mdi-sort-ascending::before{content:"\F04BC"}.mdi-sort-bool-ascending::before{content:"\F1385"}.mdi-sort-bool-ascending-variant::before{content:"\F1386"}.mdi-sort-bool-descending::before{content:"\F1387"}.mdi-sort-bool-descending-variant::before{content:"\F1388"}.mdi-sort-calendar-ascending::before{content:"\F1547"}.mdi-sort-calendar-descending::before{content:"\F1548"}.mdi-sort-clock-ascending::before{content:"\F1549"}.mdi-sort-clock-ascending-outline::before{content:"\F154A"}.mdi-sort-clock-descending::before{content:"\F154B"}.mdi-sort-clock-descending-outline::before{content:"\F154C"}.mdi-sort-descending::before{content:"\F04BD"}.mdi-sort-numeric-ascending::before{content:"\F1389"}.mdi-sort-numeric-ascending-variant::before{content:"\F090D"}.mdi-sort-numeric-descending::before{content:"\F138A"}.mdi-sort-numeric-descending-variant::before{content:"\F0AD2"}.mdi-sort-numeric-variant::before{content:"\F04BE"}.mdi-sort-reverse-variant::before{content:"\F033C"}.mdi-sort-variant::before{content:"\F04BF"}.mdi-sort-variant-lock::before{content:"\F0CCD"}.mdi-sort-variant-lock-open::before{content:"\F0CCE"}.mdi-sort-variant-off::before{content:"\F1ABB"}.mdi-sort-variant-remove::before{content:"\F1147"}.mdi-soundbar::before{content:"\F17DB"}.mdi-soundcloud::before{content:"\F04C0"}.mdi-source-branch::before{content:"\F062C"}.mdi-source-branch-check::before{content:"\F14CF"}.mdi-source-branch-minus::before{content:"\F14CB"}.mdi-source-branch-plus::before{content:"\F14CA"}.mdi-source-branch-refresh::before{content:"\F14CD"}.mdi-source-branch-remove::before{content:"\F14CC"}.mdi-source-branch-sync::before{content:"\F14CE"}.mdi-source-commit::before{content:"\F0718"}.mdi-source-commit-end::before{content:"\F0719"}.mdi-source-commit-end-local::before{content:"\F071A"}.mdi-source-commit-local::before{content:"\F071B"}.mdi-source-commit-next-local::before{content:"\F071C"}.mdi-source-commit-start::before{content:"\F071D"}.mdi-source-commit-start-next-local::before{content:"\F071E"}.mdi-source-fork::before{content:"\F04C1"}.mdi-source-merge::before{content:"\F062D"}.mdi-source-pull::before{content:"\F04C2"}.mdi-source-repository::before{content:"\F0CCF"}.mdi-source-repository-multiple::before{content:"\F0CD0"}.mdi-soy-sauce::before{content:"\F07EE"}.mdi-soy-sauce-off::before{content:"\F13FC"}.mdi-spa::before{content:"\F0CD1"}.mdi-spa-outline::before{content:"\F0CD2"}.mdi-space-invaders::before{content:"\F0BC9"}.mdi-space-station::before{content:"\F1383"}.mdi-spade::before{content:"\F0E65"}.mdi-speaker::before{content:"\F04C3"}.mdi-speaker-bluetooth::before{content:"\F09A2"}.mdi-speaker-message::before{content:"\F1B11"}.mdi-speaker-multiple::before{content:"\F0D38"}.mdi-speaker-off::before{content:"\F04C4"}.mdi-speaker-pause::before{content:"\F1B73"}.mdi-speaker-play::before{content:"\F1B72"}.mdi-speaker-stop::before{content:"\F1B74"}.mdi-speaker-wireless::before{content:"\F071F"}.mdi-spear::before{content:"\F1845"}.mdi-speedometer::before{content:"\F04C5"}.mdi-speedometer-medium::before{content:"\F0F85"}.mdi-speedometer-slow::before{content:"\F0F86"}.mdi-spellcheck::before{content:"\F04C6"}.mdi-sphere::before{content:"\F1954"}.mdi-sphere-off::before{content:"\F1955"}.mdi-spider::before{content:"\F11EA"}.mdi-spider-outline::before{content:"\F1C75"}.mdi-spider-thread::before{content:"\F11EB"}.mdi-spider-web::before{content:"\F0BCA"}.mdi-spirit-level::before{content:"\F14F1"}.mdi-spoon-sugar::before{content:"\F1429"}.mdi-spotify::before{content:"\F04C7"}.mdi-spotlight::before{content:"\F04C8"}.mdi-spotlight-beam::before{content:"\F04C9"}.mdi-spray::before{content:"\F0665"}.mdi-spray-bottle::before{content:"\F0AE0"}.mdi-sprinkler::before{content:"\F105F"}.mdi-sprinkler-fire::before{content:"\F199D"}.mdi-sprinkler-variant::before{content:"\F1060"}.mdi-sprout::before{content:"\F0E66"}.mdi-sprout-outline::before{content:"\F0E67"}.mdi-square::before{content:"\F0764"}.mdi-square-circle::before{content:"\F1500"}.mdi-square-circle-outline::before{content:"\F1C50"}.mdi-square-edit-outline::before{content:"\F090C"}.mdi-square-medium::before{content:"\F0A13"}.mdi-square-medium-outline::before{content:"\F0A14"}.mdi-square-off::before{content:"\F12EE"}.mdi-square-off-outline::before{content:"\F12EF"}.mdi-square-opacity::before{content:"\F1854"}.mdi-square-outline::before{content:"\F0763"}.mdi-square-root::before{content:"\F0784"}.mdi-square-root-box::before{content:"\F09A3"}.mdi-square-rounded::before{content:"\F14FB"}.mdi-square-rounded-badge::before{content:"\F1A07"}.mdi-square-rounded-badge-outline::before{content:"\F1A08"}.mdi-square-rounded-outline::before{content:"\F14FC"}.mdi-square-small::before{content:"\F0A15"}.mdi-square-wave::before{content:"\F147B"}.mdi-squeegee::before{content:"\F0AE1"}.mdi-ssh::before{content:"\F08C0"}.mdi-stack-exchange::before{content:"\F060B"}.mdi-stack-overflow::before{content:"\F04CC"}.mdi-stackpath::before{content:"\F0359"}.mdi-stadium::before{content:"\F0FF9"}.mdi-stadium-outline::before{content:"\F1B03"}.mdi-stadium-variant::before{content:"\F0720"}.mdi-stairs::before{content:"\F04CD"}.mdi-stairs-box::before{content:"\F139E"}.mdi-stairs-down::before{content:"\F12BE"}.mdi-stairs-up::before{content:"\F12BD"}.mdi-stamper::before{content:"\F0D39"}.mdi-standard-definition::before{content:"\F07EF"}.mdi-star::before{content:"\F04CE"}.mdi-star-box::before{content:"\F0A73"}.mdi-star-box-multiple::before{content:"\F1286"}.mdi-star-box-multiple-outline::before{content:"\F1287"}.mdi-star-box-outline::before{content:"\F0A74"}.mdi-star-check::before{content:"\F1566"}.mdi-star-check-outline::before{content:"\F156A"}.mdi-star-circle::before{content:"\F04CF"}.mdi-star-circle-outline::before{content:"\F09A4"}.mdi-star-cog::before{content:"\F1668"}.mdi-star-cog-outline::before{content:"\F1669"}.mdi-star-crescent::before{content:"\F0979"}.mdi-star-david::before{content:"\F097A"}.mdi-star-face::before{content:"\F09A5"}.mdi-star-four-points::before{content:"\F0AE2"}.mdi-star-four-points-box::before{content:"\F1C51"}.mdi-star-four-points-box-outline::before{content:"\F1C52"}.mdi-star-four-points-circle::before{content:"\F1C53"}.mdi-star-four-points-circle-outline::before{content:"\F1C54"}.mdi-star-four-points-outline::before{content:"\F0AE3"}.mdi-star-four-points-small::before{content:"\F1C55"}.mdi-star-half::before{content:"\F0246"}.mdi-star-half-full::before{content:"\F04D0"}.mdi-star-minus::before{content:"\F1564"}.mdi-star-minus-outline::before{content:"\F1568"}.mdi-star-off::before{content:"\F04D1"}.mdi-star-off-outline::before{content:"\F155B"}.mdi-star-outline::before{content:"\F04D2"}.mdi-star-plus::before{content:"\F1563"}.mdi-star-plus-outline::before{content:"\F1567"}.mdi-star-remove::before{content:"\F1565"}.mdi-star-remove-outline::before{content:"\F1569"}.mdi-star-settings::before{content:"\F166A"}.mdi-star-settings-outline::before{content:"\F166B"}.mdi-star-shooting::before{content:"\F1741"}.mdi-star-shooting-outline::before{content:"\F1742"}.mdi-star-three-points::before{content:"\F0AE4"}.mdi-star-three-points-outline::before{content:"\F0AE5"}.mdi-state-machine::before{content:"\F11EF"}.mdi-steam::before{content:"\F04D3"}.mdi-steering::before{content:"\F04D4"}.mdi-steering-off::before{content:"\F090E"}.mdi-step-backward::before{content:"\F04D5"}.mdi-step-backward-2::before{content:"\F04D6"}.mdi-step-forward::before{content:"\F04D7"}.mdi-step-forward-2::before{content:"\F04D8"}.mdi-stethoscope::before{content:"\F04D9"}.mdi-sticker::before{content:"\F1364"}.mdi-sticker-alert::before{content:"\F1365"}.mdi-sticker-alert-outline::before{content:"\F1366"}.mdi-sticker-check::before{content:"\F1367"}.mdi-sticker-check-outline::before{content:"\F1368"}.mdi-sticker-circle-outline::before{content:"\F05D0"}.mdi-sticker-emoji::before{content:"\F0785"}.mdi-sticker-minus::before{content:"\F1369"}.mdi-sticker-minus-outline::before{content:"\F136A"}.mdi-sticker-outline::before{content:"\F136B"}.mdi-sticker-plus::before{content:"\F136C"}.mdi-sticker-plus-outline::before{content:"\F136D"}.mdi-sticker-remove::before{content:"\F136E"}.mdi-sticker-remove-outline::before{content:"\F136F"}.mdi-sticker-text::before{content:"\F178E"}.mdi-sticker-text-outline::before{content:"\F178F"}.mdi-stocking::before{content:"\F04DA"}.mdi-stomach::before{content:"\F1093"}.mdi-stool::before{content:"\F195D"}.mdi-stool-outline::before{content:"\F195E"}.mdi-stop::before{content:"\F04DB"}.mdi-stop-circle::before{content:"\F0666"}.mdi-stop-circle-outline::before{content:"\F0667"}.mdi-storage-tank::before{content:"\F1A75"}.mdi-storage-tank-outline::before{content:"\F1A76"}.mdi-store::before{content:"\F04DC"}.mdi-store-24-hour::before{content:"\F04DD"}.mdi-store-alert::before{content:"\F18C1"}.mdi-store-alert-outline::before{content:"\F18C2"}.mdi-store-check::before{content:"\F18C3"}.mdi-store-check-outline::before{content:"\F18C4"}.mdi-store-clock::before{content:"\F18C5"}.mdi-store-clock-outline::before{content:"\F18C6"}.mdi-store-cog::before{content:"\F18C7"}.mdi-store-cog-outline::before{content:"\F18C8"}.mdi-store-edit::before{content:"\F18C9"}.mdi-store-edit-outline::before{content:"\F18CA"}.mdi-store-marker::before{content:"\F18CB"}.mdi-store-marker-outline::before{content:"\F18CC"}.mdi-store-minus::before{content:"\F165E"}.mdi-store-minus-outline::before{content:"\F18CD"}.mdi-store-off::before{content:"\F18CE"}.mdi-store-off-outline::before{content:"\F18CF"}.mdi-store-outline::before{content:"\F1361"}.mdi-store-plus::before{content:"\F165F"}.mdi-store-plus-outline::before{content:"\F18D0"}.mdi-store-remove::before{content:"\F1660"}.mdi-store-remove-outline::before{content:"\F18D1"}.mdi-store-search::before{content:"\F18D2"}.mdi-store-search-outline::before{content:"\F18D3"}.mdi-store-settings::before{content:"\F18D4"}.mdi-store-settings-outline::before{content:"\F18D5"}.mdi-storefront::before{content:"\F07C7"}.mdi-storefront-check::before{content:"\F1B7D"}.mdi-storefront-check-outline::before{content:"\F1B7E"}.mdi-storefront-edit::before{content:"\F1B7F"}.mdi-storefront-edit-outline::before{content:"\F1B80"}.mdi-storefront-minus::before{content:"\F1B83"}.mdi-storefront-minus-outline::before{content:"\F1B84"}.mdi-storefront-outline::before{content:"\F10C1"}.mdi-storefront-plus::before{content:"\F1B81"}.mdi-storefront-plus-outline::before{content:"\F1B82"}.mdi-storefront-remove::before{content:"\F1B85"}.mdi-storefront-remove-outline::before{content:"\F1B86"}.mdi-stove::before{content:"\F04DE"}.mdi-strategy::before{content:"\F11D6"}.mdi-stretch-to-page::before{content:"\F0F2B"}.mdi-stretch-to-page-outline::before{content:"\F0F2C"}.mdi-string-lights::before{content:"\F12BA"}.mdi-string-lights-off::before{content:"\F12BB"}.mdi-subdirectory-arrow-left::before{content:"\F060C"}.mdi-subdirectory-arrow-right::before{content:"\F060D"}.mdi-submarine::before{content:"\F156C"}.mdi-subtitles::before{content:"\F0A16"}.mdi-subtitles-outline::before{content:"\F0A17"}.mdi-subway::before{content:"\F06AC"}.mdi-subway-alert-variant::before{content:"\F0D9D"}.mdi-subway-variant::before{content:"\F04DF"}.mdi-summit::before{content:"\F0786"}.mdi-sun-angle::before{content:"\F1B27"}.mdi-sun-angle-outline::before{content:"\F1B28"}.mdi-sun-clock::before{content:"\F1A77"}.mdi-sun-clock-outline::before{content:"\F1A78"}.mdi-sun-compass::before{content:"\F19A5"}.mdi-sun-snowflake::before{content:"\F1796"}.mdi-sun-snowflake-variant::before{content:"\F1A79"}.mdi-sun-thermometer::before{content:"\F18D6"}.mdi-sun-thermometer-outline::before{content:"\F18D7"}.mdi-sun-wireless::before{content:"\F17FE"}.mdi-sun-wireless-outline::before{content:"\F17FF"}.mdi-sunglasses::before{content:"\F04E0"}.mdi-surfing::before{content:"\F1746"}.mdi-surround-sound::before{content:"\F05C5"}.mdi-surround-sound-2-0::before{content:"\F07F0"}.mdi-surround-sound-2-1::before{content:"\F1729"}.mdi-surround-sound-3-1::before{content:"\F07F1"}.mdi-surround-sound-5-1::before{content:"\F07F2"}.mdi-surround-sound-5-1-2::before{content:"\F172A"}.mdi-surround-sound-7-1::before{content:"\F07F3"}.mdi-svg::before{content:"\F0721"}.mdi-swap-horizontal::before{content:"\F04E1"}.mdi-swap-horizontal-bold::before{content:"\F0BCD"}.mdi-swap-horizontal-circle::before{content:"\F0FE1"}.mdi-swap-horizontal-circle-outline::before{content:"\F0FE2"}.mdi-swap-horizontal-hidden::before{content:"\F1D0E"}.mdi-swap-horizontal-variant::before{content:"\F08C1"}.mdi-swap-vertical::before{content:"\F04E2"}.mdi-swap-vertical-bold::before{content:"\F0BCE"}.mdi-swap-vertical-circle::before{content:"\F0FE3"}.mdi-swap-vertical-circle-outline::before{content:"\F0FE4"}.mdi-swap-vertical-variant::before{content:"\F08C2"}.mdi-swim::before{content:"\F04E3"}.mdi-switch::before{content:"\F04E4"}.mdi-sword::before{content:"\F04E5"}.mdi-sword-cross::before{content:"\F0787"}.mdi-syllabary-hangul::before{content:"\F1333"}.mdi-syllabary-hiragana::before{content:"\F1334"}.mdi-syllabary-katakana::before{content:"\F1335"}.mdi-syllabary-katakana-halfwidth::before{content:"\F1336"}.mdi-symbol::before{content:"\F1501"}.mdi-symfony::before{content:"\F0AE6"}.mdi-synagogue::before{content:"\F1B04"}.mdi-synagogue-outline::before{content:"\F1B05"}.mdi-sync::before{content:"\F04E6"}.mdi-sync-alert::before{content:"\F04E7"}.mdi-sync-circle::before{content:"\F1378"}.mdi-sync-off::before{content:"\F04E8"}.mdi-tab::before{content:"\F04E9"}.mdi-tab-minus::before{content:"\F0B4B"}.mdi-tab-plus::before{content:"\F075C"}.mdi-tab-remove::before{content:"\F0B4C"}.mdi-tab-search::before{content:"\F199E"}.mdi-tab-unselected::before{content:"\F04EA"}.mdi-table::before{content:"\F04EB"}.mdi-table-account::before{content:"\F13B9"}.mdi-table-alert::before{content:"\F13BA"}.mdi-table-arrow-down::before{content:"\F13BB"}.mdi-table-arrow-left::before{content:"\F13BC"}.mdi-table-arrow-right::before{content:"\F13BD"}.mdi-table-arrow-up::before{content:"\F13BE"}.mdi-table-border::before{content:"\F0A18"}.mdi-table-cancel::before{content:"\F13BF"}.mdi-table-chair::before{content:"\F1061"}.mdi-table-check::before{content:"\F13C0"}.mdi-table-clock::before{content:"\F13C1"}.mdi-table-cog::before{content:"\F13C2"}.mdi-table-column::before{content:"\F0835"}.mdi-table-column-plus-after::before{content:"\F04EC"}.mdi-table-column-plus-before::before{content:"\F04ED"}.mdi-table-column-remove::before{content:"\F04EE"}.mdi-table-column-width::before{content:"\F04EF"}.mdi-table-edit::before{content:"\F04F0"}.mdi-table-eye::before{content:"\F1094"}.mdi-table-eye-off::before{content:"\F13C3"}.mdi-table-filter::before{content:"\F1B8C"}.mdi-table-furniture::before{content:"\F05BC"}.mdi-table-headers-eye::before{content:"\F121D"}.mdi-table-headers-eye-off::before{content:"\F121E"}.mdi-table-heart::before{content:"\F13C4"}.mdi-table-key::before{content:"\F13C5"}.mdi-table-large::before{content:"\F04F1"}.mdi-table-large-plus::before{content:"\F0F87"}.mdi-table-large-remove::before{content:"\F0F88"}.mdi-table-lock::before{content:"\F13C6"}.mdi-table-merge-cells::before{content:"\F09A6"}.mdi-table-minus::before{content:"\F13C7"}.mdi-table-multiple::before{content:"\F13C8"}.mdi-table-network::before{content:"\F13C9"}.mdi-table-of-contents::before{content:"\F0836"}.mdi-table-off::before{content:"\F13CA"}.mdi-table-picnic::before{content:"\F1743"}.mdi-table-pivot::before{content:"\F183C"}.mdi-table-plus::before{content:"\F0A75"}.mdi-table-question::before{content:"\F1B21"}.mdi-table-refresh::before{content:"\F13A0"}.mdi-table-remove::before{content:"\F0A76"}.mdi-table-row::before{content:"\F0837"}.mdi-table-row-height::before{content:"\F04F2"}.mdi-table-row-plus-after::before{content:"\F04F3"}.mdi-table-row-plus-before::before{content:"\F04F4"}.mdi-table-row-remove::before{content:"\F04F5"}.mdi-table-search::before{content:"\F090F"}.mdi-table-settings::before{content:"\F0838"}.mdi-table-split-cell::before{content:"\F142A"}.mdi-table-star::before{content:"\F13CB"}.mdi-table-sync::before{content:"\F13A1"}.mdi-table-tennis::before{content:"\F0E68"}.mdi-tablet::before{content:"\F04F6"}.mdi-tablet-cellphone::before{content:"\F09A7"}.mdi-tablet-dashboard::before{content:"\F0ECE"}.mdi-taco::before{content:"\F0762"}.mdi-tag::before{content:"\F04F9"}.mdi-tag-arrow-down::before{content:"\F172B"}.mdi-tag-arrow-down-outline::before{content:"\F172C"}.mdi-tag-arrow-left::before{content:"\F172D"}.mdi-tag-arrow-left-outline::before{content:"\F172E"}.mdi-tag-arrow-right::before{content:"\F172F"}.mdi-tag-arrow-right-outline::before{content:"\F1730"}.mdi-tag-arrow-up::before{content:"\F1731"}.mdi-tag-arrow-up-outline::before{content:"\F1732"}.mdi-tag-check::before{content:"\F1A7A"}.mdi-tag-check-outline::before{content:"\F1A7B"}.mdi-tag-edit::before{content:"\F1C9C"}.mdi-tag-edit-outline::before{content:"\F1C9D"}.mdi-tag-faces::before{content:"\F04FA"}.mdi-tag-heart::before{content:"\F068B"}.mdi-tag-heart-outline::before{content:"\F0BCF"}.mdi-tag-hidden::before{content:"\F1C76"}.mdi-tag-minus::before{content:"\F0910"}.mdi-tag-minus-outline::before{content:"\F121F"}.mdi-tag-multiple::before{content:"\F04FB"}.mdi-tag-multiple-outline::before{content:"\F12F7"}.mdi-tag-off::before{content:"\F1220"}.mdi-tag-off-outline::before{content:"\F1221"}.mdi-tag-outline::before{content:"\F04FC"}.mdi-tag-plus::before{content:"\F0722"}.mdi-tag-plus-outline::before{content:"\F1222"}.mdi-tag-remove::before{content:"\F0723"}.mdi-tag-remove-outline::before{content:"\F1223"}.mdi-tag-search::before{content:"\F1907"}.mdi-tag-search-outline::before{content:"\F1908"}.mdi-tag-text::before{content:"\F1224"}.mdi-tag-text-outline::before{content:"\F04FD"}.mdi-tailwind::before{content:"\F13FF"}.mdi-tally-mark-1::before{content:"\F1ABC"}.mdi-tally-mark-2::before{content:"\F1ABD"}.mdi-tally-mark-3::before{content:"\F1ABE"}.mdi-tally-mark-4::before{content:"\F1ABF"}.mdi-tally-mark-5::before{content:"\F1AC0"}.mdi-tangram::before{content:"\F04F8"}.mdi-tank::before{content:"\F0D3A"}.mdi-tanker-truck::before{content:"\F0FE5"}.mdi-tape-drive::before{content:"\F16DF"}.mdi-tape-measure::before{content:"\F0B4D"}.mdi-target::before{content:"\F04FE"}.mdi-target-account::before{content:"\F0BD0"}.mdi-target-variant::before{content:"\F0A77"}.mdi-taxi::before{content:"\F04FF"}.mdi-tea::before{content:"\F0D9E"}.mdi-tea-outline::before{content:"\F0D9F"}.mdi-teamviewer::before{content:"\F0500"}.mdi-teddy-bear::before{content:"\F18FB"}.mdi-telescope::before{content:"\F0B4E"}.mdi-television::before{content:"\F0502"}.mdi-television-ambient-light::before{content:"\F1356"}.mdi-television-box::before{content:"\F0839"}.mdi-television-classic::before{content:"\F07F4"}.mdi-television-classic-off::before{content:"\F083A"}.mdi-television-guide::before{content:"\F0503"}.mdi-television-off::before{content:"\F083B"}.mdi-television-pause::before{content:"\F0F89"}.mdi-television-play::before{content:"\F0ECF"}.mdi-television-shimmer::before{content:"\F1110"}.mdi-television-speaker::before{content:"\F1B1B"}.mdi-television-speaker-off::before{content:"\F1B1C"}.mdi-television-stop::before{content:"\F0F8A"}.mdi-temperature-celsius::before{content:"\F0504"}.mdi-temperature-fahrenheit::before{content:"\F0505"}.mdi-temperature-kelvin::before{content:"\F0506"}.mdi-temple-buddhist::before{content:"\F1B06"}.mdi-temple-buddhist-outline::before{content:"\F1B07"}.mdi-temple-hindu::before{content:"\F1B08"}.mdi-temple-hindu-outline::before{content:"\F1B09"}.mdi-tennis::before{content:"\F0DA0"}.mdi-tennis-ball::before{content:"\F0507"}.mdi-tennis-ball-outline::before{content:"\F1C5F"}.mdi-tent::before{content:"\F0508"}.mdi-terraform::before{content:"\F1062"}.mdi-terrain::before{content:"\F0509"}.mdi-test-tube::before{content:"\F0668"}.mdi-test-tube-empty::before{content:"\F0911"}.mdi-test-tube-off::before{content:"\F0912"}.mdi-text::before{content:"\F09A8"}.mdi-text-account::before{content:"\F1570"}.mdi-text-box::before{content:"\F021A"}.mdi-text-box-check::before{content:"\F0EA6"}.mdi-text-box-check-outline::before{content:"\F0EA7"}.mdi-text-box-edit::before{content:"\F1A7C"}.mdi-text-box-edit-outline::before{content:"\F1A7D"}.mdi-text-box-minus::before{content:"\F0EA8"}.mdi-text-box-minus-outline::before{content:"\F0EA9"}.mdi-text-box-multiple::before{content:"\F0AB7"}.mdi-text-box-multiple-outline::before{content:"\F0AB8"}.mdi-text-box-outline::before{content:"\F09ED"}.mdi-text-box-plus::before{content:"\F0EAA"}.mdi-text-box-plus-outline::before{content:"\F0EAB"}.mdi-text-box-remove::before{content:"\F0EAC"}.mdi-text-box-remove-outline::before{content:"\F0EAD"}.mdi-text-box-search::before{content:"\F0EAE"}.mdi-text-box-search-outline::before{content:"\F0EAF"}.mdi-text-long::before{content:"\F09AA"}.mdi-text-recognition::before{content:"\F113D"}.mdi-text-search::before{content:"\F13B8"}.mdi-text-search-variant::before{content:"\F1A7E"}.mdi-text-shadow::before{content:"\F0669"}.mdi-text-short::before{content:"\F09A9"}.mdi-texture::before{content:"\F050C"}.mdi-texture-box::before{content:"\F0FE6"}.mdi-theater::before{content:"\F050D"}.mdi-theme-light-dark::before{content:"\F050E"}.mdi-thermometer::before{content:"\F050F"}.mdi-thermometer-alert::before{content:"\F0E01"}.mdi-thermometer-auto::before{content:"\F1B0F"}.mdi-thermometer-bluetooth::before{content:"\F1895"}.mdi-thermometer-check::before{content:"\F1A7F"}.mdi-thermometer-chevron-down::before{content:"\F0E02"}.mdi-thermometer-chevron-up::before{content:"\F0E03"}.mdi-thermometer-high::before{content:"\F10C2"}.mdi-thermometer-lines::before{content:"\F0510"}.mdi-thermometer-low::before{content:"\F10C3"}.mdi-thermometer-minus::before{content:"\F0E04"}.mdi-thermometer-off::before{content:"\F1531"}.mdi-thermometer-plus::before{content:"\F0E05"}.mdi-thermometer-probe::before{content:"\F1B2B"}.mdi-thermometer-probe-off::before{content:"\F1B2C"}.mdi-thermometer-water::before{content:"\F1A80"}.mdi-thermostat::before{content:"\F0393"}.mdi-thermostat-auto::before{content:"\F1B17"}.mdi-thermostat-box::before{content:"\F0891"}.mdi-thermostat-box-auto::before{content:"\F1B18"}.mdi-thermostat-cog::before{content:"\F1C80"}.mdi-thought-bubble::before{content:"\F07F6"}.mdi-thought-bubble-outline::before{content:"\F07F7"}.mdi-thumb-down::before{content:"\F0511"}.mdi-thumb-down-outline::before{content:"\F0512"}.mdi-thumb-up::before{content:"\F0513"}.mdi-thumb-up-outline::before{content:"\F0514"}.mdi-thumbs-up-down::before{content:"\F0515"}.mdi-thumbs-up-down-outline::before{content:"\F1914"}.mdi-ticket::before{content:"\F0516"}.mdi-ticket-account::before{content:"\F0517"}.mdi-ticket-confirmation::before{content:"\F0518"}.mdi-ticket-confirmation-outline::before{content:"\F13AA"}.mdi-ticket-outline::before{content:"\F0913"}.mdi-ticket-percent::before{content:"\F0724"}.mdi-ticket-percent-outline::before{content:"\F142B"}.mdi-tie::before{content:"\F0519"}.mdi-tilde::before{content:"\F0725"}.mdi-tilde-off::before{content:"\F18F3"}.mdi-timelapse::before{content:"\F051A"}.mdi-timeline::before{content:"\F0BD1"}.mdi-timeline-alert::before{content:"\F0F95"}.mdi-timeline-alert-outline::before{content:"\F0F98"}.mdi-timeline-check::before{content:"\F1532"}.mdi-timeline-check-outline::before{content:"\F1533"}.mdi-timeline-clock::before{content:"\F11FB"}.mdi-timeline-clock-outline::before{content:"\F11FC"}.mdi-timeline-minus::before{content:"\F1534"}.mdi-timeline-minus-outline::before{content:"\F1535"}.mdi-timeline-outline::before{content:"\F0BD2"}.mdi-timeline-plus::before{content:"\F0F96"}.mdi-timeline-plus-outline::before{content:"\F0F97"}.mdi-timeline-question::before{content:"\F0F99"}.mdi-timeline-question-outline::before{content:"\F0F9A"}.mdi-timeline-remove::before{content:"\F1536"}.mdi-timeline-remove-outline::before{content:"\F1537"}.mdi-timeline-text::before{content:"\F0BD3"}.mdi-timeline-text-outline::before{content:"\F0BD4"}.mdi-timer::before{content:"\F13AB"}.mdi-timer-10::before{content:"\F051C"}.mdi-timer-3::before{content:"\F051D"}.mdi-timer-alert::before{content:"\F1ACC"}.mdi-timer-alert-outline::before{content:"\F1ACD"}.mdi-timer-cancel::before{content:"\F1ACE"}.mdi-timer-cancel-outline::before{content:"\F1ACF"}.mdi-timer-check::before{content:"\F1AD0"}.mdi-timer-check-outline::before{content:"\F1AD1"}.mdi-timer-cog::before{content:"\F1925"}.mdi-timer-cog-outline::before{content:"\F1926"}.mdi-timer-edit::before{content:"\F1AD2"}.mdi-timer-edit-outline::before{content:"\F1AD3"}.mdi-timer-lock::before{content:"\F1AD4"}.mdi-timer-lock-open::before{content:"\F1AD5"}.mdi-timer-lock-open-outline::before{content:"\F1AD6"}.mdi-timer-lock-outline::before{content:"\F1AD7"}.mdi-timer-marker::before{content:"\F1AD8"}.mdi-timer-marker-outline::before{content:"\F1AD9"}.mdi-timer-minus::before{content:"\F1ADA"}.mdi-timer-minus-outline::before{content:"\F1ADB"}.mdi-timer-music::before{content:"\F1ADC"}.mdi-timer-music-outline::before{content:"\F1ADD"}.mdi-timer-off::before{content:"\F13AC"}.mdi-timer-off-outline::before{content:"\F051E"}.mdi-timer-outline::before{content:"\F051B"}.mdi-timer-pause::before{content:"\F1ADE"}.mdi-timer-pause-outline::before{content:"\F1ADF"}.mdi-timer-play::before{content:"\F1AE0"}.mdi-timer-play-outline::before{content:"\F1AE1"}.mdi-timer-plus::before{content:"\F1AE2"}.mdi-timer-plus-outline::before{content:"\F1AE3"}.mdi-timer-refresh::before{content:"\F1AE4"}.mdi-timer-refresh-outline::before{content:"\F1AE5"}.mdi-timer-remove::before{content:"\F1AE6"}.mdi-timer-remove-outline::before{content:"\F1AE7"}.mdi-timer-sand::before{content:"\F051F"}.mdi-timer-sand-complete::before{content:"\F199F"}.mdi-timer-sand-empty::before{content:"\F06AD"}.mdi-timer-sand-full::before{content:"\F078C"}.mdi-timer-sand-paused::before{content:"\F19A0"}.mdi-timer-settings::before{content:"\F1923"}.mdi-timer-settings-outline::before{content:"\F1924"}.mdi-timer-star::before{content:"\F1AE8"}.mdi-timer-star-outline::before{content:"\F1AE9"}.mdi-timer-stop::before{content:"\F1AEA"}.mdi-timer-stop-outline::before{content:"\F1AEB"}.mdi-timer-sync::before{content:"\F1AEC"}.mdi-timer-sync-outline::before{content:"\F1AED"}.mdi-timetable::before{content:"\F0520"}.mdi-tire::before{content:"\F1896"}.mdi-toaster::before{content:"\F1063"}.mdi-toaster-off::before{content:"\F11B7"}.mdi-toaster-oven::before{content:"\F0CD3"}.mdi-toggle-switch::before{content:"\F0521"}.mdi-toggle-switch-off::before{content:"\F0522"}.mdi-toggle-switch-off-outline::before{content:"\F0A19"}.mdi-toggle-switch-outline::before{content:"\F0A1A"}.mdi-toggle-switch-variant::before{content:"\F1A25"}.mdi-toggle-switch-variant-off::before{content:"\F1A26"}.mdi-toilet::before{content:"\F09AB"}.mdi-toolbox::before{content:"\F09AC"}.mdi-toolbox-outline::before{content:"\F09AD"}.mdi-tools::before{content:"\F1064"}.mdi-tooltip::before{content:"\F0523"}.mdi-tooltip-account::before{content:"\F000C"}.mdi-tooltip-cellphone::before{content:"\F183B"}.mdi-tooltip-check::before{content:"\F155C"}.mdi-tooltip-check-outline::before{content:"\F155D"}.mdi-tooltip-edit::before{content:"\F0524"}.mdi-tooltip-edit-outline::before{content:"\F12C5"}.mdi-tooltip-image::before{content:"\F0525"}.mdi-tooltip-image-outline::before{content:"\F0BD5"}.mdi-tooltip-minus::before{content:"\F155E"}.mdi-tooltip-minus-outline::before{content:"\F155F"}.mdi-tooltip-outline::before{content:"\F0526"}.mdi-tooltip-plus::before{content:"\F0BD6"}.mdi-tooltip-plus-outline::before{content:"\F0527"}.mdi-tooltip-question::before{content:"\F1BBA"}.mdi-tooltip-question-outline::before{content:"\F1BBB"}.mdi-tooltip-remove::before{content:"\F1560"}.mdi-tooltip-remove-outline::before{content:"\F1561"}.mdi-tooltip-text::before{content:"\F0528"}.mdi-tooltip-text-outline::before{content:"\F0BD7"}.mdi-tooth::before{content:"\F08C3"}.mdi-tooth-outline::before{content:"\F0529"}.mdi-toothbrush::before{content:"\F1129"}.mdi-toothbrush-electric::before{content:"\F112C"}.mdi-toothbrush-paste::before{content:"\F112A"}.mdi-torch::before{content:"\F1606"}.mdi-tortoise::before{content:"\F0D3B"}.mdi-toslink::before{content:"\F12B8"}.mdi-touch-text-outline::before{content:"\F1C60"}.mdi-tournament::before{content:"\F09AE"}.mdi-tow-truck::before{content:"\F083C"}.mdi-tower-beach::before{content:"\F0681"}.mdi-tower-fire::before{content:"\F0682"}.mdi-town-hall::before{content:"\F1875"}.mdi-toy-brick::before{content:"\F1288"}.mdi-toy-brick-marker::before{content:"\F1289"}.mdi-toy-brick-marker-outline::before{content:"\F128A"}.mdi-toy-brick-minus::before{content:"\F128B"}.mdi-toy-brick-minus-outline::before{content:"\F128C"}.mdi-toy-brick-outline::before{content:"\F128D"}.mdi-toy-brick-plus::before{content:"\F128E"}.mdi-toy-brick-plus-outline::before{content:"\F128F"}.mdi-toy-brick-remove::before{content:"\F1290"}.mdi-toy-brick-remove-outline::before{content:"\F1291"}.mdi-toy-brick-search::before{content:"\F1292"}.mdi-toy-brick-search-outline::before{content:"\F1293"}.mdi-track-light::before{content:"\F0914"}.mdi-track-light-off::before{content:"\F1B01"}.mdi-trackpad::before{content:"\F07F8"}.mdi-trackpad-lock::before{content:"\F0933"}.mdi-tractor::before{content:"\F0892"}.mdi-tractor-variant::before{content:"\F14C4"}.mdi-trademark::before{content:"\F0A78"}.mdi-traffic-cone::before{content:"\F137C"}.mdi-traffic-light::before{content:"\F052B"}.mdi-traffic-light-outline::before{content:"\F182A"}.mdi-train::before{content:"\F052C"}.mdi-train-bus::before{content:"\F1CC7"}.mdi-train-car::before{content:"\F0BD8"}.mdi-train-car-autorack::before{content:"\F1B2D"}.mdi-train-car-box::before{content:"\F1B2E"}.mdi-train-car-box-full::before{content:"\F1B2F"}.mdi-train-car-box-open::before{content:"\F1B30"}.mdi-train-car-caboose::before{content:"\F1B31"}.mdi-train-car-centerbeam::before{content:"\F1B32"}.mdi-train-car-centerbeam-full::before{content:"\F1B33"}.mdi-train-car-container::before{content:"\F1B34"}.mdi-train-car-flatbed::before{content:"\F1B35"}.mdi-train-car-flatbed-car::before{content:"\F1B36"}.mdi-train-car-flatbed-tank::before{content:"\F1B37"}.mdi-train-car-gondola::before{content:"\F1B38"}.mdi-train-car-gondola-full::before{content:"\F1B39"}.mdi-train-car-hopper::before{content:"\F1B3A"}.mdi-train-car-hopper-covered::before{content:"\F1B3B"}.mdi-train-car-hopper-full::before{content:"\F1B3C"}.mdi-train-car-intermodal::before{content:"\F1B3D"}.mdi-train-car-passenger::before{content:"\F1733"}.mdi-train-car-passenger-door::before{content:"\F1734"}.mdi-train-car-passenger-door-open::before{content:"\F1735"}.mdi-train-car-passenger-variant::before{content:"\F1736"}.mdi-train-car-tank::before{content:"\F1B3E"}.mdi-train-variant::before{content:"\F08C4"}.mdi-tram::before{content:"\F052D"}.mdi-tram-side::before{content:"\F0FE7"}.mdi-transcribe::before{content:"\F052E"}.mdi-transcribe-close::before{content:"\F052F"}.mdi-transfer::before{content:"\F1065"}.mdi-transfer-down::before{content:"\F0DA1"}.mdi-transfer-left::before{content:"\F0DA2"}.mdi-transfer-right::before{content:"\F0530"}.mdi-transfer-up::before{content:"\F0DA3"}.mdi-transit-connection::before{content:"\F0D3C"}.mdi-transit-connection-horizontal::before{content:"\F1546"}.mdi-transit-connection-variant::before{content:"\F0D3D"}.mdi-transit-detour::before{content:"\F0F8B"}.mdi-transit-skip::before{content:"\F1515"}.mdi-transit-transfer::before{content:"\F06AE"}.mdi-transition::before{content:"\F0915"}.mdi-transition-masked::before{content:"\F0916"}.mdi-translate::before{content:"\F05CA"}.mdi-translate-off::before{content:"\F0E06"}.mdi-translate-variant::before{content:"\F1B99"}.mdi-transmission-tower::before{content:"\F0D3E"}.mdi-transmission-tower-export::before{content:"\F192C"}.mdi-transmission-tower-import::before{content:"\F192D"}.mdi-transmission-tower-off::before{content:"\F19DD"}.mdi-trash-can::before{content:"\F0A79"}.mdi-trash-can-outline::before{content:"\F0A7A"}.mdi-tray::before{content:"\F1294"}.mdi-tray-alert::before{content:"\F1295"}.mdi-tray-arrow-down::before{content:"\F0120"}.mdi-tray-arrow-up::before{content:"\F011D"}.mdi-tray-full::before{content:"\F1296"}.mdi-tray-minus::before{content:"\F1297"}.mdi-tray-plus::before{content:"\F1298"}.mdi-tray-remove::before{content:"\F1299"}.mdi-treasure-chest::before{content:"\F0726"}.mdi-treasure-chest-outline::before{content:"\F1C77"}.mdi-tree::before{content:"\F0531"}.mdi-tree-outline::before{content:"\F0E69"}.mdi-trello::before{content:"\F0532"}.mdi-trending-down::before{content:"\F0533"}.mdi-trending-neutral::before{content:"\F0534"}.mdi-trending-up::before{content:"\F0535"}.mdi-triangle::before{content:"\F0536"}.mdi-triangle-down::before{content:"\F1C56"}.mdi-triangle-down-outline::before{content:"\F1C57"}.mdi-triangle-outline::before{content:"\F0537"}.mdi-triangle-small-down::before{content:"\F1A09"}.mdi-triangle-small-up::before{content:"\F1A0A"}.mdi-triangle-wave::before{content:"\F147C"}.mdi-triforce::before{content:"\F0BD9"}.mdi-trophy::before{content:"\F0538"}.mdi-trophy-award::before{content:"\F0539"}.mdi-trophy-broken::before{content:"\F0DA4"}.mdi-trophy-outline::before{content:"\F053A"}.mdi-trophy-variant::before{content:"\F053B"}.mdi-trophy-variant-outline::before{content:"\F053C"}.mdi-truck::before{content:"\F053D"}.mdi-truck-alert::before{content:"\F19DE"}.mdi-truck-alert-outline::before{content:"\F19DF"}.mdi-truck-cargo-container::before{content:"\F18D8"}.mdi-truck-check::before{content:"\F0CD4"}.mdi-truck-check-outline::before{content:"\F129A"}.mdi-truck-delivery::before{content:"\F053E"}.mdi-truck-delivery-outline::before{content:"\F129B"}.mdi-truck-fast::before{content:"\F0788"}.mdi-truck-fast-outline::before{content:"\F129C"}.mdi-truck-flatbed::before{content:"\F1891"}.mdi-truck-minus::before{content:"\F19AE"}.mdi-truck-minus-outline::before{content:"\F19BD"}.mdi-truck-off-road::before{content:"\F1C9E"}.mdi-truck-off-road-off::before{content:"\F1C9F"}.mdi-truck-outline::before{content:"\F129D"}.mdi-truck-plus::before{content:"\F19AD"}.mdi-truck-plus-outline::before{content:"\F19BC"}.mdi-truck-remove::before{content:"\F19AF"}.mdi-truck-remove-outline::before{content:"\F19BE"}.mdi-truck-snowflake::before{content:"\F19A6"}.mdi-truck-trailer::before{content:"\F0727"}.mdi-trumpet::before{content:"\F1096"}.mdi-tshirt-crew::before{content:"\F0A7B"}.mdi-tshirt-crew-outline::before{content:"\F053F"}.mdi-tshirt-v::before{content:"\F0A7C"}.mdi-tshirt-v-outline::before{content:"\F0540"}.mdi-tsunami::before{content:"\F1A81"}.mdi-tumble-dryer::before{content:"\F0917"}.mdi-tumble-dryer-alert::before{content:"\F11BA"}.mdi-tumble-dryer-off::before{content:"\F11BB"}.mdi-tune::before{content:"\F062E"}.mdi-tune-variant::before{content:"\F1542"}.mdi-tune-vertical::before{content:"\F066A"}.mdi-tune-vertical-variant::before{content:"\F1543"}.mdi-tunnel::before{content:"\F183D"}.mdi-tunnel-outline::before{content:"\F183E"}.mdi-turbine::before{content:"\F1A82"}.mdi-turkey::before{content:"\F171B"}.mdi-turnstile::before{content:"\F0CD5"}.mdi-turnstile-outline::before{content:"\F0CD6"}.mdi-turtle::before{content:"\F0CD7"}.mdi-twitch::before{content:"\F0543"}.mdi-twitter::before{content:"\F0544"}.mdi-two-factor-authentication::before{content:"\F09AF"}.mdi-typewriter::before{content:"\F0F2D"}.mdi-ubisoft::before{content:"\F0BDA"}.mdi-ubuntu::before{content:"\F0548"}.mdi-ufo::before{content:"\F10C4"}.mdi-ufo-outline::before{content:"\F10C5"}.mdi-ultra-high-definition::before{content:"\F07F9"}.mdi-umbraco::before{content:"\F0549"}.mdi-umbrella::before{content:"\F054A"}.mdi-umbrella-beach::before{content:"\F188A"}.mdi-umbrella-beach-outline::before{content:"\F188B"}.mdi-umbrella-closed::before{content:"\F09B0"}.mdi-umbrella-closed-outline::before{content:"\F13E2"}.mdi-umbrella-closed-variant::before{content:"\F13E1"}.mdi-umbrella-outline::before{content:"\F054B"}.mdi-underwear-outline::before{content:"\F1D0F"}.mdi-undo::before{content:"\F054C"}.mdi-undo-variant::before{content:"\F054D"}.mdi-unfold-less-horizontal::before{content:"\F054E"}.mdi-unfold-less-vertical::before{content:"\F0760"}.mdi-unfold-more-horizontal::before{content:"\F054F"}.mdi-unfold-more-vertical::before{content:"\F0761"}.mdi-ungroup::before{content:"\F0550"}.mdi-unicode::before{content:"\F0ED0"}.mdi-unicorn::before{content:"\F15C2"}.mdi-unicorn-variant::before{content:"\F15C3"}.mdi-unicycle::before{content:"\F15E5"}.mdi-unity::before{content:"\F06AF"}.mdi-unreal::before{content:"\F09B1"}.mdi-update::before{content:"\F06B0"}.mdi-upload::before{content:"\F0552"}.mdi-upload-box::before{content:"\F1D10"}.mdi-upload-box-outline::before{content:"\F1D11"}.mdi-upload-circle::before{content:"\F1D12"}.mdi-upload-circle-outline::before{content:"\F1D13"}.mdi-upload-lock::before{content:"\F1373"}.mdi-upload-lock-outline::before{content:"\F1374"}.mdi-upload-multiple::before{content:"\F083D"}.mdi-upload-multiple-outline::before{content:"\F1D14"}.mdi-upload-network::before{content:"\F06F6"}.mdi-upload-network-outline::before{content:"\F0CD8"}.mdi-upload-off::before{content:"\F10C6"}.mdi-upload-off-outline::before{content:"\F10C7"}.mdi-upload-outline::before{content:"\F0E07"}.mdi-usb::before{content:"\F0553"}.mdi-usb-c-port::before{content:"\F1CBF"}.mdi-usb-flash-drive::before{content:"\F129E"}.mdi-usb-flash-drive-outline::before{content:"\F129F"}.mdi-usb-port::before{content:"\F11F0"}.mdi-vacuum::before{content:"\F19A1"}.mdi-vacuum-outline::before{content:"\F19A2"}.mdi-valve::before{content:"\F1066"}.mdi-valve-closed::before{content:"\F1067"}.mdi-valve-open::before{content:"\F1068"}.mdi-van-passenger::before{content:"\F07FA"}.mdi-van-utility::before{content:"\F07FB"}.mdi-vanish::before{content:"\F07FC"}.mdi-vanish-quarter::before{content:"\F1554"}.mdi-vanity-light::before{content:"\F11E1"}.mdi-variable::before{content:"\F0AE7"}.mdi-variable-box::before{content:"\F1111"}.mdi-vector-arrange-above::before{content:"\F0554"}.mdi-vector-arrange-below::before{content:"\F0555"}.mdi-vector-bezier::before{content:"\F0AE8"}.mdi-vector-circle::before{content:"\F0556"}.mdi-vector-circle-variant::before{content:"\F0557"}.mdi-vector-combine::before{content:"\F0558"}.mdi-vector-curve::before{content:"\F0559"}.mdi-vector-difference::before{content:"\F055A"}.mdi-vector-difference-ab::before{content:"\F055B"}.mdi-vector-difference-ba::before{content:"\F055C"}.mdi-vector-ellipse::before{content:"\F0893"}.mdi-vector-intersection::before{content:"\F055D"}.mdi-vector-line::before{content:"\F055E"}.mdi-vector-link::before{content:"\F0FE8"}.mdi-vector-point::before{content:"\F01C4"}.mdi-vector-point-edit::before{content:"\F09E8"}.mdi-vector-point-minus::before{content:"\F1B78"}.mdi-vector-point-plus::before{content:"\F1B79"}.mdi-vector-point-select::before{content:"\F055F"}.mdi-vector-polygon::before{content:"\F0560"}.mdi-vector-polygon-variant::before{content:"\F1856"}.mdi-vector-polyline::before{content:"\F0561"}.mdi-vector-polyline-edit::before{content:"\F1225"}.mdi-vector-polyline-minus::before{content:"\F1226"}.mdi-vector-polyline-plus::before{content:"\F1227"}.mdi-vector-polyline-remove::before{content:"\F1228"}.mdi-vector-radius::before{content:"\F074A"}.mdi-vector-rectangle::before{content:"\F05C6"}.mdi-vector-selection::before{content:"\F0562"}.mdi-vector-square::before{content:"\F0001"}.mdi-vector-square-close::before{content:"\F1857"}.mdi-vector-square-edit::before{content:"\F18D9"}.mdi-vector-square-minus::before{content:"\F18DA"}.mdi-vector-square-open::before{content:"\F1858"}.mdi-vector-square-plus::before{content:"\F18DB"}.mdi-vector-square-remove::before{content:"\F18DC"}.mdi-vector-triangle::before{content:"\F0563"}.mdi-vector-union::before{content:"\F0564"}.mdi-vhs::before{content:"\F0A1B"}.mdi-vibrate::before{content:"\F0566"}.mdi-vibrate-off::before{content:"\F0CD9"}.mdi-video::before{content:"\F0567"}.mdi-video-2d::before{content:"\F1A1C"}.mdi-video-3d::before{content:"\F07FD"}.mdi-video-3d-off::before{content:"\F13D9"}.mdi-video-3d-variant::before{content:"\F0ED1"}.mdi-video-4k-box::before{content:"\F083E"}.mdi-video-account::before{content:"\F0919"}.mdi-video-box::before{content:"\F00FD"}.mdi-video-box-off::before{content:"\F00FE"}.mdi-video-check::before{content:"\F1069"}.mdi-video-check-outline::before{content:"\F106A"}.mdi-video-high-definition::before{content:"\F152E"}.mdi-video-image::before{content:"\F091A"}.mdi-video-input-antenna::before{content:"\F083F"}.mdi-video-input-component::before{content:"\F0840"}.mdi-video-input-hdmi::before{content:"\F0841"}.mdi-video-input-scart::before{content:"\F0F8C"}.mdi-video-input-svideo::before{content:"\F0842"}.mdi-video-marker::before{content:"\F19A9"}.mdi-video-marker-outline::before{content:"\F19AA"}.mdi-video-minus::before{content:"\F09B2"}.mdi-video-minus-outline::before{content:"\F02BA"}.mdi-video-off::before{content:"\F0568"}.mdi-video-off-outline::before{content:"\F0BDB"}.mdi-video-outline::before{content:"\F0BDC"}.mdi-video-plus::before{content:"\F09B3"}.mdi-video-plus-outline::before{content:"\F01D3"}.mdi-video-stabilization::before{content:"\F091B"}.mdi-video-standard-definition::before{content:"\F1CA0"}.mdi-video-switch::before{content:"\F0569"}.mdi-video-switch-outline::before{content:"\F0790"}.mdi-video-vintage::before{content:"\F0A1C"}.mdi-video-wireless::before{content:"\F0ED2"}.mdi-video-wireless-outline::before{content:"\F0ED3"}.mdi-view-agenda::before{content:"\F056A"}.mdi-view-agenda-outline::before{content:"\F11D8"}.mdi-view-array::before{content:"\F056B"}.mdi-view-array-outline::before{content:"\F1485"}.mdi-view-carousel::before{content:"\F056C"}.mdi-view-carousel-outline::before{content:"\F1486"}.mdi-view-column::before{content:"\F056D"}.mdi-view-column-outline::before{content:"\F1487"}.mdi-view-comfy::before{content:"\F0E6A"}.mdi-view-comfy-outline::before{content:"\F1488"}.mdi-view-compact::before{content:"\F0E6B"}.mdi-view-compact-outline::before{content:"\F0E6C"}.mdi-view-dashboard::before{content:"\F056E"}.mdi-view-dashboard-edit::before{content:"\F1947"}.mdi-view-dashboard-edit-outline::before{content:"\F1948"}.mdi-view-dashboard-outline::before{content:"\F0A1D"}.mdi-view-dashboard-variant::before{content:"\F0843"}.mdi-view-dashboard-variant-outline::before{content:"\F1489"}.mdi-view-day::before{content:"\F056F"}.mdi-view-day-outline::before{content:"\F148A"}.mdi-view-gallery::before{content:"\F1888"}.mdi-view-gallery-outline::before{content:"\F1889"}.mdi-view-grid::before{content:"\F0570"}.mdi-view-grid-compact::before{content:"\F1C61"}.mdi-view-grid-outline::before{content:"\F11D9"}.mdi-view-grid-plus::before{content:"\F0F8D"}.mdi-view-grid-plus-outline::before{content:"\F11DA"}.mdi-view-headline::before{content:"\F0571"}.mdi-view-list::before{content:"\F0572"}.mdi-view-list-outline::before{content:"\F148B"}.mdi-view-module::before{content:"\F0573"}.mdi-view-module-outline::before{content:"\F148C"}.mdi-view-parallel::before{content:"\F0728"}.mdi-view-parallel-outline::before{content:"\F148D"}.mdi-view-quilt::before{content:"\F0574"}.mdi-view-quilt-outline::before{content:"\F148E"}.mdi-view-sequential::before{content:"\F0729"}.mdi-view-sequential-outline::before{content:"\F148F"}.mdi-view-split-horizontal::before{content:"\F0BCB"}.mdi-view-split-vertical::before{content:"\F0BCC"}.mdi-view-stream::before{content:"\F0575"}.mdi-view-stream-outline::before{content:"\F1490"}.mdi-view-week::before{content:"\F0576"}.mdi-view-week-outline::before{content:"\F1491"}.mdi-vimeo::before{content:"\F0577"}.mdi-violin::before{content:"\F060F"}.mdi-virtual-reality::before{content:"\F0894"}.mdi-virus::before{content:"\F13B6"}.mdi-virus-off::before{content:"\F18E1"}.mdi-virus-off-outline::before{content:"\F18E2"}.mdi-virus-outline::before{content:"\F13B7"}.mdi-vlc::before{content:"\F057C"}.mdi-voicemail::before{content:"\F057D"}.mdi-volcano::before{content:"\F1A83"}.mdi-volcano-outline::before{content:"\F1A84"}.mdi-volleyball::before{content:"\F09B4"}.mdi-volume-equal::before{content:"\F1B10"}.mdi-volume-high::before{content:"\F057E"}.mdi-volume-low::before{content:"\F057F"}.mdi-volume-medium::before{content:"\F0580"}.mdi-volume-minus::before{content:"\F075E"}.mdi-volume-mute::before{content:"\F075F"}.mdi-volume-off::before{content:"\F0581"}.mdi-volume-plus::before{content:"\F075D"}.mdi-volume-source::before{content:"\F1120"}.mdi-volume-variant-off::before{content:"\F0E08"}.mdi-volume-vibrate::before{content:"\F1121"}.mdi-vote::before{content:"\F0A1F"}.mdi-vote-outline::before{content:"\F0A20"}.mdi-vpn::before{content:"\F0582"}.mdi-vuejs::before{content:"\F0844"}.mdi-vuetify::before{content:"\F0E6D"}.mdi-walk::before{content:"\F0583"}.mdi-wall::before{content:"\F07FE"}.mdi-wall-fire::before{content:"\F1A11"}.mdi-wall-sconce::before{content:"\F091C"}.mdi-wall-sconce-flat::before{content:"\F091D"}.mdi-wall-sconce-flat-outline::before{content:"\F17C9"}.mdi-wall-sconce-flat-variant::before{content:"\F041C"}.mdi-wall-sconce-flat-variant-outline::before{content:"\F17CA"}.mdi-wall-sconce-outline::before{content:"\F17CB"}.mdi-wall-sconce-round::before{content:"\F0748"}.mdi-wall-sconce-round-outline::before{content:"\F17CC"}.mdi-wall-sconce-round-variant::before{content:"\F091E"}.mdi-wall-sconce-round-variant-outline::before{content:"\F17CD"}.mdi-wallet::before{content:"\F0584"}.mdi-wallet-bifold::before{content:"\F1C58"}.mdi-wallet-bifold-outline::before{content:"\F1C59"}.mdi-wallet-giftcard::before{content:"\F0585"}.mdi-wallet-membership::before{content:"\F0586"}.mdi-wallet-outline::before{content:"\F0BDD"}.mdi-wallet-plus::before{content:"\F0F8E"}.mdi-wallet-plus-outline::before{content:"\F0F8F"}.mdi-wallet-travel::before{content:"\F0587"}.mdi-wallpaper::before{content:"\F0E09"}.mdi-wan::before{content:"\F0588"}.mdi-wardrobe::before{content:"\F0F90"}.mdi-wardrobe-outline::before{content:"\F0F91"}.mdi-warehouse::before{content:"\F0F81"}.mdi-washing-machine::before{content:"\F072A"}.mdi-washing-machine-alert::before{content:"\F11BC"}.mdi-washing-machine-off::before{content:"\F11BD"}.mdi-watch::before{content:"\F0589"}.mdi-watch-export::before{content:"\F058A"}.mdi-watch-export-variant::before{content:"\F0895"}.mdi-watch-import::before{content:"\F058B"}.mdi-watch-import-variant::before{content:"\F0896"}.mdi-watch-variant::before{content:"\F0897"}.mdi-watch-vibrate::before{content:"\F06B1"}.mdi-watch-vibrate-off::before{content:"\F0CDA"}.mdi-water::before{content:"\F058C"}.mdi-water-alert::before{content:"\F1502"}.mdi-water-alert-outline::before{content:"\F1503"}.mdi-water-boiler::before{content:"\F0F92"}.mdi-water-boiler-alert::before{content:"\F11B3"}.mdi-water-boiler-auto::before{content:"\F1B98"}.mdi-water-boiler-off::before{content:"\F11B4"}.mdi-water-check::before{content:"\F1504"}.mdi-water-check-outline::before{content:"\F1505"}.mdi-water-circle::before{content:"\F1806"}.mdi-water-minus::before{content:"\F1506"}.mdi-water-minus-outline::before{content:"\F1507"}.mdi-water-off::before{content:"\F058D"}.mdi-water-off-outline::before{content:"\F1508"}.mdi-water-opacity::before{content:"\F1855"}.mdi-water-outline::before{content:"\F0E0A"}.mdi-water-percent::before{content:"\F058E"}.mdi-water-percent-alert::before{content:"\F1509"}.mdi-water-plus::before{content:"\F150A"}.mdi-water-plus-outline::before{content:"\F150B"}.mdi-water-polo::before{content:"\F12A0"}.mdi-water-pump::before{content:"\F058F"}.mdi-water-pump-off::before{content:"\F0F93"}.mdi-water-remove::before{content:"\F150C"}.mdi-water-remove-outline::before{content:"\F150D"}.mdi-water-sync::before{content:"\F17C6"}.mdi-water-thermometer::before{content:"\F1A85"}.mdi-water-thermometer-outline::before{content:"\F1A86"}.mdi-water-well::before{content:"\F106B"}.mdi-water-well-outline::before{content:"\F106C"}.mdi-waterfall::before{content:"\F1849"}.mdi-watering-can::before{content:"\F1481"}.mdi-watering-can-outline::before{content:"\F1482"}.mdi-watermark::before{content:"\F0612"}.mdi-wave::before{content:"\F0F2E"}.mdi-wave-arrow-down::before{content:"\F1CB0"}.mdi-wave-arrow-up::before{content:"\F1CB1"}.mdi-wave-undercurrent::before{content:"\F1CC0"}.mdi-waveform::before{content:"\F147D"}.mdi-waves::before{content:"\F078D"}.mdi-waves-arrow-left::before{content:"\F1859"}.mdi-waves-arrow-right::before{content:"\F185A"}.mdi-waves-arrow-up::before{content:"\F185B"}.mdi-waze::before{content:"\F0BDE"}.mdi-weather-cloudy::before{content:"\F0590"}.mdi-weather-cloudy-alert::before{content:"\F0F2F"}.mdi-weather-cloudy-arrow-right::before{content:"\F0E6E"}.mdi-weather-cloudy-clock::before{content:"\F18F6"}.mdi-weather-dust::before{content:"\F1B5A"}.mdi-weather-fog::before{content:"\F0591"}.mdi-weather-hail::before{content:"\F0592"}.mdi-weather-hazy::before{content:"\F0F30"}.mdi-weather-hurricane::before{content:"\F0898"}.mdi-weather-hurricane-outline::before{content:"\F1C78"}.mdi-weather-lightning::before{content:"\F0593"}.mdi-weather-lightning-rainy::before{content:"\F067E"}.mdi-weather-moonset::before{content:"\F1D15"}.mdi-weather-moonset-down::before{content:"\F1D16"}.mdi-weather-moonset-up::before{content:"\F1D17"}.mdi-weather-night::before{content:"\F0594"}.mdi-weather-night-partly-cloudy::before{content:"\F0F31"}.mdi-weather-partly-cloudy::before{content:"\F0595"}.mdi-weather-partly-lightning::before{content:"\F0F32"}.mdi-weather-partly-rainy::before{content:"\F0F33"}.mdi-weather-partly-snowy::before{content:"\F0F34"}.mdi-weather-partly-snowy-rainy::before{content:"\F0F35"}.mdi-weather-pouring::before{content:"\F0596"}.mdi-weather-rainy::before{content:"\F0597"}.mdi-weather-snowy::before{content:"\F0598"}.mdi-weather-snowy-heavy::before{content:"\F0F36"}.mdi-weather-snowy-rainy::before{content:"\F067F"}.mdi-weather-sunny::before{content:"\F0599"}.mdi-weather-sunny-alert::before{content:"\F0F37"}.mdi-weather-sunny-off::before{content:"\F14E4"}.mdi-weather-sunset::before{content:"\F059A"}.mdi-weather-sunset-down::before{content:"\F059B"}.mdi-weather-sunset-up::before{content:"\F059C"}.mdi-weather-tornado::before{content:"\F0F38"}.mdi-weather-windy::before{content:"\F059D"}.mdi-weather-windy-variant::before{content:"\F059E"}.mdi-web::before{content:"\F059F"}.mdi-web-box::before{content:"\F0F94"}.mdi-web-cancel::before{content:"\F1790"}.mdi-web-check::before{content:"\F0789"}.mdi-web-clock::before{content:"\F124A"}.mdi-web-minus::before{content:"\F10A0"}.mdi-web-off::before{content:"\F0A8E"}.mdi-web-plus::before{content:"\F0033"}.mdi-web-refresh::before{content:"\F1791"}.mdi-web-remove::before{content:"\F0551"}.mdi-web-sync::before{content:"\F1792"}.mdi-webcam::before{content:"\F05A0"}.mdi-webcam-off::before{content:"\F1737"}.mdi-webhook::before{content:"\F062F"}.mdi-webpack::before{content:"\F072B"}.mdi-webrtc::before{content:"\F1248"}.mdi-wechat::before{content:"\F0611"}.mdi-weight::before{content:"\F05A1"}.mdi-weight-gram::before{content:"\F0D3F"}.mdi-weight-kilogram::before{content:"\F05A2"}.mdi-weight-lifter::before{content:"\F115D"}.mdi-weight-pound::before{content:"\F09B5"}.mdi-whatsapp::before{content:"\F05A3"}.mdi-wheel-barrow::before{content:"\F14F2"}.mdi-wheelchair::before{content:"\F1A87"}.mdi-wheelchair-accessibility::before{content:"\F05A4"}.mdi-whistle::before{content:"\F09B6"}.mdi-whistle-outline::before{content:"\F12BC"}.mdi-white-balance-auto::before{content:"\F05A5"}.mdi-white-balance-incandescent::before{content:"\F05A6"}.mdi-white-balance-iridescent::before{content:"\F05A7"}.mdi-white-balance-sunny::before{content:"\F05A8"}.mdi-widgets::before{content:"\F072C"}.mdi-widgets-outline::before{content:"\F1355"}.mdi-wifi::before{content:"\F05A9"}.mdi-wifi-alert::before{content:"\F16B5"}.mdi-wifi-arrow-down::before{content:"\F16B6"}.mdi-wifi-arrow-left::before{content:"\F16B7"}.mdi-wifi-arrow-left-right::before{content:"\F16B8"}.mdi-wifi-arrow-right::before{content:"\F16B9"}.mdi-wifi-arrow-up::before{content:"\F16BA"}.mdi-wifi-arrow-up-down::before{content:"\F16BB"}.mdi-wifi-cancel::before{content:"\F16BC"}.mdi-wifi-check::before{content:"\F16BD"}.mdi-wifi-cog::before{content:"\F16BE"}.mdi-wifi-lock::before{content:"\F16BF"}.mdi-wifi-lock-open::before{content:"\F16C0"}.mdi-wifi-marker::before{content:"\F16C1"}.mdi-wifi-minus::before{content:"\F16C2"}.mdi-wifi-off::before{content:"\F05AA"}.mdi-wifi-plus::before{content:"\F16C3"}.mdi-wifi-refresh::before{content:"\F16C4"}.mdi-wifi-remove::before{content:"\F16C5"}.mdi-wifi-settings::before{content:"\F16C6"}.mdi-wifi-star::before{content:"\F0E0B"}.mdi-wifi-strength-1::before{content:"\F091F"}.mdi-wifi-strength-1-alert::before{content:"\F0920"}.mdi-wifi-strength-1-lock::before{content:"\F0921"}.mdi-wifi-strength-1-lock-open::before{content:"\F16CB"}.mdi-wifi-strength-2::before{content:"\F0922"}.mdi-wifi-strength-2-alert::before{content:"\F0923"}.mdi-wifi-strength-2-lock::before{content:"\F0924"}.mdi-wifi-strength-2-lock-open::before{content:"\F16CC"}.mdi-wifi-strength-3::before{content:"\F0925"}.mdi-wifi-strength-3-alert::before{content:"\F0926"}.mdi-wifi-strength-3-lock::before{content:"\F0927"}.mdi-wifi-strength-3-lock-open::before{content:"\F16CD"}.mdi-wifi-strength-4::before{content:"\F0928"}.mdi-wifi-strength-4-alert::before{content:"\F0929"}.mdi-wifi-strength-4-lock::before{content:"\F092A"}.mdi-wifi-strength-4-lock-open::before{content:"\F16CE"}.mdi-wifi-strength-alert-outline::before{content:"\F092B"}.mdi-wifi-strength-lock-open-outline::before{content:"\F16CF"}.mdi-wifi-strength-lock-outline::before{content:"\F092C"}.mdi-wifi-strength-off::before{content:"\F092D"}.mdi-wifi-strength-off-outline::before{content:"\F092E"}.mdi-wifi-strength-outline::before{content:"\F092F"}.mdi-wifi-sync::before{content:"\F16C7"}.mdi-wikipedia::before{content:"\F05AC"}.mdi-wind-power::before{content:"\F1A88"}.mdi-wind-power-outline::before{content:"\F1A89"}.mdi-wind-turbine::before{content:"\F0DA5"}.mdi-wind-turbine-alert::before{content:"\F19AB"}.mdi-wind-turbine-check::before{content:"\F19AC"}.mdi-window-close::before{content:"\F05AD"}.mdi-window-closed::before{content:"\F05AE"}.mdi-window-closed-variant::before{content:"\F11DB"}.mdi-window-maximize::before{content:"\F05AF"}.mdi-window-minimize::before{content:"\F05B0"}.mdi-window-open::before{content:"\F05B1"}.mdi-window-open-variant::before{content:"\F11DC"}.mdi-window-restore::before{content:"\F05B2"}.mdi-window-shutter::before{content:"\F111C"}.mdi-window-shutter-alert::before{content:"\F111D"}.mdi-window-shutter-auto::before{content:"\F1BA3"}.mdi-window-shutter-cog::before{content:"\F1A8A"}.mdi-window-shutter-open::before{content:"\F111E"}.mdi-window-shutter-settings::before{content:"\F1A8B"}.mdi-windsock::before{content:"\F15FA"}.mdi-wiper::before{content:"\F0AE9"}.mdi-wiper-wash::before{content:"\F0DA6"}.mdi-wiper-wash-alert::before{content:"\F18DF"}.mdi-wizard-hat::before{content:"\F1477"}.mdi-wordpress::before{content:"\F05B4"}.mdi-wrap::before{content:"\F05B6"}.mdi-wrap-disabled::before{content:"\F0BDF"}.mdi-wrench::before{content:"\F05B7"}.mdi-wrench-check::before{content:"\F1B8F"}.mdi-wrench-check-outline::before{content:"\F1B90"}.mdi-wrench-clock::before{content:"\F19A3"}.mdi-wrench-clock-outline::before{content:"\F1B93"}.mdi-wrench-cog::before{content:"\F1B91"}.mdi-wrench-cog-outline::before{content:"\F1B92"}.mdi-wrench-outline::before{content:"\F0BE0"}.mdi-xamarin::before{content:"\F0845"}.mdi-xml::before{content:"\F05C0"}.mdi-xmpp::before{content:"\F07FF"}.mdi-yahoo::before{content:"\F0B4F"}.mdi-yeast::before{content:"\F05C1"}.mdi-yin-yang::before{content:"\F0680"}.mdi-yoga::before{content:"\F117C"}.mdi-youtube::before{content:"\F05C3"}.mdi-youtube-gaming::before{content:"\F0848"}.mdi-youtube-studio::before{content:"\F0847"}.mdi-youtube-subscription::before{content:"\F0D40"}.mdi-youtube-tv::before{content:"\F0448"}.mdi-yurt::before{content:"\F1516"}.mdi-z-wave::before{content:"\F0AEA"}.mdi-zend::before{content:"\F0AEB"}.mdi-zigbee::before{content:"\F0D41"}.mdi-zip-box::before{content:"\F05C4"}.mdi-zip-box-outline::before{content:"\F0FFA"}.mdi-zip-disk::before{content:"\F0A23"}.mdi-zodiac-aquarius::before{content:"\F0A7D"}.mdi-zodiac-aries::before{content:"\F0A7E"}.mdi-zodiac-cancer::before{content:"\F0A7F"}.mdi-zodiac-capricorn::before{content:"\F0A80"}.mdi-zodiac-gemini::before{content:"\F0A81"}.mdi-zodiac-leo::before{content:"\F0A82"}.mdi-zodiac-libra::before{content:"\F0A83"}.mdi-zodiac-pisces::before{content:"\F0A84"}.mdi-zodiac-sagittarius::before{content:"\F0A85"}.mdi-zodiac-scorpio::before{content:"\F0A86"}.mdi-zodiac-taurus::before{content:"\F0A87"}.mdi-zodiac-virgo::before{content:"\F0A88"}.mdi-blank::before{content:"\F68C";visibility:hidden}.mdi-18px.mdi-set,.mdi-18px.mdi:before{font-size:18px}.mdi-24px.mdi-set,.mdi-24px.mdi:before{font-size:24px}.mdi-36px.mdi-set,.mdi-36px.mdi:before{font-size:36px}.mdi-48px.mdi-set,.mdi-48px.mdi:before{font-size:48px}.mdi-dark:before{color:rgba(0,0,0,0.54)}.mdi-dark.mdi-inactive:before{color:rgba(0,0,0,0.26)}.mdi-light:before{color:#fff}.mdi-light.mdi-inactive:before{color:rgba(255,255,255,0.3)}.mdi-rotate-45:before{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.mdi-rotate-90:before{-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.mdi-rotate-135:before{-webkit-transform:rotate(135deg);-ms-transform:rotate(135deg);transform:rotate(135deg)}.mdi-rotate-180:before{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.mdi-rotate-225:before{-webkit-transform:rotate(225deg);-ms-transform:rotate(225deg);transform:rotate(225deg)}.mdi-rotate-270:before{-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.mdi-rotate-315:before{-webkit-transform:rotate(315deg);-ms-transform:rotate(315deg);transform:rotate(315deg)}.mdi-flip-h:before{-webkit-transform:scaleX(-1);transform:scaleX(-1);filter:FlipH;-ms-filter:"FlipH"}.mdi-flip-v:before{-webkit-transform:scaleY(-1);transform:scaleY(-1);filter:FlipV;-ms-filter:"FlipV"}.mdi-spin:before{-webkit-animation:mdi-spin 2s infinite linear;animation:mdi-spin 2s infinite linear}@-webkit-keyframes mdi-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes mdi-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}} + +/*# sourceMappingURL=materialdesignicons.css.map */ \ No newline at end of file diff --git a/web/scripts/api.js b/web/scripts/api.js index 8c8155be6..03c3fb607 100644 --- a/web/scripts/api.js +++ b/web/scripts/api.js @@ -136,6 +136,9 @@ class ComfyApi extends EventTarget { case "execution_start": this.dispatchEvent(new CustomEvent("execution_start", { detail: msg.data })); break; + case "execution_success": + this.dispatchEvent(new CustomEvent("execution_success", { detail: msg.data })); + break; case "execution_error": this.dispatchEvent(new CustomEvent("execution_error", { detail: msg.data })); break; @@ -327,7 +330,7 @@ class ComfyApi extends EventTarget { /** * Gets user configuration data and where data should be stored - * @returns { Promise<{ storage: "server" | "browser", users?: Promise, migrated?: boolean }> } + * @returns { Promise<{ storage: "server" | "browser", users?: Promise, migrated?: boolean }> } */ async getUserConfig() { return (await this.fetchApi("/users")).json(); @@ -335,7 +338,7 @@ class ComfyApi extends EventTarget { /** * Creates a new user - * @param { string } username + * @param { string } username * @returns The fetch response */ createUser(username) { @@ -394,7 +397,7 @@ class ComfyApi extends EventTarget { * Gets a user data file for the current user * @param { string } file The name of the userdata file to load * @param { RequestInit } [options] - * @returns { Promise } The fetch response object + * @returns { Promise } The fetch response object */ async getUserData(file, options) { return this.fetchApi(`/userdata/${encodeURIComponent(file)}`, options); @@ -404,18 +407,75 @@ class ComfyApi extends EventTarget { * Stores a user data file for the current user * @param { string } file The name of the userdata file to save * @param { unknown } data The data to save to the file - * @param { RequestInit & { stringify?: boolean, throwOnError?: boolean } } [options] - * @returns { Promise } + * @param { RequestInit & { overwrite?: boolean, stringify?: boolean, throwOnError?: boolean } } [options] + * @returns { Promise } */ - async storeUserData(file, data, options = { stringify: true, throwOnError: true }) { - const resp = await this.fetchApi(`/userdata/${encodeURIComponent(file)}`, { + async storeUserData(file, data, options = { overwrite: true, stringify: true, throwOnError: true }) { + const resp = await this.fetchApi(`/userdata/${encodeURIComponent(file)}?overwrite=${options?.overwrite}`, { method: "POST", body: options?.stringify ? JSON.stringify(data) : data, ...options, - }); - if (resp.status !== 200) { + }); + if (resp.status !== 200 && options?.throwOnError !== false) { throw new Error(`Error storing user data file '${file}': ${resp.status} ${(await resp).statusText}`); } + return resp; + } + + /** + * Deletes a user data file for the current user + * @param { string } file The name of the userdata file to delete + */ + async deleteUserData(file) { + const resp = await this.fetchApi(`/userdata/${encodeURIComponent(file)}`, { + method: "DELETE", + }); + if (resp.status !== 204) { + throw new Error(`Error removing user data file '${file}': ${resp.status} ${(resp).statusText}`); + } + } + + /** + * Move a user data file for the current user + * @param { string } source The userdata file to move + * @param { string } dest The destination for the file + */ + async moveUserData(source, dest, options = { overwrite: false }) { + const resp = await this.fetchApi(`/userdata/${encodeURIComponent(source)}/move/${encodeURIComponent(dest)}?overwrite=${options?.overwrite}`, { + method: "POST", + }); + return resp; + } + + /** + * @overload + * Lists user data files for the current user + * @param { string } dir The directory in which to list files + * @param { boolean } [recurse] If the listing should be recursive + * @param { true } [split] If the paths should be split based on the os path separator + * @returns { Promise> } The list of split file paths in the format [fullPath, ...splitPath] + */ + /** + * @overload + * Lists user data files for the current user + * @param { string } dir The directory in which to list files + * @param { boolean } [recurse] If the listing should be recursive + * @param { false | undefined } [split] If the paths should be split based on the os path separator + * @returns { Promise> } The list of files + */ + async listUserData(dir, recurse, split) { + const resp = await this.fetchApi( + `/userdata?${new URLSearchParams({ + recurse, + dir, + split, + })}` + ); + if (resp.status === 404) return []; + if (resp.status !== 200) { + throw new Error(`Error getting user data list '${dir}': ${resp.status} ${resp.statusText}`); + } + return resp.json(); } } diff --git a/web/scripts/app.js b/web/scripts/app.js index 58fb765c4..8b4478a32 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -3,11 +3,13 @@ import { ComfyWidgets, initWidgets } from "./widgets.js"; import { ComfyUI, $el } from "./ui.js"; import { api } from "./api.js"; import { defaultGraph } from "./defaultGraph.js"; -import { getPngMetadata, getWebpMetadata, importA1111, getLatentMetadata } from "./pnginfo.js"; +import { getPngMetadata, getWebpMetadata, getFlacMetadata, importA1111, getLatentMetadata } from "./pnginfo.js"; import { addDomClippingSetting } from "./domWidget.js"; -import { createImageHost, calculateImageGrid } from "./ui/imagePreview.js" - -export const ANIM_PREVIEW_WIDGET = "$$comfy_animation_preview" +import { createImageHost, calculateImageGrid } from "./ui/imagePreview.js"; +import { ComfyAppMenu } from "./ui/menu/index.js"; +import { getStorageValue, setStorageValue } from "./utils.js"; +import { ComfyWorkflowManager } from "./workflows.js"; +export const ANIM_PREVIEW_WIDGET = "$$comfy_animation_preview"; function sanitizeNodeName(string) { let entityMap = { @@ -52,6 +54,12 @@ export class ComfyApp { constructor() { this.ui = new ComfyUI(this); this.logging = new ComfyLogging(this); + this.workflowManager = new ComfyWorkflowManager(this); + this.bodyTop = $el("div.comfyui-body-top", { parent: document.body }); + this.bodyLeft = $el("div.comfyui-body-left", { parent: document.body }); + this.bodyRight = $el("div.comfyui-body-right", { parent: document.body }); + this.bodyBottom = $el("div.comfyui-body-bottom", { parent: document.body }); + this.menu = new ComfyAppMenu(this); /** * List of extensions that are registered with the app @@ -63,7 +71,7 @@ export class ComfyApp { * Stores the execution output data for each node * @type {Record} */ - this.nodeOutputs = {}; + this._nodeOutputs = {}; /** * Stores the preview image data for each node @@ -78,6 +86,15 @@ export class ComfyApp { this.shiftDown = false; } + get nodeOutputs() { + return this._nodeOutputs; + } + + set nodeOutputs(value) { + this._nodeOutputs = value; + this.#invokeExtensions("onNodeOutputsUpdated", value); + } + getPreviewFormatParam() { let preview_format = this.ui.settings.getSettingValue("Comfy.PreviewFormat"); if(preview_format) @@ -1067,7 +1084,7 @@ export class ComfyApp { if (e.type == "keydown" && !e.repeat) { // Ctrl + M mute/unmute - if (e.key === 'm' && e.ctrlKey) { + if (e.key === 'm' && (e.metaKey || e.ctrlKey)) { if (this.selected_nodes) { for (var i in this.selected_nodes) { if (this.selected_nodes[i].mode === 2) { // never @@ -1081,7 +1098,7 @@ export class ComfyApp { } // Ctrl + B bypass - if (e.key === 'b' && e.ctrlKey) { + if (e.key === 'b' && (e.metaKey || e.ctrlKey)) { if (this.selected_nodes) { for (var i in this.selected_nodes) { if (this.selected_nodes[i].mode === 4) { // never @@ -1313,11 +1330,15 @@ export class ComfyApp { }); api.addEventListener("progress", ({ detail }) => { + if (this.workflowManager.activePrompt?.workflow + && this.workflowManager.activePrompt.workflow !== this.workflowManager.activeWorkflow) return; this.progress = detail; this.graph.setDirtyCanvas(true, false); }); api.addEventListener("executing", ({ detail }) => { + if (this.workflowManager.activePrompt ?.workflow + && this.workflowManager.activePrompt.workflow !== this.workflowManager.activeWorkflow) return; this.progress = null; this.runningNodeId = detail; this.graph.setDirtyCanvas(true, false); @@ -1325,6 +1346,8 @@ export class ComfyApp { }); api.addEventListener("executed", ({ detail }) => { + if (this.workflowManager.activePrompt ?.workflow + && this.workflowManager.activePrompt.workflow !== this.workflowManager.activeWorkflow) return; const output = this.nodeOutputs[detail.node]; if (detail.merge && output) { for (const k in detail.output ?? {}) { @@ -1433,6 +1456,11 @@ export class ComfyApp { }); await Promise.all(extensionPromises); + try { + this.menu.workflows.registerExtension(this); + } catch (error) { + console.error(error); + } } async #migrateSettings() { @@ -1520,15 +1548,17 @@ export class ComfyApp { */ async setup() { await this.#setUser(); - await this.ui.settings.load(); - await this.#loadExtensions(); // Create and mount the LiteGraph in the DOM const mainCanvas = document.createElement("canvas") mainCanvas.style.touchAction = "none" const canvasEl = (this.canvasEl = Object.assign(mainCanvas, { id: "graph-canvas" })); canvasEl.tabIndex = "1"; - document.body.prepend(canvasEl); + document.body.append(canvasEl); + this.resizeCanvas(); + + await Promise.all([this.workflowManager.loadWorkflows(), this.ui.settings.load()]); + await this.#loadExtensions(); addDomClippingSetting(); this.#addProcessMouseHandler(); @@ -1541,7 +1571,7 @@ export class ComfyApp { this.#addAfterConfigureHandler(); - const canvas = (this.canvas = new LGraphCanvas(canvasEl, this.graph)); + this.canvas = new LGraphCanvas(canvasEl, this.graph); this.ctx = canvasEl.getContext("2d"); LiteGraph.release_link_on_empty_shows_menu = true; @@ -1549,19 +1579,14 @@ export class ComfyApp { this.graph.start(); - function resizeCanvas() { - // Limit minimal scale to 1, see https://github.com/comfyanonymous/ComfyUI/pull/845 - const scale = Math.max(window.devicePixelRatio, 1); - const { width, height } = canvasEl.getBoundingClientRect(); - canvasEl.width = Math.round(width * scale); - canvasEl.height = Math.round(height * scale); - canvasEl.getContext("2d").scale(scale, scale); - canvas.draw(true, true); - } - // Ensure the canvas fills the window - resizeCanvas(); - window.addEventListener("resize", resizeCanvas); + this.resizeCanvas(); + window.addEventListener("resize", () => this.resizeCanvas()); + const ro = new ResizeObserver(() => this.resizeCanvas()); + ro.observe(this.bodyTop); + ro.observe(this.bodyLeft); + ro.observe(this.bodyRight); + ro.observe(this.bodyBottom); await this.#invokeExtensionsAsync("init"); await this.registerNodes(); @@ -1573,7 +1598,8 @@ export class ComfyApp { const loadWorkflow = async (json) => { if (json) { const workflow = JSON.parse(json); - await this.loadGraphData(workflow); + const workflowName = getStorageValue("Comfy.PreviousWorkflow"); + await this.loadGraphData(workflow, true, true, workflowName); return true; } }; @@ -1609,6 +1635,19 @@ export class ComfyApp { await this.#invokeExtensionsAsync("setup"); } + resizeCanvas() { + // Limit minimal scale to 1, see https://github.com/comfyanonymous/ComfyUI/pull/845 + const scale = Math.max(window.devicePixelRatio, 1); + + // Clear fixed width and height while calculating rect so it uses 100% instead + this.canvasEl.height = this.canvasEl.width = ""; + const { width, height } = this.canvasEl.getBoundingClientRect(); + this.canvasEl.width = Math.round(width * scale); + this.canvasEl.height = Math.round(height * scale); + this.canvasEl.getContext("2d").scale(scale, scale); + this.canvas?.draw(true, true); + } + /** * Registers nodes with the graph */ @@ -1795,12 +1834,29 @@ export class ComfyApp { }); } + async changeWorkflow(callback, workflow = null) { + try { + this.workflowManager.activeWorkflow?.changeTracker?.store() + } catch (error) { + console.error(error); + } + await callback(); + try { + this.workflowManager.setWorkflow(workflow); + this.workflowManager.activeWorkflow?.track() + } catch (error) { + console.error(error); + } + } + /** * Populates the graph with the specified workflow data * @param {*} graphData A serialized graph object * @param { boolean } clean If the graph state, e.g. images, should be cleared + * @param { boolean } restore_view If the graph position should be restored + * @param { import("./workflows.js").ComfyWorkflowInstance | null } workflow The workflow */ - async loadGraphData(graphData, clean = true, restore_view = true) { + async loadGraphData(graphData, clean = true, restore_view = true, workflow = null) { if (clean !== false) { this.clean(); } @@ -1818,6 +1874,12 @@ export class ComfyApp { { graphData = structuredClone(graphData); } + + try { + this.workflowManager.setWorkflow(workflow); + } catch (error) { + console.error(error); + } const missingNodeTypes = []; await this.#invokeExtensionsAsync("beforeConfigureGraph", graphData, missingNodeTypes); @@ -1840,6 +1902,11 @@ export class ComfyApp { this.canvas.ds.offset = graphData.extra.ds.offset; this.canvas.ds.scale = graphData.extra.ds.scale; } + + try { + this.workflowManager.activeWorkflow?.track() + } catch (error) { + } } catch (error) { let errorHint = []; // Try extracting filename to see if it was caused by an extension script @@ -1899,6 +1966,14 @@ export class ComfyApp { if (widget.value.startsWith("sample_")) { widget.value = widget.value.slice(7); } + if (widget.value === "euler_pp" || widget.value === "euler_ancestral_pp") { + widget.value = widget.value.slice(0, -3); + for (let w of node.widgets) { + if (w.name == "cfg") { + w.value *= 2.0; + } + } + } } } if (node.type == "KSampler" || node.type == "KSamplerAdvanced" || node.type == "PrimitiveNode") { @@ -1927,14 +2002,17 @@ export class ComfyApp { this.showMissingNodesError(missingNodeTypes); } await this.#invokeExtensionsAsync("afterConfigureGraph", missingNodeTypes); + requestAnimationFrame(() => { + this.graph.setDirtyCanvas(true, true); + }); } /** * Converts the current graph workflow for sending to the API * @returns The workflow and node links */ - async graphToPrompt() { - for (const outerNode of this.graph.computeExecutionOrder(false)) { + async graphToPrompt(graph = this.graph, clean = true) { + for (const outerNode of graph.computeExecutionOrder(false)) { if (outerNode.widgets) { for (const widget of outerNode.widgets) { // Allow widgets to run callbacks before a prompt has been queued @@ -1954,10 +2032,10 @@ export class ComfyApp { } } - const workflow = this.graph.serialize(); + const workflow = graph.serialize(); const output = {}; // Process nodes in order of execution - for (const outerNode of this.graph.computeExecutionOrder(false)) { + for (const outerNode of graph.computeExecutionOrder(false)) { const skipNode = outerNode.mode === 2 || outerNode.mode === 4; const innerNodes = (!skipNode && outerNode.getInnerNodes) ? outerNode.getInnerNodes() : [outerNode]; for (const node of innerNodes) { @@ -2049,13 +2127,14 @@ export class ComfyApp { } // Remove inputs connected to removed nodes - - for (const o in output) { - for (const i in output[o].inputs) { - if (Array.isArray(output[o].inputs[i]) - && output[o].inputs[i].length === 2 - && !output[output[o].inputs[i][0]]) { - delete output[o].inputs[i]; + if(clean) { + for (const o in output) { + for (const i in output[o].inputs) { + if (Array.isArray(output[o].inputs[i]) + && output[o].inputs[i].length === 2 + && !output[output[o].inputs[i][0]]) { + delete output[o].inputs[i]; + } } } } @@ -2123,6 +2202,14 @@ export class ComfyApp { this.lastNodeErrors = res.node_errors; if (this.lastNodeErrors.length > 0) { this.canvas.draw(true, true); + } else { + try { + this.workflowManager.storePrompt({ + id: res.prompt_id, + nodes: Object.keys(p.output) + }); + } catch (error) { + } } } catch (error) { const formattedError = this.#formatPromptError(error) @@ -2155,6 +2242,7 @@ export class ComfyApp { this.#processingQueue = false; } api.dispatchEvent(new CustomEvent("promptQueued", { detail: { number, batchCount } })); + return !this.lastNodeErrors; } showErrorOnFileLoad(file) { @@ -2170,14 +2258,24 @@ export class ComfyApp { * @param {File} file */ async handleFile(file) { + const removeExt = f => { + if(!f) return f; + const p = f.lastIndexOf("."); + if(p === -1) return f; + return f.substring(0, p); + }; + + const fileName = removeExt(file.name); if (file.type === "image/png") { const pngInfo = await getPngMetadata(file); if (pngInfo?.workflow) { - await this.loadGraphData(JSON.parse(pngInfo.workflow)); + await this.loadGraphData(JSON.parse(pngInfo.workflow), true, true, fileName); } else if (pngInfo?.prompt) { - this.loadApiJson(JSON.parse(pngInfo.prompt)); + this.loadApiJson(JSON.parse(pngInfo.prompt), fileName); } else if (pngInfo?.parameters) { - importA1111(this.graph, pngInfo.parameters); + this.changeWorkflow(() => { + importA1111(this.graph, pngInfo.parameters); + }, fileName) } else { this.showErrorOnFileLoad(file); } @@ -2188,9 +2286,22 @@ export class ComfyApp { const prompt = pngInfo?.prompt || pngInfo?.Prompt; if (workflow) { - this.loadGraphData(JSON.parse(workflow)); + this.loadGraphData(JSON.parse(workflow), true, true, fileName); } else if (prompt) { - this.loadApiJson(JSON.parse(prompt)); + this.loadApiJson(JSON.parse(prompt), fileName); + } else { + this.showErrorOnFileLoad(file); + } + } else if (file.type === "audio/flac" || file.type === "audio/x-flac") { + const pngInfo = await getFlacMetadata(file); + // Support loading workflows from that webp custom node. + const workflow = pngInfo?.workflow; + const prompt = pngInfo?.prompt; + + if (workflow) { + this.loadGraphData(JSON.parse(workflow), true, true, fileName); + } else if (prompt) { + this.loadApiJson(JSON.parse(prompt), fileName); } else { this.showErrorOnFileLoad(file); } @@ -2201,16 +2312,16 @@ export class ComfyApp { if (jsonContent?.templates) { this.loadTemplateData(jsonContent); } else if(this.isApiJson(jsonContent)) { - this.loadApiJson(jsonContent); + this.loadApiJson(jsonContent, fileName); } else { - await this.loadGraphData(jsonContent); + await this.loadGraphData(jsonContent, true, true, fileName); } }; reader.readAsText(file); } else if (file.name?.endsWith(".latent") || file.name?.endsWith(".safetensors")) { const info = await getLatentMetadata(file); if (info.workflow) { - await this.loadGraphData(JSON.parse(info.workflow)); + await this.loadGraphData(JSON.parse(info.workflow), true, true, fileName); } else if (info.prompt) { this.loadApiJson(JSON.parse(info.prompt)); } else { @@ -2225,7 +2336,7 @@ export class ComfyApp { return Object.values(data).every((v) => v.class_type); } - loadApiJson(apiData) { + loadApiJson(apiData, fileName) { const missingNodeTypes = Object.values(apiData).filter((n) => !LiteGraph.registered_node_types[n.class_type]); if (missingNodeTypes.length) { this.showMissingNodesError(missingNodeTypes.map(t => t.class_type), false); @@ -2242,38 +2353,39 @@ export class ComfyApp { app.graph.add(node); } - for (const id of ids) { - const data = apiData[id]; - const node = app.graph.getNodeById(id); - for (const input in data.inputs ?? {}) { - const value = data.inputs[input]; - if (value instanceof Array) { - const [fromId, fromSlot] = value; - const fromNode = app.graph.getNodeById(fromId); - let toSlot = node.inputs?.findIndex((inp) => inp.name === input); - if (toSlot == null || toSlot === -1) { - try { - // Target has no matching input, most likely a converted widget - const widget = node.widgets?.find((w) => w.name === input); - if (widget && node.convertWidgetToInput?.(widget)) { - toSlot = node.inputs?.length - 1; - } - } catch (error) {} - } - if (toSlot != null || toSlot !== -1) { - fromNode.connect(fromSlot, node, toSlot); - } - } else { - const widget = node.widgets?.find((w) => w.name === input); - if (widget) { - widget.value = value; - widget.callback?.(value); + this.changeWorkflow(() => { + for (const id of ids) { + const data = apiData[id]; + const node = app.graph.getNodeById(id); + for (const input in data.inputs ?? {}) { + const value = data.inputs[input]; + if (value instanceof Array) { + const [fromId, fromSlot] = value; + const fromNode = app.graph.getNodeById(fromId); + let toSlot = node.inputs?.findIndex((inp) => inp.name === input); + if (toSlot == null || toSlot === -1) { + try { + // Target has no matching input, most likely a converted widget + const widget = node.widgets?.find((w) => w.name === input); + if (widget && node.convertWidgetToInput?.(widget)) { + toSlot = node.inputs?.length - 1; + } + } catch (error) {} + } + if (toSlot != null || toSlot !== -1) { + fromNode.connect(fromSlot, node, toSlot); + } + } else { + const widget = node.widgets?.find((w) => w.name === input); + if (widget) { + widget.value = value; + widget.callback?.(value); + } } } } - } - - app.graph.arrange(); + app.graph.arrange(); + }, fileName); } /** diff --git a/web/scripts/changeTracker.js b/web/scripts/changeTracker.js new file mode 100644 index 000000000..d7798dbe9 --- /dev/null +++ b/web/scripts/changeTracker.js @@ -0,0 +1,255 @@ +// @ts-check + +import { api } from "./api.js"; +import { clone } from "./utils.js"; + +export class ChangeTracker { + static MAX_HISTORY = 50; + #app; + undo = []; + redo = []; + activeState = null; + isOurLoad = false; + /** @type { import("./workflows").ComfyWorkflow | null } */ + workflow; + + ds; + nodeOutputs; + + get app() { + return this.#app ?? this.workflow.manager.app; + } + + constructor(workflow) { + this.workflow = workflow; + } + + #setApp(app) { + this.#app = app; + } + + store() { + this.ds = { scale: this.app.canvas.ds.scale, offset: [...this.app.canvas.ds.offset] }; + } + + restore() { + if (this.ds) { + this.app.canvas.ds.scale = this.ds.scale; + this.app.canvas.ds.offset = this.ds.offset; + } + if (this.nodeOutputs) { + this.app.nodeOutputs = this.nodeOutputs; + } + } + + checkState() { + if (!this.app.graph) return; + + const currentState = this.app.graph.serialize(); + if (!this.activeState) { + this.activeState = clone(currentState); + return; + } + if (!ChangeTracker.graphEqual(this.activeState, currentState)) { + this.undo.push(this.activeState); + if (this.undo.length > ChangeTracker.MAX_HISTORY) { + this.undo.shift(); + } + this.activeState = clone(currentState); + this.redo.length = 0; + this.workflow.unsaved = true; + api.dispatchEvent(new CustomEvent("graphChanged", { detail: this.activeState })); + } + } + + async updateState(source, target) { + const prevState = source.pop(); + if (prevState) { + target.push(this.activeState); + this.isOurLoad = true; + await this.app.loadGraphData(prevState, false, false, this.workflow); + this.activeState = prevState; + } + } + + async undoRedo(e) { + if (e.ctrlKey || e.metaKey) { + if (e.key === "y") { + this.updateState(this.redo, this.undo); + return true; + } else if (e.key === "z") { + this.updateState(this.undo, this.redo); + return true; + } + } + } + + /** @param { import("./app.js").ComfyApp } app */ + static init(app) { + const changeTracker = () => app.workflowManager.activeWorkflow?.changeTracker ?? globalTracker; + globalTracker.#setApp(app); + + const loadGraphData = app.loadGraphData; + app.loadGraphData = async function () { + const v = await loadGraphData.apply(this, arguments); + const ct = changeTracker(); + if (ct.isOurLoad) { + ct.isOurLoad = false; + } else { + ct.checkState(); + } + return v; + }; + + let keyIgnored = false; + window.addEventListener( + "keydown", + (e) => { + const activeEl = document.activeElement; + requestAnimationFrame(async () => { + let bindInputEl; + // If we are auto queue in change mode then we do want to trigger on inputs + if (!app.ui.autoQueueEnabled || app.ui.autoQueueMode === "instant") { + if (activeEl?.tagName === "INPUT" || activeEl?.["type"] === "textarea") { + // Ignore events on inputs, they have their native history + return; + } + bindInputEl = activeEl; + } + + keyIgnored = e.key === "Control" || e.key === "Shift" || e.key === "Alt" || e.key === "Meta"; + if (keyIgnored) return; + + // Check if this is a ctrl+z ctrl+y + if (await changeTracker().undoRedo(e)) return; + + // If our active element is some type of input then handle changes after they're done + if (ChangeTracker.bindInput(bindInputEl)) return; + changeTracker().checkState(); + }); + }, + true + ); + + window.addEventListener("keyup", (e) => { + if (keyIgnored) { + keyIgnored = false; + changeTracker().checkState(); + } + }); + + // Handle clicking DOM elements (e.g. widgets) + window.addEventListener("mouseup", () => { + changeTracker().checkState(); + }); + + // Handle prompt queue event for dynamic widget changes + api.addEventListener("promptQueued", () => { + changeTracker().checkState(); + }); + + // Handle litegraph clicks + const processMouseUp = LGraphCanvas.prototype.processMouseUp; + LGraphCanvas.prototype.processMouseUp = function (e) { + const v = processMouseUp.apply(this, arguments); + changeTracker().checkState(); + return v; + }; + const processMouseDown = LGraphCanvas.prototype.processMouseDown; + LGraphCanvas.prototype.processMouseDown = function (e) { + const v = processMouseDown.apply(this, arguments); + changeTracker().checkState(); + return v; + }; + + // Handle litegraph context menu for COMBO widgets + const close = LiteGraph.ContextMenu.prototype.close; + LiteGraph.ContextMenu.prototype.close = function (e) { + const v = close.apply(this, arguments); + changeTracker().checkState(); + return v; + }; + + // Detects nodes being added via the node search dialog + const onNodeAdded = LiteGraph.LGraph.prototype.onNodeAdded; + LiteGraph.LGraph.prototype.onNodeAdded = function () { + const v = onNodeAdded?.apply(this, arguments); + if (!app?.configuringGraph) { + const ct = changeTracker(); + if (!ct.isOurLoad) { + ct.checkState(); + } + } + return v; + }; + + // Store node outputs + api.addEventListener("executed", ({ detail }) => { + const prompt = app.workflowManager.queuedPrompts[detail.prompt_id]; + if (!prompt?.workflow) return; + const nodeOutputs = (prompt.workflow.changeTracker.nodeOutputs ??= {}); + const output = nodeOutputs[detail.node]; + if (detail.merge && output) { + for (const k in detail.output ?? {}) { + const v = output[k]; + if (v instanceof Array) { + output[k] = v.concat(detail.output[k]); + } else { + output[k] = detail.output[k]; + } + } + } else { + nodeOutputs[detail.node] = detail.output; + } + }); + } + + static bindInput(app, activeEl) { + if (activeEl && activeEl.tagName !== "CANVAS" && activeEl.tagName !== "BODY") { + for (const evt of ["change", "input", "blur"]) { + if (`on${evt}` in activeEl) { + const listener = () => { + app.workflowManager.activeWorkflow.changeTracker.checkState(); + activeEl.removeEventListener(evt, listener); + }; + activeEl.addEventListener(evt, listener); + return true; + } + } + } + } + + static graphEqual(a, b, path = "") { + if (a === b) return true; + + if (typeof a == "object" && a && typeof b == "object" && b) { + const keys = Object.getOwnPropertyNames(a); + + if (keys.length != Object.getOwnPropertyNames(b).length) { + return false; + } + + for (const key of keys) { + let av = a[key]; + let bv = b[key]; + if (!path && key === "nodes") { + // Nodes need to be sorted as the order changes when selecting nodes + av = [...av].sort((a, b) => a.id - b.id); + bv = [...bv].sort((a, b) => a.id - b.id); + } else if (path === "extra.ds") { + // Ignore view changes + continue; + } + if (!ChangeTracker.graphEqual(av, bv, path + (path ? "." : "") + key)) { + return false; + } + } + + return true; + } + + return false; + } +} + +const globalTracker = new ChangeTracker({}); \ No newline at end of file diff --git a/web/scripts/domWidget.js b/web/scripts/domWidget.js index b7f437ad2..d97122f9d 100644 --- a/web/scripts/domWidget.js +++ b/web/scripts/domWidget.js @@ -34,8 +34,8 @@ function getClipPath(node, element) { } const widgetRect = element.getBoundingClientRect(); - const clipX = intersection[0] - widgetRect.x / scale + "px"; - const clipY = intersection[1] - widgetRect.y / scale + "px"; + const clipX = elRect.left + intersection[0] - widgetRect.x / scale + "px"; + const clipY = elRect.top + intersection[1] - widgetRect.y / scale + "px"; const clipWidth = intersection[2] + "px"; const clipHeight = intersection[3] + "px"; const path = `polygon(0% 0%, 0% 100%, ${clipX} 100%, ${clipX} ${clipY}, calc(${clipX} + ${clipWidth}) ${clipY}, calc(${clipX} + ${clipWidth}) calc(${clipY} + ${clipHeight}), ${clipX} calc(${clipY} + ${clipHeight}), ${clipX} 100%, 100% 100%, 100% 0%)`; @@ -210,7 +210,9 @@ LGraphNode.prototype.addDOMWidget = function (name, type, element, options) { if (!element.parentElement) { document.body.append(element); } - + element.hidden = true; + element.style.display = "none"; + let mouseDownHandler; if (element.blur) { mouseDownHandler = (event) => { @@ -254,15 +256,15 @@ LGraphNode.prototype.addDOMWidget = function (name, type, element, options) { const transform = new DOMMatrix() .scaleSelf(elRect.width / ctx.canvas.width, elRect.height / ctx.canvas.height) .multiplySelf(ctx.getTransform()) - .translateSelf(margin, margin + y); + .translateSelf(margin, margin + y ); const scale = new DOMMatrix().scaleSelf(transform.a, transform.d); Object.assign(element.style, { transformOrigin: "0 0", transform: scale, - left: `${transform.a + transform.e}px`, - top: `${transform.d + transform.f}px`, + left: `${transform.a + transform.e + elRect.left}px`, + top: `${transform.d + transform.f + elRect.top}px`, width: `${widgetWidth - margin * 2}px`, height: `${(widget.computedHeight ?? 50) - margin * 2}px`, position: "absolute", diff --git a/web/scripts/pnginfo.js b/web/scripts/pnginfo.js index 7132fb60f..8b1b2c61c 100644 --- a/web/scripts/pnginfo.js +++ b/web/scripts/pnginfo.js @@ -49,7 +49,7 @@ export function getPngMetadata(file) { function parseExifData(exifData) { // Check for the correct TIFF header (0x4949 for little-endian or 0x4D4D for big-endian) - const isLittleEndian = new Uint16Array(exifData.slice(0, 2))[0] === 0x4949; + const isLittleEndian = String.fromCharCode(...exifData.slice(0, 2)) === "II"; // Function to read 16-bit and 32-bit integers from binary data function readInt(offset, isLittleEndian, length) { @@ -134,6 +134,7 @@ export function getWebpMetadata(file) { let index = value.indexOf(':'); txt_chunks[value.slice(0, index)] = value.slice(index + 1); } + break; } offset += 8 + chunk_length; @@ -163,6 +164,78 @@ export function getLatentMetadata(file) { }); } + +function getString(dataView, offset, length) { + let string = ''; + for (let i = 0; i < length; i++) { + string += String.fromCharCode(dataView.getUint8(offset + i)); + } + return string; +} + +// Function to parse the Vorbis Comment block +function parseVorbisComment(dataView) { + let offset = 0; + const vendorLength = dataView.getUint32(offset, true); + offset += 4; + const vendorString = getString(dataView, offset, vendorLength); + offset += vendorLength; + + const userCommentListLength = dataView.getUint32(offset, true); + offset += 4; + const comments = {}; + for (let i = 0; i < userCommentListLength; i++) { + const commentLength = dataView.getUint32(offset, true); + offset += 4; + const comment = getString(dataView, offset, commentLength); + offset += commentLength; + + const [key, value] = comment.split('='); + + comments[key] = value; + } + + return comments; +} + +// Function to read a FLAC file and parse Vorbis comments +export function getFlacMetadata(file) { + return new Promise((r) => { + const reader = new FileReader(); + reader.onload = function(event) { + const arrayBuffer = event.target.result; + const dataView = new DataView(arrayBuffer); + + // Verify the FLAC signature + const signature = String.fromCharCode(...new Uint8Array(arrayBuffer, 0, 4)); + if (signature !== 'fLaC') { + console.error('Not a valid FLAC file'); + return; + } + + // Parse metadata blocks + let offset = 4; + let vorbisComment = null; + while (offset < dataView.byteLength) { + const isLastBlock = dataView.getUint8(offset) & 0x80; + const blockType = dataView.getUint8(offset) & 0x7F; + const blockSize = dataView.getUint32(offset, false) & 0xFFFFFF; + offset += 4; + + if (blockType === 4) { // Vorbis Comment block type + vorbisComment = parseVorbisComment(new DataView(arrayBuffer, offset, blockSize)); + } + + offset += blockSize; + if (isLastBlock) break; + } + + r(vorbisComment); + }; + reader.readAsArrayBuffer(file); + }); +} + export async function importA1111(graph, parameters) { const p = parameters.lastIndexOf("\nSteps:"); if (p > -1) { diff --git a/web/scripts/ui.js b/web/scripts/ui.js index 72e43d357..2c47412c9 100644 --- a/web/scripts/ui.js +++ b/web/scripts/ui.js @@ -6,17 +6,22 @@ import { ComfySettingsDialog } from "./ui/settings.js"; export const ComfyDialog = _ComfyDialog; /** - * - * @param { string } tag HTML Element Tag and optional classes e.g. div.class1.class2 - * @param { string | Element | Element[] | { + * @template { string | (keyof HTMLElementTagNameMap) } K + * @typedef { K extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[K] : HTMLElement } ElementType + */ + +/** + * @template { string | (keyof HTMLElementTagNameMap) } K + * @param { K } tag HTML Element Tag and optional classes e.g. div.class1.class2 + * @param { string | Element | Element[] | ({ * parent?: Element, - * $?: (el: Element) => void, + * $?: (el: ElementType) => void, * dataset?: DOMStringMap, - * style?: CSSStyleDeclaration, + * style?: Partial, * for?: string - * } | undefined } propsOrChildren - * @param { Element[] | undefined } [children] - * @returns + * } & Omit>, "style">) | undefined } [propsOrChildren] + * @param { string | Element | Element[] | undefined } [children] + * @returns { ElementType } */ export function $el(tag, propsOrChildren, children) { const split = tag.split("."); @@ -54,7 +59,7 @@ export function $el(tag, propsOrChildren, children) { Object.assign(element, propsOrChildren); if (children) { - element.append(...(children instanceof Array ? children : [children])); + element.append(...(children instanceof Array ? children.filter(Boolean) : [children])); } if (parent) { @@ -102,6 +107,8 @@ function dragElement(dragEl, settings) { } function positionElement() { + if(dragEl.style.display === "none") return; + const halfWidth = document.body.clientWidth / 2; const anchorRight = newPosX + dragEl.clientWidth / 2 > halfWidth; @@ -191,6 +198,8 @@ function dragElement(dragEl, settings) { document.onmouseup = null; document.onmousemove = null; } + + return restorePos; } class ComfyList { @@ -364,7 +373,7 @@ export class ComfyUI { const fileInput = $el("input", { id: "comfy-file-input", type: "file", - accept: ".json,image/png,.latent,.safetensors,image/webp", + accept: ".json,image/png,.latent,.safetensors,image/webp,audio/flac", style: {display: "none"}, parent: document.body, onchange: () => { @@ -372,6 +381,8 @@ export class ComfyUI { }, }); + this.loadFile = () => fileInput.click(); + const autoQueueModeEl = toggleSwitch( "autoQueueMode", [ @@ -621,10 +632,10 @@ export class ComfyUI { name: "Enable Dev mode Options", type: "boolean", defaultValue: false, - onChange: function(value) { document.getElementById("comfy-dev-save-api-button").style.display = value ? "block" : "none"}, + onChange: function(value) { document.getElementById("comfy-dev-save-api-button").style.display = value ? "flex" : "none"}, }); - dragElement(this.menuContainer, this.settings); + this.restoreMenuPosition = dragElement(this.menuContainer, this.settings); this.setStatus({exec_info: {queue_remaining: "X"}}); } diff --git a/web/scripts/ui/components/asyncDialog.js b/web/scripts/ui/components/asyncDialog.js new file mode 100644 index 000000000..434ce4b30 --- /dev/null +++ b/web/scripts/ui/components/asyncDialog.js @@ -0,0 +1,64 @@ +import { ComfyDialog } from "../dialog.js"; +import { $el } from "../../ui.js"; + +export class ComfyAsyncDialog extends ComfyDialog { + #resolve; + + constructor(actions) { + super( + "dialog.comfy-dialog.comfyui-dialog", + actions?.map((opt) => { + if (typeof opt === "string") { + opt = { text: opt }; + } + return $el("button.comfyui-button", { + type: "button", + textContent: opt.text, + onclick: () => this.close(opt.value ?? opt.text), + }); + }) + ); + } + + show(html) { + this.element.addEventListener("close", () => { + this.close(); + }); + + super.show(html); + + return new Promise((resolve) => { + this.#resolve = resolve; + }); + } + + showModal(html) { + this.element.addEventListener("close", () => { + this.close(); + }); + + super.show(html); + this.element.showModal(); + + return new Promise((resolve) => { + this.#resolve = resolve; + }); + } + + close(result = null) { + this.#resolve(result); + this.element.close(); + super.close(); + } + + static async prompt({ title = null, message, actions }) { + const dialog = new ComfyAsyncDialog(actions); + const content = [$el("span", message)]; + if (title) { + content.unshift($el("h3", title)); + } + const res = await dialog.showModal(content); + dialog.element.remove(); + return res; + } +} diff --git a/web/scripts/ui/components/button.js b/web/scripts/ui/components/button.js new file mode 100644 index 000000000..25e5aeebd --- /dev/null +++ b/web/scripts/ui/components/button.js @@ -0,0 +1,163 @@ +// @ts-check + +import { $el } from "../../ui.js"; +import { applyClasses, toggleElement } from "../utils.js"; +import { prop } from "../../utils.js"; + +/** + * @typedef {{ + * icon?: string; + * overIcon?: string; + * iconSize?: number; + * content?: string | HTMLElement; + * tooltip?: string; + * enabled?: boolean; + * action?: (e: Event, btn: ComfyButton) => void, + * classList?: import("../utils.js").ClassList, + * visibilitySetting?: { id: string, showValue: any }, + * app?: import("../../app.js").ComfyApp + * }} ComfyButtonProps + */ +export class ComfyButton { + #over = 0; + #popupOpen = false; + isOver = false; + iconElement = $el("i.mdi"); + contentElement = $el("span"); + /** + * @type {import("./popup.js").ComfyPopup} + */ + popup; + + /** + * @param {ComfyButtonProps} opts + */ + constructor({ + icon, + overIcon, + iconSize, + content, + tooltip, + action, + classList = "comfyui-button", + visibilitySetting, + app, + enabled = true, + }) { + this.element = $el("button", { + onmouseenter: () => { + this.isOver = true; + if(this.overIcon) { + this.updateIcon(); + } + }, + onmouseleave: () => { + this.isOver = false; + if(this.overIcon) { + this.updateIcon(); + } + } + + }, [this.iconElement, this.contentElement]); + + this.icon = prop(this, "icon", icon, toggleElement(this.iconElement, { onShow: this.updateIcon })); + this.overIcon = prop(this, "overIcon", overIcon, () => { + if(this.isOver) { + this.updateIcon(); + } + }); + this.iconSize = prop(this, "iconSize", iconSize, this.updateIcon); + this.content = prop( + this, + "content", + content, + toggleElement(this.contentElement, { + onShow: (el, v) => { + if (typeof v === "string") { + el.textContent = v; + } else { + el.replaceChildren(v); + } + }, + }) + ); + + this.tooltip = prop(this, "tooltip", tooltip, (v) => { + if (v) { + this.element.title = v; + } else { + this.element.removeAttribute("title"); + } + }); + this.classList = prop(this, "classList", classList, this.updateClasses); + this.hidden = prop(this, "hidden", false, this.updateClasses); + this.enabled = prop(this, "enabled", enabled, () => { + this.updateClasses(); + this.element.disabled = !this.enabled; + }); + this.action = prop(this, "action", action); + this.element.addEventListener("click", (e) => { + if (this.popup) { + // we are either a touch device or triggered by click not hover + if (!this.#over) { + this.popup.toggle(); + } + } + this.action?.(e, this); + }); + + if (visibilitySetting?.id) { + const settingUpdated = () => { + this.hidden = app.ui.settings.getSettingValue(visibilitySetting.id) !== visibilitySetting.showValue; + }; + app.ui.settings.addEventListener(visibilitySetting.id + ".change", settingUpdated); + settingUpdated(); + } + } + + updateIcon = () => (this.iconElement.className = `mdi mdi-${(this.isOver && this.overIcon) || this.icon}${this.iconSize ? " mdi-" + this.iconSize + "px" : ""}`); + updateClasses = () => { + const internalClasses = []; + if (this.hidden) { + internalClasses.push("hidden"); + } + if (!this.enabled) { + internalClasses.push("disabled"); + } + if (this.popup) { + if (this.#popupOpen) { + internalClasses.push("popup-open"); + } else { + internalClasses.push("popup-closed"); + } + } + applyClasses(this.element, this.classList, ...internalClasses); + }; + + /** + * + * @param { import("./popup.js").ComfyPopup } popup + * @param { "click" | "hover" } mode + */ + withPopup(popup, mode = "click") { + this.popup = popup; + + if (mode === "hover") { + for (const el of [this.element, this.popup.element]) { + el.addEventListener("mouseenter", () => { + this.popup.open = !!++this.#over; + }); + el.addEventListener("mouseleave", () => { + this.popup.open = !!--this.#over; + }); + } + } + + popup.addEventListener("change", () => { + this.#popupOpen = popup.open; + this.updateClasses(); + }); + + return this; + } +} diff --git a/web/scripts/ui/components/buttonGroup.js b/web/scripts/ui/components/buttonGroup.js new file mode 100644 index 000000000..573572fd0 --- /dev/null +++ b/web/scripts/ui/components/buttonGroup.js @@ -0,0 +1,45 @@ +// @ts-check + +import { $el } from "../../ui.js"; +import { ComfyButton } from "./button.js"; +import { prop } from "../../utils.js"; + +export class ComfyButtonGroup { + element = $el("div.comfyui-button-group"); + + /** @param {Array} buttons */ + constructor(...buttons) { + this.buttons = prop(this, "buttons", buttons, () => this.update()); + } + + /** + * @param {ComfyButton} button + * @param {number} index + */ + insert(button, index) { + this.buttons.splice(index, 0, button); + this.update(); + } + + /** @param {ComfyButton} button */ + append(button) { + this.buttons.push(button); + this.update(); + } + + /** @param {ComfyButton|number} indexOrButton */ + remove(indexOrButton) { + if (typeof indexOrButton !== "number") { + indexOrButton = this.buttons.indexOf(indexOrButton); + } + if (indexOrButton > -1) { + const r = this.buttons.splice(indexOrButton, 1); + this.update(); + return r; + } + } + + update() { + this.element.replaceChildren(...this.buttons.map((b) => b["element"] ?? b)); + } +} diff --git a/web/scripts/ui/components/popup.js b/web/scripts/ui/components/popup.js new file mode 100644 index 000000000..ee59b35d9 --- /dev/null +++ b/web/scripts/ui/components/popup.js @@ -0,0 +1,128 @@ +// @ts-check + +import { prop } from "../../utils.js"; +import { $el } from "../../ui.js"; +import { applyClasses } from "../utils.js"; + +export class ComfyPopup extends EventTarget { + element = $el("div.comfyui-popup"); + + /** + * @param {{ + * target: HTMLElement, + * container?: HTMLElement, + * classList?: import("../utils.js").ClassList, + * ignoreTarget?: boolean, + * closeOnEscape?: boolean, + * position?: "absolute" | "relative", + * horizontal?: "left" | "right" + * }} param0 + * @param {...HTMLElement} children + */ + constructor( + { + target, + container = document.body, + classList = "", + ignoreTarget = true, + closeOnEscape = true, + position = "absolute", + horizontal = "left", + }, + ...children + ) { + super(); + this.target = target; + this.ignoreTarget = ignoreTarget; + this.container = container; + this.position = position; + this.closeOnEscape = closeOnEscape; + this.horizontal = horizontal; + + container.append(this.element); + + this.children = prop(this, "children", children, () => { + this.element.replaceChildren(...this.children); + this.update(); + }); + this.classList = prop(this, "classList", classList, () => applyClasses(this.element, this.classList, "comfyui-popup", horizontal)); + this.open = prop(this, "open", false, (v, o) => { + if (v === o) return; + if (v) { + this.#show(); + } else { + this.#hide(); + } + }); + } + + toggle() { + this.open = !this.open; + } + + #hide() { + this.element.classList.remove("open"); + window.removeEventListener("resize", this.update); + window.removeEventListener("click", this.#clickHandler, { capture: true }); + window.removeEventListener("keydown", this.#escHandler, { capture: true }); + + this.dispatchEvent(new CustomEvent("close")); + this.dispatchEvent(new CustomEvent("change")); + } + + #show() { + this.element.classList.add("open"); + this.update(); + + window.addEventListener("resize", this.update); + window.addEventListener("click", this.#clickHandler, { capture: true }); + if (this.closeOnEscape) { + window.addEventListener("keydown", this.#escHandler, { capture: true }); + } + + this.dispatchEvent(new CustomEvent("open")); + this.dispatchEvent(new CustomEvent("change")); + } + + #escHandler = (e) => { + if (e.key === "Escape") { + this.open = false; + e.preventDefault(); + e.stopImmediatePropagation(); + } + }; + + #clickHandler = (e) => { + /** @type {any} */ + const target = e.target; + if (!this.element.contains(target) && this.ignoreTarget && !this.target.contains(target)) { + this.open = false; + } + }; + + update = () => { + const rect = this.target.getBoundingClientRect(); + this.element.style.setProperty("--bottom", "unset"); + if (this.position === "absolute") { + if (this.horizontal === "left") { + this.element.style.setProperty("--left", rect.left + "px"); + } else { + this.element.style.setProperty("--left", rect.right - this.element.clientWidth + "px"); + } + this.element.style.setProperty("--top", rect.bottom + "px"); + this.element.style.setProperty("--limit", rect.bottom + "px"); + } else { + this.element.style.setProperty("--left", 0 + "px"); + this.element.style.setProperty("--top", rect.height + "px"); + this.element.style.setProperty("--limit", rect.height + "px"); + } + + const thisRect = this.element.getBoundingClientRect(); + if (thisRect.height < 30) { + // Move up instead + this.element.style.setProperty("--top", "unset"); + this.element.style.setProperty("--bottom", rect.height + 5 + "px"); + this.element.style.setProperty("--limit", rect.height + 5 + "px"); + } + }; +} diff --git a/web/scripts/ui/components/splitButton.js b/web/scripts/ui/components/splitButton.js new file mode 100644 index 000000000..2b4e6d9f8 --- /dev/null +++ b/web/scripts/ui/components/splitButton.js @@ -0,0 +1,43 @@ +// @ts-check + +import { $el } from "../../ui.js"; +import { ComfyButton } from "./button.js"; +import { prop } from "../../utils.js"; +import { ComfyPopup } from "./popup.js"; + +export class ComfySplitButton { + /** + * @param {{ + * primary: ComfyButton, + * mode?: "hover" | "click", + * horizontal?: "left" | "right", + * position?: "relative" | "absolute" + * }} param0 + * @param {Array | Array} items + */ + constructor({ primary, mode, horizontal = "left", position = "relative" }, ...items) { + this.arrow = new ComfyButton({ + icon: "chevron-down", + }); + this.element = $el("div.comfyui-split-button" + (mode === "hover" ? ".hover" : ""), [ + $el("div.comfyui-split-primary", primary.element), + $el("div.comfyui-split-arrow", this.arrow.element), + ]); + this.popup = new ComfyPopup({ + target: this.element, + container: position === "relative" ? this.element : document.body, + classList: "comfyui-split-button-popup" + (mode === "hover" ? " hover" : ""), + closeOnEscape: mode === "click", + position, + horizontal, + }); + + this.arrow.withPopup(this.popup, mode); + + this.items = prop(this, "items", items, () => this.update()); + } + + update() { + this.popup.element.replaceChildren(...this.items.map((b) => b.element ?? b)); + } +} diff --git a/web/scripts/ui/dialog.js b/web/scripts/ui/dialog.js index aee93b3c8..803a97a2b 100644 --- a/web/scripts/ui/dialog.js +++ b/web/scripts/ui/dialog.js @@ -1,20 +1,26 @@ import { $el } from "../ui.js"; -export class ComfyDialog { - constructor() { - this.element = $el("div.comfy-modal", { parent: document.body }, [ +export class ComfyDialog extends EventTarget { + #buttons; + + constructor(type = "div", buttons = null) { + super(); + this.#buttons = buttons; + this.element = $el(type + ".comfy-modal", { parent: document.body }, [ $el("div.comfy-modal-content", [$el("p", { $: (p) => (this.textElement = p) }), ...this.createButtons()]), ]); } createButtons() { - return [ - $el("button", { - type: "button", - textContent: "Close", - onclick: () => this.close(), - }), - ]; + return ( + this.#buttons ?? [ + $el("button", { + type: "button", + textContent: "Close", + onclick: () => this.close(), + }), + ] + ); } close() { @@ -25,7 +31,7 @@ export class ComfyDialog { if (typeof html === "string") { this.textElement.innerHTML = html; } else { - this.textElement.replaceChildren(html); + this.textElement.replaceChildren(...(html instanceof Array ? html : [html])); } this.element.style.display = "flex"; } diff --git a/web/scripts/ui/menu/index.js b/web/scripts/ui/menu/index.js new file mode 100644 index 000000000..1e00b3d22 --- /dev/null +++ b/web/scripts/ui/menu/index.js @@ -0,0 +1,302 @@ +// @ts-check + +import { $el } from "../../ui.js"; +import { downloadBlob } from "../../utils.js"; +import { ComfyButton } from "../components/button.js"; +import { ComfyButtonGroup } from "../components/buttonGroup.js"; +import { ComfySplitButton } from "../components/splitButton.js"; +import { ComfyViewHistoryButton } from "./viewHistory.js"; +import { ComfyQueueButton } from "./queueButton.js"; +import { ComfyWorkflowsMenu } from "./workflows.js"; +import { ComfyViewQueueButton } from "./viewQueue.js"; +import { getInteruptButton } from "./interruptButton.js"; + +const collapseOnMobile = (t) => { + (t.element ?? t).classList.add("comfyui-menu-mobile-collapse"); + return t; +}; +const showOnMobile = (t) => { + (t.element ?? t).classList.add("lt-lg-show"); + return t; +}; + +export class ComfyAppMenu { + #sizeBreak = "lg"; + #lastSizeBreaks = { + lg: null, + md: null, + sm: null, + xs: null, + }; + #sizeBreaks = Object.keys(this.#lastSizeBreaks); + #cachedInnerSize = null; + #cacheTimeout = null; + + /** + * @param { import("../../app.js").ComfyApp } app + */ + constructor(app) { + this.app = app; + + this.workflows = new ComfyWorkflowsMenu(app); + const getSaveButton = (t) => + new ComfyButton({ + icon: "content-save", + tooltip: "Save the current workflow", + action: () => app.workflowManager.activeWorkflow.save(), + content: t, + }); + + this.logo = $el("h1.comfyui-logo.nlg-hide", { title: "ComfyUI" }, "ComfyUI"); + this.saveButton = new ComfySplitButton( + { + primary: getSaveButton(), + mode: "hover", + position: "absolute", + }, + getSaveButton("Save"), + new ComfyButton({ + icon: "content-save-edit", + content: "Save As", + tooltip: "Save the current graph as a new workflow", + action: () => app.workflowManager.activeWorkflow.save(true), + }), + new ComfyButton({ + icon: "download", + content: "Export", + tooltip: "Export the current workflow as JSON", + action: () => this.exportWorkflow("workflow", "workflow"), + }), + new ComfyButton({ + icon: "api", + content: "Export (API Format)", + tooltip: "Export the current workflow as JSON for use with the ComfyUI API", + action: () => this.exportWorkflow("workflow_api", "output"), + visibilitySetting: { id: "Comfy.DevMode", showValue: true }, + app, + }) + ); + this.actionsGroup = new ComfyButtonGroup( + new ComfyButton({ + icon: "refresh", + content: "Refresh", + tooltip: "Refresh widgets in nodes to find new models or files", + action: () => app.refreshComboInNodes(), + }), + new ComfyButton({ + icon: "clipboard-edit-outline", + content: "Clipspace", + tooltip: "Open Clipspace window", + action: () => app["openClipspace"](), + }), + new ComfyButton({ + icon: "fit-to-page-outline", + content: "Reset View", + tooltip: "Reset the canvas view", + action: () => app.resetView(), + }), + new ComfyButton({ + icon: "cancel", + content: "Clear", + tooltip: "Clears current workflow", + action: () => { + if (!app.ui.settings.getSettingValue("Comfy.ConfirmClear", true) || confirm("Clear workflow?")) { + app.clean(); + app.graph.clear(); + } + }, + }) + ); + this.settingsGroup = new ComfyButtonGroup( + new ComfyButton({ + icon: "cog", + content: "Settings", + tooltip: "Open settings", + action: () => { + app.ui.settings.show(); + }, + }) + ); + this.viewGroup = new ComfyButtonGroup( + new ComfyViewHistoryButton(app).element, + new ComfyViewQueueButton(app).element, + getInteruptButton("nlg-hide").element + ); + this.mobileMenuButton = new ComfyButton({ + icon: "menu", + action: (_, btn) => { + btn.icon = this.element.classList.toggle("expanded") ? "menu-open" : "menu"; + window.dispatchEvent(new Event("resize")); + }, + classList: "comfyui-button comfyui-menu-button", + }); + + this.element = $el("nav.comfyui-menu.lg", { style: { display: "none" } }, [ + this.logo, + this.workflows.element, + this.saveButton.element, + collapseOnMobile(this.actionsGroup).element, + $el("section.comfyui-menu-push"), + collapseOnMobile(this.settingsGroup).element, + collapseOnMobile(this.viewGroup).element, + + getInteruptButton("lt-lg-show").element, + new ComfyQueueButton(app).element, + showOnMobile(this.mobileMenuButton).element, + ]); + + let resizeHandler; + this.menuPositionSetting = app.ui.settings.addSetting({ + id: "Comfy.UseNewMenu", + defaultValue: "Disabled", + name: "[Beta] Use new menu and workflow management. Note: On small screens the menu will always be at the top.", + type: "combo", + options: ["Disabled", "Top", "Bottom"], + onChange: async (v) => { + if (v && v !== "Disabled") { + if (!resizeHandler) { + resizeHandler = () => { + this.calculateSizeBreak(); + }; + window.addEventListener("resize", resizeHandler); + } + this.updatePosition(v); + } else { + if (resizeHandler) { + window.removeEventListener("resize", resizeHandler); + resizeHandler = null; + } + document.body.style.removeProperty("display"); + app.ui.menuContainer.style.removeProperty("display"); + this.element.style.display = "none"; + app.ui.restoreMenuPosition(); + } + window.dispatchEvent(new Event("resize")); + }, + }); + } + + updatePosition(v) { + document.body.style.display = "grid"; + this.app.ui.menuContainer.style.display = "none"; + this.element.style.removeProperty("display"); + this.position = v; + if (v === "Bottom") { + this.app.bodyBottom.append(this.element); + } else { + this.app.bodyTop.prepend(this.element); + } + this.calculateSizeBreak(); + } + + updateSizeBreak(idx, prevIdx, direction) { + const newSize = this.#sizeBreaks[idx]; + if (newSize === this.#sizeBreak) return; + this.#cachedInnerSize = null; + clearTimeout(this.#cacheTimeout); + + this.#sizeBreak = this.#sizeBreaks[idx]; + for (let i = 0; i < this.#sizeBreaks.length; i++) { + const sz = this.#sizeBreaks[i]; + if (sz === this.#sizeBreak) { + this.element.classList.add(sz); + } else { + this.element.classList.remove(sz); + } + if (i < idx) { + this.element.classList.add("lt-" + sz); + } else { + this.element.classList.remove("lt-" + sz); + } + } + + if (idx) { + // We're on a small screen, force the menu at the top + if (this.position !== "Top") { + this.updatePosition("Top"); + } + } else if (this.position != this.menuPositionSetting.value) { + // Restore user position + this.updatePosition(this.menuPositionSetting.value); + } + + // Allow multiple updates, but prevent bouncing + if (!direction) { + direction = prevIdx - idx; + } else if (direction != prevIdx - idx) { + return; + } + this.calculateSizeBreak(direction); + } + + calculateSizeBreak(direction = 0) { + let idx = this.#sizeBreaks.indexOf(this.#sizeBreak); + const currIdx = idx; + const innerSize = this.calculateInnerSize(idx); + if (window.innerWidth >= this.#lastSizeBreaks[this.#sizeBreaks[idx - 1]]) { + if (idx > 0) { + idx--; + } + } else if (innerSize > this.element.clientWidth) { + this.#lastSizeBreaks[this.#sizeBreak] = Math.max(window.innerWidth, innerSize); + // We need to shrink + if (idx < this.#sizeBreaks.length - 1) { + idx++; + } + } + + this.updateSizeBreak(idx, currIdx, direction); + } + + calculateInnerSize(idx) { + // Cache the inner size to prevent too much calculation when resizing the window + clearTimeout(this.#cacheTimeout); + if (this.#cachedInnerSize) { + // Extend cache time + this.#cacheTimeout = setTimeout(() => (this.#cachedInnerSize = null), 100); + } else { + let innerSize = 0; + let count = 1; + for (const c of this.element.children) { + if (c.classList.contains("comfyui-menu-push")) continue; // ignore right push + if (idx && c.classList.contains("comfyui-menu-mobile-collapse")) continue; // ignore collapse items + innerSize += c.clientWidth; + count++; + } + innerSize += 8 * count; + this.#cachedInnerSize = innerSize; + this.#cacheTimeout = setTimeout(() => (this.#cachedInnerSize = null), 100); + } + return this.#cachedInnerSize; + } + + /** + * @param {string} defaultName + */ + getFilename(defaultName) { + if (this.app.ui.settings.getSettingValue("Comfy.PromptFilename", true)) { + defaultName = prompt("Save workflow as:", defaultName); + if (!defaultName) return; + if (!defaultName.toLowerCase().endsWith(".json")) { + defaultName += ".json"; + } + } + return defaultName; + } + + /** + * @param {string} [filename] + * @param { "workflow" | "output" } [promptProperty] + */ + async exportWorkflow(filename, promptProperty) { + if (this.app.workflowManager.activeWorkflow?.path) { + filename = this.app.workflowManager.activeWorkflow.name; + } + const p = await this.app.graphToPrompt(); + const json = JSON.stringify(p[promptProperty], null, 2); + const blob = new Blob([json], { type: "application/json" }); + const file = this.getFilename(filename); + if (!file) return; + downloadBlob(file, blob); + } +} diff --git a/web/scripts/ui/menu/interruptButton.js b/web/scripts/ui/menu/interruptButton.js new file mode 100644 index 000000000..4db3328db --- /dev/null +++ b/web/scripts/ui/menu/interruptButton.js @@ -0,0 +1,23 @@ +// @ts-check + +import { api } from "../../api.js"; +import { ComfyButton } from "../components/button.js"; + +export function getInteruptButton(visibility) { + const btn = new ComfyButton({ + icon: "close", + tooltip: "Cancel current generation", + enabled: false, + action: () => { + api.interrupt(); + }, + classList: ["comfyui-button", "comfyui-interrupt-button", visibility], + }); + + api.addEventListener("status", ({ detail }) => { + const sz = detail?.exec_info?.queue_remaining; + btn.enabled = sz > 0; + }); + + return btn; +} diff --git a/web/scripts/ui/menu/menu.css b/web/scripts/ui/menu/menu.css new file mode 100644 index 000000000..afaed3fb0 --- /dev/null +++ b/web/scripts/ui/menu/menu.css @@ -0,0 +1,705 @@ +.relative { + position: relative; +} +.hidden { + display: none !important; +} +.mdi.rotate270::before { + transform: rotate(270deg); +} + +/* Generic */ +.comfyui-button { + display: flex; + align-items: center; + gap: 0.5em; + cursor: pointer; + border: none; + border-radius: 4px; + padding: 4px 8px; + box-sizing: border-box; + margin: 0; + transition: box-shadow 0.1s; +} + +.comfyui-button:active { + box-shadow: inset 1px 1px 10px rgba(0, 0, 0, 0.5); +} +.comfyui-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} +.primary .comfyui-button, +.primary.comfyui-button { + background-color: var(--primary-bg) !important; + color: var(--primary-fg) !important; +} + +.primary .comfyui-button:not(:disabled):hover, +.primary.comfyui-button:not(:disabled):hover { + background-color: var(--primary-hover-bg) !important; + color: var(--primary-hover-fg) !important; +} + +/* Popup */ +.comfyui-popup { + position: absolute; + left: var(--left); + right: var(--right); + top: var(--top); + bottom: var(--bottom); + z-index: 2000; + max-height: calc(100vh - var(--limit) - 10px); + box-shadow: 3px 3px 5px 0px rgba(0, 0, 0, 0.3); +} + +.comfyui-popup:not(.open) { + display: none; +} + +.comfyui-popup.right.open { + border-top-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + overflow: hidden; +} +/* Split button */ +.comfyui-split-button { + position: relative; + display: flex; +} + +.comfyui-split-primary { + flex: auto; +} + +.comfyui-split-primary .comfyui-button { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: 1px solid var(--comfy-menu-bg); + width: 100%; +} + +.comfyui-split-arrow .comfyui-button { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + padding-left: 2px; + padding-right: 2px; +} + +.comfyui-split-button-popup { + white-space: nowrap; + background-color: var(--content-bg); + color: var(--content-fg); + display: flex; + flex-direction: column; + overflow: auto; +} + +.comfyui-split-button-popup.hover { + z-index: 2001; +} +.comfyui-split-button-popup > .comfyui-button { + border: none; + background-color: transparent; + color: var(--fg-color); + padding: 8px 12px 8px 8px; +} + +.comfyui-split-button-popup > .comfyui-button:not(:disabled):hover { + background-color: var(--comfy-input-bg); +} + +/* Button group */ +.comfyui-button-group { + display: flex; + border-radius: 4px; + overflow: hidden; +} + +.comfyui-button-group > .comfyui-button, +.comfyui-button-group > .comfyui-button-wrapper > .comfyui-button { + padding: 4px 10px; + border-radius: 0; +} + +/* Menu */ +.comfyui-menu { + width: 100vw; + background: var(--comfy-menu-bg); + color: var(--fg-color); + font-family: Arial, Helvetica, sans-serif; + font-size: 0.8em; + display: flex; + padding: 4px 8px; + align-items: center; + gap: 8px; + box-sizing: border-box; + z-index: 1000; + order: 0; + grid-column: 1/-1; + overflow: auto; + max-height: 90vh; +} + +.comfyui-menu>* { + flex-shrink: 0; +} +.comfyui-menu .mdi::before { + font-size: 18px; +} + +.comfyui-menu .comfyui-button { + background: var(--comfy-input-bg); + color: var(--fg-color); + white-space: nowrap; +} + +.comfyui-menu .comfyui-button:not(:disabled):hover { + background: var(--border-color); + color: var(--content-fg); +} + +.comfyui-menu .comfyui-split-button-popup > .comfyui-button { + border-radius: 0; + background-color: transparent; +} + +.comfyui-menu .comfyui-split-button-popup > .comfyui-button:not(:disabled):hover { + background-color: var(--comfy-input-bg); +} + +.comfyui-menu .comfyui-split-button-popup.left { + border-top-right-radius: 4px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; +} + +.comfyui-menu .comfyui-button.popup-open { + background-color: var(--content-bg); + color: var(--content-fg); +} + +.comfyui-menu-push { + margin-left: -0.8em; + flex: auto; +} + +.comfyui-logo { + font-size: 1.2em; + margin: 0; + user-select: none; + cursor: default; +} + +/* Workflows */ +.comfyui-workflows-button { + flex-direction: row-reverse; + max-width: 200px; + position: relative; + z-index: 0; +} + +.comfyui-workflows-button.popup-open { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} +.comfyui-workflows-button.unsaved { + font-style: italic; +} +.comfyui-workflows-button-progress { + position: absolute; + top: 0; + left: 0; + background-color: green; + height: 100%; + border-radius: 4px; + z-index: -1; +} + +.comfyui-workflows-button > span { + flex: auto; + text-align: left; + overflow: hidden; +} +.comfyui-workflows-button-inner { + display: flex; + align-items: center; + gap: 7px; + width: 150px; +} +.comfyui-workflows-label { + overflow: hidden; + text-overflow: ellipsis; + direction: rtl; + flex: auto; + position: relative; +} + +.comfyui-workflows-button.unsaved .comfyui-workflows-label { + padding-left: 8px; +} + +.comfyui-workflows-button.unsaved .comfyui-workflows-label:after { + content: "*"; + position: absolute; + top: 0; + left: 0; +} +.comfyui-workflows-button-inner .mdi-graph::before { + transform: rotate(-90deg); +} + +.comfyui-workflows-popup { + font-family: Arial, Helvetica, sans-serif; + font-size: 0.8em; + padding: 10px; + overflow: auto; + background-color: var(--content-bg); + color: var(--content-fg); + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + z-index: 400; +} + +.comfyui-workflows-panel { + min-height: 150px; +} + +.comfyui-workflows-panel .lds-ring { + transform: translate(-50%); + position: absolute; + left: 50%; + top: 75px; +} + +.comfyui-workflows-panel h3 { + margin: 10px 0 10px 0; + font-size: 11px; + opacity: 0.8; +} + +.comfyui-workflows-panel section header { + display: flex; + justify-content: space-between; + align-items: center; +} +.comfy-ui-workflows-search .mdi { + position: relative; + top: 2px; + pointer-events: none; +} +.comfy-ui-workflows-search input { + background-color: var(--comfy-input-bg); + color: var(--input-text); + border: none; + border-radius: 4px; + padding: 4px 10px; + margin-left: -24px; + text-indent: 18px; +} +.comfy-ui-workflows-search input:placeholder-shown { + width: 10px; +} +.comfy-ui-workflows-search input:placeholder-shown:focus { + width: auto; +} +.comfyui-workflows-actions { + display: flex; + gap: 10px; + margin-bottom: 10px; +} + +.comfyui-workflows-actions .comfyui-button { + background: var(--comfy-input-bg); + color: var(--input-text); +} + +.comfyui-workflows-actions .comfyui-button:not(:disabled):hover { + background: var(--primary-bg); + color: var(--primary-fg); +} + +.comfyui-workflows-favorites, +.comfyui-workflows-open { + border-bottom: 1px solid var(--comfy-input-bg); + padding-bottom: 5px; + margin-bottom: 5px; +} + +.comfyui-workflows-open .active { + font-weight: bold; +} + +.comfyui-workflows-favorites:empty { + display: none; +} + +.comfyui-workflows-tree { + padding: 0; + margin: 0; +} + +.comfyui-workflows-tree:empty::after { + content: "No saved workflows"; + display: block; + text-align: center; +} +.comfyui-workflows-tree > ul { + padding: 0; +} + +.comfyui-workflows-tree > ul ul { + margin: 0; + padding: 0 0 0 25px; +} + +.comfyui-workflows-tree:not(.filtered) .closed > ul { + display: none; +} + +.comfyui-workflows-tree li, +.comfyui-workflows-tree-file { + --item-height: 32px; + list-style-type: none; + height: var(--item-height); + display: flex; + align-items: center; + gap: 5px; + cursor: pointer; + user-select: none; +} + +.comfyui-workflows-tree-file.active::before, +.comfyui-workflows-tree li:hover::before, +.comfyui-workflows-tree-file:hover::before { + content: ""; + position: absolute; + width: 100%; + left: 0; + height: var(--item-height); + background-color: var(--content-hover-bg); + color: var(--content-hover-fg); + z-index: -1; +} + +.comfyui-workflows-tree-file.active::before { + background-color: var(--primary-bg); + color: var(--primary-fg); +} + +.comfyui-workflows-tree-file.running:not(:hover)::before { + content: ""; + position: absolute; + width: var(--progress, 0); + left: 0; + height: var(--item-height); + background-color: green; + z-index: -1; +} + +.comfyui-workflows-tree-file.unsaved span { + font-style: italic; +} + +.comfyui-workflows-tree-file span { + flex: auto; +} + +.comfyui-workflows-tree-file span + .comfyui-workflows-file-action { + margin-left: 10px; +} + +.comfyui-workflows-tree-file .comfyui-workflows-file-action { + background-color: transparent; + color: var(--fg-color); + padding: 2px 4px; +} + +.lg ~ .comfyui-workflows-popup .comfyui-workflows-tree-file:not(:hover) .comfyui-workflows-file-action { + opacity: 0; +} + +.comfyui-workflows-tree-file .comfyui-workflows-file-action:hover { + background-color: var(--primary-bg); + color: var(--primary-fg); +} + +.comfyui-workflows-tree-file .comfyui-workflows-file-action-primary { + background-color: transparent; + color: var(--fg-color); + padding: 2px 4px; + margin: 0 -4px; +} + +.comfyui-workflows-file-action-favorite .mdi-star { + color: orange; +} + +/* View List */ +.comfyui-view-list-popup { + padding: 10px; + background-color: var(--content-bg); + color: var(--content-fg); + min-width: 170px; + min-height: 435px; + display: flex; + flex-direction: column; + align-items: center; + box-sizing: border-box; +} +.comfyui-view-list-popup h3 { + margin: 0 0 5px 0; +} +.comfyui-view-list-items { + width: 100%; + background: var(--comfy-menu-bg); + border-radius: 5px; + display: flex; + justify-content: center; + flex: auto; + align-items: center; + flex-direction: column; +} +.comfyui-view-list-items section { + max-height: 400px; + overflow: auto; + width: 100%; + display: grid; + grid-template-columns: auto auto auto; + align-items: center; + justify-content: center; + gap: 5px; + padding: 5px 0; +} +.comfyui-view-list-items section + section { + border-top: 1px solid var(--border-color); + margin-top: 10px; + padding-top: 5px; +} +.comfyui-view-list-items section h5 { + grid-column: 1 / 4; + text-align: center; + margin: 5px; +} +.comfyui-view-list-items span { + text-align: center; + padding: 0 2px; +} +.comfyui-view-list-popup header { + margin-bottom: 10px; + display: flex; + gap: 5px; +} +.comfyui-view-list-popup header .comfyui-button { + border: 1px solid transparent; +} +.comfyui-view-list-popup header .comfyui-button:not(:disabled):hover { + border: 1px solid var(--comfy-menu-bg); +} +/* Queue button */ +.comfyui-queue-button .comfyui-split-primary .comfyui-button { + padding-right: 12px; +} +.comfyui-queue-count { + margin-left: 5px; + border-radius: 10px; + background-color: rgb(8, 80, 153); + padding: 2px 4px; + font-size: 10px; + min-width: 1em; + display: inline-block; +} +/* Queue options*/ +.comfyui-queue-options { + padding: 10px; + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; + display: flex; + gap: 10px; +} + +.comfyui-queue-batch { + display: flex; + flex-direction: column; + border-right: 1px solid var(--comfy-menu-bg); + padding-right: 10px; + gap: 5px; +} + +.comfyui-queue-batch input { + width: 145px; +} + +.comfyui-queue-batch .comfyui-queue-batch-value { + width: 70px; +} + +.comfyui-queue-mode { + display: flex; + flex-direction: column; +} + +.comfyui-queue-mode span { + font-weight: bold; + margin-bottom: 2px; +} + +.comfyui-queue-mode label { + display: flex; + flex-direction: row-reverse; + justify-content: start; + gap: 5px; + padding: 2px 0; +} + +.comfyui-queue-mode label input { + padding: 0; + margin: 0; +} + +/** Send to workflow widget selection dialog */ +.comfy-widget-selection-dialog { + border: none; +} + +.comfy-widget-selection-dialog div { + color: var(--fg-color); + font-family: Arial, Helvetica, sans-serif; +} + +.comfy-widget-selection-dialog h2 { + margin-top: 0; +} + +.comfy-widget-selection-dialog section { + width: fit-content; + display: flex; + flex-direction: column; +} + +.comfy-widget-selection-item { + display: flex; + gap: 10px; + align-items: center; +} + +.comfy-widget-selection-item span { + margin-right: auto; +} + +.comfy-widget-selection-item span::before { + content: '#' attr(data-id); + opacity: 0.5; + margin-right: 5px; +} + +.comfy-modal .comfy-widget-selection-item button { + font-size: 1em; +} + +/***** Responsive *****/ +.lg.comfyui-menu .lt-lg-show { + display: none !important; +} +.comfyui-menu:not(.lg) .nlg-hide { + display: none !important; +} +/** Large screen */ +.lg.comfyui-menu>.comfyui-menu-mobile-collapse .comfyui-button span, +.lg.comfyui-menu>.comfyui-menu-mobile-collapse.comfyui-button span { + display: none; +} +.lg.comfyui-menu>.comfyui-menu-mobile-collapse .comfyui-popup .comfyui-button span { + display: unset; +} + +/** Non large screen */ +.lt-lg.comfyui-menu { + flex-wrap: wrap; +} + +.lt-lg.comfyui-menu > *:not(.comfyui-menu-mobile-collapse) { + order: 1; +} + +.lt-lg.comfyui-menu > .comfyui-menu-mobile-collapse { + order: 9999; + width: 100%; +} + +.comfyui-body-bottom .lt-lg.comfyui-menu > .comfyui-menu-mobile-collapse { + order: -1; +} + +.comfyui-body-bottom .lt-lg.comfyui-menu > .comfyui-menu-button { + top: unset; + bottom: 4px; +} + +.lt-lg.comfyui-menu > .comfyui-menu-mobile-collapse.comfyui-button-group { + flex-wrap: wrap; +} + +.lt-lg.comfyui-menu > .comfyui-menu-mobile-collapse .comfyui-button, +.lt-lg.comfyui-menu > .comfyui-menu-mobile-collapse.comfyui-button { + padding: 10px; +} +.lt-lg.comfyui-menu > .comfyui-menu-mobile-collapse .comfyui-button, +.lt-lg.comfyui-menu > .comfyui-menu-mobile-collapse .comfyui-button-wrapper { + width: 100%; +} + +.lt-lg.comfyui-menu > .comfyui-menu-mobile-collapse .comfyui-popup { + position: static; + background-color: var(--comfy-input-bg); + max-width: unset; + max-height: 50vh; + overflow: auto; +} + +.lt-lg.comfyui-menu:not(.expanded) > .comfyui-menu-mobile-collapse { + display: none; +} + +.lt-lg .comfyui-queue-button { + margin-right: 44px; +} + +.lt-lg .comfyui-menu-button { + position: absolute; + top: 4px; + right: 8px; +} + +.lt-lg.comfyui-menu > .comfyui-menu-mobile-collapse .comfyui-view-list-popup { + border-radius: 0; +} + +.lt-lg.comfyui-menu .comfyui-workflows-popup { + width: 100vw; +} + +/** Small */ +.lt-md .comfyui-workflows-button-inner { + width: unset !important; +} +.lt-md .comfyui-workflows-label { + display: none; +} + +/** Extra small */ +.lt-sm .comfyui-queue-button { + margin-right: 0; + width: 100%; +} +.lt-sm .comfyui-queue-button .comfyui-button { + justify-content: center; +} +.lt-sm .comfyui-interrupt-button { + margin-right: 45px; +} +.comfyui-body-bottom .lt-sm.comfyui-menu > .comfyui-menu-button{ + bottom: 41px; +} \ No newline at end of file diff --git a/web/scripts/ui/menu/queueButton.js b/web/scripts/ui/menu/queueButton.js new file mode 100644 index 000000000..608f4cc9b --- /dev/null +++ b/web/scripts/ui/menu/queueButton.js @@ -0,0 +1,93 @@ +// @ts-check + +import { ComfyButton } from "../components/button.js"; +import { $el } from "../../ui.js"; +import { api } from "../../api.js"; +import { ComfySplitButton } from "../components/splitButton.js"; +import { ComfyQueueOptions } from "./queueOptions.js"; +import { prop } from "../../utils.js"; + +export class ComfyQueueButton { + element = $el("div.comfyui-queue-button"); + #internalQueueSize = 0; + + queuePrompt = async (e) => { + this.#internalQueueSize += this.queueOptions.batchCount; + // Hold shift to queue front, event is undefined when auto-queue is enabled + await this.app.queuePrompt(e?.shiftKey ? -1 : 0, this.queueOptions.batchCount); + }; + + constructor(app) { + this.app = app; + this.queueSizeElement = $el("span.comfyui-queue-count", { + textContent: "?", + }); + + const queue = new ComfyButton({ + content: $el("div", [ + $el("span", { + textContent: "Queue", + }), + this.queueSizeElement, + ]), + icon: "play", + classList: "comfyui-button", + action: this.queuePrompt, + }); + + this.queueOptions = new ComfyQueueOptions(app); + + const btn = new ComfySplitButton( + { + primary: queue, + mode: "click", + position: "absolute", + horizontal: "right", + }, + this.queueOptions.element + ); + btn.element.classList.add("primary"); + this.element.append(btn.element); + + this.autoQueueMode = prop(this, "autoQueueMode", "", () => { + switch (this.autoQueueMode) { + case "instant": + queue.icon = "infinity"; + break; + case "change": + queue.icon = "auto-mode"; + break; + default: + queue.icon = "play"; + break; + } + }); + + this.queueOptions.addEventListener("autoQueueMode", (e) => (this.autoQueueMode = e["detail"])); + + api.addEventListener("graphChanged", () => { + if (this.autoQueueMode === "change") { + if (this.#internalQueueSize) { + this.graphHasChanged = true; + } else { + this.graphHasChanged = false; + this.queuePrompt(); + } + } + }); + + api.addEventListener("status", ({ detail }) => { + this.#internalQueueSize = detail?.exec_info?.queue_remaining; + if (this.#internalQueueSize != null) { + this.queueSizeElement.textContent = this.#internalQueueSize > 99 ? "99+" : this.#internalQueueSize + ""; + this.queueSizeElement.title = `${this.#internalQueueSize} prompts in queue`; + if (!this.#internalQueueSize && !app.lastExecutionError) { + if (this.autoQueueMode === "instant" || (this.autoQueueMode === "change" && this.graphHasChanged)) { + this.graphHasChanged = false; + this.queuePrompt(); + } + } + } + }); + } +} diff --git a/web/scripts/ui/menu/queueOptions.js b/web/scripts/ui/menu/queueOptions.js new file mode 100644 index 000000000..f3d34e74e --- /dev/null +++ b/web/scripts/ui/menu/queueOptions.js @@ -0,0 +1,77 @@ +// @ts-check + +import { $el } from "../../ui.js"; +import { prop } from "../../utils.js"; + +export class ComfyQueueOptions extends EventTarget { + element = $el("div.comfyui-queue-options"); + + constructor(app) { + super(); + this.app = app; + + this.batchCountInput = $el("input", { + className: "comfyui-queue-batch-value", + type: "number", + min: "1", + value: "1", + oninput: () => (this.batchCount = +this.batchCountInput.value), + }); + + this.batchCountRange = $el("input", { + type: "range", + min: "1", + max: "100", + value: "1", + oninput: () => (this.batchCount = +this.batchCountRange.value), + }); + + this.element.append( + $el("div.comfyui-queue-batch", [ + $el( + "label", + { + textContent: "Batch count: ", + }, + this.batchCountInput + ), + this.batchCountRange, + ]) + ); + + const createOption = (text, value, checked = false) => + $el( + "label", + { textContent: text }, + $el("input", { + type: "radio", + name: "AutoQueueMode", + checked, + value, + oninput: (e) => (this.autoQueueMode = e.target["value"]), + }) + ); + + this.autoQueueEl = $el("div.comfyui-queue-mode", [ + $el("span", "Auto Queue:"), + createOption("Disabled", "", true), + createOption("Instant", "instant"), + createOption("On Change", "change"), + ]); + + this.element.append(this.autoQueueEl); + + this.batchCount = prop(this, "batchCount", 1, () => { + this.batchCountInput.value = this.batchCount + ""; + this.batchCountRange.value = this.batchCount + ""; + }); + + this.autoQueueMode = prop(this, "autoQueueMode", "Disabled", () => { + this.dispatchEvent( + new CustomEvent("autoQueueMode", { + detail: this.autoQueueMode, + }) + ); + }); + } +} diff --git a/web/scripts/ui/menu/viewHistory.js b/web/scripts/ui/menu/viewHistory.js new file mode 100644 index 000000000..de6b343dc --- /dev/null +++ b/web/scripts/ui/menu/viewHistory.js @@ -0,0 +1,27 @@ +// @ts-check + +import { ComfyButton } from "../components/button.js"; +import { ComfyViewList, ComfyViewListButton } from "./viewList.js"; + +export class ComfyViewHistoryButton extends ComfyViewListButton { + constructor(app) { + super(app, { + button: new ComfyButton({ + content: "View History", + icon: "history", + tooltip: "View history", + classList: "comfyui-button comfyui-history-button", + }), + list: ComfyViewHistoryList, + mode: "History", + }); + } +} + +export class ComfyViewHistoryList extends ComfyViewList { + async loadItems() { + const items = await super.loadItems(); + items["History"].reverse(); + return items; + } +} diff --git a/web/scripts/ui/menu/viewList.js b/web/scripts/ui/menu/viewList.js new file mode 100644 index 000000000..693ca335c --- /dev/null +++ b/web/scripts/ui/menu/viewList.js @@ -0,0 +1,203 @@ +// @ts-check + +import { ComfyButton } from "../components/button.js"; +import { $el } from "../../ui.js"; +import { api } from "../../api.js"; +import { ComfyPopup } from "../components/popup.js"; + +export class ComfyViewListButton { + get open() { + return this.popup.open; + } + + set open(open) { + this.popup.open = open; + } + + constructor(app, { button, list, mode }) { + this.app = app; + this.button = button; + this.element = $el("div.comfyui-button-wrapper", this.button.element); + this.popup = new ComfyPopup({ + target: this.element, + container: this.element, + horizontal: "right", + }); + this.list = new (list ?? ComfyViewList)(app, mode, this.popup); + this.popup.children = [this.list.element]; + this.popup.addEventListener("open", () => { + this.list.update(); + }); + this.popup.addEventListener("close", () => { + this.list.close(); + }); + this.button.withPopup(this.popup); + + api.addEventListener("status", () => { + if (this.popup.open) { + this.popup.update(); + } + }); + } +} + +export class ComfyViewList { + popup; + + constructor(app, mode, popup) { + this.app = app; + this.mode = mode; + this.popup = popup; + this.type = mode.toLowerCase(); + + this.items = $el(`div.comfyui-${this.type}-items.comfyui-view-list-items`); + this.clear = new ComfyButton({ + icon: "cancel", + content: "Clear", + action: async () => { + this.showSpinner(false); + await api.clearItems(this.type); + await this.update(); + }, + }); + + this.refresh = new ComfyButton({ + icon: "refresh", + content: "Refresh", + action: async () => { + await this.update(false); + }, + }); + + this.element = $el(`div.comfyui-${this.type}-popup.comfyui-view-list-popup`, [ + $el("h3", mode), + $el("header", [this.clear.element, this.refresh.element]), + this.items, + ]); + + api.addEventListener("status", () => { + if (this.popup.open) { + this.update(); + } + }); + } + + async close() { + this.items.replaceChildren(); + } + + async update(resize = true) { + this.showSpinner(resize); + const res = await this.loadItems(); + let any = false; + + const names = Object.keys(res); + const sections = names + .map((section) => { + const items = res[section]; + if (items?.length) { + any = true; + } else { + return; + } + + const rows = []; + if (names.length > 1) { + rows.push($el("h5", section)); + } + rows.push(...items.flatMap((item) => this.createRow(item, section))); + return $el("section", rows); + }) + .filter(Boolean); + + if (any) { + this.items.replaceChildren(...sections); + } else { + this.items.replaceChildren($el("h5", "None")); + } + + this.popup.update(); + this.clear.enabled = this.refresh.enabled = true; + this.element.style.removeProperty("height"); + } + + showSpinner(resize = true) { + // if (!this.spinner) { + // this.spinner = createSpinner(); + // } + // if (!resize) { + // this.element.style.height = this.element.clientHeight + "px"; + // } + // this.clear.enabled = this.refresh.enabled = false; + // this.items.replaceChildren( + // $el( + // "div", + // { + // style: { + // fontSize: "18px", + // }, + // }, + // this.spinner + // ) + // ); + // this.popup.update(); + } + + async loadItems() { + return await api.getItems(this.type); + } + + getRow(item, section) { + return { + text: item.prompt[0] + "", + actions: [ + { + text: "Load", + action: async () => { + try { + await this.app.loadGraphData(item.prompt[3].extra_pnginfo.workflow); + if (item.outputs) { + this.app.nodeOutputs = item.outputs; + } + } catch (error) { + alert("Error loading workflow: " + error.message); + console.error(error); + } + }, + }, + { + text: "Delete", + action: async () => { + try { + await api.deleteItem(this.type, item.prompt[1]); + this.update(); + } catch (error) {} + }, + }, + ], + }; + } + + createRow = (item, section) => { + const row = this.getRow(item, section); + return [ + $el("span", row.text), + ...row.actions.map( + (a) => + new ComfyButton({ + content: a.text, + action: async (e, btn) => { + btn.enabled = false; + try { + await a.action(); + } catch (error) { + throw error; + } finally { + btn.enabled = true; + } + }, + }).element + ), + ]; + }; +} diff --git a/web/scripts/ui/menu/viewQueue.js b/web/scripts/ui/menu/viewQueue.js new file mode 100644 index 000000000..97d012986 --- /dev/null +++ b/web/scripts/ui/menu/viewQueue.js @@ -0,0 +1,55 @@ +// @ts-check + +import { ComfyButton } from "../components/button.js"; +import { ComfyViewList, ComfyViewListButton } from "./viewList.js"; +import { api } from "../../api.js"; + +export class ComfyViewQueueButton extends ComfyViewListButton { + constructor(app) { + super(app, { + button: new ComfyButton({ + content: "View Queue", + icon: "format-list-numbered", + tooltip: "View queue", + classList: "comfyui-button comfyui-queue-button", + }), + list: ComfyViewQueueList, + mode: "Queue", + }); + } +} + +export class ComfyViewQueueList extends ComfyViewList { + getRow = (item, section) => { + if (section !== "Running") { + return super.getRow(item, section); + } + return { + text: item.prompt[0] + "", + actions: [ + { + text: "Load", + action: async () => { + try { + await this.app.loadGraphData(item.prompt[3].extra_pnginfo.workflow); + if (item.outputs) { + this.app.nodeOutputs = item.outputs; + } + } catch (error) { + alert("Error loading workflow: " + error.message); + console.error(error); + } + }, + }, + { + text: "Cancel", + action: async () => { + try { + await api.interrupt(); + } catch (error) {} + }, + }, + ], + }; + } +} diff --git a/web/scripts/ui/menu/workflows.js b/web/scripts/ui/menu/workflows.js new file mode 100644 index 000000000..3b904fb4b --- /dev/null +++ b/web/scripts/ui/menu/workflows.js @@ -0,0 +1,770 @@ +// @ts-check + +import { ComfyButton } from "../components/button.js"; +import { prop, getStorageValue, setStorageValue } from "../../utils.js"; +import { $el } from "../../ui.js"; +import { api } from "../../api.js"; +import { ComfyPopup } from "../components/popup.js"; +import { createSpinner } from "../spinner.js"; +import { ComfyWorkflow, trimJsonExt } from "../../workflows.js"; +import { ComfyAsyncDialog } from "../components/asyncDialog.js"; + +export class ComfyWorkflowsMenu { + #first = true; + element = $el("div.comfyui-workflows"); + + get open() { + return this.popup.open; + } + + set open(open) { + this.popup.open = open; + } + + /** + * @param {import("../../app.js").ComfyApp} app + */ + constructor(app) { + this.app = app; + this.#bindEvents(); + + const classList = { + "comfyui-workflows-button": true, + "comfyui-button": true, + unsaved: getStorageValue("Comfy.PreviousWorkflowUnsaved") === "true", + running: false, + }; + this.buttonProgress = $el("div.comfyui-workflows-button-progress"); + this.workflowLabel = $el("span.comfyui-workflows-label", ""); + this.button = new ComfyButton({ + content: $el("div.comfyui-workflows-button-inner", [$el("i.mdi.mdi-graph"), this.workflowLabel, this.buttonProgress]), + icon: "chevron-down", + classList, + }); + + this.element.append(this.button.element); + + this.popup = new ComfyPopup({ target: this.element, classList: "comfyui-workflows-popup" }); + this.content = new ComfyWorkflowsContent(app, this.popup); + this.popup.children = [this.content.element]; + this.popup.addEventListener("change", () => { + this.button.icon = "chevron-" + (this.popup.open ? "up" : "down"); + }); + this.button.withPopup(this.popup); + + this.unsaved = prop(this, "unsaved", classList.unsaved, (v) => { + classList.unsaved = v; + this.button.classList = classList; + setStorageValue("Comfy.PreviousWorkflowUnsaved", v); + }); + } + + #updateProgress = () => { + const prompt = this.app.workflowManager.activePrompt; + let percent = 0; + if (this.app.workflowManager.activeWorkflow === prompt?.workflow) { + const total = Object.values(prompt.nodes); + const done = total.filter(Boolean); + percent = (done.length / total.length) * 100; + } + this.buttonProgress.style.width = percent + "%"; + }; + + #updateActive = () => { + const active = this.app.workflowManager.activeWorkflow; + this.button.tooltip = active.path; + this.workflowLabel.textContent = active.name; + this.unsaved = active.unsaved; + + if (this.#first) { + this.#first = false; + this.content.load(); + } + + this.#updateProgress(); + }; + + #bindEvents() { + this.app.workflowManager.addEventListener("changeWorkflow", this.#updateActive); + this.app.workflowManager.addEventListener("rename", this.#updateActive); + this.app.workflowManager.addEventListener("delete", this.#updateActive); + + this.app.workflowManager.addEventListener("save", () => { + this.unsaved = this.app.workflowManager.activeWorkflow.unsaved; + }); + + this.app.workflowManager.addEventListener("execute", (e) => { + this.#updateProgress(); + }); + + api.addEventListener("graphChanged", () => { + this.unsaved = true; + }); + } + + #getMenuOptions(callback) { + const menu = []; + const directories = new Map(); + for (const workflow of this.app.workflowManager.workflows || []) { + const path = workflow.pathParts; + if (!path) continue; + let parent = menu; + let currentPath = ""; + for (let i = 0; i < path.length - 1; i++) { + currentPath += "/" + path[i]; + let newParent = directories.get(currentPath); + if (!newParent) { + newParent = { + title: path[i], + has_submenu: true, + submenu: { + options: [], + }, + }; + parent.push(newParent); + newParent = newParent.submenu.options; + directories.set(currentPath, newParent); + } + parent = newParent; + } + parent.push({ + title: trimJsonExt(path[path.length - 1]), + callback: () => callback(workflow), + }); + } + return menu; + } + + #getFavoriteMenuOptions(callback) { + const menu = []; + for (const workflow of this.app.workflowManager.workflows || []) { + if (workflow.isFavorite) { + menu.push({ + title: "⭐ " + workflow.name, + callback: () => callback(workflow), + }); + } + } + return menu; + } + + /** + * @param {import("../../app.js").ComfyApp} app + */ + registerExtension(app) { + const self = this; + app.registerExtension({ + name: "Comfy.Workflows", + async beforeRegisterNodeDef(nodeType) { + function getImageWidget(node) { + const inputs = { ...node.constructor?.nodeData?.input?.required, ...node.constructor?.nodeData?.input?.optional }; + for (const input in inputs) { + if (inputs[input][0] === "IMAGEUPLOAD") { + const imageWidget = node.widgets.find((w) => w.name === (inputs[input]?.[1]?.widget ?? "image")); + if (imageWidget) return imageWidget; + } + } + } + + function setWidgetImage(node, widget, img) { + const url = new URL(img.src); + const filename = url.searchParams.get("filename"); + const subfolder = url.searchParams.get("subfolder"); + const type = url.searchParams.get("type"); + const imageId = `${subfolder ? subfolder + "/" : ""}${filename} [${type}]`; + widget.value = imageId; + node.imgs = [img]; + app.graph.setDirtyCanvas(true, true); + } + + /** + * @param {HTMLImageElement} img + * @param {ComfyWorkflow} workflow + */ + async function sendToWorkflow(img, workflow) { + const openWorkflow = app.workflowManager.openWorkflows.find((w) => w.path === workflow.path); + if (openWorkflow) { + workflow = openWorkflow; + } + + await workflow.load(); + let options = []; + const nodes = app.graph.computeExecutionOrder(false); + for (const node of nodes) { + const widget = getImageWidget(node); + if (widget == null) continue; + + if (node.title?.toLowerCase().includes("input")) { + options = [{ widget, node }]; + break; + } else { + options.push({ widget, node }); + } + } + + if (!options.length) { + alert("No image nodes have been found in this workflow!"); + return; + } else if (options.length > 1) { + const dialog = new WidgetSelectionDialog(options); + const res = await dialog.show(app); + if (!res) return; + options = [res]; + } + + setWidgetImage(options[0].node, options[0].widget, img); + } + + const getExtraMenuOptions = nodeType.prototype["getExtraMenuOptions"]; + nodeType.prototype["getExtraMenuOptions"] = function (_, options) { + const r = getExtraMenuOptions?.apply?.(this, arguments); + + const setting = app.ui.settings.getSettingValue("Comfy.UseNewMenu", false); + if (setting && setting != "Disabled") { + const t = /** @type { {imageIndex?: number, overIndex?: number, imgs: string[]} } */ /** @type {any} */ (this); + let img; + if (t.imageIndex != null) { + // An image is selected so select that + img = t.imgs?.[t.imageIndex]; + } else if (t.overIndex != null) { + // No image is selected but one is hovered + img = t.img?.s[t.overIndex]; + } + + if (img) { + let pos = options.findIndex((o) => o.content === "Save Image"); + if (pos === -1) { + pos = 0; + } else { + pos++; + } + + options.splice(pos, 0, { + content: "Send to workflow", + has_submenu: true, + submenu: { + options: [ + { + callback: () => sendToWorkflow(img, app.workflowManager.activeWorkflow), + title: "[Current workflow]", + }, + ...self.#getFavoriteMenuOptions(sendToWorkflow.bind(null, img)), + null, + ...self.#getMenuOptions(sendToWorkflow.bind(null, img)), + ], + }, + }); + } + } + + return r; + }; + }, + }); + } +} + +export class ComfyWorkflowsContent { + element = $el("div.comfyui-workflows-panel"); + treeState = {}; + treeFiles = {}; + /** @type { Map } */ + openFiles = new Map(); + /** @type {WorkflowElement} */ + activeElement = null; + + /** + * @param {import("../../app.js").ComfyApp} app + * @param {ComfyPopup} popup + */ + constructor(app, popup) { + this.app = app; + this.popup = popup; + this.actions = $el("div.comfyui-workflows-actions", [ + new ComfyButton({ + content: "Default", + icon: "file-code", + iconSize: 18, + classList: "comfyui-button primary", + tooltip: "Load default workflow", + action: () => { + popup.open = false; + app.loadGraphData(); + app.resetView(); + }, + }).element, + new ComfyButton({ + content: "Browse", + icon: "folder", + iconSize: 18, + tooltip: "Browse for an image or exported workflow", + action: () => { + popup.open = false; + app.ui.loadFile(); + }, + }).element, + new ComfyButton({ + content: "Blank", + icon: "plus-thick", + iconSize: 18, + tooltip: "Create a new blank workflow", + action: () => { + app.workflowManager.setWorkflow(null); + app.clean(); + app.graph.clear(); + app.workflowManager.activeWorkflow.track(); + popup.open = false; + }, + }).element, + ]); + + this.spinner = createSpinner(); + this.element.replaceChildren(this.actions, this.spinner); + + this.popup.addEventListener("open", () => this.load()); + this.popup.addEventListener("close", () => this.element.replaceChildren(this.actions, this.spinner)); + + this.app.workflowManager.addEventListener("favorite", (e) => { + const workflow = e["detail"]; + const button = this.treeFiles[workflow.path]?.primary; + if (!button) return; // Can happen when a workflow is renamed + button.icon = this.#getFavoriteIcon(workflow); + button.overIcon = this.#getFavoriteOverIcon(workflow); + this.updateFavorites(); + }); + + for (const e of ["save", "open", "close", "changeWorkflow"]) { + // TODO: dont be lazy and just update the specific element + app.workflowManager.addEventListener(e, () => this.updateOpen()); + } + this.app.workflowManager.addEventListener("rename", () => this.load()); + this.app.workflowManager.addEventListener("execute", (e) => this.#updateActive()); + } + + async load() { + await this.app.workflowManager.loadWorkflows(); + this.updateTree(); + this.updateFavorites(); + this.updateOpen(); + this.element.replaceChildren(this.actions, this.openElement, this.favoritesElement, this.treeElement); + } + + updateOpen() { + const current = this.openElement; + this.openFiles.clear(); + + this.openElement = $el("div.comfyui-workflows-open", [ + $el("h3", "Open"), + ...this.app.workflowManager.openWorkflows.map((w) => { + const wrapper = new WorkflowElement(this, w, { + primary: { element: $el("i.mdi.mdi-18px.mdi-progress-pencil") }, + buttons: [ + this.#getRenameButton(w), + new ComfyButton({ + icon: "close", + iconSize: 18, + classList: "comfyui-button comfyui-workflows-file-action", + tooltip: "Close workflow", + action: (e) => { + e.stopImmediatePropagation(); + this.app.workflowManager.closeWorkflow(w); + }, + }), + ], + }); + if (w.unsaved) { + wrapper.element.classList.add("unsaved"); + } + if(w === this.app.workflowManager.activeWorkflow) { + wrapper.element.classList.add("active"); + } + + this.openFiles.set(w, wrapper); + return wrapper.element; + }), + ]); + + this.#updateActive(); + current?.replaceWith(this.openElement); + } + + updateFavorites() { + const current = this.favoritesElement; + const favorites = [...this.app.workflowManager.workflows.filter((w) => w.isFavorite)]; + + this.favoritesElement = $el("div.comfyui-workflows-favorites", [ + $el("h3", "Favorites"), + ...favorites + .map((w) => { + return this.#getWorkflowElement(w).element; + }) + .filter(Boolean), + ]); + + current?.replaceWith(this.favoritesElement); + } + + filterTree() { + if (!this.filterText) { + this.treeRoot.classList.remove("filtered"); + // Unfilter whole tree + for (const item of Object.values(this.treeFiles)) { + item.element.parentElement.style.removeProperty("display"); + this.showTreeParents(item.element.parentElement); + } + return; + } + this.treeRoot.classList.add("filtered"); + const searchTerms = this.filterText.toLocaleLowerCase().split(" "); + for (const item of Object.values(this.treeFiles)) { + const parts = item.workflow.pathParts; + let termIndex = 0; + let valid = false; + for (const part of parts) { + let currentIndex = 0; + do { + currentIndex = part.indexOf(searchTerms[termIndex], currentIndex); + if (currentIndex > -1) currentIndex += searchTerms[termIndex].length; + } while (currentIndex !== -1 && ++termIndex < searchTerms.length); + + if (termIndex >= searchTerms.length) { + valid = true; + break; + } + } + if (valid) { + item.element.parentElement.style.removeProperty("display"); + this.showTreeParents(item.element.parentElement); + } else { + item.element.parentElement.style.display = "none"; + this.hideTreeParents(item.element.parentElement); + } + } + } + + hideTreeParents(element) { + // Hide all parents if no children are visible + if (element.parentElement?.classList.contains("comfyui-workflows-tree") === false) { + for (let i = 1; i < element.parentElement.children.length; i++) { + const c = element.parentElement.children[i]; + if (c.style.display !== "none") { + return; + } + } + element.parentElement.style.display = "none"; + this.hideTreeParents(element.parentElement); + } + } + + showTreeParents(element) { + if (element.parentElement?.classList.contains("comfyui-workflows-tree") === false) { + element.parentElement.style.removeProperty("display"); + this.showTreeParents(element.parentElement); + } + } + + updateTree() { + const current = this.treeElement; + const nodes = {}; + let typingTimeout; + + this.treeFiles = {}; + this.treeRoot = $el("ul.comfyui-workflows-tree"); + this.treeElement = $el("section", [ + $el("header", [ + $el("h3", "Browse"), + $el("div.comfy-ui-workflows-search", [ + $el("i.mdi.mdi-18px.mdi-magnify"), + $el("input", { + placeholder: "Search", + value: this.filterText ?? "", + oninput: (e) => { + this.filterText = e.target["value"]?.trim(); + clearTimeout(typingTimeout); + typingTimeout = setTimeout(() => this.filterTree(), 250); + }, + }), + ]), + ]), + this.treeRoot, + ]); + + for (const workflow of this.app.workflowManager.workflows) { + if (!workflow.pathParts) continue; + + let currentPath = ""; + let currentRoot = this.treeRoot; + + for (let i = 0; i < workflow.pathParts.length; i++) { + currentPath += (currentPath ? "\\" : "") + workflow.pathParts[i]; + const parentNode = nodes[currentPath] ?? this.#createNode(currentPath, workflow, i, currentRoot); + + nodes[currentPath] = parentNode; + currentRoot = parentNode; + } + } + + current?.replaceWith(this.treeElement); + this.filterTree(); + } + + #expandNode(el, workflow, thisPath, i) { + const expanded = !el.classList.toggle("closed"); + if (expanded) { + let c = ""; + for (let j = 0; j <= i; j++) { + c += (c ? "\\" : "") + workflow.pathParts[j]; + this.treeState[c] = true; + } + } else { + let c = thisPath; + for (let j = i + 1; j < workflow.pathParts.length; j++) { + c += (c ? "\\" : "") + workflow.pathParts[j]; + delete this.treeState[c]; + } + delete this.treeState[thisPath]; + } + } + + #updateActive() { + this.#removeActive(); + + const active = this.app.workflowManager.activePrompt; + if (!active?.workflow) return; + + const open = this.openFiles.get(active.workflow); + if (!open) return; + + this.activeElement = open; + + const total = Object.values(active.nodes); + const done = total.filter(Boolean); + const percent = done.length / total.length; + open.element.classList.add("running"); + open.element.style.setProperty("--progress", percent * 100 + "%"); + open.primary.element.classList.remove("mdi-progress-pencil"); + open.primary.element.classList.add("mdi-play"); + } + + #removeActive() { + if (!this.activeElement) return; + this.activeElement.element.classList.remove("running"); + this.activeElement.element.style.removeProperty("--progress"); + this.activeElement.primary.element.classList.add("mdi-progress-pencil"); + this.activeElement.primary.element.classList.remove("mdi-play"); + } + + /** @param {ComfyWorkflow} workflow */ + #getFavoriteIcon(workflow) { + return workflow.isFavorite ? "star" : "file-outline"; + } + + /** @param {ComfyWorkflow} workflow */ + #getFavoriteOverIcon(workflow) { + return workflow.isFavorite ? "star-off" : "star-outline"; + } + + /** @param {ComfyWorkflow} workflow */ + #getFavoriteTooltip(workflow) { + return workflow.isFavorite ? "Remove this workflow from your favorites" : "Add this workflow to your favorites"; + } + + /** @param {ComfyWorkflow} workflow */ + #getFavoriteButton(workflow, primary) { + return new ComfyButton({ + icon: this.#getFavoriteIcon(workflow), + overIcon: this.#getFavoriteOverIcon(workflow), + iconSize: 18, + classList: "comfyui-button comfyui-workflows-file-action-favorite" + (primary ? " comfyui-workflows-file-action-primary" : ""), + tooltip: this.#getFavoriteTooltip(workflow), + action: (e) => { + e.stopImmediatePropagation(); + workflow.favorite(!workflow.isFavorite); + }, + }); + } + + /** @param {ComfyWorkflow} workflow */ + #getDeleteButton(workflow) { + const deleteButton = new ComfyButton({ + icon: "delete", + tooltip: "Delete this workflow", + classList: "comfyui-button comfyui-workflows-file-action", + iconSize: 18, + action: async (e, btn) => { + e.stopImmediatePropagation(); + + if (btn.icon === "delete-empty") { + btn.enabled = false; + await workflow.delete(); + await this.load(); + } else { + btn.icon = "delete-empty"; + btn.element.style.background = "red"; + } + }, + }); + deleteButton.element.addEventListener("mouseleave", () => { + deleteButton.icon = "delete"; + deleteButton.element.style.removeProperty("background"); + }); + return deleteButton; + } + + /** @param {ComfyWorkflow} workflow */ + #getInsertButton(workflow) { + return new ComfyButton({ + icon: "file-move-outline", + iconSize: 18, + tooltip: "Insert this workflow into the current workflow", + classList: "comfyui-button comfyui-workflows-file-action", + action: (e) => { + if (!this.app.shiftDown) { + this.popup.open = false; + } + e.stopImmediatePropagation(); + if (!this.app.shiftDown) { + this.popup.open = false; + } + workflow.insert(); + }, + }); + } + + /** @param {ComfyWorkflow} workflow */ + #getRenameButton(workflow) { + return new ComfyButton({ + icon: "pencil", + tooltip: workflow.path ? "Rename this workflow" : "This workflow can't be renamed as it hasn't been saved.", + classList: "comfyui-button comfyui-workflows-file-action", + iconSize: 18, + enabled: !!workflow.path, + action: async (e) => { + e.stopImmediatePropagation(); + const newName = prompt("Enter new name", workflow.path); + if (newName) { + await workflow.rename(newName); + } + }, + }); + } + + /** @param {ComfyWorkflow} workflow */ + #getWorkflowElement(workflow) { + return new WorkflowElement(this, workflow, { + primary: this.#getFavoriteButton(workflow, true), + buttons: [this.#getInsertButton(workflow), this.#getRenameButton(workflow), this.#getDeleteButton(workflow)], + }); + } + + /** @param {ComfyWorkflow} workflow */ + #createLeafNode(workflow) { + const fileNode = this.#getWorkflowElement(workflow); + this.treeFiles[workflow.path] = fileNode; + return fileNode; + } + + #createNode(currentPath, workflow, i, currentRoot) { + const part = workflow.pathParts[i]; + + const parentNode = $el("ul" + (this.treeState[currentPath] ? "" : ".closed"), { + $: (el) => { + el.onclick = (e) => { + this.#expandNode(el, workflow, currentPath, i); + e.stopImmediatePropagation(); + }; + }, + }); + currentRoot.append(parentNode); + + // Create a node for the current part and an inner UL for its children if it isnt a leaf node + const leaf = i === workflow.pathParts.length - 1; + let nodeElement; + if (leaf) { + nodeElement = this.#createLeafNode(workflow).element; + } else { + nodeElement = $el("li", [$el("i.mdi.mdi-18px.mdi-folder"), $el("span", part)]); + } + parentNode.append(nodeElement); + return parentNode; + } +} + +class WorkflowElement { + /** + * @param { ComfyWorkflowsContent } parent + * @param { ComfyWorkflow } workflow + */ + constructor(parent, workflow, { tagName = "li", primary, buttons }) { + this.parent = parent; + this.workflow = workflow; + this.primary = primary; + this.buttons = buttons; + + this.element = $el( + tagName + ".comfyui-workflows-tree-file", + { + onclick: () => { + workflow.load(); + this.parent.popup.open = false; + }, + title: this.workflow.path, + }, + [this.primary?.element, $el("span", workflow.name), ...buttons.map((b) => b.element)] + ); + } +} + +class WidgetSelectionDialog extends ComfyAsyncDialog { + #options; + + /** + * @param {Array<{widget: {name: string}, node: {pos: [number, number], title: string, id: string, type: string}}>} options + */ + constructor(options) { + super(); + this.#options = options; + } + + show(app) { + this.element.classList.add("comfy-widget-selection-dialog"); + return super.show( + $el("div", [ + $el("h2", "Select image target"), + $el( + "p", + "This workflow has multiple image loader nodes, you can rename a node to include 'input' in the title for it to be automatically selected, or select one below." + ), + $el( + "section", + this.#options.map((opt) => { + return $el("div.comfy-widget-selection-item", [ + $el("span", { dataset: { id: opt.node.id } }, `${opt.node.title ?? opt.node.type} ${opt.widget.name}`), + $el( + "button.comfyui-button", + { + onclick: () => { + app.canvas.ds.offset[0] = -opt.node.pos[0] + 50; + app.canvas.ds.offset[1] = -opt.node.pos[1] + 50; + app.canvas.selectNode(opt.node); + app.graph.setDirtyCanvas(true, true); + }, + }, + "Show" + ), + $el( + "button.comfyui-button.primary", + { + onclick: () => { + this.close(opt); + }, + }, + "Select" + ), + ]); + }) + ), + ]) + ); + } +} \ No newline at end of file diff --git a/web/scripts/ui/settings.js b/web/scripts/ui/settings.js index 9e9d13af0..819e4e7d6 100644 --- a/web/scripts/ui/settings.js +++ b/web/scripts/ui/settings.js @@ -47,6 +47,17 @@ export class ComfySettingsDialog extends ComfyDialog { return Object.values(this.settingsLookup); } + #dispatchChange(id, value, oldValue) { + this.dispatchEvent( + new CustomEvent(id + ".change", { + detail: { + value, + oldValue + }, + }) + ); + } + async load() { if (this.app.storageLocation === "browser") { this.settingsValues = localStorage; @@ -56,7 +67,9 @@ export class ComfySettingsDialog extends ComfyDialog { // Trigger onChange for any settings added before load for (const id in this.settingsLookup) { - this.settingsLookup[id].onChange?.(this.settingsValues[this.getId(id)]); + const value = this.settingsValues[this.getId(id)]; + this.settingsLookup[id].onChange?.(value); + this.#dispatchChange(id, value); } } @@ -90,6 +103,7 @@ export class ComfySettingsDialog extends ComfyDialog { if (id in this.settingsLookup) { this.settingsLookup[id].onChange?.(value, oldValue); } + this.#dispatchChange(id, value, oldValue); await api.storeSetting(id, value); } @@ -136,6 +150,8 @@ export class ComfySettingsDialog extends ComfyDialog { onChange, name, render: () => { + if (type === "hidden") return; + const setter = (v) => { if (onChange) { onChange(v, value); @@ -310,7 +326,7 @@ export class ComfySettingsDialog extends ComfyDialog { }, [$el("th"), $el("th", { style: { width: "33%" } })] ), - ...this.settings.sort((a, b) => a.name.localeCompare(b.name)).map((s) => s.render()) + ...this.settings.sort((a, b) => a.name.localeCompare(b.name)).map((s) => s.render()).filter(Boolean) ); this.element.showModal(); } diff --git a/web/scripts/ui/utils.js b/web/scripts/ui/utils.js new file mode 100644 index 000000000..e37d8b41e --- /dev/null +++ b/web/scripts/ui/utils.js @@ -0,0 +1,56 @@ +/** + * @typedef { string | string[] | Record } ClassList + */ + +/** + * @param { HTMLElement } element + * @param { ClassList } classList + * @param { string[] } requiredClasses + */ +export function applyClasses(element, classList, ...requiredClasses) { + classList ??= ""; + + let str; + if (typeof classList === "string") { + str = classList; + } else if (classList instanceof Array) { + str = classList.join(" "); + } else { + str = Object.entries(classList).reduce((p, c) => { + if (c[1]) { + p += (p.length ? " " : "") + c[0]; + } + return p; + }, ""); + } + element.className = str; + if (requiredClasses) { + element.classList.add(...requiredClasses); + } +} + +/** + * @param { HTMLElement } element + * @param { { onHide?: (el: HTMLElement) => void, onShow?: (el: HTMLElement, value) => void } } [param1] + * @returns + */ +export function toggleElement(element, { onHide, onShow } = {}) { + let placeholder; + let hidden; + return (value) => { + if (value) { + if (hidden) { + hidden = false; + placeholder.replaceWith(element); + } + onShow?.(element, value); + } else { + if (!placeholder) { + placeholder = document.createComment(""); + } + hidden = true; + element.replaceWith(placeholder); + onHide?.(element); + } + }; +} diff --git a/web/scripts/utils.js b/web/scripts/utils.js index 01b988462..cda7600f6 100644 --- a/web/scripts/utils.js +++ b/web/scripts/utils.js @@ -1,4 +1,5 @@ import { $el } from "./ui.js"; +import { api } from "./api.js"; // Simple date formatter const parts = { @@ -25,6 +26,19 @@ function formatDate(text, date) { }); } + +export function clone(obj) { + try { + if (typeof structuredClone !== "undefined") { + return structuredClone(obj); + } + } catch (error) { + // structuredClone is stricter than using JSON.parse/stringify so fallback to that + } + + return JSON.parse(JSON.stringify(obj)); +} + export function applyTextReplacements(app, value) { return value.replace(/%([^%]+)%/g, function (match, text) { const split = text.split("."); @@ -86,3 +100,57 @@ export async function addStylesheet(urlOrFile, relativeTo) { }); }); } + +/** + * @param { string } filename + * @param { Blob } blob + */ +export function downloadBlob(filename, blob) { + const url = URL.createObjectURL(blob); + const a = $el("a", { + href: url, + download: filename, + style: { display: "none" }, + parent: document.body, + }); + a.click(); + setTimeout(function () { + a.remove(); + window.URL.revokeObjectURL(url); + }, 0); +} + +/** + * @template T + * @param {string} name + * @param {T} [defaultValue] + * @param {(currentValue: any, previousValue: any)=>void} [onChanged] + * @returns {T} + */ +export function prop(target, name, defaultValue, onChanged) { + let currentValue; + Object.defineProperty(target, name, { + get() { + return currentValue; + }, + set(newValue) { + const prevValue = currentValue; + currentValue = newValue; + onChanged?.(currentValue, prevValue, target, name); + }, + }); + return defaultValue; +} + +export function getStorageValue(id) { + const clientId = api.clientId ?? api.initialClientId; + return (clientId && sessionStorage.getItem(`${id}:${clientId}`)) ?? localStorage.getItem(id); +} + +export function setStorageValue(id, value) { + const clientId = api.clientId ?? api.initialClientId; + if (clientId) { + sessionStorage.setItem(`${id}:${clientId}`, value); + } + localStorage.setItem(id, value); +} \ No newline at end of file diff --git a/web/scripts/workflows.js b/web/scripts/workflows.js new file mode 100644 index 000000000..d38b6f5fc --- /dev/null +++ b/web/scripts/workflows.js @@ -0,0 +1,450 @@ +// @ts-check + +import { api } from "./api.js"; +import { ChangeTracker } from "./changeTracker.js"; +import { ComfyAsyncDialog } from "./ui/components/asyncDialog.js"; +import { getStorageValue, setStorageValue } from "./utils.js"; + +function appendJsonExt(path) { + if (!path.toLowerCase().endsWith(".json")) { + path += ".json"; + } + return path; +} + +export function trimJsonExt(path) { + return path?.replace(/\.json$/, ""); +} + +export class ComfyWorkflowManager extends EventTarget { + /** @type {string | null} */ + #activePromptId = null; + #unsavedCount = 0; + #activeWorkflow; + + /** @type {Record} */ + workflowLookup = {}; + /** @type {Array} */ + workflows = []; + /** @type {Array} */ + openWorkflows = []; + /** @type {Record}>} */ + queuedPrompts = {}; + + get activeWorkflow() { + return this.#activeWorkflow ?? this.openWorkflows[0]; + } + + get activePromptId() { + return this.#activePromptId; + } + + get activePrompt() { + return this.queuedPrompts[this.#activePromptId]; + } + + /** + * @param {import("./app.js").ComfyApp} app + */ + constructor(app) { + super(); + this.app = app; + ChangeTracker.init(app); + + this.#bindExecutionEvents(); + } + + #bindExecutionEvents() { + // TODO: on reload, set active prompt based on the latest ws message + + const emit = () => this.dispatchEvent(new CustomEvent("execute", { detail: this.activePrompt })); + let executing = null; + api.addEventListener("execution_start", (e) => { + this.#activePromptId = e.detail.prompt_id; + + // This event can fire before the event is stored, so put a placeholder + this.queuedPrompts[this.#activePromptId] ??= { nodes: {} }; + emit(); + }); + api.addEventListener("execution_cached", (e) => { + if (!this.activePrompt) return; + for (const n of e.detail.nodes) { + this.activePrompt.nodes[n] = true; + } + emit(); + }); + api.addEventListener("executed", (e) => { + if (!this.activePrompt) return; + this.activePrompt.nodes[e.detail.node] = true; + emit(); + }); + api.addEventListener("executing", (e) => { + if (!this.activePrompt) return; + + if (executing) { + // Seems sometimes nodes that are cached fire executing but not executed + this.activePrompt.nodes[executing] = true; + } + executing = e.detail; + if (!executing) { + delete this.queuedPrompts[this.#activePromptId]; + this.#activePromptId = null; + } + emit(); + }); + } + + async loadWorkflows() { + try { + let favorites; + const resp = await api.getUserData("workflows/.index.json"); + let info; + if (resp.status === 200) { + info = await resp.json(); + favorites = new Set(info?.favorites ?? []); + } else { + favorites = new Set(); + } + + const workflows = (await api.listUserData("workflows", true, true)).map((w) => { + let workflow = this.workflowLookup[w[0]]; + if (!workflow) { + workflow = new ComfyWorkflow(this, w[0], w.slice(1), favorites.has(w[0])); + this.workflowLookup[workflow.path] = workflow; + } + return workflow; + }); + + this.workflows = workflows; + } catch (error) { + alert("Error loading workflows: " + (error.message ?? error)); + this.workflows = []; + } + } + + async saveWorkflowMetadata() { + await api.storeUserData("workflows/.index.json", { + favorites: [...this.workflows.filter((w) => w.isFavorite).map((w) => w.path)], + }); + } + + /** + * @param {string | ComfyWorkflow | null} workflow + */ + setWorkflow(workflow) { + if (workflow && typeof workflow === "string") { + // Selected by path, i.e. on reload of last workflow + const found = this.workflows.find((w) => w.path === workflow); + if (found) { + workflow = found; + workflow.unsaved = !workflow || getStorageValue("Comfy.PreviousWorkflowUnsaved") === "true"; + } + } + + if (!(workflow instanceof ComfyWorkflow)) { + // Still not found, either reloading a deleted workflow or blank + workflow = new ComfyWorkflow(this, workflow || "Unsaved Workflow" + (this.#unsavedCount++ ? ` (${this.#unsavedCount})` : "")); + } + + const index = this.openWorkflows.indexOf(workflow); + if (index === -1) { + // Opening a new workflow + this.openWorkflows.push(workflow); + } + + this.#activeWorkflow = workflow; + + setStorageValue("Comfy.PreviousWorkflow", this.activeWorkflow.path ?? ""); + this.dispatchEvent(new CustomEvent("changeWorkflow")); + } + + storePrompt({ nodes, id }) { + this.queuedPrompts[id] ??= {}; + this.queuedPrompts[id].nodes = { + ...nodes.reduce((p, n) => { + p[n] = false; + return p; + }, {}), + ...this.queuedPrompts[id].nodes, + }; + this.queuedPrompts[id].workflow = this.activeWorkflow; + } + + /** + * @param {ComfyWorkflow} workflow + */ + async closeWorkflow(workflow, warnIfUnsaved = true) { + if (!workflow.isOpen) { + return true; + } + if (workflow.unsaved && warnIfUnsaved) { + const res = await ComfyAsyncDialog.prompt({ + title: "Save Changes?", + message: `Do you want to save changes to "${workflow.path ?? workflow.name}" before closing?`, + actions: ["Yes", "No", "Cancel"], + }); + if (res === "Yes") { + const active = this.activeWorkflow; + if (active !== workflow) { + // We need to switch to the workflow to save it + await workflow.load(); + } + + if (!(await workflow.save())) { + // Save was canceled, restore the previous workflow + if (active !== workflow) { + await active.load(); + } + return; + } + } else if (res === "Cancel") { + return; + } + } + workflow.changeTracker = null; + this.openWorkflows.splice(this.openWorkflows.indexOf(workflow), 1); + if (this.openWorkflows.length) { + this.#activeWorkflow = this.openWorkflows[0]; + await this.#activeWorkflow.load(); + } else { + // Load default + await this.app.loadGraphData(); + } + } +} + +export class ComfyWorkflow { + #name; + #path; + #pathParts; + #isFavorite = false; + /** @type {ChangeTracker | null} */ + changeTracker = null; + unsaved = false; + + get name() { + return this.#name; + } + + get path() { + return this.#path; + } + + get pathParts() { + return this.#pathParts; + } + + get isFavorite() { + return this.#isFavorite; + } + + get isOpen() { + return !!this.changeTracker; + } + + /** + * @overload + * @param {ComfyWorkflowManager} manager + * @param {string} path + */ + /** + * @overload + * @param {ComfyWorkflowManager} manager + * @param {string} path + * @param {string[]} pathParts + * @param {boolean} isFavorite + */ + /** + * @param {ComfyWorkflowManager} manager + * @param {string} path + * @param {string[]} [pathParts] + * @param {boolean} [isFavorite] + */ + constructor(manager, path, pathParts, isFavorite) { + this.manager = manager; + if (pathParts) { + this.#updatePath(path, pathParts); + this.#isFavorite = isFavorite; + } else { + this.#name = path; + this.unsaved = true; + } + } + + /** + * @param {string} path + * @param {string[]} [pathParts] + */ + #updatePath(path, pathParts) { + this.#path = path; + + if (!pathParts) { + if (!path.includes("\\")) { + pathParts = path.split("/"); + } else { + pathParts = path.split("\\"); + } + } + + this.#pathParts = pathParts; + this.#name = trimJsonExt(pathParts[pathParts.length - 1]); + } + + async getWorkflowData() { + const resp = await api.getUserData("workflows/" + this.path); + if (resp.status !== 200) { + alert(`Error loading workflow file '${this.path}': ${resp.status} ${resp.statusText}`); + return; + } + return await resp.json(); + } + + load = async () => { + if (this.isOpen) { + await this.manager.app.loadGraphData(this.changeTracker.activeState, true, true, this); + } else { + const data = await this.getWorkflowData(); + if (!data) return; + await this.manager.app.loadGraphData(data, true, true, this); + } + }; + + async save(saveAs = false) { + if (!this.path || saveAs) { + return !!(await this.#save(null, false)); + } else { + return !!(await this.#save(this.path, true)); + } + } + + /** + * @param {boolean} value + */ + async favorite(value) { + try { + if (this.#isFavorite === value) return; + this.#isFavorite = value; + await this.manager.saveWorkflowMetadata(); + this.manager.dispatchEvent(new CustomEvent("favorite", { detail: this })); + } catch (error) { + alert("Error favoriting workflow " + this.path + "\n" + (error.message ?? error)); + } + } + + /** + * @param {string} path + */ + async rename(path) { + path = appendJsonExt(path); + let resp = await api.moveUserData("workflows/" + this.path, "workflows/" + path); + + if (resp.status === 409) { + if (!confirm(`Workflow '${path}' already exists, do you want to overwrite it?`)) return resp; + resp = await api.moveUserData("workflows/" + this.path, "workflows/" + path, { overwrite: true }); + } + + if (resp.status !== 200) { + alert(`Error renaming workflow file '${this.path}': ${resp.status} ${resp.statusText}`); + return; + } + + const isFav = this.isFavorite; + if (isFav) { + await this.favorite(false); + } + path = (await resp.json()).substring("workflows/".length); + this.#updatePath(path, null); + if (isFav) { + await this.favorite(true); + } + this.manager.dispatchEvent(new CustomEvent("rename", { detail: this })); + setStorageValue("Comfy.PreviousWorkflow", this.path ?? ""); + } + + async insert() { + const data = await this.getWorkflowData(); + if (!data) return; + + const old = localStorage.getItem("litegrapheditor_clipboard"); + const graph = new LGraph(data); + const canvas = new LGraphCanvas(null, graph, { skip_events: true, skip_render: true }); + canvas.selectNodes(); + canvas.copyToClipboard(); + this.manager.app.canvas.pasteFromClipboard(); + localStorage.setItem("litegrapheditor_clipboard", old); + } + + async delete() { + // TODO: fix delete of current workflow - should mark workflow as unsaved and when saving use old name by default + + try { + if (this.isFavorite) { + await this.favorite(false); + } + await api.deleteUserData("workflows/" + this.path); + this.unsaved = true; + this.#path = null; + this.#pathParts = null; + this.manager.workflows.splice(this.manager.workflows.indexOf(this), 1); + this.manager.dispatchEvent(new CustomEvent("delete", { detail: this })); + } catch (error) { + alert(`Error deleting workflow: ${error.message || error}`); + } + } + + track() { + if (this.changeTracker) { + this.changeTracker.restore(); + } else { + this.changeTracker = new ChangeTracker(this); + } + } + + /** + * @param {string|null} path + * @param {boolean} overwrite + */ + async #save(path, overwrite) { + if (!path) { + path = prompt("Save workflow as:", trimJsonExt(this.path) ?? this.name ?? "workflow"); + if (!path) return; + } + + path = appendJsonExt(path); + + const p = await this.manager.app.graphToPrompt(); + const json = JSON.stringify(p.workflow, null, 2); + let resp = await api.storeUserData("workflows/" + path, json, { stringify: false, throwOnError: false, overwrite }); + if (resp.status === 409) { + if (!confirm(`Workflow '${path}' already exists, do you want to overwrite it?`)) return; + resp = await api.storeUserData("workflows/" + path, json, { stringify: false }); + } + + if (resp.status !== 200) { + alert(`Error saving workflow '${this.path}': ${resp.status} ${resp.statusText}`); + return; + } + + path = (await resp.json()).substring("workflows/".length); + + if (!this.path) { + // Saved new workflow, patch this instance + this.#updatePath(path, null); + await this.manager.loadWorkflows(); + this.unsaved = false; + this.manager.dispatchEvent(new CustomEvent("rename", { detail: this })); + setStorageValue("Comfy.PreviousWorkflow", this.path ?? ""); + } else if (path !== this.path) { + // Saved as, open the new copy + await this.manager.loadWorkflows(); + const workflow = this.manager.workflowLookup[path]; + await workflow.load(); + } else { + // Normal save + this.unsaved = false; + this.manager.dispatchEvent(new CustomEvent("save", { detail: this })); + } + + return true; + } +} diff --git a/web/style.css b/web/style.css index cf7a8b9ea..8ef1d0dd1 100644 --- a/web/style.css +++ b/web/style.css @@ -1,3 +1,5 @@ +@import url("scripts/ui/menu/menu.css"); + :root { --fg-color: #000; --bg-color: #fff; @@ -10,12 +12,24 @@ --border-color: #4e4e4e; --tr-even-bg-color: #222; --tr-odd-bg-color: #353535; + --primary-bg: #236692; + --primary-fg: #ffffff; + --primary-hover-bg: #3485bb; + --primary-hover-fg: #ffffff; + --content-bg: #e0e0e0; + --content-fg: #000; + --content-hover-bg: #adadad; + --content-hover-fg: #000; } @media (prefers-color-scheme: dark) { :root { --fg-color: #fff; --bg-color: #202020; + --content-bg: #4e4e4e; + --content-fg: #fff; + --content-hover-bg: #222; + --content-hover-fg: #fff; } } @@ -26,11 +40,46 @@ body { overflow: hidden; background-color: var(--bg-color); color: var(--fg-color); + grid-template-columns: auto 1fr auto; + grid-template-rows: auto 1fr auto; + min-height: -webkit-fill-available; + max-height: -webkit-fill-available; + min-width: -webkit-fill-available; + max-width: -webkit-fill-available; +} + +.comfyui-body-top { + order: -5; + grid-column: 1/-1; + z-index: 10; + display: flex; + flex-direction: column; +} + +.comfyui-body-left { + order: -4; + z-index: 10; + display: flex; } #graph-canvas { width: 100%; height: 100%; + order: -3; +} + +.comfyui-body-right { + order: -2; + z-index: 10; + display: flex; +} + +.comfyui-body-bottom { + order: -1; + grid-column: 1/-1; + z-index: 10; + display: flex; + flex-direction: column; } .comfy-multiline-input { @@ -364,6 +413,41 @@ dialog::backdrop { background: rgba(0, 0, 0, 0.5); } +.comfy-dialog.comfyui-dialog.comfy-modal { + top: 0; + left: 0; + right: 0; + bottom: 0; + transform: none; +} + +.comfy-dialog.comfy-modal { + font-family: Arial, sans-serif; + border-color: var(--bg-color); + box-shadow: none; + border: 2px solid var(--border-color); +} + +.comfy-dialog .comfy-modal-content { + flex-direction: row; + flex-wrap: wrap; + gap: 10px; + color: var(--fg-color); +} + +.comfy-dialog .comfy-modal-content h3 { + margin-top: 0; +} + +.comfy-dialog .comfy-modal-content > p { + width: 100%; +} + +.comfy-dialog .comfy-modal-content > .comfyui-button { + flex: 1; + justify-content: center; +} + #comfy-settings-dialog { padding: 0; width: 41rem; @@ -557,3 +641,7 @@ dialog::backdrop { border-top: none; } } + +audio.comfy-audio.empty-audio-widget { + display: none; +} diff --git a/web/types/comfy.d.ts b/web/types/comfy.d.ts index f7129b555..9a338b349 100644 --- a/web/types/comfy.d.ts +++ b/web/types/comfy.d.ts @@ -10,24 +10,24 @@ export interface ComfyExtension { * Allows any initialisation, e.g. loading resources. Called after the canvas is created but before nodes are added * @param app The ComfyUI app instance */ - init(app: ComfyApp): Promise; + init?(app: ComfyApp): Promise; /** * Allows any additonal setup, called after the application is fully set up and running * @param app The ComfyUI app instance */ - setup(app: ComfyApp): Promise; + setup?(app: ComfyApp): Promise; /** * Called before nodes are registered with the graph * @param defs The collection of node definitions, add custom ones or edit existing ones * @param app The ComfyUI app instance */ - addCustomNodeDefs(defs: Record, app: ComfyApp): Promise; + addCustomNodeDefs?(defs: Record, app: ComfyApp): Promise; /** * Allows the extension to add custom widgets * @param app The ComfyUI app instance * @returns An array of {[widget name]: widget data} */ - getCustomWidgets( + getCustomWidgets?( app: ComfyApp ): Promise< Record { widget?: IWidget; minWidth?: number; minHeight?: number }> @@ -38,12 +38,12 @@ export interface ComfyExtension { * @param nodeData The original node object info config object * @param app The ComfyUI app instance */ - beforeRegisterNodeDef(nodeType: typeof LGraphNode, nodeData: ComfyObjectInfo, app: ComfyApp): Promise; + beforeRegisterNodeDef?(nodeType: typeof LGraphNode, nodeData: ComfyObjectInfo, app: ComfyApp): Promise; /** * Allows the extension to register additional nodes with LGraph after standard nodes are added * @param app The ComfyUI app instance */ - registerCustomNodes(app: ComfyApp): Promise; + registerCustomNodes?(app: ComfyApp): Promise; /** * Allows the extension to modify a node that has been reloaded onto the graph. * If you break something in the backend and want to patch workflows in the frontend @@ -51,13 +51,13 @@ export interface ComfyExtension { * @param node The node that has been loaded * @param app The ComfyUI app instance */ - loadedGraphNode(node: LGraphNode, app: ComfyApp); + loadedGraphNode?(node: LGraphNode, app: ComfyApp); /** * Allows the extension to run code after the constructor of the node * @param node The node that has been created * @param app The ComfyUI app instance */ - nodeCreated(node: LGraphNode, app: ComfyApp); + nodeCreated?(node: LGraphNode, app: ComfyApp); } export type ComfyObjectInfo = {