Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b797710ade | ||
|
|
2e0a643901 | ||
|
|
3fc874dd22 | ||
|
|
f40a58f7a8 | ||
|
|
d322caf561 | ||
|
|
94a0a48b23 |
@@ -1,93 +0,0 @@
|
|||||||
name: Rebase PR
|
|
||||||
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
workflow_dispatch: # Enable manual triggering
|
|
||||||
inputs:
|
|
||||||
branch:
|
|
||||||
description: 'Select the branch to rebase the PR too'
|
|
||||||
required: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check-comment:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: read
|
|
||||||
outputs:
|
|
||||||
is_rebase: ${{ steps.check-rebase.outputs.is_rebase }}
|
|
||||||
steps:
|
|
||||||
- name: Check comment is rebase
|
|
||||||
if: ${{ github.event.issue.pull_request }} && startsWith(github.event.comment.body || '', '/rebase')
|
|
||||||
id: check-rebase
|
|
||||||
run: |
|
|
||||||
echo "User Comment: $COMMENT_BODY"
|
|
||||||
echo "is_rebase=true" >> $GITHUB_OUTPUT
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
COMMENT_BODY: ${{ github.event.comment.body }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
rebase:
|
|
||||||
needs: check-comment
|
|
||||||
if: ${{ needs.check-comment.outputs.is_rebase }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
id-token: write
|
|
||||||
steps:
|
|
||||||
- name: Check user permissions
|
|
||||||
id: check-permissions
|
|
||||||
run: |
|
|
||||||
USER_LOGIN="${{ github.event.comment.user.login }}"
|
|
||||||
COLLABORATORS=$(gh api "/repos/${{ github.repository }}/collaborators" \
|
|
||||||
--jq '.[] | select(.permissions.admin == true or .permissions.maintain == true or .permissions.push == true) | .login')
|
|
||||||
if [[ "$COLLABORATORS" =~ "$USER_LOGIN" ]]; then
|
|
||||||
echo "is_authorized=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "::error::User $USER_LOGIN lacks required permissions"
|
|
||||||
gh pr comment ${{ github.event.issue.number }} --body "$USER_LOGIN lacks required permissions. Please contact a maintainer."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install GitHub CLI
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install gh
|
|
||||||
echo "gh cli installed"
|
|
||||||
|
|
||||||
- name: Find latest release branch
|
|
||||||
id: find_release_branch
|
|
||||||
run: |
|
|
||||||
git fetch origin
|
|
||||||
LATEST_BRANCH=$(git branch -r | grep 'origin/release-v' | sed 's/origin\///' | sort -V | tail -n 1)
|
|
||||||
echo "Latest release branch: $LATEST_BRANCH"
|
|
||||||
echo "latest_branch=$LATEST_BRANCH" >> $GITHUB_OUTPUT
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Rebase current PR onto latest release branch
|
|
||||||
if: ${{ needs.check-comment.outputs.is_rebase }} && steps.check-permissions.outputs.is_authorized == 'true'
|
|
||||||
run: |
|
|
||||||
# Configure Git
|
|
||||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git config --global user.name "GitHub Actions Bot"
|
|
||||||
|
|
||||||
echo "going to branch: $TARGET_BRANCH"
|
|
||||||
git fetch origin $TARGET_BRANCH
|
|
||||||
#git rebase origin/$TARGET_BRANCH
|
|
||||||
gh pr edit ${{ github.event.issue.number }} --base $TARGET_BRANCH
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
REPO: ${{ github.event.repository.name }}
|
|
||||||
TARGET_BRANCH: ${{ steps.find_release_branch.outputs.latest_branch }}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
name: Update Release Notes on Release Event
|
|
||||||
|
|
||||||
env:
|
|
||||||
QCOW2_IMG: ${{ vars.REGISTRY }}/${{ vars.REPO }}/vjailbreak
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
logLevel:
|
|
||||||
description: 'Log level'
|
|
||||||
required: true
|
|
||||||
default: 'info'
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- info
|
|
||||||
- warning
|
|
||||||
- debug
|
|
||||||
environment:
|
|
||||||
description: 'Environment to run in'
|
|
||||||
type: environment
|
|
||||||
required: true
|
|
||||||
branch:
|
|
||||||
description: 'Branch to use'
|
|
||||||
required: true
|
|
||||||
default: 'gh-pages'
|
|
||||||
release_tag:
|
|
||||||
description: 'Manually run for a specific release tag'
|
|
||||||
required: true
|
|
||||||
type: text
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check-and-wait-for-artifacts:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
tag: ${{ steps.get_tag.outputs.tag }}
|
|
||||||
steps:
|
|
||||||
- name: Set Tag for Release Event
|
|
||||||
if: github.event_name == 'release'
|
|
||||||
id: set_release_tag
|
|
||||||
run: echo "tag=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Set Tag for Manual Trigger
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
id: set_manual_tag
|
|
||||||
run: echo "tag=${{ github.event.inputs.release_tag }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Get Tag
|
|
||||||
id: get_tag
|
|
||||||
run: echo "tag=${{ steps.set_release_tag.outputs.tag || steps.set_manual_tag.outputs.tag }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: |
|
|
||||||
curl -LO https://github.com/oras-project/oras/releases/download/v1.2.1/oras_1.2.1_linux_amd64.tar.gz
|
|
||||||
sudo tar -C /usr/local/bin/ -xzvf oras_1.2.1_linux_amd64.tar.gz oras
|
|
||||||
|
|
||||||
- name: Wait and check for QCOW image (Max 45 mins)
|
|
||||||
run: |
|
|
||||||
RELEASE_TAG="${{ steps.get_tag.outputs.tag }}"
|
|
||||||
QCOW_IMAGE_URL="${{ env.QCOW2_IMG }}:${RELEASE_TAG}"
|
|
||||||
|
|
||||||
echo "Waiting for artifact to be available at $QCOW_IMAGE_URL"
|
|
||||||
|
|
||||||
for i in $(seq 1 135); do
|
|
||||||
if oras manifest fetch "$QCOW_IMAGE_URL" &>/dev/null; then
|
|
||||||
echo ""
|
|
||||||
echo "Success! Artifact found."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $i -eq 135 ]]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
|
|
||||||
sleep 20
|
|
||||||
done
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Artifact not found after 45 minutes. Failing workflow."
|
|
||||||
exit 1
|
|
||||||
|
|
||||||
update-release-notes:
|
|
||||||
needs: check-and-wait-for-artifacts
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: gh-pages
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Install GitHub CLI and jq
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y gh jq
|
|
||||||
|
|
||||||
- name: Set Tag from Previous Event
|
|
||||||
id: set_tag
|
|
||||||
run: echo "tag=${{ needs.check-and-wait-for-artifacts.outputs.tag }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Generate Notes for New Release
|
|
||||||
id: process_release
|
|
||||||
run: |
|
|
||||||
RELEASE_TAG="${{ steps.set_tag.outputs.tag }}"
|
|
||||||
|
|
||||||
echo ">>> Processing new release: $RELEASE_TAG"
|
|
||||||
|
|
||||||
RELEASE_NOTES=$(gh release view "$RELEASE_TAG" --json body --template '{{.body}}' || echo "")
|
|
||||||
if [ -z "$RELEASE_NOTES" ]; then
|
|
||||||
echo "No release notes found for $RELEASE_TAG, skipping."
|
|
||||||
echo "processed_release=false" >> $GITHUB_OUTPUT
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# find the previous tag
|
|
||||||
ALL_TAGS_SORTED=$(git tag --sort=version:refname)
|
|
||||||
LAST_TAG=$(echo "$ALL_TAGS_SORTED" | grep -B 1 -x "$RELEASE_TAG" | head -n 1)
|
|
||||||
|
|
||||||
if [[ -n "$LAST_TAG" && "$LAST_TAG" != "$RELEASE_TAG" ]]; then
|
|
||||||
echo "Found previous version: $LAST_TAG. Updating version numbers in docs..."
|
|
||||||
sed -i "s|$LAST_TAG|$RELEASE_TAG|g" docs/src/content/docs/introduction/getting_started.mdx
|
|
||||||
sed -i "s|$LAST_TAG|$RELEASE_TAG|g" docs/src/components/githubRelease.astro
|
|
||||||
sed -i "s|$LAST_TAG|$RELEASE_TAG|g" docs/src/content/docs/index.mdx
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create the new release note file
|
|
||||||
FILE_NAME="docs/src/content/docs/release_docs/$RELEASE_TAG.md"
|
|
||||||
mkdir -p "$(dirname "$FILE_NAME")"
|
|
||||||
{
|
|
||||||
echo "---"
|
|
||||||
echo "title: $RELEASE_TAG"
|
|
||||||
echo "description: Release Notes for $RELEASE_TAG"
|
|
||||||
echo "---"
|
|
||||||
echo ""
|
|
||||||
echo "$RELEASE_NOTES"
|
|
||||||
} > "$FILE_NAME"
|
|
||||||
|
|
||||||
echo "processed_release=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "release_tag=$RELEASE_TAG" >> $GITHUB_OUTPUT
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Archive and Delete Old Release Notes
|
|
||||||
if: steps.process_release.outputs.processed_release == 'true'
|
|
||||||
uses: platform9/vjailbreak/.github/actions/archive-old-release-notes@main
|
|
||||||
|
|
||||||
- name: Create PR with changes
|
|
||||||
if: steps.process_release.outputs.processed_release == 'true'
|
|
||||||
uses: platform9/vjailbreak/.github/actions/create-docs-pr@main
|
|
||||||
with:
|
|
||||||
branch-prefix: update-release-docs
|
|
||||||
commit-message: "docs: Update for release ${{ steps.process_release.outputs.release_tag }}"
|
|
||||||
pr-title: "docs: Update for release ${{ steps.process_release.outputs.release_tag }}"
|
|
||||||
pr-body: "This PR was automatically generated."
|
|
||||||
retry: 'false'
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
name: Manual Docs Backfill
|
|
||||||
|
|
||||||
env:
|
|
||||||
QCOW2_IMG: ${{ vars.REGISTRY }}/${{ vars.REPO }}/vjailbreak
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
release_tag:
|
|
||||||
description: 'Single release tag to process'
|
|
||||||
required: false
|
|
||||||
process_all_recent:
|
|
||||||
description: 'Process all missing releases'
|
|
||||||
required: true
|
|
||||||
default: true
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
backfill-release-notes:
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout gh-pages Branch
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: gh-pages
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Install GitHub CLI and jq
|
|
||||||
run: sudo apt-get update && sudo apt-get install -y gh jq skopeo
|
|
||||||
|
|
||||||
- name: Process and Generate Release Notes
|
|
||||||
id: process_releases
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
# This function processes a single release tag
|
|
||||||
process_release() {
|
|
||||||
local RELEASE_TAG=$1
|
|
||||||
if [ -f "docs/src/content/docs/release_docs/$RELEASE_TAG.md" ]; then
|
|
||||||
echo "Documentation for $RELEASE_TAG already exists, skipping."
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
local QCOW_IMAGE_URI="docker://${{ env.QCOW2_IMG }}:${RELEASE_TAG}"
|
|
||||||
echo "--> Checking for image: $QCOW_IMAGE_URI"
|
|
||||||
if ! skopeo inspect "$QCOW_IMAGE_URI" &>/dev/null; then
|
|
||||||
echo "::warning::Image not found for tag $RELEASE_TAG. Skipping doc generation for this release."
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
echo "--> Image found. Proceeding with doc generation."
|
|
||||||
|
|
||||||
echo ">>> Processing release: $RELEASE_TAG"
|
|
||||||
RELEASE_NOTES=$(gh release view "$RELEASE_TAG" --json body --template '{{.body}}' || echo "")
|
|
||||||
if [ -z "$RELEASE_NOTES" ]; then
|
|
||||||
echo "No release notes found for $RELEASE_TAG, skipping."; return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
local ALL_TAGS_SORTED=$(git tag --sort=version:refname)
|
|
||||||
local LAST_TAG=$(echo "$ALL_TAGS_SORTED" | grep -B 1 -x "$RELEASE_TAG" | head -n 1)
|
|
||||||
|
|
||||||
if [[ -n "$LAST_TAG" && "$LAST_TAG" != "$RELEASE_TAG" ]]; then
|
|
||||||
echo "Found previous version: $LAST_TAG. Updating docs..."
|
|
||||||
sed -i "s|$LAST_TAG|$RELEASE_TAG|g" docs/src/content/docs/introduction/getting_started.mdx
|
|
||||||
sed -i "s|$LAST_TAG|$RELEASE_TAG|g" docs/src/components/githubRelease.astro
|
|
||||||
sed -i "s|$LAST_TAG|$RELEASE_TAG|g" docs/src/content/docs/index.mdx
|
|
||||||
fi
|
|
||||||
|
|
||||||
local FILE_NAME="docs/src/content/docs/release_docs/$RELEASE_TAG.md"
|
|
||||||
mkdir -p "$(dirname "$FILE_NAME")"
|
|
||||||
{ echo "---"; echo "title: $RELEASE_TAG"; echo "description: Release Notes for $RELEASE_TAG"; echo "---"; echo ""; echo "$RELEASE_NOTES"; } > "$FILE_NAME"
|
|
||||||
echo "Created documentation file: $FILE_NAME"
|
|
||||||
PROCESSED_LIST_TEMP+="$RELEASE_TAG "
|
|
||||||
}
|
|
||||||
export -f process_release
|
|
||||||
PROCESSED_LIST_TEMP=""
|
|
||||||
|
|
||||||
if [[ -n "${{ github.event.inputs.release_tag }}" ]]; then
|
|
||||||
echo "Processing single specified release..."
|
|
||||||
process_release "${{ github.event.inputs.release_tag }}"
|
|
||||||
elif [[ "${{ github.event.inputs.process_all_recent }}" == "true" ]]; then
|
|
||||||
echo "Processing all recent missing releases..."
|
|
||||||
ALL_RELEASES=$(gh release list --limit 100 --json tagName --jq '.[].tagName' | sort -V)
|
|
||||||
for TAG in $ALL_RELEASES; do process_release "$TAG"; done
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "PROCESSED_RELEASES=${PROCESSED_LIST_TEMP}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Archive and Delete Old Release Notes
|
|
||||||
if: steps.process_releases.outputs.PROCESSED_RELEASES != ''
|
|
||||||
uses: platform9/vjailbreak/.github/actions/archive-old-release-notes@main
|
|
||||||
|
|
||||||
- name: Create PR with changes
|
|
||||||
if: steps.process_releases.outputs.PROCESSED_RELEASES != ''
|
|
||||||
uses: platform9/vjailbreak/.github/actions/create-docs-pr@main
|
|
||||||
with:
|
|
||||||
branch-prefix: backfill-docs
|
|
||||||
commit-message: "docs: Backfill missing release documentation for ${{ steps.process_releases.outputs.PROCESSED_RELEASES }}"
|
|
||||||
pr-title: "docs: Backfill release documentation for ${{ steps.process_releases.outputs.PROCESSED_RELEASES }}"
|
|
||||||
pr-body: "This PR was automatically generated to backfill documentation for one or more releases."
|
|
||||||
retry: 'true'
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
name: Pre-Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
tag:
|
|
||||||
description: "Release tag (e.g. v0.4.0)"
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
branch:
|
|
||||||
description: "Branch to use (default: main)"
|
|
||||||
required: false
|
|
||||||
default: "main"
|
|
||||||
type: string
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
generate-crds:
|
|
||||||
name: Generate CRDs and Installer
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout branch
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.inputs.branch || 'main' }}
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version-file: k8s/migration/go.mod
|
|
||||||
cache-dependency-path: k8s/migration/go.sum
|
|
||||||
|
|
||||||
- name: Install controller-gen
|
|
||||||
run: |
|
|
||||||
go install sigs.k8s.io/controller-tools/cmd/[email protected]
|
|
||||||
|
|
||||||
- name: Setup Kustomize
|
|
||||||
uses: imranismail/setup-kustomize@v2
|
|
||||||
with:
|
|
||||||
kustomize-version: '5.3.0'
|
|
||||||
|
|
||||||
- name: Run build-installer
|
|
||||||
run: |
|
|
||||||
cd k8s/migration
|
|
||||||
make build-installer TAG=${{ github.event.inputs.tag }}
|
|
||||||
|
|
||||||
- name: Check for changes
|
|
||||||
id: changes
|
|
||||||
run: |
|
|
||||||
if [[ -n "$(git status --porcelain)" ]]; then
|
|
||||||
echo "changes=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "changes=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Disable git hooks
|
|
||||||
if: steps.changes.outputs.changes == 'true'
|
|
||||||
run: git config core.hooksPath /dev/null
|
|
||||||
|
|
||||||
- name: Create Pull Request
|
|
||||||
if: steps.changes.outputs.changes == 'true'
|
|
||||||
uses: peter-evans/create-pull-request@v6
|
|
||||||
with:
|
|
||||||
branch: pre-release/${{ github.event.inputs.tag }}
|
|
||||||
base: main
|
|
||||||
commit-message: "chore: generate CRDs and installer for ${{ github.event.inputs.tag }}"
|
|
||||||
title: "chore: Pre-release CRD generation for ${{ github.event.inputs.tag }}"
|
|
||||||
body: |
|
|
||||||
Auto-generated CRDs and installer manifests for `${{ github.event.inputs.tag }}`.
|
|
||||||
|
|
||||||
Please review and merge before creating the release.
|
|
||||||
@@ -1,223 +1,2 @@
|
|||||||
<div align="center">
|
# vjailbreak-docs
|
||||||
|
Helping VMware users migrate to alternative Hypervisors
|
||||||
# vJailbreak
|
|
||||||
|
|
||||||
A free tool that simplifies the migration of virtual machines from VMware to any OpenStack-compliant cloud.
|
|
||||||
|
|
||||||
[](https://github.com/platform9/vjailbreak/actions/workflows/packer.yml)
|
|
||||||
[](https://github.com/platform9/vjailbreak/actions/workflows/golangci-lint.yaml)
|
|
||||||
|
|
||||||
[](https://github.com/platform9/vjailbreak/releases/latest)
|
|
||||||
[](https://github.com/platform9/vjailbreak/releases)
|
|
||||||
[](https://github.com/platform9/vjailbreak/stargazers)
|
|
||||||
[](https://github.com/platform9/vjailbreak/network/members)
|
|
||||||
|
|
||||||
[](https://deepwiki.com/platform9/vjailbreak)
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
vJailbreak is a powerful migration tool designed to seamlessly transfer virtual machines from VMware environments to any OpenStack-compliant cloud platform. The project aims to simplify the complex process of VM migration while ensuring compatibility and performance in the target environment.
|
|
||||||
|
|
||||||
### Key Features
|
|
||||||
|
|
||||||
- **VMware Integration**: Connect directly to vCenter to access and discover source VMs
|
|
||||||
|
|
||||||
- **Automated VM Conversion**: Convert VM disks from `vmdk` to `qcow2` format and prepare for OpenStack environment
|
|
||||||
|
|
||||||
- **OpenStack Integration**: Direct deployment to any OpenStack-compliant cloud with network and storage mapping
|
|
||||||
|
|
||||||
- **Flexible Migration Options**: Support for both hot and cold migrations with customizable scheduling
|
|
||||||
|
|
||||||
- **Rolling Conversion**: Staged migration process that minimizes downtime and resource usage
|
|
||||||
|
|
||||||
- **Advanced Migration Options**: Customizable migration parameters including network configuration, resource allocation, and storage mappings
|
|
||||||
|
|
||||||
- **Health Verification**: Post-migration health checks to ensure successful migration
|
|
||||||
|
|
||||||
- **Scalable Architecture**: Scale up or down migration agents based on workload
|
|
||||||
|
|
||||||
- **Enhanced Security**: Secure handling of credentials and data throughout the migration process
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Comprehensive documentation for vJailbreak is available on our documentation site:
|
|
||||||
|
|
||||||
[📚 vJailbreak Documentation](https://platform9.github.io/vjailbreak/introduction/getting_started/)
|
|
||||||
|
|
||||||
## Demonstration
|
|
||||||
|
|
||||||
### Video Overview
|
|
||||||
|
|
||||||
Click the image below to watch a demonstration of vJailbreak in action:
|
|
||||||
|
|
||||||
[](https://www.youtube.com/watch?v=seThilJ5ujM)
|
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
|
|
||||||
### Migration Setup
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Click to view migration setup screenshots</summary>
|
|
||||||
|
|
||||||
#### Migration Form (Step 1)
|
|
||||||

|
|
||||||
|
|
||||||
#### Migration Form (Step 2)
|
|
||||||

|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Migration Progress
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Click to view migration progress screenshots</summary>
|
|
||||||
|
|
||||||
#### Progress View (Stage 1)
|
|
||||||

|
|
||||||
|
|
||||||
#### Progress View (Stage 2)
|
|
||||||

|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Agent Scaling
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Click to view agent scaling screenshots</summary>
|
|
||||||
|
|
||||||
#### Scaling Up
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
#### Scaling Down
|
|
||||||

|
|
||||||
</details>
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This project is available under the [Business Source License 1.1](LICENSE). See the LICENSE file for full details.
|
|
||||||
|
|
||||||
Key points from the license:
|
|
||||||
- Licensor: Platform9 Systems, Inc.
|
|
||||||
- Licensed Work: All versions of vJailbreak (c) 2024 Platform9 Systems, Inc.
|
|
||||||
- Change Date: Four years from the date the Licensed Work is published
|
|
||||||
- Change License: MPL 2.0
|
|
||||||
|
|
||||||
For information about alternative licensing arrangements, contact info@platform9.com.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
- **VMware Environment**:
|
|
||||||
- VMware vCenter with appropriate permissions
|
|
||||||
- vSphere environment accessible to vJailbreak
|
|
||||||
|
|
||||||
- **OpenStack Environment**:
|
|
||||||
- OpenStack-compliant cloud target
|
|
||||||
- Network and storage access
|
|
||||||
|
|
||||||
- **Network Connectivity**:
|
|
||||||
- Access to vCenter, ESXi, and OpenStack API endpoints
|
|
||||||
- Access to download virtio drivers and other components
|
|
||||||
- ICMP (ping) access for connectivity verification
|
|
||||||
- **DNS Resolution**: Ensure that DNS resolution for vCenter, all ESXi hosts and OpenStack endpoints is properly configured. DNS for ESXi hosts is specifically required during the VM copy phase and migration may fail without it.
|
|
||||||
|
|
||||||
- **Supported OS**:
|
|
||||||
- All operating systems supported by virt-v2v
|
|
||||||
- See [virt-v2v support page](https://libguestfs.org/virt-v2v-support.1.html) for details
|
|
||||||
|
|
||||||
> **Note:** For an extensive and detailed list of all prerequisites, including network ports, access requirements, and FAQ, please refer to the [Prerequisites documentation](https://platform9.github.io/vjailbreak/introduction/prerequisites/).
|
|
||||||
|
|
||||||
### Quick Start
|
|
||||||
|
|
||||||
1. **Install ORAS and download vJailbreak**:
|
|
||||||
```bash
|
|
||||||
# Install ORAS (see https://oras.land/docs/installation)
|
|
||||||
|
|
||||||
# Download the latest vJailbreak image
|
|
||||||
oras pull quay.io/platform9/vjailbreak:<tag>
|
|
||||||
# This downloads the image to vjailbreak_qcow2/vjailbreak-image.qcow2
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Upload image and create vJailbreak VM**:
|
|
||||||
```bash
|
|
||||||
# Upload the image to your OpenStack environment
|
|
||||||
openstack image create --os-interface admin --insecure \
|
|
||||||
--container-format bare --disk-format qcow2 \
|
|
||||||
--file vjailbreak_qcow2/vjailbreak-image.qcow2 vjailbreak-image
|
|
||||||
|
|
||||||
# Deploy a VM from this image (use UI or CLI)
|
|
||||||
# - Choose m1.xlarge flavor (or larger for large VM migrations)
|
|
||||||
# - Select a network that can reach your VMware vCenter
|
|
||||||
# - Configure security group to allow required traffic
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Copy VDDK Libraries (Standard Copy method only)**:
|
|
||||||
- VDDK is required only if you plan to use the **Standard** storage copy method. As of
|
|
||||||
**v0.4.10**, vJailbreak defaults to **vJailbreak Accelerated Copy**. Along with
|
|
||||||
**Storage-Accelerated Copy**, it does not require VDDK at all. Skip this step unless you
|
|
||||||
specifically need Standard copy.
|
|
||||||
- Download [VDDK libraries](https://developer.broadcom.com/sdks/vmware-virtual-disk-development-kit-vddk/)
|
|
||||||
- Copy to `/home/ubuntu` on the vJailbreak VM
|
|
||||||
- Untar to create `vmware-vix-disklib-distrib` in `/home/ubuntu`
|
|
||||||
- See [vJailbreak Accelerated Copy](https://platform9.github.io/vjailbreak/concepts/vjailbreak-accelerated-copy/) and [Storage-Accelerated Copy](https://platform9.github.io/vjailbreak/concepts/storage-accelerated-copy/) for VDDK-free migration options
|
|
||||||
|
|
||||||
4. **Configure DNS Resolution**:
|
|
||||||
- Proper DNS resolution for your VMware and OpenStack URLs is required for vJailbreak to function correctly
|
|
||||||
|
|
||||||
- **Static Entries**: Adding entries to `/etc/hosts` will apply changes immediately
|
|
||||||
```bash
|
|
||||||
# Example /etc/hosts entry
|
|
||||||
192.168.1.100 vcenter.example.com
|
|
||||||
192.168.2.100 openstack.example.com
|
|
||||||
|
|
||||||
# ESXi hosts entries (required for VM copy phase)
|
|
||||||
192.168.1.101 esxi01.example.com esxi01
|
|
||||||
192.168.1.102 esxi02.example.com esxi02
|
|
||||||
```
|
|
||||||
|
|
||||||
- **DNS Configuration**: If modifying `/etc/resolv.conf`, you must restart the controller pod for changes to take effect
|
|
||||||
```bash
|
|
||||||
# After modifying resolv.conf
|
|
||||||
kubectl -n vjailbreak rollout restart deployment migration-controller-manager
|
|
||||||
```
|
|
||||||
|
|
||||||
5. **Launch vJailbreak**:
|
|
||||||
- Connect to the vJailbreak UI using the VM's IP address
|
|
||||||
- Provide VMware vCenter and OpenStack credentials
|
|
||||||
- Begin migrating VMs
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Refer to the [documentation](https://platform9.github.io/vjailbreak/introduction/getting_started/) for detailed usage instructions.
|
|
||||||
|
|
||||||
## Community and Support
|
|
||||||
|
|
||||||
- **GitHub Issues**: For bug reports and feature requests
|
|
||||||
- **Documentation**: [Complete vJailbreak Documentation](https://platform9.github.io/vjailbreak/)
|
|
||||||
- **Reddit Community**: Join our [r/vjailbreak](https://www.reddit.com/r/vjailbreak/) subreddit
|
|
||||||
- **Commercial Support**: For enterprise support, contact [Platform9](https://platform9.com/)
|
|
||||||
|
|
||||||
## Acknowledgements
|
|
||||||
|
|
||||||
vJailbreak builds upon several open-source technologies:
|
|
||||||
|
|
||||||
- [virt-v2v](https://github.com/virt-manager/virt-manager)
|
|
||||||
- [nbdkit](https://gitlab.com/nbdkit/nbdkit)
|
|
||||||
- [k3s](https://k3s.io/)
|
|
||||||
- [OpenStack](https://www.openstack.org/)
|
|
||||||
- [govmomi](https://github.com/vmware/govmomi)
|
|
||||||
- [virtio-win](https://github.com/virtio-win/kvm-guest-drivers-windows)
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Contributions to vJailbreak are welcome! Please feel free to submit issues and pull requests.
|
|
||||||
|
|
||||||
1. Fork the repository
|
|
||||||
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
||||||
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
||||||
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
||||||
5. Open a Pull Request
|
|
||||||
|
|
||||||
Please ensure your code follows the project's coding standards and includes appropriate tests.
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 397 KiB |
|
After Width: | Height: | Size: 399 KiB |
|
After Width: | Height: | Size: 288 KiB |
|
After Width: | Height: | Size: 229 KiB |
|
After Width: | Height: | Size: 238 KiB |
@@ -6,7 +6,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
networkMapping: networkmapping
|
networkMapping: networkmapping
|
||||||
storageMapping: storagemapping
|
storageMapping: storagemapping
|
||||||
osFamily: windowsGuest
|
osType: windows
|
||||||
source:
|
source:
|
||||||
datacenter: Datacenter Name
|
datacenter: Datacenter Name
|
||||||
vmwareRef: vmwarecreds
|
vmwareRef: vmwarecreds
|
||||||
|
|||||||
@@ -20,20 +20,6 @@ spec:
|
|||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
envFrom:
|
|
||||||
- configMapRef:
|
|
||||||
name: pf9-env
|
|
||||||
optional: true
|
|
||||||
volumeMounts:
|
|
||||||
- name: pf9-logs
|
|
||||||
mountPath: /var/log/pf9
|
|
||||||
readOnly: true
|
|
||||||
volumes:
|
|
||||||
- name: pf9-logs
|
|
||||||
hostPath:
|
|
||||||
path: /var/log/pf9
|
|
||||||
type: DirectoryOrCreate
|
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
@@ -56,14 +42,6 @@ metadata:
|
|||||||
namespace: migration-system
|
namespace: migration-system
|
||||||
annotations:
|
annotations:
|
||||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
|
||||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
|
||||||
nginx.ingress.kubernetes.io/proxy-body-size: "500m"
|
|
||||||
nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
|
|
||||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
|
|
||||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
|
|
||||||
nginx.ingress.kubernetes.io/proxy-buffering: "off"
|
|
||||||
nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
|
|
||||||
spec:
|
spec:
|
||||||
ingressClassName: nginx
|
ingressClassName: nginx
|
||||||
rules:
|
rules:
|
||||||
@@ -86,8 +64,6 @@ metadata:
|
|||||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
|
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
|
||||||
nginx.ingress.kubernetes.io/rewrite-target: /$1
|
nginx.ingress.kubernetes.io/rewrite-target: /$1
|
||||||
nginx.ingress.kubernetes.io/use-regex: "true"
|
nginx.ingress.kubernetes.io/use-regex: "true"
|
||||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
|
||||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
|
||||||
spec:
|
spec:
|
||||||
ingressClassName: nginx
|
ingressClassName: nginx
|
||||||
rules:
|
rules:
|
||||||
|
|||||||
@@ -1,110 +0,0 @@
|
|||||||
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app.kubernetes.io/managed-by: kustomize
|
|
||||||
app.kubernetes.io/name: migration
|
|
||||||
control-plane: controller-manager
|
|
||||||
name: migration-controller-manager
|
|
||||||
namespace: migration-system
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
control-plane: controller-manager
|
|
||||||
strategy:
|
|
||||||
type: Recreate
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
kubectl.kubernetes.io/default-container: manager
|
|
||||||
labels:
|
|
||||||
control-plane: controller-manager
|
|
||||||
spec:
|
|
||||||
affinity:
|
|
||||||
nodeAffinity:
|
|
||||||
requiredDuringSchedulingIgnoredDuringExecution:
|
|
||||||
nodeSelectorTerms:
|
|
||||||
- matchExpressions:
|
|
||||||
- key: node-role.kubernetes.io/control-plane
|
|
||||||
operator: Exists
|
|
||||||
containers:
|
|
||||||
- args:
|
|
||||||
- --leader-elect=false
|
|
||||||
- --health-probe-bind-address=:8081
|
|
||||||
command:
|
|
||||||
- /manager
|
|
||||||
env:
|
|
||||||
- name: MAX_CONCURRENT_RECONCILES
|
|
||||||
value: "5"
|
|
||||||
envFrom:
|
|
||||||
- configMapRef:
|
|
||||||
name: pf9-env
|
|
||||||
optional: true
|
|
||||||
image: quay.io/platform9/vjailbreak-controller:v0.4.10
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
lifecycle:
|
|
||||||
preStop:
|
|
||||||
exec:
|
|
||||||
command:
|
|
||||||
- /bin/sh
|
|
||||||
- -c
|
|
||||||
- sleep 5
|
|
||||||
livenessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /healthz
|
|
||||||
port: 8081
|
|
||||||
initialDelaySeconds: 15
|
|
||||||
periodSeconds: 20
|
|
||||||
name: manager
|
|
||||||
readinessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /readyz
|
|
||||||
port: 8081
|
|
||||||
initialDelaySeconds: 5
|
|
||||||
periodSeconds: 10
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 200m
|
|
||||||
memory: 256Mi
|
|
||||||
volumeMounts:
|
|
||||||
- mountPath: /etc/pf9/k3s
|
|
||||||
name: master-token
|
|
||||||
- mountPath: /home/ubuntu
|
|
||||||
name: vddk
|
|
||||||
- mountPath: /etc/hosts
|
|
||||||
name: hosts-file
|
|
||||||
readOnly: true
|
|
||||||
- mountPath: /host/dmi/product_uuid
|
|
||||||
name: dmi-product-uuid
|
|
||||||
readOnly: true
|
|
||||||
dnsConfig:
|
|
||||||
options:
|
|
||||||
- name: ndots
|
|
||||||
value: "1"
|
|
||||||
dnsPolicy: ClusterFirstWithHostNet
|
|
||||||
hostNetwork: true
|
|
||||||
securityContext:
|
|
||||||
runAsGroup: 0
|
|
||||||
runAsUser: 0
|
|
||||||
serviceAccountName: migration-controller-manager
|
|
||||||
terminationGracePeriodSeconds: 30
|
|
||||||
volumes:
|
|
||||||
- hostPath:
|
|
||||||
path: /var/lib/rancher/k3s/server
|
|
||||||
type: Directory
|
|
||||||
name: master-token
|
|
||||||
- hostPath:
|
|
||||||
path: /home/ubuntu
|
|
||||||
type: Directory
|
|
||||||
name: vddk
|
|
||||||
- hostPath:
|
|
||||||
path: /etc/hosts
|
|
||||||
type: File
|
|
||||||
name: hosts-file
|
|
||||||
- hostPath:
|
|
||||||
path: /sys/class/dmi/id/product_uuid
|
|
||||||
type: File
|
|
||||||
name: dmi-product-uuid
|
|
||||||
---
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: vpwned-sdk
|
|
||||||
name: migration-vpwned-sdk
|
|
||||||
namespace: migration-system
|
|
||||||
spec:
|
|
||||||
progressDeadlineSeconds: 600
|
|
||||||
replicas: 1
|
|
||||||
revisionHistoryLimit: 10
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: vpwned-sdk
|
|
||||||
strategy:
|
|
||||||
rollingUpdate:
|
|
||||||
maxSurge: 25%
|
|
||||||
maxUnavailable: 25%
|
|
||||||
type: RollingUpdate
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
container.apparmor.security.beta.kubernetes.io/vpwned: unconfined
|
|
||||||
labels:
|
|
||||||
app: vpwned-sdk
|
|
||||||
spec:
|
|
||||||
affinity:
|
|
||||||
nodeAffinity:
|
|
||||||
requiredDuringSchedulingIgnoredDuringExecution:
|
|
||||||
nodeSelectorTerms:
|
|
||||||
- matchExpressions:
|
|
||||||
- key: node-role.kubernetes.io/control-plane
|
|
||||||
operator: Exists
|
|
||||||
containers:
|
|
||||||
- env:
|
|
||||||
- name: DBUS_SYSTEM_BUS_ADDRESS
|
|
||||||
value: unix:path=/run/dbus/system_bus_socket
|
|
||||||
envFrom:
|
|
||||||
- configMapRef:
|
|
||||||
name: pf9-env
|
|
||||||
optional: true
|
|
||||||
image: quay.io/platform9/vjailbreak-vpwned:v0.4.10
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
name: vpwned
|
|
||||||
ports:
|
|
||||||
- containerPort: 3001
|
|
||||||
protocol: TCP
|
|
||||||
resources: {}
|
|
||||||
securityContext:
|
|
||||||
allowPrivilegeEscalation: false
|
|
||||||
capabilities:
|
|
||||||
add:
|
|
||||||
- DAC_OVERRIDE
|
|
||||||
drop:
|
|
||||||
- ALL
|
|
||||||
runAsUser: 0
|
|
||||||
terminationMessagePath: /dev/termination-log
|
|
||||||
terminationMessagePolicy: File
|
|
||||||
volumeMounts:
|
|
||||||
- mountPath: /etc/hosts
|
|
||||||
name: hosts-file
|
|
||||||
readOnly: true
|
|
||||||
- mountPath: /home/ubuntu
|
|
||||||
name: vddk-storage
|
|
||||||
- mountPath: /run/dbus/system_bus_socket
|
|
||||||
name: dbus-socket
|
|
||||||
- mountPath: /etc/systemd/timesyncd.conf.d
|
|
||||||
name: timesyncd-conf-dir
|
|
||||||
- mountPath: /usr/share/zoneinfo
|
|
||||||
name: host-zoneinfo
|
|
||||||
readOnly: true
|
|
||||||
- mountPath: /etc/pf9
|
|
||||||
name: pf9-config
|
|
||||||
- mountPath: /var/log/pf9
|
|
||||||
name: pf9-logs
|
|
||||||
readOnly: true
|
|
||||||
dnsConfig:
|
|
||||||
options:
|
|
||||||
- name: ndots
|
|
||||||
value: "1"
|
|
||||||
dnsPolicy: ClusterFirst
|
|
||||||
restartPolicy: Always
|
|
||||||
schedulerName: default-scheduler
|
|
||||||
securityContext: {}
|
|
||||||
serviceAccountName: migration-controller-manager
|
|
||||||
terminationGracePeriodSeconds: 30
|
|
||||||
volumes:
|
|
||||||
- hostPath:
|
|
||||||
path: /etc/hosts
|
|
||||||
type: File
|
|
||||||
name: hosts-file
|
|
||||||
- hostPath:
|
|
||||||
path: /home/ubuntu
|
|
||||||
type: DirectoryOrCreate
|
|
||||||
name: vddk-storage
|
|
||||||
- hostPath:
|
|
||||||
path: /run/dbus/system_bus_socket
|
|
||||||
type: Socket
|
|
||||||
name: dbus-socket
|
|
||||||
- hostPath:
|
|
||||||
path: /etc/systemd/timesyncd.conf.d
|
|
||||||
type: DirectoryOrCreate
|
|
||||||
name: timesyncd-conf-dir
|
|
||||||
- hostPath:
|
|
||||||
path: /usr/share/zoneinfo
|
|
||||||
type: Directory
|
|
||||||
name: host-zoneinfo
|
|
||||||
- hostPath:
|
|
||||||
path: /etc/pf9
|
|
||||||
type: Directory
|
|
||||||
name: pf9-config
|
|
||||||
- hostPath:
|
|
||||||
path: /var/log/pf9
|
|
||||||
type: DirectoryOrCreate
|
|
||||||
name: pf9-logs
|
|
||||||
---
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: vjailbreak-ui
|
|
||||||
namespace: migration-system
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: vjailbreak-ui
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: vjailbreak-ui
|
|
||||||
spec:
|
|
||||||
affinity:
|
|
||||||
nodeAffinity:
|
|
||||||
requiredDuringSchedulingIgnoredDuringExecution:
|
|
||||||
nodeSelectorTerms:
|
|
||||||
- matchExpressions:
|
|
||||||
- key: node-role.kubernetes.io/control-plane
|
|
||||||
operator: Exists
|
|
||||||
serviceAccountName: ui-manager-sa
|
|
||||||
containers:
|
|
||||||
- name: vjailbreak-ui-container
|
|
||||||
image: quay.io/platform9/vjailbreak-ui:v0.4.10
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
envFrom:
|
|
||||||
- configMapRef:
|
|
||||||
name: pf9-env
|
|
||||||
optional: true
|
|
||||||
volumeMounts:
|
|
||||||
- name: nginx-shadow-htpasswd
|
|
||||||
mountPath: /etc/nginx/shadow
|
|
||||||
volumes:
|
|
||||||
- name: nginx-shadow-htpasswd
|
|
||||||
hostPath:
|
|
||||||
path: /etc/htpasswd
|
|
||||||
type: FileOrCreate
|
|
||||||
---
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
|
|
||||||
apiVersion: v1
|
|
||||||
kind: PersistentVolumeClaim
|
|
||||||
metadata:
|
|
||||||
name: vjailbreak-ai-data
|
|
||||||
namespace: migration-system
|
|
||||||
spec:
|
|
||||||
accessModes:
|
|
||||||
- ReadWriteOnce
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: 2Gi
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: vjailbreak-ai
|
|
||||||
namespace: migration-system
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: vjailbreak-ai
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: vjailbreak-ai
|
|
||||||
spec:
|
|
||||||
affinity:
|
|
||||||
nodeAffinity:
|
|
||||||
requiredDuringSchedulingIgnoredDuringExecution:
|
|
||||||
nodeSelectorTerms:
|
|
||||||
- matchExpressions:
|
|
||||||
- key: node-role.kubernetes.io/control-plane
|
|
||||||
operator: Exists
|
|
||||||
serviceAccountName: vjailbreak-ai-sa
|
|
||||||
containers:
|
|
||||||
- name: vjailbreak-ai
|
|
||||||
image: quay.io/platform9/vjailbreak-ai:v0.4.10
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
ports:
|
|
||||||
- containerPort: 8080
|
|
||||||
env:
|
|
||||||
- name: ANTHROPIC_API_KEY
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: vjailbreak-ai-secret
|
|
||||||
key: api-key
|
|
||||||
optional: true
|
|
||||||
- name: CHROMA_PATH
|
|
||||||
value: /data/chroma
|
|
||||||
- name: CONTEXT_PATH
|
|
||||||
value: /data/context.md
|
|
||||||
- name: ALLOWED_ORIGINS
|
|
||||||
value: "http://vjailbreak-ui-service.migration-system.svc.cluster.local"
|
|
||||||
volumeMounts:
|
|
||||||
- name: ai-data
|
|
||||||
mountPath: /data
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
memory: "256Mi"
|
|
||||||
cpu: "100m"
|
|
||||||
limits:
|
|
||||||
memory: "1Gi"
|
|
||||||
cpu: "500m"
|
|
||||||
volumes:
|
|
||||||
- name: ai-data
|
|
||||||
persistentVolumeClaim:
|
|
||||||
claimName: vjailbreak-ai-data
|
|
||||||
---
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: vjailbreak-ai-context
|
|
||||||
namespace: migration-system
|
|
||||||
data:
|
|
||||||
additional_context: |
|
|
||||||
## vJailbreak Architecture
|
|
||||||
|
|
||||||
vJailbreak migrates VMware VMs to OpenStack in this sequence:
|
|
||||||
1. Controller creates a v2v-helper pod per migration
|
|
||||||
2. v2v-helper runs virt-v2v with the nbdkit+VDDK plugin to stream VMDK data
|
|
||||||
3. Converted disk is uploaded to OpenStack Glance as QCOW2 (or written to a Cinder volume via RAW)
|
|
||||||
4. Nova boots the migrated VM using the uploaded image or volume
|
|
||||||
|
|
||||||
Key components:
|
|
||||||
- **migration-controller-manager** — Kubernetes controller in `migration-system` namespace; reconciles Migration CRs
|
|
||||||
- **v2v-helper pod** — named `<migration-name>` in `migration-system`; runs virt-v2v; one pod per Migration
|
|
||||||
- **VDDK** — VMware Virtual Disk Development Kit at `/home/ubuntu/vmware-vix-disklib-distrib/` on the vJailbreak VM
|
|
||||||
- **Conversion scratch space** — `emptyDir` at `/var/tmp/v2v-conversion-disks/` inside v2v-helper pod (~2× VM disk size required)
|
|
||||||
- **storageCopyMethod** — `hot` (live/CBT incremental) or `cold` (offline full-copy); set in MigrationTemplate
|
|
||||||
|
|
||||||
CRD hierarchy: Migration → MigrationPlan → MigrationTemplate → NetworkMapping + StorageMapping
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Common Failure Patterns and Fixes
|
|
||||||
|
|
||||||
### VDDK / VMware Connectivity
|
|
||||||
| Symptom | Likely Cause | Fix |
|
|
||||||
|---------|-------------|-----|
|
|
||||||
| `VixDiskLib_Open failed` / `Transport error` | VDDK library missing or wrong version | Verify `/home/ubuntu/vmware-vix-disklib-distrib/` exists; VDDK 7.0+ required |
|
|
||||||
| `Failed to connect to host <esxi-fqdn>` | ESXi hostname not resolving in pod | Add ESXi host entries to `/etc/hosts` on vJailbreak VM, then restart controller |
|
|
||||||
| `SSL certificate verify failed` | vCenter TLS cert untrusted | Set `InsecureSkipVerify: true` in VMwareCreds or add cert to trust store |
|
|
||||||
| `NoPermission` / `NotAuthenticated` | Insufficient vCenter permissions | Account needs Datastore.Browse, VirtualMachine.Provisioning.DiskRandomRead, Global.DisableMethods |
|
|
||||||
| `CBT not enabled` / `queryChangedDiskAreas` error | Changed Block Tracking disabled on source VM | Enable CBT in vCenter VM settings, create a snapshot, then retry |
|
|
||||||
|
|
||||||
### virt-v2v / Conversion
|
|
||||||
| Symptom | Likely Cause | Fix |
|
|
||||||
|---------|-------------|-----|
|
|
||||||
| `No space left on device` | Node disk exhausted during conversion | Ensure node has ≥2× VM disk size free in `/var/tmp`; check `df -h` on vJailbreak VM |
|
|
||||||
| `libguestfs: error: could not create appliance` | libguestfs kernel/QEMU unavailable in pod | Check pod for missing KVM device; vJailbreak VM must have nested virt or bare-metal KVM |
|
|
||||||
| `Failed to locate virtio drivers` / `virtio-win` | virtio-win ISO not found | Confirm virtio-win ISO is present at the expected path in the v2v-helper image |
|
|
||||||
| `qemu-img: Could not open` / `corrupt` | VMDK corrupt or CBT snapshot stale | Remove stale snapshots in vCenter; try `storageCopyMethod: cold` |
|
|
||||||
| `virt-v2v: error: inspection of disk image failed` | Unsupported guest OS | Check virt-v2v support page; Windows requires virtio-win, Linux needs grub accessible |
|
|
||||||
| Conversion stuck / timeout | Very large VM or slow storage | Increase `migrationTimeout` in MigrationPlan; check network throughput between vJailbreak and ESXi |
|
|
||||||
|
|
||||||
### OpenStack Upload / Deploy
|
|
||||||
| Symptom | Likely Cause | Fix |
|
|
||||||
|---------|-------------|-----|
|
|
||||||
| `No valid host found` | Flavor constraints or resource exhaustion | Verify flavor exists and Nova has capacity; check `openstack flavor list` |
|
|
||||||
| `Quota exceeded` | OpenStack project quota hit | Check `openstack quota show` for instances, cores, RAM, volumes, gigabytes |
|
|
||||||
| `Network <name> could not be found` | NetworkMapping source or target name mismatch | Verify NetworkMapping.Spec matches exact OpenStack network names |
|
|
||||||
| `VolumeType <name> not found` | StorageMapping mismatch | Verify StorageMapping.Spec matches exact Cinder volume type names; case-sensitive |
|
|
||||||
| `Provided image is too large` | Glance upload size limit | Increase `glance-api.conf image_size_cap`; or use `storageCopyMethod: raw-volume` to bypass Glance |
|
|
||||||
| `ImageNotFound` during Nova boot | Glance upload failed or image in error state | Check `openstack image list`; look for image in `killed` or `queued` state |
|
|
||||||
|
|
||||||
### Kubernetes / Controller
|
|
||||||
| Symptom | Likely Cause | Fix |
|
|
||||||
|---------|-------------|-----|
|
|
||||||
| Pod `OOMKilled` | Insufficient memory for conversion | Large Windows VMs need 4–8 GB; increase v2v-helper memory limit in MigrationPlan |
|
|
||||||
| Pod stuck in `Pending` | Node selector mismatch or node resource shortage | Check `kubectl describe pod <name>` for scheduling events |
|
|
||||||
| `context deadline exceeded` in controller | Migration timeout too short | Increase `migrationTimeout` in MigrationPlan spec |
|
|
||||||
| Migration stuck in `DataCopyStart` | NBD/VDDK stream stalled | Check v2v-helper logs for `nbdkit` errors; restart migration |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Analysis Guidelines
|
|
||||||
|
|
||||||
- **Always quote specific log lines** as evidence in `root_cause` — vague causes are not actionable
|
|
||||||
- **fix_steps** should be concrete shell commands or UI steps, not generic advice
|
|
||||||
- Check `storageCopyMethod` (`hot` vs `cold`) — hot migrations have extra pre-copy phases that can fail
|
|
||||||
- If `phase` is `Failed` but logs are empty, check controller logs for reconcile errors mentioning the Migration name
|
|
||||||
- Network and storage mapping errors almost always have the exact mismatched name in the log — quote it
|
|
||||||
- If confidence is `low` or `none`, list the specific information that would be needed to diagnose further
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: vjailbreak-ai-context
|
|
||||||
namespace: migration-system
|
|
||||||
data:
|
|
||||||
# Operator-provided context injected into every AI analysis prompt.
|
|
||||||
# Edit the value below to add site-specific information.
|
|
||||||
# Examples:
|
|
||||||
# - Custom VDDK install path
|
|
||||||
# - Known ESXi certificate issues in this environment
|
|
||||||
# - Network restrictions that affect migrations
|
|
||||||
# - OpenStack volume type mappings in use
|
|
||||||
additional_context: |
|
|
||||||
# Add operator-specific notes here.
|
|
||||||
# Example:
|
|
||||||
# VDDK is installed at /opt/vmware/vddk (non-standard path).
|
|
||||||
# All ESXi hosts use self-signed TLS certificates -- SSL errors are expected.
|
|
||||||
# OpenStack Cinder volume type "ssd" maps to VMware datastore "fast-ssd".
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
# Prerequisites:
|
|
||||||
# Create the API key Secret via Settings → AI in the vJailbreak UI, or manually:
|
|
||||||
# kubectl -n migration-system create secret generic vjailbreak-ai-secret \
|
|
||||||
# --from-literal=api-key=<anthropic-api-key> \
|
|
||||||
# --from-literal=admin-key=<admin-key>
|
|
||||||
# The Deployment uses optional: true so it starts without the Secret,
|
|
||||||
# but AI analysis calls will fail until the key is configured.
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: vjailbreak-ai
|
|
||||||
namespace: migration-system
|
|
||||||
labels:
|
|
||||||
app: vjailbreak-ai
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: vjailbreak-ai
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: vjailbreak-ai
|
|
||||||
spec:
|
|
||||||
securityContext:
|
|
||||||
runAsNonRoot: true
|
|
||||||
runAsUser: 1001
|
|
||||||
fsGroup: 1001
|
|
||||||
containers:
|
|
||||||
- name: vjailbreak-ai
|
|
||||||
image: quay.io/platform9/vjailbreak-ai:main
|
|
||||||
ports:
|
|
||||||
- containerPort: 8080
|
|
||||||
env:
|
|
||||||
- name: ANTHROPIC_API_KEY
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: vjailbreak-ai-secret
|
|
||||||
key: api-key
|
|
||||||
optional: true # Secret must be created via Settings UI before AI analysis works
|
|
||||||
- name: ADMIN_API_KEY
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: vjailbreak-ai-secret
|
|
||||||
key: admin-key
|
|
||||||
optional: true
|
|
||||||
volumeMounts:
|
|
||||||
- name: chroma-data
|
|
||||||
mountPath: /data
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 200m
|
|
||||||
memory: 512Mi
|
|
||||||
limits:
|
|
||||||
cpu: "1"
|
|
||||||
memory: 1Gi
|
|
||||||
livenessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /health
|
|
||||||
port: 8080
|
|
||||||
initialDelaySeconds: 30
|
|
||||||
periodSeconds: 30
|
|
||||||
readinessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /health
|
|
||||||
port: 8080
|
|
||||||
initialDelaySeconds: 10
|
|
||||||
periodSeconds: 10
|
|
||||||
volumes:
|
|
||||||
- name: chroma-data
|
|
||||||
persistentVolumeClaim:
|
|
||||||
claimName: vjailbreak-ai-chroma
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: PersistentVolumeClaim
|
|
||||||
metadata:
|
|
||||||
name: vjailbreak-ai-chroma
|
|
||||||
namespace: migration-system
|
|
||||||
spec:
|
|
||||||
accessModes:
|
|
||||||
- ReadWriteOnce
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: 2Gi
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: vjailbreak-ai
|
|
||||||
namespace: migration-system
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
app: vjailbreak-ai
|
|
||||||
ports:
|
|
||||||
- port: 8080
|
|
||||||
targetPort: 8080
|
|
||||||
type: ClusterIP
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
apiVersion: vjailbreak.k8s.pf9.io/v1alpha1
|
|
||||||
kind: VolumeImageProfile
|
|
||||||
metadata:
|
|
||||||
name: default-windows
|
|
||||||
namespace: migration-system
|
|
||||||
spec:
|
|
||||||
osFamily: windowsGuest
|
|
||||||
description: Default profile for Windows VMs
|
|
||||||
properties:
|
|
||||||
hw_qemu_guest_agent: "yes"
|
|
||||||
hw_video_model: virtio
|
|
||||||
hw_pointer_model: usbtablet
|
|
||||||
hw_disk_bus: virtio
|
|
||||||
os_type: windows
|
|
||||||
---
|
|
||||||
apiVersion: vjailbreak.k8s.pf9.io/v1alpha1
|
|
||||||
kind: VolumeImageProfile
|
|
||||||
metadata:
|
|
||||||
name: default-linux
|
|
||||||
namespace: migration-system
|
|
||||||
spec:
|
|
||||||
osFamily: linuxGuest
|
|
||||||
description: Default profile for Linux VMs
|
|
||||||
properties:
|
|
||||||
hw_qemu_guest_agent: "yes"
|
|
||||||
hw_video_model: virtio
|
|
||||||
hw_pointer_model: usbtablet
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# build output
|
||||||
|
dist/
|
||||||
|
# generated types
|
||||||
|
.astro/
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# logs
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
|
||||||
|
# environment variables
|
||||||
|
.env
|
||||||
|
.env.production
|
||||||
|
|
||||||
|
# macOS-specific files
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
<!DOCTYPE html><html lang="en" dir="ltr" data-theme="dark" data-has-hero class="astro-bguv2lll"> <head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><title>404 | vJailbreak</title><link rel="canonical" href="https://platform9.github.io/vjailbreak/404/"/><link rel="sitemap" href="/vjailbreak/sitemap-index.xml"/><link rel="shortcut icon" href="/vjailbreak/favicon.svg" type="image/svg+xml"/><meta name="generator" content="Astro v5.12.8"/><meta name="generator" content="Starlight v0.32.6"/><meta property="og:title" content="404"/><meta property="og:type" content="article"/><meta property="og:url" content="https://platform9.github.io/vjailbreak/404/"/><meta property="og:locale" content="en"/><meta property="og:description"/><meta property="og:site_name" content="vJailbreak"/><meta name="twitter:card" content="summary_large_image"/><script>
|
||||||
|
window.StarlightThemeProvider = (() => {
|
||||||
|
const storedTheme =
|
||||||
|
typeof localStorage !== 'undefined' && localStorage.getItem('starlight-theme');
|
||||||
|
const theme =
|
||||||
|
storedTheme ||
|
||||||
|
(window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');
|
||||||
|
document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark';
|
||||||
|
return {
|
||||||
|
updatePickers(theme = storedTheme || 'auto') {
|
||||||
|
document.querySelectorAll('starlight-theme-select').forEach((picker) => {
|
||||||
|
const select = picker.querySelector('select');
|
||||||
|
if (select) select.value = theme;
|
||||||
|
/** @type {HTMLTemplateElement | null} */
|
||||||
|
const tmpl = document.querySelector(`#theme-icons`);
|
||||||
|
const newIcon = tmpl && tmpl.content.querySelector('.' + theme);
|
||||||
|
if (newIcon) {
|
||||||
|
const oldIcon = picker.querySelector('svg.label-icon');
|
||||||
|
if (oldIcon) {
|
||||||
|
oldIcon.replaceChildren(...newIcon.cloneNode(true).childNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
</script><template id="theme-icons"><svg aria-hidden="true" class="light astro-c6vsoqas" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M5 12a1 1 0 0 0-1-1H3a1 1 0 0 0 0 2h1a1 1 0 0 0 1-1Zm.64 5-.71.71a1 1 0 0 0 0 1.41 1 1 0 0 0 1.41 0l.71-.71A1 1 0 0 0 5.64 17ZM12 5a1 1 0 0 0 1-1V3a1 1 0 0 0-2 0v1a1 1 0 0 0 1 1Zm5.66 2.34a1 1 0 0 0 .7-.29l.71-.71a1 1 0 1 0-1.41-1.41l-.66.71a1 1 0 0 0 0 1.41 1 1 0 0 0 .66.29Zm-12-.29a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.71-.71a1.004 1.004 0 1 0-1.43 1.41l.73.71ZM21 11h-1a1 1 0 0 0 0 2h1a1 1 0 0 0 0-2Zm-2.64 6A1 1 0 0 0 17 18.36l.71.71a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.76-.66ZM12 6.5a5.5 5.5 0 1 0 5.5 5.5A5.51 5.51 0 0 0 12 6.5Zm0 9a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7Zm0 3.5a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1a1 1 0 0 0-1-1Z"/></svg> <svg aria-hidden="true" class="dark astro-c6vsoqas" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21.64 13a1 1 0 0 0-1.05-.14 8.049 8.049 0 0 1-3.37.73 8.15 8.15 0 0 1-8.14-8.1 8.59 8.59 0 0 1 .25-2A1 1 0 0 0 8 2.36a10.14 10.14 0 1 0 14 11.69 1 1 0 0 0-.36-1.05Zm-9.5 6.69A8.14 8.14 0 0 1 7.08 5.22v.27a10.15 10.15 0 0 0 10.14 10.14 9.784 9.784 0 0 0 2.1-.22 8.11 8.11 0 0 1-7.18 4.32v-.04Z"/></svg> <svg aria-hidden="true" class="auto astro-c6vsoqas" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg> </template><link rel="stylesheet" href="/vjailbreak/_astro/print.BJ0teN4y.css" media="print"><link rel="stylesheet" href="/vjailbreak/_astro/index.V9BDhjML.css">
|
||||||
|
<style>:root{--sl-badge-default-border: var(--sl-color-accent);--sl-badge-default-bg: var(--sl-color-accent-low);--sl-badge-default-text: #fff;--sl-badge-note-border: var(--sl-color-blue);--sl-badge-note-bg: var(--sl-color-blue-low);--sl-badge-note-text: #fff;--sl-badge-danger-border: var(--sl-color-red);--sl-badge-danger-bg: var(--sl-color-red-low);--sl-badge-danger-text: #fff;--sl-badge-success-border: var(--sl-color-green);--sl-badge-success-bg: var(--sl-color-green-low);--sl-badge-success-text: #fff;--sl-badge-caution-border: var(--sl-color-orange);--sl-badge-caution-bg: var(--sl-color-orange-low);--sl-badge-caution-text: #fff;--sl-badge-tip-border: var(--sl-color-purple);--sl-badge-tip-bg: var(--sl-color-purple-low);--sl-badge-tip-text: #fff}[data-theme=light]:root{--sl-badge-default-bg: var(--sl-color-accent-high);--sl-badge-note-bg: var(--sl-color-blue-high);--sl-badge-danger-bg: var(--sl-color-red-high);--sl-badge-success-bg: var(--sl-color-green-high);--sl-badge-caution-bg: var(--sl-color-orange-high);--sl-badge-tip-bg: var(--sl-color-purple-high)}.sl-badge:where(.astro-avdet4wd){display:inline-block;border:1px solid var(--sl-color-border-badge);border-radius:.25rem;font-family:var(--sl-font-system-mono);line-height:normal;color:var(--sl-color-text-badge);background-color:var(--sl-color-bg-badge);overflow-wrap:anywhere}.sidebar-content .sl-badge:where(.astro-avdet4wd){line-height:1;font-size:var(--sl-text-xs);padding:.125rem .375rem}.sidebar-content a[aria-current=page]>.sl-badge:where(.astro-avdet4wd){--sl-color-bg-badge: transparent;--sl-color-border-badge: currentColor;color:inherit}.default:where(.astro-avdet4wd){--sl-color-bg-badge: var(--sl-badge-default-bg);--sl-color-border-badge: var(--sl-badge-default-border);--sl-color-text-badge: var(--sl-badge-default-text)}.note:where(.astro-avdet4wd){--sl-color-bg-badge: var(--sl-badge-note-bg);--sl-color-border-badge: var(--sl-badge-note-border);--sl-color-text-badge: var(--sl-badge-note-text)}.danger:where(.astro-avdet4wd){--sl-color-bg-badge: var(--sl-badge-danger-bg);--sl-color-border-badge: var(--sl-badge-danger-border);--sl-color-text-badge: var(--sl-badge-danger-text)}.success:where(.astro-avdet4wd){--sl-color-bg-badge: var(--sl-badge-success-bg);--sl-color-border-badge: var(--sl-badge-success-border);--sl-color-text-badge: var(--sl-badge-success-text)}.tip:where(.astro-avdet4wd){--sl-color-bg-badge: var(--sl-badge-tip-bg);--sl-color-border-badge: var(--sl-badge-tip-border);--sl-color-text-badge: var(--sl-badge-tip-text)}.caution:where(.astro-avdet4wd){--sl-color-bg-badge: var(--sl-badge-caution-bg);--sl-color-border-badge: var(--sl-badge-caution-border);--sl-color-text-badge: var(--sl-badge-caution-text)}.small:where(.astro-avdet4wd){font-size:var(--sl-text-xs);padding:.125rem .25rem}.medium:where(.astro-avdet4wd){font-size:var(--sl-text-sm);padding:.175rem .35rem}.large:where(.astro-avdet4wd){font-size:var(--sl-text-base);padding:.225rem .45rem}.sl-markdown-content :is(h1,h2,h3,h4,h5,h6) .sl-badge:where(.astro-avdet4wd){vertical-align:middle}
|
||||||
|
.card-grid:where(.astro-zntqmydn){display:grid;grid-template-columns:100%;gap:1rem}.card-grid:where(.astro-zntqmydn)>*{margin-top:0!important}@media (min-width: 50rem){.card-grid:where(.astro-zntqmydn){grid-template-columns:1fr 1fr;gap:1.5rem}.stagger:where(.astro-zntqmydn){--stagger-height: 5rem;padding-bottom:var(--stagger-height)}.stagger:where(.astro-zntqmydn)>*:nth-child(2n){transform:translateY(var(--stagger-height))}}
|
||||||
|
.card:where(.astro-v5tidmuc){--sl-card-border: var(--sl-color-purple);--sl-card-bg: var(--sl-color-purple-low);border:1px solid var(--sl-color-gray-5);background-color:var(--sl-color-black);padding:clamp(1rem,calc(.125rem + 3vw),2.5rem);flex-direction:column;gap:clamp(.5rem,calc(.125rem + 1vw),1rem)}.card:where(.astro-v5tidmuc):nth-child(4n+1){--sl-card-border: var(--sl-color-orange);--sl-card-bg: var(--sl-color-orange-low)}.card:where(.astro-v5tidmuc):nth-child(4n+3){--sl-card-border: var(--sl-color-green);--sl-card-bg: var(--sl-color-green-low)}.card:where(.astro-v5tidmuc):nth-child(4n+4){--sl-card-border: var(--sl-color-red);--sl-card-bg: var(--sl-color-red-low)}.card:where(.astro-v5tidmuc):nth-child(4n+5){--sl-card-border: var(--sl-color-blue);--sl-card-bg: var(--sl-color-blue-low)}.title:where(.astro-v5tidmuc){font-weight:600;font-size:var(--sl-text-h4);color:var(--sl-color-white);line-height:var(--sl-line-height-headings);gap:1rem;align-items:center}.card:where(.astro-v5tidmuc) .icon:where(.astro-v5tidmuc){border:1px solid var(--sl-card-border);background-color:var(--sl-card-bg);padding:.2em;border-radius:.25rem}.card:where(.astro-v5tidmuc) .body:where(.astro-v5tidmuc){margin:0;font-size:clamp(var(--sl-text-sm),calc(.5rem + 1vw),var(--sl-text-body))}
|
||||||
|
svg:where(.astro-c6vsoqas){color:var(--sl-icon-color);font-size:var(--sl-icon-size, 1em);width:1em;height:1em}
|
||||||
|
starlight-tabs:where(.astro-esqgolmp){display:block}.tablist-wrapper:where(.astro-esqgolmp){overflow-x:auto}:where(.astro-esqgolmp)[role=tablist]{display:flex;list-style:none;border-bottom:2px solid var(--sl-color-gray-5);padding:0}.tab:where(.astro-esqgolmp){margin-bottom:-2px}.tab:where(.astro-esqgolmp)>:where(.astro-esqgolmp)[role=tab]{display:flex;align-items:center;gap:.5rem;padding:0 1.25rem;text-decoration:none;border-bottom:2px solid var(--sl-color-gray-5);color:var(--sl-color-gray-3);outline-offset:var(--sl-outline-offset-inside);overflow-wrap:initial}.tab:where(.astro-esqgolmp) :where(.astro-esqgolmp)[role=tab][aria-selected=true]{color:var(--sl-color-white);border-color:var(--sl-color-text-accent);font-weight:600}.tablist-wrapper:where(.astro-esqgolmp)~[role=tabpanel]{margin-top:1rem}
|
||||||
|
.sl-steps{--bullet-size: calc(var(--sl-line-height) * 1rem);--bullet-margin: .375rem;list-style:none;counter-reset:steps-counter var(--sl-steps-start, 0);padding-inline-start:0}.sl-steps>li{counter-increment:steps-counter;position:relative;padding-inline-start:calc(var(--bullet-size) + 1rem);padding-bottom:1px;min-height:calc(var(--bullet-size) + var(--bullet-margin))}.sl-steps>li+li{margin-top:0}.sl-steps>li:before{content:counter(steps-counter);position:absolute;top:0;inset-inline-start:0;width:var(--bullet-size);height:var(--bullet-size);line-height:var(--bullet-size);font-size:var(--sl-text-xs);font-weight:600;text-align:center;color:var(--sl-color-white);background-color:var(--sl-color-gray-6);border-radius:99rem;box-shadow:inset 0 0 0 1px var(--sl-color-gray-5)}.sl-steps>li:after{--guide-width: 1px;content:"";position:absolute;top:calc(var(--bullet-size) + var(--bullet-margin));bottom:var(--bullet-margin);inset-inline-start:calc((var(--bullet-size) - var(--guide-width)) / 2);width:var(--guide-width);background-color:var(--sl-color-hairline-light)}.sl-steps>li>:first-child{--lh: calc(1em * var(--sl-line-height));--shift-y: calc(.5 * (var(--bullet-size) - var(--lh)));transform:translateY(var(--shift-y));margin-bottom:var(--shift-y)}.sl-steps>li>:first-child:where(h1,h2,h3,h4,h5,h6){--lh: calc(1em * var(--sl-line-height-headings))}@supports (--prop: 1lh){.sl-steps>li>:first-child{--lh: 1lh}}
|
||||||
|
.sl-link-button:where(.astro-xwgiixxa){align-items:center;border:1px solid transparent;border-radius:999rem;display:inline-flex;font-size:var(--sl-text-sm);gap:.5em;line-height:1.1875;outline-offset:.25rem;padding:.4375rem 1.125rem;text-decoration:none}.sl-link-button:where(.astro-xwgiixxa).primary{background:var(--sl-color-text-accent);border-color:var(--sl-color-text-accent);color:var(--sl-color-black)}.sl-link-button:where(.astro-xwgiixxa).primary:hover{color:var(--sl-color-black)}.sl-link-button:where(.astro-xwgiixxa).secondary{border-color:inherit;color:var(--sl-color-white)}.sl-link-button:where(.astro-xwgiixxa).minimal{color:var(--sl-color-white);padding-inline:0}.sl-link-button:where(.astro-xwgiixxa) svg{flex-shrink:0}@media (min-width: 50rem){.sl-link-button:where(.astro-xwgiixxa){font-size:var(--sl-text-base);padding:.9375rem 1.25rem}}.sl-markdown-content .sl-link-button:where(.astro-xwgiixxa){margin-inline-end:1rem}.sl-markdown-content .sl-link-button:where(.astro-xwgiixxa):not(:where(p *)){margin-block:1rem}
|
||||||
|
</style><script type="module" src="/vjailbreak/_astro/page.Es7s6Xc5.js"></script></head> <body class="astro-bguv2lll"> <a href="#_top" class="astro-7q3lir66">Skip to content</a> <div class="page sl-flex astro-vrdttmbt"> <header class="header astro-vrdttmbt"><div class="header sl-flex astro-3ef6ksr2"> <div class="title-wrapper sl-flex astro-3ef6ksr2"> <a href="/vjailbreak/" class="site-title sl-flex astro-m46x6ez3"> <img class="astro-m46x6ez3" alt src="/vjailbreak/_astro/platform9-logo.PaszzYBQ.svg" width="120" height="60"> <span class="sr-only astro-m46x6ez3" translate="no"> vJailbreak </span> </a> </div> <div class="sl-flex print:hidden astro-3ef6ksr2"> <site-search class="astro-3ef6ksr2 astro-v37mnknz" data-translations="{"placeholder":"Search"}"> <button data-open-modal disabled aria-label="Search" aria-keyshortcuts="Control+K" class="astro-v37mnknz"> <svg aria-hidden="true" class="astro-v37mnknz astro-c6vsoqas" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21.71 20.29 18 16.61A9 9 0 1 0 16.61 18l3.68 3.68a.999.999 0 0 0 1.42 0 1 1 0 0 0 0-1.39ZM11 18a7 7 0 1 1 0-14 7 7 0 0 1 0 14Z"/></svg> <span class="sl-hidden md:sl-block astro-v37mnknz" aria-hidden="true">Search</span> <kbd class="sl-hidden md:sl-flex astro-v37mnknz" style="display: none;"> <kbd class="astro-v37mnknz">Ctrl</kbd><kbd class="astro-v37mnknz">K</kbd> </kbd> </button> <dialog style="padding:0" aria-label="Search" class="astro-v37mnknz"> <div class="dialog-frame sl-flex astro-v37mnknz"> <button data-close-modal class="sl-flex md:sl-hidden astro-v37mnknz"> Cancel </button> <div class="search-container astro-v37mnknz"> <div id="starlight__search" class="astro-v37mnknz"></div> </div> </div> </dialog> </site-search> <script>
|
||||||
|
(() => {
|
||||||
|
const openBtn = document.querySelector('button[data-open-modal]');
|
||||||
|
const shortcut = openBtn?.querySelector('kbd');
|
||||||
|
if (!openBtn || !(shortcut instanceof HTMLElement)) return;
|
||||||
|
const platformKey = shortcut.querySelector('kbd');
|
||||||
|
if (platformKey && /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {
|
||||||
|
platformKey.textContent = '⌘';
|
||||||
|
openBtn.setAttribute('aria-keyshortcuts', 'Meta+K');
|
||||||
|
}
|
||||||
|
shortcut.style.display = '';
|
||||||
|
})();
|
||||||
|
</script> <script type="module" src="/vjailbreak/_astro/Search.astro_astro_type_script_index_0_lang.PKSD7nbt.js"></script> </div> <div class="sl-hidden md:sl-flex print:hidden right-group astro-3ef6ksr2"> <div class="sl-flex social-icons astro-3ef6ksr2"> <a href="https://github.com/platform9/vjailbreak" rel="me" class="sl-flex astro-wy4te6ga"><span class="sr-only astro-wy4te6ga">GitHub</span><svg aria-hidden="true" class="astro-wy4te6ga astro-c6vsoqas" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M12 .3a12 12 0 0 0-3.8 23.38c.6.12.83-.26.83-.57L9 21.07c-3.34.72-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.08-.74.09-.73.09-.73 1.2.09 1.83 1.24 1.83 1.24 1.08 1.83 2.81 1.3 3.5 1 .1-.78.42-1.31.76-1.61-2.67-.3-5.47-1.33-5.47-5.93 0-1.31.47-2.38 1.24-3.22-.14-.3-.54-1.52.1-3.18 0 0 1-.32 3.3 1.23a11.5 11.5 0 0 1 6 0c2.28-1.55 3.29-1.23 3.29-1.23.64 1.66.24 2.88.12 3.18a4.65 4.65 0 0 1 1.23 3.22c0 4.61-2.8 5.63-5.48 5.92.42.36.81 1.1.81 2.22l-.01 3.29c0 .31.2.69.82.57A12 12 0 0 0 12 .3Z"/></svg> </a><a href="https://join.slack.com/t/vjailbreak/shared_invite/zt-314pppw43-F1vzd6ZaPW5PoZqF~aa8lA" rel="me" class="sl-flex astro-wy4te6ga"><span class="sr-only astro-wy4te6ga">Slack</span><svg aria-hidden="true" class="astro-wy4te6ga astro-c6vsoqas" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52Zm1.271 0a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313ZM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834Zm0 1.271a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312Zm10.122 2.521a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834Zm-1.268 0a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312Zm-2.523 10.122a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52Zm0-1.268a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313Z"/></svg> </a> </div> <div class="sl-flex release-dropdown astro-3ef6ksr2"> <!-- Dropdown --><div class="select-container"> <label for="release-select" class="select-label">Latest Release:</label> <select id="release-select" class="release-select"> <option>Loading releases...</option> </select> </div> <script>(function(){const astroBaseURL = "https://platform9.github.io/";
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
const CACHE_KEY = 'githubReleases';
|
||||||
|
const CACHE_EXPIRY = 60 * 60 * 1000; // 1 hour
|
||||||
|
const select = document.getElementById('release-select');
|
||||||
|
|
||||||
|
// Check cache first
|
||||||
|
if (typeof window !== 'undefined' && window.localStorage) {
|
||||||
|
const cachedReleases = localStorage.getItem(CACHE_KEY);
|
||||||
|
const cacheExpiry = localStorage.getItem(`${CACHE_KEY}_expiry`);
|
||||||
|
|
||||||
|
if (cachedReleases && cacheExpiry && Date.now() < Number(cacheExpiry)) {
|
||||||
|
try {
|
||||||
|
console.debug("Reading releases from cache:", JSON.parse(cachedReleases)); // Debug log
|
||||||
|
populateDropdown(JSON.parse(cachedReleases));
|
||||||
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Cache corrupted clearing", e);
|
||||||
|
localStorage.removeItem(CACHE_KEY)
|
||||||
|
localStorage.removeItem(`${CACHE_KEY}_expiry`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.debug("Fetching releases from GitHub"); // Debug log
|
||||||
|
const response = await fetch('https://api.github.com/repos/platform9/vjailbreak/releases');
|
||||||
|
const data = await response.json();
|
||||||
|
const releases = data.slice(0, 5);
|
||||||
|
|
||||||
|
// Store in cache
|
||||||
|
if (typeof window !== 'undefined' && window.localStorage) {
|
||||||
|
localStorage.setItem(CACHE_KEY, JSON.stringify(releases));
|
||||||
|
localStorage.setItem(`${CACHE_KEY}_expiry`, String(Date.now() + CACHE_EXPIRY));
|
||||||
|
}
|
||||||
|
|
||||||
|
populateDropdown(releases);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching releases:", error);
|
||||||
|
populateDropdown([{
|
||||||
|
id: 0,
|
||||||
|
name: "v0.1.7",
|
||||||
|
html_url: "https://github.com/platform9/vjailbreak/releases/tag/v0.1.7"
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateDropdown(releases) {
|
||||||
|
const currentURL = astroBaseURL || window.location.origin; // Use Astro.site if available
|
||||||
|
const pathPrefix = astroBaseURL ? '/vjailbreak/release_docs/' : '/release_docs/';
|
||||||
|
select.innerHTML = releases.map(release => {
|
||||||
|
const nameModified = release.name.replace(/\./g, '');
|
||||||
|
const releaseDocsURL = `${currentURL}${pathPrefix}${nameModified}/`;
|
||||||
|
return `<option value="${release.name}">${release.name}</option>`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
select.selectedIndex = 0;
|
||||||
|
|
||||||
|
localStorage.setItem('vjailbreakSelectedVersion', select.value);
|
||||||
|
select.onchange = (e) => {
|
||||||
|
localStorage.setItem('vjailbreakSelectedVersion', e.target.value);
|
||||||
|
|
||||||
|
const version = e.target.value;
|
||||||
|
const btns = document.querySelectorAll('.version-btn');
|
||||||
|
btns.forEach(btn => {
|
||||||
|
if (btn.textContent === version) {
|
||||||
|
btn.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();</script> </div> <starlight-theme-select> <label style="--sl-select-width: 6.25em" class="astro-4yphtoen"> <span class="sr-only astro-4yphtoen">Select theme</span> <svg aria-hidden="true" class="icon label-icon astro-4yphtoen astro-c6vsoqas" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg> <select value="auto" autocomplete="off" class="astro-4yphtoen"> <option value="dark" class="astro-4yphtoen">Dark</option><option value="light" class="astro-4yphtoen">Light</option><option value="auto" selected class="astro-4yphtoen">Auto</option> </select> <svg aria-hidden="true" class="icon caret astro-4yphtoen astro-c6vsoqas" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M17 9.17a1 1 0 0 0-1.41 0L12 12.71 8.46 9.17a1 1 0 1 0-1.41 1.42l4.24 4.24a1.002 1.002 0 0 0 1.42 0L17 10.59a1.002 1.002 0 0 0 0-1.42Z"/></svg> </label> </starlight-theme-select> <script>
|
||||||
|
StarlightThemeProvider.updatePickers();
|
||||||
|
</script> <script type="module">const r="starlight-theme",o=e=>e==="auto"||e==="dark"||e==="light"?e:"auto",c=()=>o(typeof localStorage<"u"&&localStorage.getItem(r));function n(e){typeof localStorage<"u"&&localStorage.setItem(r,e==="light"||e==="dark"?e:"")}const l=()=>matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";function t(e){StarlightThemeProvider.updatePickers(e),document.documentElement.dataset.theme=e==="auto"?l():e,n(e)}matchMedia("(prefers-color-scheme: light)").addEventListener("change",()=>{c()==="auto"&&t("auto")});class s extends HTMLElement{constructor(){super(),t(c()),this.querySelector("select")?.addEventListener("change",a=>{a.currentTarget instanceof HTMLSelectElement&&t(o(a.currentTarget.value))})}}customElements.define("starlight-theme-select",s);</script> <script type="module">class s extends HTMLElement{constructor(){super();const e=this.querySelector("select");e&&(e.addEventListener("change",t=>{t.currentTarget instanceof HTMLSelectElement&&(window.location.pathname=t.currentTarget.value)}),window.addEventListener("pageshow",t=>{if(!t.persisted)return;const n=e.querySelector("option[selected]")?.index;n!==e.selectedIndex&&(e.selectedIndex=n??0)}))}}customElements.define("starlight-lang-select",s);</script> </div> </div> </header> <div class="main-frame astro-vrdttmbt"> <script type="module">const a=document.getElementById("starlight__sidebar"),n=a?.querySelector("sl-sidebar-state-persist"),o="sl-sidebar-state",i=()=>{let t=[];const e=n?.dataset.hash||"";try{const s=sessionStorage.getItem(o),r=JSON.parse(s||"{}");Array.isArray(r.open)&&r.hash===e&&(t=r.open)}catch{}return{hash:e,open:t,scroll:a?.scrollTop||0}},c=t=>{try{sessionStorage.setItem(o,JSON.stringify(t))}catch{}},d=()=>c(i()),l=(t,e)=>{const s=i();s.open[e]=t,c(s)};n?.addEventListener("click",t=>{if(!(t.target instanceof Element))return;const e=t.target.closest("summary")?.closest("details");if(!e)return;const s=e.querySelector("sl-sidebar-restore"),r=parseInt(s?.dataset.index||"");isNaN(r)||l(!e.open,r)});addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&d()});addEventListener("pageHide",d);</script> <div class="lg:sl-flex astro-67yu43on"> <div class="main-pane astro-67yu43on"> <main class="astro-bguv2lll" lang="en" dir="ltr"> <div class="content-panel astro-7nkwcw3z"> <div class="sl-container astro-7nkwcw3z"> <div class="hero astro-jbfsktt5"> <div class="sl-flex stack astro-jbfsktt5"> <div class="sl-flex copy astro-jbfsktt5"> <h1 id="_top" data-page-title class="astro-jbfsktt5">404</h1> <div class="tagline astro-jbfsktt5">Page not found. Check the URL or try using the search bar.</div> </div> </div> </div> <div class="sl-markdown-content"> </div> <footer class="sl-flex astro-3yyafb3n"> <div class="meta sl-flex astro-3yyafb3n"> </div> <div class="pagination-links print:hidden astro-u2l5gyhi" dir="ltr"> </div> </footer> </div> </div> </main> </div> </div> </div> </div> </body></html>
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Starlight Starter Kit: Basics
|
||||||
|
|
||||||
|
[](https://starlight.astro.build)
|
||||||
|
|
||||||
|
```
|
||||||
|
npm create astro@latest -- --template starlight
|
||||||
|
```
|
||||||
|
|
||||||
|
[](https://stackblitz.com/github/withastro/starlight/tree/main/examples/basics)
|
||||||
|
[](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/basics)
|
||||||
|
[](https://app.netlify.com/start/deploy?repository=https://github.com/withastro/starlight&create_from_path=examples/basics)
|
||||||
|
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fwithastro%2Fstarlight%2Ftree%2Fmain%2Fexamples%2Fbasics&project-name=my-starlight-docs&repository-name=my-starlight-docs)
|
||||||
|
|
||||||
|
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
||||||
|
|
||||||
|
## 🚀 Project Structure
|
||||||
|
|
||||||
|
Inside of your Astro + Starlight project, you'll see the following folders and files:
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── public/
|
||||||
|
├── src/
|
||||||
|
│ ├── assets/
|
||||||
|
│ ├── content/
|
||||||
|
│ │ ├── docs/
|
||||||
|
│ └── content.config.ts
|
||||||
|
├── astro.config.mjs
|
||||||
|
├── package.json
|
||||||
|
└── tsconfig.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.
|
||||||
|
|
||||||
|
Images can be added to `src/assets/` and embedded in Markdown with a relative link.
|
||||||
|
|
||||||
|
Static assets, like favicons, can be placed in the `public/` directory.
|
||||||
|
|
||||||
|
## 🧞 Commands
|
||||||
|
|
||||||
|
All commands are run from the root of the project, from a terminal:
|
||||||
|
|
||||||
|
| Command | Action |
|
||||||
|
| :------------------------ | :----------------------------------------------- |
|
||||||
|
| `npm install` | Installs dependencies |
|
||||||
|
| `npm run dev` | Starts local dev server at `localhost:4321` |
|
||||||
|
| `npm run build` | Build your production site to `./dist/` |
|
||||||
|
| `npm run preview` | Preview your build locally, before deploying |
|
||||||
|
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
||||||
|
| `npm run astro -- --help` | Get help using the Astro CLI |
|
||||||
|
|
||||||
|
## 👀 Want to learn more?
|
||||||
|
|
||||||
|
Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import{S as r}from"./TableOfContents.astro_astro_type_script_index_0_lang.CKWWgpjV.js";class c extends r{set current(e){super.current=e;const t=this.querySelector(".display-current");t&&(t.textContent=e.textContent)}constructor(){super();const e=this.querySelector("details");if(!e)return;const t=()=>{e.open=!1};e.querySelectorAll("a").forEach(s=>{s.addEventListener("click",t)}),window.addEventListener("click",s=>{e.contains(s.target)||t()}),window.addEventListener("keydown",s=>{if(s.key==="Escape"&&e.open){const o=e.contains(document.activeElement);if(t(),o){const n=e.querySelector("summary");n&&n.focus()}}})}}customElements.define("mobile-starlight-toc",c);
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["_astro/ui-core.BqAjPdsf.js","_astro/preload-helper.D6OiyG8N.js"])))=>i.map(i=>d[i]);
|
||||||
|
import{_ as p}from"./preload-helper.D6OiyG8N.js";const g={ranking:{pageLength:.1,termFrequency:.1,termSaturation:2,termSimilarity:9}};class h extends HTMLElement{constructor(){super();const r=this.querySelector("button[data-open-modal]"),u=this.querySelector("button[data-close-modal]"),a=this.querySelector("dialog"),m=this.querySelector(".dialog-frame"),i=e=>{("href"in(e.target||{})||document.body.contains(e.target)&&!m.contains(e.target))&&n()},l=e=>{a.showModal(),document.body.toggleAttribute("data-search-modal-open",!0),this.querySelector("input")?.focus(),e?.stopPropagation(),window.addEventListener("click",i)},n=()=>a.close();r.addEventListener("click",l),r.disabled=!1,u.addEventListener("click",n),a.addEventListener("close",()=>{document.body.toggleAttribute("data-search-modal-open",!1),window.removeEventListener("click",i)}),window.addEventListener("keydown",e=>{(e.metaKey===!0||e.ctrlKey===!0)&&e.key==="k"&&(a.open?n():l(),e.preventDefault())});let d={};try{d=JSON.parse(this.dataset.translations||"{}")}catch{}const c=this.dataset.stripTrailingSlash!==void 0?e=>e.replace(/(.)\/(#.*)?$/,"$1$2"):e=>e;window.addEventListener("DOMContentLoaded",()=>{(window.requestIdleCallback||(o=>setTimeout(o,1)))(async()=>{const{PagefindUI:o}=await p(async()=>{const{PagefindUI:t}=await import("./ui-core.BqAjPdsf.js");return{PagefindUI:t}},__vite__mapDeps([0,1]));new o({...g,element:"#starlight__search",baseUrl:"/vjailbreak/",bundlePath:"/vjailbreak/".replace(/\/$/,"")+"/pagefind/",showImages:!1,translations:d,showSubResults:!0,processResult:t=>{t.url=c(t.url),t.sub_results=t.sub_results.map(s=>(s.url=c(s.url),s))}})})})}}customElements.define("site-search",h);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
const g="_top";class f extends HTMLElement{constructor(){super(),this._current=this.querySelector('a[aria-current="true"]'),this.minH=parseInt(this.dataset.minH||"2",10),this.maxH=parseInt(this.dataset.maxH||"3",10),this.onIdle=e=>(window.requestIdleCallback||(o=>setTimeout(o,1)))(e),this.init=()=>{const e=[...this.querySelectorAll("a")],o=t=>{if(t instanceof HTMLHeadingElement){if(t.id===g)return!0;const s=t.tagName[1];if(s){const n=parseInt(s,10);if(n>=this.minH&&n<=this.maxH)return!0}}return!1},i=t=>{if(!t)return null;const s=t;for(;t;){if(o(t))return t;for(t=t.previousElementSibling;t?.lastElementChild;)t=t.lastElementChild;const n=i(t);if(n)return n}return i(s.parentElement)},c=t=>{for(const{isIntersecting:s,target:n}of t){if(!s)continue;const l=i(n);if(!l)continue;const m=e.find(d=>d.hash==="#"+encodeURIComponent(l.id));if(m){this.current=m;break}}},a=document.querySelectorAll("main [id], main [id] ~ *, main .content > *");let r;const u=()=>{r||(r=new IntersectionObserver(c,{rootMargin:this.getRootMargin()}),a.forEach(t=>r.observe(t)))};u();let h;window.addEventListener("resize",()=>{r&&(r.disconnect(),r=void 0),clearTimeout(h),h=setTimeout(()=>this.onIdle(u),200)})},this.onIdle(()=>this.init())}set current(e){e!==this._current&&(this._current&&this._current.removeAttribute("aria-current"),e.setAttribute("aria-current","true"),this._current=e)}getRootMargin(){const e=document.querySelector("header")?.getBoundingClientRect().height||0,o=this.querySelector("summary")?.getBoundingClientRect().height||0,i=e+o+32,c=i+53,a=document.documentElement.clientHeight;return`-${i}px 0% ${c-a}px`}}customElements.define("starlight-toc",f);export{f as S};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import{e as x,c as O,g as m,k as P,h as p,j as w,l as c,m as A,n as I,t as N,o as E}from"./_baseUniq.DrZ7Fcz9.js";import{aQ as g,ar as F,aR as M,aS as T,aT as _,aU as l,aV as $,aW as B,aX as S,aY as y}from"./mermaid.core.BGhbGlGd.js";var R=/\s/;function G(n){for(var r=n.length;r--&&R.test(n.charAt(r)););return r}var H=/^\s+/;function L(n){return n&&n.slice(0,G(n)+1).replace(H,"")}var o=NaN,W=/^[-+]0x[0-9a-f]+$/i,X=/^0b[01]+$/i,Y=/^0o[0-7]+$/i,q=parseInt;function z(n){if(typeof n=="number")return n;if(x(n))return o;if(g(n)){var r=typeof n.valueOf=="function"?n.valueOf():n;n=g(r)?r+"":r}if(typeof n!="string")return n===0?n:+n;n=L(n);var t=X.test(n);return t||Y.test(n)?q(n.slice(2),t?2:8):W.test(n)?o:+n}var v=1/0,C=17976931348623157e292;function K(n){if(!n)return n===0?n:0;if(n=z(n),n===v||n===-v){var r=n<0?-1:1;return r*C}return n===n?n:0}function Q(n){var r=K(n),t=r%1;return r===r?t?r-t:r:0}function fn(n){var r=n==null?0:n.length;return r?O(n):[]}var b=Object.prototype,U=b.hasOwnProperty,dn=F(function(n,r){n=Object(n);var t=-1,i=r.length,a=i>2?r[2]:void 0;for(a&&M(r[0],r[1],a)&&(i=1);++t<i;)for(var f=r[t],e=T(f),s=-1,d=e.length;++s<d;){var u=e[s],h=n[u];(h===void 0||_(h,b[u])&&!U.call(n,u))&&(n[u]=f[u])}return n});function un(n){var r=n==null?0:n.length;return r?n[r-1]:void 0}function D(n){return function(r,t,i){var a=Object(r);if(!l(r)){var f=m(t);r=P(r),t=function(s){return f(a[s],s,a)}}var e=n(r,t,i);return e>-1?a[f?r[e]:e]:void 0}}var J=Math.max;function Z(n,r,t){var i=n==null?0:n.length;if(!i)return-1;var a=t==null?0:Q(t);return a<0&&(a=J(i+a,0)),p(n,m(r),a)}var hn=D(Z);function V(n,r){var t=-1,i=l(n)?Array(n.length):[];return w(n,function(a,f,e){i[++t]=r(a,f,e)}),i}function gn(n,r){var t=$(n)?c:V;return t(n,m(r))}var j=Object.prototype,k=j.hasOwnProperty;function nn(n,r){return n!=null&&k.call(n,r)}function mn(n,r){return n!=null&&A(n,r,nn)}function rn(n,r){return n<r}function tn(n,r,t){for(var i=-1,a=n.length;++i<a;){var f=n[i],e=r(f);if(e!=null&&(s===void 0?e===e&&!x(e):t(e,s)))var s=e,d=f}return d}function on(n){return n&&n.length?tn(n,B,rn):void 0}function an(n,r,t,i){if(!g(n))return n;r=I(r,n);for(var a=-1,f=r.length,e=f-1,s=n;s!=null&&++a<f;){var d=N(r[a]),u=t;if(d==="__proto__"||d==="constructor"||d==="prototype")return n;if(a!=e){var h=s[d];u=void 0,u===void 0&&(u=g(h)?h:S(r[a+1])?[]:{})}y(s,d,u),s=s[d]}return n}function vn(n,r,t){for(var i=-1,a=r.length,f={};++i<a;){var e=r[i],s=E(n,e);t(s,e)&&an(f,I(e,n),s)}return f}export{rn as a,tn as b,V as c,vn as d,on as e,fn as f,hn as g,mn as h,dn as i,Q as j,un as l,gn as m,K as t};
|
||||||
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1 @@
|
|||||||
|
import{a0 as ln,a1 as an,a2 as H,a3 as q,a4 as B,a5 as un,a6 as y,a7 as tn,a8 as L,a9 as _,aa as rn,ab as o,ac as sn,ad as on,ae as fn}from"./mermaid.core.BGhbGlGd.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,C,a){var O=I-l,i=D-h,n=C-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function W(l,h,I,D,v,A,C){var a=l-I,O=h-D,i=(C?A:-A)/L(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,F=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*L(on(0,T*T*R-P*P)),j=(P*g-m*S)/R,z=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=j-F,e=z-t,r=w-F,G=p-t;return x*x+e*e>r*r+G*G&&(j=w,z=p),{cx:j,cy:z,x01:-n,y01:-d,x11:j*(v/T-1),y11:z*(v/T-1)}}function hn(){var l=cn,h=yn,I=B(0),D=null,v=gn,A=dn,C=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,F=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(F>tn-y)a.moveTo(s*H(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*H(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=F,S=F,j=C.apply(this,arguments)/2,z=j>y&&(D?+D.apply(this,arguments):L(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if(z>y){var G=sn(z/u*q(j)),M=sn(z/s*q(j));(P-=G*2)>y?(G*=t?1:-1,R+=G,T-=G):(P=0,R=T=(f+c)/2),(S-=M*2)>y?(M*=t?1:-1,m+=M,g-=M):(S=0,m=g=(f+c)/2)}var J=s*H(m),K=s*q(m),N=u*H(T),Q=u*q(T);if(w>y){var U=s*H(g),V=s*q(g),X=u*H(R),Y=u*q(R),E;if(F<an)if(E=pn(J,K,X,Y,U,V,N,Q)){var Z=J-E[0],$=K-E[1],b=U-E[0],k=V-E[1],nn=1/q(fn((Z*b+$*k)/(L(Z*Z+$*$)*L(b*b+k*k)))/2),en=L(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=W(X,Y,J,K,s,x,t),r=W(U,V,N,Q,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(J,K),a.arc(0,0,s,m,g,!t)):a.moveTo(J,K),!(u>y)||!(P>y)?a.lineTo(N,Q):p>y?(e=W(N,Q,U,V,u,-p,t),r=W(J,K,X,Y,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[H(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:B(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:B(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:B(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:B(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:B(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:B(+n),i):A},i.padAngle=function(n){return arguments.length?(C=typeof n=="function"?n:B(+n),i):C},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import{ai as o,aj as n}from"./mermaid.core.BGhbGlGd.js";const t=(a,r)=>o.lang.round(n.parse(a)[r]);export{t as c};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import{_ as i}from"./mermaid.core.BGhbGlGd.js";function t(c,e){c.accDescr&&e.setAccDescription?.(c.accDescr),c.accTitle&&e.setAccTitle?.(c.accTitle),c.title&&e.setDiagramTitle?.(c.title)}i(t,"populateCommonDb");export{t as p};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import{_ as n,U as o,j as l}from"./mermaid.core.BGhbGlGd.js";var x=n((s,t)=>{const e=s.append("rect");if(e.attr("x",t.x),e.attr("y",t.y),e.attr("fill",t.fill),e.attr("stroke",t.stroke),e.attr("width",t.width),e.attr("height",t.height),t.name&&e.attr("name",t.name),t.rx&&e.attr("rx",t.rx),t.ry&&e.attr("ry",t.ry),t.attrs!==void 0)for(const r in t.attrs)e.attr(r,t.attrs[r]);return t.class&&e.attr("class",t.class),e},"drawRect"),d=n((s,t)=>{const e={x:t.startx,y:t.starty,width:t.stopx-t.startx,height:t.stopy-t.starty,fill:t.fill,stroke:t.stroke,class:"rect"};x(s,e).lower()},"drawBackgroundRect"),g=n((s,t)=>{const e=t.text.replace(o," "),r=s.append("text");r.attr("x",t.x),r.attr("y",t.y),r.attr("class","legend"),r.style("text-anchor",t.anchor),t.class&&r.attr("class",t.class);const a=r.append("tspan");return a.attr("x",t.x+t.textMargin*2),a.text(e),r},"drawText"),h=n((s,t,e,r)=>{const a=s.append("image");a.attr("x",t),a.attr("y",e);const i=l.sanitizeUrl(r);a.attr("xlink:href",i)},"drawImage"),m=n((s,t,e,r)=>{const a=s.append("use");a.attr("x",t),a.attr("y",e);const i=l.sanitizeUrl(r);a.attr("xlink:href",`#${i}`)},"drawEmbeddedImage"),y=n(()=>({x:0,y:0,width:100,height:100,fill:"#EDF2AE",stroke:"#666",anchor:"start",rx:0,ry:0}),"getNoteRect"),p=n(()=>({x:0,y:0,width:100,height:100,"text-anchor":"start",style:"#666",textMargin:0,rx:0,ry:0,tspan:!0}),"getTextObj");export{d as a,p as b,m as c,x as d,h as e,g as f,y as g};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import{_ as i}from"./mermaid.core.BGhbGlGd.js";var r=class{constructor(t){this.init=t,this.records=this.init()}static{i(this,"ImperativeState")}reset(){this.records=this.init()}};export{r as I};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import{_ as a,d as o}from"./mermaid.core.BGhbGlGd.js";var d=a((t,e)=>{let n;return e==="sandbox"&&(n=o("#i"+t)),(e==="sandbox"?o(n.nodes()[0].contentDocument.body):o("body")).select(`[id="${t}"]`)},"getDiagramElement");export{d as g};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import{_ as e}from"./mermaid.core.BGhbGlGd.js";var l=e(()=>`
|
||||||
|
/* Font Awesome icon styling - consolidated */
|
||||||
|
.label-icon {
|
||||||
|
display: inline-block;
|
||||||
|
height: 1em;
|
||||||
|
overflow: visible;
|
||||||
|
vertical-align: -0.125em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node .label-icon path {
|
||||||
|
fill: currentColor;
|
||||||
|
stroke: revert;
|
||||||
|
stroke-width: revert;
|
||||||
|
}
|
||||||
|
`,"getIconStyles");export{l as g};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import{_ as a,e as w,l as x}from"./mermaid.core.BGhbGlGd.js";var d=a((e,t,i,r)=>{e.attr("class",i);const{width:o,height:h,x:n,y:c}=u(e,t);w(e,h,o,r);const s=l(n,c,o,h,t);e.attr("viewBox",s),x.debug(`viewBox configured: ${s} with padding: ${t}`)},"setupViewPortForSVG"),u=a((e,t)=>{const i=e.node()?.getBBox()||{width:0,height:0,x:0,y:0};return{width:i.width+t*2,height:i.height+t*2,x:i.x,y:i.y}},"calculateDimensionsWithPadding"),l=a((e,t,i,r,o)=>`${e-o} ${t-o} ${i} ${r}`,"createViewBox");export{d as s};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import{s as a,c as s,a as e,C as t}from"./chunk-SZ463SBG.D54NqtH8.js";import{_ as i}from"./mermaid.core.BGhbGlGd.js";import"./chunk-E2GYISFI.C5auD6vd.js";import"./chunk-BFAMUDN2.Dg0ATuDz.js";import"./chunk-SKB7J2MH.DthSJpGM.js";import"./preload-helper.D6OiyG8N.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import{s as a,c as s,a as e,C as t}from"./chunk-SZ463SBG.D54NqtH8.js";import{_ as i}from"./mermaid.core.BGhbGlGd.js";import"./chunk-E2GYISFI.C5auD6vd.js";import"./chunk-BFAMUDN2.Dg0ATuDz.js";import"./chunk-SKB7J2MH.DthSJpGM.js";import"./preload-helper.D6OiyG8N.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
|
||||||
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 66 KiB |
@@ -0,0 +1 @@
|
|||||||
|
import{b as r}from"./_baseUniq.DrZ7Fcz9.js";var e=4;function a(o){return r(o,e)}export{a as c};
|
||||||
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 80 KiB |
@@ -0,0 +1 @@
|
|||||||
|
function H(n){return Math.abs(n=Math.round(n))>=1e21?n.toLocaleString("en").replace(/,/g,""):n.toString(10)}function j(n,t){if((e=(n=t?n.toExponential(t-1):n.toExponential()).indexOf("e"))<0)return null;var e,i=n.slice(0,e);return[i.length>1?i[0]+i.slice(2):i,+n.slice(e+1)]}function J(n){return n=j(Math.abs(n)),n?n[1]:NaN}function K(n,t){return function(e,i){for(var o=e.length,f=[],c=0,u=n[0],p=0;o>0&&u>0&&(p+u+1>i&&(u=Math.max(1,i-p)),f.push(e.substring(o-=u,o+u)),!((p+=u+1)>i));)u=n[c=(c+1)%n.length];return f.reverse().join(t)}}function Q(n){return function(t){return t.replace(/[0-9]/g,function(e){return n[+e]})}}var V=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function N(n){if(!(t=V.exec(n)))throw new Error("invalid format: "+n);var t;return new $({fill:t[1],align:t[2],sign:t[3],symbol:t[4],zero:t[5],width:t[6],comma:t[7],precision:t[8]&&t[8].slice(1),trim:t[9],type:t[10]})}N.prototype=$.prototype;function $(n){this.fill=n.fill===void 0?" ":n.fill+"",this.align=n.align===void 0?">":n.align+"",this.sign=n.sign===void 0?"-":n.sign+"",this.symbol=n.symbol===void 0?"":n.symbol+"",this.zero=!!n.zero,this.width=n.width===void 0?void 0:+n.width,this.comma=!!n.comma,this.precision=n.precision===void 0?void 0:+n.precision,this.trim=!!n.trim,this.type=n.type===void 0?"":n.type+""}$.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(this.width===void 0?"":Math.max(1,this.width|0))+(this.comma?",":"")+(this.precision===void 0?"":"."+Math.max(0,this.precision|0))+(this.trim?"~":"")+this.type};function W(n){n:for(var t=n.length,e=1,i=-1,o;e<t;++e)switch(n[e]){case".":i=o=e;break;case"0":i===0&&(i=e),o=e;break;default:if(!+n[e])break n;i>0&&(i=0);break}return i>0?n.slice(0,i)+n.slice(o+1):n}var U;function _(n,t){var e=j(n,t);if(!e)return n+"";var i=e[0],o=e[1],f=o-(U=Math.max(-8,Math.min(8,Math.floor(o/3)))*3)+1,c=i.length;return f===c?i:f>c?i+new Array(f-c+1).join("0"):f>0?i.slice(0,f)+"."+i.slice(f):"0."+new Array(1-f).join("0")+j(n,Math.max(0,t+f-1))[0]}function G(n,t){var e=j(n,t);if(!e)return n+"";var i=e[0],o=e[1];return o<0?"0."+new Array(-o).join("0")+i:i.length>o+1?i.slice(0,o+1)+"."+i.slice(o+1):i+new Array(o-i.length+2).join("0")}const I={"%":(n,t)=>(n*100).toFixed(t),b:n=>Math.round(n).toString(2),c:n=>n+"",d:H,e:(n,t)=>n.toExponential(t),f:(n,t)=>n.toFixed(t),g:(n,t)=>n.toPrecision(t),o:n=>Math.round(n).toString(8),p:(n,t)=>G(n*100,t),r:G,s:_,X:n=>Math.round(n).toString(16).toUpperCase(),x:n=>Math.round(n).toString(16)};function X(n){return n}var O=Array.prototype.map,R=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function v(n){var t=n.grouping===void 0||n.thousands===void 0?X:K(O.call(n.grouping,Number),n.thousands+""),e=n.currency===void 0?"":n.currency[0]+"",i=n.currency===void 0?"":n.currency[1]+"",o=n.decimal===void 0?".":n.decimal+"",f=n.numerals===void 0?X:Q(O.call(n.numerals,String)),c=n.percent===void 0?"%":n.percent+"",u=n.minus===void 0?"−":n.minus+"",p=n.nan===void 0?"NaN":n.nan+"";function F(a){a=N(a);var x=a.fill,M=a.align,m=a.sign,w=a.symbol,l=a.zero,S=a.width,E=a.comma,g=a.precision,L=a.trim,d=a.type;d==="n"?(E=!0,d="g"):I[d]||(g===void 0&&(g=12),L=!0,d="g"),(l||x==="0"&&M==="=")&&(l=!0,x="0",M="=");var Z=w==="$"?e:w==="#"&&/[boxX]/.test(d)?"0"+d.toLowerCase():"",q=w==="$"?i:/[%p]/.test(d)?c:"",T=I[d],B=/[defgprs%]/.test(d);g=g===void 0?6:/[gprs]/.test(d)?Math.max(1,Math.min(21,g)):Math.max(0,Math.min(20,g));function C(r){var y=Z,h=q,b,D,k;if(d==="c")h=T(r)+h,r="";else{r=+r;var P=r<0||1/r<0;if(r=isNaN(r)?p:T(Math.abs(r),g),L&&(r=W(r)),P&&+r==0&&m!=="+"&&(P=!1),y=(P?m==="("?m:u:m==="-"||m==="("?"":m)+y,h=(d==="s"?R[8+U/3]:"")+h+(P&&m==="("?")":""),B){for(b=-1,D=r.length;++b<D;)if(k=r.charCodeAt(b),48>k||k>57){h=(k===46?o+r.slice(b+1):r.slice(b))+h,r=r.slice(0,b);break}}}E&&!l&&(r=t(r,1/0));var z=y.length+r.length+h.length,s=z<S?new Array(S-z+1).join(x):"";switch(E&&l&&(r=t(s+r,s.length?S-h.length:1/0),s=""),M){case"<":r=y+r+h+s;break;case"=":r=y+s+r+h;break;case"^":r=s.slice(0,z=s.length>>1)+y+r+h+s.slice(z);break;default:r=s+y+r+h;break}return f(r)}return C.toString=function(){return a+""},C}function Y(a,x){var M=F((a=N(a),a.type="f",a)),m=Math.max(-8,Math.min(8,Math.floor(J(x)/3)))*3,w=Math.pow(10,-m),l=R[8+m/3];return function(S){return M(w*S)+l}}return{format:F,formatPrefix:Y}}var A,nn,tn;rn({thousands:",",grouping:[3],currency:["$",""]});function rn(n){return A=v(n),nn=A.format,tn=A.formatPrefix,A}export{tn as a,nn as b,J as e,N as f};
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import{p as y}from"./chunk-353BL4L5.DKwi8utJ.js";import{_ as l,s as B,g as S,q as F,p as z,a as E,b as P,D as m,H as W,e as D,y as T,E as _,F as A,l as w}from"./mermaid.core.BGhbGlGd.js";import{p as N}from"./treemap-75Q7IDZK.BJixwsOc.js";import"./preload-helper.D6OiyG8N.js";import"./_baseUniq.DrZ7Fcz9.js";import"./_basePickBy.Blj6Mziw.js";import"./clone.CJouE3HP.js";var x={packet:[]},v=structuredClone(x),L=A.packet,Y=l(()=>{const t=m({...L,..._().packet});return t.showBits&&(t.paddingY+=10),t},"getConfig"),H=l(()=>v.packet,"getPacket"),I=l(t=>{t.length>0&&v.packet.push(t)},"pushWord"),M=l(()=>{T(),v=structuredClone(x)},"clear"),u={pushWord:I,getPacket:H,getConfig:Y,clear:M,setAccTitle:P,getAccTitle:E,setDiagramTitle:z,getDiagramTitle:F,getAccDescription:S,setAccDescription:B},O=1e4,q=l(t=>{y(t,u);let e=-1,o=[],s=1;const{bitsPerRow:n}=u.getConfig();for(let{start:a,end:r,bits:c,label:f}of t.blocks){if(a!==void 0&&r!==void 0&&r<a)throw new Error(`Packet block ${a} - ${r} is invalid. End must be greater than start.`);if(a??=e+1,a!==e+1)throw new Error(`Packet block ${a} - ${r??a} is not contiguous. It should start from ${e+1}.`);if(c===0)throw new Error(`Packet block ${a} is invalid. Cannot have a zero bit field.`);for(r??=a+(c??1)-1,c??=r-a+1,e=r,w.debug(`Packet block ${a} - ${e} with label ${f}`);o.length<=n+1&&u.getPacket().length<O;){const[d,p]=G({start:a,end:r,bits:c,label:f},s,n);if(o.push(d),d.end+1===s*n&&(u.pushWord(o),o=[],s++),!p)break;({start:a,end:r,bits:c,label:f}=p)}}u.pushWord(o)},"populate"),G=l((t,e,o)=>{if(t.start===void 0)throw new Error("start should have been set during first phase");if(t.end===void 0)throw new Error("end should have been set during first phase");if(t.start>t.end)throw new Error(`Block start ${t.start} is greater than block end ${t.end}.`);if(t.end+1<=e*o)return[t,void 0];const s=e*o-1,n=e*o;return[{start:t.start,end:s,label:t.label,bits:s-t.start},{start:n,end:t.end,label:t.label,bits:t.end-n}]},"getNextFittingBlock"),K={parse:l(async t=>{const e=await N("packet",t);w.debug(e),q(e)},"parse")},R=l((t,e,o,s)=>{const n=s.db,a=n.getConfig(),{rowHeight:r,paddingY:c,bitWidth:f,bitsPerRow:d}=a,p=n.getPacket(),i=n.getDiagramTitle(),k=r+c,g=k*(p.length+1)-(i?0:r),b=f*d+2,h=W(e);h.attr("viewbox",`0 0 ${b} ${g}`),D(h,g,b,a.useMaxWidth);for(const[C,$]of p.entries())U(h,$,C,a);h.append("text").text(i).attr("x",b/2).attr("y",g-k/2).attr("dominant-baseline","middle").attr("text-anchor","middle").attr("class","packetTitle")},"draw"),U=l((t,e,o,{rowHeight:s,paddingX:n,paddingY:a,bitWidth:r,bitsPerRow:c,showBits:f})=>{const d=t.append("g"),p=o*(s+a)+a;for(const i of e){const k=i.start%c*r+1,g=(i.end-i.start+1)*r-n;if(d.append("rect").attr("x",k).attr("y",p).attr("width",g).attr("height",s).attr("class","packetBlock"),d.append("text").attr("x",k+g/2).attr("y",p+s/2).attr("class","packetLabel").attr("dominant-baseline","middle").attr("text-anchor","middle").text(i.label),!f)continue;const b=i.end===i.start,h=p-2;d.append("text").attr("x",k+(b?g/2:0)).attr("y",h).attr("class","packetByte start").attr("dominant-baseline","auto").attr("text-anchor",b?"middle":"start").text(i.start),b||d.append("text").attr("x",k+g).attr("y",h).attr("class","packetByte end").attr("dominant-baseline","auto").attr("text-anchor","end").text(i.end)}},"drawWord"),X={draw:R},j={byteFontSize:"10px",startByteColor:"black",endByteColor:"black",labelColor:"black",labelFontSize:"12px",titleColor:"black",titleFontSize:"14px",blockStrokeColor:"black",blockStrokeWidth:"1",blockFillColor:"#efefef"},J=l(({packet:t}={})=>{const e=m(j,t);return`
|
||||||
|
.packetByte {
|
||||||
|
font-size: ${e.byteFontSize};
|
||||||
|
}
|
||||||
|
.packetByte.start {
|
||||||
|
fill: ${e.startByteColor};
|
||||||
|
}
|
||||||
|
.packetByte.end {
|
||||||
|
fill: ${e.endByteColor};
|
||||||
|
}
|
||||||
|
.packetLabel {
|
||||||
|
fill: ${e.labelColor};
|
||||||
|
font-size: ${e.labelFontSize};
|
||||||
|
}
|
||||||
|
.packetTitle {
|
||||||
|
fill: ${e.titleColor};
|
||||||
|
font-size: ${e.titleFontSize};
|
||||||
|
}
|
||||||
|
.packetBlock {
|
||||||
|
stroke: ${e.blockStrokeColor};
|
||||||
|
stroke-width: ${e.blockStrokeWidth};
|
||||||
|
fill: ${e.blockFillColor};
|
||||||
|
}
|
||||||
|
`},"styles"),ot={parser:K,db:u,renderer:X,styles:J};export{ot as diagram};
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import{p as k}from"./chunk-353BL4L5.DKwi8utJ.js";import{_ as l,s as R,g as E,q as F,p as I,a as _,b as D,H as G,y as P,D as f,E as C,F as z,l as H,K as V}from"./mermaid.core.BGhbGlGd.js";import{p as W}from"./treemap-75Q7IDZK.BJixwsOc.js";import"./preload-helper.D6OiyG8N.js";import"./_baseUniq.DrZ7Fcz9.js";import"./_basePickBy.Blj6Mziw.js";import"./clone.CJouE3HP.js";var h={showLegend:!0,ticks:5,max:null,min:0,graticule:"circle"},w={axes:[],curves:[],options:h},m=structuredClone(w),B=z.radar,j=l(()=>f({...B,...C().radar}),"getConfig"),b=l(()=>m.axes,"getAxes"),q=l(()=>m.curves,"getCurves"),K=l(()=>m.options,"getOptions"),N=l(a=>{m.axes=a.map(t=>({name:t.name,label:t.label??t.name}))},"setAxes"),U=l(a=>{m.curves=a.map(t=>({name:t.name,label:t.label??t.name,entries:X(t.entries)}))},"setCurves"),X=l(a=>{if(a[0].axis==null)return a.map(e=>e.value);const t=b();if(t.length===0)throw new Error("Axes must be populated before curves for reference entries");return t.map(e=>{const r=a.find(s=>s.axis?.$refText===e.name);if(r===void 0)throw new Error("Missing entry for axis "+e.label);return r.value})},"computeCurveEntries"),Y=l(a=>{const t=a.reduce((e,r)=>(e[r.name]=r,e),{});m.options={showLegend:t.showLegend?.value??h.showLegend,ticks:t.ticks?.value??h.ticks,max:t.max?.value??h.max,min:t.min?.value??h.min,graticule:t.graticule?.value??h.graticule}},"setOptions"),Z=l(()=>{P(),m=structuredClone(w)},"clear"),$={getAxes:b,getCurves:q,getOptions:K,setAxes:N,setCurves:U,setOptions:Y,getConfig:j,clear:Z,setAccTitle:D,getAccTitle:_,setDiagramTitle:I,getDiagramTitle:F,getAccDescription:E,setAccDescription:R},J=l(a=>{k(a,$);const{axes:t,curves:e,options:r}=a;$.setAxes(t),$.setCurves(e),$.setOptions(r)},"populate"),Q={parse:l(async a=>{const t=await W("radar",a);H.debug(t),J(t)},"parse")},tt=l((a,t,e,r)=>{const s=r.db,o=s.getAxes(),i=s.getCurves(),n=s.getOptions(),c=s.getConfig(),d=s.getDiagramTitle(),u=G(t),p=et(u,c),g=n.max??Math.max(...i.map(y=>Math.max(...y.entries))),x=n.min,v=Math.min(c.width,c.height)/2;at(p,o,v,n.ticks,n.graticule),rt(p,o,v,c),M(p,o,i,x,g,n.graticule,c),T(p,i,n.showLegend,c),p.append("text").attr("class","radarTitle").text(d).attr("x",0).attr("y",-c.height/2-c.marginTop)},"draw"),et=l((a,t)=>{const e=t.width+t.marginLeft+t.marginRight,r=t.height+t.marginTop+t.marginBottom,s={x:t.marginLeft+t.width/2,y:t.marginTop+t.height/2};return a.attr("viewbox",`0 0 ${e} ${r}`).attr("width",e).attr("height",r),a.append("g").attr("transform",`translate(${s.x}, ${s.y})`)},"drawFrame"),at=l((a,t,e,r,s)=>{if(s==="circle")for(let o=0;o<r;o++){const i=e*(o+1)/r;a.append("circle").attr("r",i).attr("class","radarGraticule")}else if(s==="polygon"){const o=t.length;for(let i=0;i<r;i++){const n=e*(i+1)/r,c=t.map((d,u)=>{const p=2*u*Math.PI/o-Math.PI/2,g=n*Math.cos(p),x=n*Math.sin(p);return`${g},${x}`}).join(" ");a.append("polygon").attr("points",c).attr("class","radarGraticule")}}},"drawGraticule"),rt=l((a,t,e,r)=>{const s=t.length;for(let o=0;o<s;o++){const i=t[o].label,n=2*o*Math.PI/s-Math.PI/2;a.append("line").attr("x1",0).attr("y1",0).attr("x2",e*r.axisScaleFactor*Math.cos(n)).attr("y2",e*r.axisScaleFactor*Math.sin(n)).attr("class","radarAxisLine"),a.append("text").text(i).attr("x",e*r.axisLabelFactor*Math.cos(n)).attr("y",e*r.axisLabelFactor*Math.sin(n)).attr("class","radarAxisLabel")}},"drawAxes");function M(a,t,e,r,s,o,i){const n=t.length,c=Math.min(i.width,i.height)/2;e.forEach((d,u)=>{if(d.entries.length!==n)return;const p=d.entries.map((g,x)=>{const v=2*Math.PI*x/n-Math.PI/2,y=A(g,r,s,c),O=y*Math.cos(v),S=y*Math.sin(v);return{x:O,y:S}});o==="circle"?a.append("path").attr("d",L(p,i.curveTension)).attr("class",`radarCurve-${u}`):o==="polygon"&&a.append("polygon").attr("points",p.map(g=>`${g.x},${g.y}`).join(" ")).attr("class",`radarCurve-${u}`)})}l(M,"drawCurves");function A(a,t,e,r){const s=Math.min(Math.max(a,t),e);return r*(s-t)/(e-t)}l(A,"relativeRadius");function L(a,t){const e=a.length;let r=`M${a[0].x},${a[0].y}`;for(let s=0;s<e;s++){const o=a[(s-1+e)%e],i=a[s],n=a[(s+1)%e],c=a[(s+2)%e],d={x:i.x+(n.x-o.x)*t,y:i.y+(n.y-o.y)*t},u={x:n.x-(c.x-i.x)*t,y:n.y-(c.y-i.y)*t};r+=` C${d.x},${d.y} ${u.x},${u.y} ${n.x},${n.y}`}return`${r} Z`}l(L,"closedRoundCurve");function T(a,t,e,r){if(!e)return;const s=(r.width/2+r.marginRight)*3/4,o=-(r.height/2+r.marginTop)*3/4,i=20;t.forEach((n,c)=>{const d=a.append("g").attr("transform",`translate(${s}, ${o+c*i})`);d.append("rect").attr("width",12).attr("height",12).attr("class",`radarLegendBox-${c}`),d.append("text").attr("x",16).attr("y",0).attr("class","radarLegendText").text(n.label)})}l(T,"drawLegend");var st={draw:tt},nt=l((a,t)=>{let e="";for(let r=0;r<a.THEME_COLOR_LIMIT;r++){const s=a[`cScale${r}`];e+=`
|
||||||
|
.radarCurve-${r} {
|
||||||
|
color: ${s};
|
||||||
|
fill: ${s};
|
||||||
|
fill-opacity: ${t.curveOpacity};
|
||||||
|
stroke: ${s};
|
||||||
|
stroke-width: ${t.curveStrokeWidth};
|
||||||
|
}
|
||||||
|
.radarLegendBox-${r} {
|
||||||
|
fill: ${s};
|
||||||
|
fill-opacity: ${t.curveOpacity};
|
||||||
|
stroke: ${s};
|
||||||
|
}
|
||||||
|
`}return e},"genIndexStyles"),ot=l(a=>{const t=V(),e=C(),r=f(t,e.themeVariables),s=f(r.radar,a);return{themeVariables:r,radarOptions:s}},"buildRadarStyleOptions"),it=l(({radar:a}={})=>{const{themeVariables:t,radarOptions:e}=ot(a);return`
|
||||||
|
.radarTitle {
|
||||||
|
font-size: ${t.fontSize};
|
||||||
|
color: ${t.titleColor};
|
||||||
|
dominant-baseline: hanging;
|
||||||
|
text-anchor: middle;
|
||||||
|
}
|
||||||
|
.radarAxisLine {
|
||||||
|
stroke: ${e.axisColor};
|
||||||
|
stroke-width: ${e.axisStrokeWidth};
|
||||||
|
}
|
||||||
|
.radarAxisLabel {
|
||||||
|
dominant-baseline: middle;
|
||||||
|
text-anchor: middle;
|
||||||
|
font-size: ${e.axisLabelFontSize}px;
|
||||||
|
color: ${e.axisColor};
|
||||||
|
}
|
||||||
|
.radarGraticule {
|
||||||
|
fill: ${e.graticuleColor};
|
||||||
|
fill-opacity: ${e.graticuleOpacity};
|
||||||
|
stroke: ${e.graticuleColor};
|
||||||
|
stroke-width: ${e.graticuleStrokeWidth};
|
||||||
|
}
|
||||||
|
.radarLegendText {
|
||||||
|
text-anchor: start;
|
||||||
|
font-size: ${e.legendFontSize}px;
|
||||||
|
dominant-baseline: hanging;
|
||||||
|
}
|
||||||
|
${nt(t,e)}
|
||||||
|
`},"styles"),ht={parser:Q,db:$,renderer:st,styles:it};export{ht as diagram};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
try{(()=>{function a(e){if(!e)return;let t=e.getAttribute("tabindex")!==null,n=e.scrollWidth>e.clientWidth;n&&!t?e.setAttribute("tabindex","0"):!n&&t&&e.removeAttribute("tabindex")}var u=window.requestIdleCallback||(e=>setTimeout(e,1)),i=window.cancelIdleCallback||clearTimeout;function l(e){let t=new Set,n,r;return new ResizeObserver(c=>{c.forEach(o=>t.add(o.target)),n&&clearTimeout(n),r&&i(r),n=setTimeout(()=>{r&&i(r),r=u(()=>{t.forEach(o=>e(o)),t.clear()})},250)})}function d(e,t){e.querySelectorAll?.(".expressive-code pre > code").forEach(n=>{let r=n.parentElement;r&&t.observe(r)})}var s=l(a);d(document,s);var b=new MutationObserver(e=>e.forEach(t=>t.addedNodes.forEach(n=>{d(n,s)})));b.observe(document.body,{childList:!0,subtree:!0});document.addEventListener("astro:page-load",()=>{d(document,s)});})();}catch(e){console.error("[EC] tabindex-js-module failed:",e)}
|
||||||
|
try{(()=>{function i(o){let e=document.createElement("pre");Object.assign(e.style,{opacity:"0",pointerEvents:"none",position:"absolute",overflow:"hidden",left:"0",top:"0",width:"20px",height:"20px",webkitUserSelect:"auto",userSelect:"all"}),e.ariaHidden="true",e.textContent=o,document.body.appendChild(e);let a=document.createRange();a.selectNode(e);let n=getSelection();if(!n)return!1;n.removeAllRanges(),n.addRange(a);let r=!1;try{r=document.execCommand("copy")}finally{n.removeAllRanges(),document.body.removeChild(e)}return r}async function l(o){let e=o.currentTarget,a=e.dataset,n=!1,r=a.code.replace(/\u007f/g,`
|
||||||
|
`);try{await navigator.clipboard.writeText(r),n=!0}catch{n=i(r)}if(!n||e.parentNode?.querySelector(".feedback"))return;let t=document.createElement("div");t.classList.add("feedback"),t.append(a.copied),e.before(t),t.offsetWidth,requestAnimationFrame(()=>t?.classList.add("show"));let c=()=>!t||t.classList.remove("show"),d=()=>{!t||parseFloat(getComputedStyle(t).opacity)>0||(t.remove(),t=void 0)};setTimeout(c,1500),setTimeout(d,2500),e.addEventListener("blur",c),t.addEventListener("transitioncancel",d),t.addEventListener("transitionend",d)}function s(o){o.querySelectorAll?.(".expressive-code .copy button").forEach(e=>e.addEventListener("click",l))}s(document);var u=new MutationObserver(o=>o.forEach(e=>e.addedNodes.forEach(a=>{s(a)})));u.observe(document.body,{childList:!0,subtree:!0});document.addEventListener("astro:page-load",()=>{s(document)});})();}catch(e){console.error("[EC] copy-js-module failed:",e)}
|
||||||
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,2 @@
|
|||||||
|
import{_ as e,l as s,H as n,e as i,I as p}from"./mermaid.core.BGhbGlGd.js";import{p as g}from"./treemap-75Q7IDZK.BJixwsOc.js";import"./preload-helper.D6OiyG8N.js";import"./_baseUniq.DrZ7Fcz9.js";import"./_basePickBy.Blj6Mziw.js";import"./clone.CJouE3HP.js";var v={parse:e(async r=>{const a=await g("info",r);s.debug(a)},"parse")},d={version:p.version+""},m=e(()=>d.version,"getVersion"),c={getVersion:m},l=e((r,a,o)=>{s.debug(`rendering info diagram
|
||||||
|
`+r);const t=n(a);i(t,100,400,!0),t.append("g").append("text").attr("x",100).attr("y",40).attr("class","version").attr("font-size",32).style("text-anchor","middle").text(`v${o}`)},"draw"),f={draw:l},z={parser:v,db:c,renderer:f};export{z as diagram};
|
||||||
|
After Width: | Height: | Size: 73 KiB |
@@ -0,0 +1 @@
|
|||||||
|
function t(e,a){switch(arguments.length){case 0:break;case 1:this.range(e);break;default:this.range(a).domain(e);break}return this}export{t as i};
|
||||||
|
After Width: | Height: | Size: 93 KiB |
@@ -0,0 +1 @@
|
|||||||
|
import{i as a}from"./init.Gi6I4Gst.js";class o extends Map{constructor(n,t=g){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:t}}),n!=null)for(const[r,s]of n)this.set(r,s)}get(n){return super.get(c(this,n))}has(n){return super.has(c(this,n))}set(n,t){return super.set(l(this,n),t)}delete(n){return super.delete(p(this,n))}}function c({_intern:e,_key:n},t){const r=n(t);return e.has(r)?e.get(r):t}function l({_intern:e,_key:n},t){const r=n(t);return e.has(r)?e.get(r):(e.set(r,t),t)}function p({_intern:e,_key:n},t){const r=n(t);return e.has(r)&&(t=e.get(r),e.delete(r)),t}function g(e){return e!==null&&typeof e=="object"?e.valueOf():e}const f=Symbol("implicit");function h(){var e=new o,n=[],t=[],r=f;function s(u){let i=e.get(u);if(i===void 0){if(r!==f)return r;e.set(u,i=n.push(u)-1)}return t[i%t.length]}return s.domain=function(u){if(!arguments.length)return n.slice();n=[],e=new o;for(const i of u)e.has(i)||e.set(i,n.push(i)-1);return s},s.range=function(u){return arguments.length?(t=Array.from(u),s):t.slice()},s.unknown=function(u){return arguments.length?(r=u,s):r},s.copy=function(){return h(n,t).unknown(r)},a.apply(s,arguments),s}export{h as o};
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["_astro/mermaid.core.BGhbGlGd.js","_astro/preload-helper.D6OiyG8N.js"])))=>i.map(i=>d[i]);
|
||||||
|
import{_ as L}from"./preload-helper.D6OiyG8N.js";const v=new Set,u=new WeakSet;let g=!0,y,p=!1;function A(e){p||(p=!0,g??=!1,y??="hover",S(),T(),C(),O())}function S(){for(const e of["touchstart","mousedown"])document.body.addEventListener(e,t=>{l(t.target,"tap")&&f(t.target.href,{ignoreSlowConnection:!0})},{passive:!0})}function T(){let e;document.body.addEventListener("focusin",a=>{l(a.target,"hover")&&t(a)},{passive:!0}),document.body.addEventListener("focusout",r,{passive:!0}),h(()=>{for(const a of document.getElementsByTagName("a"))u.has(a)||l(a,"hover")&&(u.add(a),a.addEventListener("mouseenter",t,{passive:!0}),a.addEventListener("mouseleave",r,{passive:!0}))});function t(a){const i=a.target.href;e&&clearTimeout(e),e=setTimeout(()=>{f(i)},80)}function r(){e&&(clearTimeout(e),e=0)}}function C(){let e;h(()=>{for(const t of document.getElementsByTagName("a"))u.has(t)||l(t,"viewport")&&(u.add(t),e??=M(),e.observe(t))})}function M(){const e=new WeakMap;return new IntersectionObserver((t,r)=>{for(const a of t){const i=a.target,n=e.get(i);a.isIntersecting?(n&&clearTimeout(n),e.set(i,setTimeout(()=>{r.unobserve(i),e.delete(i),f(i.href)},300))):n&&(clearTimeout(n),e.delete(i))}})}function O(){h(()=>{for(const e of document.getElementsByTagName("a"))l(e,"load")&&f(e.href)})}function f(e,t){e=e.replace(/#.*/,"");const r=t?.ignoreSlowConnection??!1;if(P(e,r))if(v.add(e),document.createElement("link").relList?.supports?.("prefetch")&&t?.with!=="fetch"){const a=document.createElement("link");a.rel="prefetch",a.setAttribute("href",e),document.head.append(a)}else fetch(e,{priority:"low"})}function P(e,t){if(!navigator.onLine||!t&&k())return!1;try{const r=new URL(e,location.href);return location.origin===r.origin&&(location.pathname!==r.pathname||location.search!==r.search)&&!v.has(e)}catch{}return!1}function l(e,t){if(e?.tagName!=="A")return!1;const r=e.dataset.astroPrefetch;return r==="false"?!1:t==="tap"&&(r!=null||g)&&k()?!0:r==null&&g||r===""?t===y:r===t}function k(){if("connection"in navigator){const e=navigator.connection;return e.saveData||/2g/.test(e.effectiveType)}return!1}function h(e){e();let t=!1;document.addEventListener("astro:page-load",()=>{if(!t){t=!0;return}e()})}const b=()=>document.querySelectorAll("pre.mermaid").length>0;b()?(console.log("[astro-mermaid] Mermaid diagrams detected, loading mermaid.js..."),L(()=>import("./mermaid.core.BGhbGlGd.js").then(e=>e.bC),__vite__mapDeps([0,1])).then(async({default:e})=>{const t=[{name:"logos",loader:"() => fetch('https://unpkg.com/@iconify-json/logos@1/icons.json').then(res => res.json())"}];if(t&&t.length>0){console.log("[astro-mermaid] Registering",t.length,"icon packs");const n=t.map(s=>({name:s.name,loader:new Function("return "+s.loader)()}));await e.registerIconPacks(n)}const r={startOnLoad:!1,theme:"forest"},a={light:"default",dark:"dark"};async function i(){console.log("[astro-mermaid] Initializing mermaid diagrams...");const n=document.querySelectorAll("pre.mermaid");if(console.log("[astro-mermaid] Found",n.length,"mermaid diagrams"),n.length===0)return;let s=r.theme;{const o=document.documentElement.getAttribute("data-theme"),c=document.body.getAttribute("data-theme");s=a[o||c]||r.theme,console.log("[astro-mermaid] Using theme:",s,"from",o?"html":"body")}e.initialize({...r,theme:s,gitGraph:{mainBranchName:"main",showCommitLabel:!0,showBranches:!0,rotateCommitLabel:!0}});for(const o of n){if(o.hasAttribute("data-processed"))continue;o.hasAttribute("data-diagram")||o.setAttribute("data-diagram",o.textContent||"");const c=o.getAttribute("data-diagram")||"",d="mermaid-"+Math.random().toString(36).slice(2,11);console.log("[astro-mermaid] Rendering diagram:",d);try{const m=document.getElementById(d);m&&m.remove();const{svg:E}=await e.render(d,c);o.innerHTML=E,o.setAttribute("data-processed","true"),console.log("[astro-mermaid] Successfully rendered diagram:",d)}catch(m){console.error("[astro-mermaid] Mermaid rendering error for diagram:",d,m),o.innerHTML=`<div style="color: red; padding: 1rem; border: 1px solid red; border-radius: 0.5rem;">
|
||||||
|
<strong>Error rendering diagram:</strong><br/>
|
||||||
|
${m.message||"Unknown error"}
|
||||||
|
</div>`,o.setAttribute("data-processed","true")}}}i();{const n=new MutationObserver(s=>{for(const o of s)o.type==="attributes"&&o.attributeName==="data-theme"&&(document.querySelectorAll("pre.mermaid[data-processed]").forEach(c=>{c.removeAttribute("data-processed")}),i())});n.observe(document.documentElement,{attributes:!0,attributeFilter:["data-theme"]}),n.observe(document.body,{attributes:!0,attributeFilter:["data-theme"]})}document.addEventListener("astro:after-swap",()=>{b()&&i()})}).catch(e=>{console.error("[astro-mermaid] Failed to load mermaid:",e)})):console.log("[astro-mermaid] No mermaid diagrams found on this page, skipping mermaid.js load");const w=document.createElement("style");w.textContent=`
|
||||||
|
/* Prevent layout shifts by setting minimum height */
|
||||||
|
pre.mermaid {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 2rem 0;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
overflow: auto;
|
||||||
|
min-height: 200px; /* Prevent layout shift */
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading state with skeleton loader */
|
||||||
|
pre.mermaid:not([data-processed]) {
|
||||||
|
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
animation: shimmer 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark mode skeleton loader */
|
||||||
|
[data-theme="dark"] pre.mermaid:not([data-processed]) {
|
||||||
|
background: linear-gradient(90deg, #2a2a2a 25%, #3a3a3a 50%, #2a2a2a 75%);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shimmer {
|
||||||
|
0% {
|
||||||
|
background-position: -200% 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 200% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show processed diagrams with smooth transition */
|
||||||
|
pre.mermaid[data-processed] {
|
||||||
|
animation: none;
|
||||||
|
background: transparent;
|
||||||
|
min-height: auto; /* Allow natural height after render */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure responsive sizing for mermaid SVGs */
|
||||||
|
pre.mermaid svg {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optional: Add subtle background for better visibility */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
pre.mermaid[data-processed] {
|
||||||
|
background-color: rgba(255, 255, 255, 0.02);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
pre.mermaid[data-processed] {
|
||||||
|
background-color: rgba(0, 0, 0, 0.02);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Respect user's color scheme preference */
|
||||||
|
[data-theme="dark"] pre.mermaid[data-processed] {
|
||||||
|
background-color: rgba(255, 255, 255, 0.02);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="light"] pre.mermaid[data-processed] {
|
||||||
|
background-color: rgba(0, 0, 0, 0.02);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
`;document.head.appendChild(w);A();
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import{p as V}from"./chunk-353BL4L5.DKwi8utJ.js";import{a4 as S,a7 as z,aG as U,_ as u,g as j,s as q,a as H,b as Z,q as J,p as K,l as F,c as Q,D as X,H as Y,N as tt,e as et,y as at,F as rt}from"./mermaid.core.BGhbGlGd.js";import{p as nt}from"./treemap-75Q7IDZK.BJixwsOc.js";import{d as P}from"./arc.CuRSuedG.js";import{o as it}from"./ordinal.BYWQX77i.js";import"./preload-helper.D6OiyG8N.js";import"./_baseUniq.DrZ7Fcz9.js";import"./_basePickBy.Blj6Mziw.js";import"./clone.CJouE3HP.js";import"./init.Gi6I4Gst.js";function st(t,a){return a<t?-1:a>t?1:a>=t?0:NaN}function ot(t){return t}function lt(){var t=ot,a=st,m=null,s=S(0),p=S(z),x=S(0);function i(e){var r,l=(e=U(e)).length,d,A,h=0,c=new Array(l),n=new Array(l),v=+s.apply(this,arguments),w=Math.min(z,Math.max(-z,p.apply(this,arguments)-v)),f,T=Math.min(Math.abs(w)/l,x.apply(this,arguments)),$=T*(w<0?-1:1),g;for(r=0;r<l;++r)(g=n[c[r]=r]=+t(e[r],r,e))>0&&(h+=g);for(a!=null?c.sort(function(y,D){return a(n[y],n[D])}):m!=null&&c.sort(function(y,D){return m(e[y],e[D])}),r=0,A=h?(w-l*$)/h:0;r<l;++r,v=f)d=c[r],g=n[d],f=v+(g>0?g*A:0)+$,n[d]={data:e[d],index:r,value:g,startAngle:v,endAngle:f,padAngle:T};return n}return i.value=function(e){return arguments.length?(t=typeof e=="function"?e:S(+e),i):t},i.sortValues=function(e){return arguments.length?(a=e,m=null,i):a},i.sort=function(e){return arguments.length?(m=e,a=null,i):m},i.startAngle=function(e){return arguments.length?(s=typeof e=="function"?e:S(+e),i):s},i.endAngle=function(e){return arguments.length?(p=typeof e=="function"?e:S(+e),i):p},i.padAngle=function(e){return arguments.length?(x=typeof e=="function"?e:S(+e),i):x},i}var ct=rt.pie,G={sections:new Map,showData:!1},b=G.sections,N=G.showData,ut=structuredClone(ct),pt=u(()=>structuredClone(ut),"getConfig"),dt=u(()=>{b=new Map,N=G.showData,at()},"clear"),gt=u(({label:t,value:a})=>{b.has(t)||(b.set(t,a),F.debug(`added new section: ${t}, with value: ${a}`))},"addSection"),ft=u(()=>b,"getSections"),mt=u(t=>{N=t},"setShowData"),ht=u(()=>N,"getShowData"),R={getConfig:pt,clear:dt,setDiagramTitle:K,getDiagramTitle:J,setAccTitle:Z,getAccTitle:H,setAccDescription:q,getAccDescription:j,addSection:gt,getSections:ft,setShowData:mt,getShowData:ht},vt=u((t,a)=>{V(t,a),a.setShowData(t.showData),t.sections.map(a.addSection)},"populateDb"),yt={parse:u(async t=>{const a=await nt("pie",t);F.debug(a),vt(a,R)},"parse")},St=u(t=>`
|
||||||
|
.pieCircle{
|
||||||
|
stroke: ${t.pieStrokeColor};
|
||||||
|
stroke-width : ${t.pieStrokeWidth};
|
||||||
|
opacity : ${t.pieOpacity};
|
||||||
|
}
|
||||||
|
.pieOuterCircle{
|
||||||
|
stroke: ${t.pieOuterStrokeColor};
|
||||||
|
stroke-width: ${t.pieOuterStrokeWidth};
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
.pieTitleText {
|
||||||
|
text-anchor: middle;
|
||||||
|
font-size: ${t.pieTitleTextSize};
|
||||||
|
fill: ${t.pieTitleTextColor};
|
||||||
|
font-family: ${t.fontFamily};
|
||||||
|
}
|
||||||
|
.slice {
|
||||||
|
font-family: ${t.fontFamily};
|
||||||
|
fill: ${t.pieSectionTextColor};
|
||||||
|
font-size:${t.pieSectionTextSize};
|
||||||
|
// fill: white;
|
||||||
|
}
|
||||||
|
.legend text {
|
||||||
|
fill: ${t.pieLegendTextColor};
|
||||||
|
font-family: ${t.fontFamily};
|
||||||
|
font-size: ${t.pieLegendTextSize};
|
||||||
|
}
|
||||||
|
`,"getStyles"),xt=St,At=u(t=>{const a=[...t.entries()].map(s=>({label:s[0],value:s[1]})).sort((s,p)=>p.value-s.value);return lt().value(s=>s.value)(a)},"createPieArcs"),wt=u((t,a,m,s)=>{F.debug(`rendering pie chart
|
||||||
|
`+t);const p=s.db,x=Q(),i=X(p.getConfig(),x.pie),e=40,r=18,l=4,d=450,A=d,h=Y(a),c=h.append("g");c.attr("transform","translate("+A/2+","+d/2+")");const{themeVariables:n}=x;let[v]=tt(n.pieOuterStrokeWidth);v??=2;const w=i.textPosition,f=Math.min(A,d)/2-e,T=P().innerRadius(0).outerRadius(f),$=P().innerRadius(f*w).outerRadius(f*w);c.append("circle").attr("cx",0).attr("cy",0).attr("r",f+v/2).attr("class","pieOuterCircle");const g=p.getSections(),y=At(g),D=[n.pie1,n.pie2,n.pie3,n.pie4,n.pie5,n.pie6,n.pie7,n.pie8,n.pie9,n.pie10,n.pie11,n.pie12],C=it(D);c.selectAll("mySlices").data(y).enter().append("path").attr("d",T).attr("fill",o=>C(o.data.label)).attr("class","pieCircle");let W=0;g.forEach(o=>{W+=o}),c.selectAll("mySlices").data(y).enter().append("text").text(o=>(o.data.value/W*100).toFixed(0)+"%").attr("transform",o=>"translate("+$.centroid(o)+")").style("text-anchor","middle").attr("class","slice"),c.append("text").text(p.getDiagramTitle()).attr("x",0).attr("y",-400/2).attr("class","pieTitleText");const M=c.selectAll(".legend").data(C.domain()).enter().append("g").attr("class","legend").attr("transform",(o,k)=>{const E=r+l,L=E*C.domain().length/2,_=12*r,B=k*E-L;return"translate("+_+","+B+")"});M.append("rect").attr("width",r).attr("height",r).style("fill",C).style("stroke",C),M.data(y).append("text").attr("x",r+l).attr("y",r-l).text(o=>{const{label:k,value:E}=o.data;return p.getShowData()?`${k} [${E}]`:k});const I=Math.max(...M.selectAll("text").nodes().map(o=>o?.getBoundingClientRect().width??0)),O=A+e+r+l+I;h.attr("viewBox",`0 0 ${O} ${d}`),et(h,d,O,i.useMaxWidth)},"draw"),Dt={draw:wt},Nt={parser:yt,db:R,renderer:Dt,styles:xt};export{Nt as diagram};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2.72 -1.34 120 60" width="120" height="60"><path d="M102.768 40.478c-1.87 0-3.452 1.5-3.452 3.38 0 1.798 1.5 3.38 3.38 3.38.288 0 .575-.072.647-.072l-1.87 2.59c-.072.072-.072.144-.072.216s.144.144.216.144h.575c.144 0 .36-.144.503-.216l2.66-3.74c.072-.144.216-.36.288-.432 0-.072.575-1.08.575-1.798-.072-1.942-1.5-3.452-3.452-3.452zm2.373 3.38c0 1.295-1.08 2.373-2.373 2.373s-2.373-1.08-2.373-2.373 1.08-2.373 2.373-2.373 2.373 1.08 2.373 2.373z" fill="#00aae7"/><path d="M34.087 40.982c-.072-.144-.144-.216-.216-.216h-.72c-.144 0-.216.144-.288.216l-4.17 8.846c-.072.072-.072.216-.072.288 0 0 .072.072.144.072h.863c.072 0 .216 0 .216-.072.072-.072.072-.144.072-.216l.863-1.87c.072-.072.072-.144.072-.144h5.178c.072 0 .072 0 .072.072l.935 1.942c.072.072.072.216.288.216h.863c.072 0 .144-.072.144-.072s.072-.072 0-.144zm1.582 5.825h-4.315l2.158-4.53zm-9.925 2.23h-4.962V40.9c0-.144-.072-.216-.216-.216h-.72c-.216 0-.216.072-.216.216v9c0 .144.072.216.216.216h5.825c.144 0 .216-.072.216-.216l-.072-.647c0-.072 0-.144-.072-.216zm-12.873-8.27H8.628c-.288 0-.288.144-.288.36v8.846c0 .072.072.144.216.144h.647c.144 0 .216-.072.216-.288v-3.812c0-.072 0-.144.144-.144h3.524c1.654 0 2.805-1.08 2.805-2.59 0-1.223-.935-2.517-3.02-2.517zm1.942 2.59c0 .79-.647 1.582-1.87 1.582H9.635c-.072 0-.144-.072-.144-.144v-2.95c0-.072.072-.072.072-.072h3.38c.647 0 1.15.216 1.438.503s.432.647.432 1.08zm33.37-2.66H38.69c-.144 0-.144.072-.144.216v.575c0 .144 0 .216.216.216h4.1v8.127c0 .144.072.216.216.216h.72c.144 0 .216-.072.216-.216v-8.055h4.1c.216 0 .216-.072.216-.216V40.9c.072-.216-.072-.216-.144-.216zm34.017 2.59c0-1.295-.935-2.59-3.02-2.59h-4.243c-.288 0-.288.216-.288.36V49.9c0 .144.072.216.216.216h.647c.144 0 .216-.072.216-.288v-3.812c0-.072 0-.144.144-.144h1.438c.36.503 2.086 2.517 3.308 4.027a.55.55 0 0 0 .36.144h.863s.36 0 .216-.144l-.144-.144-3.236-3.955h.575c1.798.144 2.95-.935 2.95-2.517zm-1.08.072c0 .79-.647 1.582-1.87 1.582h-3.308c-.072 0-.144-.072-.144-.144v-2.95c0-.072.072-.072.072-.072h3.38c.647 0 1.15.216 1.438.503s.432.647.432 1.08zm-22.222-2.517h-7.264a.31.31 0 0 0-.288.288v8.918c0 .144.072.216.144.216h.79c.072 0 .144-.072.144-.144v-4.027h5.466c.072 0 .144-.072.144-.144v-.72c0-.072-.072-.144-.144-.144h-5.466v-2.95c0-.072 0-.072.072-.072h6.4c.144 0 .216-.072.216-.216v-.647c0-.072 0-.144-.072-.144 0-.216-.072-.216-.144-.216zm35.96-.144h-.575c-.144 0-.216.072-.288.144l-3.524 3.596s-.072 0-.072-.072l-3.452-3.524s-.144-.072-.288-.072h-.575c-.072 0-.216 0-.216.216v9c0 .216.072.216.216.216h.72c.072 0 .216 0 .216-.216V42.78L90.1 45.8a.55.55 0 0 0 .36.144c.216 0 .36-.144.36-.144l3.092-3.092v7.264c0 .144.072.216.216.216h.79c.144 0 .216-.072.216-.216v-9c-.072-.072-.072-.216-.288-.288zm-28.623-.216c-2.877 0-5.178 2.23-5.178 4.962s2.3 4.962 5.178 4.962 5.178-2.23 5.178-4.962-2.3-4.962-5.178-4.962zm4.027 4.9c0 2.086-1.798 3.812-4.027 3.812s-4.027-1.726-4.027-3.812 1.798-3.812 4.027-3.812c2.23.072 4.027 1.726 4.027 3.812z" fill="#00000a"/><path d="M82.068 16.98l-7.633-3.127-9.196-3.678-7.817-3.22c-.184-.092-.276 0-.276 0l-7.725 3.127-1.38.552-6.437 2.667L32.4 16.98s-.092.092 0 .092l8.644 3.494 16.093 6.62h.276l16-6.53 8.644-3.494c.276-.092 0-.184 0-.184zm-10.483-3.127l-6.437 2.575-6.437-2.575 6.437-2.667zm-7.817 3.22L57.33 19.74l-6.437-2.575 6.437-2.667zM57.24 8.06l6.437 2.667-6.437 2.667-6.437-2.667zm-7.817 3.127l6.437 2.667-6.437 2.667-6.53-2.667zM35.17 17.073l6.437-2.575 6.437 2.667-6.437 2.575zm7.91 3.22l6.437-2.667 6.437 2.667-6.437 2.575zm14.162 5.793l-6.437-2.667 6.437-2.667 6.437 2.575zm7.91-3.22l-6.437-2.575 6.437-2.667 6.437 2.575zm7.91-3.22l-6.437-2.575 6.437-2.575 6.437 2.575z" fill="#00aae7"/><path d="M63.768 17.073L57.33 19.74l-6.437-2.667 6.437-2.667zm7.817 3.22l-6.437 2.575-6.437-2.575 6.437-2.667zm-7.91 3.22l-6.437 2.575-6.345-2.575 6.437-2.667z" fill="#008ccc"/><path d="M81.15 23.878l-24 9.84-24.093-9.84 7.91-3.22 16.093 6.62h.276l16-6.53z" fill="#007bb6"/><path d="M48.043 17.073l-6.437 2.667-6.437-2.667 6.345-2.667z" fill="#68cef2"/><path d="M55.86 20.292l-6.437 2.667-6.345-2.667 6.345-2.575z" fill="#008ccc"/><path d="M55.952 13.855l-6.53 2.667-6.437-2.667 6.437-2.667zm7.817-3.22l-6.437 2.667-6.437-2.667L57.24 8.06zm7.817 3.22l-6.437 2.667-6.437-2.667 6.437-2.575zm7.817 3.22l-6.345 2.575-6.437-2.575 6.345-2.667z" fill="#68cef2"/></svg>
|
||||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1 @@
|
|||||||
|
const p="modulepreload",v=function(l){return"/vjailbreak/"+l},d={},y=function(f,c,E){let i=Promise.resolve();if(c&&c.length>0){let r=function(e){return Promise.all(e.map(o=>Promise.resolve(o).then(s=>({status:"fulfilled",value:s}),s=>({status:"rejected",reason:s}))))};document.getElementsByTagName("link");const t=document.querySelector("meta[property=csp-nonce]"),u=t?.nonce||t?.getAttribute("nonce");i=r(c.map(e=>{if(e=v(e),e in d)return;d[e]=!0;const o=e.endsWith(".css"),s=o?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${e}"]${s}`))return;const n=document.createElement("link");if(n.rel=o?"stylesheet":p,o||(n.as="script"),n.crossOrigin="",n.href=e,u&&n.setAttribute("nonce",u),document.head.appendChild(n),o)return new Promise((m,h)=>{n.addEventListener("load",m),n.addEventListener("error",()=>h(new Error(`Unable to preload CSS for ${e}`)))})}))}function a(r){const t=new Event("vite:preloadError",{cancelable:!0});if(t.payload=r,window.dispatchEvent(t),!t.defaultPrevented)throw r}return i.then(r=>{for(const t of r||[])t.status==="rejected"&&a(t.reason);return f().catch(a)})};export{y as _};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
@media print{:root[data-theme]:is(:root){--sl-color-white: hsl(224, 10%, 10%);--sl-color-gray-1: hsl(224, 14%, 16%);--sl-color-gray-2: hsl(224, 10%, 23%);--sl-color-gray-3: hsl(224, 7%, 36%);--sl-color-gray-4: hsl(224, 6%, 56%);--sl-color-gray-5: hsl(224, 6%, 77%);--sl-color-gray-6: hsl(224, 20%, 94%);--sl-color-gray-7: hsl(224, 19%, 97%);--sl-color-black: hsl(0, 0%, 100%);--sl-color-orange-high: hsl(var(--sl-hue-orange), 80%, 25%);--sl-color-orange: hsl(var(--sl-hue-orange), 90%, 60%);--sl-color-orange-low: hsl(var(--sl-hue-orange), 90%, 88%);--sl-color-green-high: hsl(var(--sl-hue-green), 80%, 22%);--sl-color-green: hsl(var(--sl-hue-green), 90%, 46%);--sl-color-green-low: hsl(var(--sl-hue-green), 85%, 90%);--sl-color-blue-high: hsl(var(--sl-hue-blue), 80%, 30%);--sl-color-blue: hsl(var(--sl-hue-blue), 90%, 60%);--sl-color-blue-low: hsl(var(--sl-hue-blue), 88%, 90%);--sl-color-purple-high: hsl(var(--sl-hue-purple), 90%, 30%);--sl-color-purple: hsl(var(--sl-hue-purple), 90%, 60%);--sl-color-purple-low: hsl(var(--sl-hue-purple), 80%, 90%);--sl-color-red-high: hsl(var(--sl-hue-red), 80%, 30%);--sl-color-red: hsl(var(--sl-hue-red), 90%, 60%);--sl-color-red-low: hsl(var(--sl-hue-red), 80%, 90%);--sl-color-accent-high: hsl(234, 80%, 30%);--sl-color-accent: hsl(234, 90%, 60%);--sl-color-accent-low: hsl(234, 88%, 90%);--sl-color-text-accent: var(--sl-color-accent);--sl-color-text-invert: var(--sl-color-black);--sl-color-bg-nav: var(--sl-color-gray-7);--sl-color-bg-sidebar: var(--sl-color-bg);--sl-color-bg-inline-code: var(--sl-color-gray-6);--sl-color-bg-accent: var(--sl-color-accent);--sl-color-hairline-light: var(--sl-color-gray-6);--sl-color-hairline-shade: var(--sl-color-gray-6);--sl-color-backdrop-overlay: hsla(225, 9%, 36%, .66);--sl-shadow-sm: none;--sl-shadow-md: none;--sl-shadow-lg: none}.print\:hidden{display:none!important}.print\:flex{display:flex!important}.print\:block{display:block!important}main{padding-bottom:0!important}main>.content-panel{padding-block-start:0!important}.content-panel+.content-panel{border:0!important}.page>header{position:relative!important}.page>.main-frame{padding-top:0;padding-inline-start:0}.main-pane{--sl-sidebar-width: 0px !important;--sl-content-width: 100% !important}.sl-banner{--sl-color-banner-text: var(--sl-color-white) !important;background-color:transparent!important}.sl-markdown-content :is(h1,h2,h3,h4,h5,h6){break-after:avoid}.sl-markdown-content :is(p,li){orphans:2;widows:2}.sl-markdown-content pre{overflow-x:hidden!important;white-space:pre-wrap!important}.sl-markdown-content .expressive-code,.sl-markdown-content figure,.sl-markdown-content pre{break-inside:avoid}.expressive-code .frame.is-terminal .header:before{box-shadow:inset 99rem 99rem var(--sl-color-gray-5)}.expressive-code .frame.has-title:not(.is-terminal) .header{background:transparent!important;border-bottom:1px solid var(--sl-color-gray-6)!important}.expressive-code .frame.has-title:not(.is-terminal) .title{background:transparent!important}.expressive-code .frame.has-title:not(.is-terminal) .title:after{border-top:0!important}.expressive-code .copy{display:none!important}.sl-markdown-content code:not(:where(.not-content *)){background-color:transparent!important;padding:0!important;margin-block:unset!important;font-size:.9375em!important}.sl-badge{background:transparent!important;color:var(--sl-color-white)!important}starlight-file-tree{break-inside:avoid}starlight-file-tree .highlight{outline:3px solid var(--sl-color-accent-low);color:var(--sl-color-text)!important;background-color:transparent!important}.starlight-aside{break-inside:avoid}.sl-link-button.primary{background:transparent!important;border-color:var(--sl-color-white)!important;color:var(--sl-color-white)!important}starlight-tabs{break-inside:avoid}.sl-steps>li:after{box-shadow:inset 99rem 99rem var(--sl-color-hairline-light)}}
|
||||||
|
After Width: | Height: | Size: 49 KiB |