diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000..1d953f4bd7 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/.github/DockerfileBackendTests b/.github/DockerfileBackendTests index b56e64d085..9fa9d788ff 100644 --- a/.github/DockerfileBackendTests +++ b/.github/DockerfileBackendTests @@ -1,5 +1,5 @@ ARG DEBIAN_IMAGE=debian:bookworm-slim -ARG RUST_IMAGE=rust:1.79-slim-bookworm +ARG RUST_IMAGE=rust:1.80-slim-bookworm ARG PYTHON_IMAGE=python:3.11.4-slim-bookworm FROM ${DEBIAN_IMAGE} as downloader @@ -11,8 +11,8 @@ SHELL ["/bin/bash", "-c"] RUN apt update -y RUN apt install -y unzip curl -RUN [ "$TARGETPLATFORM" == "linux/amd64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.41.0/deno-x86_64-unknown-linux-gnu.zip -o deno.zip || true -RUN [ "$TARGETPLATFORM" == "linux/arm64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.41.0/deno-aarch64-unknown-linux-gnu.zip -o deno.zip || true +RUN [ "$TARGETPLATFORM" == "linux/amd64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.46.3/deno-x86_64-unknown-linux-gnu.zip -o deno.zip || true +RUN [ "$TARGETPLATFORM" == "linux/arm64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.46.3/deno-aarch64-unknown-linux-gnu.zip -o deno.zip || true RUN unzip deno.zip && rm deno.zip @@ -53,7 +53,7 @@ RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VER RUN /usr/local/bin/python3 -m pip install pip-tools -COPY --from=oven/bun:1.1.8 /usr/local/bin/bun /usr/bin/bun +COPY --from=oven/bun:1.1.27 /usr/local/bin/bun /usr/bin/bun RUN [ "$TARGETPLATFORM" == "linux/amd64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.41.0/deno-x86_64-unknown-linux-gnu.zip -o deno.zip || true diff --git a/.github/change-versions.sh b/.github/change-versions.sh index 8974c283ab..77ecbc6985 100755 --- a/.github/change-versions.sh +++ b/.github/change-versions.sh @@ -7,7 +7,7 @@ VERSION=$1 echo "Updating versions to: $VERSION" sed -i -e "/^version =/s/= .*/= \"$VERSION\"/" ${root_dirpath}/backend/Cargo.toml -sed -i -e "/^export const VERSION =/s/= .*/= \"v$VERSION\";/" ${root_dirpath}/cli/main.ts +sed -i -e "/^export const VERSION =/s/= .*/= \"$VERSION\";/" ${root_dirpath}/cli/main.ts sed -i -e "/^export const VERSION =/s/= .*/= \"v$VERSION\";/" ${root_dirpath}/benchmarks/lib.ts sed -i -e "/version: /s/: .*/: $VERSION/" ${root_dirpath}/backend/windmill-api/openapi.yaml sed -i -e "/version: /s/: .*/: $VERSION/" ${root_dirpath}/openflow.openapi.yaml diff --git a/.github/workflows/backend-test.yml b/.github/workflows/backend-test.yml index 4a3a9f69e7..9963ecd4d1 100644 --- a/.github/workflows/backend-test.yml +++ b/.github/workflows/backend-test.yml @@ -29,10 +29,10 @@ jobs: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 with: - toolchain: 1.79.0 + toolchain: 1.80.0 # - uses: Swatinem/rust-cache@v2 # with: # workspaces: | diff --git a/.github/workflows/build-caddy-l4-image.yml b/.github/workflows/build-caddy-l4-image.yml index c6d9c13f8e..cafa9f8e47 100644 --- a/.github/workflows/build-caddy-l4-image.yml +++ b/.github/workflows/build-caddy-l4-image.yml @@ -16,7 +16,7 @@ jobs: - uses: depot/setup-action@v1 - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -26,7 +26,7 @@ jobs: type=raw,value=latest,enable={{is_default_branch}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} diff --git a/.github/workflows/build-staging-image.yml b/.github/workflows/build-staging-image.yml index 2940114f19..744ae83aae 100644 --- a/.github/workflows/build-staging-image.yml +++ b/.github/workflows/build-staging-image.yml @@ -34,7 +34,7 @@ jobs: - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-staging-ee @@ -45,7 +45,7 @@ jobs: type=ref,event=branch - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} diff --git a/.github/workflows/build_cli_image.yml b/.github/workflows/build_cli_image.yml index 7f66d68f9e..5b71a786aa 100644 --- a/.github/workflows/build_cli_image.yml +++ b/.github/workflows/build_cli_image.yml @@ -18,13 +18,13 @@ jobs: publish_cli: runs-on: ubicloud steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: depot/setup-action@v1 - name: Docker meta id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -35,7 +35,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} diff --git a/.github/workflows/build_ws.yml b/.github/workflows/build_ws.yml index a01f8f6cb6..cccab8bea0 100644 --- a/.github/workflows/build_ws.yml +++ b/.github/workflows/build_ws.yml @@ -16,13 +16,13 @@ jobs: publish_multiplayer: runs-on: ubicloud-standard-8 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: depot/setup-action@v1 - name: Docker meta id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -33,7 +33,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} diff --git a/.github/workflows/change-versions.yml b/.github/workflows/change-versions.yml index 65a66a6fa4..846eaa9658 100644 --- a/.github/workflows/change-versions.yml +++ b/.github/workflows/change-versions.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubicloud container: node:18 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: git config --system --add safe.directory /__w/windmill/windmill - name: Change versions run: ./.github/change-versions.sh "$(cat version.txt)" diff --git a/.github/workflows/deno_on_release.yml b/.github/workflows/deno_on_release.yml index 68c8b69aa6..61f3c3d7e6 100644 --- a/.github/workflows/deno_on_release.yml +++ b/.github/workflows/deno_on_release.yml @@ -10,7 +10,7 @@ jobs: build_deno_and_push_to_repo: runs-on: ubicloud steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: generate_deno run: | cd deno-client @@ -33,7 +33,7 @@ jobs: needs: [build_deno_and_push_to_repo] runs-on: ubicloud steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: ${{ github.repository_owner }}/${{ env.repo }} token: ${{ secrets.DENO_PAT }} diff --git a/.github/workflows/docker-image-rpi4.yml b/.github/workflows/docker-image-rpi4.yml index dd64cafe71..9fc20c3a87 100644 --- a/.github/workflows/docker-image-rpi4.yml +++ b/.github/workflows/docker-image-rpi4.yml @@ -37,7 +37,7 @@ jobs: - uses: depot/setup-action@v1 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -49,7 +49,7 @@ jobs: - name: Docker meta id: meta-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index cd1bb62cf7..d0bfd53ae8 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -1,7 +1,11 @@ env: REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.event_name != 'pull_request' && github.repository || 'windmill-labs/windmill-test' }} - DEV_SHA: ${{ github.event_name != 'pull_request' && 'dev' || format('pr-{0}', github.event.number) }} + IMAGE_NAME: + ${{ github.event_name != 'pull_request' && github.repository || + 'windmill-labs/windmill-test' }} + DEV_SHA: + ${{ github.event_name != 'pull_request' && 'dev' || format('pr-{0}', + github.event.number) }} name: Build windmill:main on: @@ -44,7 +48,7 @@ jobs: - uses: depot/setup-action@v1 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -56,7 +60,7 @@ jobs: - name: Docker meta id: meta-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -106,7 +110,7 @@ jobs: - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee @@ -117,7 +121,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -168,7 +172,7 @@ jobs: - name: Docker meta id: meta-ee-public-py312 - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-py312 @@ -179,7 +183,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -275,7 +279,7 @@ jobs: mv "${{ steps.extract-ee.outputs.destination }}/windmill" "${{ steps.extract-ee.outputs.destination }}/windmill-ee-${ARCH}" - name: Attach binary to release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: files: | ${{ steps.extract.outputs.destination }}/* @@ -319,7 +323,7 @@ jobs: # mv "${{ steps.extract-ee.outputs.destination }}/windmill" "${{ steps.extract-ee.outputs.destination }}/windmill-ee-${ARCH}" # - name: Attach binary to release - # uses: softprops/action-gh-release@v1 + # uses: softprops/action-gh-release@v2 # with: # files: | # ${{ steps.extract.outputs.destination }}/* @@ -358,7 +362,7 @@ jobs: with: fetch-depth: 0 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -377,7 +381,7 @@ jobs: with: fetch-depth: 0 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -445,7 +449,7 @@ jobs: - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-nsjail @@ -457,7 +461,7 @@ jobs: type=sha,enable=true,priority=100,prefix=,suffix=,format=short - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -472,6 +476,7 @@ jobs: file: "./docker/DockerfileNsjail" tags: | ${{ steps.meta-ee-public.outputs.tags }} + ghcr.io/windmill-labs/windmill-ee-nsjail:main labels: | ${{ steps.meta-ee-public.outputs.labels }} org.opencontainers.image.licenses=Windmill-Enterprise-License @@ -490,15 +495,15 @@ jobs: - uses: depot/setup-action@v1 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - + - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-reports @@ -536,12 +541,12 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - + - name: get git hash if: github.event_name != 'pull_request' id: git_hash @@ -557,7 +562,7 @@ jobs: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-nsjail:${{ steps.git_hash.outputs.GIT_HASH }} path: "/static_frontend/." - - uses: reggionick/s3-deploy@v3 + - uses: reggionick/s3-deploy@v4 if: github.event_name != 'pull_request' with: folder: ${{ steps.extract.outputs.destination }} @@ -580,7 +585,7 @@ jobs: - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-cuda @@ -591,7 +596,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -610,9 +615,9 @@ jobs: ${{ steps.meta-ee-public.outputs.labels }} org.opencontainers.image.licenses=Windmill-Enterprise-License - build_ee_slim: + build_slim: if: ${{ startsWith(github.ref, 'refs/tags/') }} - needs: [build_ee] + needs: [build] runs-on: ubicloud steps: - uses: actions/checkout@v4 @@ -626,10 +631,10 @@ jobs: - name: Docker meta id: meta-ee-public - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-slim + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-slim flavor: | latest=false tags: | @@ -637,7 +642,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -654,4 +659,140 @@ jobs: ${{ steps.meta-ee-public.outputs.tags }} labels: | ${{ steps.meta-ee-public.outputs.labels }} + + build_ee_slim: + if: ${{ startsWith(github.ref, 'refs/tags/') }} + needs: [build_ee] + runs-on: ubicloud + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v2 + + - uses: depot/setup-action@v1 + + - name: Docker meta + id: meta-ee-public + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-slim + flavor: | + latest=false + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push publicly ee + uses: depot/build-push-action@v1 + with: + context: . + platforms: linux/amd64 + push: true + file: "./docker/DockerfileSlimEe" + tags: | + ${{ steps.meta-ee-public.outputs.tags }} + labels: | + ${{ steps.meta-ee-public.outputs.labels }} + org.opencontainers.image.licenses=Windmill-Enterprise-License + + build_full: + if: ${{ startsWith(github.ref, 'refs/tags/') }} + needs: [build] + runs-on: ubicloud + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v2 + + - uses: depot/setup-action@v1 + + - name: Docker meta + id: meta-public + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-full + flavor: | + latest=false + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push publicly + uses: depot/build-push-action@v1 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + file: "./docker/DockerfileFull" + tags: | + ${{ steps.meta-public.outputs.tags }} + labels: | + ${{ steps.meta-public.outputs.labels }} + + build_ee_full: + if: ${{ startsWith(github.ref, 'refs/tags/') }} + needs: [build_ee] + runs-on: ubicloud + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v2 + + - uses: depot/setup-action@v1 + + - name: Docker meta + id: meta-ee-public + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-full + flavor: | + latest=false + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push publicly ee + uses: depot/build-push-action@v1 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + file: "./docker/DockerfileFullEe" + tags: | + ${{ steps.meta-ee-public.outputs.tags }} + labels: | + ${{ steps.meta-ee-public.outputs.labels }} org.opencontainers.image.licenses=Windmill-Enterprise-License diff --git a/.github/workflows/frontend-check.yml b/.github/workflows/frontend-check.yml index ac8ad4272e..845d03146d 100644 --- a/.github/workflows/frontend-check.yml +++ b/.github/workflows/frontend-check.yml @@ -10,7 +10,7 @@ jobs: npm_check: runs-on: ubicloud-standard-8 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-node@v3 with: node-version: 18 diff --git a/.github/workflows/go_on_release.yml b/.github/workflows/go_on_release.yml index 44b6a030a8..4d39d70178 100644 --- a/.github/workflows/go_on_release.yml +++ b/.github/workflows/go_on_release.yml @@ -12,7 +12,7 @@ jobs: build_go_and_push_to_repo: runs-on: ubicloud-standard-8 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 - name: install_jq run: | @@ -42,7 +42,7 @@ jobs: needs: [build_go_and_push_to_repo] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: ${{ github.repository_owner }}/${{ env.repo }} token: ${{ secrets.DENO_PAT }} diff --git a/.github/workflows/npm_on_release.yml b/.github/workflows/npm_on_release.yml index a8e28722cc..bf4af33f80 100644 --- a/.github/workflows/npm_on_release.yml +++ b/.github/workflows/npm_on_release.yml @@ -1,18 +1,33 @@ -name: Publish typescript-client +name: Publish typescript-client & CLI to NPM on release on: push: tags: - "v*" + workflow_dispatch: jobs: - build_npm: + publish_typescript_client: runs-on: ubicloud-standard-8 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "20.x" registry-url: "https://registry.npmjs.org" - - run: cd typescript-client && ./publish.sh + - run: cd typescript-client && ./publish.sh && cd .. + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + publish_cli: + runs-on: ubicloud-standard-8 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version: "20.x" + registry-url: "https://registry.npmjs.org" + - uses: denoland/setup-deno@v1 + with: + deno-version: v1.x + - run: cd cli && ./build.sh && cd npm && npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish_lsp.yml b/.github/workflows/publish_lsp.yml index f4c7ed3351..84f1f836aa 100644 --- a/.github/workflows/publish_lsp.yml +++ b/.github/workflows/publish_lsp.yml @@ -27,13 +27,13 @@ jobs: needs: [sleep] runs-on: ubicloud steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: depot/setup-action@v1 - name: Docker meta id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -44,7 +44,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Login to registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} diff --git a/.github/workflows/pypi_on_release.yml b/.github/workflows/pypi_on_release.yml index 328033d362..39a3e11b2e 100644 --- a/.github/workflows/pypi_on_release.yml +++ b/.github/workflows/pypi_on_release.yml @@ -12,7 +12,7 @@ jobs: container: image: ghcr.io/windmill-labs/python-client-builder steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Upload python client env: PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} diff --git a/.gitignore b/.gitignore index 282fa5fb48..ffda06e6cb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ frontend/src/routes/test.svelte CaddyfileRemoteMalo *.swp **/.idea/ +.direnv diff --git a/CHANGELOG.md b/CHANGELOG.md index bf2c4b711b..0e06756175 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,298 @@ # Changelog +## [1.397.1](https://github.com/windmill-labs/windmill/compare/v1.397.0...v1.397.1) (2024-09-20) + + +### Bug Fixes + +* **go:** put shared directory in job dir and not go parent ([623ece8](https://github.com/windmill-labs/windmill/commit/623ece8c6791b2c18648a68c562fcd5c8291be9b)) +* improve ability to paste from macos in vscode extension ([07372e7](https://github.com/windmill-labs/windmill/commit/07372e7e65d77df338718929f133e477a1daf993)) +* update git sync script ([30fe28c](https://github.com/windmill-labs/windmill/commit/30fe28ceecb9043eee6811dce8c3e2cd9224927b)) + +## [1.397.0](https://github.com/windmill-labs/windmill/compare/v1.396.1...v1.397.0) (2024-09-18) + + +### Features + +* ansible playbook support ([#4399](https://github.com/windmill-labs/windmill/issues/4399)) ([6855b8d](https://github.com/windmill-labs/windmill/commit/6855b8da9ad92aed514ee1ab214c9550d04e7a22)) + +## [1.396.1](https://github.com/windmill-labs/windmill/compare/v1.396.0...v1.396.1) (2024-09-18) + + +### Bug Fixes + +* postgres scripts that take longer than 20s do not timeout anymore ([37d152f](https://github.com/windmill-labs/windmill/commit/37d152feeb6abeb061daa5c93c24916e520b1fd0)) + +## [1.396.0](https://github.com/windmill-labs/windmill/compare/v1.395.0...v1.396.0) (2024-09-17) + + +### Features + +* Allow setProgress and getProgress from within the script ([#4400](https://github.com/windmill-labs/windmill/issues/4400)) ([d6d4756](https://github.com/windmill-labs/windmill/commit/d6d4756b7a40249dbc622c8a93633e8d8b8333da)) + +## [1.395.0](https://github.com/windmill-labs/windmill/compare/v1.394.6...v1.395.0) (2024-09-17) + + +### Features + +* failed key renewal alert + renew on start if no recent renewal ([#4387](https://github.com/windmill-labs/windmill/issues/4387)) ([de78f6c](https://github.com/windmill-labs/windmill/commit/de78f6c19266c67d43c7f80016a94b7988347e01)) + + +### Bug Fixes + +* cannot create duplicate apps and raw_apps ([d57b139](https://github.com/windmill-labs/windmill/commit/d57b139df2267d1650749b31a3cce5742a3654d9)) +* **cli:** update CLI schema parsers to latest ([6ba77d5](https://github.com/windmill-labs/windmill/commit/6ba77d533fc1c50cf4153730adaf1b14a466f10a)) +* **deno:** replace lock-write with frozen=false ([277d085](https://github.com/windmill-labs/windmill/commit/277d085dbed0b9b1424348cc580ba601d935759b)) +* **frontend:** add support for step id change for forloops and branch… ([#4395](https://github.com/windmill-labs/windmill/issues/4395)) ([97839a3](https://github.com/windmill-labs/windmill/commit/97839a3583ef398c11e2f51058aaceed8e7382fb)) +* **frontend:** new resource type name must be snake case ([#4396](https://github.com/windmill-labs/windmill/issues/4396)) ([9297ffc](https://github.com/windmill-labs/windmill/commit/9297ffcac4d2092022463cd68b4e8ce8f02dcb3c)) +* improve vscode extension handling of relative paths ([8ae6c32](https://github.com/windmill-labs/windmill/commit/8ae6c3262a75af378a261b49f0e3a08d668c74b3)) +* update bun to 1.1.27 ([39374d7](https://github.com/windmill-labs/windmill/commit/39374d7ee13ffa0fe1e4ded146c91869acad144c)) + +## [1.394.6](https://github.com/windmill-labs/windmill/compare/v1.394.5...v1.394.6) (2024-09-15) + + +### Bug Fixes + +* improve first time setup experience ([396258f](https://github.com/windmill-labs/windmill/commit/396258f637e65361a9d9e0285b0a42ca5189fad4)) + +## [1.394.5](https://github.com/windmill-labs/windmill/compare/v1.394.4...v1.394.5) (2024-09-13) + + +### Bug Fixes + +* add filename to s3 upload ([11ca14a](https://github.com/windmill-labs/windmill/commit/11ca14a2d32155e215c0d14d485e2c4048e5c66e)) +* parquet renderer display number of rows" ([#4389](https://github.com/windmill-labs/windmill/issues/4389)) ([51cf420](https://github.com/windmill-labs/windmill/commit/51cf420272cce1948dc4295b587f5037455c4eba)) +* queue metrics graph ([#4388](https://github.com/windmill-labs/windmill/issues/4388)) ([af85d49](https://github.com/windmill-labs/windmill/commit/af85d4936ddd01b390976c9989f3e4e72da3d01e)) +* update internal hub scritps to bun ([#4384](https://github.com/windmill-labs/windmill/issues/4384)) ([f140daf](https://github.com/windmill-labs/windmill/commit/f140daf4dc18db0a11bf478451aa57ae4698fd32)) + +## [1.394.4](https://github.com/windmill-labs/windmill/compare/v1.394.3...v1.394.4) (2024-09-13) + + +### Bug Fixes + +* **frontend:** prompt fix-AI not to rename existing variables ([#4382](https://github.com/windmill-labs/windmill/issues/4382)) ([03a2eae](https://github.com/windmill-labs/windmill/commit/03a2eae49ac5b7c858e642e9f264beebbb2e9b34)) +* **frontend:** table footer display on safari ([#4377](https://github.com/windmill-labs/windmill/issues/4377)) ([93e5ba1](https://github.com/windmill-labs/windmill/commit/93e5ba1d16fcf52dea54ae4b4d7e5b02a899d0bd)) +* **image:** correctly publish windmill-full image ([bde3339](https://github.com/windmill-labs/windmill/commit/bde3339de53ad8430df6d7add6cfb00b4eb895c6)) +* improve app select propagation to list inputs in apps ([fb4c8d2](https://github.com/windmill-labs/windmill/commit/fb4c8d266a359af1ada4541e21b68bac9cb268a8)) +* improve password input for resources editor ([5bef077](https://github.com/windmill-labs/windmill/commit/5bef077480f1d708c507d943abcb4d36de084175)) +* multiple secret picker candidates in resource adder ([f222645](https://github.com/windmill-labs/windmill/commit/f222645dcead8f6608b81be36c683df679a5ae1c)) +* tighten inputs for granular kinds ([#4379](https://github.com/windmill-labs/windmill/issues/4379)) ([ff08b5a](https://github.com/windmill-labs/windmill/commit/ff08b5a9b5606f02228d0b54b45d422704fed3cb)) +* tighten number input validity if min or max is set ([7c16f2c](https://github.com/windmill-labs/windmill/commit/7c16f2cef4943a5d02e2bc6163761d80618aeae4)) +* timeout in pg executor on postgresql connection after 20s ([4dc9ca7](https://github.com/windmill-labs/windmill/commit/4dc9ca7f4e1477c087fe4f9bf6ea03fbcc99099c)) + +## [1.394.3](https://github.com/windmill-labs/windmill/compare/v1.394.2...v1.394.3) (2024-09-11) + + +### Bug Fixes + +* improve runFlowAsync and run_flow_async default behavior + time formatting of scheduled for ([51e6f36](https://github.com/windmill-labs/windmill/commit/51e6f36e13b251f01ddb8514de0d6d1a2bcd2244)) + +## [1.394.2](https://github.com/windmill-labs/windmill/compare/v1.394.1...v1.394.2) (2024-09-11) + + +### Bug Fixes + +* add tag_override for script in flows ([0e64380](https://github.com/windmill-labs/windmill/commit/0e6438047369e0c074e93246d627ecf06c0c78d5)) +* graceful worker exits for same worker jobs ([#4371](https://github.com/windmill-labs/windmill/issues/4371)) ([042a2bf](https://github.com/windmill-labs/windmill/commit/042a2bf917173a540aab7251a559c72c9c687228)) + +## [1.394.1](https://github.com/windmill-labs/windmill/compare/v1.394.0...v1.394.1) (2024-09-11) + + +### Bug Fixes + +* default success handler key can be viewed by anyone in the workspace ([c44e0d3](https://github.com/windmill-labs/windmill/commit/c44e0d37426599186a890f11a079bf2c2030e32d)) +* handle better same_worker flow monitor ([4720237](https://github.com/windmill-labs/windmill/commit/4720237091d4f41d85d9a0f177428d7c3e6d917e)) +* same worker is transitive on nested flows ([decb487](https://github.com/windmill-labs/windmill/commit/decb4873f1d6080f90c1fb2a8dac70423ae2d11a)) + +## [1.394.0](https://github.com/windmill-labs/windmill/compare/v1.393.4...v1.394.0) (2024-09-10) + + +### Features + +* add ability to edit id in flows ([#4364](https://github.com/windmill-labs/windmill/issues/4364)) ([a19db9a](https://github.com/windmill-labs/windmill/commit/a19db9a8d36fd07ff123e09ee079128e353273ad)) + + +### Bug Fixes + +* **cli:** browser login works on npm ([cfb50ce](https://github.com/windmill-labs/windmill/commit/cfb50ce8b8cf5e0e45af4b0fc79e9741d8077c31)) +* **cli:** on node, prompt paste accept more than 8 chars ([e824d2a](https://github.com/windmill-labs/windmill/commit/e824d2a76c0bdcb8aedec190640b26e259ad1131)) +* migrate git sync to using bun based script ([6b43d7e](https://github.com/windmill-labs/windmill/commit/6b43d7e227f2af2d4838d5f816672798d1857e19)) + +## [1.393.4](https://github.com/windmill-labs/windmill/compare/v1.393.3...v1.393.4) (2024-09-09) + + +### Bug Fixes + +* bun scripts cached in docker image have their dependencies pre-loaded ([4a6c3c8](https://github.com/windmill-labs/windmill/commit/4a6c3c8cc51e9e9b15410b4894ae6065e19d6068)) +* **cli:** add --extra-includes to improve git sync capabilities ([9329006](https://github.com/windmill-labs/windmill/commit/9329006ad822e78c196d5ea6469b694d20c9a67f)) +* fix hub sync script ([4e09e7f](https://github.com/windmill-labs/windmill/commit/4e09e7f4517c26fa91820d5fe8202a36ed84ef1c)) + +## [1.393.3](https://github.com/windmill-labs/windmill/compare/v1.393.2...v1.393.3) (2024-09-07) + + +### Bug Fixes + +* **cli:** guide users to migrate to node version of the CLI ([3998ecb](https://github.com/windmill-labs/windmill/commit/3998ecbf7b5c1c1e4ed9f6fb8911e1e18317f815)) + +## [1.393.2](https://github.com/windmill-labs/windmill/compare/v1.393.1...v1.393.2) (2024-09-07) + + +### Bug Fixes + +* **cli:** add --base-url option to add possibility of setting every arg without needing to add a workspace first ([1e813b2](https://github.com/windmill-labs/windmill/commit/1e813b26103098c69ac7880876611954b0ff6996)) + +## [1.393.1](https://github.com/windmill-labs/windmill/compare/v1.393.0...v1.393.1) (2024-09-07) + + +### Bug Fixes + +* fix CLI publishing ([65cddaf](https://github.com/windmill-labs/windmill/commit/65cddaf9752722b1a9489d54e646e270ce742e1d)) + +## [1.393.0](https://github.com/windmill-labs/windmill/compare/v1.392.0...v1.393.0) (2024-09-07) + + +### Features + +* make CLI node compatible ([#4347](https://github.com/windmill-labs/windmill/issues/4347)) ([9b4c598](https://github.com/windmill-labs/windmill/commit/9b4c59809c2b30d419168e624b83379023c5cb5f)) + +## [1.392.0](https://github.com/windmill-labs/windmill/compare/v1.391.0...v1.392.0) (2024-09-06) + + +### Features + +* add load more to runs page if nb of jobs >= 1000 ([e30c344](https://github.com/windmill-labs/windmill/commit/e30c344d329e6dcfa6a560eabae00dd31e774e04)) +* schedule success handler ([#4346](https://github.com/windmill-labs/windmill/issues/4346)) ([dbd4292](https://github.com/windmill-labs/windmill/commit/dbd429226051c74acaf61807ffb13ee1c61e46b1)) + + +### Bug Fixes + +* fix error handler new script if no modules ([32f2d0f](https://github.com/windmill-labs/windmill/commit/32f2d0fc8011943524623917689ff0921ee6d906)) +* improve app reports puppeteer interactions ([df72026](https://github.com/windmill-labs/windmill/commit/df720260b8ebb2b9ccf16dd2ad89d2a13a112c60)) +* increase AI gen timeout + upgrade to 16k gpt4o ([#4340](https://github.com/windmill-labs/windmill/issues/4340)) ([067110e](https://github.com/windmill-labs/windmill/commit/067110e62f1b064268b2c2de07b7832874ace509)) +* make select not reset on user changes in app + app css fix ([8bea2e4](https://github.com/windmill-labs/windmill/commit/8bea2e473df9e59aa0b244f09bee0a84a432cb3d)) +* nativets correct transform resources in args ([50f32c4](https://github.com/windmill-labs/windmill/commit/50f32c4e12b0ece808b810bb7c67255d467a0ab2)) + +## [1.391.0](https://github.com/windmill-labs/windmill/compare/v1.390.1...v1.391.0) (2024-09-04) + + +### Features + +* add slack as a critical alert channel ([#4319](https://github.com/windmill-labs/windmill/issues/4319)) ([a7a08cf](https://github.com/windmill-labs/windmill/commit/a7a08cf9f3b40f6d90d1a1f72ad5ab6e6212b6b9)) + + +### Bug Fixes + +* improve wm_labels indices + UX nits ([ce70693](https://github.com/windmill-labs/windmill/commit/ce7069375481652f88e0417828a0a17a8f429957)) + +## [1.390.1](https://github.com/windmill-labs/windmill/compare/v1.390.0...v1.390.1) (2024-09-03) + + +### Bug Fixes + +* do not require hasNullParent only if scriptPathExact on runs search ([d172e45](https://github.com/windmill-labs/windmill/commit/d172e45766220c525e91f933f22a32738fa2709e)) +* prevent brute force attacks on tokens by slowing unauthorized response ([acfe778](https://github.com/windmill-labs/windmill/commit/acfe7786152f036f2476f93ab5536571514fa9e3)) + +## [1.390.0](https://github.com/windmill-labs/windmill/compare/v1.389.1...v1.390.0) (2024-09-02) + + +### Features + +* add yaml editor in flow builder ([71470d7](https://github.com/windmill-labs/windmill/commit/71470d7da9d3c7a52d7c5a206849f2e63ac4fa02)) + + +### Bug Fixes + +* improve dependency map to handle recusrive loops + handle better flow relative imports ([cdd7349](https://github.com/windmill-labs/windmill/commit/cdd7349f6769a0195f367a1ac27f802287a1f900)) + +## [1.389.1](https://github.com/windmill-labs/windmill/compare/v1.389.0...v1.389.1) (2024-09-02) + + +### Bug Fixes + +* fix erronous branchone status in flow viewer ([e311684](https://github.com/windmill-labs/windmill/commit/e311684a668c461538a3456c02c82a1ea6fecbc9)) +* +## [1.389.0](https://github.com/windmill-labs/windmill/compare/v1.388.0...v1.389.0) (2024-09-01) + + +### Features + +* service logs ([#4244](https://github.com/windmill-labs/windmill/issues/4244)) ([2fe48df](https://github.com/windmill-labs/windmill/commit/2fe48df720b102255832dc6438d5d64f3443207a)) + + +### Bug Fixes + +* prevent duplicate worker alerts ([#4309](https://github.com/windmill-labs/windmill/issues/4309)) ([8e30928](https://github.com/windmill-labs/windmill/commit/8e30928a78c20daef81bc4f98487ab601ecc9b58)) + +## [1.388.0](https://github.com/windmill-labs/windmill/compare/v1.387.1...v1.388.0) (2024-08-30) + + +### Features + +* add rust ([#4253](https://github.com/windmill-labs/windmill/issues/4253)) ([a2beed9](https://github.com/windmill-labs/windmill/commit/a2beed9d7335856bc956ff34343cdaf5a9b8d281)) +* min workers in worker group alert + zombie job critical alert ([#4307](https://github.com/windmill-labs/windmill/issues/4307)) ([aa6fd84](https://github.com/windmill-labs/windmill/commit/aa6fd84079b6015d82d7603218b2c8cb7a156c40)) + +## [1.387.1](https://github.com/windmill-labs/windmill/compare/v1.387.0...v1.387.1) (2024-08-30) + + +### Bug Fixes + +* fix resource list in args being pre-pended with $res ([2397588](https://github.com/windmill-labs/windmill/commit/239758835503ead5bbb1830c04b4fea5d13ad425)) +* improve history navigation on the runs page ([487e7ca](https://github.com/windmill-labs/windmill/commit/487e7ca715d37b4b59a3a03ba8ff2bb644118635)) + +## [1.387.0](https://github.com/windmill-labs/windmill/compare/v1.386.0...v1.387.0) (2024-08-29) + + +### Features + +* **frontend:** add a favorite button on detail pages ([#4297](https://github.com/windmill-labs/windmill/issues/4297)) ([8148518](https://github.com/windmill-labs/windmill/commit/8148518c5c7780d7999b884b0a9e0e540ece09fd)) +* **frontend:** add indicator when a component is locked ([#4296](https://github.com/windmill-labs/windmill/issues/4296)) ([d9b358b](https://github.com/windmill-labs/windmill/commit/d9b358bcc20d2603ef94ada765d395e370d58fc7)) + +## [1.386.0](https://github.com/windmill-labs/windmill/compare/v1.385.0...v1.386.0) (2024-08-28) + + +### Features + +* add vim support for monaco/webeditor ([1ec45e5](https://github.com/windmill-labs/windmill/commit/1ec45e5ad6436d36d3951a75663b4f310025d765)) +* **frontend:** add support to copy a cell value in the clipboard in aggrid tables ([#4286](https://github.com/windmill-labs/windmill/issues/4286)) ([d1ba9b1](https://github.com/windmill-labs/windmill/commit/d1ba9b14040f9c21612a46b36379cce95448fba6)) +* **frontend:** manage ag grid actions programmatically ([#4289](https://github.com/windmill-labs/windmill/issues/4289)) ([a411179](https://github.com/windmill-labs/windmill/commit/a4111798d54f5aa1539dd917eb59ec825c9a4a0b)) +* show last job instead of current job on workers page ([#4293](https://github.com/windmill-labs/windmill/issues/4293)) ([84ce3d8](https://github.com/windmill-labs/windmill/commit/84ce3d819d19254e89c0da9ddf0b9f3819fe6025)) + + +### Bug Fixes + +* cache hub scripts in more cases + pre-cache hub scripts deps in deno ([16465e4](https://github.com/windmill-labs/windmill/commit/16465e47c8acf6320694a821b375aa20ee51067c)) +* items with starred info ([#4298](https://github.com/windmill-labs/windmill/issues/4298)) ([e16bd4a](https://github.com/windmill-labs/windmill/commit/e16bd4a9d25d945b13696f8f7d9e39b10acdb444)) +* show vCPU, mem aggregate on top of worker group ([e083177](https://github.com/windmill-labs/windmill/commit/e0831777a1a8798ba4234f299035c6f471078553)) +* smtp server build without parquet feature ([#4292](https://github.com/windmill-labs/windmill/issues/4292)) ([906cf10](https://github.com/windmill-labs/windmill/commit/906cf1006e5447be075694d7d4903cea04b85737)) + +## [1.385.0](https://github.com/windmill-labs/windmill/compare/v1.384.0...v1.385.0) (2024-08-26) + + +### Features + +* s3 image preview ([#4262](https://github.com/windmill-labs/windmill/issues/4262)) ([35d665f](https://github.com/windmill-labs/windmill/commit/35d665f6179e0a52dd30512e378f270c44703f48)) + + +### Bug Fixes + +* **frontend:** fix inserting Ws scripts from the search menu ([#4290](https://github.com/windmill-labs/windmill/issues/4290)) ([4efc40f](https://github.com/windmill-labs/windmill/commit/4efc40fbb0214fba65f6ff95782e6ead3b20bc71)) + +## [1.384.0](https://github.com/windmill-labs/windmill/compare/v1.383.1...v1.384.0) (2024-08-26) + + +### Features + +* **frontend:** Add a toggle to disable breakpoints in the App editor ([#4274](https://github.com/windmill-labs/windmill/issues/4274)) ([5b2dd75](https://github.com/windmill-labs/windmill/commit/5b2dd7573d7ac2bd1b4ff06094a2dfd480ed24a4)) +* **frontend:** hide/show app editor panels ([#4266](https://github.com/windmill-labs/windmill/issues/4266)) ([fdfd385](https://github.com/windmill-labs/windmill/commit/fdfd385a68c8e05eff147a9471a9f3f44f39e13e)) +* put email triggers attachments on s3 ([#4272](https://github.com/windmill-labs/windmill/issues/4272)) ([5bd38f7](https://github.com/windmill-labs/windmill/commit/5bd38f78089a4beb4a28ba32bc99e649f8119a4c)) + + +### Bug Fixes + +* bun 1.1.21->1.1.25 ([7fa648f](https://github.com/windmill-labs/windmill/commit/7fa648f0876f5b5509fed39b314f40f08528b123)) +* **lsp:** use ruff server instead of ruff-lsp ([88648af](https://github.com/windmill-labs/windmill/commit/88648af1cd6f9e4436e2fd3100f3ece764da75f1)) +* update monaco-editor to latest monaco/language-client ([#4285](https://github.com/windmill-labs/windmill/issues/4285)) ([32c0b89](https://github.com/windmill-labs/windmill/commit/32c0b89729d98a25a5937af1ee41e8ea36334509)) + ## [1.383.1](https://github.com/windmill-labs/windmill/compare/v1.383.0...v1.383.1) (2024-08-22) diff --git a/Dockerfile b/Dockerfile index 6d5a2d29f4..a1c77f7e13 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ARG DEBIAN_IMAGE=debian:bookworm-slim -ARG RUST_IMAGE=rust:1.79-slim-bookworm +ARG RUST_IMAGE=rust:1.80-slim-bookworm ARG PYTHON_IMAGE=python:3.11.8-slim-bookworm FROM ${RUST_IMAGE} AS rust_base @@ -70,7 +70,9 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \ COPY ./openflow.openapi.yaml /openflow.openapi.yaml COPY ./backend ./ -COPY --from=frontend /frontend /frontend +RUN mkdir -p /frontend + +COPY --from=frontend /frontend/build /frontend/build COPY --from=frontend /backend/windmill-api/openapi-deref.yaml ./windmill-api/openapi-deref.yaml COPY .git/ .git/ @@ -86,17 +88,24 @@ ARG POWERSHELL_VERSION=7.3.5 ARG POWERSHELL_DEB_VERSION=7.3.5-1 ARG KUBECTL_VERSION=1.28.7 ARG HELM_VERSION=3.14.3 +ARG GO_VERSION=1.22.5 ARG APP=/usr/src/app ARG WITH_POWERSHELL=true ARG WITH_KUBECTL=true ARG WITH_HELM=true - +ARG WITH_GIT=true RUN apt-get update \ - && apt-get install -y ca-certificates wget curl git jq unzip build-essential unixodbc xmlsec1 software-properties-common \ + && apt-get install -y ca-certificates wget curl jq unzip build-essential unixodbc xmlsec1 software-properties-common \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* +RUN if [ "$WITH_GIT" = "true" ]; then \ + apt-get update -y \ + && apt-get install -y git \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/*; \ + else echo 'Building the image without git'; fi; RUN if [ "$WITH_POWERSHELL" = "true" ]; then \ if [ "$TARGETPLATFORM" = "linux/amd64" ]; then apt-get update -y && apt install libicu-dev -y && wget -O 'pwsh.deb' "https://github.com/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/powershell_${POWERSHELL_DEB_VERSION}.deb_amd64.deb" && apt-get clean \ @@ -131,14 +140,14 @@ RUN if [ "$WITH_KUBECTL" = "true" ]; then \ RUN set -eux; \ arch="$(dpkg --print-architecture)"; arch="${arch##*-}"; \ case "$arch" in \ - 'amd64') \ - targz='go1.22.5.linux-amd64.tar.gz'; \ + "amd64") \ + targz="go${GO_VERSION}.linux-amd64.tar.gz"; \ ;; \ - 'arm64') \ - targz='go1.22.5.linux-arm64.tar.gz'; \ + "arm64") \ + targz="go${GO_VERSION}.linux-arm64.tar.gz"; \ ;; \ - 'armhf') \ - targz='go1.22.5.linux-armv6l.tar.gz'; \ + "armhf") \ + targz="go${GO_VERSION}.linux-armv6l.tar.gz"; \ ;; \ *) echo >&2 "error: unsupported architecture '$arch' (likely packaging update needed)"; exit 1 ;; \ esac; \ @@ -149,7 +158,7 @@ ENV GO_PATH=/usr/local/go/bin/go RUN curl -sL https://deb.nodesource.com/setup_20.x | bash - RUN apt-get -y update && apt-get install -y curl nodejs awscli && apt-get clean \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* # go build is slower the first time it is ran, so we prewarm it in the build RUN mkdir -p /tmp/gobuildwarm && cd /tmp/gobuildwarm && go mod init gobuildwarm && printf "package foo\nimport (\"fmt\")\nfunc main() { fmt.Println(42) }" > warm.go && go mod tidy && go build -x && rm -rf /tmp/gobuildwarm @@ -161,9 +170,9 @@ RUN /usr/local/bin/python3 -m pip install pip-tools COPY --from=builder /frontend/build /static_frontend COPY --from=builder /windmill/target/release/windmill ${APP}/windmill -COPY --from=denoland/deno:1.45.4 --chmod=755 /usr/bin/deno /usr/bin/deno +COPY --from=denoland/deno:1.46.3 --chmod=755 /usr/bin/deno /usr/bin/deno -COPY --from=oven/bun:1.1.25 /usr/local/bin/bun /usr/bin/bun +COPY --from=oven/bun:1.1.27 /usr/local/bin/bun /usr/bin/bun COPY --from=php:8.3.7-cli /usr/local/bin/php /usr/bin/php COPY --from=composer:2.7.6 /usr/bin/composer /usr/bin/composer @@ -171,15 +180,16 @@ COPY --from=composer:2.7.6 /usr/bin/composer /usr/bin/composer # add the docker client to call docker from a worker if enabled COPY --from=docker:dind /usr/local/bin/docker /usr/local/bin/ +ENV RUSTUP_HOME="/usr/local/rustup" +ENV CARGO_HOME="/usr/local/cargo" + WORKDIR ${APP} RUN ln -s ${APP}/windmill /usr/local/bin/windmill COPY ./frontend/src/lib/hubPaths.json ${APP}/hubPaths.json -RUN windmill cache ${APP}/hubPaths.json - -RUN rm ${APP}/hubPaths.json +RUN windmill cache ${APP}/hubPaths.json && rm ${APP}/hubPaths.json && chmod -R 777 /tmp/windmill EXPOSE 8000 diff --git a/README.md b/README.md index b5a14eda55..eb6c64ee2a 100644 --- a/README.md +++ b/README.md @@ -352,14 +352,25 @@ you to have it being synced automatically everyday. | DISABLE_RESPONSE_LOGS | false | Disable response logs | Server | ## Run a local dev setup +See the [./frontend/README_DEV.md](./frontend/README_DEV.md) file for all +running options. + ### only Frontend This will use the backend of but your own frontend -with hot-code reloading. -1. Install [caddy](https://caddyserver.com) -2. Go to `frontend/`: - 1. `npm install`, `npm run generate-backend-client` then `npm run dev` - 2. In another shell `sudo caddy run --config CaddyfileRemote` -3. Et voilà, windmill should be available at `http://localhost/` +with hot-code reloading. Note that you will need to use a username / password login due to CSRF checks using a different auth provider. + +In the `frontend/` directory: + +1. install the dependencies with `npm install` (or `pnpm install` or `yarn`) +2. generate the windmill client: + ``` + npm run generate-backend-client + ## on mac use + npm run generate-backend-client-mac + ``` +3. Run your dev server with `npm run dev` +4. Et voilà, windmill should be available at `http://localhost/` + ### Backend + Frontend See the [./frontend/README_DEV.md](./frontend/README_DEV.md) file for all running options. diff --git a/backend/.sqlx/query-00ce4ed3ca0eac7cb6283b047353a64b9e78c4beb423f04baef9a53fbf87e9f9.json b/backend/.sqlx/query-00ce4ed3ca0eac7cb6283b047353a64b9e78c4beb423f04baef9a53fbf87e9f9.json new file mode 100644 index 0000000000..e4909fc4da --- /dev/null +++ b/backend/.sqlx/query-00ce4ed3ca0eac7cb6283b047353a64b9e78c4beb423f04baef9a53fbf87e9f9.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO alerts (alert_type, message) VALUES ('recovered_critical_error', $1)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [] + }, + "hash": "00ce4ed3ca0eac7cb6283b047353a64b9e78c4beb423f04baef9a53fbf87e9f9" +} diff --git a/backend/.sqlx/query-03d63d2e64b012f624d2731b5bcb8849c74a9474777be61edf0ed43ddda07ef3.json b/backend/.sqlx/query-03d63d2e64b012f624d2731b5bcb8849c74a9474777be61edf0ed43ddda07ef3.json index c501c6f1f8..39374fabd8 100644 --- a/backend/.sqlx/query-03d63d2e64b012f624d2731b5bcb8849c74a9474777be61edf0ed43ddda07ef3.json +++ b/backend/.sqlx/query-03d63d2e64b012f624d2731b5bcb8849c74a9474777be61edf0ed43ddda07ef3.json @@ -32,6 +32,11 @@ "ordinal": 5, "name": "created_by", "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "format_extension", + "type_info": "Varchar" } ], "parameters": { @@ -46,6 +51,7 @@ true, true, true, + true, true ] }, diff --git a/backend/.sqlx/query-050fb876e10ad13654dbbde4532f408ff1ac92ed0f5d31a3ef6c58313e1f8671.json b/backend/.sqlx/query-050fb876e10ad13654dbbde4532f408ff1ac92ed0f5d31a3ef6c58313e1f8671.json new file mode 100644 index 0000000000..9b50ef2c69 --- /dev/null +++ b/backend/.sqlx/query-050fb876e10ad13654dbbde4532f408ff1ac92ed0f5d31a3ef6c58313e1f8671.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT healthy, created_at FROM healthchecks WHERE check_type = 'min_alive_workers_' || $1 ORDER BY created_at DESC LIMIT 1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "healthy", + "type_info": "Bool" + }, + { + "ordinal": 1, + "name": "created_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "050fb876e10ad13654dbbde4532f408ff1ac92ed0f5d31a3ef6c58313e1f8671" +} diff --git a/backend/.sqlx/query-051acd49542618e3be5654dce94567a02e87be23a4c0863e3b2d53b5c2cb6749.json b/backend/.sqlx/query-051acd49542618e3be5654dce94567a02e87be23a4c0863e3b2d53b5c2cb6749.json new file mode 100644 index 0000000000..c7c7260ed4 --- /dev/null +++ b/backend/.sqlx/query-051acd49542618e3be5654dce94567a02e87be23a4c0863e3b2d53b5c2cb6749.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE schedule SET on_success = NULL, on_success_extra_args = NULL WHERE workspace_id = $1 RETURNING path", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "051acd49542618e3be5654dce94567a02e87be23a4c0863e3b2d53b5c2cb6749" +} diff --git a/backend/.sqlx/query-0a686ca61444d7ad7484071727aa039a6ea6697e5a49a633b767c052aa3e0a18.json b/backend/.sqlx/query-0a686ca61444d7ad7484071727aa039a6ea6697e5a49a633b767c052aa3e0a18.json index 580e8bfd01..a4c8e3ea0c 100644 --- a/backend/.sqlx/query-0a686ca61444d7ad7484071727aa039a6ea6697e5a49a633b767c052aa3e0a18.json +++ b/backend/.sqlx/query-0a686ca61444d7ad7484071727aa039a6ea6697e5a49a633b767c052aa3e0a18.json @@ -56,7 +56,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-0aa47e68f9e21115d96a8a1117e95f800c8bfb9bd6872a657c7e7131a21563c8.json b/backend/.sqlx/query-0aa47e68f9e21115d96a8a1117e95f800c8bfb9bd6872a657c7e7131a21563c8.json new file mode 100644 index 0000000000..fe02b79503 --- /dev/null +++ b/backend/.sqlx/query-0aa47e68f9e21115d96a8a1117e95f800c8bfb9bd6872a657c7e7131a21563c8.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT 1 FROM password WHERE email = 'admin@windmill.dev' AND password_hash = '$argon2id$v=19$m=4096,t=3,p=1$oLJo/lPn/gezXCuFOEyaNw$i0T2tCkw3xUFsrBIKZwr8jVNHlIfoxQe+HfDnLtd12I'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "0aa47e68f9e21115d96a8a1117e95f800c8bfb9bd6872a657c7e7131a21563c8" +} diff --git a/backend/.sqlx/query-620ddf29c5e867079df4c2aa6e80bccb19beeb9ddfa308ca97f254cd5ba8157e.json b/backend/.sqlx/query-0ad36c1598ff4ece0c325eaeb9a9177a87e1accd192402e21db5ae09c3498ab0.json similarity index 83% rename from backend/.sqlx/query-620ddf29c5e867079df4c2aa6e80bccb19beeb9ddfa308ca97f254cd5ba8157e.json rename to backend/.sqlx/query-0ad36c1598ff4ece0c325eaeb9a9177a87e1accd192402e21db5ae09c3498ab0.json index 790543d970..fc94db0309 100644 --- a/backend/.sqlx/query-620ddf29c5e867079df4c2aa6e80bccb19beeb9ddfa308ca97f254cd5ba8157e.json +++ b/backend/.sqlx/query-0ad36c1598ff4ece0c325eaeb9a9177a87e1accd192402e21db5ae09c3498ab0.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO queue\n (workspace_id, id, running, parent_job, created_by, permissioned_as, scheduled_for, \n script_hash, script_path, raw_code, raw_lock, args, job_kind, schedule_path, raw_flow, flow_status, is_flow_step, language, started_at, same_worker, pre_run_error, email, visible_to_owner, root_job, tag, concurrent_limit, concurrency_time_window_s, timeout, flow_step_id, cache_ttl, priority)\n VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, now()), $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, CASE WHEN $3 THEN now() END, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30) RETURNING id", + "query": "INSERT INTO queue\n (workspace_id, id, running, parent_job, created_by, permissioned_as, scheduled_for, \n script_hash, script_path, raw_code, raw_lock, args, job_kind, schedule_path, raw_flow, flow_status, is_flow_step, language, started_at, same_worker, pre_run_error, email, visible_to_owner, root_job, tag, concurrent_limit, concurrency_time_window_s, timeout, flow_step_id, cache_ttl, priority, last_ping)\n VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, now()), $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, CASE WHEN $3 THEN now() END, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, NULL) RETURNING id", "describe": { "columns": [ { @@ -70,7 +70,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } @@ -93,5 +95,5 @@ false ] }, - "hash": "620ddf29c5e867079df4c2aa6e80bccb19beeb9ddfa308ca97f254cd5ba8157e" + "hash": "0ad36c1598ff4ece0c325eaeb9a9177a87e1accd192402e21db5ae09c3498ab0" } diff --git a/backend/.sqlx/query-0c2e53960dc7786c848079b155e62994d4a861f1dbb9752c0a27428d83040e13.json b/backend/.sqlx/query-0c2e53960dc7786c848079b155e62994d4a861f1dbb9752c0a27428d83040e13.json new file mode 100644 index 0000000000..5c33539878 --- /dev/null +++ b/backend/.sqlx/query-0c2e53960dc7786c848079b155e62994d4a861f1dbb9752c0a27428d83040e13.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT value, is_secret FROM variable WHERE path = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "is_secret", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "0c2e53960dc7786c848079b155e62994d4a861f1dbb9752c0a27428d83040e13" +} diff --git a/backend/.sqlx/query-19bc874a06658b549e13cfa080ac2133190ba448d6f7830c8f1f7c22e4d753b8.json b/backend/.sqlx/query-19bc874a06658b549e13cfa080ac2133190ba448d6f7830c8f1f7c22e4d753b8.json new file mode 100644 index 0000000000..1fadd917d4 --- /dev/null +++ b/backend/.sqlx/query-19bc874a06658b549e13cfa080ac2133190ba448d6f7830c8f1f7c22e4d753b8.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT value FROM global_settings WHERE name = 'slack'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "19bc874a06658b549e13cfa080ac2133190ba448d6f7830c8f1f7c22e4d753b8" +} diff --git a/backend/.sqlx/query-1a612eb0b64eddd2c5657ef73598c47886545796424f8612135b711e2b9ddb6c.json b/backend/.sqlx/query-1a612eb0b64eddd2c5657ef73598c47886545796424f8612135b711e2b9ddb6c.json index 9463b1e558..e74be644c7 100644 --- a/backend/.sqlx/query-1a612eb0b64eddd2c5657ef73598c47886545796424f8612135b711e2b9ddb6c.json +++ b/backend/.sqlx/query-1a612eb0b64eddd2c5657ef73598c47886545796424f8612135b711e2b9ddb6c.json @@ -50,7 +50,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-20fcdcd2674a52ee9bd8d1de518d6bce075f20bcd5d2328f183d8a59331f6bb1.json b/backend/.sqlx/query-20fcdcd2674a52ee9bd8d1de518d6bce075f20bcd5d2328f183d8a59331f6bb1.json new file mode 100644 index 0000000000..824335990f --- /dev/null +++ b/backend/.sqlx/query-20fcdcd2674a52ee9bd8d1de518d6bce075f20bcd5d2328f183d8a59331f6bb1.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO resource\n (workspace_id, path, value, resource_type, created_by, edited_at)\n VALUES ($1, $2, $3, $4, $5, now()) ON CONFLICT (workspace_id, path) DO UPDATE SET value = $3, edited_at = now()", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Jsonb", + "Varchar", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "20fcdcd2674a52ee9bd8d1de518d6bce075f20bcd5d2328f183d8a59331f6bb1" +} diff --git a/backend/.sqlx/query-31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed.json b/backend/.sqlx/query-31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed.json new file mode 100644 index 0000000000..85c0412f3b --- /dev/null +++ b/backend/.sqlx/query-31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE schedule SET on_success = $1, on_success_extra_args = $2 WHERE workspace_id = $3 RETURNING path", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Json", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "31fe5d2965f7b25dea785f8be529a9b2c4c83c910fd7e2a08f4d95ae195ab3ed" +} diff --git a/backend/.sqlx/query-33c1793e55b1127d88d2509aadd0eb04e042463200f237b4c2cb176612fa16fe.json b/backend/.sqlx/query-33c1793e55b1127d88d2509aadd0eb04e042463200f237b4c2cb176612fa16fe.json new file mode 100644 index 0000000000..8728e35a0c --- /dev/null +++ b/backend/.sqlx/query-33c1793e55b1127d88d2509aadd0eb04e042463200f237b4c2cb176612fa16fe.json @@ -0,0 +1,21 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines, json_fmt) VALUES ($1, $2::text::LOG_MODE, $3, $4, $5, $6, $7, $8)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Varchar", + "Timestamp", + "Varchar", + "Int8", + "Int8", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "33c1793e55b1127d88d2509aadd0eb04e042463200f237b4c2cb176612fa16fe" +} diff --git a/backend/.sqlx/query-354f88b23d20f92c6b6d5bdd8d6c69b08c6a86116cbfd0ecad8f112f7f49d8d1.json b/backend/.sqlx/query-354f88b23d20f92c6b6d5bdd8d6c69b08c6a86116cbfd0ecad8f112f7f49d8d1.json new file mode 100644 index 0000000000..4b03b16262 --- /dev/null +++ b/backend/.sqlx/query-354f88b23d20f92c6b6d5bdd8d6c69b08c6a86116cbfd0ecad8f112f7f49d8d1.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT SUBSTRING(name, 9) as \"name!\", (config.config->'min_alive_workers_alert_threshold')::INT as \"threshold!\" \n FROM config \n WHERE name LIKE 'worker__%' AND config->'min_alive_workers_alert_threshold' IS NOT NULL", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "name!", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "threshold!", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null, + null + ] + }, + "hash": "354f88b23d20f92c6b6d5bdd8d6c69b08c6a86116cbfd0ecad8f112f7f49d8d1" +} diff --git a/backend/.sqlx/query-388b3705f641621b0c2f4496e36cb7aa5a75b7e40fa312eff6590e54b02635a2.json b/backend/.sqlx/query-388b3705f641621b0c2f4496e36cb7aa5a75b7e40fa312eff6590e54b02635a2.json new file mode 100644 index 0000000000..48f8d1e10c --- /dev/null +++ b/backend/.sqlx/query-388b3705f641621b0c2f4496e36cb7aa5a75b7e40fa312eff6590e54b02635a2.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS(SELECT 1 FROM metrics WHERE id = 'license_key_renewal' AND created_at > NOW() - INTERVAL '24 hours')", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "388b3705f641621b0c2f4496e36cb7aa5a75b7e40fa312eff6590e54b02635a2" +} diff --git a/backend/.sqlx/query-3d60b4f2cbedb61affeff94fd77b7c86493c30a4d3d648d0660a3281824156b9.json b/backend/.sqlx/query-3d60b4f2cbedb61affeff94fd77b7c86493c30a4d3d648d0660a3281824156b9.json new file mode 100644 index 0000000000..4c17792a7b --- /dev/null +++ b/backend/.sqlx/query-3d60b4f2cbedb61affeff94fd77b7c86493c30a4d3d648d0660a3281824156b9.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) FROM global_settings WHERE name = 'base_url'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "3d60b4f2cbedb61affeff94fd77b7c86493c30a4d3d648d0660a3281824156b9" +} diff --git a/backend/.sqlx/query-4422b7183ede17a9cbde4afae41be4da5447020e39398deedbcca9121492834a.json b/backend/.sqlx/query-4422b7183ede17a9cbde4afae41be4da5447020e39398deedbcca9121492834a.json index 1163e930c9..3e8ba47b99 100644 --- a/backend/.sqlx/query-4422b7183ede17a9cbde4afae41be4da5447020e39398deedbcca9121492834a.json +++ b/backend/.sqlx/query-4422b7183ede17a9cbde4afae41be4da5447020e39398deedbcca9121492834a.json @@ -135,6 +135,16 @@ }, { "ordinal": 26, + "name": "on_success", + "type_info": "Varchar" + }, + { + "ordinal": 27, + "name": "on_success_extra_args", + "type_info": "Json" + }, + { + "ordinal": 28, "name": "jobs", "type_info": "JsonArray" } @@ -173,6 +183,8 @@ false, true, true, + true, + true, null ] }, diff --git a/backend/.sqlx/query-7c95f3652de4561b18c1a340db3e0113a4777d38de4468fc41b22ce5b6fd1db7.json b/backend/.sqlx/query-44dd7a66ecc9564ad5727970b5f60a1717eda8924999741be522ffb74cc173fa.json similarity index 63% rename from backend/.sqlx/query-7c95f3652de4561b18c1a340db3e0113a4777d38de4468fc41b22ce5b6fd1db7.json rename to backend/.sqlx/query-44dd7a66ecc9564ad5727970b5f60a1717eda8924999741be522ffb74cc173fa.json index 7222da038c..9f97b97a88 100644 --- a/backend/.sqlx/query-7c95f3652de4561b18c1a340db3e0113a4777d38de4468fc41b22ce5b6fd1db7.json +++ b/backend/.sqlx/query-44dd7a66ecc9564ad5727970b5f60a1717eda8924999741be522ffb74cc173fa.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "WITH queue_metrics as (\n SELECT id, value, created_at\n FROM metrics\n WHERE id LIKE 'queue_%'\n AND created_at > now() - interval '14 day'\n ORDER BY created_at ASC\n )\n SELECT id, array_agg(json_build_object('value', value, 'created_at', created_at)) as \"values!\"\n FROM queue_metrics\n GROUP BY id\n ORDER BY id ASC", + "query": "WITH queue_metrics as (\n SELECT id, value, created_at\n FROM metrics\n WHERE id LIKE 'queue_%'\n AND created_at > now() - interval '14 day'\n )\n SELECT id, array_agg(json_build_object('value', value, 'created_at', created_at) ORDER BY created_at ASC) as \"values!\"\n FROM queue_metrics\n GROUP BY id\n ORDER BY id ASC", "describe": { "columns": [ { @@ -22,5 +22,5 @@ null ] }, - "hash": "7c95f3652de4561b18c1a340db3e0113a4777d38de4468fc41b22ce5b6fd1db7" + "hash": "44dd7a66ecc9564ad5727970b5f60a1717eda8924999741be522ffb74cc173fa" } diff --git a/backend/.sqlx/query-4c0067c2135a259aea5cc2db60f7375a9a33671be8ef406427d90f67a98c9c9f.json b/backend/.sqlx/query-4c0067c2135a259aea5cc2db60f7375a9a33671be8ef406427d90f67a98c9c9f.json new file mode 100644 index 0000000000..32295ea1e1 --- /dev/null +++ b/backend/.sqlx/query-4c0067c2135a259aea5cc2db60f7375a9a33671be8ef406427d90f67a98c9c9f.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO alerts (alert_type, message) VALUES ('critical_error', $1)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [] + }, + "hash": "4c0067c2135a259aea5cc2db60f7375a9a33671be8ef406427d90f67a98c9c9f" +} diff --git a/backend/.sqlx/query-4cfa57b2a836242d55071ef237855b21bbc487b80bda7fd6250ac12e93938577.json b/backend/.sqlx/query-4cfa57b2a836242d55071ef237855b21bbc487b80bda7fd6250ac12e93938577.json new file mode 100644 index 0000000000..5ac1cd561e --- /dev/null +++ b/backend/.sqlx/query-4cfa57b2a836242d55071ef237855b21bbc487b80bda7fd6250ac12e93938577.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO healthchecks (check_type, healthy) \n SELECT 'min_alive_workers_' || $1, true \n WHERE NOT EXISTS (\n SELECT 1 FROM healthchecks \n WHERE check_type = 'min_alive_workers_' || $1 AND created_at > NOW() - INTERVAL '2 minutes'\n )\n RETURNING id", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "4cfa57b2a836242d55071ef237855b21bbc487b80bda7fd6250ac12e93938577" +} diff --git a/backend/.sqlx/query-89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec.json b/backend/.sqlx/query-56eafd6d3c72f7114e3d6764184825e2671283fc70abba9a036e88699430af0f.json similarity index 74% rename from backend/.sqlx/query-89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec.json rename to backend/.sqlx/query-56eafd6d3c72f7114e3d6764184825e2671283fc70abba9a036e88699430af0f.json index 1f40dbca3b..9f22b4df19 100644 --- a/backend/.sqlx/query-89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec.json +++ b/backend/.sqlx/query-56eafd6d3c72f7114e3d6764184825e2671283fc70abba9a036e88699430af0f.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "CREATE INDEX CONCURRENTLY labeled_jobs_on_jobs ON completed_job USING GIN ((result -> 'wm_labels')) WHERE result ? 'wm_label';", + "query": "CREATE INDEX CONCURRENTLY labeled_jobs_on_jobs ON completed_job USING GIN ((result -> 'wm_labels')) WHERE result ? 'wm_labels'", "describe": { "columns": [], "parameters": { @@ -8,5 +8,5 @@ }, "nullable": [] }, - "hash": "89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec" + "hash": "56eafd6d3c72f7114e3d6764184825e2671283fc70abba9a036e88699430af0f" } diff --git a/backend/.sqlx/query-5f22a7c9170f035779782591b4bfb1d462d5c796f08c7481c42154f9bfacf388.json b/backend/.sqlx/query-5f22a7c9170f035779782591b4bfb1d462d5c796f08c7481c42154f9bfacf388.json new file mode 100644 index 0000000000..1aea7e585c --- /dev/null +++ b/backend/.sqlx/query-5f22a7c9170f035779782591b4bfb1d462d5c796f08c7481c42154f9bfacf388.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO healthchecks (check_type, healthy) \n SELECT 'min_alive_workers_' || $1, false\n WHERE NOT EXISTS (\n SELECT 1 FROM healthchecks \n WHERE check_type = 'min_alive_workers_' || $1 AND created_at > NOW() - INTERVAL '2 minutes'\n )\n RETURNING id", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "5f22a7c9170f035779782591b4bfb1d462d5c796f08c7481c42154f9bfacf388" +} diff --git a/backend/.sqlx/query-661f472ff3860983322162420457f5033b9c9afc344d9c3e385ba20a3ad2197a.json b/backend/.sqlx/query-661f472ff3860983322162420457f5033b9c9afc344d9c3e385ba20a3ad2197a.json index 75b8108281..1fa370e682 100644 --- a/backend/.sqlx/query-661f472ff3860983322162420457f5033b9c9afc344d9c3e385ba20a3ad2197a.json +++ b/backend/.sqlx/query-661f472ff3860983322162420457f5033b9c9afc344d9c3e385ba20a3ad2197a.json @@ -5,7 +5,7 @@ "columns": [ { "ordinal": 0, - "name": "?column?", + "name": "bool", "type_info": "Bool" } ], diff --git a/backend/.sqlx/query-74d5757014fc7a6818ae857bfdda9f6317cf2b9e0a78cbad80ebdc935d3246fd.json b/backend/.sqlx/query-74d5757014fc7a6818ae857bfdda9f6317cf2b9e0a78cbad80ebdc935d3246fd.json new file mode 100644 index 0000000000..0501df6cfe --- /dev/null +++ b/backend/.sqlx/query-74d5757014fc7a6818ae857bfdda9f6317cf2b9e0a78cbad80ebdc935d3246fd.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT 1 FROM password LIMIT 2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "74d5757014fc7a6818ae857bfdda9f6317cf2b9e0a78cbad80ebdc935d3246fd" +} diff --git a/backend/.sqlx/query-76ca60e456022cf3d1931245b7daf22783c81bc757d735a4b247cc693dfed719.json b/backend/.sqlx/query-76ca60e456022cf3d1931245b7daf22783c81bc757d735a4b247cc693dfed719.json new file mode 100644 index 0000000000..530638af1f --- /dev/null +++ b/backend/.sqlx/query-76ca60e456022cf3d1931245b7daf22783c81bc757d735a4b247cc693dfed719.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE queue\n SET flow_status = JSONB_SET(flow_status, ARRAY['modules', flow_status->>'step', 'progress'], $1)\n WHERE id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "76ca60e456022cf3d1931245b7daf22783c81bc757d735a4b247cc693dfed719" +} diff --git a/backend/.sqlx/query-7b1239ad6460e8f5fb41bfe12f662a779528784ec8cf3f6dcce5545ab90bf234.json b/backend/.sqlx/query-7b1239ad6460e8f5fb41bfe12f662a779528784ec8cf3f6dcce5545ab90bf234.json index 7bdf4f49a7..a7a5b812f7 100644 --- a/backend/.sqlx/query-7b1239ad6460e8f5fb41bfe12f662a779528784ec8cf3f6dcce5545ab90bf234.json +++ b/backend/.sqlx/query-7b1239ad6460e8f5fb41bfe12f662a779528784ec8cf3f6dcce5545ab90bf234.json @@ -32,6 +32,11 @@ "ordinal": 5, "name": "created_by", "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "format_extension", + "type_info": "Varchar" } ], "parameters": { @@ -45,6 +50,7 @@ true, true, true, + true, true ] }, diff --git a/backend/.sqlx/query-7fa8fca5b5cdf147da0cf8ae5a0d9fdee37dd8df66974c8d33f58a88b1bca537.json b/backend/.sqlx/query-7fa8fca5b5cdf147da0cf8ae5a0d9fdee37dd8df66974c8d33f58a88b1bca537.json new file mode 100644 index 0000000000..e4aa1f4f24 --- /dev/null +++ b/backend/.sqlx/query-7fa8fca5b5cdf147da0cf8ae5a0d9fdee37dd8df66974c8d33f58a88b1bca537.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM healthchecks WHERE check_type LIKE 'min_alive_workers_%' AND created_at < NOW() - INTERVAL '48 hours'", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "7fa8fca5b5cdf147da0cf8ae5a0d9fdee37dd8df66974c8d33f58a88b1bca537" +} diff --git a/backend/.sqlx/query-55d6c6f887f1cceb311d9ab034d3485b8ccb2d07d723f184cef2696760d3ccf9.json b/backend/.sqlx/query-8375c1efeb1e2a2d2803052a2899bf70f4a6434eb91b4b05b9fb8420beae26af.json similarity index 78% rename from backend/.sqlx/query-55d6c6f887f1cceb311d9ab034d3485b8ccb2d07d723f184cef2696760d3ccf9.json rename to backend/.sqlx/query-8375c1efeb1e2a2d2803052a2899bf70f4a6434eb91b4b05b9fb8420beae26af.json index dc06930fb1..4bcbb0380f 100644 --- a/backend/.sqlx/query-55d6c6f887f1cceb311d9ab034d3485b8ccb2d07d723f184cef2696760d3ccf9.json +++ b/backend/.sqlx/query-8375c1efeb1e2a2d2803052a2899bf70f4a6434eb91b4b05b9fb8420beae26af.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT worker, worker_instance, EXTRACT(EPOCH FROM (now() - ping_at))::integer as last_ping, started_at, ip, jobs_executed, CASE WHEN $4 IS TRUE THEN current_job_id ELSE NULL END as current_job_id, CASE WHEN $4 IS TRUE THEN current_job_workspace_id ELSE NULL END as current_job_workspace_id, custom_tags, worker_group, wm_version, occupancy_rate, memory, vcpus, memory_usage, wm_memory_usage\n FROM worker_ping\n WHERE ($1::integer IS NULL AND ping_at > now() - interval '5 minute') OR (ping_at > now() - ($1 || ' seconds')::interval)\n ORDER BY ping_at desc LIMIT $2 OFFSET $3", + "query": "SELECT worker, worker_instance, EXTRACT(EPOCH FROM (now() - ping_at))::integer as last_ping, started_at, ip, jobs_executed, CASE WHEN $4 IS TRUE THEN current_job_id ELSE NULL END as last_job_id, CASE WHEN $4 IS TRUE THEN current_job_workspace_id ELSE NULL END as last_job_workspace_id, custom_tags, worker_group, wm_version, occupancy_rate, memory, vcpus, memory_usage, wm_memory_usage\n FROM worker_ping\n WHERE ($1::integer IS NULL AND ping_at > now() - interval '5 minute') OR (ping_at > now() - ($1 || ' seconds')::interval)\n ORDER BY ping_at desc LIMIT $2 OFFSET $3", "describe": { "columns": [ { @@ -35,12 +35,12 @@ }, { "ordinal": 6, - "name": "current_job_id", + "name": "last_job_id", "type_info": "Uuid" }, { "ordinal": 7, - "name": "current_job_workspace_id", + "name": "last_job_workspace_id", "type_info": "Varchar" }, { @@ -111,5 +111,5 @@ true ] }, - "hash": "55d6c6f887f1cceb311d9ab034d3485b8ccb2d07d723f184cef2696760d3ccf9" + "hash": "8375c1efeb1e2a2d2803052a2899bf70f4a6434eb91b4b05b9fb8420beae26af" } diff --git a/backend/.sqlx/query-845120388af12c2b2f57fedf95c8cce4a406b74c9a8c8590a3bae323d59d046a.json b/backend/.sqlx/query-845120388af12c2b2f57fedf95c8cce4a406b74c9a8c8590a3bae323d59d046a.json new file mode 100644 index 0000000000..afede37f44 --- /dev/null +++ b/backend/.sqlx/query-845120388af12c2b2f57fedf95c8cce4a406b74c9a8c8590a3bae323d59d046a.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM log_file WHERE log_ts <= now() - ($1::bigint::text || ' s')::interval ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "845120388af12c2b2f57fedf95c8cce4a406b74c9a8c8590a3bae323d59d046a" +} diff --git a/backend/.sqlx/query-8b10c9ade85c0307e300224e87962ceba8e7ccbe53b56c4670a1634bb9d0e89c.json b/backend/.sqlx/query-8b10c9ade85c0307e300224e87962ceba8e7ccbe53b56c4670a1634bb9d0e89c.json index 3eddd1237b..ebd2e2535d 100644 --- a/backend/.sqlx/query-8b10c9ade85c0307e300224e87962ceba8e7ccbe53b56c4670a1634bb9d0e89c.json +++ b/backend/.sqlx/query-8b10c9ade85c0307e300224e87962ceba8e7ccbe53b56c4670a1634bb9d0e89c.json @@ -55,7 +55,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-7ab02d2c060ed12531e6af98a5d3369afe534519bf48f61f88f60786db870c24.json b/backend/.sqlx/query-8c15ea27be82665fe74a4be3182a5049fa937e30b4115caf0ba8d61d34f2089a.json similarity index 50% rename from backend/.sqlx/query-7ab02d2c060ed12531e6af98a5d3369afe534519bf48f61f88f60786db870c24.json rename to backend/.sqlx/query-8c15ea27be82665fe74a4be3182a5049fa937e30b4115caf0ba8d61d34f2089a.json index f20c2c1562..9b20861537 100644 --- a/backend/.sqlx/query-7ab02d2c060ed12531e6af98a5d3369afe534519bf48f61f88f60786db870c24.json +++ b/backend/.sqlx/query-8c15ea27be82665fe74a4be3182a5049fa937e30b4115caf0ba8d61d34f2089a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE queue SET running = false, started_at = null, logs = logs || '\nRestarted job after not receiving job''s ping for too long the ' || now() || '\n\n' \n WHERE last_ping < now() - ($1 || ' seconds')::interval\n AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'singlescriptflow') AND same_worker = false RETURNING id, workspace_id, last_ping", + "query": "UPDATE queue SET running = false, started_at = null\n WHERE last_ping < now() - ($1 || ' seconds')::interval\n AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'singlescriptflow') AND same_worker = false RETURNING id, workspace_id, last_ping", "describe": { "columns": [ { @@ -30,5 +30,5 @@ true ] }, - "hash": "7ab02d2c060ed12531e6af98a5d3369afe534519bf48f61f88f60786db870c24" + "hash": "8c15ea27be82665fe74a4be3182a5049fa937e30b4115caf0ba8d61d34f2089a" } diff --git a/backend/.sqlx/query-8dd1de2aca8c6c9ffaddd2c41c3a614a50fa5fd03c2d3b9a41bd85a7f156345e.json b/backend/.sqlx/query-8dd1de2aca8c6c9ffaddd2c41c3a614a50fa5fd03c2d3b9a41bd85a7f156345e.json new file mode 100644 index 0000000000..c1a63e668f --- /dev/null +++ b/backend/.sqlx/query-8dd1de2aca8c6c9ffaddd2c41c3a614a50fa5fd03c2d3b9a41bd85a7f156345e.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT count(*) \n FROM worker_ping \n WHERE worker_group LIKE $1 AND ping_at > now() - INTERVAL '2 minutes'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "8dd1de2aca8c6c9ffaddd2c41c3a614a50fa5fd03c2d3b9a41bd85a7f156345e" +} diff --git a/backend/.sqlx/query-8e7ff45c5378c3a3406ba94dc0653afa5d28c072203617c598caefaaf1bafcfb.json b/backend/.sqlx/query-8e7ff45c5378c3a3406ba94dc0653afa5d28c072203617c598caefaaf1bafcfb.json index 251d21f167..72ab4ffe26 100644 --- a/backend/.sqlx/query-8e7ff45c5378c3a3406ba94dc0653afa5d28c072203617c598caefaaf1bafcfb.json +++ b/backend/.sqlx/query-8e7ff45c5378c3a3406ba94dc0653afa5d28c072203617c598caefaaf1bafcfb.json @@ -36,7 +36,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-9422431d79de41518f651ef24e86819d7b6a2f5531740a7deea1b51775335977.json b/backend/.sqlx/query-9422431d79de41518f651ef24e86819d7b6a2f5531740a7deea1b51775335977.json new file mode 100644 index 0000000000..7f2936f195 --- /dev/null +++ b/backend/.sqlx/query-9422431d79de41518f651ef24e86819d7b6a2f5531740a7deea1b51775335977.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT scalar_int FROM job_stats WHERE workspace_id = $1 AND job_id = $2 AND metric_id = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "scalar_int", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text", + "Uuid", + "Text" + ] + }, + "nullable": [ + true + ] + }, + "hash": "9422431d79de41518f651ef24e86819d7b6a2f5531740a7deea1b51775335977" +} diff --git a/backend/.sqlx/query-e87c317550af671e4b65752a9c0b659cedf430fb7242faee4379b4a13e5fd763.json b/backend/.sqlx/query-958ed17dafffdd37e636ccd244dc4ca60cbf562e6f6a371d5f9a9943fb30254c.json similarity index 69% rename from backend/.sqlx/query-e87c317550af671e4b65752a9c0b659cedf430fb7242faee4379b4a13e5fd763.json rename to backend/.sqlx/query-958ed17dafffdd37e636ccd244dc4ca60cbf562e6f6a371d5f9a9943fb30254c.json index 83ae3520d7..31501b4094 100644 --- a/backend/.sqlx/query-e87c317550af671e4b65752a9c0b659cedf430fb7242faee4379b4a13e5fd763.json +++ b/backend/.sqlx/query-958ed17dafffdd37e636ccd244dc4ca60cbf562e6f6a371d5f9a9943fb30254c.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO dependency_map (workspace_id, importer_path, importer_kind, imported_path, importer_node_id)\n VALUES ($1, $2, $4::text::IMPORTER_KIND, $3, $5)", + "query": "INSERT INTO dependency_map (workspace_id, importer_path, importer_kind, imported_path, importer_node_id)\n VALUES ($1, $2, $4::text::IMPORTER_KIND, $3, $5) ON CONFLICT DO NOTHING", "describe": { "columns": [], "parameters": { @@ -14,5 +14,5 @@ }, "nullable": [] }, - "hash": "e87c317550af671e4b65752a9c0b659cedf430fb7242faee4379b4a13e5fd763" + "hash": "958ed17dafffdd37e636ccd244dc4ca60cbf562e6f6a371d5f9a9943fb30254c" } diff --git a/backend/.sqlx/query-c1de24c68933ab35934395d74c5d2747b3da80c96e255ccf0c4e053206a9ad1b.json b/backend/.sqlx/query-9cf96fa6364b7f34dc83719b4a0e97e8494393c29f7c8d915aa54da7ab7eed51.json similarity index 63% rename from backend/.sqlx/query-c1de24c68933ab35934395d74c5d2747b3da80c96e255ccf0c4e053206a9ad1b.json rename to backend/.sqlx/query-9cf96fa6364b7f34dc83719b4a0e97e8494393c29f7c8d915aa54da7ab7eed51.json index a690ad155e..92825535a4 100644 --- a/backend/.sqlx/query-c1de24c68933ab35934395d74c5d2747b3da80c96e255ccf0c4e053206a9ad1b.json +++ b/backend/.sqlx/query-9cf96fa6364b7f34dc83719b4a0e97e8494393c29f7c8d915aa54da7ab7eed51.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE worker_ping SET ping_at = now(), jobs_executed = $1, custom_tags = $2, occupancy_rate = $3, memory_usage = $4, wm_memory_usage = $5, current_job_id = NULL, current_job_workspace_id = NULL, vcpus = COALESCE($7, vcpus), memory = COALESCE($8, memory) WHERE worker = $6", + "query": "UPDATE worker_ping SET ping_at = now(), jobs_executed = $1, custom_tags = $2, occupancy_rate = $3, memory_usage = $4, wm_memory_usage = $5, vcpus = COALESCE($7, vcpus), memory = COALESCE($8, memory) WHERE worker = $6", "describe": { "columns": [], "parameters": { @@ -17,5 +17,5 @@ }, "nullable": [] }, - "hash": "c1de24c68933ab35934395d74c5d2747b3da80c96e255ccf0c4e053206a9ad1b" + "hash": "9cf96fa6364b7f34dc83719b4a0e97e8494393c29f7c8d915aa54da7ab7eed51" } diff --git a/backend/.sqlx/query-9d25fbd21a63e6e9ccfdbf0460c8b3ca6d7fa05600067f379659b59b6f2bf418.json b/backend/.sqlx/query-9d25fbd21a63e6e9ccfdbf0460c8b3ca6d7fa05600067f379659b59b6f2bf418.json index 2220f81e41..4f8a78ca66 100644 --- a/backend/.sqlx/query-9d25fbd21a63e6e9ccfdbf0460c8b3ca6d7fa05600067f379659b59b6f2bf418.json +++ b/backend/.sqlx/query-9d25fbd21a63e6e9ccfdbf0460c8b3ca6d7fa05600067f379659b59b6f2bf418.json @@ -55,7 +55,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-9d3556319411a27a875bf6cf0e5eda837cc63e4d8be912c0b5bfeea4a0c8db2e.json b/backend/.sqlx/query-9d3556319411a27a875bf6cf0e5eda837cc63e4d8be912c0b5bfeea4a0c8db2e.json index b1a706e87a..2393bc83df 100644 --- a/backend/.sqlx/query-9d3556319411a27a875bf6cf0e5eda837cc63e4d8be912c0b5bfeea4a0c8db2e.json +++ b/backend/.sqlx/query-9d3556319411a27a875bf6cf0e5eda837cc63e4d8be912c0b5bfeea4a0c8db2e.json @@ -50,7 +50,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-9f1f388924176dbe3dea882e0c62728a82ba256029096812dd705ccb1a552cfe.json b/backend/.sqlx/query-9f1f388924176dbe3dea882e0c62728a82ba256029096812dd705ccb1a552cfe.json new file mode 100644 index 0000000000..51ddd8af63 --- /dev/null +++ b/backend/.sqlx/query-9f1f388924176dbe3dea882e0c62728a82ba256029096812dd705ccb1a552cfe.json @@ -0,0 +1,19 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, account, is_oauth)\n VALUES ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (workspace_id, path) DO UPDATE SET value = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + "Bool", + "Int4", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "9f1f388924176dbe3dea882e0c62728a82ba256029096812dd705ccb1a552cfe" +} diff --git a/backend/.sqlx/query-aa5bdf0ab8781cf984711ae4f4351eb3bd5621ae081a418f1d4dbcb8359a8adb.json b/backend/.sqlx/query-aa5bdf0ab8781cf984711ae4f4351eb3bd5621ae081a418f1d4dbcb8359a8adb.json new file mode 100644 index 0000000000..9a38a434b0 --- /dev/null +++ b/backend/.sqlx/query-aa5bdf0ab8781cf984711ae4f4351eb3bd5621ae081a418f1d4dbcb8359a8adb.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE password SET name = $1 WHERE email = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text" + ] + }, + "nullable": [] + }, + "hash": "aa5bdf0ab8781cf984711ae4f4351eb3bd5621ae081a418f1d4dbcb8359a8adb" +} diff --git a/backend/.sqlx/query-ae25fae1aca2cffc43a6054cd54639ba9deaaef419ad4cb2655e7e95f602a688.json b/backend/.sqlx/query-ae25fae1aca2cffc43a6054cd54639ba9deaaef419ad4cb2655e7e95f602a688.json new file mode 100644 index 0000000000..5634e60233 --- /dev/null +++ b/backend/.sqlx/query-ae25fae1aca2cffc43a6054cd54639ba9deaaef419ad4cb2655e7e95f602a688.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO job_logs (job_id, logs) VALUES ($1,'Restarted job after not receiving job''s ping for too long the ' || now() || '\n\n') \n ON CONFLICT (job_id) DO UPDATE SET logs = job_logs.logs || '\nRestarted job after not receiving job''s ping for too long the ' || now() || '\n\n' WHERE job_logs.job_id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "ae25fae1aca2cffc43a6054cd54639ba9deaaef419ad4cb2655e7e95f602a688" +} diff --git a/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json b/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json index 99269c9851..54e94cfb8f 100644 --- a/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json +++ b/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json @@ -18,8 +18,8 @@ "Left": [] }, "nullable": [ - true, - false + false, + true ] }, "hash": "b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76" diff --git a/backend/.sqlx/query-b8d392ccfcccafe0c19511b3567bc11779b1052b0948c410468a8aeba1d26d33.json b/backend/.sqlx/query-b8d392ccfcccafe0c19511b3567bc11779b1052b0948c410468a8aeba1d26d33.json index fc91f7103d..c403f6a428 100644 --- a/backend/.sqlx/query-b8d392ccfcccafe0c19511b3567bc11779b1052b0948c410468a8aeba1d26d33.json +++ b/backend/.sqlx/query-b8d392ccfcccafe0c19511b3567bc11779b1052b0948c410468a8aeba1d26d33.json @@ -32,6 +32,11 @@ "ordinal": 5, "name": "created_by", "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "format_extension", + "type_info": "Varchar" } ], "parameters": { @@ -45,6 +50,7 @@ true, true, true, + true, true ] }, diff --git a/backend/.sqlx/query-c1ceb03e0eafd2e494c06cef1ec96f78c2cfd42ed7d1ca6cfd35288b561120db.json b/backend/.sqlx/query-c1ceb03e0eafd2e494c06cef1ec96f78c2cfd42ed7d1ca6cfd35288b561120db.json new file mode 100644 index 0000000000..d1a89a6ad6 --- /dev/null +++ b/backend/.sqlx/query-c1ceb03e0eafd2e494c06cef1ec96f78c2cfd42ed7d1ca6cfd35288b561120db.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT healthy, created_at FROM healthchecks WHERE check_type = 'min_alive_workers_' || $1 AND created_at > NOW() - INTERVAL '24 hours' ORDER BY created_at DESC", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "healthy", + "type_info": "Bool" + }, + { + "ordinal": 1, + "name": "created_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "c1ceb03e0eafd2e494c06cef1ec96f78c2cfd42ed7d1ca6cfd35288b561120db" +} diff --git a/backend/.sqlx/query-cf1cef7e0fe2e7e3db96b0ec005360361b9eec023a6fc2a4a7a917f59d86af4d.json b/backend/.sqlx/query-cf1cef7e0fe2e7e3db96b0ec005360361b9eec023a6fc2a4a7a917f59d86af4d.json new file mode 100644 index 0000000000..2556ac5580 --- /dev/null +++ b/backend/.sqlx/query-cf1cef7e0fe2e7e3db96b0ec005360361b9eec023a6fc2a4a7a917f59d86af4d.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT name, format_extension FROM resource_type WHERE format_extension IS NOT NULL AND (workspace_id = $1 OR workspace_id = 'admins')", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "format_extension", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + true + ] + }, + "hash": "cf1cef7e0fe2e7e3db96b0ec005360361b9eec023a6fc2a4a7a917f59d86af4d" +} diff --git a/backend/.sqlx/query-d5a8614286c170e0d175903cd1b53ff66b37ed8110a0b67aedb9f25e6a7383e1.json b/backend/.sqlx/query-d5a8614286c170e0d175903cd1b53ff66b37ed8110a0b67aedb9f25e6a7383e1.json index 6d48bd9f44..164157b02f 100644 --- a/backend/.sqlx/query-d5a8614286c170e0d175903cd1b53ff66b37ed8110a0b67aedb9f25e6a7383e1.json +++ b/backend/.sqlx/query-d5a8614286c170e0d175903cd1b53ff66b37ed8110a0b67aedb9f25e6a7383e1.json @@ -76,7 +76,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-d600a0ad953ed131952d9c46deb8f65143894f86517f2b5b2d51bc9a2857695c.json b/backend/.sqlx/query-d600a0ad953ed131952d9c46deb8f65143894f86517f2b5b2d51bc9a2857695c.json new file mode 100644 index 0000000000..34afed8276 --- /dev/null +++ b/backend/.sqlx/query-d600a0ad953ed131952d9c46deb8f65143894f86517f2b5b2d51bc9a2857695c.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT (scalar_int)::int FROM job_stats WHERE job_id = $1 AND workspace_id = $2 AND metric_id = 'progress_perc'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "scalar_int", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Uuid", + "Text" + ] + }, + "nullable": [ + true + ] + }, + "hash": "d600a0ad953ed131952d9c46deb8f65143894f86517f2b5b2d51bc9a2857695c" +} diff --git a/backend/.sqlx/query-dee32ce9c4010ae407b4d1ba2ecf2062c36ee5dab3d4894ad4b2aa8b2f5a0db9.json b/backend/.sqlx/query-dee32ce9c4010ae407b4d1ba2ecf2062c36ee5dab3d4894ad4b2aa8b2f5a0db9.json new file mode 100644 index 0000000000..bb8d339e55 --- /dev/null +++ b/backend/.sqlx/query-dee32ce9c4010ae407b4d1ba2ecf2062c36ee5dab3d4894ad4b2aa8b2f5a0db9.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS(SELECT 1 FROM log_file WHERE hostname = $1 AND log_ts = $2)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Timestamp" + ] + }, + "nullable": [ + null + ] + }, + "hash": "dee32ce9c4010ae407b4d1ba2ecf2062c36ee5dab3d4894ad4b2aa8b2f5a0db9" +} diff --git a/backend/.sqlx/query-e1c715020f1efb00123171edfb6173bfeaaa95d4f870240e42b76e5df304ce99.json b/backend/.sqlx/query-e1c715020f1efb00123171edfb6173bfeaaa95d4f870240e42b76e5df304ce99.json index 9d5cfdf5af..38c8521741 100644 --- a/backend/.sqlx/query-e1c715020f1efb00123171edfb6173bfeaaa95d4f870240e42b76e5df304ce99.json +++ b/backend/.sqlx/query-e1c715020f1efb00123171edfb6173bfeaaa95d4f870240e42b76e5df304ce99.json @@ -55,7 +55,9 @@ "powershell", "mssql", "php", - "bunnative" + "bunnative", + "rust", + "ansible" ] } } diff --git a/backend/.sqlx/query-eb1f7f01461f5a7540c273b37e5d578c31cf151ab3ef813f7aada76533761e12.json b/backend/.sqlx/query-eb1f7f01461f5a7540c273b37e5d578c31cf151ab3ef813f7aada76533761e12.json index cd523b4c22..73c1fd7b2c 100644 --- a/backend/.sqlx/query-eb1f7f01461f5a7540c273b37e5d578c31cf151ab3ef813f7aada76533761e12.json +++ b/backend/.sqlx/query-eb1f7f01461f5a7540c273b37e5d578c31cf151ab3ef813f7aada76533761e12.json @@ -32,6 +32,11 @@ "ordinal": 5, "name": "created_by", "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "format_extension", + "type_info": "Varchar" } ], "parameters": { @@ -43,6 +48,7 @@ true, true, true, + true, true ] }, diff --git a/backend/.sqlx/query-fb581eb6f883ebb5909a00c65a6e1217f088290fce0e052171230bcd88f945b9.json b/backend/.sqlx/query-fb581eb6f883ebb5909a00c65a6e1217f088290fce0e052171230bcd88f945b9.json new file mode 100644 index 0000000000..b3f640dd76 --- /dev/null +++ b/backend/.sqlx/query-fb581eb6f883ebb5909a00c65a6e1217f088290fce0e052171230bcd88f945b9.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO global_settings (name, value) VALUES ('slack', $1) ON CONFLICT (name) DO UPDATE SET value = $1, updated_at = now()", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb" + ] + }, + "nullable": [] + }, + "hash": "fb581eb6f883ebb5909a00c65a6e1217f088290fce0e052171230bcd88f945b9" +} diff --git a/backend/.sqlx/query-d249343a1d9fce2f7ca9e6e447eb32d7d11b61acdab80dda24db4a9ba3e1f7e6.json b/backend/.sqlx/query-ffedbb3a2676a6d7b71f81f89109a02a8dba90d40144e942527f8a3fc36dfbc1.json similarity index 57% rename from backend/.sqlx/query-d249343a1d9fce2f7ca9e6e447eb32d7d11b61acdab80dda24db4a9ba3e1f7e6.json rename to backend/.sqlx/query-ffedbb3a2676a6d7b71f81f89109a02a8dba90d40144e942527f8a3fc36dfbc1.json index a3cd9e0c30..c58dfad63a 100644 --- a/backend/.sqlx/query-d249343a1d9fce2f7ca9e6e447eb32d7d11b61acdab80dda24db4a9ba3e1f7e6.json +++ b/backend/.sqlx/query-ffedbb3a2676a6d7b71f81f89109a02a8dba90d40144e942527f8a3fc36dfbc1.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO resource_type\n (workspace_id, name, schema, description, created_by, edited_at)\n VALUES ($1, $2, $3, $4, $5, now())", + "query": "INSERT INTO resource_type\n (workspace_id, name, schema, description, created_by, format_extension, edited_at)\n VALUES ($1, $2, $3, $4, $5, $6, now())", "describe": { "columns": [], "parameters": { @@ -9,10 +9,11 @@ "Varchar", "Jsonb", "Text", + "Varchar", "Varchar" ] }, "nullable": [] }, - "hash": "d249343a1d9fce2f7ca9e6e447eb32d7d11b61acdab80dda24db4a9ba3e1f7e6" + "hash": "ffedbb3a2676a6d7b71f81f89109a02a8dba90d40144e942527f8a3fc36dfbc1" } diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 58231cc1d2..48eae53d77 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] @@ -177,9 +177,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "arc-swap" @@ -229,9 +229,9 @@ checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -286,7 +286,7 @@ dependencies = [ "arrow-data", "arrow-schema", "chrono", - "chrono-tz", + "chrono-tz 0.9.0", "half", "hashbrown 0.14.5", "num", @@ -383,7 +383,7 @@ dependencies = [ "arrow-schema", "chrono", "half", - "indexmap 2.4.0", + "indexmap 2.5.0", "lexical-core", "num", "serde", @@ -465,7 +465,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -529,13 +529,13 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-lite 2.3.0", "slab", ] @@ -548,61 +548,32 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", - "async-io 2.3.4", - "async-lock 3.4.0", + "async-io", + "async-lock", "blocking", "futures-lite 2.3.0", "once_cell", ] -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2 0.4.10", - "waker-fn", -] - [[package]] name = "async-io" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ - "async-lock 3.4.0", + "async-lock", "cfg-if", "concurrent-queue", "futures-io", "futures-lite 2.3.0", "parking", - "polling 3.7.3", - "rustix 0.38.34", + "polling", + "rustix", "slab", "tracing", "windows-sys 0.59.0", ] -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - [[package]] name = "async-lock" version = "3.4.0" @@ -641,24 +612,24 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "async-std" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" dependencies = [ "async-channel 1.9.0", "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io", + "async-lock", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 1.13.0", + "futures-lite 2.3.0", "gloo-timers", "kv-log-macro", "log", @@ -689,7 +660,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -725,13 +696,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -785,9 +756,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "aws-config" -version = "1.5.5" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e95816a168520d72c0e7680c405a5a8c1fb6a035b4bc4b9d7b0de8e1a941697" +checksum = "848d7b9b605720989929279fa644ce8f244d0ce3146fcca5b70e4eb7b3c020fc" dependencies = [ "aws-credential-types", "aws-runtime", @@ -802,7 +773,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.1.0", + "fastrand 2.1.1", "hex", "http 0.2.12", "ring 0.17.8", @@ -815,9 +786,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16838e6c9e12125face1c1eff1343c75e3ff540de98ff7ebd61874a89bcfeb9" +checksum = "60e8f6b615cb5fc60a98132268508ad104310f0cfb25a1c22eee76efdf9154da" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -827,19 +798,20 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.4.0" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f42c2d4218de4dcd890a109461e2f799a1a2ba3bcd2cde9af88360f5df9266c6" +checksum = "a10d5c055aa540164d9561a0e2e74ad30f0dcf7393c3a92f6733ddf9c5762468" dependencies = [ "aws-credential-types", "aws-sigv4", "aws-smithy-async", "aws-smithy-http", + "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.1.0", + "fastrand 2.1.1", "http 0.2.12", "http-body 0.4.6", "once_cell", @@ -851,9 +823,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.39.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11822090cf501c316c6f75711d77b96fba30658e3867a7762e5e2f5d32d31e81" +checksum = "70a9d27ed1c12b1140c47daf1bc541606c43fdafd918c4797d520db0043ceef2" dependencies = [ "aws-credential-types", "aws-runtime", @@ -873,9 +845,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.40.0" +version = "1.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78a2a06ff89176123945d1bbe865603c4d7101bea216a550bb4d2e4e9ba74d74" +checksum = "44514a6ca967686cde1e2a1b81df6ef1883d0e3e570da8d8bc5c491dcb6fc29b" dependencies = [ "aws-credential-types", "aws-runtime", @@ -895,9 +867,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.39.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20a91795850826a6f456f4a48eff1dfa59a0e69bdbf5b8c50518fd372106574" +checksum = "cd7a4d279762a35b9df97209f6808b95d4fe78547fe2316b4d200a0283960c5a" dependencies = [ "aws-credential-types", "aws-runtime", @@ -918,9 +890,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df1b0fa6be58efe9d4ccc257df0a53b89cd8909e86591a13ca54817c87517be" +checksum = "cc8db6904450bafe7473c6ca9123f88cc11089e41a025408f992db4e22d3be68" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -952,9 +924,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.60.9" +version = "0.60.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9cd0ae3d97daa0a2bf377a4d8e8e1362cae590c4a1aad0d40058ebca18eb91e" +checksum = "5c8bc3e8fdc6b8d07d976e301c02fe553f72a39b7a9fea820e023268467d7ab6" dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", @@ -991,16 +963,16 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.6.3" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0abbf454960d0db2ad12684a1640120e7557294b0ff8e2f11236290a1b293225" +checksum = "d1ce695746394772e7000b39fe073095db6d45a862d0767dd5ad0ac0d7f8eb87" dependencies = [ "aws-smithy-async", "aws-smithy-http", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", - "fastrand 2.1.0", + "fastrand 2.1.1", "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", @@ -1035,9 +1007,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.2" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cee7cadb433c781d3299b916fbf620fea813bf38f49db282fb6858141a05cc8" +checksum = "03701449087215b5369c7ea17fef0dd5d24cb93439ec5af0c7615f58c3f22605" dependencies = [ "base64-simd 0.8.0", "bytes", @@ -1061,9 +1033,9 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.8" +version = "0.60.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d123fbc2a4adc3c301652ba8e149bf4bc1d1725affb9784eb20c953ace06bf55" +checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" dependencies = [ "xmlparser", ] @@ -1078,7 +1050,7 @@ dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", "aws-smithy-types", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "tracing", ] @@ -1140,17 +1112,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide 0.8.0", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -1264,13 +1236,13 @@ dependencies = [ "lazy_static", "lazycell", "log", - "prettyplease 0.2.20", + "prettyplease 0.2.22", "proc-macro2", "quote", "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.75", + "syn 2.0.77", "which 4.4.2", ] @@ -1289,7 +1261,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -1362,7 +1334,7 @@ dependencies = [ "arrayvec", "cc", "cfg-if", - "constant_time_eq 0.3.0", + "constant_time_eq 0.3.1", ] [[package]] @@ -1433,7 +1405,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "syn_derive", ] @@ -1507,9 +1479,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" dependencies = [ "bytemuck_derive", ] @@ -1522,7 +1494,7 @@ checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -1533,9 +1505,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "bytes-utils" @@ -1637,9 +1609,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.13" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" dependencies = [ "jobserver", "libc", @@ -1695,7 +1667,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" dependencies = [ "chrono", - "chrono-tz-build", + "chrono-tz-build 0.3.0", + "phf", +] + +[[package]] +name = "chrono-tz" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6" +dependencies = [ + "chrono", + "chrono-tz-build 0.4.0", "phf", ] @@ -1710,6 +1693,16 @@ dependencies = [ "phf_codegen", ] +[[package]] +name = "chrono-tz-build" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7" +dependencies = [ + "parse-zoneinfo", + "phf_codegen", +] + [[package]] name = "cipher" version = "0.3.0" @@ -1742,9 +1735,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.16" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", @@ -1752,9 +1745,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", @@ -1771,7 +1764,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -1886,9 +1879,9 @@ dependencies = [ [[package]] name = "const_format" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" dependencies = [ "const_format_proc_macros", "konst", @@ -1896,9 +1889,9 @@ dependencies = [ [[package]] name = "const_format_proc_macros" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" dependencies = [ "proc-macro2", "quote", @@ -1913,9 +1906,9 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "convert_case" @@ -1977,9 +1970,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -2144,7 +2137,7 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "subtle", "zeroize", ] @@ -2157,7 +2150,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -2205,7 +2198,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -2227,7 +2220,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -2289,7 +2282,7 @@ dependencies = [ "glob", "half", "hashbrown 0.14.5", - "indexmap 2.4.0", + "indexmap 2.5.0", "itertools 0.12.1", "log", "num_cpus", @@ -2458,7 +2451,7 @@ dependencies = [ "datafusion-expr", "datafusion-physical-expr", "hashbrown 0.14.5", - "indexmap 2.4.0", + "indexmap 2.5.0", "itertools 0.12.1", "log", "regex-syntax 0.8.4", @@ -2487,7 +2480,7 @@ dependencies = [ "half", "hashbrown 0.14.5", "hex", - "indexmap 2.4.0", + "indexmap 2.5.0", "itertools 0.12.1", "log", "paste", @@ -2531,7 +2524,7 @@ dependencies = [ "futures", "half", "hashbrown 0.14.5", - "indexmap 2.4.0", + "indexmap 2.5.0", "itertools 0.12.1", "log", "once_cell", @@ -2678,11 +2671,11 @@ dependencies = [ "http 1.1.0", "http-body-util", "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper-rustls 0.27.3", "hyper-util", "ipnet", "percent-encoding", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "serde", "serde_json", "tokio", @@ -2714,7 +2707,7 @@ dependencies = [ "dlopen2", "dlopen2_derive", "once_cell", - "rustls-native-certs 0.7.2", + "rustls-native-certs 0.7.3", "rustls-pemfile 2.1.3", ] @@ -2747,7 +2740,7 @@ dependencies = [ "quote", "strum 0.25.0", "strum_macros 0.25.3", - "syn 2.0.75", + "syn 2.0.77", "thiserror", ] @@ -2796,13 +2789,13 @@ checksum = "2b995ce6016bc4f05453c8632a9d42a58536c1cbb7ece09f1aa66dda3f8d474b" dependencies = [ "deno_core", "deno_native_certs", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pemfile 2.1.3", "rustls-tokio-stream", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "serde", "tokio", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] @@ -2925,8 +2918,8 @@ dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 2.0.75", + "rustc_version 0.4.1", + "syn 2.0.77", ] [[package]] @@ -3023,7 +3016,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -3172,14 +3165,14 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -3199,7 +3192,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -3288,9 +3281,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "ff" @@ -3310,9 +3303,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "filetime" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", @@ -3333,14 +3326,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8add37afff2d4ffa83bc748a70b4b1370984f6980768554182424ef71447c35f" dependencies = [ "bitflags 1.3.2", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] name = "flate2" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c0596c1eac1f9e04ed902702e9878208b336edc9d6fddc8a48387349bab3666" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", "libz-sys", @@ -3402,59 +3395,63 @@ checksum = "32016f1242eb82af5474752d00fd8ebcd9004bd69b462b1c91de833972d08ed4" dependencies = [ "proc-macro2", "swc_macros_common", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "frunk" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a351b59e12f97b4176ee78497dff72e4276fb1ceb13e19056aca7fa0206287" +checksum = "874b6a17738fc273ec753618bac60ddaeac48cb1d7684c3e7bd472e57a28b817" dependencies = [ "frunk_core", "frunk_derives", "frunk_proc_macros", + "serde", ] [[package]] name = "frunk_core" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2469fab0bd07e64ccf0ad57a1438f63160c69b2e57f04a439653d68eb558d6" +checksum = "3529a07095650187788833d585c219761114005d5976185760cf794d265b6a5c" +dependencies = [ + "serde", +] [[package]] name = "frunk_derives" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fa992f1656e1707946bbba340ad244f0814009ef8c0118eb7b658395f19a2e" +checksum = "e99b8b3c28ae0e84b604c75f721c21dc77afb3706076af5e8216d15fd1deaae3" dependencies = [ "frunk_proc_macro_helpers", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "frunk_proc_macro_helpers" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35b54add839292b743aeda6ebedbd8b11e93404f902c56223e51b9ec18a13d2c" +checksum = "05a956ef36c377977e512e227dcad20f68c2786ac7a54dacece3746046fea5ce" dependencies = [ "frunk_core", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "frunk_proc_macros" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b85a1d4a9a6b300b41c05e8e13ef2feca03e0334127f29eca9506a7fe13a93" +checksum = "67e86c2c9183662713fea27ea527aad20fb15fee635a71081ff91bf93df4dc51" dependencies = [ "frunk_core", "frunk_proc_macro_helpers", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -3463,7 +3460,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7e180ac76c23b45e767bd7ae9579bc0bb458618c4bc71835926e098e61d15f8" dependencies = [ - "rustix 0.38.34", + "rustix", "windows-sys 0.52.0", ] @@ -3563,7 +3560,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-core", "futures-io", "parking", @@ -3578,7 +3575,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -3810,9 +3807,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "git-version" @@ -3831,7 +3828,7 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -3855,9 +3852,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "gloo-timers" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", @@ -3909,7 +3906,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.4.0", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -3928,7 +3925,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.4.0", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -4249,16 +4246,16 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", "hyper 1.4.1", "hyper-util", - "rustls 0.23.12", - "rustls-native-certs 0.7.2", + "rustls 0.23.13", + "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -4316,9 +4313,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -4382,9 +4379,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -4437,17 +4434,6 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "ipconfig" version = "0.3.2" @@ -4462,9 +4448,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "is-macro" @@ -4475,7 +4461,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -4537,9 +4523,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -4564,7 +4550,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee7893dab2e44ae5f9d0173f26ff4aa327c10b01b06a72b52dd9405b628640d" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.5.0", ] [[package]] @@ -4724,14 +4710,14 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.3", + "redox_syscall 0.5.4", ] [[package]] name = "libsqlite3-sys" -version = "0.28.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -4751,9 +4737,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc53a7799a7496ebc9fd29f31f7df80e83c9bda5299768af5f9e59eeea74647" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", @@ -4767,12 +4753,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -4890,9 +4870,9 @@ dependencies = [ [[package]] name = "mail-parser" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5a1335c3a964788c90cb42ae04a34b5f2628e89566949ce3bd4ada695c0bcd" +checksum = "93c3b9e5d8b17faf573330bbc43b37d6e918c0a3bf8a88e7d0a220ebc84af9fc" dependencies = [ "encoding_rs", "serde", @@ -4907,19 +4887,19 @@ dependencies = [ "base64 0.22.1", "gethostname", "mail-builder", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pki-types", "smtp-proto", "tokio", "tokio-rustls 0.26.0", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] name = "malachite" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905472e3a4adfc48b7a6eeb8beb7aba09e851b9e74ba53a4b53798e401b2badf" +checksum = "5616515d632967cd329b6f6db96be9a03ea0b3a49cdbc45b0016803dad8a77b7" dependencies = [ "malachite-base", "malachite-nz", @@ -4928,9 +4908,9 @@ dependencies = [ [[package]] name = "malachite-base" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5f8d7930df6fcb9c86761ca0999ba484d7b6469c81cee4a7d38da5386440f96" +checksum = "46059721011b0458b7bd6d9179be5d0b60294281c23320c207adceaecc54d13b" dependencies = [ "hashbrown 0.14.5", "itertools 0.11.0", @@ -4953,9 +4933,9 @@ dependencies = [ [[package]] name = "malachite-nz" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa263ca62420c1f65cf6758f55c979a49ad83169f332e602b1890f1e1277a429" +checksum = "1503b27e825cabd1c3d0ff1e95a39fb2ec9eab6fd3da6cfa41aec7091d273e78" dependencies = [ "itertools 0.11.0", "libm", @@ -4964,9 +4944,9 @@ dependencies = [ [[package]] name = "malachite-q" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7619384a5b9b54dd576ae5dd9a8a9438353ada4e50adf737c2e002088ba366e" +checksum = "a475503a70a3679dbe3b9b230a23622516742528ba614a7b2490f180ea9cb514" dependencies = [ "itertools 0.11.0", "malachite-base", @@ -5045,9 +5025,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", "stable_deref_trait", @@ -5078,16 +5058,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "minicov" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" -dependencies = [ - "cc", - "walkdir", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -5142,7 +5112,7 @@ checksum = "a7ce64b975ed4f123575d11afd9491f2e37bbd5813fbfbc0f09ae1fbddea74e0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -5181,7 +5151,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "termcolor", "thiserror", ] @@ -5448,9 +5418,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -5591,7 +5561,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -5680,9 +5650,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -5702,7 +5672,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall 0.5.4", "smallvec", "windows-targets 0.52.6", ] @@ -5848,7 +5818,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.4.0", + "indexmap 2.5.0", ] [[package]] @@ -5909,7 +5879,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -5950,7 +5920,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -5972,7 +5942,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-io", ] @@ -6025,22 +5995,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - [[package]] name = "polling" version = "3.7.3" @@ -6051,7 +6005,7 @@ dependencies = [ "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.34", + "rustix", "tracing", "windows-sys 0.59.0", ] @@ -6095,9 +6049,9 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02048d9e032fb3cc3413bbf7b83a15d84a5d419778e2628751896d856498eee9" +checksum = "f66ea23a2d0e5734297357705193335e0a957696f34bed2f2faefacb2fec336f" dependencies = [ "array-init", "bit-vec", @@ -6143,12 +6097,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.20" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -6162,11 +6116,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit 0.22.21", ] [[package]] @@ -6201,7 +6155,7 @@ checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f" dependencies = [ "proc-macro-rules-macros", "proc-macro2", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -6213,7 +6167,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -6274,7 +6228,7 @@ dependencies = [ "schemars", "serde", "serde_json", - "syn 2.0.75", + "syn 2.0.77", "thiserror", "typify", "unicode-ident", @@ -6294,7 +6248,7 @@ dependencies = [ "serde_json", "serde_tokenstream", "serde_yaml", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -6337,7 +6291,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -6351,9 +6305,9 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" dependencies = [ "cc", ] @@ -6378,6 +6332,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags 2.6.0", + "getopts", + "memchr", + "unicase", +] + [[package]] name = "pulp" version = "0.18.22" @@ -6418,9 +6384,9 @@ dependencies = [ [[package]] name = "quick_cache" -version = "0.6.3" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc1dd700847420feb1735b16f8d7ee8a8704f4caec7b1aa19f074ea4f7f25ae" +checksum = "7d7c94f8935a9df96bb6380e8592c70edf497a643f94bd23b2f76b399385dbf4" dependencies = [ "ahash 0.8.11", "equivalent", @@ -6430,16 +6396,16 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.12", + "rustls 0.23.13", "socket2 0.5.7", "thiserror", "tokio", @@ -6448,15 +6414,15 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand 0.8.5", "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.12", + "rustls 0.23.13", "slab", "thiserror", "tinyvec", @@ -6465,22 +6431,22 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ "libc", "once_cell", "socket2 0.5.7", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -6657,18 +6623,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags 2.6.0", ] @@ -6822,7 +6779,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper-rustls 0.27.3", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -6834,15 +6791,15 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.12", - "rustls-native-certs 0.7.2", + "rustls 0.23.13", + "rustls-native-certs 0.7.3", "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.1", - "system-configuration 0.6.0", + "system-configuration 0.6.1", "tokio", "tokio-native-tls", "tokio-rustls 0.26.0", @@ -7017,7 +6974,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.75", + "syn 2.0.77", "walkdir", ] @@ -7087,9 +7044,9 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.23", ] @@ -7109,28 +7066,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.27" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys", "windows-sys 0.52.0", ] @@ -7148,15 +7091,15 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "log", "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -7175,9 +7118,22 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04182dffc9091a404e0fc069ea5cd60e5b866c3adf881eff99a32d048242dffa" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.3", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", "rustls-pemfile 2.1.3", @@ -7218,7 +7174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22557157d7395bc30727745b365d923f1ecc230c4c80b176545f3f4f08c46e33" dependencies = [ "futures", - "rustls 0.23.12", + "rustls 0.23.13", "socket2 0.5.7", "tokio", ] @@ -7235,9 +7191,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -7317,9 +7273,9 @@ checksum = "ad97d4ce1560a5e27cec89519dc8300d1aa6035b099821261c651486a19e44d5" [[package]] name = "safetensors" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7725d4d98fa515472f43a6e2bbf956c48e06b89bb50593a040e5945160214450" +checksum = "44560c11236a6130a46ce36c836a62936dc81ebf8c36a37947423571be0e55b6" dependencies = [ "serde", "serde_json", @@ -7369,11 +7325,11 @@ checksum = "ece8e78b2f38ec51c51f5d475df0a7187ba5111b2a28bdc761ee05b075d40a71" [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -7399,7 +7355,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -7499,9 +7455,9 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -7540,13 +7496,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -7557,16 +7513,16 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.5.0", "itoa", "memchr", "ryu", @@ -7632,7 +7588,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -7670,7 +7626,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.4.0", + "indexmap 2.5.0", "serde", "serde_derive", "serde_json", @@ -7687,7 +7643,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -7696,7 +7652,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.5.0", "itoa", "ryu", "serde", @@ -8011,9 +7967,9 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ "nom", "unicode_categories", @@ -8037,14 +7993,14 @@ checksum = "01b2e185515564f15375f593fb966b5718bc624ba77fe49fa4616ad619690554" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "sqlx" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27144619c6e5802f1380337a209d2ac1c431002dd74c6e60aebff3c506dc4f0c" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -8055,9 +8011,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a999083c1af5b5d6c071d34a708a19ba3e02106ad82ef7bbd69f5e48266b613b" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ "atoi", "bigdecimal", @@ -8076,14 +8032,14 @@ dependencies = [ "hashbrown 0.14.5", "hashlink", "hex", - "indexmap 2.4.0", + "indexmap 2.5.0", "log", "memchr", "once_cell", "paste", "percent-encoding", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls 0.23.13", + "rustls-pemfile 2.1.3", "serde", "serde_json", "sha2 0.10.8", @@ -8095,27 +8051,27 @@ dependencies = [ "tracing", "url", "uuid 1.10.0", - "webpki-roots 0.25.4", + "webpki-roots 0.26.6", ] [[package]] name = "sqlx-macros" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23217eb7d86c584b8cbe0337b9eacf12ab76fe7673c513141ec42565698bb88" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "sqlx-macros-core" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a099220ae541c5db479c6424bdf1b200987934033c2584f79a0e1693601e776" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", @@ -8131,7 +8087,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.75", + "syn 2.0.77", "tempfile", "tokio", "url", @@ -8139,9 +8095,9 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5afe4c38a9b417b6a9a5eeffe7235d0a106716495536e7727d1c7f4b1ff3eba6" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", "base64 0.22.1", @@ -8184,9 +8140,9 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1dbb157e65f10dbe01f729339c06d239120221c9ad9fa0ba8408c4cc18ecf21" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", "base64 0.22.1", @@ -8226,9 +8182,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2cdd83c008a622d94499c0006d8ee5f821f36c89b7d625c900e5dc30b5c5ee" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "chrono", @@ -8257,15 +8213,15 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stacker" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a5daa25ea337c85ed954c0496e3bdd2c7308cc3b24cf7b50d04876654c579f" +checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b" dependencies = [ "cc", "cfg-if", "libc", "psm", - "windows-sys 0.36.1", + "windows-sys 0.59.0", ] [[package]] @@ -8283,7 +8239,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -8337,7 +8293,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -8350,7 +8306,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -8453,7 +8409,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84b67e115ab136fe0eb03558bb0508ca7782eeb446a96d165508c48617e3fd94" dependencies = [ "anyhow", - "indexmap 2.4.0", + "indexmap 2.5.0", "serde", "serde_json", "swc_cached", @@ -8469,7 +8425,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -8535,7 +8491,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -8604,7 +8560,7 @@ checksum = "d37dc505c92af56d0f77cf6f31a6ccd37ac40cad1e01ff77277e0b1c70e8f8ff" dependencies = [ "better_scoped_tls", "bitflags 2.6.0", - "indexmap 2.4.0", + "indexmap 2.5.0", "once_cell", "phf", "rustc-hash 1.1.0", @@ -8642,7 +8598,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -8673,7 +8629,7 @@ checksum = "446da32cac8299973aaf1d37496562bfd0c1e4f3c3ab5d0af6f07f42e8184102" dependencies = [ "base64 0.21.7", "dashmap", - "indexmap 2.4.0", + "indexmap 2.5.0", "once_cell", "serde", "sha1", @@ -8712,7 +8668,7 @@ version = "0.130.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13e62b199454a576c5fdbd7e1bef8ab88a395427456d8a713d994b7d469833aa" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.5.0", "num_cpus", "once_cell", "rustc-hash 1.1.0", @@ -8761,7 +8717,7 @@ checksum = "695a1d8b461033d32429b5befbf0ad4d7a2c4d6ba9cd5ba4e0645c615839e8e4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -8772,7 +8728,7 @@ checksum = "91745f3561057493d2da768437c427c0e979dff7396507ae02f16c981c4a8466" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -8795,7 +8751,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -8811,9 +8767,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.75" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -8829,7 +8785,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -8855,7 +8811,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -8885,9 +8841,9 @@ dependencies = [ [[package]] name = "system-configuration" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bc6ee10a9b4fcf576e9b0819d95ec16f4d2c02d39fd83ac1c8789785c4a42" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.6.0", "core-foundation", @@ -9079,9 +9035,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", - "fastrand 2.1.0", + "fastrand 2.1.1", "once_cell", - "rustix 0.38.34", + "rustix", "windows-sys 0.59.0", ] @@ -9120,7 +9076,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -9319,9 +9275,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -9344,7 +9300,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -9359,9 +9315,9 @@ dependencies = [ [[package]] name = "tokio-postgres" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03adcf0147e203b6032c0b2d30be1415ba03bc348901f3ff1cc0df6a733e60c3" +checksum = "3b5d3742945bc7d7f210693b0c58ae542c6fd47b17adbbda0885f3dcb34a6bdb" dependencies = [ "async-trait", "byteorder", @@ -9399,7 +9355,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pki-types", "tokio", ] @@ -9418,9 +9374,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -9444,9 +9400,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -9477,7 +9433,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.20", + "toml_edit 0.22.21", ] [[package]] @@ -9495,7 +9451,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.5.0", "serde", "serde_spanned", "toml_datetime", @@ -9504,22 +9460,11 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" dependencies = [ - "indexmap 2.4.0", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" -dependencies = [ - "indexmap 2.4.0", + "indexmap 2.5.0", "serde", "serde_spanned", "toml_datetime", @@ -9557,9 +9502,9 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36b837f86b25d7c0d7988f00a54e74739be6477f2aac6201b8f429a7569991b7" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" dependencies = [ "tower-layer", "tower-service", @@ -9627,6 +9572,18 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.27" @@ -9635,7 +9592,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -9853,7 +9810,7 @@ dependencies = [ "regress", "schemars", "serde_json", - "syn 2.0.75", + "syn 2.0.77", "thiserror", "unicode-ident", ] @@ -9870,7 +9827,7 @@ dependencies = [ "serde", "serde_json", "serde_tokenstream", - "syn 2.0.75", + "syn 2.0.77", "typify-impl", ] @@ -9967,9 +9924,9 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-id" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1b6def86329695390197b82c1e244a54a131ceb66c996f2088a3876e2ae083f" +checksum = "10103c57044730945224467c09f71a4db0071c123a0648cc3e818913bde6b561" [[package]] name = "unicode-id-start" @@ -9979,15 +9936,15 @@ checksum = "02aebfa694eccbbbffdd92922c7de136b9fe764396d2f10e21bce1681477cfc1" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -10009,21 +9966,21 @@ checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unicode_categories" @@ -10033,9 +9990,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "unicode_names2" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addeebf294df7922a1164f729fb27ebbbcea99cc32b3bf08afab62757f707677" +checksum = "d1673eca9782c84de5f81b82e4109dcfb3611c8ba0d52930ec4a9478f547b2dd" dependencies = [ "phf", "unicode_names2_generator", @@ -10043,9 +10000,9 @@ dependencies = [ [[package]] name = "unicode_names2_generator" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f444b8bba042fe3c1251ffaca35c603f2dc2ccc08d595c65a8c4f76f3e8426c0" +checksum = "b91e5b84611016120197efd7dc93ef76774f4e084cd73c9fb3ea4a86c570c56e" dependencies = [ "getopts", "log", @@ -10082,12 +10039,12 @@ dependencies = [ "log", "native-tls", "once_cell", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pki-types", "serde", "serde_json", "url", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] @@ -10244,35 +10201,34 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", - "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -10282,9 +10238,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10292,32 +10248,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-bindgen-test" -version = "0.3.43" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9" +checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" dependencies = [ "console_error_panic_hook", "js-sys", - "minicov", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -10326,13 +10281,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.43" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" +checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -10359,9 +10314,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -10385,9 +10340,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -10401,7 +10356,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.34", + "rustix", ] [[package]] @@ -10412,17 +10367,17 @@ checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" dependencies = [ "either", "home", - "rustix 0.38.34", + "rustix", "winsafe", ] [[package]] name = "whoami" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall 0.5.4", "wasite", "web-sys", ] @@ -10466,7 +10421,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "axum", @@ -10478,9 +10433,11 @@ dependencies = [ "gethostname", "git-version", "lazy_static", + "object_store", "once_cell", "pg-embed", "prometheus", + "quote", "rand 0.8.5", "reqwest 0.12.7", "rsmq_async", @@ -10506,7 +10463,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "argon2", @@ -10523,7 +10480,7 @@ dependencies = [ "candle-nn", "candle-transformers", "chrono", - "chrono-tz", + "chrono-tz 0.10.0", "cookie 0.17.0", "crc", "cron", @@ -10569,7 +10526,7 @@ dependencies = [ "tokio-native-tls", "tokio-tar", "tokio-util", - "tower 0.5.0", + "tower 0.5.1", "tower-cookies", "tower-http", "tracing", @@ -10590,7 +10547,7 @@ dependencies = [ [[package]] name = "windmill-api-client" -version = "1.383.1" +version = "1.397.1" dependencies = [ "base64 0.21.7", "chrono", @@ -10608,7 +10565,7 @@ dependencies = [ [[package]] name = "windmill-audit" -version = "1.383.1" +version = "1.397.1" dependencies = [ "chrono", "serde", @@ -10621,7 +10578,7 @@ dependencies = [ [[package]] name = "windmill-common" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "async-stream", @@ -10630,13 +10587,15 @@ dependencies = [ "axum", "bytes", "chrono", + "const_format", "cron", "futures-core", + "gethostname", "git-version", "hex", "hmac", "hyper 1.4.1", - "indexmap 2.4.0", + "indexmap 2.5.0", "itertools 0.13.0", "lazy_static", "magic-crypt", @@ -10654,6 +10613,7 @@ dependencies = [ "tikv-jemalloc-ctl", "tokio", "tracing", + "tracing-appender", "tracing-flame", "tracing-loki", "tracing-subscriber", @@ -10662,7 +10622,7 @@ dependencies = [ [[package]] name = "windmill-git-sync" -version = "1.383.1" +version = "1.397.1" dependencies = [ "regex", "rsmq_async", @@ -10677,7 +10637,7 @@ dependencies = [ [[package]] name = "windmill-indexer" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "bytes", @@ -10698,26 +10658,28 @@ dependencies = [ [[package]] name = "windmill-parser" -version = "1.383.1" +version = "1.397.1" dependencies = [ + "convert_case 0.6.0", "serde", "serde_json", ] [[package]] name = "windmill-parser-bash" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "lazy_static", "regex", + "regex-lite", "serde_json", "windmill-parser", ] [[package]] name = "windmill-parser-go" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "gosyn", @@ -10729,32 +10691,30 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "lazy_static", "regex", + "regex-lite", "serde_json", "windmill-parser", ] [[package]] name = "windmill-parser-php" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", - "convert_case 0.6.0", "itertools 0.13.0", - "lazy_static", "php-parser-rs", - "regex", "serde_json", "windmill-parser", ] [[package]] name = "windmill-parser-py" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "itertools 0.13.0", @@ -10765,7 +10725,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "async-recursion", @@ -10773,6 +10733,7 @@ dependencies = [ "lazy_static", "phf", "regex", + "regex-lite", "rustpython-parser", "serde_json", "sqlx", @@ -10780,23 +10741,40 @@ dependencies = [ "windmill-parser", ] +[[package]] +name = "windmill-parser-rust" +version = "1.397.1" +dependencies = [ + "anyhow", + "convert_case 0.6.0", + "itertools 0.13.0", + "lazy_static", + "pulldown-cmark", + "quote", + "regex", + "serde_json", + "syn 2.0.77", + "toml 0.7.8", + "windmill-parser", +] + [[package]] name = "windmill-parser-sql" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "lazy_static", "regex", + "regex-lite", "serde_json", "windmill-parser", ] [[package]] name = "windmill-parser-ts" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", - "convert_case 0.6.0", "lazy_static", "regex", "serde-wasm-bindgen", @@ -10812,7 +10790,7 @@ dependencies = [ [[package]] name = "windmill-parser-wasm" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "getrandom 0.2.15", @@ -10825,20 +10803,32 @@ dependencies = [ "windmill-parser-graphql", "windmill-parser-php", "windmill-parser-py", + "windmill-parser-rust", "windmill-parser-sql", "windmill-parser-ts", + "windmill-parser-yaml", +] + +[[package]] +name = "windmill-parser-yaml" +version = "1.397.1" +dependencies = [ + "anyhow", + "serde_json", + "windmill-parser", + "yaml-rust", ] [[package]] name = "windmill-queue" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "async-recursion", "axum", "bigdecimal", "chrono", - "chrono-tz", + "chrono-tz 0.10.0", "cron", "futures-core", "hex", @@ -10864,7 +10854,7 @@ dependencies = [ [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.383.1" +version = "1.397.1" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -10874,7 +10864,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.383.1" +version = "1.397.1" dependencies = [ "anyhow", "async-recursion", @@ -10939,9 +10929,12 @@ dependencies = [ "windmill-parser-php", "windmill-parser-py", "windmill-parser-py-imports", + "windmill-parser-rust", "windmill-parser-sql", "windmill-parser-ts", + "windmill-parser-yaml", "windmill-queue", + "yaml-rust", "zstd 0.12.4", ] @@ -10984,19 +10977,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -11067,12 +11047,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -11085,12 +11059,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -11109,12 +11077,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -11127,12 +11089,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -11157,12 +11113,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -11225,8 +11175,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", - "linux-raw-sys 0.4.14", - "rustix 0.38.34", + "linux-raw-sys", + "rustix", ] [[package]] @@ -11244,6 +11194,15 @@ dependencies = [ "lzma-sys", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yansi" version = "0.5.1" @@ -11270,7 +11229,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "synstructure", ] @@ -11292,7 +11251,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -11312,7 +11271,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "synstructure", ] diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 05890db10c..c77b140846 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.383.1" +version = "1.397.1" authors.workspace = true edition.workspace = true @@ -18,14 +18,16 @@ members = [ "./parsers/windmill-parser-ts", "./parsers/windmill-parser-wasm", "./parsers/windmill-parser-go", + "./parsers/windmill-parser-rust", "./parsers/windmill-parser-bash", "./parsers/windmill-parser-py", "./parsers/windmill-parser-py-imports", "./parsers/windmill-sql-datatype-parser-wasm", + "./parsers/windmill-parser-yaml", ] [workspace.package] -version = "1.383.1" +version = "1.397.1" authors = ["Ruben Fiszel "] edition = "2021" @@ -47,7 +49,7 @@ flamegraph = ["windmill-common/flamegraph", "windmill-worker/flamegraph"] loki = ["windmill-common/loki"] pg_embed = ["dep:pg-embed"] embedding = ["windmill-api/embedding"] -parquet = ["windmill-api/parquet", "windmill-common/parquet", "windmill-worker/parquet", "windmill-indexer/parquet"] +parquet = ["windmill-api/parquet", "windmill-common/parquet", "windmill-worker/parquet", "windmill-indexer/parquet", "dep:object_store"] prometheus = ["windmill-common/prometheus", "windmill-api/prometheus", "windmill-worker/prometheus", "windmill-queue/prometheus"] flow_testing = ["windmill-worker/flow_testing"] openidconnect = ["windmill-api/openidconnect"] @@ -84,7 +86,9 @@ gethostname.workspace = true serde_json.workspace = true serde.workspace = true deno_core.workspace = true +object_store = { workspace = true, optional = true } pg-embed = {git = "https://github.com/faokunega/pg-embed", optional = true, default-features = false, features = ['rt_tokio']} +quote.workspace = true [target.'cfg(not(target_env = "msvc"))'.dependencies] @@ -114,6 +118,8 @@ windmill-parser-ts = { path = "./parsers/windmill-parser-ts" } windmill-parser-py = { path = "./parsers/windmill-parser-py" } windmill-parser-py-imports = { path = "./parsers/windmill-parser-py-imports" } windmill-parser-go = { path = "./parsers/windmill-parser-go" } +windmill-parser-rust = { path = "./parsers/windmill-parser-rust" } +windmill-parser-yaml = { path = "./parsers/windmill-parser-yaml" } windmill-parser-bash = { path = "./parsers/windmill-parser-bash" } windmill-parser-sql = { path = "./parsers/windmill-parser-sql" } windmill-parser-graphql = { path = "./parsers/windmill-parser-graphql" } @@ -136,6 +142,7 @@ chrono = { version = "0.4.35", features = ["serde"] } chrono-tz = "^0" tracing = "^0" tracing-subscriber = { version = "^0", features = ["env-filter", "json"] } +tracing-appender = "^0" prometheus = { version = "^0", default-features = false } cookie = { version = "0.17.0" } phf = { version = "0.11", features = ["macros"] } @@ -214,7 +221,7 @@ rsmq_async = { version = "5.1.5" } gosyn = "0.2.6" bytes = "1.4.0" gethostname = "0.4.3" -wasm-bindgen = "0.2.92" +wasm-bindgen = "=0.2.92" serde-wasm-bindgen = "0.6.5" wasm-bindgen-test = "0.3.42" convert_case = "0.6.0" @@ -266,3 +273,10 @@ tikv-jemalloc-ctl = { version = "^0.5" } triomphe = "<0.1.12" tantivy = "0.22.0" + +pulldown-cmark = "0.9" +toml = "0.7" +syn = { version = "2.0.74", features = ["full"] } +quote = "1.0.36" +regex-lite = "0.1.6" +yaml-rust = "0.4.5" diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 8260652cea..c2d0f0dd53 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -7cf76a8c6694b59f4615b0c8fa61fb02411326a7 \ No newline at end of file +534f50aae2f89281304b3c3ba943d18afc07fad4 \ No newline at end of file diff --git a/backend/migrations/20240613150524_add_job_perms.down.sql b/backend/migrations/20240613150524_add_job_perms.down.sql index d2f607c5b8..f489666b92 100644 --- a/backend/migrations/20240613150524_add_job_perms.down.sql +++ b/backend/migrations/20240613150524_add_job_perms.down.sql @@ -1 +1,2 @@ -- Add down migration script here +DROP TABLE public.job_perms; \ No newline at end of file diff --git a/backend/migrations/20240807114128_add_rust_lang.down.sql b/backend/migrations/20240807114128_add_rust_lang.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240807114128_add_rust_lang.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240807114128_add_rust_lang.up.sql b/backend/migrations/20240807114128_add_rust_lang.up.sql new file mode 100644 index 0000000000..2a3cc1bae1 --- /dev/null +++ b/backend/migrations/20240807114128_add_rust_lang.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER TYPE SCRIPT_LANG ADD VALUE IF NOT EXISTS 'rust'; +UPDATE config set config = jsonb_set(config, '{worker_tags}', config->'worker_tags' || '["rust"]'::jsonb) where name = 'worker__default' and config @> '{"worker_tags": ["deno", "python3", "go", "bash", "powershell", "dependency", "flow", "hub", "other", "bun", "php"]}'::jsonb AND NOT config->'worker_tags' @> '"rust"'::jsonb; diff --git a/backend/migrations/20240815085729_add_logfile.down.sql b/backend/migrations/20240815085729_add_logfile.down.sql new file mode 100644 index 0000000000..c2a9f2d62d --- /dev/null +++ b/backend/migrations/20240815085729_add_logfile.down.sql @@ -0,0 +1,4 @@ +-- Add down migration script here +DROP TABLE log_file; +DROP TYPE LOG_MODE; + diff --git a/backend/migrations/20240815085729_add_logfile.up.sql b/backend/migrations/20240815085729_add_logfile.up.sql new file mode 100644 index 0000000000..1a79a9e7b1 --- /dev/null +++ b/backend/migrations/20240815085729_add_logfile.up.sql @@ -0,0 +1,16 @@ +-- Add up migration script here +-- Add up migration script here +CREATE TYPE LOG_MODE AS ENUM ('standalone', 'server', 'worker', 'agent', 'indexer'); +CREATE TABLE log_file ( + hostname VARCHAR(255) NOT NULL, + log_ts TIMESTAMP, + ok_lines BIGINT, + err_lines BIGINT, + mode LOG_MODE NOT NULL, + worker_group VARCHAR(255), + file_path VARCHAR(510) NOT NULL, + PRIMARY KEY (hostname, log_ts) +); + +CREATE INDEX log_file_log_ts_idx ON log_file (log_ts); +CREATE INDEX log_file_hostname_log_ts_idx ON log_file (hostname, log_ts); \ No newline at end of file diff --git a/backend/migrations/20240829143329_alert_center.down.sql b/backend/migrations/20240829143329_alert_center.down.sql new file mode 100644 index 0000000000..fe1cb273be --- /dev/null +++ b/backend/migrations/20240829143329_alert_center.down.sql @@ -0,0 +1,3 @@ +-- Add down migration script here +drop table alerts; +drop table healthchecks; \ No newline at end of file diff --git a/backend/migrations/20240829143329_alert_center.up.sql b/backend/migrations/20240829143329_alert_center.up.sql new file mode 100644 index 0000000000..7cf4f65ba7 --- /dev/null +++ b/backend/migrations/20240829143329_alert_center.up.sql @@ -0,0 +1,16 @@ +-- Add up migration script here +create table alerts ( + id serial PRIMARY KEY, + alert_type varchar(50) NOT NULL, + message text NOT NULL, + created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +create table healthchecks ( + id bigserial PRIMARY KEY, + check_type varchar(50) NOT NULL, + healthy boolean NOT NULL, + created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +create index healthchecks_check_type_created_at on healthchecks(check_type, created_at); diff --git a/backend/migrations/20240831202016_add_json_fmt_to_log_file.down.sql b/backend/migrations/20240831202016_add_json_fmt_to_log_file.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240831202016_add_json_fmt_to_log_file.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240831202016_add_json_fmt_to_log_file.up.sql b/backend/migrations/20240831202016_add_json_fmt_to_log_file.up.sql new file mode 100644 index 0000000000..df50f2bc9a --- /dev/null +++ b/backend/migrations/20240831202016_add_json_fmt_to_log_file.up.sql @@ -0,0 +1,2 @@ +-- Add up migration script here +ALTER TABLE log_file ADD COLUMN IF NOT EXISTS json_fmt boolean DEFAULT false; \ No newline at end of file diff --git a/backend/migrations/20240906082526_add_ansible_lang.down.sql b/backend/migrations/20240906082526_add_ansible_lang.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240906082526_add_ansible_lang.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240906082526_add_ansible_lang.up.sql b/backend/migrations/20240906082526_add_ansible_lang.up.sql new file mode 100644 index 0000000000..6f9df11f42 --- /dev/null +++ b/backend/migrations/20240906082526_add_ansible_lang.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER TYPE SCRIPT_LANG ADD VALUE IF NOT EXISTS 'ansible'; +UPDATE config set config = jsonb_set(config, '{worker_tags}', config->'worker_tags' || '["ansible"]'::jsonb) where name = 'worker__default' and config @> '{"worker_tags": ["deno", "python3", "go", "bash", "powershell", "dependency", "flow", "hub", "other", "bun", "php", "rust"]}'::jsonb AND NOT config->'worker_tags' @> '"ansible"'::jsonb; diff --git a/backend/migrations/20240906151147_add_success_handler.down.sql b/backend/migrations/20240906151147_add_success_handler.down.sql new file mode 100644 index 0000000000..33b6e62539 --- /dev/null +++ b/backend/migrations/20240906151147_add_success_handler.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +ALTER TABLE schedule DROP COLUMN on_success, DROP COLUMN on_success_extra_args; \ No newline at end of file diff --git a/backend/migrations/20240906151147_add_success_handler.up.sql b/backend/migrations/20240906151147_add_success_handler.up.sql new file mode 100644 index 0000000000..3465ed5ea5 --- /dev/null +++ b/backend/migrations/20240906151147_add_success_handler.up.sql @@ -0,0 +1,2 @@ +-- Add up migration script here +ALTER TABLE schedule ADD COLUMN on_success VARCHAR(1000), ADD COLUMN on_success_extra_args json; \ No newline at end of file diff --git a/backend/migrations/20240907150910_migrate_to_new_cli.down.sql b/backend/migrations/20240907150910_migrate_to_new_cli.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240907150910_migrate_to_new_cli.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240907150910_migrate_to_new_cli.up.sql b/backend/migrations/20240907150910_migrate_to_new_cli.up.sql new file mode 100644 index 0000000000..aa88241d14 --- /dev/null +++ b/backend/migrations/20240907150910_migrate_to_new_cli.up.sql @@ -0,0 +1,11 @@ + +-- Add up migration script here +UPDATE script SET content = 'import * as wmill from "windmill-cli@1.393.2" + +export async function main(x: string) { + await wmill.hubPull({ workspace: "admins", token: process.env["WM_TOKEN"], baseUrl: process.env["BASE_URL"] }) + return x +} +', language = 'bun', +lock = '{\n "dependencies": {\n "windmill-cli": "latest"\n }\n}\n//bun.lockb\n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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACmAgAANAAAgAMAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA2gIAAE4AAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADEDAAA6AACAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABrAwAASAAAgAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAswMAAEYAAIAFAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABYEAABMAACABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABiBAAAPgAAgAQAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAArwQAAEYAAIAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPUEAAA7AACACgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA/BQAARgAAgAIAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAkwUAAEQAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANcFAAAyAACAAwAAAAcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAqBgAATAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdgYAAEYAAIACAAAAAwAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMHAABEAACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABHBwAARAAAgAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAiwcAAD4AAIAFAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkHAABQAACAAgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAZCAAANgAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAATwgAADgAAIACAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAIcIAABAAACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADHCAAAMQAAgAEAAAAAAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA+AgAAC4AAIADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAC8JAAA6AACAAwAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABpCQAASAAAgAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAsQkAADcAAIAEAAAAEwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8KAABOAACAAAAAAAUAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAANCwAAPgAAgAUAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAASwsAAEoAAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJULAABIAACAAQAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADdCwAARAAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAIQwAAEQAAIAAAAAAAQAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGUMAABCAACAAQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACnDAAAQQAAgAEAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA6AwAAD4AAIABAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAACYNAAA6AACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABgDQAAOAAAgAEAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAmA0AADEAAIAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkNAABAAACAAQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAJDgAAPgAAgAIAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAARw4AADgAAIABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAH8OAAA+AACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADJDgAAQAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACQ8AADgAAIACAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEEPAAAwAACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABxDwAANgAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAApw8AADIAAIAAAAAABQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANkPAAAyAACAAgAAAAYAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAALEAAALAAAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxAAADAAAIABAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGcQAAAwAACAAQAAAAgAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACXEAAALAAAgAIAAAABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAwxAAAEAAAIABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMRAAA0AACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA3EQAAQAAAgAEAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdxEAAD4AAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAALURAAA/AACAAQAAABQAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD+EQAAPQAAgAAAAAAEAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAUxIAAEAAAIACAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJMSAAA4AACAAgAAAAUAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADLEgAAMgAAgAMAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA/RIAADcAAIABAAAABgAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEkTAAA+AACAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACHEwAAPQAAgAIAAAABAAAAIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxBMAADcAAIABAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPsTAAAtAACABgAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA0FAAAQAAAgAEAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAoRQAAEUAAIABAAAADQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOYUAABCAACAAQAAAAIAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABJFQAANAAAgAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAfRUAAEIAAIABAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8VAAA+AACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD9FQAAOgAAgAEAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxYAADoAAIABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHEWAAA6AACAAQAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADQFgAATgAAgAEAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAShcAAFgAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKIXAABMAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADuFwAAMAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAHhgAAFAAAIABAAAAAQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAG4YAAA8AACAAgAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC8GAAAOgAAgAEAAAAJAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA9hgAADoAAIAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADAZAAA2AACAAQAAAAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABmGQAANgAAgAEAAAADAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAphkAADwAAIAAAAAABgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOIZAAA0AACAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAWGgAAMAAAgAEAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAURoAADcAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGgcAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACsHAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA8hwAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADodAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAB+HQAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxh0AAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABIeAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABYHgAARAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAnB4AAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOQeAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAwHwAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAeB8AAE4AAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMYfAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAASIAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAWCAAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKAgAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADkIAAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAALCEAAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHghAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC+IQAASgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACCIAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAFAiAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACcIgAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAbWltZQAAAABjbGkuanMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAZXNidWlsZABGGgAACwAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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bmFsU3RyaW5nPiAxNiBzaXplb2YsIDggYWxpZ25vZgp4lwAAAAAAANa7AAAAAAAACjx1OD4gMSBzaXplb2YsIDEgYWxpZ25vZgoAAHdpbmRtaWxsLWNsaWVzbS9tYWluLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2luZG1pbGwtY2xpLy0vd2luZG1pbGwtY2xpLTEuMzkzLjIudGd6QGF5b25saS9qc2V4dGdpdGlnbm9yZS1wYXJzZXJtaW5pbWF0Y2h3aW5kbWlsbC1jbGllbnRAZGVuby9zaGltLWRlbm9odHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZGVuby9zaGltLWRlbm8vLS9zaGltLWRlbm8tMC4xOC4yLnRnekBkZW5vL3NoaW0tZGVuby10ZXN0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGRlbm8vc2hpbS1kZW5vLXRlc3QvLS9zaGltLWRlbm8tdGVzdC0wLjUuMC50Z3pub2RlLXdoaWNoYmluL3doaWNoLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2hpY2gvLS93aGljaC00LjAuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pc2V4ZS8tL2lzZXhlLTMuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dzLy0vd3MtOC4xOC4wLnRnemJ1ZmZlcnV0aWx1dGYtOC12YWxpZGF0ZWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dpbmRtaWxsLWNsaWVudC8tL3dpbmRtaWxsLWNsaWVudC0xLjM2NC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL29wZW4vLS9vcGVuLTEwLjEuMC50Z3pkZWZhdWx0LWJyb3dzZXJkZWZpbmUtbGF6eS1wcm9waXMtaW5zaWRlLWNvbnRhaW5lcmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzLXdzbC8tL2lzLXdzbC0zLjEuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1pbnNpZGUtY29udGFpbmVyLy0vaXMtaW5zaWRlLWNvbnRhaW5lci0xLjAuMC50Z3ppcy1kb2NrZXJodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1kb2NrZXIvLS9pcy1kb2NrZXItMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmaW5lLWxhenktcHJvcC8tL2RlZmluZS1sYXp5LXByb3AtMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLy0vZGVmYXVsdC1icm93c2VyLTUuMi4xLnRnemJ1bmRsZS1uYW1lZGVmYXVsdC1icm93c2VyLWlkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLWlkLy0vZGVmYXVsdC1icm93c2VyLWlkLTUuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2J1bmRsZS1uYW1lLy0vYnVuZGxlLW5hbWUtNC4xLjAudGd6cnVuLWFwcGxlc2NyaXB0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcnVuLWFwcGxlc2NyaXB0Ly0vcnVuLWFwcGxlc2NyaXB0LTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21pbmltYXRjaC8tL21pbmltYXRjaC0xMC4wLjEudGd6YnJhY2UtZXhwYW5zaW9uaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnJhY2UtZXhwYW5zaW9uLy0vYnJhY2UtZXhwYW5zaW9uLTIuMC4xLnRnemJhbGFuY2VkLW1hdGNoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYmFsYW5jZWQtbWF0Y2gvLS9iYWxhbmNlZC1tYXRjaC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9qc3ppcC8tL2pzemlwLTMuNy4xLnRnenJlYWRhYmxlLXN0cmVhbXNldC1pbW1lZGlhdGUtc2hpbWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NldC1pbW1lZGlhdGUtc2hpbS8tL3NldC1pbW1lZGlhdGUtc2hpbS0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yZWFkYWJsZS1zdHJlYW0vLS9yZWFkYWJsZS1zdHJlYW0tMi4zLjgudGd6Y29yZS11dGlsLWlzcHJvY2Vzcy1uZXh0aWNrLWFyZ3NzYWZlLWJ1ZmZlcnN0cmluZ19kZWNvZGVydXRpbC1kZXByZWNhdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlsLWRlcHJlY2F0ZS8tL3V0aWwtZGVwcmVjYXRlLTEuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0cmluZ19kZWNvZGVyLy0vc3RyaW5nX2RlY29kZXItMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZS1idWZmZXIvLS9zYWZlLWJ1ZmZlci01LjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wcm9jZXNzLW5leHRpY2stYXJncy8tL3Byb2Nlc3MtbmV4dGljay1hcmdzLTIuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzYXJyYXkvLS9pc2FycmF5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2luaGVyaXRzLy0vaW5oZXJpdHMtMi4wLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29yZS11dGlsLWlzLy0vY29yZS11dGlsLWlzLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Bha28vLS9wYWtvLTEuMC4xMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9saWUvLS9saWUtMy4zLjAudGd6aW1tZWRpYXRlaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaW1tZWRpYXRlLy0vaW1tZWRpYXRlLTMuMC42LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dpdGlnbm9yZS1wYXJzZXIvLS9naXRpZ25vcmUtcGFyc2VyLTAuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2V4cHJlc3MvLS9leHByZXNzLTQuMTkuMi50Z3plbmNvZGV1cmxwcm94eS1hZGRyYm9keS1wYXJzZXJlc2NhcGUtaHRtbGh0dHAtZXJyb3Jzb24tZmluaXNoZWR1dGlscy1tZXJnZWNvbnRlbnQtdHlwZWZpbmFsaGFuZGxlcnJhbmdlLXBhcnNlcnNlcnZlLXN0YXRpY2FycmF5LWZsYXR0ZW5wYXRoLXRvLXJlZ2V4cHNldHByb3RvdHlwZW9mY29va2llLXNpZ25hdHVyZW1lcmdlLWRlc2NyaXB0b3JzY29udGVudC1kaXNwb3NpdGlvbmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtZGlzcG9zaXRpb24vLS9jb250ZW50LWRpc3Bvc2l0aW9uLTAuNS40LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NhZmUtYnVmZmVyLy0vc2FmZS1idWZmZXItNS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVyZ2UtZGVzY3JpcHRvcnMvLS9tZXJnZS1kZXNjcmlwdG9ycy0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9jb29raWUtc2lnbmF0dXJlLy0vY29va2llLXNpZ25hdHVyZS0xLjAuNi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zZXRwcm90b3R5cGVvZi8tL3NldHByb3RvdHlwZW9mLTEuMi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3BhdGgtdG8tcmVnZXhwLy0vcGF0aC10by1yZWdleHAtMC4xLjcudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYXJyYXktZmxhdHRlbi8tL2FycmF5LWZsYXR0ZW4tMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2VydmUtc3RhdGljLy0vc2VydmUtc3RhdGljLTEuMTUuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lc2NhcGUtaHRtbC8tL2VzY2FwZS1odG1sLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VuY29kZXVybC8tL2VuY29kZXVybC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wYXJzZXVybC8tL3BhcnNldXJsLTEuMy4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NlbmQvLS9zZW5kLTAuMTguMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yYW5nZS1wYXJzZXIvLS9yYW5nZS1wYXJzZXItMS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvb24tZmluaXNoZWQvLS9vbi1maW5pc2hlZC0yLjQuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lZS1maXJzdC8tL2VlLWZpcnN0LTEuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2h0dHAtZXJyb3JzLy0vaHR0cC1lcnJvcnMtMi4wLjAudGd6dG9pZGVudGlmaWVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdG9pZGVudGlmaWVyLy0vdG9pZGVudGlmaWVyLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0YXR1c2VzLy0vc3RhdHVzZXMtMi4wLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVwZC8tL2RlcGQtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVzdHJveS8tL2Rlc3Ryb3ktMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnJlc2gvLS9mcmVzaC0wLjUuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9kZWJ1Zy8tL2RlYnVnLTIuNi45LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21zLy0vbXMtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS8tL21pbWUtMS42LjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXRhZy8tL2V0YWctMS44LjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbXMvLS9tcy0yLjEuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9maW5hbGhhbmRsZXIvLS9maW5hbGhhbmRsZXItMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdW5waXBlLy0vdW5waXBlLTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtdHlwZS8tL2NvbnRlbnQtdHlwZS0xLjAuNS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlscy1tZXJnZS8tL3V0aWxzLW1lcmdlLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2JvZHktcGFyc2VyLy0vYm9keS1wYXJzZXItMS4yMC4yLnRnemljb252LWxpdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pY29udi1saXRlLy0vaWNvbnYtbGl0ZS0wLjQuMjQudGd6Pj0gMi4xLjIgPCAzc2FmZXItYnVmZmVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZXItYnVmZmVyLy0vc2FmZXItYnVmZmVyLTIuMS4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Jhdy1ib2R5Ly0vcmF3LWJvZHktMi41LjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnl0ZXMvLS9ieXRlcy0zLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy90eXBlLWlzLy0vdHlwZS1pcy0xLjYuMTgudGd6bWltZS10eXBlc21lZGlhLXR5cGVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVkaWEtdHlwZXIvLS9tZWRpYS10eXBlci0wLjMuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9taW1lLXR5cGVzLy0vbWltZS10eXBlcy0yLjEuMzUudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS1kYi8tL21pbWUtZGItMS41Mi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3FzLy0vcXMtNi4xMS4wLnRnenNpZGUtY2hhbm5lbGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NpZGUtY2hhbm5lbC8tL3NpZGUtY2hhbm5lbC0xLjAuNi50Z3pjYWxsLWJpbmRlcy1lcnJvcnNnZXQtaW50cmluc2ljb2JqZWN0LWluc3BlY3RodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9vYmplY3QtaW5zcGVjdC8tL29iamVjdC1pbnNwZWN0LTEuMTMuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9nZXQtaW50cmluc2ljLy0vZ2V0LWludHJpbnNpYy0xLjIuNC50Z3pmdW5jdGlvbi1iaW5kaGFzLXByb3RvaGFzLXN5bWJvbHNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXNvd24vLS9oYXNvd24tMi4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnVuY3Rpb24tYmluZC8tL2Z1bmN0aW9uLWJpbmQtMS4xLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaGFzLXN5bWJvbHMvLS9oYXMtc3ltYm9scy0xLjAuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvdG8vLS9oYXMtcHJvdG8tMS4wLjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZXJyb3JzLy0vZXMtZXJyb3JzLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NhbGwtYmluZC8tL2NhbGwtYmluZC0xLjAuNy50Z3plcy1kZWZpbmUtcHJvcGVydHlzZXQtZnVuY3Rpb24tbGVuZ3RoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2V0LWZ1bmN0aW9uLWxlbmd0aC8tL3NldC1mdW5jdGlvbi1sZW5ndGgtMS4yLjIudGd6ZGVmaW5lLWRhdGEtcHJvcGVydHloYXMtcHJvcGVydHktZGVzY3JpcHRvcnNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMvLS9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMtMS4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZGVmaW5lLXByb3BlcnR5Ly0vZXMtZGVmaW5lLXByb3BlcnR5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dvcGQvLS9nb3BkLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RlZmluZS1kYXRhLXByb3BlcnR5Ly0vZGVmaW5lLWRhdGEtcHJvcGVydHktMS4xLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcHJveHktYWRkci8tL3Byb3h5LWFkZHItMi4wLjcudGd6Zm9yd2FyZGVkaXBhZGRyLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaXBhZGRyLmpzLy0vaXBhZGRyLmpzLTEuOS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ZvcndhcmRlZC8tL2ZvcndhcmRlZC0wLjIuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9tZXRob2RzLy0vbWV0aG9kcy0xLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9hY2NlcHRzLy0vYWNjZXB0cy0xLjMuOC50Z3puZWdvdGlhdG9yaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbmVnb3RpYXRvci8tL25lZ290aWF0b3ItMC42LjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29va2llLy0vY29va2llLTAuNi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3ZhcnkvLS92YXJ5LTEuMS4yLnRnemJpbi9lc2J1aWxkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXNidWlsZC8tL2VzYnVpbGQtMC4yMy4xLnRnekBlc2J1aWxkL2FpeC1wcGM2NEBlc2J1aWxkL2FuZHJvaWQtYXJtQGVzYnVpbGQvYW5kcm9pZC1hcm02NEBlc2J1aWxkL2FuZHJvaWQteDY0QGVzYnVpbGQvZGFyd2luLWFybTY0QGVzYnVpbGQvZGFyd2luLXg2NEBlc2J1aWxkL2ZyZWVic2QtYXJtNjRAZXNidWlsZC9mcmVlYnNkLXg2NEBlc2J1aWxkL2xpbnV4LWFybUBlc2J1aWxkL2xpbnV4LWFybTY0QGVzYnVpbGQvbGludXgtaWEzMkBlc2J1aWxkL2xpbnV4LWxvb25nNjRAZXNidWlsZC9saW51eC1taXBzNjRlbEBlc2J1aWxkL2xpbnV4LXBwYzY0QGVzYnVpbGQvbGludXgtcmlzY3Y2NEBlc2J1aWxkL2xpbnV4LXMzOTB4QGVzYnVpbGQvbGludXgteDY0QGVzYnVpbGQvbmV0YnNkLXg2NEBlc2J1aWxkL29wZW5ic2QtYXJtNjRAZXNidWlsZC9vcGVuYnNkLXg2NEBlc2J1aWxkL3N1bm9zLXg2NEBlc2J1aWxkL3dpbjMyLWFybTY0QGVzYnVpbGQvd2luMzItaWEzMkBlc2J1aWxkL3dpbjMyLXg2NGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLXg2NC8tL3dpbjMyLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvd2luMzItaWEzMi8tL3dpbjMyLWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLWFybTY0Ly0vd2luMzItYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3N1bm9zLXg2NC8tL3N1bm9zLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC14NjQvLS9vcGVuYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC1hcm02NC8tL29wZW5ic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL25ldGJzZC14NjQvLS9uZXRic2QteDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC14NjQvLS9saW51eC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXMzOTB4Ly0vbGludXgtczM5MHgtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXJpc2N2NjQvLS9saW51eC1yaXNjdjY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1wcGM2NC8tL2xpbnV4LXBwYzY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1taXBzNjRlbC8tL2xpbnV4LW1pcHM2NGVsLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1sb29uZzY0Ly0vbGludXgtbG9vbmc2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvbGludXgtaWEzMi8tL2xpbnV4LWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybTY0Ly0vbGludXgtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybS8tL2xpbnV4LWFybS0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC14NjQvLS9mcmVlYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC1hcm02NC8tL2ZyZWVic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2Rhcndpbi14NjQvLS9kYXJ3aW4teDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9kYXJ3aW4tYXJtNjQvLS9kYXJ3aW4tYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQteDY0Ly0vYW5kcm9pZC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQtYXJtNjQvLS9hbmRyb2lkLWFybTY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9hbmRyb2lkLWFybS8tL2FuZHJvaWQtYXJtLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9haXgtcHBjNjQvLS9haXgtcHBjNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VzLW1haW4vLS9lcy1tYWluLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RpZmYvLS9kaWZmLTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0BheW9ubGkvanNleHQvLS9qc2V4dC0wLjkuNjMudGd6c3Vkby1wcm9tcHRodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zdWRvLXByb21wdC8tL3N1ZG8tcHJvbXB0LTkuMi4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ljb252LWxpdGUvLS9pY29udi1saXRlLTAuNi4zLnRnej49IDIuMS4yIDwgMy4wLjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==' +WHERE hash = -28028598712388162 AND workspace_id = 'admins'; \ No newline at end of file diff --git a/backend/migrations/20240908214334_migrate_to_new_cli_2.down.sql b/backend/migrations/20240908214334_migrate_to_new_cli_2.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240908214334_migrate_to_new_cli_2.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240908214334_migrate_to_new_cli_2.up.sql b/backend/migrations/20240908214334_migrate_to_new_cli_2.up.sql new file mode 100644 index 0000000000..445ecee8f5 --- /dev/null +++ b/backend/migrations/20240908214334_migrate_to_new_cli_2.up.sql @@ -0,0 +1,17 @@ +-- Add up migration script here + +-- Add up migration script here +UPDATE script SET content = 'import * as wmill from "windmill-cli@1.393.2" + +export async function main() { + await wmill.hubPull({ workspace: "admins", token: process.env["WM_TOKEN"], baseUrl: process.env["BASE_URL"] }); +} +', language = 'bun', +lock = '{ + "dependencies": { + "windmill-cli": "latest" + } +} +//bun.lockb +IyEvdXNyL2Jpbi9lbnYgYnVuCmJ1bi1sb2NrZmlsZS1mb3JtYXQtdjAKAgAAADZs4+6pAntv6Gcmv9boDBPUxzf1WFcr6QlPZXdejHxj3rsAAAAAAAB/AAAAAAAAAAgAAAAAAAAACAAAAAAAAACAAAAAAAAAAAN+AAAAAAAAAAAAAAAAAAAAAAAAAAAMAACAjgAAAA8AAIDeAAAAFAAAgHdoaWNoAAAAaXNleGUAAAB3cwAAAAAAAH8AAAAPAACAb3BlbgAAAABpcy13c2wAAJMCAAATAACAKAMAAAkAAICDAgAAEAAAgHQCAAAPAACABAQAABIAAID5AwAACwAAgKAEAAAPAACAdgAAAAkAAIAwBQAADwAAgIUFAAAOAACAanN6aXAAAAAYBgAAEgAAgAkGAAAPAACA9QYAAA4AAIDnBgAADgAAgNwGAAALAACAyAYAABQAAIBpc2FycmF5AGluaGVyaXRzvAYAAAwAAIBwYWtvAAAAAGxpZQAAAAAAJgkAAAkAAIBmAAAAEAAAgGV4cHJlc3MArAoAABMAAIDcBgAACwAAgJsKAAARAACAiwoAABAAAIB9CgAADgAAgG8KAAAOAACAYgoAAA0AAIBWCgAADAAAgAYKAAALAACA6AkAAAkAAIBwYXJzZXVybHNlbmQAAAAASgoAAAwAAIAcCgAACwAAgGVlLWZpcnN0EQoAAAsAAIC9DgAADAAAgHN0YXR1c2VzZGVwZAAAAABkZXN0cm95AGZyZXNoAAAAZGVidWcAAABtcwAAAAAAAG1pbWUAAAAAZXRhZwAAAABtcwAAAAAAAD4KAAAMAACAdW5waXBlAAAyCgAADAAAgCcKAAALAACA+wkAAAsAAID0EQAACgAAgEcSAAAMAACAcmF3LWJvZHlieXRlcwAAAHR5cGUtaXMAPhMAAAsAAIA0EwAACgAAgG1pbWUtZGIAcXMAAAAAAAAoFAAADAAAgJMUAAAOAACAhhQAAA0AAIBoYXNvd24AACgVAAANAACAPhUAAAsAAIA1FQAACQAAgH0UAAAJAACAdBQAAAkAAIC9FgAAEwAAgDIXAAAYAACAqxYAABIAAIBnb3BkAAAAAB4XAAAUAACA8QkAAAoAAICzGAAACQAAgKoYAAAJAACAbWV0aG9kcwBhY2NlcHRzAJwZAAAKAACAY29va2llAAB2YXJ5AAAAAGVzYnVpbGQAVhwAABIAAIBDHAAAEwAAgC8cAAAUAACAHRwAABIAAIAJHAAAFAAAgPMbAAAWAACA4BsAABMAAIDOGwAAEgAAgLobAAAUAACApBsAABYAAICQGwAAFAAAgHkbAAAXAACAYxsAABYAAIBQGwAAEwAAgDwbAAAUAACAKhsAABIAAIAWGwAAFAAAgAAbAAAWAACA7RoAABMAAIDYGgAAFQAAgMQaAAAUAACArhoAABYAAICaGgAAFAAAgIgaAAASAACAZXMtbWFpbgBkaWZmAAAAAFkAAAANAACAySMAAAsAAID0EQAACgAAgAAAAAAAAAAAjXMqtgf1QSfVqtrJiGJRfQkrLIxflZh6zG2O96NP8kaoLFfaUxLq1wcESX24jjzLmQ1nY/ePqP86/4YWqwXdAiLwpdtElNniRZFku3lzNwR46KOUH/7zM3q/FOAUERX5jwge6KFzpdc5tTtdIg2K5DCQVnHT53CASLo1WxSMLiMfAuJeUe7ucFm/7gWc3u0oV1HUTV3yyeGhAGTHGI/oi3ivxiIcTZjCy+0FWEEmvzaiM9ZOn6X5N7vS5mKoc7SHIdsvXideIefLO0Y7l3ulTxPefb/TYzkSEZrqFxjf1Ge2h6G4RW+Ips8pG9voSJrm03RIAmd848v0i2YEy18wuWI1+rrrUq2yLUrGRXEubx7dQ0Hc3VH6qSHbL14nXiHnTtp2+m5wviqbvCu3PnmxOnc+72XAbJAuC3Znf9Xf/iuETwhuPIOZWpt8LAXlw/fhyT/azL6Im7S0qOJ6Dzeu9HIQv7fy+VyQNs3oOqeu6P0G6CHMTQoMsThFZaJiAxdbEI95h4xd7WhNmb434wqMrt2MxpELDAct4RvC9IRrAfE0jrBCvDhscI5ukc7EeeM1+8ASh8Vgb52OgwA04RrKxqS0xNW1149IZiOG1+0PgQK7ZxljywG5KqS0xNW1149IalsvWr3TBCSOWeuZeCgtmxtg85GEWxZQVuHuNK1GLpUsytXsrdATRcmvPrpkVDwg+Q0itRVAoPB4NFx+gLclgqjINcRNuuZtc1/8HZD4iEFiWaeBsOaPOC8Bk5dey2H0w8Wk8f3GpW4XeINmbZ3zzQ0W+FrwjOB9RXlCmrvBRQ3srz2hFLVVKEg/iwmJSuDQm5nKGnFtuAsHnJHMI4Pmoh0c/X+RqufJJU0hoMQ/3BM/XvJ2+kOfrPC3iJCZCOU4og6YuXWNu0AYn3uZjahUMv0/Ucm4aJeZ1RzA3FO0xKRtxKN+P97YUeer5VNuspkUe/TWOX+rcFjk0RGQrjZf7dTAB0Tn+biUcgVr5uhAkPiT06TkMVPtBRDg22TUyYyIECM9Q3cH87c2TMy2oZK0eggRPiu4AZTMyPaAH3ykVZPB5ZGoExdH95M77CNqjZqIMhF9VuG6UmKIBKxoXxE6eOeWdPKhP/a7Yhb8CQ8fFPZsYKL/1pG5QSoSKDMBi+Oh0aEQHcQo6U+rRmldcj8nnKKpfmruCCXS24NmRjGW2sFpuTyoNAZt5sIA7kcm6QJADRdE6Z6udscwQppftwYPAp4bMLrT6WNaGPr6MVLKNmVSPtArHB0Rp8gHUJdG6G3C3t6/nasyvTmXXSZYY/glCeh4dtSNTIka5NOL1K5eN/SPRV5V16nxj8mvPrpkVDwgAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAFwAAAEIAAIABAAAAiQEAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJ0AAABBAACAAAAAABIAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADyAAAASgAAgAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAUgEAADIAAIAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAIQBAAAyAACAAwAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC2AQAALQAAgAgAAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA+wEAAEgAAIABAAAAbAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEMCAAAxAACACgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACmAgAANAAAgAMAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA2gIAAE4AAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADEDAAA6AACAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABrAwAASAAAgAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAswMAAEYAAIAFAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABYEAABMAACABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABiBAAAPgAAgAQAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAArwQAAEYAAIAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPUEAAA7AACACgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA/BQAARgAAgAIAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAkwUAAEQAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANcFAAAyAACAAwAAAAcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAqBgAATAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdgYAAEYAAIACAAAAAwAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMHAABEAACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABHBwAARAAAgAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAiwcAAD4AAIAFAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkHAABQAACAAgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAZCAAANgAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAATwgAADgAAIACAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAIcIAABAAACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADHCAAAMQAAgAEAAAAAAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA+AgAAC4AAIADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAC8JAAA6AACAAwAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABpCQAASAAAgAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAsQkAADcAAIAEAAAAEwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8KAABOAACAAAAAAAUAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAANCwAAPgAAgAUAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAASwsAAEoAAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJULAABIAACAAQAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADdCwAARAAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAIQwAAEQAAIAAAAAAAQAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGUMAABCAACAAQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACnDAAAQQAAgAEAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA6AwAAD4AAIABAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAACYNAAA6AACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABgDQAAOAAAgAEAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAmA0AADEAAIAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkNAABAAACAAQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAJDgAAPgAAgAIAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAARw4AADgAAIABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAH8OAAA+AACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADJDgAAQAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACQ8AADgAAIACAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEEPAAAwAACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABxDwAANgAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAApw8AADIAAIAAAAAABQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANkPAAAyAACAAgAAAAYAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAALEAAALAAAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxAAADAAAIABAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGcQAAAwAACAAQAAAAgAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACXEAAALAAAgAIAAAABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAwxAAAEAAAIABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMRAAA0AACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA3EQAAQAAAgAEAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdxEAAD4AAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAALURAAA/AACAAQAAABQAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD+EQAAPQAAgAAAAAAEAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAUxIAAEAAAIACAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJMSAAA4AACAAgAAAAUAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADLEgAAMgAAgAMAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA/RIAADcAAIABAAAABgAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEkTAAA+AACAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACHEwAAPQAAgAIAAAABAAAAIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxBMAADcAAIABAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPsTAAAtAACABgAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA0FAAAQAAAgAEAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAoRQAAEUAAIABAAAADQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOYUAABCAACAAQAAAAIAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABJFQAANAAAgAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAfRUAAEIAAIABAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8VAAA+AACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD9FQAAOgAAgAEAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxYAADoAAIABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHEWAAA6AACAAQAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADQFgAATgAAgAEAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAShcAAFgAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKIXAABMAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADuFwAAMAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAHhgAAFAAAIABAAAAAQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAG4YAAA8AACAAgAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC8GAAAOgAAgAEAAAAJAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA9hgAADoAAIAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADAZAAA2AACAAQAAAAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABmGQAANgAAgAEAAAADAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAphkAADwAAIAAAAAABgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOIZAAA0AACAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAWGgAAMAAAgAEAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAURoAADcAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGgcAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACsHAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA8hwAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADodAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAB+HQAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxh0AAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABIeAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABYHgAARAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAnB4AAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOQeAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAwHwAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAeB8AAE4AAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMYfAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAASIAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAWCAAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKAgAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADkIAAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAALCEAAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHghAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC+IQAASgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACCIAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAFAiAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACcIgAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAbWltZQAAAABjbGkuanMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAZXNidWlsZABGGgAACwAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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ybmFsU3RyaW5nPiAxNiBzaXplb2YsIDggYWxpZ25vZgp4lwAAAAAAANa7AAAAAAAACjx1OD4gMSBzaXplb2YsIDEgYWxpZ25vZgoAAHdpbmRtaWxsLWNsaWVzbS9tYWluLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2luZG1pbGwtY2xpLy0vd2luZG1pbGwtY2xpLTEuMzkzLjIudGd6QGF5b25saS9qc2V4dGdpdGlnbm9yZS1wYXJzZXJtaW5pbWF0Y2h3aW5kbWlsbC1jbGllbnRAZGVuby9zaGltLWRlbm9odHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZGVuby9zaGltLWRlbm8vLS9zaGltLWRlbm8tMC4xOC4yLnRnekBkZW5vL3NoaW0tZGVuby10ZXN0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGRlbm8vc2hpbS1kZW5vLXRlc3QvLS9zaGltLWRlbm8tdGVzdC0wLjUuMC50Z3pub2RlLXdoaWNoYmluL3doaWNoLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2hpY2gvLS93aGljaC00LjAuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pc2V4ZS8tL2lzZXhlLTMuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dzLy0vd3MtOC4xOC4wLnRnemJ1ZmZlcnV0aWx1dGYtOC12YWxpZGF0ZWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dpbmRtaWxsLWNsaWVudC8tL3dpbmRtaWxsLWNsaWVudC0xLjM2NC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL29wZW4vLS9vcGVuLTEwLjEuMC50Z3pkZWZhdWx0LWJyb3dzZXJkZWZpbmUtbGF6eS1wcm9waXMtaW5zaWRlLWNvbnRhaW5lcmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzLXdzbC8tL2lzLXdzbC0zLjEuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1pbnNpZGUtY29udGFpbmVyLy0vaXMtaW5zaWRlLWNvbnRhaW5lci0xLjAuMC50Z3ppcy1kb2NrZXJodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1kb2NrZXIvLS9pcy1kb2NrZXItMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmaW5lLWxhenktcHJvcC8tL2RlZmluZS1sYXp5LXByb3AtMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLy0vZGVmYXVsdC1icm93c2VyLTUuMi4xLnRnemJ1bmRsZS1uYW1lZGVmYXVsdC1icm93c2VyLWlkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLWlkLy0vZGVmYXVsdC1icm93c2VyLWlkLTUuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2J1bmRsZS1uYW1lLy0vYnVuZGxlLW5hbWUtNC4xLjAudGd6cnVuLWFwcGxlc2NyaXB0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcnVuLWFwcGxlc2NyaXB0Ly0vcnVuLWFwcGxlc2NyaXB0LTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21pbmltYXRjaC8tL21pbmltYXRjaC0xMC4wLjEudGd6YnJhY2UtZXhwYW5zaW9uaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnJhY2UtZXhwYW5zaW9uLy0vYnJhY2UtZXhwYW5zaW9uLTIuMC4xLnRnemJhbGFuY2VkLW1hdGNoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYmFsYW5jZWQtbWF0Y2gvLS9iYWxhbmNlZC1tYXRjaC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9qc3ppcC8tL2pzemlwLTMuNy4xLnRnenJlYWRhYmxlLXN0cmVhbXNldC1pbW1lZGlhdGUtc2hpbWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NldC1pbW1lZGlhdGUtc2hpbS8tL3NldC1pbW1lZGlhdGUtc2hpbS0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yZWFkYWJsZS1zdHJlYW0vLS9yZWFkYWJsZS1zdHJlYW0tMi4zLjgudGd6Y29yZS11dGlsLWlzcHJvY2Vzcy1uZXh0aWNrLWFyZ3NzYWZlLWJ1ZmZlcnN0cmluZ19kZWNvZGVydXRpbC1kZXByZWNhdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlsLWRlcHJlY2F0ZS8tL3V0aWwtZGVwcmVjYXRlLTEuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0cmluZ19kZWNvZGVyLy0vc3RyaW5nX2RlY29kZXItMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZS1idWZmZXIvLS9zYWZlLWJ1ZmZlci01LjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wcm9jZXNzLW5leHRpY2stYXJncy8tL3Byb2Nlc3MtbmV4dGljay1hcmdzLTIuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzYXJyYXkvLS9pc2FycmF5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2luaGVyaXRzLy0vaW5oZXJpdHMtMi4wLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29yZS11dGlsLWlzLy0vY29yZS11dGlsLWlzLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Bha28vLS9wYWtvLTEuMC4xMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9saWUvLS9saWUtMy4zLjAudGd6aW1tZWRpYXRlaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaW1tZWRpYXRlLy0vaW1tZWRpYXRlLTMuMC42LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dpdGlnbm9yZS1wYXJzZXIvLS9naXRpZ25vcmUtcGFyc2VyLTAuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2V4cHJlc3MvLS9leHByZXNzLTQuMTkuMi50Z3plbmNvZGV1cmxwcm94eS1hZGRyYm9keS1wYXJzZXJlc2NhcGUtaHRtbGh0dHAtZXJyb3Jzb24tZmluaXNoZWR1dGlscy1tZXJnZWNvbnRlbnQtdHlwZWZpbmFsaGFuZGxlcnJhbmdlLXBhcnNlcnNlcnZlLXN0YXRpY2FycmF5LWZsYXR0ZW5wYXRoLXRvLXJlZ2V4cHNldHByb3RvdHlwZW9mY29va2llLXNpZ25hdHVyZW1lcmdlLWRlc2NyaXB0b3JzY29udGVudC1kaXNwb3NpdGlvbmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtZGlzcG9zaXRpb24vLS9jb250ZW50LWRpc3Bvc2l0aW9uLTAuNS40LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NhZmUtYnVmZmVyLy0vc2FmZS1idWZmZXItNS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVyZ2UtZGVzY3JpcHRvcnMvLS9tZXJnZS1kZXNjcmlwdG9ycy0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9jb29raWUtc2lnbmF0dXJlLy0vY29va2llLXNpZ25hdHVyZS0xLjAuNi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zZXRwcm90b3R5cGVvZi8tL3NldHByb3RvdHlwZW9mLTEuMi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3BhdGgtdG8tcmVnZXhwLy0vcGF0aC10by1yZWdleHAtMC4xLjcudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYXJyYXktZmxhdHRlbi8tL2FycmF5LWZsYXR0ZW4tMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2VydmUtc3RhdGljLy0vc2VydmUtc3RhdGljLTEuMTUuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lc2NhcGUtaHRtbC8tL2VzY2FwZS1odG1sLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VuY29kZXVybC8tL2VuY29kZXVybC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wYXJzZXVybC8tL3BhcnNldXJsLTEuMy4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NlbmQvLS9zZW5kLTAuMTguMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yYW5nZS1wYXJzZXIvLS9yYW5nZS1wYXJzZXItMS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvb24tZmluaXNoZWQvLS9vbi1maW5pc2hlZC0yLjQuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lZS1maXJzdC8tL2VlLWZpcnN0LTEuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2h0dHAtZXJyb3JzLy0vaHR0cC1lcnJvcnMtMi4wLjAudGd6dG9pZGVudGlmaWVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdG9pZGVudGlmaWVyLy0vdG9pZGVudGlmaWVyLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0YXR1c2VzLy0vc3RhdHVzZXMtMi4wLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVwZC8tL2RlcGQtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVzdHJveS8tL2Rlc3Ryb3ktMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnJlc2gvLS9mcmVzaC0wLjUuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9kZWJ1Zy8tL2RlYnVnLTIuNi45LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21zLy0vbXMtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS8tL21pbWUtMS42LjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXRhZy8tL2V0YWctMS44LjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbXMvLS9tcy0yLjEuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9maW5hbGhhbmRsZXIvLS9maW5hbGhhbmRsZXItMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdW5waXBlLy0vdW5waXBlLTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtdHlwZS8tL2NvbnRlbnQtdHlwZS0xLjAuNS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlscy1tZXJnZS8tL3V0aWxzLW1lcmdlLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2JvZHktcGFyc2VyLy0vYm9keS1wYXJzZXItMS4yMC4yLnRnemljb252LWxpdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pY29udi1saXRlLy0vaWNvbnYtbGl0ZS0wLjQuMjQudGd6Pj0gMi4xLjIgPCAzc2FmZXItYnVmZmVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZXItYnVmZmVyLy0vc2FmZXItYnVmZmVyLTIuMS4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Jhdy1ib2R5Ly0vcmF3LWJvZHktMi41LjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnl0ZXMvLS9ieXRlcy0zLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy90eXBlLWlzLy0vdHlwZS1pcy0xLjYuMTgudGd6bWltZS10eXBlc21lZGlhLXR5cGVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVkaWEtdHlwZXIvLS9tZWRpYS10eXBlci0wLjMuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9taW1lLXR5cGVzLy0vbWltZS10eXBlcy0yLjEuMzUudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS1kYi8tL21pbWUtZGItMS41Mi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3FzLy0vcXMtNi4xMS4wLnRnenNpZGUtY2hhbm5lbGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NpZGUtY2hhbm5lbC8tL3NpZGUtY2hhbm5lbC0xLjAuNi50Z3pjYWxsLWJpbmRlcy1lcnJvcnNnZXQtaW50cmluc2ljb2JqZWN0LWluc3BlY3RodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9vYmplY3QtaW5zcGVjdC8tL29iamVjdC1pbnNwZWN0LTEuMTMuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9nZXQtaW50cmluc2ljLy0vZ2V0LWludHJpbnNpYy0xLjIuNC50Z3pmdW5jdGlvbi1iaW5kaGFzLXByb3RvaGFzLXN5bWJvbHNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXNvd24vLS9oYXNvd24tMi4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnVuY3Rpb24tYmluZC8tL2Z1bmN0aW9uLWJpbmQtMS4xLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaGFzLXN5bWJvbHMvLS9oYXMtc3ltYm9scy0xLjAuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvdG8vLS9oYXMtcHJvdG8tMS4wLjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZXJyb3JzLy0vZXMtZXJyb3JzLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NhbGwtYmluZC8tL2NhbGwtYmluZC0xLjAuNy50Z3plcy1kZWZpbmUtcHJvcGVydHlzZXQtZnVuY3Rpb24tbGVuZ3RoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2V0LWZ1bmN0aW9uLWxlbmd0aC8tL3NldC1mdW5jdGlvbi1sZW5ndGgtMS4yLjIudGd6ZGVmaW5lLWRhdGEtcHJvcGVydHloYXMtcHJvcGVydHktZGVzY3JpcHRvcnNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMvLS9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMtMS4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZGVmaW5lLXByb3BlcnR5Ly0vZXMtZGVmaW5lLXByb3BlcnR5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dvcGQvLS9nb3BkLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RlZmluZS1kYXRhLXByb3BlcnR5Ly0vZGVmaW5lLWRhdGEtcHJvcGVydHktMS4xLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcHJveHktYWRkci8tL3Byb3h5LWFkZHItMi4wLjcudGd6Zm9yd2FyZGVkaXBhZGRyLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaXBhZGRyLmpzLy0vaXBhZGRyLmpzLTEuOS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ZvcndhcmRlZC8tL2ZvcndhcmRlZC0wLjIuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9tZXRob2RzLy0vbWV0aG9kcy0xLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9hY2NlcHRzLy0vYWNjZXB0cy0xLjMuOC50Z3puZWdvdGlhdG9yaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbmVnb3RpYXRvci8tL25lZ290aWF0b3ItMC42LjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29va2llLy0vY29va2llLTAuNi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3ZhcnkvLS92YXJ5LTEuMS4yLnRnemJpbi9lc2J1aWxkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXNidWlsZC8tL2VzYnVpbGQtMC4yMy4xLnRnekBlc2J1aWxkL2FpeC1wcGM2NEBlc2J1aWxkL2FuZHJvaWQtYXJtQGVzYnVpbGQvYW5kcm9pZC1hcm02NEBlc2J1aWxkL2FuZHJvaWQteDY0QGVzYnVpbGQvZGFyd2luLWFybTY0QGVzYnVpbGQvZGFyd2luLXg2NEBlc2J1aWxkL2ZyZWVic2QtYXJtNjRAZXNidWlsZC9mcmVlYnNkLXg2NEBlc2J1aWxkL2xpbnV4LWFybUBlc2J1aWxkL2xpbnV4LWFybTY0QGVzYnVpbGQvbGludXgtaWEzMkBlc2J1aWxkL2xpbnV4LWxvb25nNjRAZXNidWlsZC9saW51eC1taXBzNjRlbEBlc2J1aWxkL2xpbnV4LXBwYzY0QGVzYnVpbGQvbGludXgtcmlzY3Y2NEBlc2J1aWxkL2xpbnV4LXMzOTB4QGVzYnVpbGQvbGludXgteDY0QGVzYnVpbGQvbmV0YnNkLXg2NEBlc2J1aWxkL29wZW5ic2QtYXJtNjRAZXNidWlsZC9vcGVuYnNkLXg2NEBlc2J1aWxkL3N1bm9zLXg2NEBlc2J1aWxkL3dpbjMyLWFybTY0QGVzYnVpbGQvd2luMzItaWEzMkBlc2J1aWxkL3dpbjMyLXg2NGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLXg2NC8tL3dpbjMyLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvd2luMzItaWEzMi8tL3dpbjMyLWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLWFybTY0Ly0vd2luMzItYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3N1bm9zLXg2NC8tL3N1bm9zLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC14NjQvLS9vcGVuYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC1hcm02NC8tL29wZW5ic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL25ldGJzZC14NjQvLS9uZXRic2QteDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC14NjQvLS9saW51eC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXMzOTB4Ly0vbGludXgtczM5MHgtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXJpc2N2NjQvLS9saW51eC1yaXNjdjY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1wcGM2NC8tL2xpbnV4LXBwYzY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1taXBzNjRlbC8tL2xpbnV4LW1pcHM2NGVsLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1sb29uZzY0Ly0vbGludXgtbG9vbmc2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvbGludXgtaWEzMi8tL2xpbnV4LWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybTY0Ly0vbGludXgtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybS8tL2xpbnV4LWFybS0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC14NjQvLS9mcmVlYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC1hcm02NC8tL2ZyZWVic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2Rhcndpbi14NjQvLS9kYXJ3aW4teDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9kYXJ3aW4tYXJtNjQvLS9kYXJ3aW4tYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQteDY0Ly0vYW5kcm9pZC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQtYXJtNjQvLS9hbmRyb2lkLWFybTY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9hbmRyb2lkLWFybS8tL2FuZHJvaWQtYXJtLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9haXgtcHBjNjQvLS9haXgtcHBjNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VzLW1haW4vLS9lcy1tYWluLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RpZmYvLS9kaWZmLTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0BheW9ubGkvanNleHQvLS9qc2V4dC0wLjkuNjMudGd6c3Vkby1wcm9tcHRodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zdWRvLXByb21wdC8tL3N1ZG8tcHJvbXB0LTkuMi4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ljb252LWxpdGUvLS9pY29udi1saXRlLTAuNi4zLnRnej49IDIuMS4yIDwgMy4wLjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==' +WHERE hash = -28028598712388162 AND workspace_id = 'admins'; \ No newline at end of file diff --git a/backend/migrations/20240908222917_migrate_to_new_cli_3.down.sql b/backend/migrations/20240908222917_migrate_to_new_cli_3.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240908222917_migrate_to_new_cli_3.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240908222917_migrate_to_new_cli_3.up.sql b/backend/migrations/20240908222917_migrate_to_new_cli_3.up.sql new file mode 100644 index 0000000000..678fbc81d7 --- /dev/null +++ b/backend/migrations/20240908222917_migrate_to_new_cli_3.up.sql @@ -0,0 +1,15 @@ +-- Add up migration script here +UPDATE script SET content = 'import * as wmill from "windmill-cli@1.393.2" + +export async function main() { + await wmill.hubPull({ workspace: "admins", token: process.env["WM_TOKEN"], baseUrl: globalThis.process.env["BASE_URL"] }); +} +', language = 'bun', +lock = '{ + "dependencies": { + "windmill-cli": "latest" + } +} +//bun.lockb +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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACmAgAANAAAgAMAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA2gIAAE4AAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADEDAAA6AACAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABrAwAASAAAgAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAswMAAEYAAIAFAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABYEAABMAACABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABiBAAAPgAAgAQAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAArwQAAEYAAIAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPUEAAA7AACACgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA/BQAARgAAgAIAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAkwUAAEQAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANcFAAAyAACAAwAAAAcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAqBgAATAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdgYAAEYAAIACAAAAAwAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMHAABEAACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABHBwAARAAAgAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAiwcAAD4AAIAFAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkHAABQAACAAgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAZCAAANgAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAATwgAADgAAIACAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAIcIAABAAACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADHCAAAMQAAgAEAAAAAAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA+AgAAC4AAIADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAC8JAAA6AACAAwAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABpCQAASAAAgAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAsQkAADcAAIAEAAAAEwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8KAABOAACAAAAAAAUAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAANCwAAPgAAgAUAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAASwsAAEoAAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJULAABIAACAAQAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADdCwAARAAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAIQwAAEQAAIAAAAAAAQAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGUMAABCAACAAQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACnDAAAQQAAgAEAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA6AwAAD4AAIABAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAACYNAAA6AACAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABgDQAAOAAAgAEAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAmA0AADEAAIAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMkNAABAAACAAQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAJDgAAPgAAgAIAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAARw4AADgAAIABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAH8OAAA+AACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADJDgAAQAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACQ8AADgAAIACAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEEPAAAwAACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABxDwAANgAAgAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAApw8AADIAAIAAAAAABQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAANkPAAAyAACAAgAAAAYAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAALEAAALAAAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxAAADAAAIABAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGcQAAAwAACAAQAAAAgAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACXEAAALAAAgAIAAAABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAwxAAAEAAAIABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAMRAAA0AACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA3EQAAQAAAgAEAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAdxEAAD4AAIABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAALURAAA/AACAAQAAABQAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD+EQAAPQAAgAAAAAAEAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAUxIAAEAAAIACAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAJMSAAA4AACAAgAAAAUAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADLEgAAMgAAgAMAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA/RIAADcAAIABAAAABgAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAEkTAAA+AACAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACHEwAAPQAAgAIAAAABAAAAIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxBMAADcAAIABAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAPsTAAAtAACABgAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA0FAAAQAAAgAEAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAoRQAAEUAAIABAAAADQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOYUAABCAACAAQAAAAIAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABJFQAANAAAgAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAfRUAAEIAAIABAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAL8VAAA+AACAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAD9FQAAOgAAgAEAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAANxYAADoAAIABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHEWAAA6AACAAQAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADQFgAATgAAgAEAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAShcAAFgAAIABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKIXAABMAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADuFwAAMAAAgAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAHhgAAFAAAIABAAAAAQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAG4YAAA8AACAAgAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC8GAAAOgAAgAEAAAAJAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA9hgAADoAAIAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADAZAAA2AACAAQAAAAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABmGQAANgAAgAEAAAADAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAphkAADwAAIAAAAAABgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOIZAAA0AACAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAWGgAAMAAAgAEAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAURoAADcAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAGgcAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACsHAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAA8hwAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAADodAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAB+HQAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAxh0AAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAABIeAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABYHgAARAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAnB4AAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAOQeAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAwHwAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAeB8AAE4AAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAMYfAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAASIAAARgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAWCAAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAKAgAABEAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAADkIAAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAALCEAAEwAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAHghAABGAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAC+IQAASgAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAACCIAAEgAAIAAAAAAFwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAFAiAABMAACAAAAAABcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAACcIgAASAAAgAAAAAAXAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAbWltZQAAAABjbGkuanMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAZXNidWlsZABGGgAACwAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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ybmFsU3RyaW5nPiAxNiBzaXplb2YsIDggYWxpZ25vZgp4lwAAAAAAANa7AAAAAAAACjx1OD4gMSBzaXplb2YsIDEgYWxpZ25vZgoAAHdpbmRtaWxsLWNsaWVzbS9tYWluLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2luZG1pbGwtY2xpLy0vd2luZG1pbGwtY2xpLTEuMzkzLjIudGd6QGF5b25saS9qc2V4dGdpdGlnbm9yZS1wYXJzZXJtaW5pbWF0Y2h3aW5kbWlsbC1jbGllbnRAZGVuby9zaGltLWRlbm9odHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZGVuby9zaGltLWRlbm8vLS9zaGltLWRlbm8tMC4xOC4yLnRnekBkZW5vL3NoaW0tZGVuby10ZXN0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGRlbm8vc2hpbS1kZW5vLXRlc3QvLS9zaGltLWRlbm8tdGVzdC0wLjUuMC50Z3pub2RlLXdoaWNoYmluL3doaWNoLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvd2hpY2gvLS93aGljaC00LjAuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pc2V4ZS8tL2lzZXhlLTMuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dzLy0vd3MtOC4xOC4wLnRnemJ1ZmZlcnV0aWx1dGYtOC12YWxpZGF0ZWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3dpbmRtaWxsLWNsaWVudC8tL3dpbmRtaWxsLWNsaWVudC0xLjM2NC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL29wZW4vLS9vcGVuLTEwLjEuMC50Z3pkZWZhdWx0LWJyb3dzZXJkZWZpbmUtbGF6eS1wcm9waXMtaW5zaWRlLWNvbnRhaW5lcmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzLXdzbC8tL2lzLXdzbC0zLjEuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1pbnNpZGUtY29udGFpbmVyLy0vaXMtaW5zaWRlLWNvbnRhaW5lci0xLjAuMC50Z3ppcy1kb2NrZXJodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pcy1kb2NrZXIvLS9pcy1kb2NrZXItMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmaW5lLWxhenktcHJvcC8tL2RlZmluZS1sYXp5LXByb3AtMy4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLy0vZGVmYXVsdC1icm93c2VyLTUuMi4xLnRnemJ1bmRsZS1uYW1lZGVmYXVsdC1icm93c2VyLWlkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVmYXVsdC1icm93c2VyLWlkLy0vZGVmYXVsdC1icm93c2VyLWlkLTUuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2J1bmRsZS1uYW1lLy0vYnVuZGxlLW5hbWUtNC4xLjAudGd6cnVuLWFwcGxlc2NyaXB0aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcnVuLWFwcGxlc2NyaXB0Ly0vcnVuLWFwcGxlc2NyaXB0LTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21pbmltYXRjaC8tL21pbmltYXRjaC0xMC4wLjEudGd6YnJhY2UtZXhwYW5zaW9uaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnJhY2UtZXhwYW5zaW9uLy0vYnJhY2UtZXhwYW5zaW9uLTIuMC4xLnRnemJhbGFuY2VkLW1hdGNoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYmFsYW5jZWQtbWF0Y2gvLS9iYWxhbmNlZC1tYXRjaC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9qc3ppcC8tL2pzemlwLTMuNy4xLnRnenJlYWRhYmxlLXN0cmVhbXNldC1pbW1lZGlhdGUtc2hpbWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NldC1pbW1lZGlhdGUtc2hpbS8tL3NldC1pbW1lZGlhdGUtc2hpbS0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yZWFkYWJsZS1zdHJlYW0vLS9yZWFkYWJsZS1zdHJlYW0tMi4zLjgudGd6Y29yZS11dGlsLWlzcHJvY2Vzcy1uZXh0aWNrLWFyZ3NzYWZlLWJ1ZmZlcnN0cmluZ19kZWNvZGVydXRpbC1kZXByZWNhdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlsLWRlcHJlY2F0ZS8tL3V0aWwtZGVwcmVjYXRlLTEuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0cmluZ19kZWNvZGVyLy0vc3RyaW5nX2RlY29kZXItMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZS1idWZmZXIvLS9zYWZlLWJ1ZmZlci01LjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wcm9jZXNzLW5leHRpY2stYXJncy8tL3Byb2Nlc3MtbmV4dGljay1hcmdzLTIuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2lzYXJyYXkvLS9pc2FycmF5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2luaGVyaXRzLy0vaW5oZXJpdHMtMi4wLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29yZS11dGlsLWlzLy0vY29yZS11dGlsLWlzLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Bha28vLS9wYWtvLTEuMC4xMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9saWUvLS9saWUtMy4zLjAudGd6aW1tZWRpYXRlaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaW1tZWRpYXRlLy0vaW1tZWRpYXRlLTMuMC42LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dpdGlnbm9yZS1wYXJzZXIvLS9naXRpZ25vcmUtcGFyc2VyLTAuMC4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2V4cHJlc3MvLS9leHByZXNzLTQuMTkuMi50Z3plbmNvZGV1cmxwcm94eS1hZGRyYm9keS1wYXJzZXJlc2NhcGUtaHRtbGh0dHAtZXJyb3Jzb24tZmluaXNoZWR1dGlscy1tZXJnZWNvbnRlbnQtdHlwZWZpbmFsaGFuZGxlcnJhbmdlLXBhcnNlcnNlcnZlLXN0YXRpY2FycmF5LWZsYXR0ZW5wYXRoLXRvLXJlZ2V4cHNldHByb3RvdHlwZW9mY29va2llLXNpZ25hdHVyZW1lcmdlLWRlc2NyaXB0b3JzY29udGVudC1kaXNwb3NpdGlvbmh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtZGlzcG9zaXRpb24vLS9jb250ZW50LWRpc3Bvc2l0aW9uLTAuNS40LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NhZmUtYnVmZmVyLy0vc2FmZS1idWZmZXItNS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVyZ2UtZGVzY3JpcHRvcnMvLS9tZXJnZS1kZXNjcmlwdG9ycy0xLjAuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9jb29raWUtc2lnbmF0dXJlLy0vY29va2llLXNpZ25hdHVyZS0xLjAuNi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zZXRwcm90b3R5cGVvZi8tL3NldHByb3RvdHlwZW9mLTEuMi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3BhdGgtdG8tcmVnZXhwLy0vcGF0aC10by1yZWdleHAtMC4xLjcudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYXJyYXktZmxhdHRlbi8tL2FycmF5LWZsYXR0ZW4tMS4xLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2VydmUtc3RhdGljLy0vc2VydmUtc3RhdGljLTEuMTUuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lc2NhcGUtaHRtbC8tL2VzY2FwZS1odG1sLTEuMC4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VuY29kZXVybC8tL2VuY29kZXVybC0xLjAuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9wYXJzZXVybC8tL3BhcnNldXJsLTEuMy4zLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NlbmQvLS9zZW5kLTAuMTguMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9yYW5nZS1wYXJzZXIvLS9yYW5nZS1wYXJzZXItMS4yLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvb24tZmluaXNoZWQvLS9vbi1maW5pc2hlZC0yLjQuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9lZS1maXJzdC8tL2VlLWZpcnN0LTEuMS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2h0dHAtZXJyb3JzLy0vaHR0cC1lcnJvcnMtMi4wLjAudGd6dG9pZGVudGlmaWVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdG9pZGVudGlmaWVyLy0vdG9pZGVudGlmaWVyLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3N0YXR1c2VzLy0vc3RhdHVzZXMtMi4wLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVwZC8tL2RlcGQtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZGVzdHJveS8tL2Rlc3Ryb3ktMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnJlc2gvLS9mcmVzaC0wLjUuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9kZWJ1Zy8tL2RlYnVnLTIuNi45LnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL21zLy0vbXMtMi4wLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS8tL21pbWUtMS42LjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXRhZy8tL2V0YWctMS44LjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbXMvLS9tcy0yLjEuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9maW5hbGhhbmRsZXIvLS9maW5hbGhhbmRsZXItMS4yLjAudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvdW5waXBlLy0vdW5waXBlLTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NvbnRlbnQtdHlwZS8tL2NvbnRlbnQtdHlwZS0xLjAuNS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy91dGlscy1tZXJnZS8tL3V0aWxzLW1lcmdlLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2JvZHktcGFyc2VyLy0vYm9keS1wYXJzZXItMS4yMC4yLnRnemljb252LWxpdGVodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9pY29udi1saXRlLy0vaWNvbnYtbGl0ZS0wLjQuMjQudGd6Pj0gMi4xLjIgPCAzc2FmZXItYnVmZmVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2FmZXItYnVmZmVyLy0vc2FmZXItYnVmZmVyLTIuMS4yLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3Jhdy1ib2R5Ly0vcmF3LWJvZHktMi41LjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvYnl0ZXMvLS9ieXRlcy0zLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy90eXBlLWlzLy0vdHlwZS1pcy0xLjYuMTgudGd6bWltZS10eXBlc21lZGlhLXR5cGVyaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWVkaWEtdHlwZXIvLS9tZWRpYS10eXBlci0wLjMuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9taW1lLXR5cGVzLy0vbWltZS10eXBlcy0yLjEuMzUudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbWltZS1kYi8tL21pbWUtZGItMS41Mi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3FzLy0vcXMtNi4xMS4wLnRnenNpZGUtY2hhbm5lbGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3NpZGUtY2hhbm5lbC8tL3NpZGUtY2hhbm5lbC0xLjAuNi50Z3pjYWxsLWJpbmRlcy1lcnJvcnNnZXQtaW50cmluc2ljb2JqZWN0LWluc3BlY3RodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9vYmplY3QtaW5zcGVjdC8tL29iamVjdC1pbnNwZWN0LTEuMTMuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9nZXQtaW50cmluc2ljLy0vZ2V0LWludHJpbnNpYy0xLjIuNC50Z3pmdW5jdGlvbi1iaW5kaGFzLXByb3RvaGFzLXN5bWJvbHNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXNvd24vLS9oYXNvd24tMi4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZnVuY3Rpb24tYmluZC8tL2Z1bmN0aW9uLWJpbmQtMS4xLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaGFzLXN5bWJvbHMvLS9oYXMtc3ltYm9scy0xLjAuMy50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvdG8vLS9oYXMtcHJvdG8tMS4wLjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZXJyb3JzLy0vZXMtZXJyb3JzLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2NhbGwtYmluZC8tL2NhbGwtYmluZC0xLjAuNy50Z3plcy1kZWZpbmUtcHJvcGVydHlzZXQtZnVuY3Rpb24tbGVuZ3RoaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvc2V0LWZ1bmN0aW9uLWxlbmd0aC8tL3NldC1mdW5jdGlvbi1sZW5ndGgtMS4yLjIudGd6ZGVmaW5lLWRhdGEtcHJvcGVydHloYXMtcHJvcGVydHktZGVzY3JpcHRvcnNodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMvLS9oYXMtcHJvcGVydHktZGVzY3JpcHRvcnMtMS4wLjIudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXMtZGVmaW5lLXByb3BlcnR5Ly0vZXMtZGVmaW5lLXByb3BlcnR5LTEuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2dvcGQvLS9nb3BkLTEuMC4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RlZmluZS1kYXRhLXByb3BlcnR5Ly0vZGVmaW5lLWRhdGEtcHJvcGVydHktMS4xLjQudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvcHJveHktYWRkci8tL3Byb3h5LWFkZHItMi4wLjcudGd6Zm9yd2FyZGVkaXBhZGRyLmpzaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvaXBhZGRyLmpzLy0vaXBhZGRyLmpzLTEuOS4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ZvcndhcmRlZC8tL2ZvcndhcmRlZC0wLjIuMC50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9tZXRob2RzLy0vbWV0aG9kcy0xLjEuMi50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9hY2NlcHRzLy0vYWNjZXB0cy0xLjMuOC50Z3puZWdvdGlhdG9yaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvbmVnb3RpYXRvci8tL25lZ290aWF0b3ItMC42LjMudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvY29va2llLy0vY29va2llLTAuNi4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL3ZhcnkvLS92YXJ5LTEuMS4yLnRnemJpbi9lc2J1aWxkaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvZXNidWlsZC8tL2VzYnVpbGQtMC4yMy4xLnRnekBlc2J1aWxkL2FpeC1wcGM2NEBlc2J1aWxkL2FuZHJvaWQtYXJtQGVzYnVpbGQvYW5kcm9pZC1hcm02NEBlc2J1aWxkL2FuZHJvaWQteDY0QGVzYnVpbGQvZGFyd2luLWFybTY0QGVzYnVpbGQvZGFyd2luLXg2NEBlc2J1aWxkL2ZyZWVic2QtYXJtNjRAZXNidWlsZC9mcmVlYnNkLXg2NEBlc2J1aWxkL2xpbnV4LWFybUBlc2J1aWxkL2xpbnV4LWFybTY0QGVzYnVpbGQvbGludXgtaWEzMkBlc2J1aWxkL2xpbnV4LWxvb25nNjRAZXNidWlsZC9saW51eC1taXBzNjRlbEBlc2J1aWxkL2xpbnV4LXBwYzY0QGVzYnVpbGQvbGludXgtcmlzY3Y2NEBlc2J1aWxkL2xpbnV4LXMzOTB4QGVzYnVpbGQvbGludXgteDY0QGVzYnVpbGQvbmV0YnNkLXg2NEBlc2J1aWxkL29wZW5ic2QtYXJtNjRAZXNidWlsZC9vcGVuYnNkLXg2NEBlc2J1aWxkL3N1bm9zLXg2NEBlc2J1aWxkL3dpbjMyLWFybTY0QGVzYnVpbGQvd2luMzItaWEzMkBlc2J1aWxkL3dpbjMyLXg2NGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLXg2NC8tL3dpbjMyLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvd2luMzItaWEzMi8tL3dpbjMyLWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3dpbjMyLWFybTY0Ly0vd2luMzItYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL3N1bm9zLXg2NC8tL3N1bm9zLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC14NjQvLS9vcGVuYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvb3BlbmJzZC1hcm02NC8tL29wZW5ic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL25ldGJzZC14NjQvLS9uZXRic2QteDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC14NjQvLS9saW51eC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXMzOTB4Ly0vbGludXgtczM5MHgtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LXJpc2N2NjQvLS9saW51eC1yaXNjdjY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1wcGM2NC8tL2xpbnV4LXBwYzY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1taXBzNjRlbC8tL2xpbnV4LW1pcHM2NGVsLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9saW51eC1sb29uZzY0Ly0vbGludXgtbG9vbmc2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvbGludXgtaWEzMi8tL2xpbnV4LWlhMzItMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybTY0Ly0vbGludXgtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2xpbnV4LWFybS8tL2xpbnV4LWFybS0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC14NjQvLS9mcmVlYnNkLXg2NC0wLjIzLjEudGd6aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcvQGVzYnVpbGQvZnJlZWJzZC1hcm02NC8tL2ZyZWVic2QtYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2Rhcndpbi14NjQvLS9kYXJ3aW4teDY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9kYXJ3aW4tYXJtNjQvLS9kYXJ3aW4tYXJtNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQteDY0Ly0vYW5kcm9pZC14NjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0Blc2J1aWxkL2FuZHJvaWQtYXJtNjQvLS9hbmRyb2lkLWFybTY0LTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9hbmRyb2lkLWFybS8tL2FuZHJvaWQtYXJtLTAuMjMuMS50Z3podHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9AZXNidWlsZC9haXgtcHBjNjQvLS9haXgtcHBjNjQtMC4yMy4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2VzLW1haW4vLS9lcy1tYWluLTEuMy4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2RpZmYvLS9kaWZmLTcuMC4wLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL0BheW9ubGkvanNleHQvLS9qc2V4dC0wLjkuNjMudGd6c3Vkby1wcm9tcHRodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZy9zdWRvLXByb21wdC8tL3N1ZG8tcHJvbXB0LTkuMi4xLnRnemh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnL2ljb252LWxpdGUvLS9pY29udi1saXRlLTAuNi4zLnRnej49IDIuMS4yIDwgMy4wLjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==' +WHERE hash = -28028598712388162 AND workspace_id = 'admins'; \ No newline at end of file diff --git a/backend/migrations/20240910151523_resource_type_file_format.down.sql b/backend/migrations/20240910151523_resource_type_file_format.down.sql new file mode 100644 index 0000000000..f891983f26 --- /dev/null +++ b/backend/migrations/20240910151523_resource_type_file_format.down.sql @@ -0,0 +1,3 @@ +-- Add down migration script here +ALTER TABLE resource_type + DROP COLUMN format_extension; diff --git a/backend/migrations/20240910151523_resource_type_file_format.up.sql b/backend/migrations/20240910151523_resource_type_file_format.up.sql new file mode 100644 index 0000000000..7bc683ff14 --- /dev/null +++ b/backend/migrations/20240910151523_resource_type_file_format.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER TABLE resource_type + ADD COLUMN format_extension VARCHAR(20); diff --git a/backend/parsers/windmill-parser-bash/Cargo.toml b/backend/parsers/windmill-parser-bash/Cargo.toml index 9d2070f6c8..4c7db23313 100644 --- a/backend/parsers/windmill-parser-bash/Cargo.toml +++ b/backend/parsers/windmill-parser-bash/Cargo.toml @@ -8,9 +8,14 @@ authors.workspace = true name = "windmill_parser_bash" path = "./src/lib.rs" +[target.'cfg(target_arch = "wasm32")'.dependencies] +regex-lite.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +regex.workspace = true + [dependencies] windmill-parser.workspace = true anyhow.workspace = true -regex.workspace = true lazy_static.workspace = true -serde_json.workspace = true \ No newline at end of file +serde_json.workspace = true diff --git a/backend/parsers/windmill-parser-bash/src/lib.rs b/backend/parsers/windmill-parser-bash/src/lib.rs index fa5eb3973d..515ef3822a 100644 --- a/backend/parsers/windmill-parser-bash/src/lib.rs +++ b/backend/parsers/windmill-parser-bash/src/lib.rs @@ -1,7 +1,12 @@ #![allow(non_snake_case)] // TODO: switch to parse_* function naming use anyhow::anyhow; + +#[cfg(not(target_arch = "wasm32"))] use regex::Regex; +#[cfg(target_arch = "wasm32")] +use regex_lite::Regex; + use serde_json::json; use std::collections::HashMap; diff --git a/backend/parsers/windmill-parser-graphql/Cargo.toml b/backend/parsers/windmill-parser-graphql/Cargo.toml index da1a8bf9c6..7f0a93b6f3 100644 --- a/backend/parsers/windmill-parser-graphql/Cargo.toml +++ b/backend/parsers/windmill-parser-graphql/Cargo.toml @@ -8,9 +8,14 @@ authors.workspace = true name = "windmill_parser_graphql" path = "./src/lib.rs" +[target.'cfg(target_arch = "wasm32")'.dependencies] +regex-lite.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +regex.workspace = true + [dependencies] windmill-parser.workspace = true anyhow.workspace = true -regex.workspace = true lazy_static.workspace = true -serde_json.workspace = true \ No newline at end of file +serde_json.workspace = true diff --git a/backend/parsers/windmill-parser-graphql/src/lib.rs b/backend/parsers/windmill-parser-graphql/src/lib.rs index 99eb8db261..060ae294d1 100644 --- a/backend/parsers/windmill-parser-graphql/src/lib.rs +++ b/backend/parsers/windmill-parser-graphql/src/lib.rs @@ -1,7 +1,12 @@ #![allow(non_snake_case)] // TODO: switch to parse_* function naming use anyhow::anyhow; + +#[cfg(not(target_arch = "wasm32"))] use regex::Regex; +#[cfg(target_arch = "wasm32")] +use regex_lite::Regex; + use serde_json::json; use windmill_parser::{Arg, MainArgSignature, Typ}; diff --git a/backend/parsers/windmill-parser-php/Cargo.toml b/backend/parsers/windmill-parser-php/Cargo.toml index 05d86a6c67..8bd3182f91 100644 --- a/backend/parsers/windmill-parser-php/Cargo.toml +++ b/backend/parsers/windmill-parser-php/Cargo.toml @@ -14,6 +14,3 @@ itertools.workspace = true serde_json.workspace = true anyhow.workspace = true php-parser-rs.workspace = true -convert_case.workspace = true -lazy_static.workspace = true -regex.workspace = true \ No newline at end of file diff --git a/backend/parsers/windmill-parser-php/src/lib.rs b/backend/parsers/windmill-parser-php/src/lib.rs index 27befc1ea7..5adf1dc0d7 100644 --- a/backend/parsers/windmill-parser-php/src/lib.rs +++ b/backend/parsers/windmill-parser-php/src/lib.rs @@ -1,7 +1,5 @@ -use convert_case::{Case, Casing}; -use regex::Regex; use serde_json::Value; -use windmill_parser::{Arg, MainArgSignature, Typ}; +use windmill_parser::{to_snake_case, Arg, MainArgSignature, Typ}; use php_parser_rs::parser::{ self, @@ -13,17 +11,6 @@ use php_parser_rs::parser::{ }, }; -lazy_static::lazy_static! { - static ref RE_SNK_CASE: Regex = Regex::new(r"_(\d)").unwrap(); -} - -fn to_snake_case(s: String) -> String { - let r = s.to_case(Case::Snake); - - // s_3 => s3 - RE_SNK_CASE.replace_all(&r, "$1").to_string() -} - fn parse_php_type(e: Type) -> Typ { match e { Type::Float(_) => Typ::Float, @@ -32,7 +19,7 @@ fn parse_php_type(e: Type) -> Typ { Type::String(_) => Typ::Str(None), Type::Array(_) => Typ::List(Box::new(Typ::Str(None))), Type::Object(_) => Typ::Object(vec![]), - Type::Named(_, name) => Typ::Resource(to_snake_case(name.to_string())), + Type::Named(_, name) => Typ::Resource(to_snake_case(name.to_string().as_ref())), _ => Typ::Unknown, } } diff --git a/backend/parsers/windmill-parser-py-imports/Cargo.toml b/backend/parsers/windmill-parser-py-imports/Cargo.toml index 665b6df211..078b15418b 100644 --- a/backend/parsers/windmill-parser-py-imports/Cargo.toml +++ b/backend/parsers/windmill-parser-py-imports/Cargo.toml @@ -8,13 +8,18 @@ authors.workspace = true name = "windmill_parser_py_imports" path = "./src/lib.rs" +[target.'cfg(target_arch = "wasm32")'.dependencies] +regex-lite.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +regex.workspace = true + [dependencies] windmill-parser.workspace = true windmill-common.workspace = true rustpython-parser.workspace = true phf.workspace = true itertools.workspace = true -regex.workspace = true serde_json.workspace = true anyhow.workspace = true lazy_static.workspace = true diff --git a/backend/parsers/windmill-parser-py-imports/src/lib.rs b/backend/parsers/windmill-parser-py-imports/src/lib.rs index 00810a7858..34487e04ef 100644 --- a/backend/parsers/windmill-parser-py-imports/src/lib.rs +++ b/backend/parsers/windmill-parser-py-imports/src/lib.rs @@ -10,7 +10,11 @@ use async_recursion::async_recursion; use itertools::Itertools; use lazy_static::lazy_static; use phf::phf_map; + +#[cfg(not(target_arch = "wasm32"))] use regex::Regex; +#[cfg(target_arch = "wasm32")] +use regex_lite::Regex; use rustpython_parser::{ ast::{Stmt, StmtImport, StmtImportFrom, Suite}, diff --git a/backend/parsers/windmill-parser-rust/Cargo.toml b/backend/parsers/windmill-parser-rust/Cargo.toml new file mode 100644 index 0000000000..e1dcf84449 --- /dev/null +++ b/backend/parsers/windmill-parser-rust/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "windmill-parser-rust" +version.workspace = true +edition.workspace = true +authors.workspace = true + +[lib] +name = "windmill_parser_rust" +path = "./src/lib.rs" + +[dependencies] +windmill-parser.workspace = true +itertools.workspace = true +serde_json.workspace = true +anyhow.workspace = true +convert_case.workspace = true +lazy_static.workspace = true +regex.workspace = true +pulldown-cmark.workspace = true +toml.workspace = true +syn.workspace = true +quote.workspace = true diff --git a/backend/parsers/windmill-parser-rust/manifest/Cargo.toml.default b/backend/parsers/windmill-parser-rust/manifest/Cargo.toml.default new file mode 100644 index 0000000000..6c9e93c8a1 --- /dev/null +++ b/backend/parsers/windmill-parser-rust/manifest/Cargo.toml.default @@ -0,0 +1,16 @@ +[[bin]] +name = "main" +path = "./main.rs" + +[package] +authors = ["Anonymous"] +edition = "2021" +name = "main" +version = "0.1.0" + +[profile.release] +strip = true + +[dependencies] +serde = { version = "1.0.207", features = ["derive"] } +serde_json = "1.0.124" diff --git a/backend/parsers/windmill-parser-rust/src/lib.rs b/backend/parsers/windmill-parser-rust/src/lib.rs new file mode 100644 index 0000000000..f9a2a5b677 --- /dev/null +++ b/backend/parsers/windmill-parser-rust/src/lib.rs @@ -0,0 +1,501 @@ +use anyhow::anyhow; +use itertools::Itertools; +use quote::ToTokens; +use regex::Regex; +use windmill_parser::{Arg, MainArgSignature, Typ}; + +pub fn otyp_to_string(otyp: Option) -> String { + otyp.unwrap() +} + +pub fn parse_rust_signature(code: &str) -> anyhow::Result { + let ast: syn::File = syn::parse_file(code)?; + + if let Some(main_fn) = ast.items.iter().find_map(|item| match item { + syn::Item::Fn(f) if f.sig.ident == "main" => Some(f), + _ => None, + }) { + let args = main_fn + .sig + .inputs + .iter() + .map(|param| { + let (otyp, typ, name) = parse_rust_typ(param); + Arg { name, otyp, typ, default: None, has_default: false, oidx: None } + }) + .collect_vec(); + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args, + no_main_func: Some(false), + }) + } else { + Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args: vec![], + no_main_func: Some(true), + }) + } +} + +pub fn parse_rust_deps_into_manifest(code: &str) -> anyhow::Result { + const MODIFIABLE_MANIFEST_TABLES: &[&str] = &["dependencies"]; + + let partial_manifest = find_embedded_manifest(code).unwrap_or(Manifest::Toml("".to_string())); + let partial_manifest = partial_manifest.into_toml()?; + let mut manif = default_manifest(); + for table_name in MODIFIABLE_MANIFEST_TABLES { + match partial_manifest.get(*table_name) { + Some(toml::Value::Table(tab)) => { + // Merge. + match manif.entry(*table_name) { + toml::map::Entry::Vacant(e) => { + e.insert(toml::Value::Table(tab.to_owned())); + } + toml::map::Entry::Occupied(e) => { + let into_t = match e.into_mut() { + toml::Value::Table(t) => Some(t), + _ => None, + }; + into_t.ok_or(anyhow!(""))?.extend(tab.to_owned()); + } + } + } + Some(v) => { + // Just replace. + manif.insert(table_name.to_string(), v.to_owned()); + } + None => (), + } + } + + Ok(manif.to_string()) +} + +fn parse_pat_type(p: Box) -> Typ { + match *p { + syn::Type::Array(a) => { + let inner_typ = parse_pat_type(a.elem); + Typ::List(Box::new(inner_typ)) + } + // syn::Type::BareFn(_) => todo!(), + // syn::Type::Group(_) => todo!(), + // syn::Type::ImplTrait(_) => todo!(), + // syn::Type::Infer(_) => todo!(), + // syn::Type::Macro(_) => todo!(), + // syn::Type::Never(_) => todo!(), + syn::Type::Paren(e) => parse_pat_type(e.elem), + syn::Type::Path(e) => { + if let Some(u) = e.path.segments.last() { + match u.ident.to_string().as_str() { + "usize" | "u8" | "u16" | "u32" | "u64" | "u128" | "isize" | "i8" | "i16" + | "i32" | "i64" | "i128" => Typ::Int, + "String" | "str" => Typ::Str(None), + "bool" => Typ::Bool, + "f32" | "f64" => Typ::Float, + "Vec" => { + if let syn::PathArguments::AngleBracketed(t) = &u.arguments { + if let Some(syn::GenericArgument::Type(a)) = t.args.last() { + Typ::List(Box::new(parse_pat_type(Box::new(a.clone())))) + } else { + Typ::Unknown + } + } else { + Typ::Unknown + } + } + _ => Typ::Unknown, + } + } else { + Typ::Unknown + } + } + // syn::Type::Ptr(_) => todo!(), + syn::Type::Reference(e) => parse_pat_type(e.elem), + syn::Type::Slice(e) => Typ::List(Box::new(parse_pat_type(e.elem))), + // syn::Type::TraitObject(_) => todo!(), + // syn::Type::Tuple(_) => todo!(), + // syn::Type::Verbatim(_) => todo!(), + _ => Typ::Unknown, + } +} + +fn parse_rust_typ(param_typ: &syn::FnArg) -> (Option, Typ, String) { + match param_typ { + syn::FnArg::Receiver(_) => (None, Typ::Unknown, "self".to_string()), + syn::FnArg::Typed(s) => { + let name = match *s.pat.clone() { + syn::Pat::Ident(p) => p.ident.to_string(), + _ => "undefined".to_string(), + }; + + let otyp = Some(s.ty.to_token_stream().to_string()); + let typ = parse_pat_type(s.ty.clone()); + (otyp, typ, name) + } + } +} + +#[derive(Debug, PartialEq)] +enum Manifest { + Toml(String), + DepList(String), +} + +impl Manifest { + pub fn into_toml(self) -> anyhow::Result { + match self { + Manifest::Toml(s) => toml::from_str(&s), + Manifest::DepList(s) => Manifest::dep_list_to_toml(&s), + } + .map_err(|e| anyhow!("Could not parse embedded manifest: {}", e)) + } + + fn dep_list_to_toml(s: &str) -> ::std::result::Result { + let mut r = String::new(); + r.push_str("[dependencies]\n"); + for dep in s.trim().split(',') { + // If there's no version specified, add one. + match dep.contains('=') { + true => { + r.push_str(dep); + r.push('\n'); + } + false => { + r.push_str(dep); + r.push_str("=\"*\"\n"); + } + } + } + + toml::from_str(&r) + } +} + +fn default_manifest() -> toml::value::Table { + toml::from_str(include_str!("../manifest/Cargo.toml.default")) + .expect("Failed to parse Cargo.toml.default") +} + +/** +* Get a `Manifest` that can be made into a TOML table. The format and logic are the same as in +* the rust-script or cargo-eval projects. +*/ +fn find_embedded_manifest(s: &str) -> Option { + find_short_hand_manifest(s).or_else(|| find_code_block_manifest(s)) +} + +fn find_short_hand_manifest(s: &str) -> Option { + let re: Regex = Regex::new(r"^(?i)\s*//\s*cargo-deps\s*:(.*?)(\r\n|\n)").unwrap(); + /* + This is pretty simple: the only valid syntax for this is for the first, non-blank line to contain a single-line comment whose first token is `cargo-deps:`. That's it. + */ + if let Some(cap) = re.captures(s) { + if let Some(m) = cap.get(1) { + return Some(Manifest::DepList(m.as_str().to_string())); + } + } + None +} + +/** +Locates a "code block manifest" in Rust source. +*/ +fn find_code_block_manifest(s: &str) -> Option { + let re_crate_comment: Regex = { + Regex::new( + r"(?x) + ^\s* + (/\*!|//(!|/)) + ", + ) + .unwrap() + }; + + let start = match re_crate_comment.captures(s) { + Some(cap) => match cap.get(1) { + Some(m) => m.start(), + None => return None, + }, + None => return None, + }; + + let comment = match extract_comment(&s[start..]) { + Some(s) => s, + None => { + return None; + } + }; + + scrape_markdown_manifest(&comment).map(|s| Manifest::Toml(s)) +} + +/** +Extracts the first `Cargo` fenced code block from a chunk of Markdown. +*/ +fn scrape_markdown_manifest(content: &str) -> Option { + use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag}; + + // To match librustdoc/html/markdown.rs, opts. + let exts = Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES; + + let md = Parser::new_ext(content, exts); + + let mut found = false; + let mut output = None; + + for item in md { + match item { + Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(ref info))) + if info.to_lowercase() == "cargo" && output.is_none() => + { + found = true; + } + Event::Text(ref text) if found => { + let s = output.get_or_insert(String::new()); + s.push_str(text); + } + Event::End(Tag::CodeBlock(_)) if found => { + found = false; + } + _ => (), + } + } + + output +} + +/** +Extracts the contents of a Rust doc comment. +*/ +fn extract_comment(s: &str) -> Option { + use std::cmp::min; + + fn extract_block(s: &str) -> Option { + /* + On every line: + + - update nesting level and detect end-of-comment + - if margin is None: + - if there appears to be a margin, set margin. + - strip off margin marker + - update the leading space counter + - strip leading space + - append content + */ + let mut r = String::new(); + + let margin_re: Regex = Regex::new(r"^\s*\*( |$)").unwrap(); + let space_re: Regex = Regex::new(r"^(\s+)").unwrap(); + let nesting_re: Regex = Regex::new(r"/\*|\*/").unwrap(); + + let mut leading_space = None; + let mut margin = None; + let mut depth: u32 = 1; + + for line in s.lines() { + if depth == 0 { + break; + } + + let mut end_of_comment = None; + + for (end, marker) in nesting_re.find_iter(line).map(|m| (m.start(), m.as_str())) { + match (marker, depth) { + ("/*", _) => depth += 1, + ("*/", 1) => { + end_of_comment = Some(end); + depth = 0; + break; + } + ("*/", _) => depth -= 1, + _ => return None, + } + } + + let line = end_of_comment.map(|end| &line[..end]).unwrap_or(line); + + margin = margin.or_else(|| margin_re.find(line).map(|m| m.as_str())); + + let line = if let Some(margin) = margin { + let end = line + .char_indices() + .take(margin.len()) + .map(|(i, c)| i + c.len_utf8()) + .last() + .unwrap_or(0); + &line[end..] + } else { + line + }; + + leading_space = leading_space.or_else(|| space_re.find(line).map(|m| m.end())); + + let strip_len = min(leading_space.unwrap_or(0), line.len()); + let line = &line[strip_len..]; + + r.push_str(line); + + r.push('\n'); + } + + Some(r) + } + + fn extract_line(s: &str) -> Option { + let mut r = String::new(); + + let comment_re = Regex::new(r"^\s*//(!|/)").unwrap(); + + let space_re = Regex::new(r"^(\s+)").unwrap(); + + let mut leading_space = None; + + for line in s.lines() { + let content = match comment_re.find(line) { + Some(m) => &line[m.end()..], + None => break, + }; + + leading_space = leading_space.or_else(|| { + space_re + .captures(content) + .and_then(|c| c.get(1)) + .map(|m| m.end()) + }); + + let strip_len = min(leading_space.unwrap_or(0), content.len()); + let content = &content[strip_len..]; + + r.push_str(content); + + r.push('\n'); + } + + Some(r) + } + + if let Some(stripped) = s.strip_prefix("/*!") { + extract_block(stripped) + } else if s.starts_with("//!") || s.starts_with("///") { + extract_line(s) + } else { + None + } +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn test_parse_rust_signature() { + let code = r#" +// commenting comments + +fn main( + my_int: i8, + my_vec: Vec, + mut my_arr: [u8; 9], + my_complex: Vec>, +) -> Result { + println!("My int is {}", my_int); +}"#; + + let ret = parse_rust_signature(code).unwrap(); + + assert_eq!(ret.args.len(), 4); + + assert_eq!(ret.args[0].name, "my_int"); + assert_eq!(ret.args[0].otyp, Some("i8".to_string())); + assert_eq!(ret.args[0].typ, Typ::Int); + + assert_eq!(ret.args[1].name, "my_vec"); + assert_eq!(ret.args[1].otyp, Some("Vec < u8 >".to_string())); + assert_eq!(ret.args[1].typ, Typ::List(Box::new(Typ::Int))); + + assert_eq!(ret.args[2].name, "my_arr"); + assert_eq!(ret.args[2].otyp, Some("[u8 ; 9]".to_string())); + assert_eq!(ret.args[2].typ, Typ::List(Box::new(Typ::Int))); + + assert_eq!(ret.args[3].name, "my_complex"); + assert_eq!( + ret.args[3].otyp, + Some("Vec < Result < MyStruct , anyhow :: Error > >".to_string()) + ); + assert_eq!(ret.args[3].typ, Typ::List(Box::new(Typ::Unknown))); + + let code = r#" +// commenting comments + +fn main( + my_str_slice: &str, + my_String: String, + mut my_mut_ref_to_string: &mut String, + my_string_vec: Vec, +) -> Result { + println!("My int is {}", my_int); +}"#; + + let ret = parse_rust_signature(code).unwrap(); + + assert_eq!(ret.args.len(), 4); + + assert_eq!(ret.args[0].name, "my_str_slice"); + assert_eq!(ret.args[0].otyp, Some("& str".to_string())); + assert_eq!(ret.args[0].typ, Typ::Str(None)); + + assert_eq!(ret.args[1].name, "my_String"); + assert_eq!(ret.args[1].otyp, Some("String".to_string())); + assert_eq!(ret.args[1].typ, Typ::Str(None)); + + assert_eq!(ret.args[2].name, "my_mut_ref_to_string"); + assert_eq!(ret.args[2].otyp, Some("& mut String".to_string())); + assert_eq!(ret.args[2].typ, Typ::Str(None)); + + assert_eq!(ret.args[3].name, "my_string_vec"); + assert_eq!( + ret.args[3].otyp, + Some("Vec < String >".to_string()) + ); + assert_eq!(ret.args[3].typ, Typ::List(Box::new(Typ::Str(None)))); + } + + #[test] + fn test_parse_rust_manifest() { + assert_eq!(find_embedded_manifest("fn main() {}"), None); + + let code = r#" + +//! Crate doc comment right here +//! We need to use the `cargo` language in the code bloc +//! +//! ```cargo +//! [dependencies] +//! time = "0.1.25" +//! ``` + +fn main() { + println!("{}", time::now().rfc822z()); +} + "#; + let manif = find_embedded_manifest(code); + + assert_eq!( + manif, + Some(Manifest::Toml( + r#"[dependencies] +time = "0.1.25" +"# + .to_string() + )) + ); + let _full_manif = parse_rust_deps_into_manifest(code).unwrap(); + } + + #[test] + fn test_default_manifest() { + default_manifest(); + } +} diff --git a/backend/parsers/windmill-parser-sql/Cargo.toml b/backend/parsers/windmill-parser-sql/Cargo.toml index 421aff33a2..085b709faa 100644 --- a/backend/parsers/windmill-parser-sql/Cargo.toml +++ b/backend/parsers/windmill-parser-sql/Cargo.toml @@ -8,9 +8,14 @@ authors.workspace = true name = "windmill_parser_sql" path = "./src/lib.rs" +[target.'cfg(target_arch = "wasm32")'.dependencies] +regex-lite.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +regex.workspace = true + [dependencies] windmill-parser.workspace = true anyhow.workspace = true -regex.workspace = true lazy_static.workspace = true -serde_json.workspace = true \ No newline at end of file +serde_json.workspace = true diff --git a/backend/parsers/windmill-parser-sql/src/lib.rs b/backend/parsers/windmill-parser-sql/src/lib.rs index 8f22bd1faa..fbb4ac5d40 100644 --- a/backend/parsers/windmill-parser-sql/src/lib.rs +++ b/backend/parsers/windmill-parser-sql/src/lib.rs @@ -1,7 +1,12 @@ #![allow(non_snake_case)] // TODO: switch to parse_* function naming use anyhow::anyhow; + +#[cfg(not(target_arch = "wasm32"))] use regex::Regex; +#[cfg(target_arch = "wasm32")] +use regex_lite::Regex; + use serde_json::json; use std::{ diff --git a/backend/parsers/windmill-parser-ts/Cargo.toml b/backend/parsers/windmill-parser-ts/Cargo.toml index 2a84c4e542..5f04b14f3b 100644 --- a/backend/parsers/windmill-parser-ts/Cargo.toml +++ b/backend/parsers/windmill-parser-ts/Cargo.toml @@ -22,6 +22,5 @@ swc_ecma_ast.workspace = true swc_ecma_visit.workspace = true serde_json.workspace = true anyhow.workspace = true -convert_case.workspace = true regex.workspace = true lazy_static.workspace = true diff --git a/backend/parsers/windmill-parser-ts/src/lib.rs b/backend/parsers/windmill-parser-ts/src/lib.rs index 56d645edf4..41ad759f0a 100644 --- a/backend/parsers/windmill-parser-ts/src/lib.rs +++ b/backend/parsers/windmill-parser-ts/src/lib.rs @@ -1,5 +1,3 @@ -use convert_case::{Case, Casing}; -use regex::Regex; /* * Author: Ruben Fiszel * Copyright: Windmill Labs, Inc 2022 @@ -11,7 +9,9 @@ use regex::Regex; use serde_json::Value; use std::collections::HashSet; use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; -use windmill_parser::{json_to_typ, Arg, MainArgSignature, ObjectProperty, OneOfVariant, Typ}; +use windmill_parser::{ + json_to_typ, to_snake_case, Arg, MainArgSignature, ObjectProperty, OneOfVariant, Typ, +}; use swc_common::{sync::Lrc, FileName, SourceMap, SourceMapper, Span, Spanned}; use swc_ecma_ast::{ @@ -23,6 +23,7 @@ use swc_ecma_ast::{ }; use swc_ecma_parser::{lexer::Lexer, EsConfig, Parser, StringInput, Syntax, TsConfig}; +use regex::Regex; #[cfg(target_arch = "wasm32")] use wasm_bindgen::prelude::*; @@ -294,7 +295,6 @@ fn binding_ident_to_arg(BindingIdent { id, type_ann }: &BindingIdent) -> (String } lazy_static::lazy_static! { - static ref RE_SNK_CASE: Regex = Regex::new(r"_(\d)").unwrap(); static ref IMPORTS_VERSION: Regex = Regex::new(r"^((?:\@[^\/\@]+\/[^\/\@]+)|(?:[^\/\@]+))(?:\@(?:[^\/]+))?(.*)$").unwrap(); } @@ -320,13 +320,6 @@ pub fn remove_pinned_imports(code: &str) -> anyhow::Result { Ok(content) } -fn to_snake_case(s: &str) -> String { - let r = s.to_case(Case::Snake); - - // s_3 => s3 - RE_SNK_CASE.replace_all(&r, "$1").to_string() -} - fn tstype_to_typ(ts_type: &TsType) -> (Typ, bool) { match ts_type { TsType::TsKeywordType(t) => ( diff --git a/backend/parsers/windmill-parser-wasm/Cargo.toml b/backend/parsers/windmill-parser-wasm/Cargo.toml index a42672e7af..2513ece67b 100644 --- a/backend/parsers/windmill-parser-wasm/Cargo.toml +++ b/backend/parsers/windmill-parser-wasm/Cargo.toml @@ -12,17 +12,33 @@ path = "./src/lib.rs" [dev-dependencies] wasm-bindgen-test.workspace = true +windmill-parser-ts.workspace = true +windmill-parser-bash.workspace = true + +[features] +default = [] +go-parser = [ "dep:windmill-parser-go"] +bash-parser = [ "dep:windmill-parser-bash"] +sql-parser = [ "dep:windmill-parser-sql"] +py-parser = [ "dep:windmill-parser-py"] +ts-parser = [ "dep:windmill-parser-ts"] +php-parser = [ "dep:windmill-parser-php"] +rust-parser = [ "dep:windmill-parser-rust"] +graphql-parser = [ "dep:windmill-parser-graphql"] +ansible-parser = [ "dep:windmill-parser-yaml"] [dependencies] anyhow.workspace = true windmill-parser.workspace = true -windmill-parser-go.workspace = true -windmill-parser-bash.workspace = true -windmill-parser-sql.workspace = true -windmill-parser-py.workspace = true -windmill-parser-ts.workspace = true -windmill-parser-php.workspace = true -windmill-parser-graphql.workspace = true +windmill-parser-go = { workspace = true, optional = true } +windmill-parser-bash = { workspace = true, optional = true } +windmill-parser-sql = { workspace = true, optional = true } +windmill-parser-py = { workspace = true, optional = true } +windmill-parser-ts = { workspace = true, optional = true } +windmill-parser-php = { workspace = true, optional = true } +windmill-parser-graphql = { workspace = true, optional = true } +windmill-parser-rust = { workspace = true, optional = true } +windmill-parser-yaml = { workspace = true, optional = true } wasm-bindgen.workspace = true serde_json.workspace = true getrandom = { workspace = true, features = ["js"] } diff --git a/backend/parsers/windmill-parser-wasm/README_DEV.md b/backend/parsers/windmill-parser-wasm/README_DEV.md new file mode 100644 index 0000000000..ff3f866f4e --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/README_DEV.md @@ -0,0 +1,25 @@ +### Windmill parser wasm + +How to build + +``` +wasm-pack build --release --target web +``` + +#### Prerequisite + +Install wasm-pack + +``` +cargo install wasm-pack +``` + +#### To use it on a dev environment + +Go to frontend and run: + +``` +npm install ../backend/parsers/windmill-parser-wasm/pkg +``` + +Make sure to not reset the package.json before commiting diff --git a/backend/parsers/windmill-parser-wasm/build-deno-pkgs.sh b/backend/parsers/windmill-parser-wasm/build-deno-pkgs.sh new file mode 100755 index 0000000000..3ac0f9b424 --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/build-deno-pkgs.sh @@ -0,0 +1,44 @@ +#!/bin/bash +set -eou pipefail + +# full pkg +OUT_DIR="pkg" +wasm-pack build --release --target web --out-dir $OUT_DIR --all-features \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort + +# bun and deno +OUT_DIR="pkg-ts" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "ts-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-ts"/' $OUT_DIR/package.json + +# sql languages, graphql and bash/powershell, since they all use regex +OUT_DIR="pkg-regex" +wasm-pack build --release --target web --out-dir $OUT_DIR \ + --features "sql-parser,graphql-parser,bash-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-regex"/' $OUT_DIR/package.json + +# python +OUT_DIR="pkg-py" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "py-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-py"/' $OUT_DIR/package.json + +# go +OUT_DIR="pkg-go" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "go-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-go"/' $OUT_DIR/package.json + +# php +OUT_DIR="pkg-php" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "php-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-php"/' $OUT_DIR/package.json + +# rust +OUT_DIR="pkg-rust" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "rust-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-rust"/' $OUT_DIR/package.json diff --git a/backend/parsers/windmill-parser-wasm/build-pkgs.sh b/backend/parsers/windmill-parser-wasm/build-pkgs.sh new file mode 100755 index 0000000000..66dafe3ccc --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/build-pkgs.sh @@ -0,0 +1,50 @@ +#!/bin/bash +set -eou pipefail + +# full pkg +OUT_DIR="pkg" +wasm-pack build --release --target web --out-dir $OUT_DIR --all-features \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort + +# bun and deno +OUT_DIR="pkg-ts" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "ts-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-ts"/' $OUT_DIR/package.json + +# sql languages, graphql and bash/powershell, since they all use regex +OUT_DIR="pkg-regex" +wasm-pack build --release --target web --out-dir $OUT_DIR \ + --features "sql-parser,graphql-parser,bash-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-regex"/' $OUT_DIR/package.json + +# python +OUT_DIR="pkg-py" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "py-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-py"/' $OUT_DIR/package.json + +# go +OUT_DIR="pkg-go" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "go-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-go"/' $OUT_DIR/package.json + +# php +OUT_DIR="pkg-php" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "php-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-php"/' $OUT_DIR/package.json + +# rust +OUT_DIR="pkg-rust" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "rust-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-rust"/' $OUT_DIR/package.json + +# ansible +OUT_DIR="pkg-yaml" +wasm-pack build --release --target web --out-dir $OUT_DIR --features "ansible-parser" \ + -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort +sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-yaml"/' $OUT_DIR/package.json diff --git a/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.d.ts b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.d.ts new file mode 100644 index 0000000000..10824a1c62 --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.d.ts @@ -0,0 +1,126 @@ +// deno-lint-ignore-file +// deno-fmt-ignore-file + +export interface InstantiateResult { + instance: WebAssembly.Instance; + exports: { + parse_deno: typeof parse_deno; + parse_outputs: typeof parse_outputs; + parse_ts_imports: typeof parse_ts_imports; + parse_bash: typeof parse_bash; + parse_powershell: typeof parse_powershell; + parse_go: typeof parse_go; + parse_python: typeof parse_python; + parse_sql: typeof parse_sql; + parse_mysql: typeof parse_mysql; + parse_bigquery: typeof parse_bigquery; + parse_snowflake: typeof parse_snowflake; + parse_mssql: typeof parse_mssql; + parse_db_resource: typeof parse_db_resource; + parse_graphql: typeof parse_graphql; + parse_php: typeof parse_php; + parse_rust: typeof parse_rust + }; +} + +/** Gets if the Wasm module has been instantiated. */ +export function isInstantiated(): boolean; + +/** Options for instantiating a Wasm instance. */ +export interface InstantiateOptions { + /** Optional url to the Wasm file to instantiate. */ + url?: URL; + /** Callback to decompress the raw Wasm file bytes before instantiating. */ + decompress?: (bytes: Uint8Array) => Uint8Array; +} + +/** Instantiates an instance of the Wasm module returning its functions. +* @remarks It is safe to call this multiple times and once successfully +* loaded it will always return a reference to the same object. */ +export function instantiate(opts?: InstantiateOptions): Promise; + +/** Instantiates an instance of the Wasm module along with its exports. + * @remarks It is safe to call this multiple times and once successfully + * loaded it will always return a reference to the same object. */ +export function instantiateWithInstance(opts?: InstantiateOptions): Promise; + +/** +* @param {string} code +* @returns {string} +*/ +export function parse_deno(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_outputs(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_ts_imports(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_bash(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_powershell(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_go(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_python(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_sql(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_mysql(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_bigquery(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_snowflake(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_mssql(code: string): string; +/** +* @param {string} code +* @returns {string | undefined} +*/ +export function parse_db_resource(code: string): string | undefined; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_graphql(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_php(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_rust(code: string): string; diff --git a/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.js b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.js new file mode 100644 index 0000000000..ea2404efeb --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm.generated.js @@ -0,0 +1,1166 @@ +// @generated file from wasmbuild -- do not edit +// @ts-nocheck: generated +// deno-lint-ignore-file +// deno-fmt-ignore-file +/// + +// source-hash: d36b5583d8f6223c130a246a8713b8621d55b990 +let wasm; + +const heap = new Array(128).fill(undefined); + +heap.push(undefined, null, true, false); + +function getObject(idx) { + return heap[idx]; +} + +let WASM_VECTOR_LEN = 0; + +let cachedUint8Memory0 = null; + +function getUint8Memory0() { + if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { + cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8Memory0; +} + +const cachedTextEncoder = typeof TextEncoder !== "undefined" + ? new TextEncoder("utf-8") + : { + encode: () => { + throw Error("TextEncoder not available"); + }, + }; + +const encodeString = function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); +}; + +function passStringToWasm0(arg, malloc, realloc) { + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8Memory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +function isLikeNone(x) { + return x === undefined || x === null; +} + +let cachedInt32Memory0 = null; + +function getInt32Memory0() { + if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { + cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachedInt32Memory0; +} + +let heap_next = heap.length; + +function dropObject(idx) { + if (idx < 132) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +let cachedFloat64Memory0 = null; + +function getFloat64Memory0() { + if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) { + cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer); + } + return cachedFloat64Memory0; +} + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +const cachedTextDecoder = typeof TextDecoder !== "undefined" + ? new TextDecoder("utf-8", { ignoreBOM: true, fatal: true }) + : { + decode: () => { + throw Error("TextDecoder not available"); + }, + }; + +if (typeof TextDecoder !== "undefined") cachedTextDecoder.decode(); + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); +} + +let cachedBigInt64Memory0 = null; + +function getBigInt64Memory0() { + if ( + cachedBigInt64Memory0 === null || cachedBigInt64Memory0.byteLength === 0 + ) { + cachedBigInt64Memory0 = new BigInt64Array(wasm.memory.buffer); + } + return cachedBigInt64Memory0; +} + +function debugString(val) { + // primitive types + const type = typeof val; + if (type == "number" || type == "boolean" || val == null) { + return `${val}`; + } + if (type == "string") { + return `"${val}"`; + } + if (type == "symbol") { + const description = val.description; + if (description == null) { + return "Symbol"; + } else { + return `Symbol(${description})`; + } + } + if (type == "function") { + const name = val.name; + if (typeof name == "string" && name.length > 0) { + return `Function(${name})`; + } else { + return "Function"; + } + } + // objects + if (Array.isArray(val)) { + const length = val.length; + let debug = "["; + if (length > 0) { + debug += debugString(val[0]); + } + for (let i = 1; i < length; i++) { + debug += ", " + debugString(val[i]); + } + debug += "]"; + return debug; + } + // Test for built-in + const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); + let className; + if (builtInMatches.length > 1) { + className = builtInMatches[1]; + } else { + // Failed to match the standard '[object ClassName]' + return toString.call(val); + } + if (className == "Object") { + // we're a user defined class or Object + // JSON.stringify avoids problems with cycles, and is generally much + // easier than looping through ownProperties of `val`. + try { + return "Object(" + JSON.stringify(val) + ")"; + } catch (_) { + return "Object"; + } + } + // errors + if (val instanceof Error) { + return `${val.name}: ${val.message}\n${val.stack}`; + } + // TODO we could test for more things here, like `Set`s and `Map`s. + return className; +} +/** + * @param {string} code + * @returns {string} + */ +export function parse_deno(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_deno(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_outputs(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_outputs(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_ts_imports(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_ts_imports(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_bash(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_bash(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_powershell(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_powershell(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_go(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_go(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_python(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_python(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_sql(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_sql(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_mysql(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_mysql(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_bigquery(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_bigquery(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_snowflake(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_snowflake(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_mssql(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_mssql(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string | undefined} + */ +export function parse_db_resource(code) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_db_resource(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + let v2; + if (r0 !== 0) { + v2 = getStringFromWasm0(r0, r1).slice(); + wasm.__wbindgen_free(r0, r1 * 1, 1); + } + return v2; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_graphql(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_graphql(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_php(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_php(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +/** + * @param {string} code + * @returns {string} + */ +export function parse_rust(code) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + code, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + wasm.parse_rust(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_exn_store(addHeapObject(e)); + } +} + +const imports = { + __wbindgen_placeholder__: { + __wbindgen_string_get: function (arg0, arg1) { + const obj = getObject(arg1); + const ret = typeof obj === "string" ? obj : undefined; + var ptr1 = isLikeNone(ret) + ? 0 + : passStringToWasm0( + ret, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + var len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, + __wbindgen_object_drop_ref: function (arg0) { + takeObject(arg0); + }, + __wbindgen_boolean_get: function (arg0) { + const v = getObject(arg0); + const ret = typeof v === "boolean" ? (v ? 1 : 0) : 2; + return ret; + }, + __wbindgen_is_bigint: function (arg0) { + const ret = typeof (getObject(arg0)) === "bigint"; + return ret; + }, + __wbindgen_number_get: function (arg0, arg1) { + const obj = getObject(arg1); + const ret = typeof obj === "number" ? obj : undefined; + getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret; + getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); + }, + __wbindgen_is_object: function (arg0) { + const val = getObject(arg0); + const ret = typeof val === "object" && val !== null; + return ret; + }, + __wbindgen_in: function (arg0, arg1) { + const ret = getObject(arg0) in getObject(arg1); + return ret; + }, + __wbindgen_bigint_from_i64: function (arg0) { + const ret = arg0; + return addHeapObject(ret); + }, + __wbindgen_jsval_eq: function (arg0, arg1) { + const ret = getObject(arg0) === getObject(arg1); + return ret; + }, + __wbindgen_bigint_from_u64: function (arg0) { + const ret = BigInt.asUintN(64, arg0); + return addHeapObject(ret); + }, + __wbindgen_error_new: function (arg0, arg1) { + const ret = new Error(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }, + __wbg_eval_c227cc6614cd76e5: function (arg0, arg1) { + const ret = eval(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }, + __wbindgen_jsval_loose_eq: function (arg0, arg1) { + const ret = getObject(arg0) == getObject(arg1); + return ret; + }, + __wbg_get_bd8e338fbd5f5cc8: function (arg0, arg1) { + const ret = getObject(arg0)[arg1 >>> 0]; + return addHeapObject(ret); + }, + __wbg_length_cd7af8117672b8b8: function (arg0) { + const ret = getObject(arg0).length; + return ret; + }, + __wbindgen_is_function: function (arg0) { + const ret = typeof (getObject(arg0)) === "function"; + return ret; + }, + __wbg_next_40fc327bfc8770e6: function (arg0) { + const ret = getObject(arg0).next; + return addHeapObject(ret); + }, + __wbg_next_196c84450b364254: function () { + return handleError(function (arg0) { + const ret = getObject(arg0).next(); + return addHeapObject(ret); + }, arguments); + }, + __wbg_done_298b57d23c0fc80c: function (arg0) { + const ret = getObject(arg0).done; + return ret; + }, + __wbg_value_d93c65011f51a456: function (arg0) { + const ret = getObject(arg0).value; + return addHeapObject(ret); + }, + __wbg_iterator_2cee6dadfd956dfa: function () { + const ret = Symbol.iterator; + return addHeapObject(ret); + }, + __wbg_get_e3c254076557e348: function () { + return handleError(function (arg0, arg1) { + const ret = Reflect.get(getObject(arg0), getObject(arg1)); + return addHeapObject(ret); + }, arguments); + }, + __wbg_call_27c0f87801dedf93: function () { + return handleError(function (arg0, arg1) { + const ret = getObject(arg0).call(getObject(arg1)); + return addHeapObject(ret); + }, arguments); + }, + __wbg_isArray_2ab64d95e09ea0ae: function (arg0) { + const ret = Array.isArray(getObject(arg0)); + return ret; + }, + __wbg_instanceof_ArrayBuffer_836825be07d4c9d2: function (arg0) { + let result; + try { + result = getObject(arg0) instanceof ArrayBuffer; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_Map_87917e0a7aaf4012: function (arg0) { + let result; + try { + result = getObject(arg0) instanceof Map; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_isSafeInteger_f7b04ef02296c4d2: function (arg0) { + const ret = Number.isSafeInteger(getObject(arg0)); + return ret; + }, + __wbg_entries_95cc2c823b285a09: function (arg0) { + const ret = Object.entries(getObject(arg0)); + return addHeapObject(ret); + }, + __wbg_buffer_12d079cc21e14bdb: function (arg0) { + const ret = getObject(arg0).buffer; + return addHeapObject(ret); + }, + __wbg_new_63b92bc8671ed464: function (arg0) { + const ret = new Uint8Array(getObject(arg0)); + return addHeapObject(ret); + }, + __wbg_set_a47bac70306a19a7: function (arg0, arg1, arg2) { + getObject(arg0).set(getObject(arg1), arg2 >>> 0); + }, + __wbg_length_c20a40f15020d68a: function (arg0) { + const ret = getObject(arg0).length; + return ret; + }, + __wbg_instanceof_Uint8Array_2b3bbecd033d19f6: function (arg0) { + let result; + try { + result = getObject(arg0) instanceof Uint8Array; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbindgen_bigint_get_as_i64: function (arg0, arg1) { + const v = getObject(arg1); + const ret = typeof v === "bigint" ? v : undefined; + getBigInt64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? BigInt(0) : ret; + getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); + }, + __wbindgen_debug_string: function (arg0, arg1) { + const ret = debugString(getObject(arg1)); + const ptr1 = passStringToWasm0( + ret, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, + __wbindgen_throw: function (arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }, + __wbindgen_memory: function () { + const ret = wasm.memory; + return addHeapObject(ret); + }, + }, +}; + +class WasmBuildLoader { + #options; + #lastLoadPromise; + #instantiated; + + constructor(options) { + this.#options = options; + } + + get instance() { + return this.#instantiated?.instance; + } + + get module() { + return this.#instantiated?.module; + } + + load( + url, + decompress, + ) { + if (this.#instantiated) { + return Promise.resolve(this.#instantiated); + } else if (this.#lastLoadPromise == null) { + this.#lastLoadPromise = (async () => { + try { + this.#instantiated = await this.#instantiate(url, decompress); + return this.#instantiated; + } finally { + this.#lastLoadPromise = undefined; + } + })(); + } + return this.#lastLoadPromise; + } + + async #instantiate(url, decompress) { + const imports = this.#options.imports; + if (this.#options.cache != null && url.protocol !== "file:") { + try { + const result = await this.#options.cache( + url, + decompress ?? ((bytes) => bytes), + ); + if (result instanceof URL) { + url = result; + decompress = undefined; // already decompressed + } else if (result != null) { + return WebAssembly.instantiate(result, imports); + } + } catch { + // ignore if caching ever fails (ex. when on deploy) + } + } + + const isFile = url.protocol === "file:"; + + // make file urls work in Node via dnt + const isNode = globalThis.process?.versions?.node != null; + if (isFile && typeof Deno !== "object") { + throw new Error( + "Loading local files are not supported in this environment", + ); + } + if (isNode && isFile) { + // the deno global will be shimmed by dnt + const wasmCode = await Deno.readFile(url); + return WebAssembly.instantiate( + decompress ? decompress(wasmCode) : wasmCode, + imports, + ); + } + + switch (url.protocol) { + case "file:": + case "https:": + case "http:": { + const wasmResponse = await fetchWithRetries(url); + if (decompress) { + const wasmCode = new Uint8Array(await wasmResponse.arrayBuffer()); + return WebAssembly.instantiate(decompress(wasmCode), imports); + } + if ( + isFile || + wasmResponse.headers.get("content-type")?.toLowerCase() + .startsWith("application/wasm") + ) { + return WebAssembly.instantiateStreaming(wasmResponse, imports); + } else { + return WebAssembly.instantiate( + await wasmResponse.arrayBuffer(), + imports, + ); + } + } + default: + throw new Error(`Unsupported protocol: ${url.protocol}`); + } + } +} +const isNodeOrDeno = typeof Deno === "object" || + (typeof process !== "undefined" && process.versions != null && + process.versions.node != null); + +const loader = new WasmBuildLoader({ + imports, + cache: isNodeOrDeno ? cacheToLocalDir : undefined, +}); + +export async function instantiate(opts) { + return (await instantiateWithInstance(opts)).exports; +} + +export async function instantiateWithInstance(opts) { + const { instance } = await loader.load( + opts?.url ?? new URL("windmill_parser_wasm_bg.wasm", import.meta.url), + opts?.decompress, + ); + wasm = wasm ?? instance.exports; + cachedInt32Memory0 = cachedInt32Memory0 ?? new Int32Array(wasm.memory.buffer); + cachedUint8Memory0 = cachedUint8Memory0 ?? new Uint8Array(wasm.memory.buffer); + return { + instance, + exports: getWasmInstanceExports(), + }; +} + +function getWasmInstanceExports() { + return { + parse_deno, + parse_outputs, + parse_ts_imports, + parse_bash, + parse_powershell, + parse_go, + parse_python, + parse_sql, + parse_mysql, + parse_bigquery, + parse_snowflake, + parse_mssql, + parse_db_resource, + parse_graphql, + parse_php, + parse_rust, + }; +} + +export function isInstantiated() { + return loader.instance != null; +} +export async function cacheToLocalDir(url, decompress) { + const localPath = await getUrlLocalPath(url); + if (localPath == null) { + return undefined; + } + if (!await exists(localPath)) { + const fileBytes = decompress(new Uint8Array(await getUrlBytes(url))); + try { + await Deno.writeFile(localPath, fileBytes); + } catch { + // ignore and return the wasm bytes + return fileBytes; + } + } + return toFileUrl(localPath); +} +async function getUrlLocalPath(url) { + try { + const dataDirPath = await getInitializedLocalDataDirPath(); + const hash = await getUrlHash(url); + return `${dataDirPath}/${hash}.wasm`; + } catch { + return undefined; + } +} +async function getInitializedLocalDataDirPath() { + const dataDir = localDataDir(); + if (dataDir == null) { + throw new Error(`Could not find local data directory.`); + } + const dirPath = `${dataDir}/deno-wasmbuild`; + await ensureDir(dirPath); + return dirPath; +} +async function exists(filePath) { + try { + await Deno.lstat(filePath); + return true; + } catch (error) { + if (error instanceof Deno.errors.NotFound) { + return false; + } + throw error; + } +} +async function ensureDir(dir) { + try { + const fileInfo = await Deno.lstat(dir); + if (!fileInfo.isDirectory) { + throw new Error(`Path was not a directory '${dir}'`); + } + } catch (err) { + if (err instanceof Deno.errors.NotFound) { + // if dir not exists. then create it. + await Deno.mkdir(dir, { recursive: true }); + return; + } + throw err; + } +} +async function getUrlHash(url) { + // Taken from MDN: https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest + const hashBuffer = await crypto.subtle.digest( + "SHA-256", + new TextEncoder().encode(url.href), + ); + // convert buffer to byte array + const hashArray = Array.from(new Uint8Array(hashBuffer)); + // convert bytes to hex string + const hashHex = hashArray + .map((b) => b.toString(16).padStart(2, "0")) + .join(""); + return hashHex; +} +async function getUrlBytes(url) { + const response = await fetchWithRetries(url); + return await response.arrayBuffer(); +} +// the below is extracted from deno_std/path +const WHITESPACE_ENCODINGS = { + "\u0009": "%09", + "\u000A": "%0A", + "\u000B": "%0B", + "\u000C": "%0C", + "\u000D": "%0D", + "\u0020": "%20", +}; +function encodeWhitespace(string) { + return string.replaceAll(/[\s]/g, (c) => { + return WHITESPACE_ENCODINGS[c] ?? c; + }); +} +function toFileUrl(path) { + return Deno.build.os === "windows" + ? windowsToFileUrl(path) + : posixToFileUrl(path); +} +function posixToFileUrl(path) { + const url = new URL("file:///"); + url.pathname = encodeWhitespace( + path.replace(/%/g, "%25").replace(/\\/g, "%5C"), + ); + return url; +} +function windowsToFileUrl(path) { + const [, hostname, pathname] = path.match( + /^(?:[/\\]{2}([^/\\]+)(?=[/\\](?:[^/\\]|$)))?(.*)/, + ); + const url = new URL("file:///"); + url.pathname = encodeWhitespace(pathname.replace(/%/g, "%25")); + if (hostname != null && hostname != "localhost") { + url.hostname = hostname; + if (!url.hostname) { + throw new TypeError("Invalid hostname."); + } + } + return url; +} +export async function fetchWithRetries(url, maxRetries = 5) { + let sleepMs = 250; + let iterationCount = 0; + while (true) { + iterationCount++; + try { + const res = await fetch(url); + if (res.ok || iterationCount > maxRetries) { + return res; + } + } catch (err) { + if (iterationCount > maxRetries) { + throw err; + } + } + console.warn(`Failed fetching. Retrying in ${sleepMs}ms...`); + await new Promise((resolve) => setTimeout(resolve, sleepMs)); + sleepMs = Math.min(sleepMs * 2, 10000); + } +} +// MIT License - Copyright (c) justjavac. +// https://github.com/justjavac/deno_dirs/blob/e8c001bbef558f08fd486d444af391729b0b8068/data_local_dir/mod.ts +function localDataDir() { + switch (Deno.build.os) { + case "linux": { + const xdg = Deno.env.get("XDG_DATA_HOME"); + if (xdg) { + return xdg; + } + const home = Deno.env.get("HOME"); + if (home) { + return `${home}/.local/share`; + } + break; + } + case "darwin": { + const home = Deno.env.get("HOME"); + if (home) { + return `${home}/Library/Application Support`; + } + break; + } + case "windows": + return Deno.env.get("LOCALAPPDATA") ?? undefined; + } + return undefined; +} diff --git a/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm_bg.wasm b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm_bg.wasm new file mode 100644 index 0000000000..de163879c8 Binary files /dev/null and b/backend/parsers/windmill-parser-wasm/lib/windmill_parser_wasm_bg.wasm differ diff --git a/backend/parsers/windmill-parser-wasm/pkg/package.json b/backend/parsers/windmill-parser-wasm/pkg/package.json index 0c70400479..e63340cf07 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/package.json +++ b/backend/parsers/windmill-parser-wasm/pkg/package.json @@ -3,7 +3,7 @@ "collaborators": [ "Ruben Fiszel " ], - "version": "1.367.2", + "version": "1.385.0", "files": [ "windmill_parser_wasm_bg.wasm", "windmill_parser_wasm.js", diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.d.ts b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.d.ts index 30e4bc2f54..439090ee9a 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.d.ts +++ b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.d.ts @@ -75,6 +75,11 @@ export function parse_graphql(code: string): string; * @returns {string} */ export function parse_php(code: string): string; +/** +* @param {string} code +* @returns {string} +*/ +export function parse_rust(code: string): string; export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; @@ -95,6 +100,7 @@ export interface InitOutput { readonly parse_db_resource: (a: number, b: number, c: number) => void; readonly parse_graphql: (a: number, b: number, c: number) => void; readonly parse_php: (a: number, b: number, c: number) => void; + readonly parse_rust: (a: number, b: number, c: number) => void; readonly __wbindgen_malloc: (a: number, b: number) => number; readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; readonly __wbindgen_add_to_stack_pointer: (a: number) => number; @@ -107,18 +113,18 @@ export type SyncInitInput = BufferSource | WebAssembly.Module; * Instantiates the given `module`, which can either be bytes or * a precompiled `WebAssembly.Module`. * -* @param {SyncInitInput} module +* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated. * * @returns {InitOutput} */ -export function initSync(module: SyncInitInput): InitOutput; +export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput; /** * If `module_or_path` is {RequestInfo} or {URL}, makes a request and * for everything else, calls `WebAssembly.instantiate` directly. * -* @param {InitInput | Promise} module_or_path +* @param {{ module_or_path: InitInput | Promise }} module_or_path - Passing `InitInput` directly is deprecated. * * @returns {Promise} */ -export default function __wbg_init (module_or_path?: InitInput | Promise): Promise; +export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise } | InitInput | Promise): Promise; diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js index a945347d31..ae0865a76c 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js +++ b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm.js @@ -22,13 +22,13 @@ function takeObject(idx) { let WASM_VECTOR_LEN = 0; -let cachedUint8Memory0 = null; +let cachedUint8ArrayMemory0 = null; -function getUint8Memory0() { - if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { - cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); +function getUint8ArrayMemory0() { + if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { + cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); } - return cachedUint8Memory0; + return cachedUint8ArrayMemory0; } const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); @@ -51,7 +51,7 @@ function passStringToWasm0(arg, malloc, realloc) { if (realloc === undefined) { const buf = cachedTextEncoder.encode(arg); const ptr = malloc(buf.length, 1) >>> 0; - getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); + getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); WASM_VECTOR_LEN = buf.length; return ptr; } @@ -59,7 +59,7 @@ function passStringToWasm0(arg, malloc, realloc) { let len = arg.length; let ptr = malloc(len, 1) >>> 0; - const mem = getUint8Memory0(); + const mem = getUint8ArrayMemory0(); let offset = 0; @@ -74,7 +74,7 @@ function passStringToWasm0(arg, malloc, realloc) { arg = arg.slice(offset); } ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; - const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); const ret = encodeString(arg, view); offset += ret.written; @@ -89,22 +89,13 @@ function isLikeNone(x) { return x === undefined || x === null; } -let cachedInt32Memory0 = null; +let cachedDataViewMemory0 = null; -function getInt32Memory0() { - if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { - cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); +function getDataViewMemory0() { + if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) { + cachedDataViewMemory0 = new DataView(wasm.memory.buffer); } - return cachedInt32Memory0; -} - -let cachedFloat64Memory0 = null; - -function getFloat64Memory0() { - if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) { - cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer); - } - return cachedFloat64Memory0; + return cachedDataViewMemory0; } function addHeapObject(obj) { @@ -122,16 +113,7 @@ if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; function getStringFromWasm0(ptr, len) { ptr = ptr >>> 0; - return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); -} - -let cachedBigInt64Memory0 = null; - -function getBigInt64Memory0() { - if (cachedBigInt64Memory0 === null || cachedBigInt64Memory0.byteLength === 0) { - cachedBigInt64Memory0 = new BigInt64Array(wasm.memory.buffer); - } - return cachedBigInt64Memory0; + return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); } function debugString(val) { @@ -210,8 +192,8 @@ export function parse_deno(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_deno(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -233,8 +215,8 @@ export function parse_outputs(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_outputs(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -256,8 +238,8 @@ export function parse_ts_imports(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_ts_imports(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -279,8 +261,8 @@ export function parse_bash(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_bash(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -302,8 +284,8 @@ export function parse_powershell(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_powershell(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -325,8 +307,8 @@ export function parse_go(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_go(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -348,8 +330,8 @@ export function parse_python(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_python(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -371,8 +353,8 @@ export function parse_sql(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_sql(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -394,8 +376,8 @@ export function parse_mysql(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_mysql(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -417,8 +399,8 @@ export function parse_bigquery(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_bigquery(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -440,8 +422,8 @@ export function parse_snowflake(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_snowflake(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -463,8 +445,8 @@ export function parse_mssql(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_mssql(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -484,8 +466,8 @@ export function parse_db_resource(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_db_resource(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); let v2; if (r0 !== 0) { v2 = getStringFromWasm0(r0, r1).slice(); @@ -509,8 +491,8 @@ export function parse_graphql(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_graphql(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -532,8 +514,8 @@ export function parse_php(code) { const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len0 = WASM_VECTOR_LEN; wasm.parse_php(retptr, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); deferred2_0 = r0; deferred2_1 = r1; return getStringFromWasm0(r0, r1); @@ -585,7 +567,7 @@ async function __wbg_load(module, imports) { function __wbg_get_imports() { const imports = {}; imports.wbg = {}; - imports.wbg.__wbg_eval_aa725d466edcea2c = function(arg0, arg1) { + imports.wbg.__wbg_eval_204ec87eadeaef4a = function(arg0, arg1) { const ret = eval(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }; @@ -597,8 +579,8 @@ function __wbg_get_imports() { const ret = typeof(obj) === 'string' ? obj : undefined; var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); }; imports.wbg.__wbindgen_boolean_get = function(arg0) { const v = getObject(arg0); @@ -612,8 +594,8 @@ function __wbg_get_imports() { imports.wbg.__wbindgen_number_get = function(arg0, arg1) { const obj = getObject(arg1); const ret = typeof(obj) === 'number' ? obj : undefined; - getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret; - getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); + getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true); }; imports.wbg.__wbindgen_is_object = function(arg0) { const val = getObject(arg0); @@ -644,11 +626,11 @@ function __wbg_get_imports() { const ret = getObject(arg0) == getObject(arg1); return ret; }; - imports.wbg.__wbg_get_bd8e338fbd5f5cc8 = function(arg0, arg1) { + imports.wbg.__wbg_get_3baa728f9d58d3f6 = function(arg0, arg1) { const ret = getObject(arg0)[arg1 >>> 0]; return addHeapObject(ret); }; - imports.wbg.__wbg_length_cd7af8117672b8b8 = function(arg0) { + imports.wbg.__wbg_length_ae22078168b726f5 = function(arg0) { const ret = getObject(arg0).length; return ret; }; @@ -656,39 +638,39 @@ function __wbg_get_imports() { const ret = typeof(getObject(arg0)) === 'function'; return ret; }; - imports.wbg.__wbg_next_40fc327bfc8770e6 = function(arg0) { + imports.wbg.__wbg_next_de3e9db4440638b2 = function(arg0) { const ret = getObject(arg0).next; return addHeapObject(ret); }; - imports.wbg.__wbg_next_196c84450b364254 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_next_f9cb570345655b9a = function() { return handleError(function (arg0) { const ret = getObject(arg0).next(); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_done_298b57d23c0fc80c = function(arg0) { + imports.wbg.__wbg_done_bfda7aa8f252b39f = function(arg0) { const ret = getObject(arg0).done; return ret; }; - imports.wbg.__wbg_value_d93c65011f51a456 = function(arg0) { + imports.wbg.__wbg_value_6d39332ab4788d86 = function(arg0) { const ret = getObject(arg0).value; return addHeapObject(ret); }; - imports.wbg.__wbg_iterator_2cee6dadfd956dfa = function() { + imports.wbg.__wbg_iterator_888179a48810a9fe = function() { const ret = Symbol.iterator; return addHeapObject(ret); }; - imports.wbg.__wbg_get_e3c254076557e348 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_get_224d16597dbbfd96 = function() { return handleError(function (arg0, arg1) { const ret = Reflect.get(getObject(arg0), getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_call_27c0f87801dedf93 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_call_1084a111329e68ce = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).call(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_isArray_2ab64d95e09ea0ae = function(arg0) { + imports.wbg.__wbg_isArray_8364a5371e9737d8 = function(arg0) { const ret = Array.isArray(getObject(arg0)); return ret; }; - imports.wbg.__wbg_instanceof_ArrayBuffer_836825be07d4c9d2 = function(arg0) { + imports.wbg.__wbg_instanceof_ArrayBuffer_61dfc3198373c902 = function(arg0) { let result; try { result = getObject(arg0) instanceof ArrayBuffer; @@ -698,7 +680,7 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_instanceof_Map_87917e0a7aaf4012 = function(arg0) { + imports.wbg.__wbg_instanceof_Map_763ce0e95960d55e = function(arg0) { let result; try { result = getObject(arg0) instanceof Map; @@ -708,30 +690,30 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_isSafeInteger_f7b04ef02296c4d2 = function(arg0) { + imports.wbg.__wbg_isSafeInteger_7f1ed56200d90674 = function(arg0) { const ret = Number.isSafeInteger(getObject(arg0)); return ret; }; - imports.wbg.__wbg_entries_95cc2c823b285a09 = function(arg0) { + imports.wbg.__wbg_entries_7a0e06255456ebcd = function(arg0) { const ret = Object.entries(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_buffer_12d079cc21e14bdb = function(arg0) { + imports.wbg.__wbg_buffer_b7b08af79b0b0974 = function(arg0) { const ret = getObject(arg0).buffer; return addHeapObject(ret); }; - imports.wbg.__wbg_new_63b92bc8671ed464 = function(arg0) { + imports.wbg.__wbg_new_ea1883e1e5e86686 = function(arg0) { const ret = new Uint8Array(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_set_a47bac70306a19a7 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_set_d1e79e2388520f18 = function(arg0, arg1, arg2) { getObject(arg0).set(getObject(arg1), arg2 >>> 0); }; - imports.wbg.__wbg_length_c20a40f15020d68a = function(arg0) { + imports.wbg.__wbg_length_8339fcf5d8ecd12e = function(arg0) { const ret = getObject(arg0).length; return ret; }; - imports.wbg.__wbg_instanceof_Uint8Array_2b3bbecd033d19f6 = function(arg0) { + imports.wbg.__wbg_instanceof_Uint8Array_247a91427532499e = function(arg0) { let result; try { result = getObject(arg0) instanceof Uint8Array; @@ -744,15 +726,15 @@ function __wbg_get_imports() { imports.wbg.__wbindgen_bigint_get_as_i64 = function(arg0, arg1) { const v = getObject(arg1); const ret = typeof(v) === 'bigint' ? v : undefined; - getBigInt64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? BigInt(0) : ret; - getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); + getDataViewMemory0().setBigInt64(arg0 + 8 * 1, isLikeNone(ret) ? BigInt(0) : ret, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true); }; imports.wbg.__wbindgen_debug_string = function(arg0, arg1) { const ret = debugString(getObject(arg1)); const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); }; imports.wbg.__wbindgen_throw = function(arg0, arg1) { throw new Error(getStringFromWasm0(arg0, arg1)); @@ -765,17 +747,16 @@ function __wbg_get_imports() { return imports; } -function __wbg_init_memory(imports, maybe_memory) { +function __wbg_init_memory(imports, memory) { } function __wbg_finalize_init(instance, module) { wasm = instance.exports; __wbg_init.__wbindgen_wasm_module = module; - cachedBigInt64Memory0 = null; - cachedFloat64Memory0 = null; - cachedInt32Memory0 = null; - cachedUint8Memory0 = null; + cachedDataViewMemory0 = null; + cachedUint8ArrayMemory0 = null; + return wasm; @@ -784,6 +765,12 @@ function __wbg_finalize_init(instance, module) { function initSync(module) { if (wasm !== undefined) return wasm; + + if (typeof module !== 'undefined' && Object.getPrototypeOf(module) === Object.prototype) + ({module} = module) + else + console.warn('using deprecated parameters for `initSync()`; pass a single object instead') + const imports = __wbg_get_imports(); __wbg_init_memory(imports); @@ -797,24 +784,30 @@ function initSync(module) { return __wbg_finalize_init(instance, module); } -async function __wbg_init(input) { +async function __wbg_init(module_or_path) { if (wasm !== undefined) return wasm; - if (typeof input === 'undefined') { - input = new URL('windmill_parser_wasm_bg.wasm', import.meta.url); + + if (typeof module_or_path !== 'undefined' && Object.getPrototypeOf(module_or_path) === Object.prototype) + ({module_or_path} = module_or_path) + else + console.warn('using deprecated parameters for the initialization function; pass a single object instead') + + if (typeof module_or_path === 'undefined') { + module_or_path = new URL('windmill_parser_wasm_bg.wasm', import.meta.url); } const imports = __wbg_get_imports(); - if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { - input = fetch(input); + if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) { + module_or_path = fetch(module_or_path); } __wbg_init_memory(imports); - const { instance, module } = await __wbg_load(await input, imports); + const { instance, module } = await __wbg_load(await module_or_path, imports); return __wbg_finalize_init(instance, module); } -export { initSync } +export { initSync }; export default __wbg_init; diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm index eb64263b45..501033c565 100644 Binary files a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm and b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm differ diff --git a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm.d.ts b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm.d.ts index 1fdcb8941c..5e6938f873 100644 --- a/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm.d.ts +++ b/backend/parsers/windmill-parser-wasm/pkg/windmill_parser_wasm_bg.wasm.d.ts @@ -16,6 +16,7 @@ export function parse_mssql(a: number, b: number, c: number): void; export function parse_db_resource(a: number, b: number, c: number): void; export function parse_graphql(a: number, b: number, c: number): void; export function parse_php(a: number, b: number, c: number): void; +export function parse_rust(a: number, b: number, c: number): void; export function __wbindgen_malloc(a: number, b: number): number; export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number; export function __wbindgen_add_to_stack_pointer(a: number): number; diff --git a/backend/parsers/windmill-parser-wasm/publish-pkgs.sh b/backend/parsers/windmill-parser-wasm/publish-pkgs.sh new file mode 100755 index 0000000000..7e2fd8beb2 --- /dev/null +++ b/backend/parsers/windmill-parser-wasm/publish-pkgs.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -eou pipefail +cd "$(dirname "${BASH_SOURCE[0]}")" + +args=${1:-} + +pushd "pkg-ts" && npm publish ${args} +popd + +pushd "pkg-regex" && npm publish ${args} +popd + +pushd "pkg-py" && npm publish ${args} +popd + +pushd "pkg-go" && npm publish ${args} +popd + +pushd "pkg-php" && npm publish ${args} +popd + +pushd "pkg-rust" && npm publish ${args} +popd diff --git a/backend/parsers/windmill-parser-wasm/src/lib.rs b/backend/parsers/windmill-parser-wasm/src/lib.rs index 5218357656..c10f30c138 100644 --- a/backend/parsers/windmill-parser-wasm/src/lib.rs +++ b/backend/parsers/windmill-parser-wasm/src/lib.rs @@ -1,8 +1,12 @@ +#[cfg(feature = "ts-parser")] use serde_json::json; +#[allow(unused_imports)] use wasm_bindgen::prelude::*; use windmill_parser::MainArgSignature; +#[cfg(feature = "ts-parser")] use windmill_parser_ts::{parse_expr_for_ids, parse_expr_for_imports}; +#[allow(dead_code)] fn wrap_sig(r: anyhow::Result) -> String { if let Ok(r) = r { return serde_json::to_string(&r).unwrap(); @@ -11,11 +15,13 @@ fn wrap_sig(r: anyhow::Result) -> String { } } +#[cfg(feature = "ts-parser")] #[wasm_bindgen] pub fn parse_deno(code: &str) -> String { wrap_sig(windmill_parser_ts::parse_deno_signature(code, false, None)) } +#[cfg(feature = "ts-parser")] #[wasm_bindgen] pub fn parse_outputs(code: &str) -> String { let parsed = parse_expr_for_ids(code); @@ -27,6 +33,7 @@ pub fn parse_outputs(code: &str) -> String { return serde_json::to_string(&r).unwrap(); } +#[cfg(feature = "ts-parser")] #[wasm_bindgen] pub fn parse_ts_imports(code: &str) -> String { let parsed = parse_expr_for_imports(code); @@ -38,62 +45,86 @@ pub fn parse_ts_imports(code: &str) -> String { return serde_json::to_string(&r).unwrap(); } +#[cfg(feature = "bash-parser")] #[wasm_bindgen] pub fn parse_bash(code: &str) -> String { wrap_sig(windmill_parser_bash::parse_bash_sig(code)) } +#[cfg(feature = "bash-parser")] #[wasm_bindgen] pub fn parse_powershell(code: &str) -> String { wrap_sig(windmill_parser_bash::parse_powershell_sig(code)) } +#[cfg(feature = "go-parser")] #[wasm_bindgen] pub fn parse_go(code: &str) -> String { wrap_sig(windmill_parser_go::parse_go_sig(code)) } +#[cfg(feature = "py-parser")] #[wasm_bindgen] pub fn parse_python(code: &str) -> String { wrap_sig(windmill_parser_py::parse_python_signature(code, None)) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_sql(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_pgsql_sig(code)) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_mysql(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_mysql_sig(code)) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_bigquery(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_bigquery_sig(code)) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_snowflake(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_snowflake_sig(code)) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_mssql(code: &str) -> String { wrap_sig(windmill_parser_sql::parse_mssql_sig(code)) } +#[cfg(feature = "sql-parser")] #[wasm_bindgen] pub fn parse_db_resource(code: &str) -> Option { windmill_parser_sql::parse_db_resource(code) } +#[cfg(feature = "graphql-parser")] #[wasm_bindgen] pub fn parse_graphql(code: &str) -> String { wrap_sig(windmill_parser_graphql::parse_graphql_sig(code)) } +#[cfg(feature = "php-parser")] #[wasm_bindgen] pub fn parse_php(code: &str) -> String { wrap_sig(windmill_parser_php::parse_php_signature(code, None)) } + +#[cfg(feature = "rust-parser")] +#[wasm_bindgen] +pub fn parse_rust(code: &str) -> String { + wrap_sig(windmill_parser_rust::parse_rust_signature(code)) +} + +#[cfg(feature = "ansible-parser")] +#[wasm_bindgen] +pub fn parse_ansible(code: &str) -> String { + wrap_sig(windmill_parser_yaml::parse_ansible_sig(code)) +} diff --git a/backend/parsers/windmill-parser-yaml/Cargo.toml b/backend/parsers/windmill-parser-yaml/Cargo.toml new file mode 100644 index 0000000000..9bcfbea7a7 --- /dev/null +++ b/backend/parsers/windmill-parser-yaml/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "windmill-parser-yaml" +version.workspace = true +authors.workspace = true +edition.workspace = true + +[lib] +name = "windmill_parser_yaml" +path = "./src/lib.rs" + +[dependencies] +yaml-rust.workspace = true +windmill-parser.workspace = true +anyhow.workspace = true +serde_json.workspace = true diff --git a/backend/parsers/windmill-parser-yaml/src/lib.rs b/backend/parsers/windmill-parser-yaml/src/lib.rs new file mode 100644 index 0000000000..dd9e25e564 --- /dev/null +++ b/backend/parsers/windmill-parser-yaml/src/lib.rs @@ -0,0 +1,268 @@ +use anyhow::anyhow; +use serde_json::json; +use windmill_parser::{Arg, MainArgSignature, ObjectProperty, Typ}; +use yaml_rust::{Yaml, YamlEmitter, YamlLoader}; + +pub fn parse_ansible_sig(inner_content: &str) -> anyhow::Result { + let docs = YamlLoader::load_from_str(inner_content) + .map_err(|e| anyhow!("Failed to parse yaml: {}", e))?; + + if docs.len() < 2 { + return Ok(MainArgSignature { + star_args: false, + star_kwargs: false, + args: vec![], + no_main_func: None, + }); + } + + let mut args = vec![]; + if let Yaml::Hash(doc) = &docs[0] { + for (key, value) in doc { + match key { + Yaml::String(key) if key == "extra_vars" => { + if let Yaml::Hash(v) = &value { + for (key, arg) in v { + if let Yaml::String(arg_name) = key { + args.push(Arg { + name: arg_name.to_string(), + otyp: None, + typ: parse_ansible_typ(&arg), + default: None, + has_default: false, + oidx: None, + }) + } + } + } + } + Yaml::String(key) if key == "inventory" => { + for inv in parse_inventories(value)? { + if inv.pinned_resource.is_some() { + continue; + } + args.push(Arg { + name: inv.name, + otyp: None, + typ: Typ::Resource(inv.resource_type.unwrap_or("Unknown".to_string())), + has_default: inv.default.is_some(), + default: inv.default.map(|v| json!(format!("$res:{}", v))), + oidx: None, + }) + } + } + _ => (), + } + } + } + Ok(MainArgSignature { star_args: false, star_kwargs: false, args, no_main_func: None }) +} + +fn parse_ansible_typ(arg: &Yaml) -> Typ { + if let Yaml::Hash(arg) = arg { + if let Some(Yaml::String(typ)) = arg.get(&Yaml::String("type".to_string())) { + match typ.as_ref() { + "boolean" => Typ::Bool, + "integer" => Typ::Int, + "number" => Typ::Float, + "string" => { + if let Some(Yaml::String(fmt)) = arg.get(&Yaml::String("format".to_string())) { + match fmt.as_ref() { + "date-time" | "datetime" => Typ::Datetime, + "email" => Typ::Email, + _ => Typ::Str(None), + } + } else { + Typ::Str(None) + } + } + "object" => { + if let Some(Yaml::Hash(props)) = + arg.get(&Yaml::String("properties".to_string())) + { + let mut prop_vec = vec![]; + for (key, value) in props { + if let Yaml::String(key) = key { + prop_vec.push(ObjectProperty { + key: key.clone(), + typ: Box::new(parse_ansible_typ(value)), + }) + } + } + Typ::Object(prop_vec) + } else { + Typ::Object(vec![]) + } + } + "array" => { + if let Some(items) = arg.get(&Yaml::String("items".to_string())) { + Typ::List(Box::new(parse_ansible_typ(items))) + } else { + Typ::List(Box::new(Typ::Unknown)) + } + } + "windmill_resource" => { + if let Some(Yaml::String(res_name)) = + arg.get(&Yaml::String("resource_type".to_string())) + { + Typ::Resource(res_name.clone()) + } else { + Typ::Resource("".to_string()) + } + } + _ => Typ::Unknown, + } + } else { + Typ::Unknown + } + } else { + Typ::Unknown + } +} + +#[derive(Debug)] +pub struct FileResource { + pub resource_path: String, + pub target_path: String, +} + +#[derive(Debug, Clone)] +pub struct AnsibleInventory { + pub default: Option, + pub name: String, + resource_type: Option, + pub pinned_resource: Option, +} +#[derive(Debug)] +pub struct AnsibleRequirements { + pub python_reqs: Vec, + pub collections: Option, + pub file_resources: Vec, + pub inventories: Vec, +} + +fn parse_inventories(inventory_yaml: &Yaml) -> anyhow::Result> { + if let Yaml::Array(arr) = inventory_yaml { + let mut ret = vec![]; + for (i, inv) in arr.iter().enumerate() { + if let Yaml::Hash(inv) = inv { + let resource_type = inv + .get(&Yaml::String("resource_type".to_string())) + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + + let windmill_path = inv + .get(&Yaml::String("default".to_string())) + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + + let name = if i == 0 { + "inventory.ini".to_string() + } else { + format!("inventory-{}.ini", i) + }; + + let name = inv + .get(&Yaml::String("name".to_string())) + .and_then(|v| v.as_str()) + .unwrap_or(name.as_str()) + .to_string(); + + let pin = inv + .get(&Yaml::String("resource".to_string())) + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + + ret.push(AnsibleInventory { default: windmill_path, name, resource_type, pinned_resource: pin }); + } + } + return Ok(ret); + } + return Err(anyhow!("Invalid inventory definition")); +} + +pub fn parse_ansible_reqs( + inner_content: &str, +) -> anyhow::Result<(String, Option, String)> { + let mut logs = String::new(); + let docs = YamlLoader::load_from_str(inner_content) + .map_err(|e| anyhow!("Failed to parse yaml: {}", e))?; + + if docs.len() < 2 { + return Ok((logs, None, inner_content.to_string())); + } + + let mut ret = AnsibleRequirements { + python_reqs: vec![], + collections: None, + file_resources: vec![], + inventories: vec![], + }; + + if let Yaml::Hash(doc) = &docs[0] { + for (key, value) in doc { + match key { + Yaml::String(key) if key == "dependencies" => { + if let Yaml::Hash(deps) = value { + if let Some(galaxy_requirements) = + deps.get(&Yaml::String("galaxy".to_string())) + { + let mut out_str = String::new(); + let mut emitter = YamlEmitter::new(&mut out_str); + emitter.dump(galaxy_requirements)?; + ret.collections = Some(out_str); + } + if let Some(Yaml::Array(py_reqs)) = + deps.get(&Yaml::String("python".to_string())) + { + ret.python_reqs = py_reqs + .iter() + .map(|d| d.as_str().map(|s| s.to_string())) + .filter_map(|x| x) + .collect(); + } + } + } + Yaml::String(key) if key == "file_resources" => { + if let Yaml::Array(file_resources) = value { + let resources: anyhow::Result> = + file_resources.iter().map(parse_file_resource).collect(); + ret.file_resources.append(&mut resources?); + } + } + Yaml::String(key) if key == "extra_vars" => {} + Yaml::String(key) if key == "inventory" => { + ret.inventories = parse_inventories(value)?; + } + Yaml::String(key) => logs.push_str(&format!("\nUnknown field `{}`. Ignoring", key)), + _ => (), + } + } + } + let mut out_str = String::new(); + let mut emitter = YamlEmitter::new(&mut out_str); + + for i in 1..docs.len() { + emitter.dump(&docs[i])?; + } + Ok((logs, Some(ret), out_str)) +} + +fn parse_file_resource(yaml: &Yaml) -> anyhow::Result { + if let Yaml::Hash(f) = yaml { + if let Some(Yaml::String(resource_path)) = f.get(&Yaml::String("resource".to_string())) + { + let target_path = f + .get(&Yaml::String("target".to_string())) + .and_then(|x| x.as_str()) + .map(|x| x.to_string()) + .ok_or(anyhow!( + "No `target` provided for file resource {}. Please input a target relative path for the ansible playbook to see this file.", + resource_path + ))?; + return Ok(FileResource { resource_path: resource_path.clone(), target_path }); + } + return Err(anyhow!("File resource should have a `resource` field, linking to a text file resource")); + } + return Err(anyhow!("Invalid file resource: Should be a dictionary.")); +} diff --git a/backend/parsers/windmill-parser/Cargo.toml b/backend/parsers/windmill-parser/Cargo.toml index 9bf4ad5eba..7dc464a4b3 100644 --- a/backend/parsers/windmill-parser/Cargo.toml +++ b/backend/parsers/windmill-parser/Cargo.toml @@ -11,3 +11,4 @@ path = "./src/lib.rs" [dependencies] serde = { version = "1.0", features = ["derive"] } serde_json.workspace = true +convert_case.workspace = true diff --git a/backend/parsers/windmill-parser/src/lib.rs b/backend/parsers/windmill-parser/src/lib.rs index a739dc53d2..c65b95d07c 100644 --- a/backend/parsers/windmill-parser/src/lib.rs +++ b/backend/parsers/windmill-parser/src/lib.rs @@ -6,6 +6,7 @@ * LICENSE-AGPL for a copy of the license. */ +use convert_case::{Boundary, Case, Casing}; use serde::Serialize; use serde_json::Value; @@ -75,3 +76,88 @@ pub fn json_to_typ(js: &Value) -> Typ { _ => Typ::Unknown, } } + +pub fn to_snake_case(s: &str) -> String { + s.with_boundaries(&Boundary::defaults()) + .without_boundaries(&Boundary::letter_digit()) + .to_case(Case::Snake) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_snake_case() { + assert_eq!("s3", to_snake_case("S3")); + assert_eq!("s3", to_snake_case("s3")); + assert_eq!("s_3", to_snake_case("S_3")); + assert_eq!("type_name_here", to_snake_case("typeNameHere")); + } + + #[test] + fn test_empty_string() { + assert_eq!(to_snake_case(""), ""); + } + + #[test] + fn test_single_char_lowercase() { + assert_eq!(to_snake_case("a"), "a"); + } + + #[test] + fn test_single_char_uppercase() { + assert_eq!(to_snake_case("A"), "a"); + } + + #[test] + fn test_all_uppercase() { + assert_eq!(to_snake_case("TEST"), "test"); + } + + #[test] + fn test_all_lowercase() { + assert_eq!(to_snake_case("test"), "test"); + } + + #[test] + fn test_mixed_case() { + assert_eq!(to_snake_case("testCase"), "test_case"); + } + + #[test] + fn test_mixed_case_with_numbers() { + assert_eq!(to_snake_case("testCase1"), "test_case1"); + assert_eq!(to_snake_case("Test123Case"), "test123_case"); + } + + #[test] + fn test_numbers_with_hyphen() { + assert_eq!(to_snake_case("test-3"), "test_3"); + } + + #[test] + fn test_string_with_spaces() { + assert_eq!(to_snake_case("This is a Test"), "this_is_a_test"); + } + + #[test] + fn test_snake_case_input() { + assert_eq!(to_snake_case("already_snake_case"), "already_snake_case"); + } + + #[test] + fn test_kebab_case_input() { + assert_eq!(to_snake_case("already-kebab-case"), "already_kebab_case"); + } + + #[test] + fn test_mixed_delimiters() { + assert_eq!(to_snake_case("test-Case_with Spaces"), "test_case_with_spaces"); + } + + #[test] + fn test_leading_and_trailing_spaces() { + assert_eq!(to_snake_case(" test case "), "test_case"); + } +} diff --git a/backend/src/main.rs b/backend/src/main.rs index ebc7f6dc3b..608e1870ec 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -7,8 +7,8 @@ */ use anyhow::Context; -use gethostname::gethostname; use git_version::git_version; +use monitor::{send_current_log_file_to_object_store, send_logs_to_object_store}; use rand::Rng; use sqlx::{postgres::PgListener, Pool, Postgres}; use std::{ @@ -20,6 +20,7 @@ use tokio::{ fs::{create_dir_all, DirBuilder, File}, io::AsyncReadExt, }; +use uuid::Uuid; use windmill_api::HTTP_CLIENT; #[cfg(feature = "enterprise")] @@ -36,9 +37,10 @@ use windmill_common::{ REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING, SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, }, + scripts::ScriptLang, stats_ee::schedule_stats, - utils::{rd_string, Mode}, - worker::{reload_custom_tags_setting, WORKER_GROUP}, + utils::{hostname, rd_string, Mode}, + worker::{reload_custom_tags_setting, HUB_CACHE_DIR, TMP_DIR, WORKER_GROUP}, DB, METRICS_ENABLED, }; @@ -61,8 +63,8 @@ use windmill_common::global_settings::OBJECT_STORE_CACHE_CONFIG_SETTING; use windmill_worker::{ get_hub_script_content_and_requirements, BUN_BUNDLE_CACHE_DIR, BUN_CACHE_DIR, BUN_DEPSTAR_CACHE_DIR, DENO_CACHE_DIR, DENO_CACHE_DIR_DEPS, DENO_CACHE_DIR_NPM, - GO_BIN_CACHE_DIR, GO_CACHE_DIR, HUB_CACHE_DIR, LOCK_CACHE_DIR, PIP_CACHE_DIR, - POWERSHELL_CACHE_DIR, TAR_PIP_CACHE_DIR, TMP_LOGS_DIR, + GO_BIN_CACHE_DIR, GO_CACHE_DIR, LOCK_CACHE_DIR, PIP_CACHE_DIR, POWERSHELL_CACHE_DIR, + RUST_CACHE_DIR, TAR_PIP_CACHE_DIR, TMP_LOGS_DIR, }; use crate::monitor::{ @@ -134,7 +136,52 @@ async fn cache_hub_scripts(file_path: Option) -> anyhow::Result<()> { create_dir_all(HUB_CACHE_DIR).await?; for path in paths.values() { - get_hub_script_content_and_requirements(Some(path.to_string()), None).await?; + tracing::info!("Caching hub script at {path}"); + let res = get_hub_script_content_and_requirements(Some(path.to_string()), None).await?; + if res + .language + .as_ref() + .is_some_and(|x| x == &ScriptLang::Deno) + { + let job_dir = format!("{}/cache_init/{}", TMP_DIR, Uuid::new_v4()); + create_dir_all(&job_dir).await?; + let _ = windmill_worker::generate_deno_lock( + &Uuid::nil(), + &res.content, + &mut 0, + &mut None, + &job_dir, + None, + "global", + "global", + "", + ) + .await?; + tokio::fs::remove_dir_all(job_dir).await?; + } else if res.language.as_ref().is_some_and(|x| x == &ScriptLang::Bun) { + let job_id = Uuid::new_v4(); + let job_dir = format!("{}/cache_init/{}", TMP_DIR, job_id); + create_dir_all(&job_dir).await?; + if let Some(lockfile) = res.lockfile { + let _ = windmill_worker::prepare_job_dir(&lockfile, &job_dir).await?; + + let _ = windmill_worker::install_bun_lockfile( + &mut 0, + &mut None, + &job_id, + "admins", + None, + &job_dir, + "cache_init", + windmill_worker::get_common_bun_proc_envs("").await, + false, + ) + .await?; + } else { + tracing::warn!("No lockfile found for bun script {path}, skipping..."); + } + tokio::fs::remove_dir_all(job_dir).await?; + } } Ok(()) } @@ -146,8 +193,10 @@ async fn windmill_main() -> anyhow::Result<()> { std::env::set_var("RUST_LOG", "info") } + let hostname = hostname(); + #[cfg(not(feature = "flamegraph"))] - windmill_common::tracing_init::initialize_tracing(); + let _guard = windmill_common::tracing_init::initialize_tracing(&hostname); #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] tracing::info!("jemalloc enabled"); @@ -322,6 +371,7 @@ async fn windmill_main() -> anyhow::Result<()> { // migration code to avoid break windmill_api::migrate_db(&db).await?; } + let (killpill_tx, mut killpill_rx) = tokio::sync::broadcast::channel::<()>(2); let mut monitor_killpill_rx = killpill_tx.subscribe(); let server_killpill_rx = killpill_tx.subscribe(); @@ -378,6 +428,8 @@ Windmill Community Edition {GIT_VERSION} monitor_pool(&db).await; + send_logs_to_object_store(&db, &hostname, &mode); + #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] if !worker_mode { monitor_mem().await; @@ -463,6 +515,7 @@ Windmill Community Edition {GIT_VERSION} base_internal_url.clone(), rsmq.clone(), mode.clone() == Mode::Agent, + hostname.clone(), ) .await?; tracing::info!("All workers exited."); @@ -487,6 +540,11 @@ Windmill Community Edition {GIT_VERSION} loop { tokio::select! { + biased; + _ = monitor_killpill_rx.recv() => { + tracing::info!("received killpill for monitor job"); + break; + }, _ = tokio::time::sleep(Duration::from_secs(30)) => { monitor_db( &db, @@ -641,22 +699,28 @@ Windmill Community Edition {GIT_VERSION} }, Err(e) => { tracing::error!(error = %e, "Could not receive notification, attempting to reconnect listener"); - listener = retry_listen_pg(&db).await; - continue; + tokio::select! { + biased; + _ = monitor_killpill_rx.recv() => { + tracing::info!("received killpill for monitor job"); + break; + }, + new_listener = retry_listen_pg(&db) => { + listener = new_listener; + continue; + } + } } }; - }, - _ = monitor_killpill_rx.recv() => { - println!("received killpill for monitor job"); - break; } } } }); if let Err(e) = h.await { - tracing::error!("Error waiting for monitor handle:{e:#}") + tracing::error!("Error waiting for monitor handle: {e:#}") } + tracing::info!("Monitor exited"); Ok(()) as anyhow::Result<()> }; @@ -693,6 +757,8 @@ Windmill Community Edition {GIT_VERSION} } else { tracing::info!("Nothing to do, exiting."); } + send_current_log_file_to_object_store(&db, &hostname, &mode).await; + tracing::info!("Exiting connection pool"); tokio::select! { _ = db.close() => { @@ -764,6 +830,7 @@ pub async fn run_workers, agent_mode: bool, + hostname: String, ) -> anyhow::Result<()> { let mut killpill_rxs = vec![]; for _ in 0..num_workers { @@ -774,10 +841,6 @@ pub async fn run_workers (Option, Option) { + let log_dir = format!("{}/{}/", TMP_WINDMILL_LOGS_SERVICE, hostname); + let rd_dir = tokio::fs::read_dir(log_dir).await; + if let Ok(mut log_files) = rd_dir { + let mut highest_file: Option = None; + let mut second_highest_file: Option = None; + while let Ok(Some(file)) = log_files.next_entry().await { + let file_name = file + .file_name() + .to_str() + .map(|x| x.to_string()) + .unwrap_or_default(); + if file_name > highest_file.clone().unwrap_or_default() { + second_highest_file = highest_file; + highest_file = Some(file_name); + } + } + (highest_file, second_highest_file) + } else { + tracing::error!( + "Error reading log files: {TMP_WINDMILL_LOGS_SERVICE}, {:#?}", + rd_dir.unwrap_err() + ); + (None, None) + } +} + +fn get_worker_group(mode: &Mode) -> Option { + let worker_group = WORKER_GROUP.clone(); + if worker_group.is_empty() || mode == &Mode::Server || mode == &Mode::Indexer { + None + } else { + Some(worker_group) + } +} + +pub fn send_logs_to_object_store(db: &DB, hostname: &str, mode: &Mode) { + let db = db.clone(); + let hostname = hostname.to_string(); + let mode = mode.clone(); + let worker_group = get_worker_group(&mode); + tokio::spawn(async move { + let mut interval = tokio::time::interval(Duration::from_secs(10)); + interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + sleep_until_next_minute_start_plus_one_s().await; + loop { + interval.tick().await; + let (_, snd_highest_file) = find_two_highest_files(&hostname).await; + send_log_file_to_object_store( + &hostname, + &mode, + &worker_group, + &db, + snd_highest_file, + false, + ) + .await; + } + }); +} + +pub async fn send_current_log_file_to_object_store(db: &DB, hostname: &str, mode: &Mode) { + tracing::info!("Sending current log file to object store"); + let (highest_file, _) = find_two_highest_files(hostname).await; + let worker_group = get_worker_group(&mode); + send_log_file_to_object_store(hostname, mode, &worker_group, db, highest_file, true).await; +} + +fn get_now_and_str() -> (NaiveDateTime, String) { + let ts = Utc::now().naive_utc(); + ( + ts, + ts.format(windmill_common::tracing_init::LOG_TIMESTAMP_FMT) + .to_string(), + ) +} + +async fn send_log_file_to_object_store( + hostname: &str, + mode: &Mode, + worker_group: &Option, + db: &Pool, + snd_highest_file: Option, + use_now: bool, +) { + if let Some(highest_file) = snd_highest_file { + //parse datetime frome file xxxx.yyyy-MM-dd-HH-mm + let (ts, ts_str) = if use_now { + get_now_and_str() + } else { + highest_file + .split(".") + .last() + .and_then(|x| { + NaiveDateTime::parse_from_str( + x, + windmill_common::tracing_init::LOG_TIMESTAMP_FMT, + ) + .ok() + .map(|y| (y, x.to_string())) + }) + .unwrap_or_else(get_now_and_str) + }; + + let exists = sqlx::query_scalar!( + "SELECT EXISTS(SELECT 1 FROM log_file WHERE hostname = $1 AND log_ts = $2)", + hostname, + ts + ) + .fetch_one(db) + .await; + + match exists { + Ok(Some(true)) => { + return; + } + Err(e) => { + tracing::error!("Error checking if log file exists: {:?}", e); + return; + } + _ => (), + } + + #[cfg(feature = "parquet")] + let s3_client = OBJECT_STORE_CACHE_SETTINGS.read().await.clone(); + #[cfg(feature = "parquet")] + if let Some(s3_client) = s3_client { + let path = std::path::Path::new(TMP_WINDMILL_LOGS_SERVICE) + .join(hostname) + .join(&highest_file); + + //read file as byte stream + let bytes = tokio::fs::read(&path).await; + if let Err(e) = bytes { + tracing::error!("Error reading log file: {:?}", e); + return; + } + let path = object_store::path::Path::from_url_path(format!( + "{}{hostname}/{highest_file}", + windmill_common::tracing_init::LOGS_SERVICE + )); + if let Err(e) = path { + tracing::error!("Error creating log file path: {:?}", e); + return; + } + if let Err(e) = s3_client.put(&path.unwrap(), bytes.unwrap().into()).await { + tracing::error!("Error sending logs to object store: {:?}", e); + } + } + + let (ok_lines, err_lines) = read_log_counters(ts_str); + + if let Err(e) = sqlx::query!("INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines, json_fmt) VALUES ($1, $2::text::LOG_MODE, $3, $4, $5, $6, $7, $8)", + hostname, mode.to_string(), worker_group.clone(), ts, highest_file, ok_lines as i64, err_lines as i64, *JSON_FMT) + .execute(db) + .await { + tracing::error!("Error inserting log file: {:?}", e); + } + } +} + +fn read_log_counters(ts_str: String) -> (usize, usize) { + let counters = windmill_common::tracing_init::LOG_COUNTING_BY_MIN.read(); + let mut ok_lines = 0; + let mut err_lines = 0; + if let Ok(ref c) = counters { + let counter = c.get(&ts_str); + if let Some(counter) = counter { + ok_lines = counter.non_error_count; + err_lines = counter.error_count; + } else { + println!("no counter found for {ts_str}"); + } + } else { + println!("Error reading log counters 2"); + } + (ok_lines, err_lines) +} + pub async fn load_keep_job_dir(db: &DB) { let value = load_value_from_global_settings(db, KEEP_JOB_DIR_SETTING).await; match value { @@ -468,6 +665,15 @@ pub async fn delete_expired_items(db: &DB) -> () { { tracing::error!("Error deleting custom concurrency key: {:?}", e); } + if let Err(e) = sqlx::query!( + "DELETE FROM log_file WHERE log_ts <= now() - ($1::bigint::text || ' s')::interval ", + job_retention_secs + ) + .execute(&mut *tx) + .await + { + tracing::error!("Error deleting log file: {:?}", e); + } } } Err(e) => { @@ -599,7 +805,9 @@ pub async fn reload_s3_cache_setting(db: &DB) { secret_key: None, endpoint: None, store_logs: None, + path_style: None, allow_http: None, + port: None, }) .await .ok(); @@ -835,11 +1043,19 @@ pub async fn monitor_db( } }; + let worker_groups_alerts_f = async { + #[cfg(feature = "enterprise")] + if server_mode && !initial_load { + worker_groups_alerts(&db).await; + } + }; + join!( expired_items_f, zombie_jobs_f, expose_queue_metrics_f, - verify_license_key_f + verify_license_key_f, + worker_groups_alerts_f ); } @@ -1037,7 +1253,7 @@ async fn handle_zombie_jobs ) { if *RESTART_ZOMBIE_JOBS { let restarted = sqlx::query!( - "UPDATE queue SET running = false, started_at = null, logs = logs || '\nRestarted job after not receiving job''s ping for too long the ' || now() || '\n\n' + "UPDATE queue SET running = false, started_at = null WHERE last_ping < now() - ($1 || ' seconds')::interval AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'singlescriptflow') AND same_worker = false RETURNING id, workspace_id, last_ping", *ZOMBIE_JOB_TIMEOUT, @@ -1050,13 +1266,25 @@ async fn handle_zombie_jobs if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) { QUEUE_ZOMBIE_RESTART_COUNT.inc_by(restarted.len() as _); } + let base_url = BASE_URL.read().await.clone(); for r in restarted { - tracing::error!( - "Zombie job detected, restarting it: {} {} {:?}", - r.id, - r.workspace_id, - r.last_ping + let last_ping = if let Some(x) = r.last_ping { + format!("last ping at {x}") + } else { + "no last ping".to_string() + }; + let url = format!("{}/run/{}?workspace={}", base_url, r.id, r.workspace_id,); + let error_message = format!( + "Zombie job {} on {} ({}) detected, restarting it, {}", + r.id, r.workspace_id, url, last_ping ); + + let _ = sqlx::query!(" + INSERT INTO job_logs (job_id, logs) VALUES ($1,'Restarted job after not receiving job''s ping for too long the ' || now() || '\n\n') + ON CONFLICT (job_id) DO UPDATE SET logs = job_logs.logs || '\nRestarted job after not receiving job''s ping for too long the ' || now() || '\n\n' WHERE job_logs.job_id = $1", r.id) + .execute(db).await; + tracing::error!(error_message); + report_critical_error(error_message, db.clone()).await; } } @@ -1084,6 +1312,8 @@ async fn handle_zombie_jobs // since the job is unrecoverable, the same worker queue should never be sent anything let (same_worker_tx_never_used, _same_worker_rx_never_used) = mpsc::channel::(1); + let same_worker_tx_never_used = + SameWorkerSender(same_worker_tx_never_used, Arc::new(AtomicU16::new(0))); let (send_result_never_used, _send_result_rx_never_used) = mpsc::channel::(1); let label = if job.permissioned_as != format!("u/{}", job.created_by) @@ -1154,16 +1384,19 @@ async fn handle_zombie_flows( for flow in flows { let status = flow.parse_flow_status(); - if status.is_some_and(|s| { - s.modules - .get(0) - .is_some_and(|x| matches!(x, FlowStatusModule::WaitingForPriorSteps { .. })) - }) { - tracing::error!( + if !flow.same_worker + && status.is_some_and(|s| { + s.modules + .get(0) + .is_some_and(|x| matches!(x, FlowStatusModule::WaitingForPriorSteps { .. })) + }) + { + let error_message = format!( "Zombie flow detected: {} in workspace {}. It hasn't started yet, restarting it.", - flow.id, - flow.workspace_id + flow.id, flow.workspace_id ); + tracing::error!(error_message); + report_critical_error(error_message, db.clone()).await; // if the flow hasn't started and is a zombie, we can simply restart it sqlx::query!( "UPDATE queue SET running = false, started_at = null WHERE id = $1 AND canceled = false", @@ -1183,6 +1416,7 @@ async fn handle_zombie_flows( format!("Flow {id} was cancelled because it") } ); + report_critical_error(reason.clone(), db.clone()).await; cancel_zombie_flow_job(db, flow, &rsmq, reason).await?; } } diff --git a/backend/tests/worker.rs b/backend/tests/worker.rs index 6e81aabbd3..ec4f4cd9f8 100644 --- a/backend/tests/worker.rs +++ b/backend/tests/worker.rs @@ -75,7 +75,9 @@ async fn initialize_tracing() { use std::sync::Once; static ONCE: Once = Once::new(); - ONCE.call_once(windmill_common::tracing_init::initialize_tracing); + ONCE.call_once(|| { + let _ = windmill_common::tracing_init::initialize_tracing("test"); + }); } /// it's important this is unique between tests as there is one prometheus registry and @@ -1741,6 +1743,41 @@ func main(derp string) (string, error) { assert_eq!(result, serde_json::json!("hello world")); } +#[sqlx::test(fixtures("base"))] +async fn test_rust_job(db: Pool) { + initialize_tracing().await; + let server = ApiServer::start(db.clone()).await; + let port = server.addr.port(); + + let content = r#" +fn main(world: String) -> Result { + println!("Which world to greet today?"); + Ok(format!("Hello {}!", world)) +} + "# + .to_owned(); + + let result = RunJob::from(JobPayload::Code(RawCode { + hash: None, + content, + path: None, + lock: None, + language: ScriptLang::Rust, + custom_concurrency_key: None, + concurrent_limit: None, + concurrency_time_window_s: None, + cache_ttl: None, + dedicated_worker: None, + })) + .arg("world", json!("Hyrule")) + .run_until_complete(&db, port) + .await + .json_result() + .unwrap(); + + assert_eq!(result, serde_json::json!("Hello Hyrule!")); +} + #[sqlx::test(fixtures("base"))] async fn test_bash_job(db: Pool) { initialize_tracing().await; @@ -2675,7 +2712,7 @@ async fn test_flow_lock_all(db: Pool) { in_test_worker(&db, listen_first_job, port).await; let modules = client - .get_flow_by_path("test-workspace", "g/all/flow_lock_all") + .get_flow_by_path("test-workspace", "g/all/flow_lock_all", None) .await .unwrap() .into_inner() @@ -2697,7 +2734,8 @@ async fn test_flow_lock_all(db: Pool) { language: windmill_api_client::types::RawScriptLanguage::Go | windmill_api_client::types::RawScriptLanguage::Python3 | windmill_api_client::types::RawScriptLanguage::Deno, lock: Some(ref lock), .. - }) if lock.len() > 0) + }) if lock.len() > 0), + "{:?}", m.value ); }); } @@ -2944,6 +2982,8 @@ async fn test_script_schedule_handlers(db: Pool) { on_recovery: Some("script/f/system/schedule_recovery_handler".to_string()), on_recovery_times: None, on_recovery_extra_args: None, + on_success: None, + on_success_extra_args: None, path: "f/system/failing_script_schedule".to_string(), script_path: "f/system/failing_script".to_string(), timezone: "UTC".to_string(), @@ -3011,6 +3051,8 @@ async fn test_script_schedule_handlers(db: Pool) { on_recovery: Some("script/f/system/schedule_recovery_handler".to_string()), on_recovery_times: None, on_recovery_extra_args: None, + on_success: None, + on_success_extra_args: None, timezone: "UTC".to_string(), schedule: format!("{} {} * * * *", then.second(), then.minute()).to_string(), ws_error_handler_muted: None, @@ -3089,6 +3131,8 @@ async fn test_flow_schedule_handlers(db: Pool) { on_recovery: Some("script/f/system/schedule_recovery_handler".to_string()), on_recovery_times: None, on_recovery_extra_args: None, + on_success: None, + on_success_extra_args: None, path: "f/system/failing_flow_schedule".to_string(), script_path: "f/system/failing_flow".to_string(), timezone: "UTC".to_string(), @@ -3157,6 +3201,8 @@ async fn test_flow_schedule_handlers(db: Pool) { on_recovery: Some("script/f/system/schedule_recovery_handler".to_string()), on_recovery_times: None, on_recovery_extra_args: None, + on_success: None, + on_success_extra_args: None, timezone: "UTC".to_string(), schedule: format!("{} {} * * * *", then.second(), then.minute()).to_string(), ws_error_handler_muted: None, diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index bbb0b02347..99e48ec00b 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.383.1 + version: 1.397.1 title: Windmill API contact: @@ -342,6 +342,8 @@ paths: properties: is_super_admin: type: boolean + name: + type: string responses: "200": description: user updated @@ -2585,6 +2587,36 @@ paths: schema: type: string + + /oauth/connect_slack_callback: + post: + summary: connect slack callback instance + operationId: connectSlackCallbackInstance + tags: + - oauth + requestBody: + description: code endpoint + required: true + content: + application/json: + schema: + type: object + properties: + code: + type: string + state: + type: string + required: + - code + - state + responses: + "200": + description: success message + content: + text/plain: + schema: + type: string + /oauth/connect_callback/{client_name}: post: summary: connect callback @@ -3056,6 +3088,22 @@ paths: schema: type: string + /w/{workspace}/resources/file_resource_type_to_file_ext_map: + get: + summary: get map from resource type to format extension + operationId: fileResourceTypeToFileExtMap + tags: + - resource + parameters: + - $ref: "#/components/parameters/WorkspaceId" + responses: + "200": + description: map from resource type to file ext + content: + application/json: + schema: {} + + /w/{workspace}/resources/type/delete/{path}: delete: summary: delete resource_type @@ -3924,6 +3972,10 @@ paths: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ScriptPath" + - name: with_starred_info + in: query + schema: + type: boolean responses: "200": description: script details @@ -4059,6 +4111,10 @@ paths: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ScriptHash" + - name: with_starred_info + in: query + schema: + type: boolean responses: "200": description: script details @@ -4515,6 +4571,10 @@ paths: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ScriptPath" + - name: with_starred_info + in: query + schema: + type: boolean responses: "200": description: flow details @@ -4693,26 +4753,6 @@ paths: schema: type: string - /w/{workspace}/flows/input_history/p/{path}: - get: - summary: list inputs for previous completed flow jobs - operationId: getFlowInputHistoryByPath - tags: - - flow - parameters: - - $ref: "#/components/parameters/WorkspaceId" - - $ref: "#/components/parameters/ScriptPath" - - $ref: "#/components/parameters/Page" - - $ref: "#/components/parameters/PerPage" - responses: - "200": - description: input history for completed jobs with this flow path - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/Input" /w/{workspace}/raw_apps/list: get: @@ -4932,6 +4972,10 @@ paths: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ScriptPath" + - name: with_starred_info + in: query + schema: + type: boolean responses: "200": description: app details @@ -5808,6 +5852,8 @@ paths: - $ref: "#/components/parameters/ScriptExactHash" - $ref: "#/components/parameters/StartedBefore" - $ref: "#/components/parameters/StartedAfter" + - $ref: "#/components/parameters/CreatedBefore" + - $ref: "#/components/parameters/CreatedAfter" - $ref: "#/components/parameters/CreatedOrStartedBefore" - $ref: "#/components/parameters/Running" - $ref: "#/components/parameters/ScheduledForBeforeNow" @@ -5963,6 +6009,10 @@ paths: in: query schema: type: integer + - name: get_progress + in: query + schema: + type: boolean responses: "200": @@ -5982,6 +6032,8 @@ paths: type: integer mem_peak: type: integer + progress: + type: integer flow_status: $ref: "#/components/schemas/WorkflowStatusRecord" @@ -6119,7 +6171,7 @@ paths: /w/{workspace}/jobs_u/queue/cancel/{id}: post: - summary: cancel queued job + summary: cancel queued or running job operationId: cancelQueuedJob tags: - job @@ -6750,7 +6802,7 @@ paths: properties: handler_type: type: string - enum: ["error", "recovery"] + enum: ["error", "recovery", "success"] override_existing: type: boolean path: @@ -8317,6 +8369,38 @@ paths: application/json: schema: {} + /w/{workspace}/job_helpers/load_table_count/{path}: + get: + summary: Load the table row count + operationId: loadTableRowCount + tags: + - helpers + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + - name: search_col + in: query + schema: + type: string + - name: search_term + in: query + schema: + type: string + - name: storage + in: query + schema: + type: string + responses: + "200": + description: Table count + content: + application/json: + schema: + type: object + properties: + count: + type: number + /w/{workspace}/job_helpers/load_csv_preview/{path}: get: summary: Load a preview of a csv file @@ -8585,6 +8669,116 @@ paths: items: $ref: "#/components/schemas/TimeseriesMetric" + /w/{workspace}/job_metrics/set_progress/{id}: + post: + summary: set job metrics + operationId: setJobProgress + tags: + - metrics + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/JobId" + requestBody: + description: parameters for statistics retrieval + required: true + content: + application/json: + schema: + type: object + properties: + percent: + type: integer + flow_job_id: + type: string + format: uuid + + responses: + "200": + description: Job progress updated + content: + application/json: + schema: {} + + /w/{workspace}/job_metrics/get_progress/{id}: + get: + summary: get job progress + operationId: getJobProgress + tags: + - metrics + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/JobId" + responses: + "200": + description: job progress between 0 and 99 + content: + application/json: + schema: + type: integer + /service_logs/list_files: + get: + summary: list log files ordered by timestamp + operationId: listLogFiles + tags: + - service_logs + parameters: + - $ref: "#/components/parameters/Before" + - $ref: "#/components/parameters/After" + - name: with_error + in: query + required: false + schema: + type: boolean + responses: + "200": + description: time + content: + application/json: + schema: + type: array + items: + type: object + properties: + hostname: + type: string + mode: + type: string + worker_group: + type: string + log_ts: + type: string + format: date-time + file_path: + type: string + ok_lines: + type: integer + err_lines: + type: integer + json_fmt: + type: boolean + required: + - hostname + - mode + - log_ts + - file_path + - json_fmt + + /service_logs/get_log_file/{path}: + get: + summary: get log file by path + operationId: getLogFile + tags: + - service_logs + parameters: + - $ref: "#/components/parameters/Path" + responses: + "200": + description: log stream + content: + text/plain: + schema: + type: string + /concurrency_groups/list: get: summary: List all concurrency groups @@ -8942,6 +9136,20 @@ components: in: query schema: type: string + CreatedBefore: + name: created_before + description: filter on created before (inclusive) timestamp + in: query + schema: + type: string + format: date-time + CreatedAfter: + name: created_after + description: filter on created after (exclusive) timestamp + in: query + schema: + type: string + format: date-time StartedBefore: name: started_before description: filter on started before (inclusive) timestamp @@ -8956,6 +9164,13 @@ components: schema: type: string format: date-time + Before: + name: before + description: filter on started before (inclusive) timestamp + in: query + schema: + type: string + format: date-time CreatedOrStartedAfter: name: created_or_started_after description: @@ -9032,13 +9247,6 @@ components: schema: type: string format: date-time - Before: - name: before - description: filter on created before (exclusive) timestamp - in: query - schema: - type: string - format: date-time Username: name: username description: filter on exact username of user @@ -9169,6 +9377,8 @@ components: nativets, bun, php, + rust, + ansible, ] kind: type: string @@ -9267,6 +9477,8 @@ components: nativets, bun, php, + rust, + ansible, ] kind: type: string @@ -9484,6 +9696,8 @@ components: nativets, bun, php, + rust, + ansible, ] email: type: string @@ -9599,6 +9813,8 @@ components: nativets, bun, php, + rust, + ansible, ] is_skipped: type: boolean @@ -10137,7 +10353,9 @@ components: graphql, nativets, bun, - php + php, + rust, + ansible, ] tag: type: string @@ -10285,6 +10503,8 @@ components: edited_at: type: string format: date-time + format_extension: + type: string required: - name @@ -10340,6 +10560,10 @@ components: type: number on_recovery_extra_args: $ref: "#/components/schemas/ScriptArgs" + on_success: + type: string + on_success_extra_args: + $ref: "#/components/schemas/ScriptArgs" ws_error_handler_muted: type: boolean retry: @@ -10418,6 +10642,10 @@ components: type: number on_recovery_extra_args: $ref: "#/components/schemas/ScriptArgs" + on_success: + type: string + on_success_extra_args: + $ref: "#/components/schemas/ScriptArgs" ws_error_handler_muted: type: boolean retry: @@ -10463,6 +10691,10 @@ components: type: number on_recovery_extra_args: $ref: "#/components/schemas/ScriptArgs" + on_success: + type: string + on_success_extra_args: + $ref: "#/components/schemas/ScriptArgs" ws_error_handler_muted: type: boolean retry: @@ -10564,9 +10796,9 @@ components: type: string wm_version: type: string - current_job_id: + last_job_id: type: string - current_job_workspace_id: + last_job_workspace_id: type: string occupancy_rate: type: number @@ -11267,7 +11499,9 @@ components: graphql, nativets, bun, - php + php, + rust, + ansible, ] required: - raw_code diff --git a/backend/windmill-api/src/apps.rs b/backend/windmill-api/src/apps.rs index 9bfb84e34f..7bed72c50e 100644 --- a/backend/windmill-api/src/apps.rs +++ b/backend/windmill-api/src/apps.rs @@ -11,6 +11,7 @@ use crate::{ db::{ApiAuthed, DB}, resources::get_resource_value_interpolated_internal, users::{require_owner_of_path, OptAuthed}, + utils::WithStarredInfoQuery, variables::encrypt, webhook_util::{WebhookMessage, WebhookShared}, HTTP_CLIENT, @@ -118,6 +119,15 @@ pub struct AppWithLastVersion { pub extra_perms: Option, } +#[derive(Serialize, FromRow)] +pub struct AppWithLastVersionAndStarred { + #[sqlx(flatten)] + #[serde(flatten)] + pub app: AppWithLastVersion, + #[serde(skip_serializing_if = "Option::is_none")] + pub starred: Option, +} + #[derive(Serialize, Deserialize, FromRow)] pub struct AppWithLastVersionAndDraft { pub id: i64, @@ -316,20 +326,44 @@ async fn get_app( authed: ApiAuthed, Extension(user_db): Extension, Path((w_id, path)): Path<(String, StripPath)>, -) -> JsonResult { + Query(query): Query, +) -> JsonResult { let path = path.to_path(); let mut tx = user_db.begin(&authed).await?; - let app_o = sqlx::query_as::<_, AppWithLastVersion>( - "SELECT app.id, app.path, app.summary, app.versions, app.policy, - app.extra_perms, app_version.value, - app_version.created_at, app_version.created_by from app, app_version - WHERE app.path = $1 AND app.workspace_id = $2 AND app_version.id = app.versions[array_upper(app.versions, 1)]", - ) - .bind(path.to_owned()) - .bind(&w_id) - .fetch_optional(&mut *tx) - .await?; + let app_o = if query.with_starred_info.unwrap_or(false) { + sqlx::query_as::<_, AppWithLastVersionAndStarred>( + "SELECT app.id, app.path, app.summary, app.versions, app.policy, + app.extra_perms, app_version.value, + app_version.created_at, app_version.created_by, favorite.path IS NOT NULL as starred + FROM app + JOIN app_version + ON app_version.id = app.versions[array_upper(app.versions, 1)] + LEFT JOIN favorite + ON favorite.favorite_kind = 'app' + AND favorite.workspace_id = app.workspace_id + AND favorite.path = app.path + AND favorite.usr = $3 + WHERE app.path = $1 AND app.workspace_id = $2", + ) + .bind(path.to_owned()) + .bind(&w_id) + .bind(&authed.username) + .fetch_optional(&mut *tx) + .await? + } else { + sqlx::query_as::<_, AppWithLastVersionAndStarred>( + "SELECT app.id, app.path, app.summary, app.versions, app.policy, + app.extra_perms, app_version.value, + app_version.created_at, app_version.created_by, NULL as starred + FROM app, app_version + WHERE app.path = $1 AND app.workspace_id = $2 AND app_version.id = app.versions[array_upper(app.versions, 1)]", + ) + .bind(path.to_owned()) + .bind(&w_id) + .fetch_optional(&mut *tx) + .await? + }; tx.commit().await?; let app = not_found_if_none(app_o, "App", path)?; @@ -575,7 +609,7 @@ async fn create_app( } let exists = sqlx::query_scalar!( - "SELECT EXISTS(SELECT 1 FROM raw_app WHERE path = $1 AND workspace_id = $2)", + "SELECT EXISTS(SELECT 1 FROM app WHERE path = $1 AND workspace_id = $2)", &app.path, w_id ) diff --git a/backend/windmill-api/src/db.rs b/backend/windmill-api/src/db.rs index e2cc2cfa71..470a21bccc 100644 --- a/backend/windmill-api/src/db.rs +++ b/backend/windmill-api/src/db.rs @@ -136,15 +136,6 @@ impl Migrate for CustomMigrator { migration.version, migration.description ); - if migration.version == 20240424083501 { - tracing::info!("Special migration to add index concurrently on job labels 2"); - sqlx::query!( - "DROP INDEX CONCURRENTLY IF EXISTS labeled_jobs_on_jobs" - ).execute(&mut *self.inner).await?; - sqlx::query!( - "CREATE INDEX CONCURRENTLY labeled_jobs_on_jobs ON completed_job USING GIN ((result -> 'wm_labels')) WHERE result ? 'wm_label';" - ).execute(&mut *self.inner).await?; - } let r = self.inner.apply(migration).await; tracing::info!("Finished applying migration {}", migration.version); r @@ -309,9 +300,6 @@ macro_rules! run_windmill_migration { .await?; tx.commit().await?; tracing::info!("released lock for {migration_job_name}"); - - - tracing::info!("Finished applying {migration_job_name} migration"); } else { tracing::info!("migration {migration_job_name} already done"); @@ -481,6 +469,16 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> { .await?; }); + run_windmill_migration!("fix_labeled_jobs_index", &db, { + tracing::info!("Special migration to add index concurrently on job labels 2"); + sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS labeled_jobs_on_jobs") + .execute(db) + .await?; + sqlx::query!( + "CREATE INDEX CONCURRENTLY labeled_jobs_on_jobs ON completed_job USING GIN ((result -> 'wm_labels')) WHERE result ? 'wm_labels'" + ).execute(db).await?; + }); + Ok(()) } diff --git a/backend/windmill-api/src/flows.rs b/backend/windmill-api/src/flows.rs index 0dbe994040..2fedf3709c 100644 --- a/backend/windmill-api/src/flows.rs +++ b/backend/windmill-api/src/flows.rs @@ -9,6 +9,7 @@ use std::collections::HashMap; use crate::db::ApiAuthed; +use crate::utils::WithStarredInfoQuery; use crate::{ db::DB, schedule::clear_schedule, @@ -35,7 +36,7 @@ use windmill_common::HUB_BASE_URL; use windmill_common::{ db::UserDB, error::{self, to_anyhow, Error, JsonResult, Result}, - flows::{Flow, ListFlowQuery, ListableFlow, NewFlow}, + flows::{Flow, FlowWithStarred, ListFlowQuery, ListableFlow, NewFlow}, jobs::JobPayload, schedule::Schedule, scripts::Schema, @@ -876,13 +877,31 @@ async fn get_flow_by_path( authed: ApiAuthed, Extension(user_db): Extension, Path((w_id, path)): Path<(String, StripPath)>, -) -> JsonResult { + Query(query): Query, +) -> JsonResult { let path = path.to_path(); let mut tx = user_db.begin(&authed).await?; - let flow_o = - sqlx::query_as::<_, Flow>( - "SELECT flow.workspace_id, flow.path, flow.summary, flow.description, flow.archived, flow.extra_perms, flow.draft_only, flow.dedicated_worker, flow.tag, flow.ws_error_handler_muted, flow.timeout, flow.visible_to_runner_only, flow_version.schema, flow_version.value, flow_version.created_at as edited_at, flow_version.created_by as edited_by + let flow_o = if query.with_starred_info.unwrap_or(false) { + sqlx::query_as::<_, FlowWithStarred>( + "SELECT flow.workspace_id, flow.path, flow.summary, flow.description, flow.archived, flow.extra_perms, flow.draft_only, flow.dedicated_worker, flow.tag, flow.ws_error_handler_muted, flow.timeout, flow.visible_to_runner_only, flow_version.schema, flow_version.value, flow_version.created_at as edited_at, flow_version.created_by as edited_by, favorite.path IS NOT NULL as starred + FROM flow + LEFT JOIN favorite + ON favorite.favorite_kind = 'flow' + AND favorite.workspace_id = flow.workspace_id + AND favorite.path = flow.path + AND favorite.usr = $3 + LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] + WHERE flow.path = $1 AND flow.workspace_id = $2" + ) + .bind(path) + .bind(w_id) + .bind(&authed.username) + .fetch_optional(&mut *tx) + .await? + } else { + sqlx::query_as::<_, FlowWithStarred>( + "SELECT flow.workspace_id, flow.path, flow.summary, flow.description, flow.archived, flow.extra_perms, flow.draft_only, flow.dedicated_worker, flow.tag, flow.ws_error_handler_muted, flow.timeout, flow.visible_to_runner_only, flow_version.schema, flow_version.value, flow_version.created_at as edited_at, flow_version.created_by as edited_by, NULL as starred FROM flow LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] WHERE flow.path = $1 AND flow.workspace_id = $2" @@ -890,7 +909,8 @@ async fn get_flow_by_path( .bind(path) .bind(w_id) .fetch_optional(&mut *tx) - .await?; + .await? + }; tx.commit().await?; let flow = not_found_if_none(flow_o, "Flow", path)?; diff --git a/backend/windmill-api/src/granular_acls.rs b/backend/windmill-api/src/granular_acls.rs index f7c984d0e7..fb6d2e26f5 100644 --- a/backend/windmill-api/src/granular_acls.rs +++ b/backend/windmill-api/src/granular_acls.rs @@ -23,6 +23,10 @@ use windmill_common::{ utils::{not_found_if_none, StripPath}, }; +const KINDS: [&str; 9] = [ + "script", "group_", "resource", "schedule", "variable", "flow", "folder", "app", "raw_app", +]; + pub fn workspaced_service() -> Router { Router::new() .route("/get/*path", get(get_granular_acls)) @@ -49,6 +53,11 @@ async fn add_granular_acl( let (kind, path) = path .split_once('/') .ok_or_else(|| Error::BadRequest("Invalid path or kind".to_string()))?; + + if !KINDS.contains(&kind) { + return Err(Error::BadRequest("Invalid kind".to_string())); + } + let mut tx = user_db.begin(&authed).await?; let identifier = if kind == "group_" || kind == "folder" { @@ -69,9 +78,10 @@ async fn add_granular_acl( } let obj_o = sqlx::query_scalar::<_, serde_json::Value>(&format!( - "UPDATE {kind} SET extra_perms = jsonb_set(extra_perms, '{{\"{owner}\"}}', to_jsonb($1), \ - true) WHERE {identifier} = $2 AND workspace_id = $3 RETURNING extra_perms" + "UPDATE {kind} SET extra_perms = jsonb_set(extra_perms, $1, to_jsonb($2), \ + true) WHERE {identifier} = $3 AND workspace_id = $4 RETURNING extra_perms" )) + .bind(vec![owner]) .bind(write.unwrap_or(false)) .bind(path) .bind(&w_id) @@ -158,6 +168,10 @@ async fn remove_granular_acl( .split_once('/') .ok_or_else(|| Error::BadRequest("Invalid path or kind".to_string()))?; + if !KINDS.contains(&kind) { + return Err(Error::BadRequest("Invalid kind".to_string())); + } + if !authed.is_admin { if kind == "folder" { crate::folders::require_is_owner(&authed, path)?; @@ -267,6 +281,10 @@ async fn get_granular_acls( .split_once('/') .ok_or_else(|| Error::BadRequest("Invalid path or kind".to_string()))?; + if !KINDS.contains(&kind) { + return Err(Error::BadRequest("Invalid kind".to_string())); + } + let mut tx = user_db.begin(&authed).await?; let identifier = if kind == "group_" { "name" } else { "path" }; diff --git a/backend/windmill-api/src/job_metrics.rs b/backend/windmill-api/src/job_metrics.rs index 4a57ed28d4..2af59383a8 100644 --- a/backend/windmill-api/src/job_metrics.rs +++ b/backend/windmill-api/src/job_metrics.rs @@ -1,12 +1,18 @@ use crate::db::DB; -use axum::{extract::Path, routing::post, Extension, Json, Router}; +use axum::{ + extract::Path, + routing::{get, post}, + Extension, Json, Router, +}; use serde::{Deserialize, Serialize}; use tower_http::cors::{Any, CorsLayer}; use uuid::Uuid; use windmill_common::{ - error, - job_metrics::{JobStatsRecord, MetricKind}, + error::{self, Error}, + job_metrics::{ + record_metric, register_metric_for_job, JobStatsRecord, MetricKind, MetricNumericValue, + }, }; pub fn workspaced_service() -> Router { @@ -15,7 +21,16 @@ pub fn workspaced_service() -> Router { .allow_headers([http::header::CONTENT_TYPE, http::header::AUTHORIZATION]) .allow_origin(Any); - Router::new().route("/get/:id", post(get_job_metrics).layer(cors.clone())) + Router::new() + .route("/get/:id", post(get_job_metrics).layer(cors.clone())) + .route( + "/set_progress/:id", + post(set_job_progress).layer(cors.clone()), + ) + .route( + "/get_progress/:id", + get(get_job_progress).layer(cors.clone()), + ) } #[derive(Deserialize)] @@ -137,6 +152,93 @@ async fn get_job_metrics( let response = JobStatsResponse { metrics_metadata, scalar_metrics, timeseries_metrics }; Ok(Json(response)) } +#[derive(Deserialize)] +struct JobProgressSetRequest { + percent: i32, + /// Optional parent flow id + /// Used to modify flow status + /// Specifically `progress` field in corresponding FlowStatusModule in `InProgress` state + flow_job_id: Option, +} + +async fn set_job_progress( + Extension(db): Extension, + Path((w_id, job_id)): Path<(String, Uuid)>, + Json(JobProgressSetRequest { percent, flow_job_id }): Json, +) -> error::JsonResult<()> { + // If flow_job_id exists, than we should modify flow_status of corresponding module + // Individual jobs and flows are handled differently + if let Some(flow_job_id) = flow_job_id { + // TODO: Return error if trying to set completed job? + sqlx::query!( + "UPDATE queue + SET flow_status = JSONB_SET(flow_status, ARRAY['modules', flow_status->>'step', 'progress'], $1) + WHERE id = $2", + serde_json::json!(percent.clamp(0, 99)), + flow_job_id + ) + .execute(&db) + .await?; + } + + let record_progress = || { + record_metric( + &db, + w_id.clone(), + job_id, + "progress_perc".to_owned(), + MetricNumericValue::Integer(percent), + ) + }; + + // Try to record + if let Err(err) = record_progress().await { + if matches!(err, Error::MetricNotFound(..)) { + // Register + // TODO: Reset progress after job is finished (in case it reruns same job)? + _ = register_metric_for_job( + &db, + w_id.clone(), + job_id, + "progress_perc".to_string(), + MetricKind::ScalarInt, + Some("Job Execution Progress (%)".to_owned()), + ) + .await?; + // Retry recording progress + record_progress().await.map_err(|err| { + // If for some reason it still returns same error, this error will be converted to BadRequest and returned + if let Error::MetricNotFound(body) = err { + Error::BadRequest(body) + } else { + err + } + })?; + } else { + return Err(err); + } + }; + return Ok(Json(())); +} + +async fn get_job_progress( + Extension(db): Extension, + Path((w_id, job_id)): Path<(String, Uuid)>, +) -> error::JsonResult> { + let progress: Option> = sqlx::query_scalar!( + "SELECT (scalar_int)::int FROM job_stats WHERE job_id = $1 AND workspace_id = $2 AND metric_id = 'progress_perc'", + job_id, w_id) + .fetch_optional(&db) + .await?; + + let respond_value = if let Some(Some(progress)) = progress { + Some(progress.clamp(0, 99)) + } else { + None + }; + + Ok(Json(respond_value)) +} fn timeseries_sample( from: Option>, diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index 43db962e6a..cec301ad05 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -33,6 +33,7 @@ use crate::add_webhook_allowed_origin; use crate::concurrency_groups::join_concurrency_key; use crate::db::ApiAuthed; +use crate::utils::content_plain; use crate::{ db::DB, users::{check_scopes, require_owner_of_path, OptAuthed}, @@ -791,6 +792,11 @@ async fn get_logs_from_store( let logs = logs.to_string(); let stream = async_stream::stream! { + yield Ok(bytes::Bytes::from( + r#"to remove ansi colors, use: | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g' + "# + .to_string(), + )); for file_p in file_index.clone() { let file_p_2 = file_p.clone(); let file = os.get(&object_store::path::Path::from(file_p)).await; @@ -832,6 +838,10 @@ async fn get_logs_from_disk( let logs = logs.to_string(); let stream = async_stream::stream! { + yield Ok(bytes::Bytes::from( + r#"to remove ansi colors, use: | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g' + "#.to_string(), + )); for file_p in file_index.clone() { let mut file = tokio::fs::File::open(format!("{TMP_DIR}/{file_p}")).await.map_err(to_anyhow)?; let mut buffer = Vec::new(); @@ -847,14 +857,6 @@ async fn get_logs_from_disk( return None; } -fn content_plain(body: Body) -> Response { - use axum::http::header; - Response::builder() - .header(header::CONTENT_TYPE, "text/plain") - .body(body) - .unwrap() -} - async fn get_job_logs( OptAuthed(opt_authed): OptAuthed, Extension(db): Extension, @@ -899,6 +901,10 @@ async fn get_job_logs( { return r.map(content_plain); } + let logs = format!( + "to remove ansi colors, use: | sed 's/\\x1B\\[[0-9;]\\{{1,\\}}[A-Za-z]//g'\n{}", + logs + ); Ok(content_plain(Body::from(logs))) } else { let text = sqlx::query!( @@ -929,6 +935,11 @@ async fn get_job_logs( if let Some(r) = get_logs_from_disk(text.log_offset, &logs, &text.log_file_index).await { return r.map(content_plain); } + + let logs = format!( + "to remove ansi colors, use: | sed 's/\\x1B\\[[0-9;]\\{{1,\\}}[A-Za-z]//g'\n{}", + logs + ); Ok(content_plain(Body::from(logs))) } } @@ -1036,17 +1047,17 @@ pub struct ListableCompletedJob { #[derive(Deserialize, Clone, Default)] pub struct RunJobQuery { - scheduled_for: Option>, - scheduled_in_secs: Option, - parent_job: Option, - root_job: Option, - invisible_to_owner: Option, - queue_limit: Option, - payload: Option, - job_id: Option, - tag: Option, - timeout: Option, - cache_ttl: Option, + pub scheduled_for: Option>, + pub scheduled_in_secs: Option, + pub parent_job: Option, + pub root_job: Option, + pub invisible_to_owner: Option, + pub queue_limit: Option, + pub payload: Option, + pub job_id: Option, + pub tag: Option, + pub timeout: Option, + pub cache_ttl: Option, } impl RunJobQuery { @@ -1168,16 +1179,10 @@ pub fn filter_list_queue_query( sqlb.and_where_eq("parent_job", "?".bind(pj)); } if let Some(dt) = &lq.started_before { - sqlb.and_where_le( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_le("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.started_after { - sqlb.and_where_ge( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(fs) = &lq.is_flow_step { sqlb.and_where_eq("is_flow_step", fs); @@ -1189,16 +1194,10 @@ pub fn filter_list_queue_query( } if let Some(dt) = &lq.created_before { - sqlb.and_where_le( - "created_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_le("created_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.created_after { - sqlb.and_where_ge( - "created_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_ge("created_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.created_or_started_after { @@ -1578,7 +1577,11 @@ async fn list_jobs( None }; - let sql = if lq.success.is_none() && lq.label.is_none() { + let sql = if lq.success.is_none() + && lq.label.is_none() + && lq.created_or_started_before.is_none() + && lq.started_before.is_none() + { let mut sqlq = list_queue_jobs_query( &w_id, &ListQueueQuery { order_desc: Some(true), ..lq.into() }, @@ -1598,6 +1601,11 @@ async fn list_jobs( sqlq.limit(per_page).offset(offset).query()? } } else { + if sqlc.is_none() { + return Err(error::Error::BadRequest( + "cannot specify success, label, created_or_started_before, or started_before with running".to_string(), + )); + } sqlc.unwrap().limit(per_page).offset(offset).query()? }; let mut tx = user_db.begin(&authed).await?; @@ -4499,6 +4507,7 @@ pub async fn run_job_by_hash_inner( pub struct JobUpdateQuery { pub running: bool, pub log_offset: i32, + pub get_progress: Option, } #[derive(Serialize)] @@ -4508,6 +4517,7 @@ pub struct JobUpdate { pub new_logs: Option, pub log_offset: Option, pub mem_peak: Option, + pub progress: Option, pub flow_status: Option>, } @@ -4575,7 +4585,7 @@ async fn get_job_update( OptAuthed(opt_authed): OptAuthed, Extension(db): Extension, Path((w_id, job_id)): Path<(String, Uuid)>, - Query(JobUpdateQuery { running, log_offset }): Query, + Query(JobUpdateQuery { running, log_offset, get_progress }): Query, ) -> error::JsonResult { let record = sqlx::query_as::<_, JobUpdateRow>( "SELECT running, substr(concat(coalesce(queue.logs, ''), job_logs.logs), greatest($1 - job_logs.log_offset, 0)) as logs, mem_peak, @@ -4591,6 +4601,20 @@ async fn get_job_update( .fetch_optional(&db) .await?; + let progress: Option = if get_progress == Some(true){ + sqlx::query_scalar!( + "SELECT scalar_int FROM job_stats WHERE workspace_id = $1 AND job_id = $2 AND metric_id = $3", + &w_id, + job_id, + "progress_perc" + + ) + .fetch_one(&db) + .await? + } else { + None + }; + if let Some(record) = record { if opt_authed.is_none() && record.created_by != "anonymous" { return Err(Error::BadRequest( @@ -4608,6 +4632,7 @@ async fn get_job_update( completed: None, new_logs: record.logs, mem_peak: record.mem_peak, + progress, flow_status: record .flow_status .map(|x: sqlx::types::Json>| x.0), @@ -4640,6 +4665,7 @@ async fn get_job_update( log_offset: record.log_offset, new_logs: record.logs, mem_peak: record.mem_peak, + progress, flow_status: record .flow_status .map(|x: sqlx::types::Json>| x.0), @@ -4662,6 +4688,13 @@ pub fn filter_list_completed_query( .on_eq("id", "outstanding_wait_time.job_id"); } + if let Some(label) = &lq.label { + let mut wh = format!("result->'wm_labels' ? "); + wh.push_str(&format!("'{}'", &label.replace("'", "''"))); + sqlb.and_where("result ? 'wm_labels'"); + sqlb.and_where(&wh); + } + if w_id != "admins" || !lq.all_workspaces.is_some_and(|x| x) { sqlb.and_where_eq("workspace_id", "?".bind(&w_id)); } @@ -4692,36 +4725,28 @@ pub fn filter_list_completed_query( sqlb.and_where_eq("parent_job", "?".bind(pj)); } if let Some(dt) = &lq.started_before { - sqlb.and_where_le( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_le("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.started_after { - sqlb.and_where_ge( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.created_or_started_before { - sqlb.and_where_le( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_le("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.created_or_started_after { - sqlb.and_where_ge( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339())); + } + + if let Some(dt) = &lq.created_before { + sqlb.and_where_le("created_at", "?".bind(&dt.to_rfc3339())); + } + if let Some(dt) = &lq.created_after { + sqlb.and_where_ge("created_at", "?".bind(&dt.to_rfc3339())); } if let Some(dt) = &lq.created_or_started_after_completed_jobs { - sqlb.and_where_ge( - "started_at", - format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()), - ); + sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339())); } if let Some(sk) = &lq.is_skipped { @@ -4750,13 +4775,6 @@ pub fn filter_list_completed_query( sqlb.and_where("result @> ?".bind(&result.replace("'", "''"))); } - if let Some(label) = &lq.label { - let mut wh = format!("result->'wm_labels' ? "); - wh.push_str(&format!("'{}'", &label.replace("'", "''"))); - sqlb.and_where(&wh); - sqlb.and_where("result ? 'wm_labels'"); - } - if lq.is_not_schedule.unwrap_or(false) { sqlb.and_where("schedule_path IS null"); } diff --git a/backend/windmill-api/src/lib.rs b/backend/windmill-api/src/lib.rs index ed842aeb42..4a37ad8f3e 100644 --- a/backend/windmill-api/src/lib.rs +++ b/backend/windmill-api/src/lib.rs @@ -76,6 +76,7 @@ mod saml_ee; mod schedule; mod scim_ee; mod scripts; +mod service_logs; mod settings; pub mod smtp_server_ee; mod static_assets; @@ -291,6 +292,7 @@ pub async fn run_server( ) .nest("/settings", settings::global_service()) .nest("/workers", workers::global_service()) + .nest("/service_logs", service_logs::global_service()) .nest("/configs", configs::global_service()) .nest("/scripts", scripts::global_service()) .nest("/integrations", integration::global_service()) @@ -389,7 +391,7 @@ pub async fn run_server( let server = server.with_graceful_shutdown(async move { rx.recv().await.ok(); - println!("Graceful shutdown of server"); + tracing::info!("Graceful shutdown of server"); }); server.await?; diff --git a/backend/windmill-api/src/openai.rs b/backend/windmill-api/src/openai.rs index d11bfcd6ed..0794dadaa5 100644 --- a/backend/windmill-api/src/openai.rs +++ b/backend/windmill-api/src/openai.rs @@ -1,9 +1,6 @@ use std::collections::HashMap; -use crate::{ - db::{ApiAuthed, DB}, - HTTP_CLIENT, -}; +use crate::db::{ApiAuthed, DB}; use axum::{ body::Bytes, @@ -13,6 +10,7 @@ use axum::{ Router, }; use quick_cache::sync::Cache; +use reqwest::Client; use serde_json::value::RawValue; use windmill_audit::audit_ee::audit_log; use windmill_audit::ActionKind; @@ -24,6 +22,13 @@ use windmill_common::{ use crate::variables::decrypt; use serde::Deserialize; +lazy_static::lazy_static! { + static ref HTTP_CLIENT: Client = reqwest::ClientBuilder::new() + .timeout(std::time::Duration::from_secs(60 * 5)) + .user_agent("windmill/beta") + .build().unwrap(); +} + pub fn workspaced_service() -> Router { let router = Router::new().route("/proxy/*openai_path", post(proxy)); diff --git a/backend/windmill-api/src/raw_apps.rs b/backend/windmill-api/src/raw_apps.rs index 20da51f3c7..59f2471c4d 100644 --- a/backend/windmill-api/src/raw_apps.rs +++ b/backend/windmill-api/src/raw_apps.rs @@ -158,7 +158,7 @@ async fn create_app( } let exists = sqlx::query_scalar!( - "SELECT EXISTS(SELECT 1 FROM app WHERE path = $1 AND workspace_id = $2)", + "SELECT EXISTS(SELECT 1 FROM raw_app WHERE path = $1 AND workspace_id = $2)", app.path, w_id ) diff --git a/backend/windmill-api/src/resources.rs b/backend/windmill-api/src/resources.rs index fbc5f53d00..1fb5b12259 100644 --- a/backend/windmill-api/src/resources.rs +++ b/backend/windmill-api/src/resources.rs @@ -6,6 +6,8 @@ * LICENSE-AGPL for a copy of the license. */ +use std::collections::HashMap; + use crate::{ db::{ApiAuthed, DB}, users::{maybe_refresh_folders, require_owner_of_path, Tokened}, @@ -56,6 +58,7 @@ pub fn workspaced_service() -> Router { .route("/type/exists/:name", get(exists_resource_type)) .route("/type/update/:name", post(update_resource_type)) .route("/type/delete/:name", delete(delete_resource_type)) + .route("/file_resource_type_to_file_ext_map", get(file_resource_ext_to_resource_type)) .route("/type/create", post(create_resource_type)) } @@ -71,6 +74,7 @@ pub struct ResourceType { pub description: Option, pub created_by: Option, pub edited_at: Option>, + pub format_extension: Option, } #[derive(Deserialize)] @@ -78,6 +82,7 @@ pub struct CreateResourceType { pub name: String, pub schema: Option, pub description: Option, + pub format_extension: Option, } #[derive(Deserialize)] @@ -913,6 +918,35 @@ async fn update_resource_value( Ok(format!("value of resource {} updated", path)) } +async fn file_resource_ext_to_resource_type( + Extension(db): Extension, + Path(w_id): Path, +) -> JsonResult> { + #[derive(Serialize, sqlx::FromRow)] + struct LocalFileResourceExtension { + name: String, + format_extension: Option, + } + + let r = sqlx::query_as!(LocalFileResourceExtension, " + SELECT name, format_extension FROM resource_type WHERE format_extension IS NOT NULL AND (workspace_id = $1 OR workspace_id = 'admins')", w_id) + .fetch_all(&db) + .await?; + + let hashmap: HashMap = r + .into_iter() + .filter_map(|entry| { + if let Some(format_extension) = entry.format_extension { + Some((entry.name, format_extension)) + } else { + None + } + }) + .collect(); + + Ok(Json(hashmap)) +} + async fn list_resource_types( Extension(db): Extension, Path(w_id): Path, @@ -996,13 +1030,14 @@ async fn create_resource_type( sqlx::query!( "INSERT INTO resource_type - (workspace_id, name, schema, description, created_by, edited_at) - VALUES ($1, $2, $3, $4, $5, now())", + (workspace_id, name, schema, description, created_by, format_extension, edited_at) + VALUES ($1, $2, $3, $4, $5, $6, now())", w_id, resource_type.name, resource_type.schema, resource_type.description, - authed.username + authed.username, + resource_type.format_extension, ) .execute(&mut *tx) .await?; diff --git a/backend/windmill-api/src/schedule.rs b/backend/windmill-api/src/schedule.rs index d52d441608..7a18976b03 100644 --- a/backend/windmill-api/src/schedule.rs +++ b/backend/windmill-api/src/schedule.rs @@ -69,6 +69,8 @@ pub struct NewSchedule { pub on_recovery: Option, pub on_recovery_times: Option, pub on_recovery_extra_args: Option, + pub on_success: Option, + pub on_success_extra_args: Option, pub ws_error_handler_muted: Option, pub retry: Option, pub tag: Option, @@ -92,6 +94,7 @@ pub struct ErrorOrRecoveryHandler { pub enum HandlerType { Error, Recovery, + Success, } async fn check_path_conflict<'c>( @@ -133,6 +136,13 @@ async fn create_schedule( )); } + #[cfg(not(feature = "enterprise"))] + if ns.on_success.is_some() { + return Err(Error::BadRequest( + "on_success is only available in enterprise version".to_string(), + )); + } + #[cfg(not(feature = "enterprise"))] if ns.on_failure_times.is_some() && ns.on_failure_times.unwrap() > 1 { return Err(Error::BadRequest( @@ -158,9 +168,10 @@ async fn create_schedule( "INSERT INTO schedule (workspace_id, path, schedule, timezone, edited_by, script_path, \ is_flow, args, enabled, email, on_failure, on_failure_times, on_failure_exact, \ on_failure_extra_args, on_recovery, on_recovery_times, on_recovery_extra_args, \ + on_success, on_success_extra_args, \ ws_error_handler_muted, retry, summary, no_flow_overlap, tag, paused_until \ ) VALUES ( \ - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23 \ + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25 \ ) RETURNING *") .bind(&w_id) .bind(&ns.path) @@ -179,6 +190,8 @@ async fn create_schedule( .bind(&ns.on_recovery) .bind(&ns.on_recovery_times) .bind(&ns.on_recovery_extra_args) + .bind(&ns.on_success) + .bind(&ns.on_success_extra_args) .bind(&ns.ws_error_handler_muted.unwrap_or(false)) .bind(&ns.retry) .bind(&ns.summary) @@ -248,9 +261,10 @@ async fn edit_schedule( let schedule = sqlx::query_as::<_, Schedule>( "UPDATE schedule SET schedule = $1, timezone = $2, args = $3, on_failure = $4, on_failure_times = $5, \ on_failure_exact = $6, on_failure_extra_args = $7, on_recovery = $8, on_recovery_times = $9, \ - on_recovery_extra_args = $10, ws_error_handler_muted = $11, retry = $12, summary = $13, \ - no_flow_overlap = $14, tag = $15, paused_until = $16 - WHERE path = $17 AND workspace_id = $18 RETURNING *") + on_recovery_extra_args = $10, on_success = $11, on_success_extra_args = $12, \ + ws_error_handler_muted = $13, retry = $14, summary = $15, \ + no_flow_overlap = $16, tag = $17, paused_until = $18 + WHERE path = $19 AND workspace_id = $20 RETURNING *") .bind(&es.schedule) .bind(&es.timezone) .bind(&es.args) @@ -261,6 +275,8 @@ async fn edit_schedule( .bind(&es.on_recovery) .bind(&es.on_recovery_times) .bind(&es.on_recovery_extra_args) + .bind(&es.on_success) + .bind(&es.on_success_extra_args) .bind(&es.ws_error_handler_muted.unwrap_or(false)) .bind(&es.retry) .bind(&es.summary) @@ -376,6 +392,8 @@ pub struct ScheduleWJobs { pub on_recovery: Option, pub on_recovery_times: Option, pub on_recovery_extra_args: Option, + pub on_success: Option, + pub on_success_extra_args: Option, pub ws_error_handler_muted: bool, pub retry: Option, pub jobs: Option>, @@ -680,6 +698,18 @@ async fn set_default_error_handler( (key, None) } } + HandlerType::Success => { + let key = format!("default_success_handler_{}", w_id); + if let Some(payload_path) = payload.path.as_ref() { + let value = serde_json::json!({ + "successHandlerPath": payload_path, + "successHandlerExtraArgs": payload.extra_args, + }); + (key, Some(value)) + } else { + (key, None) + } + } }; if let Some(value_content) = value { @@ -733,6 +763,25 @@ async fn set_default_error_handler( .await?; } } + HandlerType::Success => { + if payload.path.is_some() { + updated_schedules = sqlx::query_scalar!( + "UPDATE schedule SET on_success = $1, on_success_extra_args = $2 WHERE workspace_id = $3 RETURNING path", + payload.path, + payload.extra_args, + w_id, + ) + .fetch_all(&db) + .await?; + } else { + updated_schedules = sqlx::query_scalar!( + "UPDATE schedule SET on_success = NULL, on_success_extra_args = NULL WHERE workspace_id = $1 RETURNING path", + w_id, + ) + .fetch_all(&db) + .await?; + } + } } for updated_schedule_path in updated_schedules { handle_deployment_metadata( @@ -790,6 +839,8 @@ pub struct EditSchedule { pub on_recovery: Option, pub on_recovery_times: Option, pub on_recovery_extra_args: Option, + pub on_success: Option, + pub on_success_extra_args: Option, pub ws_error_handler_muted: Option, pub retry: Option, pub no_flow_overlap: Option, diff --git a/backend/windmill-api/src/scripts.rs b/backend/windmill-api/src/scripts.rs index 41214dfcbb..61e8c553ee 100644 --- a/backend/windmill-api/src/scripts.rs +++ b/backend/windmill-api/src/scripts.rs @@ -10,6 +10,7 @@ use crate::{ db::{ApiAuthed, DB}, schedule::clear_schedule, users::{maybe_refresh_folders, require_owner_of_path, AuthCache}, + utils::WithStarredInfoQuery, webhook_util::{WebhookMessage, WebhookShared}, HTTP_CLIENT, }; @@ -46,7 +47,7 @@ use windmill_common::{ schedule::Schedule, scripts::{ to_i64, HubScript, ListScriptQuery, ListableScript, NewScript, Schema, Script, ScriptHash, - ScriptHistory, ScriptHistoryUpdate, ScriptKind, ScriptLang, + ScriptHistory, ScriptHistoryUpdate, ScriptKind, ScriptLang, ScriptWithStarred, }, users::username_to_permissioned_as, utils::{ @@ -526,7 +527,8 @@ async fn create_script_internal<'c>( ))); }; - let ps = get_script_by_hash_internal(tx.transaction_mut(), &w_id, p_hash).await?; + let ScriptWithStarred { script: ps, .. } = + get_script_by_hash_internal(tx.transaction_mut(), &w_id, p_hash, None).await?; if ps.path != ns.path { require_owner_of_path(&authed, &ps.path)?; @@ -578,6 +580,7 @@ async fn create_script_internal<'c>( || ns.language == ScriptLang::Bun || ns.language == ScriptLang::Bunnative || ns.language == ScriptLang::Deno + || ns.language == ScriptLang::Rust || ns.language == ScriptLang::Php) { Some(String::new()) @@ -826,19 +829,40 @@ async fn get_script_by_path( authed: ApiAuthed, Extension(user_db): Extension, Path((w_id, path)): Path<(String, StripPath)>, -) -> JsonResult {#if !notFound} @@ -181,13 +193,29 @@ {#if !emptyString(error)}{error}{:else}
{/if} - +
+ +
+{:else if resourceTypeInfo?.format_extension} +
+ File content ({resourceTypeInfo.format_extension}) +
+
+
+ +
{:else} - ['token', 'secret', 'key', 'pass', 'private'].some((y) => x.toLowerCase().includes(y)) - ) - : undefined + function computeCandidates(resourceType: string, argsKeys: string[]) { + return apiTokenApps[resourceType]?.linkedSecret + ? ([apiTokenApps[resourceType]?.linkedSecret] as string[]) + : argsKeys.filter((x) => + ['token', 'secret', 'key', 'pass', 'private'].some((y) => x.toLowerCase().includes(y)) + ) + } - $: linkedSecret = - forceSecretValue(resourceType) ?? - linkedSecretCandidates?.sort((ua, ub) => linkedSecretValue(ub) - linkedSecretValue(ua))?.[0] + let linkedSecret: string | undefined = undefined + let linkedSecretCandidates: string[] | undefined = undefined + function computeLinkedSecret(resourceType: string, argsKeys: string[]) { + linkedSecretCandidates = computeCandidates(resourceType, argsKeys) + return ( + forceSecretValue(resourceType) ?? + linkedSecretCandidates?.sort((ua, ub) => linkedSecretValue(ub) - linkedSecretValue(ua))?.[0] + ) + } let scopes: string[] = [] let extra_params: [string, string][] = [] @@ -199,9 +205,14 @@ workspace: $workspaceStore!, path: resourceType }) + const newArgsKeys = Object.keys(resourceTypeInfo?.schema?.['properties'] ?? {}) ?? [] + if (!linkedSecret) { + linkedSecret = computeLinkedSecret(resourceType, newArgsKeys) + } } export async function next() { if (step == 1) { + linkedSecret = undefined if (manual) { getResourceTypeInfo() args = {} @@ -336,7 +347,6 @@ bind:filteredItems={filteredConnectsManual} f={(x) => x[0]} /> - {#if step == 1}
{#key resourceTypeInfo} null -{:else if value == ''} +{:else if value === ''} {''}The arg was none and the default argument of the script is a function call, hence the actual value used for this arg was the output of the script's function call for this arg max) { + error = `Should be less than or equal to ${max}` + valid && (valid = false) + } else { + error = '' + !valid && (valid = true) + } + } else if (pattern && !testRegex(pattern, v)) { if (!emptyString(customErrorMessage)) { error = customErrorMessage ?? '' } else if (format == 'email') { @@ -240,7 +253,10 @@ } function onKeyDown(e: KeyboardEvent) { - if ((e.ctrlKey || e.metaKey) && e.key == 'Enter') { + if ( + (e.ctrlKey || e.metaKey) && + (e.key == 'Enter' || e.key == 'c' || e.key == 'v' || e.key == 'x') + ) { return } e.stopPropagation() @@ -409,7 +425,8 @@ /> {:else if itemsType?.type == 'resource' && itemsType?.resourceType && resourceTypes?.includes(itemsType.resourceType)} @@ -568,7 +585,8 @@ randomFileKey={true} on:addition={(evt) => { value = { - s3: evt.detail?.path ?? '' + s3: evt.detail?.path ?? '', + filename: evt.detail?.filename ?? '' } }} on:deletion={(evt) => { @@ -815,7 +833,9 @@
{#if password || extra?.['password'] == true} - {#if onlyMaskPassword} + {#if value && typeof value == 'string' && value?.startsWith('$var:')} + + {:else if onlyMaskPassword} diff --git a/frontend/src/lib/components/AutheliaSetting.svelte b/frontend/src/lib/components/AutheliaSetting.svelte index 48d2a08d64..d97b54c7e7 100644 --- a/frontend/src/lib/components/AutheliaSetting.svelte +++ b/frontend/src/lib/components/AutheliaSetting.svelte @@ -31,6 +31,7 @@
+