From 5f25823b37c07a32ca20fd25f8ea850cfc6bd32f Mon Sep 17 00:00:00 2001 From: Julius Krumbiegel Date: Thu, 19 Mar 2026 11:50:12 +0100 Subject: [PATCH 1/4] fix: update julia-engine subtree remote URL to PumasAI/quarto-julia-engine --- src/command/dev-call/pull-git-subtree/cmd.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command/dev-call/pull-git-subtree/cmd.ts b/src/command/dev-call/pull-git-subtree/cmd.ts index d71e67bc2ba..8570902bdf2 100644 --- a/src/command/dev-call/pull-git-subtree/cmd.ts +++ b/src/command/dev-call/pull-git-subtree/cmd.ts @@ -21,7 +21,7 @@ const SUBTREES: SubtreeConfig[] = [ { name: "julia-engine", prefix: "src/resources/extension-subtrees/julia-engine", - remoteUrl: "https://github.com/gordonwoodhull/quarto-julia-engine.git", + remoteUrl: "https://github.com/PumasAI/quarto-julia-engine.git", remoteBranch: "main", }, { From 350586c71b4eda3ebdbbe15cb8dfd6d2030408d9 Mon Sep 17 00:00:00 2001 From: Gordon Woodhull Date: Thu, 19 Mar 2026 14:12:31 -0400 Subject: [PATCH 2/4] Squashed 'src/resources/extension-subtrees/julia-engine/' changes from 1de70acbd..f591fc453 f591fc453 Merge pull request #6 from PumasAI/jk/bundle-julia-resources 16a1aa0f4 chore: gitignore .claude directory 037c7bca4 docs: simplify test structure description in AGENTS.md f32744043 ci: make quarto-cli repo configurable 134aae7e0 docs: update AGENTS.md with testing and CI documentation baec85652 ci: bump actions/cache to v5.0.4, add actions:write permission 0869d5475 ci: cache typst-gather Cargo build across runs 80ae1c460 chore: whitelist only source files in test docs directory e3558bde0 ci: cancel in-progress runs on new pushes 50a9150c7 chore: remove render-generated .gitignore 0686c80e7 refactor: flatten docs/smoke-all into docs/julia-engine 0c83c6f26 refactor: restructure tests for easy quarto-cli integration 43952eb68 ci: add macOS and Windows test runners bbcae8fb4 refactor: always use quarto's bundled deno in test runner 003400e13 feat: add run-tests.sh wrapper, use quarto's bundled deno 25d0a3b81 chore: remove render artifacts and gitignore test outputs 5928ee7c7 feat: move Julia engine tests into extension repo f0791c8d1 ci: detect Julia version from quarto-cli test Manifest 5a67989d1 ci: bump quarto-cli rev to v1.9.35 4d564d55c ci: add GitHub Actions workflow for Julia engine tests 3c52cbe8f feat: bundle Julia resource files into the extension 605d04dfd Merge pull request #5 from PumasAI/jk/repo-cleanup 883587548 docs: add AGENTS.md/CLAUDE.md and update README 1bbc55d0b chore: remove obsolete files and clean up gitignore git-subtree-dir: src/resources/extension-subtrees/julia-engine git-subtree-split: f591fc4536f7f98c7be8f8cd128f85059dc24145 --- .github/workflows/ci.yml | 100 ++ .gitignore | 7 +- AGENTS.md | 61 + CLAUDE.md | 1 + Manifest.toml | 1571 ----------------- Project.toml | 4 - README.md | 12 +- _extensions/julia-engine/Project.toml | 5 + .../julia-engine/ensure_environment.jl | 32 + _extensions/julia-engine/julia-engine.js | 157 +- .../julia-engine/quartonotebookrunner.jl | 57 + .../start_quartonotebookrunner_detached.jl | 17 + example.qmd | 80 - src/julia-engine.ts | 21 +- tests/docs/julia-engine/.gitignore | 6 + .../engine-reordering/_quarto.yml | 3 + .../engine-reordering/notebook.qmd | 10 + tests/docs/julia-engine/sleep/_quarto.yml | 2 + tests/docs/julia-engine/sleep/sleep.qmd | 9 + .../julia-engine/source-ranges/_included.qmd | 3 + .../source-ranges/source-ranges-test.qmd | 11 + tests/run-tests.ps1 | 31 + tests/run-tests.sh | 37 + tests/smoke/julia-engine/julia.test.ts | 227 +++ tests/smoke/julia-engine/render.test.ts | 55 + 25 files changed, 833 insertions(+), 1686 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 AGENTS.md create mode 120000 CLAUDE.md delete mode 100644 Manifest.toml delete mode 100644 Project.toml create mode 100644 _extensions/julia-engine/Project.toml create mode 100644 _extensions/julia-engine/ensure_environment.jl create mode 100644 _extensions/julia-engine/quartonotebookrunner.jl create mode 100644 _extensions/julia-engine/start_quartonotebookrunner_detached.jl delete mode 100644 example.qmd create mode 100644 tests/docs/julia-engine/.gitignore create mode 100644 tests/docs/julia-engine/engine-reordering/_quarto.yml create mode 100644 tests/docs/julia-engine/engine-reordering/notebook.qmd create mode 100644 tests/docs/julia-engine/sleep/_quarto.yml create mode 100644 tests/docs/julia-engine/sleep/sleep.qmd create mode 100644 tests/docs/julia-engine/source-ranges/_included.qmd create mode 100644 tests/docs/julia-engine/source-ranges/source-ranges-test.qmd create mode 100644 tests/run-tests.ps1 create mode 100755 tests/run-tests.sh create mode 100644 tests/smoke/julia-engine/julia.test.ts create mode 100644 tests/smoke/julia-engine/render.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..4587605e710 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,100 @@ +name: CI +on: + push: + branches: [main] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + actions: write + contents: read + +# Reference quarto-cli version to test against. +# Full commit hash for reproducibility; comment documents the human-readable version. +env: + QUARTO_CLI_REPO: quarto-dev/quarto-cli + QUARTO_CLI_REV: 97e7649bf14607cf39cda13f013185a4146e047b # v1.9.35 + +jobs: + test: + name: Julia engine tests (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Checkout quarto-cli + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: ${{ env.QUARTO_CLI_REPO }} + ref: ${{ env.QUARTO_CLI_REV }} + path: _quarto-cli + + - name: Cache typst-gather build + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: _quarto-cli/package/typst-gather/target + key: ${{ runner.os }}-typst-gather-${{ env.QUARTO_CLI_REV }} + + - name: Configure Quarto (Unix) + if: runner.os != 'Windows' + working-directory: _quarto-cli + run: ./configure.sh + + - name: Configure Quarto (Windows) + if: runner.os == 'Windows' + working-directory: _quarto-cli + shell: cmd + run: ./configure.cmd + + - name: Add quarto to PATH (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + "$(Get-ChildItem -Path _quarto-cli/package/dist/bin/quarto.cmd | ForEach-Object { $_.FullName } | Split-Path)" >> $env:GITHUB_PATH + + # Rebuild the bundled JS from our TS source using the configured quarto, + # then verify it matches what's checked in. This catches forgotten rebuilds. + - name: Verify bundled JS is up to date (Unix) + if: runner.os != 'Windows' + run: | + quarto call build-ts-extension src/julia-engine.ts + if ! git diff --exit-code _extensions/julia-engine/julia-engine.js; then + echo "::error::Bundled JS is out of date. Run 'quarto call build-ts-extension src/julia-engine.ts' and commit the result." + exit 1 + fi + + - name: Verify bundled JS is up to date (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + quarto call build-ts-extension src/julia-engine.ts + git diff --exit-code _extensions/julia-engine/julia-engine.js + if ($LASTEXITCODE -ne 0) { + Write-Error "Bundled JS is out of date. Run 'quarto call build-ts-extension src/julia-engine.ts' and commit the result." + exit 1 + } + + - name: Setup Julia + uses: julia-actions/setup-julia@5c9647d97b78a5debe5164e9eec09d653d29bd71 # v2.6.1 + with: + version: "1.11" + + - name: Cache Julia packages + uses: julia-actions/cache@b6a98a496542b2eeda9b4402ce8f79f8fd753d5e # v3.0.0 + + - name: Run tests (Unix) + if: runner.os != 'Windows' + run: tests/run-tests.sh + + - name: Run tests (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: tests/run-tests.ps1 diff --git a/.gitignore b/.gitignore index 844b2d77f92..f54fb86607e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ -example.html -example_files/ +.DS_Store +.claude/ .quarto/ - -/.quarto/ **/*.quarto_ipynb +scratch/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000..4c7e6d70102 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,61 @@ +# quarto-julia-engine + +This repo contains the Julia execution engine for Quarto. The engine was originally built directly into quarto-cli but has since been refactored into an extension-style engine, moved into this separate repo, and is pulled into quarto-cli via a git subtree at `src/resources/extension-subtrees/julia-engine/`. + +The engine extension requires a compatible version of quarto (>= 1.9.0). If work involves changes to the engine–quarto interface, you'll also need a corresponding dev build of quarto-cli with matching changes. + +## Repo structure + +- `_extensions/julia-engine/` — the actual extension (contains `_extension.yml`, the bundled `julia-engine.js`, and Julia resource files like `Project.toml`, `*.jl`) +- `src/` — TypeScript source for the engine (`julia-engine.ts`, `constants.ts`). Changes here must be bundled into `_extensions/julia-engine/julia-engine.js` to take effect. +- `_quarto.yml` — makes the repo root a quarto project so rendering picks up the extension from `_extensions/` +- `tests/` — self-contained test suite (see Testing below) + +## Building + +After editing the TypeScript source in `src/`, rebuild the bundled JS: + +```sh +quarto call build-ts-extension src/julia-engine.ts +``` + +This bundles `src/julia-engine.ts` into `_extensions/julia-engine/julia-engine.js`. CI verifies the bundled JS matches the TS source. + +## Testing + +Tests are self-contained Deno tests using `jsr:` imports — no import map or quarto internals needed. `tests/docs/` contains `.qmd` files and quarto projects that the `.test.ts` files in `tests/smoke/` render and verify. These directories mirror quarto-cli's `tests/docs/` and `tests/smoke/` structure and are intended to be merged into those directories when quarto-cli runs its own CI (since this extension is a fixed part of quarto-cli via git subtree). + +### Running tests locally + +The test runner uses the deno bundled with quarto (to avoid version mismatches): + +```sh +# With quarto on PATH: +tests/run-tests.sh + +# With explicit quarto path: +QUARTO=/path/to/quarto tests/run-tests.sh + +# Run a specific test file: +tests/run-tests.sh smoke/julia-engine/render.test.ts +``` + +### Quick: render in this repo + +Create or edit a `.qmd` file in the repo root (e.g. in `scratch/`) with `engine: julia` and render it: + +```sh +quarto render scratch/test.qmd +``` + +Since this directory is a quarto project with the extension in `_extensions/`, quarto discovers and uses the engine from here. + +## CI + +CI runs on all three platforms (Linux, macOS, Windows) against a pinned quarto-cli revision (see `QUARTO_CLI_REV` in `.github/workflows/ci.yml`). It: + +1. Configures quarto from the pinned rev +2. Verifies the bundled JS is up to date with the TS source +3. Runs the full test suite + +When bumping `QUARTO_CLI_REV`, use the full commit hash annotated with the version tag for clarity (e.g. `abc123 # v1.9.35`). diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 00000000000..47dc3e3d863 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/Manifest.toml b/Manifest.toml deleted file mode 100644 index a7afb0a8f1e..00000000000 --- a/Manifest.toml +++ /dev/null @@ -1,1571 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -julia_version = "1.12.1" -manifest_format = "2.0" -project_hash = "8551d9d97d1c74b8788a9cb955d4fe3906e3f1e7" - -[[deps.AbstractFFTs]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "d92ad398961a3ed262d8bf04a1a2b8340f915fef" -uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" -version = "1.5.0" -weakdeps = ["ChainRulesCore", "Test"] - - [deps.AbstractFFTs.extensions] - AbstractFFTsChainRulesCoreExt = "ChainRulesCore" - AbstractFFTsTestExt = "Test" - -[[deps.Adapt]] -deps = ["LinearAlgebra", "Requires"] -git-tree-sha1 = "7e35fca2bdfba44d797c53dfe63a51fabf39bfc0" -uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "4.4.0" -weakdeps = ["SparseArrays", "StaticArrays"] - - [deps.Adapt.extensions] - AdaptSparseArraysExt = "SparseArrays" - AdaptStaticArraysExt = "StaticArrays" - -[[deps.AliasTables]] -deps = ["PtrArrays", "Random"] -git-tree-sha1 = "9876e1e164b144ca45e9e3198d0b689cadfed9ff" -uuid = "66dad0bd-aa9a-41b7-9441-69ab47430ed8" -version = "1.1.3" - -[[deps.ArgTools]] -uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" -version = "1.1.2" - -[[deps.Arpack]] -deps = ["Arpack_jll", "Libdl", "LinearAlgebra", "Logging"] -git-tree-sha1 = "9b9b347613394885fd1c8c7729bfc60528faa436" -uuid = "7d9fca2a-8960-54d3-9f78-7d1dccf2cb97" -version = "0.5.4" - -[[deps.Arpack_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS_jll", "Pkg"] -git-tree-sha1 = "5ba6c757e8feccf03a1554dfaf3e26b3cfc7fd5e" -uuid = "68821587-b530-5797-8361-c406ea357684" -version = "3.5.1+1" - -[[deps.Artifacts]] -uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" -version = "1.11.0" - -[[deps.AxisAlgorithms]] -deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"] -git-tree-sha1 = "01b8ccb13d68535d73d2b0c23e39bd23155fb712" -uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950" -version = "1.1.0" - -[[deps.Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" -version = "1.11.0" - -[[deps.BitFlags]] -git-tree-sha1 = "0691e34b3bb8be9307330f88d1a3c3f25466c24d" -uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35" -version = "0.1.9" - -[[deps.Bzip2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "1b96ea4a01afe0ea4090c5c8039690672dd13f2e" -uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" -version = "1.0.9+0" - -[[deps.CSV]] -deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "PrecompileTools", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings", "WorkerUtilities"] -git-tree-sha1 = "deddd8725e5e1cc49ee205a1964256043720a6c3" -uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" -version = "0.10.15" - -[[deps.Cairo_jll]] -deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "fde3bf89aead2e723284a8ff9cdf5b551ed700e8" -uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" -version = "1.18.5+0" - -[[deps.CategoricalArrays]] -deps = ["DataAPI", "Future", "Missings", "Printf", "Requires", "Statistics", "Unicode"] -git-tree-sha1 = "5084cc1a28976dd1642c9f337b28a3cb03e0f7d2" -uuid = "324d7699-5711-5eae-9e2f-1d82baa6b597" -version = "0.10.7" - -[[deps.ChainRulesCore]] -deps = ["Compat", "LinearAlgebra"] -git-tree-sha1 = "e4c6a16e77171a5f5e25e9646617ab1c276c5607" -uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.26.0" -weakdeps = ["SparseArrays"] - - [deps.ChainRulesCore.extensions] - ChainRulesCoreSparseArraysExt = "SparseArrays" - -[[deps.Clustering]] -deps = ["Distances", "LinearAlgebra", "NearestNeighbors", "Printf", "Random", "SparseArrays", "Statistics", "StatsBase"] -git-tree-sha1 = "3e22db924e2945282e70c33b75d4dde8bfa44c94" -uuid = "aaaa29a8-35af-508c-8bc3-b662a17a0fe5" -version = "0.15.8" - -[[deps.CodecZlib]] -deps = ["TranscodingStreams", "Zlib_jll"] -git-tree-sha1 = "962834c22b66e32aa10f7611c08c8ca4e20749a9" -uuid = "944b1d66-785c-5afd-91f1-9de20f533193" -version = "0.7.8" - -[[deps.ColorSchemes]] -deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"] -git-tree-sha1 = "b0fd3f56fa442f81e0a47815c92245acfaaa4e34" -uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" -version = "3.31.0" - -[[deps.ColorTypes]] -deps = ["FixedPointNumbers", "Random"] -git-tree-sha1 = "67e11ee83a43eb71ddc950302c53bf33f0690dfe" -uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" -version = "0.12.1" -weakdeps = ["StyledStrings"] - - [deps.ColorTypes.extensions] - StyledStringsExt = "StyledStrings" - -[[deps.ColorVectorSpace]] -deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "Requires", "Statistics", "TensorCore"] -git-tree-sha1 = "8b3b6f87ce8f65a2b4f857528fd8d70086cd72b1" -uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" -version = "0.11.0" -weakdeps = ["SpecialFunctions"] - - [deps.ColorVectorSpace.extensions] - SpecialFunctionsExt = "SpecialFunctions" - -[[deps.Colors]] -deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] -git-tree-sha1 = "37ea44092930b1811e666c3bc38065d7d87fcc74" -uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" -version = "0.13.1" - -[[deps.Compat]] -deps = ["TOML", "UUIDs"] -git-tree-sha1 = "9d8a54ce4b17aa5bdce0ea5c34bc5e7c340d16ad" -uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "4.18.1" -weakdeps = ["Dates", "LinearAlgebra"] - - [deps.Compat.extensions] - CompatLinearAlgebraExt = "LinearAlgebra" - -[[deps.CompilerSupportLibraries_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" -version = "1.3.0+1" - -[[deps.ConcurrentUtilities]] -deps = ["Serialization", "Sockets"] -git-tree-sha1 = "d9d26935a0bcffc87d2613ce14c527c99fc543fd" -uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb" -version = "2.5.0" - -[[deps.Contour]] -git-tree-sha1 = "439e35b0b36e2e5881738abc8857bd92ad6ff9a8" -uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" -version = "0.6.3" - -[[deps.Crayons]] -git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" -uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" -version = "4.1.1" - -[[deps.DataAPI]] -git-tree-sha1 = "abe83f3a2f1b857aac70ef8b269080af17764bbe" -uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" -version = "1.16.0" - -[[deps.DataFrames]] -deps = ["Compat", "DataAPI", "DataStructures", "Future", "InlineStrings", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrecompileTools", "PrettyTables", "Printf", "Random", "Reexport", "SentinelArrays", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] -git-tree-sha1 = "d8928e9169ff76c6281f39a659f9bca3a573f24c" -uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" -version = "1.8.1" - -[[deps.DataStructures]] -deps = ["OrderedCollections"] -git-tree-sha1 = "6c72198e6a101cccdd4c9731d3985e904ba26037" -uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.19.1" - -[[deps.DataValueInterfaces]] -git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" -uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" -version = "1.0.0" - -[[deps.Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" -version = "1.11.0" - -[[deps.Dbus_jll]] -deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "473e9afc9cf30814eb67ffa5f2db7df82c3ad9fd" -uuid = "ee1fde0b-3d02-5ea6-8484-8dfef6360eab" -version = "1.16.2+0" - -[[deps.DelimitedFiles]] -deps = ["Mmap"] -git-tree-sha1 = "9e2f36d3c96a820c678f2f1f1782582fcf685bae" -uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" -version = "1.9.1" - -[[deps.Distances]] -deps = ["LinearAlgebra", "Statistics", "StatsAPI"] -git-tree-sha1 = "c7e3a542b999843086e2f29dac96a618c105be1d" -uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" -version = "0.10.12" -weakdeps = ["ChainRulesCore", "SparseArrays"] - - [deps.Distances.extensions] - DistancesChainRulesCoreExt = "ChainRulesCore" - DistancesSparseArraysExt = "SparseArrays" - -[[deps.Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" -version = "1.11.0" - -[[deps.Distributions]] -deps = ["AliasTables", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns"] -git-tree-sha1 = "3bc002af51045ca3b47d2e1787d6ce02e68b943a" -uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" -version = "0.25.122" - - [deps.Distributions.extensions] - DistributionsChainRulesCoreExt = "ChainRulesCore" - DistributionsDensityInterfaceExt = "DensityInterface" - DistributionsTestExt = "Test" - - [deps.Distributions.weakdeps] - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - DensityInterface = "b429d917-457f-4dbc-8f4c-0cc954292b1d" - Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[deps.DocStringExtensions]] -git-tree-sha1 = "7442a5dfe1ebb773c29cc2962a8980f47221d76c" -uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.9.5" - -[[deps.Downloads]] -deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] -uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" -version = "1.6.0" - -[[deps.EpollShim_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "8a4be429317c42cfae6a7fc03c31bad1970c310d" -uuid = "2702e6a9-849d-5ed8-8c21-79e8b8f9ee43" -version = "0.0.20230411+1" - -[[deps.ExceptionUnwrapping]] -deps = ["Test"] -git-tree-sha1 = "d36f682e590a83d63d1c7dbd287573764682d12a" -uuid = "460bff9d-24e4-43bc-9d9f-a8973cb893f4" -version = "0.1.11" - -[[deps.Expat_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "27af30de8b5445644e8ffe3bcb0d72049c089cf1" -uuid = "2e619515-83b5-522b-bb60-26c02a35a201" -version = "2.7.3+0" - -[[deps.ExprTools]] -git-tree-sha1 = "27415f162e6028e81c72b82ef756bf321213b6ec" -uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" -version = "0.1.10" - -[[deps.FFMPEG]] -deps = ["FFMPEG_jll"] -git-tree-sha1 = "95ecf07c2eea562b5adbd0696af6db62c0f52560" -uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" -version = "0.4.5" - -[[deps.FFMPEG_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] -git-tree-sha1 = "ccc81ba5e42497f4e76553a5545665eed577a663" -uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" -version = "8.0.0+0" - -[[deps.FFTW]] -deps = ["AbstractFFTs", "FFTW_jll", "Libdl", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] -git-tree-sha1 = "97f08406df914023af55ade2f843c39e99c5d969" -uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" -version = "1.10.0" - -[[deps.FFTW_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "6d6219a004b8cf1e0b4dbe27a2860b8e04eba0be" -uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" -version = "3.3.11+0" - -[[deps.FileIO]] -deps = ["Pkg", "Requires", "UUIDs"] -git-tree-sha1 = "d60eb76f37d7e5a40cc2e7c36974d864b82dc802" -uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" -version = "1.17.1" -weakdeps = ["HTTP"] - - [deps.FileIO.extensions] - HTTPExt = "HTTP" - -[[deps.FilePathsBase]] -deps = ["Compat", "Dates"] -git-tree-sha1 = "3bab2c5aa25e7840a4b065805c0cdfc01f3068d2" -uuid = "48062228-2e41-5def-b9a4-89aafe57970f" -version = "0.9.24" -weakdeps = ["Mmap", "Test"] - - [deps.FilePathsBase.extensions] - FilePathsBaseMmapExt = "Mmap" - FilePathsBaseTestExt = "Test" - -[[deps.FileWatching]] -uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" -version = "1.11.0" - -[[deps.FillArrays]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "173e4d8f14230a7523ae11b9a3fa9edb3e0efd78" -uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" -version = "1.14.0" -weakdeps = ["PDMats", "SparseArrays", "Statistics"] - - [deps.FillArrays.extensions] - FillArraysPDMatsExt = "PDMats" - FillArraysSparseArraysExt = "SparseArrays" - FillArraysStatisticsExt = "Statistics" - -[[deps.FixedPointNumbers]] -deps = ["Statistics"] -git-tree-sha1 = "05882d6995ae5c12bb5f36dd2ed3f61c98cbb172" -uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" -version = "0.8.5" - -[[deps.Fontconfig_jll]] -deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Zlib_jll"] -git-tree-sha1 = "f85dac9a96a01087df6e3a749840015a0ca3817d" -uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" -version = "2.17.1+0" - -[[deps.Format]] -git-tree-sha1 = "9c68794ef81b08086aeb32eeaf33531668d5f5fc" -uuid = "1fa38f19-a742-5d3f-a2b9-30dd87b9d5f8" -version = "1.3.7" - -[[deps.FreeType2_jll]] -deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "2c5512e11c791d1baed2049c5652441b28fc6a31" -uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" -version = "2.13.4+0" - -[[deps.FriBidi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "7a214fdac5ed5f59a22c2d9a885a16da1c74bbc7" -uuid = "559328eb-81f9-559d-9380-de523a88c83c" -version = "1.0.17+0" - -[[deps.Future]] -deps = ["Random"] -uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" -version = "1.11.0" - -[[deps.GLFW_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll", "libdecor_jll", "xkbcommon_jll"] -git-tree-sha1 = "fcb0584ff34e25155876418979d4c8971243bb89" -uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" -version = "3.4.0+2" - -[[deps.GR]] -deps = ["Artifacts", "Base64", "DelimitedFiles", "Downloads", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Preferences", "Printf", "Qt6Wayland_jll", "Random", "Serialization", "Sockets", "TOML", "Tar", "Test", "p7zip_jll"] -git-tree-sha1 = "1828eb7275491981fa5f1752a5e126e8f26f8741" -uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" -version = "0.73.17" - -[[deps.GR_jll]] -deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "FreeType2_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Qt6Base_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "27299071cc29e409488ada41ec7643e0ab19091f" -uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" -version = "0.73.17+0" - -[[deps.GettextRuntime_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll"] -git-tree-sha1 = "45288942190db7c5f760f59c04495064eedf9340" -uuid = "b0724c58-0f36-5564-988d-3bb0596ebc4a" -version = "0.22.4+0" - -[[deps.Ghostscript_jll]] -deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Zlib_jll"] -git-tree-sha1 = "38044a04637976140074d0b0621c1edf0eb531fd" -uuid = "61579ee1-b43e-5ca0-a5da-69d92c66a64b" -version = "9.55.1+0" - -[[deps.Glib_jll]] -deps = ["Artifacts", "GettextRuntime_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Zlib_jll"] -git-tree-sha1 = "50c11ffab2a3d50192a228c313f05b5b5dc5acb2" -uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" -version = "2.86.0+0" - -[[deps.Graphite2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "8a6dbda1fd736d60cc477d99f2e7a042acfa46e8" -uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" -version = "1.3.15+0" - -[[deps.Grisu]] -git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" -uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" -version = "1.0.2" - -[[deps.HTTP]] -deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "PrecompileTools", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] -git-tree-sha1 = "5e6fe50ae7f23d171f44e311c2960294aaa0beb5" -uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" -version = "1.10.19" - -[[deps.HarfBuzz_jll]] -deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll"] -git-tree-sha1 = "f923f9a774fcf3f5cb761bfa43aeadd689714813" -uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" -version = "8.5.1+0" - -[[deps.HypergeometricFunctions]] -deps = ["LinearAlgebra", "OpenLibm_jll", "SpecialFunctions"] -git-tree-sha1 = "68c173f4f449de5b438ee67ed0c9c748dc31a2ec" -uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" -version = "0.3.28" - -[[deps.InlineStrings]] -git-tree-sha1 = "8f3d257792a522b4601c24a577954b0a8cd7334d" -uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48" -version = "1.4.5" - - [deps.InlineStrings.extensions] - ArrowTypesExt = "ArrowTypes" - ParsersExt = "Parsers" - - [deps.InlineStrings.weakdeps] - ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd" - Parsers = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" - -[[deps.IntelOpenMP_jll]] -deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl"] -git-tree-sha1 = "ec1debd61c300961f98064cfb21287613ad7f303" -uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" -version = "2025.2.0+0" - -[[deps.InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" -version = "1.11.0" - -[[deps.Interpolations]] -deps = ["Adapt", "AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"] -git-tree-sha1 = "65d505fa4c0d7072990d659ef3fc086eb6da8208" -uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" -version = "0.16.2" - - [deps.Interpolations.extensions] - InterpolationsForwardDiffExt = "ForwardDiff" - InterpolationsUnitfulExt = "Unitful" - - [deps.Interpolations.weakdeps] - ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" - Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" - -[[deps.InvertedIndices]] -git-tree-sha1 = "6da3c4316095de0f5ee2ebd875df8721e7e0bdbe" -uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" -version = "1.3.1" - -[[deps.IrrationalConstants]] -git-tree-sha1 = "b2d91fe939cae05960e760110b328288867b5758" -uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" -version = "0.2.6" - -[[deps.IteratorInterfaceExtensions]] -git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" -uuid = "82899510-4779-5014-852e-03e436cf321d" -version = "1.0.0" - -[[deps.JLFzf]] -deps = ["REPL", "Random", "fzf_jll"] -git-tree-sha1 = "82f7acdc599b65e0f8ccd270ffa1467c21cb647b" -uuid = "1019f520-868f-41f5-a6de-eb00f4b6a39c" -version = "0.1.11" - -[[deps.JLLWrappers]] -deps = ["Artifacts", "Preferences"] -git-tree-sha1 = "0533e564aae234aff59ab625543145446d8b6ec2" -uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" -version = "1.7.1" - -[[deps.JSON]] -deps = ["Dates", "Logging", "Parsers", "PrecompileTools", "StructUtils", "UUIDs", "Unicode"] -git-tree-sha1 = "06ea418d0c95878c8f3031023951edcf25b9e0ef" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "1.2.0" - - [deps.JSON.extensions] - JSONArrowExt = ["ArrowTypes"] - - [deps.JSON.weakdeps] - ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd" - -[[deps.JpegTurbo_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "4255f0032eafd6451d707a51d5f0248b8a165e4d" -uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" -version = "3.1.3+0" - -[[deps.JuliaSyntaxHighlighting]] -deps = ["StyledStrings"] -uuid = "ac6e5ff7-fb65-4e79-a425-ec3bc9c03011" -version = "1.12.0" - -[[deps.KernelDensity]] -deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"] -git-tree-sha1 = "ba51324b894edaf1df3ab16e2cc6bc3280a2f1a7" -uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b" -version = "0.6.10" - -[[deps.LAME_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "059aabebaa7c82ccb853dd4a0ee9d17796f7e1bc" -uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" -version = "3.100.3+0" - -[[deps.LERC_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "aaafe88dccbd957a8d82f7d05be9b69172e0cee3" -uuid = "88015f11-f218-50d7-93a8-a6af411a945d" -version = "4.0.1+0" - -[[deps.LLVMOpenMP_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "eb62a3deb62fc6d8822c0c4bef73e4412419c5d8" -uuid = "1d63c593-3942-5779-bab2-d838dc0a180e" -version = "18.1.8+0" - -[[deps.LZO_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "1c602b1127f4751facb671441ca72715cc95938a" -uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" -version = "2.10.3+0" - -[[deps.LaTeXStrings]] -git-tree-sha1 = "dda21b8cbd6a6c40d9d02a73230f9d70fed6918c" -uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" -version = "1.4.0" - -[[deps.Latexify]] -deps = ["Format", "Ghostscript_jll", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Requires"] -git-tree-sha1 = "44f93c47f9cd6c7e431f2f2091fcba8f01cd7e8f" -uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" -version = "0.16.10" - - [deps.Latexify.extensions] - DataFramesExt = "DataFrames" - SparseArraysExt = "SparseArrays" - SymEngineExt = "SymEngine" - TectonicExt = "tectonic_jll" - - [deps.Latexify.weakdeps] - DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" - SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - SymEngine = "123dc426-2d89-5057-bbad-38513e3affd8" - tectonic_jll = "d7dd28d6-a5e6-559c-9131-7eb760cdacc5" - -[[deps.LazyArtifacts]] -deps = ["Artifacts", "Pkg"] -uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" -version = "1.11.0" - -[[deps.LibCURL]] -deps = ["LibCURL_jll", "MozillaCACerts_jll"] -uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" -version = "0.6.4" - -[[deps.LibCURL_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll", "Zlib_jll", "nghttp2_jll"] -uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "8.11.1+1" - -[[deps.LibGit2]] -deps = ["LibGit2_jll", "NetworkOptions", "Printf", "SHA"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" -version = "1.11.0" - -[[deps.LibGit2_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll"] -uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" -version = "1.9.0+0" - -[[deps.LibSSH2_jll]] -deps = ["Artifacts", "Libdl", "OpenSSL_jll"] -uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" -version = "1.11.3+1" - -[[deps.Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" -version = "1.11.0" - -[[deps.Libffi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "c8da7e6a91781c41a863611c7e966098d783c57a" -uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" -version = "3.4.7+0" - -[[deps.Libglvnd_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll", "Xorg_libXext_jll"] -git-tree-sha1 = "d36c21b9e7c172a44a10484125024495e2625ac0" -uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" -version = "1.7.1+1" - -[[deps.Libiconv_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "be484f5c92fad0bd8acfef35fe017900b0b73809" -uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" -version = "1.18.0+0" - -[[deps.Libmount_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "3acf07f130a76f87c041cfb2ff7d7284ca67b072" -uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" -version = "2.41.2+0" - -[[deps.Libtiff_jll]] -deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "XZ_jll", "Zlib_jll", "Zstd_jll"] -git-tree-sha1 = "f04133fe05eff1667d2054c53d59f9122383fe05" -uuid = "89763e89-9b03-5906-acba-b20f662cd828" -version = "4.7.2+0" - -[[deps.Libuuid_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "2a7a12fc0a4e7fb773450d17975322aa77142106" -uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" -version = "2.41.2+0" - -[[deps.LinearAlgebra]] -deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] -uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -version = "1.12.0" - -[[deps.LogExpFunctions]] -deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] -git-tree-sha1 = "13ca9e2586b89836fd20cccf56e57e2b9ae7f38f" -uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" -version = "0.3.29" - - [deps.LogExpFunctions.extensions] - LogExpFunctionsChainRulesCoreExt = "ChainRulesCore" - LogExpFunctionsChangesOfVariablesExt = "ChangesOfVariables" - LogExpFunctionsInverseFunctionsExt = "InverseFunctions" - - [deps.LogExpFunctions.weakdeps] - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - ChangesOfVariables = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" - InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" - -[[deps.Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" -version = "1.11.0" - -[[deps.LoggingExtras]] -deps = ["Dates", "Logging"] -git-tree-sha1 = "f00544d95982ea270145636c181ceda21c4e2575" -uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" -version = "1.2.0" - -[[deps.MKL_jll]] -deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "oneTBB_jll"] -git-tree-sha1 = "282cadc186e7b2ae0eeadbd7a4dffed4196ae2aa" -uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" -version = "2025.2.0+0" - -[[deps.MacroTools]] -git-tree-sha1 = "1e0228a030642014fe5cfe68c2c0a818f9e3f522" -uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -version = "0.5.16" - -[[deps.Markdown]] -deps = ["Base64", "JuliaSyntaxHighlighting", "StyledStrings"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" -version = "1.11.0" - -[[deps.MbedTLS]] -deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "NetworkOptions", "Random", "Sockets"] -git-tree-sha1 = "c067a280ddc25f196b5e7df3877c6b226d390aaf" -uuid = "739be429-bea8-5141-9913-cc70e7f3736d" -version = "1.1.9" - -[[deps.MbedTLS_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "3cce3511ca2c6f87b19c34ffc623417ed2798cbd" -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" -version = "2.28.10+0" - -[[deps.Measures]] -git-tree-sha1 = "c13304c81eec1ed3af7fc20e75fb6b26092a1102" -uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" -version = "0.3.2" - -[[deps.Missings]] -deps = ["DataAPI"] -git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d" -uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" -version = "1.2.0" - -[[deps.Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" -version = "1.11.0" - -[[deps.Mocking]] -deps = ["Compat", "ExprTools"] -git-tree-sha1 = "2c140d60d7cb82badf06d8783800d0bcd1a7daa2" -uuid = "78c3b35d-d492-501b-9361-3d52fe80e533" -version = "0.8.1" - -[[deps.MozillaCACerts_jll]] -uuid = "14a3606d-f60d-562e-9121-12d972cd8159" -version = "2025.5.20" - -[[deps.MultivariateStats]] -deps = ["Arpack", "Distributions", "LinearAlgebra", "SparseArrays", "Statistics", "StatsAPI", "StatsBase"] -git-tree-sha1 = "816620e3aac93e5b5359e4fdaf23ca4525b00ddf" -uuid = "6f286f6a-111f-5878-ab1e-185364afe411" -version = "0.10.3" - -[[deps.NaNMath]] -deps = ["OpenLibm_jll"] -git-tree-sha1 = "9b8215b1ee9e78a293f99797cd31375471b2bcae" -uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -version = "1.1.3" - -[[deps.NearestNeighbors]] -deps = ["Distances", "StaticArrays"] -git-tree-sha1 = "ca7e18198a166a1f3eb92a3650d53d94ed8ca8a1" -uuid = "b8a86587-4115-5ab1-83bc-aa920d37bbce" -version = "0.4.22" - -[[deps.NetworkOptions]] -uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" -version = "1.3.0" - -[[deps.Observables]] -git-tree-sha1 = "7438a59546cf62428fc9d1bc94729146d37a7225" -uuid = "510215fc-4207-5dde-b226-833fc4488ee2" -version = "0.5.5" - -[[deps.OffsetArrays]] -git-tree-sha1 = "117432e406b5c023f665fa73dc26e79ec3630151" -uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" -version = "1.17.0" -weakdeps = ["Adapt"] - - [deps.OffsetArrays.extensions] - OffsetArraysAdaptExt = "Adapt" - -[[deps.Ogg_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "b6aa4566bb7ae78498a5e68943863fa8b5231b59" -uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" -version = "1.3.6+0" - -[[deps.OpenBLAS_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] -uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" -version = "0.3.29+0" - -[[deps.OpenLibm_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.7+0" - -[[deps.OpenSSL]] -deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"] -git-tree-sha1 = "f1a7e086c677df53e064e0fdd2c9d0b0833e3f6e" -uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c" -version = "1.5.0" - -[[deps.OpenSSL_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "3.5.1+0" - -[[deps.OpenSpecFun_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "1346c9208249809840c91b26703912dff463d335" -uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" -version = "0.5.6+0" - -[[deps.Opus_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "c392fc5dd032381919e3b22dd32d6443760ce7ea" -uuid = "91d4177d-7536-5919-b921-800302f37372" -version = "1.5.2+0" - -[[deps.OrderedCollections]] -git-tree-sha1 = "05868e21324cede2207c6f0f466b4bfef6d5e7ee" -uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.8.1" - -[[deps.PCRE2_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" -version = "10.44.0+1" - -[[deps.PDMats]] -deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] -git-tree-sha1 = "d922b4d80d1e12c658da7785e754f4796cc1d60d" -uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" -version = "0.11.36" -weakdeps = ["StatsBase"] - - [deps.PDMats.extensions] - StatsBaseExt = "StatsBase" - -[[deps.Pango_jll]] -deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "FriBidi_jll", "Glib_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "1f7f9bbd5f7a2e5a9f7d96e51c9754454ea7f60b" -uuid = "36c8627f-9965-5494-a995-c6b170f724f3" -version = "1.56.4+0" - -[[deps.Parsers]] -deps = ["Dates", "PrecompileTools", "UUIDs"] -git-tree-sha1 = "7d2f8f21da5db6a806faf7b9b292296da42b2810" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.8.3" - -[[deps.Pixman_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "Libdl"] -git-tree-sha1 = "db76b1ecd5e9715f3d043cec13b2ec93ce015d53" -uuid = "30392449-352a-5448-841d-b1acce4e97dc" -version = "0.44.2+0" - -[[deps.Pkg]] -deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "Random", "SHA", "TOML", "Tar", "UUIDs", "p7zip_jll"] -uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" -version = "1.12.0" -weakdeps = ["REPL"] - - [deps.Pkg.extensions] - REPLExt = "REPL" - -[[deps.PlotThemes]] -deps = ["PlotUtils", "Statistics"] -git-tree-sha1 = "41031ef3a1be6f5bbbf3e8073f210556daeae5ca" -uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" -version = "3.3.0" - -[[deps.PlotUtils]] -deps = ["ColorSchemes", "Colors", "Dates", "PrecompileTools", "Printf", "Random", "Reexport", "StableRNGs", "Statistics"] -git-tree-sha1 = "3ca9a356cd2e113c420f2c13bea19f8d3fb1cb18" -uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" -version = "1.4.3" - -[[deps.Plots]] -deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "JLFzf", "JSON", "LaTeXStrings", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "PrecompileTools", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "RelocatableFolders", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "TOML", "UUIDs", "UnicodeFun", "Unzip"] -git-tree-sha1 = "12ce661880f8e309569074a61d3767e5756a199f" -uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -version = "1.41.1" - - [deps.Plots.extensions] - FileIOExt = "FileIO" - GeometryBasicsExt = "GeometryBasics" - IJuliaExt = "IJulia" - ImageInTerminalExt = "ImageInTerminal" - UnitfulExt = "Unitful" - - [deps.Plots.weakdeps] - FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" - GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" - IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" - ImageInTerminal = "d8c32880-2388-543b-8c61-d9f865259254" - Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" - -[[deps.PooledArrays]] -deps = ["DataAPI", "Future"] -git-tree-sha1 = "36d8b4b899628fb92c2749eb488d884a926614d3" -uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" -version = "1.4.3" - -[[deps.PrecompileTools]] -deps = ["Preferences"] -git-tree-sha1 = "07a921781cab75691315adc645096ed5e370cb77" -uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" -version = "1.3.3" - -[[deps.Preferences]] -deps = ["TOML"] -git-tree-sha1 = "0f27480397253da18fe2c12a4ba4eb9eb208bf3d" -uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.5.0" - -[[deps.PrettyTables]] -deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "REPL", "Reexport", "StringManipulation", "Tables"] -git-tree-sha1 = "6b8e2f0bae3f678811678065c09571c1619da219" -uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" -version = "3.1.0" - -[[deps.Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" -version = "1.11.0" - -[[deps.PtrArrays]] -git-tree-sha1 = "1d36ef11a9aaf1e8b74dacc6a731dd1de8fd493d" -uuid = "43287f4e-b6f4-7ad1-bb20-aadabca52c3d" -version = "1.3.0" - -[[deps.Qt6Base_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Vulkan_Loader_jll", "Xorg_libSM_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_cursor_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "libinput_jll", "xkbcommon_jll"] -git-tree-sha1 = "34f7e5d2861083ec7596af8b8c092531facf2192" -uuid = "c0090381-4147-56d7-9ebc-da0b1113ec56" -version = "6.8.2+2" - -[[deps.Qt6Declarative_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Qt6Base_jll", "Qt6ShaderTools_jll"] -git-tree-sha1 = "da7adf145cce0d44e892626e647f9dcbe9cb3e10" -uuid = "629bc702-f1f5-5709-abd5-49b8460ea067" -version = "6.8.2+1" - -[[deps.Qt6ShaderTools_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Qt6Base_jll"] -git-tree-sha1 = "9eca9fc3fe515d619ce004c83c31ffd3f85c7ccf" -uuid = "ce943373-25bb-56aa-8eca-768745ed7b5a" -version = "6.8.2+1" - -[[deps.Qt6Wayland_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Qt6Base_jll", "Qt6Declarative_jll"] -git-tree-sha1 = "8f528b0851b5b7025032818eb5abbeb8a736f853" -uuid = "e99dba38-086e-5de3-a5b1-6e4c66e897c3" -version = "6.8.2+2" - -[[deps.QuadGK]] -deps = ["DataStructures", "LinearAlgebra"] -git-tree-sha1 = "9da16da70037ba9d701192e27befedefb91ec284" -uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" -version = "2.11.2" - - [deps.QuadGK.extensions] - QuadGKEnzymeExt = "Enzyme" - - [deps.QuadGK.weakdeps] - Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" - -[[deps.RData]] -deps = ["CategoricalArrays", "CodecZlib", "DataFrames", "Dates", "FileIO", "Requires", "TimeZones", "Unicode"] -git-tree-sha1 = "19e47a495dfb7240eb44dc6971d660f7e4244a72" -uuid = "df47a6cb-8c03-5eed-afd8-b6050d6c41da" -version = "0.8.3" - -[[deps.RDatasets]] -deps = ["CSV", "CodecZlib", "DataFrames", "FileIO", "Printf", "RData", "Reexport"] -git-tree-sha1 = "2720e6f6afb3e562ccb70a6b62f8f308ff810333" -uuid = "ce6b1742-4840-55fa-b093-852dadbb1d8b" -version = "0.7.7" - -[[deps.REPL]] -deps = ["InteractiveUtils", "JuliaSyntaxHighlighting", "Markdown", "Sockets", "StyledStrings", "Unicode"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" -version = "1.11.0" - -[[deps.Random]] -deps = ["SHA"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -version = "1.11.0" - -[[deps.Ratios]] -deps = ["Requires"] -git-tree-sha1 = "1342a47bf3260ee108163042310d26f2be5ec90b" -uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439" -version = "0.4.5" -weakdeps = ["FixedPointNumbers"] - - [deps.Ratios.extensions] - RatiosFixedPointNumbersExt = "FixedPointNumbers" - -[[deps.RecipesBase]] -deps = ["PrecompileTools"] -git-tree-sha1 = "5c3d09cc4f31f5fc6af001c250bf1278733100ff" -uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" -version = "1.3.4" - -[[deps.RecipesPipeline]] -deps = ["Dates", "NaNMath", "PlotUtils", "PrecompileTools", "RecipesBase"] -git-tree-sha1 = "45cf9fd0ca5839d06ef333c8201714e888486342" -uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" -version = "0.6.12" - -[[deps.Reexport]] -git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" -uuid = "189a3867-3050-52da-a836-e630ba90ab69" -version = "1.2.2" - -[[deps.RelocatableFolders]] -deps = ["SHA", "Scratch"] -git-tree-sha1 = "ffdaf70d81cf6ff22c2b6e733c900c3321cab864" -uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" -version = "1.0.1" - -[[deps.Requires]] -deps = ["UUIDs"] -git-tree-sha1 = "62389eeff14780bfe55195b7204c0d8738436d64" -uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.3.1" - -[[deps.Rmath]] -deps = ["Random", "Rmath_jll"] -git-tree-sha1 = "5b3d50eb374cea306873b371d3f8d3915a018f0b" -uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" -version = "0.9.0" - -[[deps.Rmath_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "58cdd8fb2201a6267e1db87ff148dd6c1dbd8ad8" -uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" -version = "0.5.1+0" - -[[deps.SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" -version = "0.7.0" - -[[deps.Scratch]] -deps = ["Dates"] -git-tree-sha1 = "9b81b8393e50b7d4e6d0a9f14e192294d3b7c109" -uuid = "6c6a2e73-6563-6170-7368-637461726353" -version = "1.3.0" - -[[deps.SentinelArrays]] -deps = ["Dates", "Random"] -git-tree-sha1 = "712fb0231ee6f9120e005ccd56297abbc053e7e0" -uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" -version = "1.4.8" - -[[deps.Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" -version = "1.11.0" - -[[deps.SharedArrays]] -deps = ["Distributed", "Mmap", "Random", "Serialization"] -uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" -version = "1.11.0" - -[[deps.Showoff]] -deps = ["Dates", "Grisu"] -git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" -uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" -version = "1.0.3" - -[[deps.SimpleBufferStream]] -git-tree-sha1 = "f305871d2f381d21527c770d4788c06c097c9bc1" -uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7" -version = "1.2.0" - -[[deps.Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" -version = "1.11.0" - -[[deps.SortingAlgorithms]] -deps = ["DataStructures"] -git-tree-sha1 = "64d974c2e6fdf07f8155b5b2ca2ffa9069b608d9" -uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" -version = "1.2.2" - -[[deps.SparseArrays]] -deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] -uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -version = "1.12.0" - -[[deps.SpecialFunctions]] -deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] -git-tree-sha1 = "f2685b435df2613e25fc10ad8c26dddb8640f547" -uuid = "276daf66-3868-5448-9aa4-cd146d93841b" -version = "2.6.1" -weakdeps = ["ChainRulesCore"] - - [deps.SpecialFunctions.extensions] - SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" - -[[deps.StableRNGs]] -deps = ["Random"] -git-tree-sha1 = "95af145932c2ed859b63329952ce8d633719f091" -uuid = "860ef19b-820b-49d6-a774-d7a799459cd3" -version = "1.0.3" - -[[deps.StaticArrays]] -deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"] -git-tree-sha1 = "b8693004b385c842357406e3af647701fe783f98" -uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.9.15" -weakdeps = ["ChainRulesCore", "Statistics"] - - [deps.StaticArrays.extensions] - StaticArraysChainRulesCoreExt = "ChainRulesCore" - StaticArraysStatisticsExt = "Statistics" - -[[deps.StaticArraysCore]] -git-tree-sha1 = "6ab403037779dae8c514bad259f32a447262455a" -uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" -version = "1.4.4" - -[[deps.Statistics]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "ae3bb1eb3bba077cd276bc5cfc337cc65c3075c0" -uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" -version = "1.11.1" -weakdeps = ["SparseArrays"] - - [deps.Statistics.extensions] - SparseArraysExt = ["SparseArrays"] - -[[deps.StatsAPI]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "9d72a13a3f4dd3795a195ac5a44d7d6ff5f552ff" -uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" -version = "1.7.1" - -[[deps.StatsBase]] -deps = ["AliasTables", "DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] -git-tree-sha1 = "a136f98cefaf3e2924a66bd75173d1c891ab7453" -uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -version = "0.34.7" - -[[deps.StatsFuns]] -deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] -git-tree-sha1 = "91f091a8716a6bb38417a6e6f274602a19aaa685" -uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" -version = "1.5.2" - - [deps.StatsFuns.extensions] - StatsFunsChainRulesCoreExt = "ChainRulesCore" - StatsFunsInverseFunctionsExt = "InverseFunctions" - - [deps.StatsFuns.weakdeps] - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" - -[[deps.StatsPlots]] -deps = ["AbstractFFTs", "Clustering", "DataStructures", "Distributions", "Interpolations", "KernelDensity", "LinearAlgebra", "MultivariateStats", "NaNMath", "Observables", "Plots", "RecipesBase", "RecipesPipeline", "Reexport", "StatsBase", "TableOperations", "Tables", "Widgets"] -git-tree-sha1 = "88cf3587711d9ad0a55722d339a013c4c56c5bbc" -uuid = "f3b207a7-027a-5e70-b257-86293d7955fd" -version = "0.15.8" - -[[deps.StringManipulation]] -deps = ["PrecompileTools"] -git-tree-sha1 = "725421ae8e530ec29bcbdddbe91ff8053421d023" -uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" -version = "0.4.1" - -[[deps.StructUtils]] -deps = ["Dates", "UUIDs"] -git-tree-sha1 = "cd47aa083c9c7bdeb7b92de26deb46d6a33163c9" -uuid = "ec057cc2-7a8d-4b58-b3b3-92acb9f63b42" -version = "2.5.1" - - [deps.StructUtils.extensions] - StructUtilsMeasurementsExt = ["Measurements"] - StructUtilsTablesExt = ["Tables"] - - [deps.StructUtils.weakdeps] - Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" - Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" - -[[deps.StyledStrings]] -uuid = "f489334b-da3d-4c2e-b8f0-e476e12c162b" -version = "1.11.0" - -[[deps.SuiteSparse]] -deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] -uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" - -[[deps.SuiteSparse_jll]] -deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] -uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" -version = "7.8.3+2" - -[[deps.TOML]] -deps = ["Dates"] -uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" -version = "1.0.3" - -[[deps.TZJData]] -deps = ["Artifacts"] -git-tree-sha1 = "72df96b3a595b7aab1e101eb07d2a435963a97e2" -uuid = "dc5dba14-91b3-4cab-a142-028a31da12f7" -version = "1.5.0+2025b" - -[[deps.TableOperations]] -deps = ["SentinelArrays", "Tables", "Test"] -git-tree-sha1 = "e383c87cf2a1dc41fa30c093b2a19877c83e1bc1" -uuid = "ab02a1b2-a7df-11e8-156e-fb1833f50b87" -version = "1.2.0" - -[[deps.TableTraits]] -deps = ["IteratorInterfaceExtensions"] -git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" -uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" -version = "1.0.1" - -[[deps.Tables]] -deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "OrderedCollections", "TableTraits"] -git-tree-sha1 = "f2c1efbc8f3a609aadf318094f8fc5204bdaf344" -uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" -version = "1.12.1" - -[[deps.Tar]] -deps = ["ArgTools", "SHA"] -uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" -version = "1.10.0" - -[[deps.TensorCore]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" -uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" -version = "0.1.1" - -[[deps.Test]] -deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -version = "1.11.0" - -[[deps.TimeZones]] -deps = ["Artifacts", "Dates", "Downloads", "InlineStrings", "Mocking", "Printf", "Scratch", "TZJData", "Unicode", "p7zip_jll"] -git-tree-sha1 = "06f4f1f3e8ff09e42e59b043a747332e88e01aba" -uuid = "f269a46b-ccf7-5d73-abea-4c690281aa53" -version = "1.22.1" -weakdeps = ["RecipesBase"] - - [deps.TimeZones.extensions] - TimeZonesRecipesBaseExt = "RecipesBase" - -[[deps.TranscodingStreams]] -git-tree-sha1 = "0c45878dcfdcfa8480052b6ab162cdd138781742" -uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" -version = "0.11.3" - -[[deps.URIs]] -git-tree-sha1 = "bef26fb046d031353ef97a82e3fdb6afe7f21b1a" -uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" -version = "1.6.1" - -[[deps.UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" -version = "1.11.0" - -[[deps.Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" -version = "1.11.0" - -[[deps.UnicodeFun]] -deps = ["REPL"] -git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" -uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" -version = "0.4.1" - -[[deps.Unzip]] -git-tree-sha1 = "ca0969166a028236229f63514992fc073799bb78" -uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d" -version = "0.2.0" - -[[deps.Vulkan_Loader_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Wayland_jll", "Xorg_libX11_jll", "Xorg_libXrandr_jll", "xkbcommon_jll"] -git-tree-sha1 = "2f0486047a07670caad3a81a075d2e518acc5c59" -uuid = "a44049a8-05dd-5a78-86c9-5fde0876e88c" -version = "1.3.243+0" - -[[deps.Wayland_jll]] -deps = ["Artifacts", "EpollShim_jll", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll"] -git-tree-sha1 = "96478df35bbc2f3e1e791bc7a3d0eeee559e60e9" -uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" -version = "1.24.0+0" - -[[deps.WeakRefStrings]] -deps = ["DataAPI", "InlineStrings", "Parsers"] -git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23" -uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5" -version = "1.4.2" - -[[deps.Widgets]] -deps = ["Colors", "Dates", "Observables", "OrderedCollections"] -git-tree-sha1 = "e9aeb174f95385de31e70bd15fa066a505ea82b9" -uuid = "cc8bc4a8-27d6-5769-a93b-9d913e69aa62" -version = "0.6.7" - -[[deps.WoodburyMatrices]] -deps = ["LinearAlgebra", "SparseArrays"] -git-tree-sha1 = "c1a7aa6219628fcd757dede0ca95e245c5cd9511" -uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6" -version = "1.0.0" - -[[deps.WorkerUtilities]] -git-tree-sha1 = "cd1659ba0d57b71a464a29e64dbc67cfe83d54e7" -uuid = "76eceee3-57b5-4d4a-8e66-0e911cebbf60" -version = "1.6.1" - -[[deps.XZ_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "fee71455b0aaa3440dfdd54a9a36ccef829be7d4" -uuid = "ffd25f8a-64ca-5728-b0f7-c24cf3aae800" -version = "5.8.1+0" - -[[deps.Xorg_libICE_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "a3ea76ee3f4facd7a64684f9af25310825ee3668" -uuid = "f67eecfb-183a-506d-b269-f58e52b52d7c" -version = "1.1.2+0" - -[[deps.Xorg_libSM_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libICE_jll"] -git-tree-sha1 = "9c7ad99c629a44f81e7799eb05ec2746abb5d588" -uuid = "c834827a-8449-5923-a945-d239c165b7dd" -version = "1.2.6+0" - -[[deps.Xorg_libX11_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] -git-tree-sha1 = "b5899b25d17bf1889d25906fb9deed5da0c15b3b" -uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" -version = "1.8.12+0" - -[[deps.Xorg_libXau_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "aa1261ebbac3ccc8d16558ae6799524c450ed16b" -uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" -version = "1.0.13+0" - -[[deps.Xorg_libXcursor_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] -git-tree-sha1 = "6c74ca84bbabc18c4547014765d194ff0b4dc9da" -uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" -version = "1.2.4+0" - -[[deps.Xorg_libXdmcp_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "52858d64353db33a56e13c341d7bf44cd0d7b309" -uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" -version = "1.1.6+0" - -[[deps.Xorg_libXext_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "a4c0ee07ad36bf8bbce1c3bb52d21fb1e0b987fb" -uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" -version = "1.3.7+0" - -[[deps.Xorg_libXfixes_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "75e00946e43621e09d431d9b95818ee751e6b2ef" -uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" -version = "6.0.2+0" - -[[deps.Xorg_libXi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] -git-tree-sha1 = "a376af5c7ae60d29825164db40787f15c80c7c54" -uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" -version = "1.8.3+0" - -[[deps.Xorg_libXinerama_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXext_jll"] -git-tree-sha1 = "a5bc75478d323358a90dc36766f3c99ba7feb024" -uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" -version = "1.1.6+0" - -[[deps.Xorg_libXrandr_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXext_jll", "Xorg_libXrender_jll"] -git-tree-sha1 = "aff463c82a773cb86061bce8d53a0d976854923e" -uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" -version = "1.5.5+0" - -[[deps.Xorg_libXrender_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "7ed9347888fac59a618302ee38216dd0379c480d" -uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" -version = "0.9.12+0" - -[[deps.Xorg_libxcb_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXau_jll", "Xorg_libXdmcp_jll"] -git-tree-sha1 = "bfcaf7ec088eaba362093393fe11aa141fa15422" -uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" -version = "1.17.1+0" - -[[deps.Xorg_libxkbfile_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "e3150c7400c41e207012b41659591f083f3ef795" -uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" -version = "1.1.3+0" - -[[deps.Xorg_xcb_util_cursor_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_jll", "Xorg_xcb_util_renderutil_jll"] -git-tree-sha1 = "9750dc53819eba4e9a20be42349a6d3b86c7cdf8" -uuid = "e920d4aa-a673-5f3a-b3d7-f755a4d47c43" -version = "0.1.6+0" - -[[deps.Xorg_xcb_util_image_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_jll"] -git-tree-sha1 = "f4fc02e384b74418679983a97385644b67e1263b" -uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" -version = "0.4.1+0" - -[[deps.Xorg_xcb_util_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll"] -git-tree-sha1 = "68da27247e7d8d8dafd1fcf0c3654ad6506f5f97" -uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" -version = "0.4.1+0" - -[[deps.Xorg_xcb_util_keysyms_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_jll"] -git-tree-sha1 = "44ec54b0e2acd408b0fb361e1e9244c60c9c3dd4" -uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" -version = "0.4.1+0" - -[[deps.Xorg_xcb_util_renderutil_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_jll"] -git-tree-sha1 = "5b0263b6d080716a02544c55fdff2c8d7f9a16a0" -uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" -version = "0.3.10+0" - -[[deps.Xorg_xcb_util_wm_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_jll"] -git-tree-sha1 = "f233c83cad1fa0e70b7771e0e21b061a116f2763" -uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" -version = "0.4.2+0" - -[[deps.Xorg_xkbcomp_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxkbfile_jll"] -git-tree-sha1 = "801a858fc9fb90c11ffddee1801bb06a738bda9b" -uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" -version = "1.4.7+0" - -[[deps.Xorg_xkeyboard_config_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xkbcomp_jll"] -git-tree-sha1 = "00af7ebdc563c9217ecc67776d1bbf037dbcebf4" -uuid = "33bec58e-1273-512f-9401-5d533626f822" -version = "2.44.0+0" - -[[deps.Xorg_xtrans_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "a63799ff68005991f9d9491b6e95bd3478d783cb" -uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" -version = "1.6.0+0" - -[[deps.Zlib_jll]] -deps = ["Libdl"] -uuid = "83775a58-1f1d-513f-b197-d71354ab007a" -version = "1.3.1+2" - -[[deps.Zstd_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "446b23e73536f84e8037f5dce465e92275f6a308" -uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" -version = "1.5.7+1" - -[[deps.eudev_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "c3b0e6196d50eab0c5ed34021aaa0bb463489510" -uuid = "35ca27e7-8b34-5b7f-bca9-bdc33f59eb06" -version = "3.2.14+0" - -[[deps.fzf_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "b6a34e0e0960190ac2a4363a1bd003504772d631" -uuid = "214eeab7-80f7-51ab-84ad-2988db7cef09" -version = "0.61.1+0" - -[[deps.libaom_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "371cc681c00a3ccc3fbc5c0fb91f58ba9bec1ecf" -uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" -version = "3.13.1+0" - -[[deps.libass_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "125eedcb0a4a0bba65b657251ce1d27c8714e9d6" -uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" -version = "0.17.4+0" - -[[deps.libblastrampoline_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" -version = "5.15.0+0" - -[[deps.libdecor_jll]] -deps = ["Artifacts", "Dbus_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pango_jll", "Wayland_jll", "xkbcommon_jll"] -git-tree-sha1 = "9bf7903af251d2050b467f76bdbe57ce541f7f4f" -uuid = "1183f4f0-6f2a-5f1a-908b-139f9cdfea6f" -version = "0.2.2+0" - -[[deps.libevdev_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "56d643b57b188d30cccc25e331d416d3d358e557" -uuid = "2db6ffa8-e38f-5e21-84af-90c45d0032cc" -version = "1.13.4+0" - -[[deps.libfdk_aac_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "646634dd19587a56ee2f1199563ec056c5f228df" -uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" -version = "2.0.4+0" - -[[deps.libinput_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "eudev_jll", "libevdev_jll", "mtdev_jll"] -git-tree-sha1 = "91d05d7f4a9f67205bd6cf395e488009fe85b499" -uuid = "36db933b-70db-51c0-b978-0f229ee0e533" -version = "1.28.1+0" - -[[deps.libpng_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "07b6a107d926093898e82b3b1db657ebe33134ec" -uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" -version = "1.6.50+0" - -[[deps.libvorbis_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll"] -git-tree-sha1 = "11e1772e7f3cc987e9d3de991dd4f6b2602663a5" -uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" -version = "1.3.8+0" - -[[deps.mtdev_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "b4d631fd51f2e9cdd93724ae25b2efc198b059b1" -uuid = "009596ad-96f7-51b1-9f1b-5ce2d5e8a71e" -version = "1.1.7+0" - -[[deps.nghttp2_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" -version = "1.64.0+1" - -[[deps.oneTBB_jll]] -deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl"] -git-tree-sha1 = "1350188a69a6e46f799d3945beef36435ed7262f" -uuid = "1317d2d5-d96f-522e-a858-c73665f53c3e" -version = "2022.0.0+1" - -[[deps.p7zip_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" -version = "17.5.0+2" - -[[deps.x264_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "14cc7083fc6dff3cc44f2bc435ee96d06ed79aa7" -uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" -version = "10164.0.1+0" - -[[deps.x265_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "e7b67590c14d487e734dcb925924c5dc43ec85f3" -uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" -version = "4.1.0+0" - -[[deps.xkbcommon_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] -git-tree-sha1 = "fbf139bce07a534df0e699dbb5f5cc9346f95cc1" -uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" -version = "1.9.2+0" diff --git a/Project.toml b/Project.toml deleted file mode 100644 index f7efb7ebea7..00000000000 --- a/Project.toml +++ /dev/null @@ -1,4 +0,0 @@ -[deps] -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b" -StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" diff --git a/README.md b/README.md index 54d01bb0f1c..a538615ec58 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,6 @@ -# engine extension for julia in quarto +# Julia engine extension for quarto -Quarto will introduce engine extensions in 1.9, and this is an experimental port of Quarto's Julia engine to the new architecture. - -Install it with - -``` -quarto add gordonwoodhull/quarto-julia-engine -``` - -You'll need the `feature/engine-extension-3` branch of Quarto, until it's merged. +Quarto's Julia engine, extracted from quarto-cli into a standalone engine extension. It was originally built directly into quarto-cli and is now pulled back in via a git subtree. ## Development diff --git a/_extensions/julia-engine/Project.toml b/_extensions/julia-engine/Project.toml new file mode 100644 index 00000000000..94def5bfc2f --- /dev/null +++ b/_extensions/julia-engine/Project.toml @@ -0,0 +1,5 @@ +[deps] +QuartoNotebookRunner = "4c0109c6-14e9-4c88-93f0-2b974d3468f4" + +[compat] +QuartoNotebookRunner = "=0.17.4" diff --git a/_extensions/julia-engine/ensure_environment.jl b/_extensions/julia-engine/ensure_environment.jl new file mode 100644 index 00000000000..3274a230f8b --- /dev/null +++ b/_extensions/julia-engine/ensure_environment.jl @@ -0,0 +1,32 @@ +using Pkg +using TOML + +# If the manifest was resolved with the exact Project.toml that we have copied +# over from quarto's resource folder, then we just ensure that it is instantiated, +# all packages are downloaded correctly, etc. +# Otherwise, we update to get the newest packages fulfilling the compat bounds set in +# the Project.toml. + +function manifest_has_correct_julia_version() + project_file = Base.active_project() + manifest_file = joinpath(dirname(project_file), "Manifest.toml") + version = VersionNumber(TOML.parsefile(manifest_file)["julia_version"]) + return version.major == VERSION.major && version.minor == VERSION.minor +end + +is_manifest_current = @static if VERSION < v"1.11.0-DEV.1135" + Pkg.is_manifest_current() +else + Pkg.is_manifest_current(dirname(Base.active_project())) +end + +manifest_matches_project_toml = is_manifest_current === true # this returns nothing if there's no manifest + +if manifest_matches_project_toml && manifest_has_correct_julia_version() + Pkg.instantiate() +else + Pkg.update() +end +# not strictly necessary, but in case of precompilation errors this will +# actually print them out explicitly +Pkg.precompile() diff --git a/_extensions/julia-engine/julia-engine.js b/_extensions/julia-engine/julia-engine.js index 04c4f0a11d3..d3a33c0f9ac 100644 --- a/_extensions/julia-engine/julia-engine.js +++ b/_extensions/julia-engine/julia-engine.js @@ -8,6 +8,22 @@ function assertPath(path) { } } +// deno:https://jsr.io/@std/path/1.0.8/_common/strip_trailing_separators.ts +function stripTrailingSeparators(segment, isSep) { + if (segment.length <= 1) { + return segment; + } + let end = segment.length; + for (let i = segment.length - 1; i > 0; i--) { + if (isSep(segment.charCodeAt(i))) { + end = i; + } else { + break; + } + } + return segment.slice(0, end); +} + // deno:https://jsr.io/@std/path/1.0.8/_common/constants.ts var CHAR_UPPERCASE_A = 65; var CHAR_LOWERCASE_A = 97; @@ -24,6 +40,9 @@ function isPosixPathSeparator(code) { } // deno:https://jsr.io/@std/path/1.0.8/windows/_util.ts +function isPosixPathSeparator2(code) { + return code === CHAR_FORWARD_SLASH; +} function isPathSeparator(code) { return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; } @@ -31,6 +50,133 @@ function isWindowsDeviceRoot(code) { return code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z || code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z; } +// deno:https://jsr.io/@std/path/1.0.8/_common/dirname.ts +function assertArg(path) { + assertPath(path); + if (path.length === 0) return "."; +} + +// deno:https://jsr.io/@std/path/1.0.8/posix/dirname.ts +function dirname(path) { + assertArg(path); + let end = -1; + let matchedNonSeparator = false; + for (let i = path.length - 1; i >= 1; --i) { + if (isPosixPathSeparator(path.charCodeAt(i))) { + if (matchedNonSeparator) { + end = i; + break; + } + } else { + matchedNonSeparator = true; + } + } + if (end === -1) { + return isPosixPathSeparator(path.charCodeAt(0)) ? "/" : "."; + } + return stripTrailingSeparators(path.slice(0, end), isPosixPathSeparator); +} + +// deno:https://jsr.io/@std/path/1.0.8/windows/dirname.ts +function dirname2(path) { + assertArg(path); + const len = path.length; + let rootEnd = -1; + let end = -1; + let matchedSlash = true; + let offset = 0; + const code = path.charCodeAt(0); + if (len > 1) { + if (isPathSeparator(code)) { + rootEnd = offset = 1; + if (isPathSeparator(path.charCodeAt(1))) { + let j = 2; + let last = j; + for (; j < len; ++j) { + if (isPathSeparator(path.charCodeAt(j))) break; + } + if (j < len && j !== last) { + last = j; + for (; j < len; ++j) { + if (!isPathSeparator(path.charCodeAt(j))) break; + } + if (j < len && j !== last) { + last = j; + for (; j < len; ++j) { + if (isPathSeparator(path.charCodeAt(j))) break; + } + if (j === len) { + return path; + } + if (j !== last) { + rootEnd = offset = j + 1; + } + } + } + } + } else if (isWindowsDeviceRoot(code)) { + if (path.charCodeAt(1) === CHAR_COLON) { + rootEnd = offset = 2; + if (len > 2) { + if (isPathSeparator(path.charCodeAt(2))) rootEnd = offset = 3; + } + } + } + } else if (isPathSeparator(code)) { + return path; + } + for (let i = len - 1; i >= offset; --i) { + if (isPathSeparator(path.charCodeAt(i))) { + if (!matchedSlash) { + end = i; + break; + } + } else { + matchedSlash = false; + } + } + if (end === -1) { + if (rootEnd === -1) return "."; + else end = rootEnd; + } + return stripTrailingSeparators(path.slice(0, end), isPosixPathSeparator2); +} + +// deno:https://jsr.io/@std/path/1.0.8/dirname.ts +function dirname3(path) { + return isWindows ? dirname2(path) : dirname(path); +} + +// deno:https://jsr.io/@std/path/1.0.8/_common/from_file_url.ts +function assertArg3(url) { + url = url instanceof URL ? url : new URL(url); + if (url.protocol !== "file:") { + throw new TypeError(`URL must be a file URL: received "${url.protocol}"`); + } + return url; +} + +// deno:https://jsr.io/@std/path/1.0.8/posix/from_file_url.ts +function fromFileUrl(url) { + url = assertArg3(url); + return decodeURIComponent(url.pathname.replace(/%(?![0-9A-Fa-f]{2})/g, "%25")); +} + +// deno:https://jsr.io/@std/path/1.0.8/windows/from_file_url.ts +function fromFileUrl2(url) { + url = assertArg3(url); + let path = decodeURIComponent(url.pathname.replace(/\//g, "\\").replace(/%(?![0-9A-Fa-f]{2})/g, "%25")).replace(/^\\*([A-Za-z]:)(\\|$)/, "$1\\"); + if (url.hostname !== "") { + path = `\\\\${url.hostname}${path}`; + } + return path; +} + +// deno:https://jsr.io/@std/path/1.0.8/from_file_url.ts +function fromFileUrl3(url) { + return isWindows ? fromFileUrl2(url) : fromFileUrl(url); +} + // deno:https://jsr.io/@std/path/1.0.8/_common/normalize.ts function assertArg4(path) { assertPath(path); @@ -488,6 +634,7 @@ var kKeepHidden = "keep-hidden"; // src/julia-engine.ts var isWindows2 = Deno.build.os === "windows"; +var extensionDir = dirname3(fromFileUrl3(import.meta.url)); var quarto; function safeRemoveSync(file, options = {}) { try { @@ -716,7 +863,7 @@ async function startOrReuseJuliaServer(options) { "Start-Process", juliaCmd(), "-ArgumentList", - powershell_argument_list_to_string("--startup-file=no", `--project=${juliaProject}`, quarto.path.resource("julia", "quartonotebookrunner.jl"), transportFile, juliaServerLogFile()), + powershell_argument_list_to_string("--startup-file=no", `--project=${juliaProject}`, join3(extensionDir, "quartonotebookrunner.jl"), transportFile, juliaServerLogFile()), "-WindowStyle", "Hidden" ], @@ -733,10 +880,10 @@ async function startOrReuseJuliaServer(options) { const command = new Deno.Command(juliaCmd(), { args: [ "--startup-file=no", - quarto.path.resource("julia", "start_quartonotebookrunner_detached.jl"), + join3(extensionDir, "start_quartonotebookrunner_detached.jl"), juliaCmd(), juliaProject, - quarto.path.resource("julia", "quartonotebookrunner.jl"), + join3(extensionDir, "quartonotebookrunner.jl"), transportFile, juliaServerLogFile() ], @@ -762,14 +909,14 @@ async function startOrReuseJuliaServer(options) { } async function ensureQuartoNotebookRunnerEnvironment(options) { const runtimeDir = quarto.path.runtime("julia"); - const projectTomlTemplate = quarto.path.resource("julia", "Project.toml"); + const projectTomlTemplate = join3(extensionDir, "Project.toml"); const projectToml = join3(runtimeDir, "Project.toml"); Deno.writeFileSync(projectToml, Deno.readFileSync(projectTomlTemplate)); const command = new Deno.Command(juliaCmd(), { args: [ "--startup-file=no", `--project=${runtimeDir}`, - quarto.path.resource("julia", "ensure_environment.jl") + join3(extensionDir, "ensure_environment.jl") ] }); const proc = command.spawn(); diff --git a/_extensions/julia-engine/quartonotebookrunner.jl b/_extensions/julia-engine/quartonotebookrunner.jl new file mode 100644 index 00000000000..d2a394da981 --- /dev/null +++ b/_extensions/julia-engine/quartonotebookrunner.jl @@ -0,0 +1,57 @@ +logfile = ARGS[2] +filehandle = open(logfile, "w") + +# We cannot start Julia in a way such that it uses line buffering or no buffering (see https://github.com/JuliaLang/julia/issues/13050) +# which means that if we just redirect all its output into a logfile (for example with `pipeline(julia_cmd, stdout = logfile)`) +# it will not actually write to the logfile until the buffer is filled or it's explicitly flushed, which can take a while. +# So when we check the logfile, we don't actually see anything if the buffer is not filled first, which +# may never be if there's little output. So instead we redirect stdout and stderr to a pipe which we manually check +# for available data in shorter intervals. We then write the data to the logfile and flush. + +pipe = Pipe() +pipe_with_color = IOContext(pipe, :color => Base.get_have_color()) +redirect_stdout(pipe_with_color) +redirect_stderr(pipe_with_color) + +function update_logfile() + data = readavailable(pipe) + if !isempty(data) + write(filehandle, data) + flush(filehandle) + end + return +end + +@async while true + update_logfile() + sleep(1) +end + +# we might lose printout from crashes if we don't do another update at the end +atexit() do + update_logfile() +end + +using Dates: now +@info "Log started at $(now())" + +using QuartoNotebookRunner +using Sockets + +transport_file = ARGS[1] +transport_dir = dirname(transport_file) + +atexit() do + rm(transport_file; force=true) +end + +server = QuartoNotebookRunner.serve(; timeout = 300) +port = server.port + +open(transport_file, "w") do io + println(io, """{"port": $port, "pid": $(Base.Libc.getpid()), "key": "$(server.key)"}""") +end + +@info "Starting server at $(now())" +wait(server) +@info "Server stopped at $(now())" diff --git a/_extensions/julia-engine/start_quartonotebookrunner_detached.jl b/_extensions/julia-engine/start_quartonotebookrunner_detached.jl new file mode 100644 index 00000000000..3771ca52322 --- /dev/null +++ b/_extensions/julia-engine/start_quartonotebookrunner_detached.jl @@ -0,0 +1,17 @@ +# it appears that deno cannot launch detached processes https://github.com/denoland/deno/issues/5501 +# so we use an indirection where we start the detached julia process using julia itself +julia_bin = ARGS[1] +project = ARGS[2] +julia_file = ARGS[3] +transport_file = ARGS[4] +logfile = ARGS[5] + +if length(ARGS) > 5 + error("Too many arguments") +end + +env = copy(ENV) +env["JULIA_LOAD_PATH"] = "@:@stdlib" # ignore the main env +cmd = `$julia_bin --startup-file=no --project=$project $julia_file $transport_file $logfile` +cmd = setenv(cmd, env) +run(detach(cmd), wait = false) diff --git a/example.qmd b/example.qmd deleted file mode 100644 index 449ad1232eb..00000000000 --- a/example.qmd +++ /dev/null @@ -1,80 +0,0 @@ ---- -title: "Julia Violin Plots Example" -author: us.anthropic.claude-sonnet-4-5-20250929-v1:0 -format: - html: - code-fold: true - fig-width: 7 - fig-height: 5 - fig-format: svg - fig-responsive: true - html-math-method: katex - code-tools: true -engine: julia ---- - -## Iris Dataset Visualization - -This example demonstrates how to create violin plots with Julia. We'll visualize the famous Iris dataset which contains measurements for three species of iris flowers. - -```{julia} -#| label: fig-violin-grid -# Load required packages -using RDatasets -using Plots -using StatsPlots - -# Load the Iris dataset -iris = dataset("datasets", "iris") - -# Create four violin plots - one for each measurement -p1 = @df iris violin(:Species, :SepalLength, - legend=false, - ylabel="Sepal Length (cm)", - fillalpha=0.7, - title="Sepal Length", - size=(300, 250)) - -p2 = @df iris violin(:Species, :SepalWidth, - legend=false, - ylabel="Sepal Width (cm)", - fillalpha=0.7, - color=:green, - title="Sepal Width", - size=(300, 250)) - -p3 = @df iris violin(:Species, :PetalLength, - legend=false, - ylabel="Petal Length (cm)", - fillalpha=0.7, - color=:orange, - title="Petal Length", - size=(300, 250)) - -p4 = @df iris violin(:Species, :PetalWidth, - legend=false, - ylabel="Petal Width (cm)", - fillalpha=0.7, - color=:red, - title="Petal Width", - size=(300, 250)) - -plot(p1, p2, p3, p4, - layout=(2,2), - size=(800, 800), - titlefontsize=10, - guidefontsize=9, - tickfontsize=7) -``` - -::: {.callout-note} -## What is a violin plot? - -A violin plot shows the distribution of data across categories. The width of each "violin" represents the density of data points at that value, making it easy to compare distributions between groups. - -In this example, we can see that: - -- *Setosa* has the shortest petals but widest sepals -- *Virginica* has the longest petals and sepals -- *Versicolor* falls between the other two species for most measurements -::: \ No newline at end of file diff --git a/src/julia-engine.ts b/src/julia-engine.ts index df2b164dcbe..233ca1dd861 100644 --- a/src/julia-engine.ts +++ b/src/julia-engine.ts @@ -5,7 +5,7 @@ */ // Standard library imports -import { join, resolve } from "path"; +import { dirname, fromFileUrl, join, resolve } from "path"; import { existsSync } from "fs/exists"; import { encodeBase64 } from "encoding/base64"; @@ -42,6 +42,9 @@ import { // Platform detection const isWindows = Deno.build.os === "windows"; +// Extension directory (where the bundled JS and resource files live) +const extensionDir = dirname(fromFileUrl(import.meta.url)); + // Module-level quarto API reference let quarto: QuartoAPI; @@ -390,7 +393,7 @@ async function startOrReuseJuliaServer( powershell_argument_list_to_string( "--startup-file=no", `--project=${juliaProject}`, - quarto.path.resource("julia", "quartonotebookrunner.jl"), + join(extensionDir, "quartonotebookrunner.jl"), transportFile, juliaServerLogFile(), ), @@ -414,13 +417,10 @@ async function startOrReuseJuliaServer( const command = new Deno.Command(juliaCmd(), { args: [ "--startup-file=no", - quarto.path.resource( - "julia", - "start_quartonotebookrunner_detached.jl", - ), + join(extensionDir, "start_quartonotebookrunner_detached.jl"), juliaCmd(), juliaProject, - quarto.path.resource("julia", "quartonotebookrunner.jl"), + join(extensionDir, "quartonotebookrunner.jl"), transportFile, juliaServerLogFile(), ], @@ -451,17 +451,14 @@ async function ensureQuartoNotebookRunnerEnvironment( options: JuliaExecuteOptions, ) { const runtimeDir = quarto.path.runtime("julia"); - const projectTomlTemplate = quarto.path.resource( - "julia", - "Project.toml", - ); + const projectTomlTemplate = join(extensionDir, "Project.toml"); const projectToml = join(runtimeDir, "Project.toml"); Deno.writeFileSync(projectToml, Deno.readFileSync(projectTomlTemplate)); const command = new Deno.Command(juliaCmd(), { args: [ "--startup-file=no", `--project=${runtimeDir}`, - quarto.path.resource("julia", "ensure_environment.jl"), + join(extensionDir, "ensure_environment.jl"), ], }); const proc = command.spawn(); diff --git a/tests/docs/julia-engine/.gitignore b/tests/docs/julia-engine/.gitignore new file mode 100644 index 00000000000..351aa45ca55 --- /dev/null +++ b/tests/docs/julia-engine/.gitignore @@ -0,0 +1,6 @@ +# Ignore everything in subdirectories (render artifacts, caches, etc.) +*/* + +# Allow only source files +!*/*.qmd +!*/_quarto.yml diff --git a/tests/docs/julia-engine/engine-reordering/_quarto.yml b/tests/docs/julia-engine/engine-reordering/_quarto.yml new file mode 100644 index 00000000000..3aaa4272ac6 --- /dev/null +++ b/tests/docs/julia-engine/engine-reordering/_quarto.yml @@ -0,0 +1,3 @@ +project: + type: default +engines: ["julia"] diff --git a/tests/docs/julia-engine/engine-reordering/notebook.qmd b/tests/docs/julia-engine/engine-reordering/notebook.qmd new file mode 100644 index 00000000000..d3cd5f9644c --- /dev/null +++ b/tests/docs/julia-engine/engine-reordering/notebook.qmd @@ -0,0 +1,10 @@ +```{julia} +using Test +@test haskey( + Base.loaded_modules, + Base.PkgId( + Base.UUID("38328d9c-a911-4051-bc06-3f7f556ffeda"), + "QuartoNotebookWorker", + ) +) +``` diff --git a/tests/docs/julia-engine/sleep/_quarto.yml b/tests/docs/julia-engine/sleep/_quarto.yml new file mode 100644 index 00000000000..b8bae5830fa --- /dev/null +++ b/tests/docs/julia-engine/sleep/_quarto.yml @@ -0,0 +1,2 @@ +project: + type: default diff --git a/tests/docs/julia-engine/sleep/sleep.qmd b/tests/docs/julia-engine/sleep/sleep.qmd new file mode 100644 index 00000000000..6e8011d326b --- /dev/null +++ b/tests/docs/julia-engine/sleep/sleep.qmd @@ -0,0 +1,9 @@ +--- +engine: julia +params: + sleep_duration: 0 +--- + +```{julia} +sleep(sleep_duration) +``` \ No newline at end of file diff --git a/tests/docs/julia-engine/source-ranges/_included.qmd b/tests/docs/julia-engine/source-ranges/_included.qmd new file mode 100644 index 00000000000..bb2b3e351a2 --- /dev/null +++ b/tests/docs/julia-engine/source-ranges/_included.qmd @@ -0,0 +1,3 @@ +```{julia} +"$(@__FILE__):$(@__LINE__)" +``` diff --git a/tests/docs/julia-engine/source-ranges/source-ranges-test.qmd b/tests/docs/julia-engine/source-ranges/source-ranges-test.qmd new file mode 100644 index 00000000000..2f59838a9a4 --- /dev/null +++ b/tests/docs/julia-engine/source-ranges/source-ranges-test.qmd @@ -0,0 +1,11 @@ +--- +title: "Test Julia source ranges with includes" +format: markdown +engine: julia +--- + +{{< include _included.qmd >}} + +```{julia} +"$(@__FILE__):$(@__LINE__)" +``` diff --git a/tests/run-tests.ps1 b/tests/run-tests.ps1 new file mode 100644 index 00000000000..225f8d1628d --- /dev/null +++ b/tests/run-tests.ps1 @@ -0,0 +1,31 @@ +# Always use the deno bundled with quarto to avoid version mismatches. +# Accepts QUARTO env var or falls back to quarto on PATH. +$ErrorActionPreference = "Stop" + +$quartoCmd = if ($env:QUARTO) { $env:QUARTO } else { "quarto" } + +$quartoBin = & $quartoCmd --paths | Select-Object -First 1 +$deno = Join-Path $quartoBin "tools" "x86_64" "deno.exe" + +if (-not (Test-Path $deno)) { + # Try aarch64 if x86_64 not found + $deno = Join-Path $quartoBin "tools" "aarch64" "deno.exe" +} + +if (-not (Test-Path $deno)) { + Write-Error "deno not found in quarto tools directory" + exit 1 +} + +Push-Location $PSScriptRoot +try { + # Run explicit files if given, otherwise discover all .test.ts files + if ($args.Count -gt 0) { + & $deno test --allow-all --no-check @args + } else { + & $deno test --allow-all --no-check smoke/ + } + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } +} finally { + Pop-Location +} diff --git a/tests/run-tests.sh b/tests/run-tests.sh new file mode 100755 index 00000000000..6791e8e97a1 --- /dev/null +++ b/tests/run-tests.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Always use the deno bundled with quarto to avoid version mismatches. +# Accepts QUARTO env var or falls back to quarto on PATH. +QUARTO="${QUARTO:-quarto}" + +if ! command -v "$QUARTO" &>/dev/null; then + echo "quarto not found. Either set QUARTO=/path/to/quarto or add it to PATH." >&2 + exit 1 +fi + +QUARTO_BIN_DIR="$("$QUARTO" --paths | head -1)" + +case "$(uname -m)" in + x86_64) DENO_ARCH_DIR=x86_64 ;; + aarch64|arm64) DENO_ARCH_DIR=aarch64 ;; + *) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;; +esac + +DENO="$QUARTO_BIN_DIR/tools/$DENO_ARCH_DIR/deno" + +if [ ! -x "$DENO" ]; then + echo "deno not found at $DENO" >&2 + exit 1 +fi + +cd "$SCRIPT_DIR" + +# Run explicit files if given, otherwise discover all .test.ts files +if [ $# -gt 0 ]; then + "$DENO" test --allow-all --no-check "$@" +else + "$DENO" test --allow-all --no-check smoke/ +fi diff --git a/tests/smoke/julia-engine/julia.test.ts b/tests/smoke/julia-engine/julia.test.ts new file mode 100644 index 00000000000..ecf33cc68fd --- /dev/null +++ b/tests/smoke/julia-engine/julia.test.ts @@ -0,0 +1,227 @@ +import { assert, assertStringIncludes } from "jsr:@std/assert"; +import { existsSync } from "jsr:@std/fs/exists"; +import { join } from "jsr:@std/path"; + +const isWindows = Deno.build.os === "windows"; +function quartoCmd(): string { + return isWindows ? "quarto.cmd" : "quarto"; +} +function docs(path: string): string { + return join("docs", path); +} +const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +// Resolve the quarto runtime dir for Julia (where transport/log files live). +// Mirrors quarto's quartoRuntimeDir("julia"). +function quartoRuntimeDir(): string { + let base: string; + switch (Deno.build.os) { + case "darwin": + base = join(Deno.env.get("HOME")!, "Library", "Caches", "quarto"); + break; + case "windows": + base = join(Deno.env.get("LOCALAPPDATA")!, "quarto"); + break; + default: { + const xdgRuntime = Deno.env.get("XDG_RUNTIME_DIR"); + if (xdgRuntime) { + base = join(xdgRuntime, "quarto"); + } else { + const cacheHome = Deno.env.get("XDG_CACHE_HOME") ?? join(Deno.env.get("HOME")!, ".cache"); + base = join(cacheHome, "quarto"); + } + break; + } + } + return join(base, "julia"); +} + +const juliaTestDir = docs("julia-engine/sleep"); +const sleepQmd = "sleep.qmd"; +assert(existsSync(join(juliaTestDir, sleepQmd))); + +function assertSuccess(output: Deno.CommandOutput) { + if (!output.success) { + console.error("Command failed:"); + console.error("stdout:\n" + new TextDecoder().decode(output.stdout)); + console.error("stderr:\n" + new TextDecoder().decode(output.stderr)); + throw new Error("Command execution was not successful"); + } +} + +function assertStdoutIncludes(output: Deno.CommandOutput, str: string) { + assertStringIncludes(new TextDecoder().decode(output.stdout), str); +} +function assertStderrIncludes(output: Deno.CommandOutput, str: string) { + assertStringIncludes(new TextDecoder().decode(output.stderr), str); +} + +Deno.test("julia engine", async (t) => { + // Setup: Clean up any leftover server state before running tests + const killcmd = new Deno.Command( + quartoCmd(), + { args: ["call", "engine", "julia", "kill"], cwd: juliaTestDir }, + ).outputSync(); + assertSuccess(killcmd); + + const transportFile = join(quartoRuntimeDir(), "julia_transport.txt"); + const logFile = join(quartoRuntimeDir(), "julia_server_log.txt"); + + try { + await Deno.remove(transportFile); + } catch { + // File might not exist, that's okay + } + + try { + await Deno.remove(logFile); + } catch { + // File might not exist, that's okay + } + + await t.step("kill without server running", () => { + const output = new Deno.Command( + quartoCmd(), + { args: ["call", "engine", "julia", "kill"], cwd: juliaTestDir }, + ).outputSync(); + assertSuccess(output); + assertStderrIncludes(output, "Julia control server is not running."); + }); + + await t.step("status without server running", () => { + const output = new Deno.Command( + quartoCmd(), + { args: ["call", "engine", "julia", "status"], cwd: juliaTestDir }, + ).outputSync(); + assertSuccess(output); + assertStderrIncludes(output, "Julia control server is not running."); + }); + + await t.step("log file doesn't exist", () => { + const log_output = new Deno.Command( + quartoCmd(), + { args: ["call", "engine", "julia", "log"], cwd: juliaTestDir }, + ).outputSync(); + assertSuccess(log_output); + assertStderrIncludes(log_output, "Server log file doesn't exist"); + }); + + await t.step("status with server and worker running", () => { + const render_output = new Deno.Command( + quartoCmd(), + { + args: [ + "render", + sleepQmd, + "-P", + "sleep_duration:0", + "--execute-daemon", + "60", + ], + cwd: juliaTestDir, + }, + ).outputSync(); + assertSuccess(render_output); + + const status_output = new Deno.Command( + quartoCmd(), + { args: ["call", "engine", "julia", "status"], cwd: juliaTestDir }, + ).outputSync(); + assertSuccess(status_output); + assertStdoutIncludes(status_output, "workers active: 1"); + }); + + await t.step("closing an idling worker", () => { + const close_output = new Deno.Command( + quartoCmd(), + { + args: ["call", "engine", "julia", "close", sleepQmd], + cwd: juliaTestDir, + }, + ).outputSync(); + assertSuccess(close_output); + assertStderrIncludes(close_output, "Worker closed successfully"); + + const status_output = new Deno.Command( + quartoCmd(), + { args: ["call", "engine", "julia", "status"], cwd: juliaTestDir }, + ).outputSync(); + assertSuccess(status_output); + assertStdoutIncludes(status_output, "workers active: 0"); + }); + + await t.step("force-closing a running worker", async () => { + const render_cmd = new Deno.Command( + quartoCmd(), + { + args: ["render", sleepQmd, "-P", "sleep_duration:30"], + cwd: juliaTestDir, + }, + ).output(); + + await delay(3000); + + const close_output = new Deno.Command( + quartoCmd(), + { + args: ["call", "engine", "julia", "close", sleepQmd], + cwd: juliaTestDir, + }, + ).outputSync(); + assertStderrIncludes(close_output, "worker is busy"); + + const status_output = new Deno.Command( + quartoCmd(), + { args: ["call", "engine", "julia", "status"], cwd: juliaTestDir }, + ).outputSync(); + assertSuccess(status_output); + assertStdoutIncludes(status_output, "workers active: 1"); + + const force_close_output = new Deno.Command( + quartoCmd(), + { + args: ["call", "engine", "julia", "close", "--force", sleepQmd], + cwd: juliaTestDir, + }, + ).outputSync(); + assertSuccess(force_close_output); + assertStderrIncludes(force_close_output, "Worker force-closed successfully"); + + const status_output_2 = new Deno.Command( + quartoCmd(), + { args: ["call", "engine", "julia", "status"], cwd: juliaTestDir }, + ).outputSync(); + assertSuccess(status_output_2); + assertStdoutIncludes(status_output_2, "workers active: 0"); + + const render_output = await render_cmd; + assertStderrIncludes(render_output, "File was force-closed during run"); + }); + + await t.step("log exists", () => { + const log_output = new Deno.Command( + quartoCmd(), + { args: ["call", "engine", "julia", "log"], cwd: juliaTestDir }, + ).outputSync(); + assertSuccess(log_output); + assertStdoutIncludes(log_output, "Log started at"); + }); + + await t.step("stop the idling server", async () => { + const stop_output = new Deno.Command( + quartoCmd(), + { args: ["call", "engine", "julia", "stop"], cwd: juliaTestDir }, + ).outputSync(); + assertSuccess(stop_output); + assertStderrIncludes(stop_output, "Server stopped"); + + await delay(2000); + + const log_output = new Deno.Command( + quartoCmd(), + { args: ["call", "engine", "julia", "log"], cwd: juliaTestDir }, + ).outputSync(); + assertSuccess(log_output); + assertStdoutIncludes(log_output, "Server stopped"); + }); +}); diff --git a/tests/smoke/julia-engine/render.test.ts b/tests/smoke/julia-engine/render.test.ts new file mode 100644 index 00000000000..91e66751d41 --- /dev/null +++ b/tests/smoke/julia-engine/render.test.ts @@ -0,0 +1,55 @@ +import { assert, assertMatch } from "jsr:@std/assert"; +import { join } from "jsr:@std/path"; +import { existsSync } from "jsr:@std/fs/exists"; + +const isWindows = Deno.build.os === "windows"; +function quartoCmd(): string { + return isWindows ? "quarto.cmd" : "quarto"; +} +function docs(path: string): string { + return join("docs", path); +} + +function renderQmd( + file: string, + args: string[] = [], + cwd?: string, +): Deno.CommandOutput { + const allArgs = ["render", file, ...args]; + const output = new Deno.Command(quartoCmd(), { args: allArgs, cwd }) + .outputSync(); + if (!output.success) { + console.error("Render failed:"); + console.error("stdout:\n" + new TextDecoder().decode(output.stdout)); + console.error("stderr:\n" + new TextDecoder().decode(output.stderr)); + throw new Error(`quarto render ${file} failed`); + } + return output; +} + +Deno.test("source ranges with includes", async () => { + const dir = docs("julia-engine/source-ranges"); + const input = join(dir, "source-ranges-test.qmd"); + renderQmd(input, ["--to", "markdown"]); + + const outputFile = join(dir, "source-ranges-test.md"); + assert(existsSync(outputFile), `Output file ${outputFile} should exist`); + const content = await Deno.readTextFile(outputFile); + + // The julia code outputs __FILE__:__LINE__. Verify source range mapping: + // line 10 of source-ranges-test.qmd and line 2 of _included.qmd + assertMatch(content, /source-ranges-test\.qmd:10/m); + assertMatch(content, /_included\.qmd:2/m); + + try { Deno.removeSync(outputFile); } catch { /* ok */ } +}); + +Deno.test("engine reordering", () => { + const dir = docs("julia-engine/engine-reordering"); + renderQmd("notebook.qmd", ["--to", "html"], dir); + + const outputFile = join(dir, "notebook.html"); + assert(existsSync(outputFile), `Output file ${outputFile} should exist`); + + try { Deno.removeSync(outputFile); } catch { /* ok */ } +}); From a871eace2fb7753c80942bd0430559495f1b2dde Mon Sep 17 00:00:00 2001 From: Julius Krumbiegel Date: Thu, 19 Mar 2026 11:40:36 +0100 Subject: [PATCH 3/4] chore: remove Julia resources and tests moved to julia-engine extension These files now live in the julia-engine extension repo at PumasAI/quarto-julia-engine and are bundled into the extension or merged into the test tree at CI time. Removed: - src/resources/julia/ (bundled into _extensions/julia-engine/) - tests/smoke/call/engine/julia/ (moved to extension tests/) - tests/docs/call/engine/julia/ (moved to extension tests/) - tests/docs/smoke-all/julia/ (moved to extension tests/) - tests/docs/smoke-all/engine-reordering/julia-engine/ (moved to extension tests/) --- src/resources/julia/Project.toml | 5 - src/resources/julia/ensure_environment.jl | 32 --- src/resources/julia/quartonotebookrunner.jl | 57 ----- .../start_quartonotebookrunner_detached.jl | 17 -- tests/docs/call/engine/julia/_quarto.yml | 3 - tests/docs/call/engine/julia/sleep.qmd | 9 - .../julia-engine/_quarto.yml | 3 - .../julia-engine/notebook.qmd | 10 - tests/docs/smoke-all/julia/_included.qmd | 3 - .../smoke-all/julia/source-ranges-test.qmd | 16 -- tests/smoke/call/engine/julia/julia.test.ts | 198 ------------------ 11 files changed, 353 deletions(-) delete mode 100644 src/resources/julia/Project.toml delete mode 100644 src/resources/julia/ensure_environment.jl delete mode 100644 src/resources/julia/quartonotebookrunner.jl delete mode 100644 src/resources/julia/start_quartonotebookrunner_detached.jl delete mode 100644 tests/docs/call/engine/julia/_quarto.yml delete mode 100644 tests/docs/call/engine/julia/sleep.qmd delete mode 100644 tests/docs/smoke-all/engine-reordering/julia-engine/_quarto.yml delete mode 100644 tests/docs/smoke-all/engine-reordering/julia-engine/notebook.qmd delete mode 100644 tests/docs/smoke-all/julia/_included.qmd delete mode 100644 tests/docs/smoke-all/julia/source-ranges-test.qmd delete mode 100644 tests/smoke/call/engine/julia/julia.test.ts diff --git a/src/resources/julia/Project.toml b/src/resources/julia/Project.toml deleted file mode 100644 index 94def5bfc2f..00000000000 --- a/src/resources/julia/Project.toml +++ /dev/null @@ -1,5 +0,0 @@ -[deps] -QuartoNotebookRunner = "4c0109c6-14e9-4c88-93f0-2b974d3468f4" - -[compat] -QuartoNotebookRunner = "=0.17.4" diff --git a/src/resources/julia/ensure_environment.jl b/src/resources/julia/ensure_environment.jl deleted file mode 100644 index 3274a230f8b..00000000000 --- a/src/resources/julia/ensure_environment.jl +++ /dev/null @@ -1,32 +0,0 @@ -using Pkg -using TOML - -# If the manifest was resolved with the exact Project.toml that we have copied -# over from quarto's resource folder, then we just ensure that it is instantiated, -# all packages are downloaded correctly, etc. -# Otherwise, we update to get the newest packages fulfilling the compat bounds set in -# the Project.toml. - -function manifest_has_correct_julia_version() - project_file = Base.active_project() - manifest_file = joinpath(dirname(project_file), "Manifest.toml") - version = VersionNumber(TOML.parsefile(manifest_file)["julia_version"]) - return version.major == VERSION.major && version.minor == VERSION.minor -end - -is_manifest_current = @static if VERSION < v"1.11.0-DEV.1135" - Pkg.is_manifest_current() -else - Pkg.is_manifest_current(dirname(Base.active_project())) -end - -manifest_matches_project_toml = is_manifest_current === true # this returns nothing if there's no manifest - -if manifest_matches_project_toml && manifest_has_correct_julia_version() - Pkg.instantiate() -else - Pkg.update() -end -# not strictly necessary, but in case of precompilation errors this will -# actually print them out explicitly -Pkg.precompile() diff --git a/src/resources/julia/quartonotebookrunner.jl b/src/resources/julia/quartonotebookrunner.jl deleted file mode 100644 index d2a394da981..00000000000 --- a/src/resources/julia/quartonotebookrunner.jl +++ /dev/null @@ -1,57 +0,0 @@ -logfile = ARGS[2] -filehandle = open(logfile, "w") - -# We cannot start Julia in a way such that it uses line buffering or no buffering (see https://github.com/JuliaLang/julia/issues/13050) -# which means that if we just redirect all its output into a logfile (for example with `pipeline(julia_cmd, stdout = logfile)`) -# it will not actually write to the logfile until the buffer is filled or it's explicitly flushed, which can take a while. -# So when we check the logfile, we don't actually see anything if the buffer is not filled first, which -# may never be if there's little output. So instead we redirect stdout and stderr to a pipe which we manually check -# for available data in shorter intervals. We then write the data to the logfile and flush. - -pipe = Pipe() -pipe_with_color = IOContext(pipe, :color => Base.get_have_color()) -redirect_stdout(pipe_with_color) -redirect_stderr(pipe_with_color) - -function update_logfile() - data = readavailable(pipe) - if !isempty(data) - write(filehandle, data) - flush(filehandle) - end - return -end - -@async while true - update_logfile() - sleep(1) -end - -# we might lose printout from crashes if we don't do another update at the end -atexit() do - update_logfile() -end - -using Dates: now -@info "Log started at $(now())" - -using QuartoNotebookRunner -using Sockets - -transport_file = ARGS[1] -transport_dir = dirname(transport_file) - -atexit() do - rm(transport_file; force=true) -end - -server = QuartoNotebookRunner.serve(; timeout = 300) -port = server.port - -open(transport_file, "w") do io - println(io, """{"port": $port, "pid": $(Base.Libc.getpid()), "key": "$(server.key)"}""") -end - -@info "Starting server at $(now())" -wait(server) -@info "Server stopped at $(now())" diff --git a/src/resources/julia/start_quartonotebookrunner_detached.jl b/src/resources/julia/start_quartonotebookrunner_detached.jl deleted file mode 100644 index 3771ca52322..00000000000 --- a/src/resources/julia/start_quartonotebookrunner_detached.jl +++ /dev/null @@ -1,17 +0,0 @@ -# it appears that deno cannot launch detached processes https://github.com/denoland/deno/issues/5501 -# so we use an indirection where we start the detached julia process using julia itself -julia_bin = ARGS[1] -project = ARGS[2] -julia_file = ARGS[3] -transport_file = ARGS[4] -logfile = ARGS[5] - -if length(ARGS) > 5 - error("Too many arguments") -end - -env = copy(ENV) -env["JULIA_LOAD_PATH"] = "@:@stdlib" # ignore the main env -cmd = `$julia_bin --startup-file=no --project=$project $julia_file $transport_file $logfile` -cmd = setenv(cmd, env) -run(detach(cmd), wait = false) diff --git a/tests/docs/call/engine/julia/_quarto.yml b/tests/docs/call/engine/julia/_quarto.yml deleted file mode 100644 index 5d28962fff4..00000000000 --- a/tests/docs/call/engine/julia/_quarto.yml +++ /dev/null @@ -1,3 +0,0 @@ -project: - type: default - diff --git a/tests/docs/call/engine/julia/sleep.qmd b/tests/docs/call/engine/julia/sleep.qmd deleted file mode 100644 index 6e8011d326b..00000000000 --- a/tests/docs/call/engine/julia/sleep.qmd +++ /dev/null @@ -1,9 +0,0 @@ ---- -engine: julia -params: - sleep_duration: 0 ---- - -```{julia} -sleep(sleep_duration) -``` \ No newline at end of file diff --git a/tests/docs/smoke-all/engine-reordering/julia-engine/_quarto.yml b/tests/docs/smoke-all/engine-reordering/julia-engine/_quarto.yml deleted file mode 100644 index 3aaa4272ac6..00000000000 --- a/tests/docs/smoke-all/engine-reordering/julia-engine/_quarto.yml +++ /dev/null @@ -1,3 +0,0 @@ -project: - type: default -engines: ["julia"] diff --git a/tests/docs/smoke-all/engine-reordering/julia-engine/notebook.qmd b/tests/docs/smoke-all/engine-reordering/julia-engine/notebook.qmd deleted file mode 100644 index 3445e8af0a1..00000000000 --- a/tests/docs/smoke-all/engine-reordering/julia-engine/notebook.qmd +++ /dev/null @@ -1,10 +0,0 @@ -```{julia} -using Test -@test haskey( - Base.loaded_modules, - Base.PkgId( - Base.UUID("38328d9c-a911-4051-bc06-3f7f556ffeda"), - "QuartoNotebookWorker", - ) -) -``` \ No newline at end of file diff --git a/tests/docs/smoke-all/julia/_included.qmd b/tests/docs/smoke-all/julia/_included.qmd deleted file mode 100644 index 1be592fa71f..00000000000 --- a/tests/docs/smoke-all/julia/_included.qmd +++ /dev/null @@ -1,3 +0,0 @@ -```{julia} -"$(@__FILE__):$(@__LINE__)" -``` \ No newline at end of file diff --git a/tests/docs/smoke-all/julia/source-ranges-test.qmd b/tests/docs/smoke-all/julia/source-ranges-test.qmd deleted file mode 100644 index a1947ac784d..00000000000 --- a/tests/docs/smoke-all/julia/source-ranges-test.qmd +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: "Test Julia source ranges with includes" -format: markdown -engine: julia -_quarto: - tests: - markdown: - ensureFileRegexMatches: - - ['source-ranges-test\.qmd:15', '_included\.qmd:2'] ---- - -{{< include _included.qmd >}} - -```{julia} -"$(@__FILE__):$(@__LINE__)" -``` diff --git a/tests/smoke/call/engine/julia/julia.test.ts b/tests/smoke/call/engine/julia/julia.test.ts deleted file mode 100644 index 351a2061e72..00000000000 --- a/tests/smoke/call/engine/julia/julia.test.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { assert, assertStringIncludes } from "testing/asserts"; -import { docs, quartoDevCmd } from "../../../../utils.ts"; -import { existsSync } from "fs/exists"; -import { sleep } from "../../../../../src/core/wait.ts"; -import { quartoRuntimeDir } from "../../../../../src/core/appdirs.ts"; -import { join } from "../../../../../src/deno_ral/path.ts"; - -const juliaTestDir = docs("call/engine/julia"); -const sleepQmd = "sleep.qmd"; -assert(existsSync(docs("call/engine/julia/sleep.qmd"))); - -function assertSuccess(output: Deno.CommandOutput) { - if (!output.success) { - console.error("Command failed:"); - console.error("stdout:\n" + new TextDecoder().decode(output.stdout)); - console.error("stderr:\n" + new TextDecoder().decode(output.stderr)); - throw new Error("Command execution was not successful"); - } -} - -function assertStdoutIncludes(output: Deno.CommandOutput, str: string) { - assertStringIncludes(new TextDecoder().decode(output.stdout), str); -} -function assertStderrIncludes(output: Deno.CommandOutput, str: string) { - assertStringIncludes(new TextDecoder().decode(output.stderr), str); -} - -Deno.test("julia engine", async (t) => { - // Setup: Clean up any leftover server state before running tests - const killcmd = new Deno.Command( - quartoDevCmd(), - { args: ["call", "engine", "julia", "kill"], cwd: juliaTestDir }, - ).outputSync(); - assertSuccess(killcmd); - - const transportFile = join(quartoRuntimeDir("julia"), "julia_transport.txt"); - const logFile = join(quartoRuntimeDir("julia"), "julia_server_log.txt"); - - try { - await Deno.remove(transportFile); - } catch { - // File might not exist, that's okay - } - - try { - await Deno.remove(logFile); - } catch { - // File might not exist, that's okay - } - - // Now run all the actual tests as steps - await t.step("kill without server running", () => { - const output = new Deno.Command( - quartoDevCmd(), - { args: ["call", "engine", "julia", "kill"], cwd: juliaTestDir }, - ).outputSync(); - assertSuccess(output); - assertStderrIncludes(output, "Julia control server is not running."); - }); - - await t.step("status without server running", () => { - const output = new Deno.Command( - quartoDevCmd(), - { args: ["call", "engine", "julia", "status"], cwd: juliaTestDir }, - ).outputSync(); - assertSuccess(output); - assertStderrIncludes(output, "Julia control server is not running."); - }); - - await t.step("log file doesn't exist", () => { - const log_output = new Deno.Command( - quartoDevCmd(), - { args: ["call", "engine", "julia", "log"], cwd: juliaTestDir }, - ).outputSync(); - assertSuccess(log_output); - assertStderrIncludes(log_output, "Server log file doesn't exist"); - }); - - await t.step("status with server and worker running", () => { - const render_output = new Deno.Command( - quartoDevCmd(), - { - args: [ - "render", - sleepQmd, - "-P", - "sleep_duration:0", - "--execute-daemon", - "60", - ], - cwd: juliaTestDir, - }, - ).outputSync(); - assertSuccess(render_output); - - const status_output = new Deno.Command( - quartoDevCmd(), - { args: ["call", "engine", "julia", "status"], cwd: juliaTestDir }, - ).outputSync(); - assertSuccess(status_output); - assertStdoutIncludes(status_output, "workers active: 1"); - }); - - await t.step("closing an idling worker", () => { - const close_output = new Deno.Command( - quartoDevCmd(), - { - args: ["call", "engine", "julia", "close", sleepQmd], - cwd: juliaTestDir, - }, - ).outputSync(); - assertSuccess(close_output); - assertStderrIncludes(close_output, "Worker closed successfully"); - - const status_output = new Deno.Command( - quartoDevCmd(), - { args: ["call", "engine", "julia", "status"], cwd: juliaTestDir }, - ).outputSync(); - assertSuccess(status_output); - assertStdoutIncludes(status_output, "workers active: 0"); - }); - - await t.step("force-closing a running worker", async () => { - // spawn a long-running command - const render_cmd = new Deno.Command( - quartoDevCmd(), - { - args: ["render", sleepQmd, "-P", "sleep_duration:30"], - cwd: juliaTestDir, - }, - ).output(); - - await sleep(3000); - - const close_output = new Deno.Command( - quartoDevCmd(), - { - args: ["call", "engine", "julia", "close", sleepQmd], - cwd: juliaTestDir, - }, - ).outputSync(); - assertStderrIncludes(close_output, "worker is busy"); - - const status_output = new Deno.Command( - quartoDevCmd(), - { args: ["call", "engine", "julia", "status"], cwd: juliaTestDir }, - ).outputSync(); - assertSuccess(status_output); - assertStdoutIncludes(status_output, "workers active: 1"); - - const force_close_output = new Deno.Command( - quartoDevCmd(), - { - args: ["call", "engine", "julia", "close", "--force", sleepQmd], - cwd: juliaTestDir, - }, - ).outputSync(); - assertSuccess(force_close_output); - assertStderrIncludes(force_close_output, "Worker force-closed successfully"); - - const status_output_2 = new Deno.Command( - quartoDevCmd(), - { args: ["call", "engine", "julia", "status"], cwd: juliaTestDir }, - ).outputSync(); - assertSuccess(status_output_2); - assertStdoutIncludes(status_output_2, "workers active: 0"); - - const render_output = await render_cmd; - assertStderrIncludes(render_output, "File was force-closed during run"); - }); - - await t.step("log exists", () => { - const log_output = new Deno.Command( - quartoDevCmd(), - { args: ["call", "engine", "julia", "log"], cwd: juliaTestDir }, - ).outputSync(); - assertSuccess(log_output); - assertStdoutIncludes(log_output, "Log started at"); - }); - - await t.step("stop the idling server", async () => { - const stop_output = new Deno.Command( - quartoDevCmd(), - { args: ["call", "engine", "julia", "stop"], cwd: juliaTestDir }, - ).outputSync(); - assertSuccess(stop_output); - assertStderrIncludes(stop_output, "Server stopped"); - - await sleep(2000); // allow a little bit of time for the server to stop and the log message to be written - - const log_output = new Deno.Command( - quartoDevCmd(), - { args: ["call", "engine", "julia", "log"], cwd: juliaTestDir }, - ).outputSync(); - assertSuccess(log_output); - assertStdoutIncludes(log_output, "Server stopped"); - }); -}); From a70895e1c55c4ab7b221d1f27db3f628b0078f71 Mon Sep 17 00:00:00 2001 From: Julius Krumbiegel Date: Thu, 19 Mar 2026 12:10:20 +0100 Subject: [PATCH 4/4] ci: extract extension test merge into reusable composite action Used in both test-smokes-parallel.yml (for bucket discovery) and test-smokes.yml (for each test runner job's fresh checkout). --- .github/actions/merge-extension-tests/action.yml | 16 ++++++++++++++++ .github/workflows/test-smokes-parallel.yml | 2 ++ .github/workflows/test-smokes.yml | 2 ++ 3 files changed, 20 insertions(+) create mode 100644 .github/actions/merge-extension-tests/action.yml diff --git a/.github/actions/merge-extension-tests/action.yml b/.github/actions/merge-extension-tests/action.yml new file mode 100644 index 00000000000..2091b9c95f8 --- /dev/null +++ b/.github/actions/merge-extension-tests/action.yml @@ -0,0 +1,16 @@ +name: "Merge extension tests into test tree" +description: > + Copies test files from extension subtrees into the main test directories + so they are discovered by the test runner and bucket creation. + Extension tests live in their own repos (single source of truth) and are + pulled in via git subtree — this step avoids duplicating them. + +runs: + using: "composite" + steps: + - name: Merge julia-engine tests + shell: bash + run: | + SUBTREE=src/resources/extension-subtrees/julia-engine/tests + cp -r "$SUBTREE/docs/julia-engine" tests/docs/julia-engine + cp -r "$SUBTREE/smoke/julia-engine" tests/smoke/julia-engine diff --git a/.github/workflows/test-smokes-parallel.yml b/.github/workflows/test-smokes-parallel.yml index d36cbe86b6e..48e02401135 100644 --- a/.github/workflows/test-smokes-parallel.yml +++ b/.github/workflows/test-smokes-parallel.yml @@ -60,6 +60,8 @@ jobs: with: version: ${{ github.ref == 'refs/heads/main' && 'pre-release' || 'release' }} + - uses: ./.github/actions/merge-extension-tests + - name: Create Job for tests id: tests-buckets run: | diff --git a/.github/workflows/test-smokes.yml b/.github/workflows/test-smokes.yml index 863e0d951ba..bd70ac69648 100644 --- a/.github/workflows/test-smokes.yml +++ b/.github/workflows/test-smokes.yml @@ -241,6 +241,8 @@ jobs: echo "Julia Jupyter:" uv run julia --project=. -e "import IJulia;println(IJulia.JUPYTER);println(IJulia.find_jupyter_subcommand(\"notebook\"))" + - uses: ./.github/actions/merge-extension-tests + - name: Setup timing file for timed test if: ${{ matrix.time-test == true }} run: |