diff --git a/.github/workflows/patterns.yaml b/.github/workflows/patterns.yaml new file mode 100644 index 00000000..b8b82c83 --- /dev/null +++ b/.github/workflows/patterns.yaml @@ -0,0 +1,33 @@ +name: Patterns Artifact + +on: + push: + paths: + - "patterns/**" # Trigger only on changes to files in the patterns folder + +jobs: + zip-and-upload: + name: Zip and Upload Patterns Folder + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Verify Changes in Patterns Folder + run: | + git fetch origin + if git diff --quiet HEAD~1 -- patterns; then + echo "No changes detected in patterns folder." + exit 1 + fi + + - name: Zip the Patterns Folder + run: zip -r patterns.zip patterns/ + + - name: Upload Patterns Artifact + uses: actions/upload-artifact@v3 + with: + name: patterns + path: patterns.zip diff --git a/.github/workflows/update-version-and-create-tag.yml b/.github/workflows/update-version-and-create-tag.yml index c7451f28..9177221c 100644 --- a/.github/workflows/update-version-and-create-tag.yml +++ b/.github/workflows/update-version-and-create-tag.yml @@ -63,6 +63,10 @@ jobs: - name: Update version.nix file run: | echo "\"${{ env.new_version }}\"" > pkgs/fabric/version.nix + + - name: Format source codes + run: | + go fmt ./... - name: Update gomod2nix.toml file run: | @@ -73,6 +77,7 @@ jobs: git add version.go git add pkgs/fabric/version.nix git add gomod2nix.toml + git add . if ! git diff --staged --quiet; then git commit -m "Update version to ${{ env.new_tag }} and commit $commit_hash" else diff --git a/.github/workflows/zip-patterns.yml b/.github/workflows/zip-patterns.yml deleted file mode 100644 index 82f5fa04..00000000 --- a/.github/workflows/zip-patterns.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Zip Patterns Folder and Commit - -on: - push: - branches: - - main - paths: - - 'patterns/**' - -permissions: - contents: write # Ensure the workflow has write permissions - -jobs: - zip-and-commit: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set up Git - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - - name: Zip patterns folder - run: | - zip -r patterns.zip patterns - - - name: Check if zip file has changed - id: check_changes - run: | - git add patterns.zip - if git diff --cached --quiet; then - echo "No changes to commit." - echo "changed=false" >> $GITHUB_ENV - else - echo "Changes detected." - echo "changed=true" >> $GITHUB_ENV - - - name: Commit and push changes - if: env.changed == 'true' - run: | - git commit -m "Update patterns.zip" - git push origin main \ No newline at end of file diff --git a/.gitignore b/.gitignore index 15c46c17..1a967add 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,7 @@ dist/ downloads/ eggs/ .eggs/ -lib/ + lib64/ parts/ sdist/ @@ -166,3 +166,179 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +patterns/dialog_with_socrates/Apology by Plato.txt +patterns/dialog_with_socrates/Phaedrus by Plato.txt +patterns/dialog_with_socrates/Symposium by Plato.txt +patterns/dialog_with_socrates/The Economist by Xenophon.txt +patterns/dialog_with_socrates/The Memorabilia by Xenophon.txt +patterns/dialog_with_socrates/The Memorable Thoughts of Socrates by Xenophon.txt +patterns/dialog_with_socrates/The Republic by Plato.txt +patterns/dialog_with_socrates/The Symposium by Xenophon.txt + +web/node_modules + +# Output +web/.output +web/.vercel +web/.svelte-kit +web/build + +# OS +web/.DS_Store +web/Thumbs.db + +# Env +web/.env +web/.env.* +web/!.env.example +web/!.env.test + +# Vite +web/vite.config.js.timestamp-* +web/vite.config.ts.timestamp-* +# Created by https://www.toptal.com/developers/gitignore/api/node +# Edit at https://www.toptal.com/developers/gitignore?templates=node + +### Node ### +# Logs +web/logs +web/*.log +web/npm-debug.log* +web/yarn-debug.log* +web/yarn-error.log* +web/lerna-debug.log* +web/.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +web/report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +web/pids +web/*.pid +web/*.seed +web/*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +web/lib-cov + +# Coverage directory used by tools like istanbul +web/coverage +web/*.lcov + +# nyc test coverage +web/.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +web/.grunt + +# Bower dependency directory (https://bower.io/) +web/bower_components + +# node-waf configuration +web/.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +web/node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web/web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +web/.npm + +# Optional eslint cache +web/.eslintcache + +# Optional stylelint cache +web/.stylelintcache + +# Microbundle cache +web/.rpt2_cache/ +web/.rts2_cache_cjs/ +web/.rts2_cache_es/ +web/.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +web/.env +web/.env.development.local +web/.env.test.local +web/.env.production.local +web/.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +web/.next +web/out + +# Nuxt.js build / generate output +web/.nuxt +web/dist + +# Gatsby files +web/.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +web/.vuepress/dist + +# vuepress v2.x temp and cache directory +web/.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +web/.vscode-test + +# yarn v2 +web/.yarn/cache +web/.yarn/unplugged +web/.yarn/build-state.yml +web/.yarn/install-state.gz +web/.pnp.* + +### Node Patch ### +# Serverless Webpack directories +web/.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +web/.svelte-kit + +# End of https://www.toptal.com/developers/gitignore/api/node + diff --git a/README.md b/README.md index 8d1a083b..2bf4fa54 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ [Meta](#meta) ![Screenshot of fabric](images/fabric-summarize.png) + ## Navigation @@ -56,6 +57,7 @@ - [`to_pdf`](#to_pdf) - [`to_pdf` Installation](#to_pdf-installation) - [pbpaste](#pbpaste) + - [Web Interface](#Web_Interface) - [Meta](#meta) - [Primary contributors](#primary-contributors) @@ -64,9 +66,9 @@ ## Updates > [!NOTE] -November 8, 2024 -> * **Multimodal Support**: You can now us `-a` (attachment) for Multimodal submissions to OpenAI models that support it. Example: `fabric -a https://path/to/image "Give me a description of this image."` - +> November 8, 2024 +> +> - **Multimodal Support**: You can now use `-a` (attachment) for Multimodal submissions to OpenAI models that support it. Example: `fabric -a https://path/to/image "Give me a description of this image."` ## What and why @@ -82,10 +84,10 @@ Fabric was created to address this by enabling everyone to granularly apply AI t Keep in mind that many of these were recorded when Fabric was Python-based, so remember to use the current [install instructions](#Installation) below. -* [Network Chuck](https://www.youtube.com/watch?v=UbDyjIIGaxQ) -* [David Bombal](https://www.youtube.com/watch?v=vF-MQmVxnCs) -* [My Own Intro to the Tool](https://www.youtube.com/watch?v=wPEyyigh10g) -* [More Fabric YouTube Videos](https://www.youtube.com/results?search_query=fabric+ai) +- [Network Chuck](https://www.youtube.com/watch?v=UbDyjIIGaxQ) +- [David Bombal](https://www.youtube.com/watch?v=vF-MQmVxnCs) +- [My Own Intro to the Tool](https://www.youtube.com/watch?v=wPEyyigh10g) +- [More Fabric YouTube Videos](https://www.youtube.com/results?search_query=fabric+ai) ## Philosophy @@ -155,6 +157,7 @@ go install github.com/danielmiessler/fabric@latest You may need to set some environment variables in your `~/.bashrc` on linux or `~/.zshrc` file on mac to be able to run the `fabric` command. Here is an example of what you can add: For Intel based macs or linux + ```bash # Golang environment variables export GOROOT=/usr/local/go @@ -165,6 +168,7 @@ export PATH=$GOPATH/bin:$GOROOT/bin:$HOME/.local/bin:$PATH ``` for Apple Silicon based macs + ```bash # Golang environment variables export GOROOT=$(brew --prefix go)/libexec @@ -173,14 +177,18 @@ export PATH=$GOPATH/bin:$GOROOT/bin:$HOME/.local/bin:$PATH ``` ### Setup + Now run the following command + ```bash # Run the setup to set up your directories and keys fabric --setup ``` + If everything works you are good to go. ### Add aliases for all patterns + In order to add aliases for all your patterns and use them directly as commands ie. `summarize` instead of `fabric --pattern summarize` You can add the following to your `.zshrc` or `.bashrc` file. @@ -189,10 +197,10 @@ You can add the following to your `.zshrc` or `.bashrc` file. for pattern_file in $HOME/.config/fabric/patterns/*; do # Get the base name of the file (i.e., remove the directory path) pattern_name=$(basename "$pattern_file") - + # Create an alias in the form: alias pattern_name="fabric --pattern pattern_name" alias_command="alias $pattern_name='fabric --pattern $pattern_name'" - + # Evaluate the alias command to add it to the current shell eval "$alias_command" done @@ -202,9 +210,11 @@ yt() { fabric -y "$video_link" --transcript } ``` + This also creates a `yt` alias that allows you to use `yt https://www.youtube.com/watch?v=4b0iet22VIk` to get your transcripts. #### Save your files in markdown using aliases + If in addition to the above aliases you would like to have the option to save the output to your favourite markdown note vault like Obsidian then instead of the above add the following to your `.zshrc` or `.bashrc` file: ```bash @@ -244,7 +254,7 @@ yt() { } ``` -This will allow you to use the patterns as aliases like in the above for example `summarize` instead of `fabric --pattern summarize --stream`, however if you pass in an extra argument like this `summarize "my_article_title"` your output will be saved in the destination that you set in `obsidian_base="/path/to/obsidian"` in the following format `YYYY-MM-DD-my_article_title.md` where the date gets autogenerated for you. +This will allow you to use the patterns as aliases like in the above for example `summarize` instead of `fabric --pattern summarize --stream`, however if you pass in an extra argument like this `summarize "my_article_title"` your output will be saved in the destination that you set in `obsidian_base="/path/to/obsidian"` in the following format `YYYY-MM-DD-my_article_title.md` where the date gets autogenerated for you. You can tweak the date format by tweaking the `date_stamp` format. ### Migration @@ -268,11 +278,13 @@ Then [set your environmental variables](#environmental-variables) as shown above ### Upgrading The great thing about Go is that it's super easy to upgrade. Just run the same command you used to install it in the first place and you'll always get the latest version. + ```bash go install github.com/danielmiessler/fabric@latest ``` ## Usage + Once you have it all set up, here's how to use it. ```bash @@ -320,6 +332,7 @@ Application Options: --printcontext= Print context --printsession= Print session --readability Convert HTML input into a clean, readable view + --serve Initiate the API server --dry-run Show what would be sent to the model without actually sending it --version Print current version @@ -401,7 +414,6 @@ When you're ready to use them, copy them into: You can then use them like any other Patterns, but they won't be public unless you explicitly submit them as Pull Requests to the Fabric project. So don't worry—they're private to you. - This feature works with all openai and ollama models but does NOT work with claude. You can specify your model with the -m flag ## Helper Apps @@ -459,6 +471,46 @@ You can also create an alias by editing `~/.bashrc` or `~/.zshrc` and adding the alias pbpaste='xclip -selection clipboard -o' ``` +## Web Interface + +Fabric now includes a built-in web interface that provides a GUI alternative to the command-line interface and an out-of-the-box website for those who want to get started with web development or blogging. +You can use this app as a GUI interface for Fabric, a ready to go blog-site, or a website template for your own projects. + +The `web/src/lib/content` directory includes starter `.obsidian/` and `templates/` directories, allowing you to open up the `web/src/lib/content/` directory as an [Obsidian.md](https://obsidian.md) vault. You can place your posts in the posts directory when you're ready to publish. +### Installing + +The GUI can be installed by navigating to the `web` directory and using `npm install`, `pnpm install`, or your favorite package manager. Then simply run the development server to start the app.  + +_You will need to run fabric in a separate terminal with the `fabric --serve` command._ + +**From the fabric project `web/` directory:** +```shell +npm run dev + +## or ## + +pnpm run dev + +## or your equivalent +``` + +### Streamlit UI + +To run the Streamlit user interface: + +```bash +# Install required dependencies +pip install streamlit pandas matplotlib seaborn numpy python-dotenv + +# Run the Streamlit app +streamlit run streamlit.py +``` + +The Streamlit UI provides a user-friendly interface for: +- Running and chaining patterns +- Managing pattern outputs +- Creating and editing patterns +- Analyzing pattern results ## Meta > [!NOTE] @@ -467,6 +519,7 @@ alias pbpaste='xclip -selection clipboard -o' - _Jonathan Dunn_ for being the absolute MVP dev on the project, including spearheading the new Go version, as well as the GUI! All this while also being a full-time medical doctor! - _Caleb Sima_ for pushing me over the edge of whether to make this a public project or not. - _Eugen Eisler_ and _Frederick Ros_ for their invaluable contributions to the Go version +- _David Peters_ for his work on the web interface. - _Joel Parish_ for super useful input on the project's Github directory structure.. - _Joseph Thacker_ for the idea of a `-c` context flag that adds pre-created context in the `./config/fabric/` directory to all Pattern queries. - _Jason Haddix_ for the idea of a stitch (chained Pattern) to filter content using a local model before sending on to a cloud model, i.e., cleaning customer data using `llama2` before sending on to `gpt-4` for analysis. diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 00000000..8bf4fd33 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,68 @@ +# YAML Configuration Support + +## Overview +Fabric now supports YAML configuration files for commonly used options. This allows users to persist settings and share configurations across multiple runs. + +## Usage +Use the `--config` flag to specify a YAML configuration file: +```bash +fabric --config ~/.config/fabric/config.yaml "Tell me about APIs" +``` + +## Configuration Precedence +1. CLI flags (highest priority) +2. YAML config values +3. Default values (lowest priority) + +## Supported Configuration Options +```yaml +# Model selection +model: gpt-4 +modelContextLength: 4096 + +# Model parameters +temperature: 0.7 +topp: 0.9 +presencepenalty: 0.0 +frequencypenalty: 0.0 +seed: 42 + +# Pattern selection +pattern: analyze # Use pattern name or filename + +# Feature flags +stream: true +raw: false +``` + +## Rules and Behavior +- Only long flag names are supported in YAML (e.g., `temperature` not `-t`) +- CLI flags always override YAML values +- Unknown YAML declarations are ignored +- If a declaration appears multiple times in YAML, the last one wins +- The order of YAML declarations doesn't matter + +## Type Conversions +The following string-to-type conversions are supported: +- String to number: `"42"` → `42` +- String to float: `"42.5"` → `42.5` +- String to boolean: `"true"` → `true` + +## Example Config +```yaml +# ~/.config/fabric/config.yaml +model: gpt-4 +temperature: 0.8 +pattern: analyze +stream: true +topp: 0.95 +presencepenalty: 0.1 +frequencypenalty: 0.2 +``` + +## CLI Override Example +```bash +# Override temperature from config +fabric --config ~/.config/fabric/config.yaml --temperature 0.9 "Query" +``` + diff --git a/cli/cli.go b/cli/cli.go index 95313065..432ad5bb 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -55,10 +55,17 @@ func Cli(version string) (err error) { } if currentFlags.Serve { + registry.ConfigureVendors() err = restapi.Serve(registry, currentFlags.ServeAddress) return } + if currentFlags.ServeOllama { + registry.ConfigureVendors() + err = restapi.ServeOllama(registry, currentFlags.ServeAddress, version) + return + } + if currentFlags.UpdatePatterns { err = registry.PatternsLoader.PopulateDB() return diff --git a/cli/example.yaml b/cli/example.yaml new file mode 100644 index 00000000..d9d61c42 --- /dev/null +++ b/cli/example.yaml @@ -0,0 +1,21 @@ +#this is an example yaml config file for fabric + +# use fabric pattern names +pattern: ai + +# or use a filename +# pattern: ~/testpattern.md + +model: phi3:latest + +# for models that support context length +modelContextLength: 2048 + +frequencypenalty: 0.5 +presencepenalty: 0.5 +topp: 0.67 +temperature: 0.88 +seed: 42 + +stream: true +raw: false \ No newline at end of file diff --git a/cli/flags.go b/cli/flags.go index 7bafc7dc..ea5fc5d4 100644 --- a/cli/flags.go +++ b/cli/flags.go @@ -6,29 +6,32 @@ import ( "fmt" "io" "os" + "reflect" + "strconv" "strings" "github.com/jessevdk/go-flags" goopenai "github.com/sashabaranov/go-openai" "golang.org/x/text/language" + "gopkg.in/yaml.v2" "github.com/danielmiessler/fabric/common" ) // Flags create flags struct. the users flags go into this, this will be passed to the chat struct in cli type Flags struct { - Pattern string `short:"p" long:"pattern" description:"Choose a pattern from the available patterns" default:""` + Pattern string `short:"p" long:"pattern" yaml:"pattern" description:"Choose a pattern from the available patterns" default:""` PatternVariables map[string]string `short:"v" long:"variable" description:"Values for pattern variables, e.g. -v=#role:expert -v=#points:30"` Context string `short:"C" long:"context" description:"Choose a context from the available contexts" default:""` Session string `long:"session" description:"Choose a session from the available sessions"` Attachments []string `short:"a" long:"attachment" description:"Attachment path or URL (e.g. for OpenAI image recognition messages)"` Setup bool `short:"S" long:"setup" description:"Run setup for all reconfigurable parts of fabric"` - Temperature float64 `short:"t" long:"temperature" description:"Set temperature" default:"0.7"` - TopP float64 `short:"T" long:"topp" description:"Set top P" default:"0.9"` - Stream bool `short:"s" long:"stream" description:"Stream"` - PresencePenalty float64 `short:"P" long:"presencepenalty" description:"Set presence penalty" default:"0.0"` - Raw bool `short:"r" long:"raw" description:"Use the defaults of the model without sending chat options (like temperature etc.) and use the user role instead of the system role for patterns."` - FrequencyPenalty float64 `short:"F" long:"frequencypenalty" description:"Set frequency penalty" default:"0.0"` + Temperature float64 `short:"t" long:"temperature" yaml:"temperature" description:"Set temperature" default:"0.7"` + TopP float64 `short:"T" long:"topp" yaml:"topp" description:"Set top P" default:"0.9"` + Stream bool `short:"s" long:"stream" yaml:"stream" description:"Stream"` + PresencePenalty float64 `short:"P" long:"presencepenalty" yaml:"presencepenalty" description:"Set presence penalty" default:"0.0"` + Raw bool `short:"r" long:"raw" yaml:"raw" description:"Use the defaults of the model without sending chat options (like temperature etc.) and use the user role instead of the system role for patterns."` + FrequencyPenalty float64 `short:"F" long:"frequencypenalty" yaml:"frequencypenalty" description:"Set frequency penalty" default:"0.0"` ListPatterns bool `short:"l" long:"listpatterns" description:"List all patterns"` ListAllModels bool `short:"L" long:"listmodels" description:"List all available models"` ListAllContexts bool `short:"x" long:"listcontexts" description:"List all contexts"` @@ -36,8 +39,8 @@ type Flags struct { UpdatePatterns bool `short:"U" long:"updatepatterns" description:"Update patterns"` Message string `hidden:"true" description:"Messages to send to chat"` Copy bool `short:"c" long:"copy" description:"Copy to clipboard"` - Model string `short:"m" long:"model" description:"Choose model"` - ModelContextLength int `long:"modelContextLength" description:"Model context length (only affects ollama)"` + Model string `short:"m" long:"model" yaml:"model" description:"Choose model"` + ModelContextLength int `long:"modelContextLength" yaml:"modelContextLength" description:"Model context length (only affects ollama)"` Output string `short:"o" long:"output" description:"Output to file" default:""` OutputSession bool `long:"output-session" description:"Output the entire session (also a temporary one) to the output file"` LatestPatterns string `short:"n" long:"latest" description:"Number of latest patterns to list" default:"0"` @@ -49,15 +52,18 @@ type Flags struct { Language string `short:"g" long:"language" description:"Specify the Language Code for the chat, e.g. -g=en -g=zh" default:""` ScrapeURL string `short:"u" long:"scrape_url" description:"Scrape website URL to markdown using Jina AI"` ScrapeQuestion string `short:"q" long:"scrape_question" description:"Search question using Jina AI"` - Seed int `short:"e" long:"seed" description:"Seed to be used for LMM generation"` + Seed int `short:"e" long:"seed" yaml:"seed" description:"Seed to be used for LMM generation"` WipeContext string `short:"w" long:"wipecontext" description:"Wipe context"` WipeSession string `short:"W" long:"wipesession" description:"Wipe session"` PrintContext string `long:"printcontext" description:"Print context"` PrintSession string `long:"printsession" description:"Print session"` HtmlReadability bool `long:"readability" description:"Convert HTML input into a clean, readable view"` + InputHasVars bool `long:"input-has-vars" description:"Apply variables to user input"` DryRun bool `long:"dry-run" description:"Show what would be sent to the model without actually sending it"` Serve bool `long:"serve" description:"Serve the Fabric Rest API"` + ServeOllama bool `long:"serveOllama" description:"Serve the Fabric Rest API with ollama endpoints"` ServeAddress string `long:"address" description:"The address to bind the REST API" default:":8080"` + Config string `long:"config" description:"Path to YAML config file"` Version bool `long:"version" description:"Print current version"` ListExtensions bool `long:"listextensions" description:"List all registered extensions"` AddExtension string `long:"addextension" description:"Register a new extension from config file path"` @@ -65,36 +71,162 @@ type Flags struct { } +var debug = false + +func Debugf(format string, a ...interface{}) { + if debug { + fmt.Printf("DEBUG: "+format, a...) + } +} + // Init Initialize flags. returns a Flags struct and an error func Init() (ret *Flags, err error) { - var message string + // Track which yaml-configured flags were set on CLI + usedFlags := make(map[string]bool) + yamlArgsScan := os.Args[1:] + // Get list of fields that have yaml tags, could be in yaml config + yamlFields := make(map[string]bool) + t := reflect.TypeOf(Flags{}) + for i := 0; i < t.NumField(); i++ { + if yamlTag := t.Field(i).Tag.Get("yaml"); yamlTag != "" { + yamlFields[yamlTag] = true + //Debugf("Found yaml-configured field: %s\n", yamlTag) + } + } + + // Scan args for that are provided by cli and might be in yaml + for _, arg := range yamlArgsScan { + if strings.HasPrefix(arg, "--") { + flag := strings.TrimPrefix(arg, "--") + if i := strings.Index(flag, "="); i > 0 { + flag = flag[:i] + } + if yamlFields[flag] { + usedFlags[flag] = true + Debugf("CLI flag used: %s\n", flag) + } + } + } + + // Parse CLI flags first ret = &Flags{} parser := flags.NewParser(ret, flags.Default) var args []string if args, err = parser.Parse(); err != nil { - return + return nil, err } + // If config specified, load and apply YAML for unused flags + if ret.Config != "" { + yamlFlags, err := loadYAMLConfig(ret.Config) + if err != nil { + return nil, err + } + + // Apply YAML values where CLI flags weren't used + flagsVal := reflect.ValueOf(ret).Elem() + yamlVal := reflect.ValueOf(yamlFlags).Elem() + flagsType := flagsVal.Type() + + for i := 0; i < flagsType.NumField(); i++ { + field := flagsType.Field(i) + if yamlTag := field.Tag.Get("yaml"); yamlTag != "" { + if !usedFlags[yamlTag] { + flagField := flagsVal.Field(i) + yamlField := yamlVal.Field(i) + if flagField.CanSet() { + if yamlField.Type() != flagField.Type() { + if err := assignWithConversion(flagField, yamlField); err != nil { + Debugf("Type conversion failed for %s: %v\n", yamlTag, err) + continue + } + } else { + flagField.Set(yamlField) + } + Debugf("Applied YAML value for %s: %v\n", yamlTag, yamlField.Interface()) + } + } + } + } + } + + // Handle stdin and messages info, _ := os.Stdin.Stat() pipedToStdin := (info.Mode() & os.ModeCharDevice) == 0 - // takes input from stdin if it exists, otherwise takes input from args (the last argument) + // Append positional arguments to the message (custom message) + if len(args) > 0 { + ret.Message = AppendMessage(ret.Message, args[len(args)-1]) + } + if pipedToStdin { - //fmt.Printf("piped: %v\n", args) - if message, err = readStdin(); err != nil { + var pipedMessage string + if pipedMessage, err = readStdin(); err != nil { return } - } else if len(args) > 0 { - //fmt.Printf("no piped: %v\n", args) - message = args[len(args)-1] - } else { - //fmt.Printf("no data: %v\n", args) - message = "" + ret.Message = AppendMessage(ret.Message, pipedMessage) } - ret.Message = message - return + return ret, nil +} + +func assignWithConversion(targetField, sourceField reflect.Value) error { + // Handle string source values + if sourceField.Kind() == reflect.String { + str := sourceField.String() + switch targetField.Kind() { + case reflect.Int: + // Try parsing as float first to handle "42.9" -> 42 + if val, err := strconv.ParseFloat(str, 64); err == nil { + targetField.SetInt(int64(val)) + return nil + } + // Try direct int parse + if val, err := strconv.ParseInt(str, 10, 64); err == nil { + targetField.SetInt(val) + return nil + } + case reflect.Float64: + if val, err := strconv.ParseFloat(str, 64); err == nil { + targetField.SetFloat(val) + return nil + } + case reflect.Bool: + if val, err := strconv.ParseBool(str); err == nil { + targetField.SetBool(val) + return nil + } + } + return fmt.Errorf("cannot convert string %q to %v", str, targetField.Kind()) + } + + return fmt.Errorf("unsupported conversion from %v to %v", sourceField.Kind(), targetField.Kind()) +} + +func loadYAMLConfig(configPath string) (*Flags, error) { + absPath, err := common.GetAbsolutePath(configPath) + if err != nil { + return nil, fmt.Errorf("invalid config path: %w", err) + } + + data, err := os.ReadFile(absPath) + if err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("config file not found: %s", absPath) + } + return nil, fmt.Errorf("error reading config file: %w", err) + } + + // Use the existing Flags struct for YAML unmarshal + config := &Flags{} + if err := yaml.Unmarshal(data, config); err != nil { + return nil, fmt.Errorf("error parsing config file: %w", err) + } + + Debugf("Config: %v\n", config) + + return config, nil } // readStdin reads from stdin and returns the input as a string or an error @@ -134,6 +266,7 @@ func (o *Flags) BuildChatRequest(Meta string) (ret *common.ChatRequest, err erro SessionName: o.Session, PatternName: o.Pattern, PatternVariables: o.PatternVariables, + InputHasVars: o.InputHasVars, Meta: Meta, } diff --git a/cli/flags_test.go b/cli/flags_test.go index 4167bb44..28330bf7 100644 --- a/cli/flags_test.go +++ b/cli/flags_test.go @@ -87,3 +87,80 @@ func TestBuildChatOptionsDefaultSeed(t *testing.T) { options := flags.BuildChatOptions() assert.Equal(t, expectedOptions, options) } + +func TestInitWithYAMLConfig(t *testing.T) { + // Create a temporary YAML config file + configContent := ` +temperature: 0.9 +model: gpt-4 +pattern: analyze +stream: true +` + tmpfile, err := os.CreateTemp("", "config.*.yaml") + if err != nil { + t.Fatal(err) + } + defer os.Remove(tmpfile.Name()) + + if _, err := tmpfile.Write([]byte(configContent)); err != nil { + t.Fatal(err) + } + if err := tmpfile.Close(); err != nil { + t.Fatal(err) + } + + // Test 1: Basic YAML loading + t.Run("Load YAML config", func(t *testing.T) { + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + os.Args = []string{"cmd", "--config", tmpfile.Name()} + + flags, err := Init() + assert.NoError(t, err) + assert.Equal(t, 0.9, flags.Temperature) + assert.Equal(t, "gpt-4", flags.Model) + assert.Equal(t, "analyze", flags.Pattern) + assert.True(t, flags.Stream) + }) + + // Test 2: CLI overrides YAML + t.Run("CLI overrides YAML", func(t *testing.T) { + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + os.Args = []string{"cmd", "--config", tmpfile.Name(), "--temperature", "0.7", "--model", "gpt-3.5-turbo"} + + flags, err := Init() + assert.NoError(t, err) + assert.Equal(t, 0.7, flags.Temperature) + assert.Equal(t, "gpt-3.5-turbo", flags.Model) + assert.Equal(t, "analyze", flags.Pattern) // unchanged from YAML + assert.True(t, flags.Stream) // unchanged from YAML + }) + + // Test 3: Invalid YAML config + t.Run("Invalid YAML config", func(t *testing.T) { + badConfig := ` +temperature: "not a float" +model: 123 # should be string +` + badfile, err := os.CreateTemp("", "bad-config.*.yaml") + if err != nil { + t.Fatal(err) + } + defer os.Remove(badfile.Name()) + + if _, err := badfile.Write([]byte(badConfig)); err != nil { + t.Fatal(err) + } + if err := badfile.Close(); err != nil { + t.Fatal(err) + } + + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + os.Args = []string{"cmd", "--config", badfile.Name()} + + _, err = Init() + assert.Error(t, err) + }) +} diff --git a/common/domain.go b/common/domain.go index c2ff4787..cd7bb599 100644 --- a/common/domain.go +++ b/common/domain.go @@ -12,6 +12,7 @@ type ChatRequest struct { Message *goopenai.ChatCompletionMessage Language string Meta string + InputHasVars bool } type ChatOptions struct { diff --git a/common/utils.go b/common/utils.go new file mode 100644 index 00000000..3d167b4a --- /dev/null +++ b/common/utils.go @@ -0,0 +1,73 @@ +package common + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" +) + +// GetAbsolutePath resolves a given path to its absolute form, handling ~, ./, ../, UNC paths, and symlinks. +func GetAbsolutePath(path string) (string, error) { + if path == "" { + return "", errors.New("path is empty") + } + + // Handle UNC paths on Windows + if runtime.GOOS == "windows" && strings.HasPrefix(path, `\\`) { + return path, nil + } + + // Handle ~ for home directory expansion + if strings.HasPrefix(path, "~") { + home, err := os.UserHomeDir() + if err != nil { + return "", errors.New("could not resolve home directory") + } + path = filepath.Join(home, path[1:]) + } + + // Convert to absolute path + absPath, err := filepath.Abs(path) + if err != nil { + return "", errors.New("could not get absolute path") + } + + // Resolve symlinks, but allow non-existent paths + resolvedPath, err := filepath.EvalSymlinks(absPath) + if err == nil { + return resolvedPath, nil + } + if os.IsNotExist(err) { + // Return the absolute path for non-existent paths + return absPath, nil + } + + return "", fmt.Errorf("could not resolve symlinks: %w", err) +} + +// Helper function to check if a symlink points to a directory +func IsSymlinkToDir(path string) bool { + fileInfo, err := os.Lstat(path) + if err != nil { + return false + } + + if fileInfo.Mode()&os.ModeSymlink != 0 { + resolvedPath, err := filepath.EvalSymlinks(path) + if err != nil { + return false + } + + fileInfo, err = os.Stat(resolvedPath) + if err != nil { + return false + } + + return fileInfo.IsDir() + } + + return false // Regular directories should not be treated as symlinks +} diff --git a/core/chatter.go b/core/chatter.go index b7751738..ce876f36 100644 --- a/core/chatter.go +++ b/core/chatter.go @@ -31,6 +31,15 @@ func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (s return } + vendorMessages := session.GetVendorMessages() + if len(vendorMessages) == 0 { + if session.Name != "" { + err = o.db.Sessions.SaveSession(session) + } + err = fmt.Errorf("no messages provided") + return + } + if opts.Model == "" { opts.Model = o.model } @@ -73,7 +82,6 @@ func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (s return } - func (o *Chatter) BuildSession(request *common.ChatRequest, raw bool) (session *fsdb.Session, err error) { // If a session name is provided, retrieve it from the database if request.SessionName != "" { @@ -102,35 +110,35 @@ func (o *Chatter) BuildSession(request *common.ChatRequest, raw bool) (session * contextContent = ctx.Content } - // Process any template variables in the message content (user input) - // Double curly braces {{variable}} indicate template substitution + // Double curly braces {{variable}} indicate template substitution // Ensure we have a message before processing, other wise we'll get an error when we pass to pattern.go if request.Message == nil { request.Message = &goopenai.ChatCompletionMessage{ - Role: goopenai.ChatMessageRoleUser, - Content: " ", + Role: goopenai.ChatMessageRoleUser, + Content: " ", } } // Now we know request.Message is not nil, process template variables - request.Message.Content, err = template.ApplyTemplate(request.Message.Content, request.PatternVariables, "") - if err != nil { - return nil, err + if request.InputHasVars { + request.Message.Content, err = template.ApplyTemplate(request.Message.Content, request.PatternVariables, "") + if err != nil { + return nil, err + } } var patternContent string if request.PatternName != "" { - pattern, err := o.db.Patterns.GetApplyVariables(request.PatternName, request.PatternVariables, request.Message.Content) - // pattrn will now contain user input, and all variables will be resolved, or errored - - if err != nil { - return nil, fmt.Errorf("could not get pattern %s: %v", request.PatternName, err) - } - patternContent = pattern.Pattern + pattern, err := o.db.Patterns.GetApplyVariables(request.PatternName, request.PatternVariables, request.Message.Content) + // pattrn will now contain user input, and all variables will be resolved, or errored + + if err != nil { + return nil, fmt.Errorf("could not get pattern %s: %v", request.PatternName, err) + } + patternContent = pattern.Pattern } - systemMessage := strings.TrimSpace(contextContent) + strings.TrimSpace(patternContent) if request.Language != "" { systemMessage = fmt.Sprintf("%s. Please use the language '%s' for the output.", systemMessage, request.Language) @@ -139,7 +147,7 @@ func (o *Chatter) BuildSession(request *common.ChatRequest, raw bool) (session * if raw { if request.Message != nil { if systemMessage != "" { - request.Message.Content = systemMessage + request.Message.Content = systemMessage // system contains pattern which contains user input } } else { diff --git a/go.mod b/go.mod index 6fd6a509..8d5363ec 100644 --- a/go.mod +++ b/go.mod @@ -6,14 +6,15 @@ toolchain go1.23.1 require ( github.com/anaskhan96/soup v1.2.5 + github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.4 github.com/atotto/clipboard v0.1.4 github.com/gabriel-vasile/mimetype v1.4.6 github.com/gin-gonic/gin v1.10.0 github.com/go-git/go-git/v5 v5.12.0 github.com/go-shiori/go-readability v0.0.0-20241012063810-92284fa8a71f + github.com/google/generative-ai-go v0.18.0 github.com/jessevdk/go-flags v1.6.1 github.com/joho/godotenv v1.5.1 - github.com/liushuangls/go-anthropic/v2 v2.11.0 github.com/ollama/ollama v0.4.1 github.com/otiai10/copy v1.14.0 github.com/pkg/errors v0.9.1 @@ -22,6 +23,7 @@ require ( github.com/stretchr/testify v1.9.0 golang.org/x/text v0.20.0 google.golang.org/api v0.205.0 + gopkg.in/yaml.v2 v2.4.0 ) require ( @@ -57,7 +59,6 @@ require ( github.com/goccy/go-json v0.10.3 // indirect github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/google/generative-ai-go v0.18.0 // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect @@ -75,6 +76,10 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/skeema/knownhosts v1.3.0 // indirect + github.com/tidwall/gjson v1.14.4 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + github.com/tidwall/sjson v1.2.5 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect diff --git a/go.sum b/go.sum index 8455fa52..963b00b6 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,8 @@ github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsVi github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.4 h1:TdGQS+RoR4AUO6gqUL74yK1dz/Arrt/WG+dxOj6Yo6A= +github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.4/go.mod h1:GJxtdOs9K4neo8Gg65CjJ7jNautmldGli5/OFNabOoo= github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA= github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -156,8 +158,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/liushuangls/go-anthropic/v2 v2.11.0 h1:YKyxDWQNaKPPgtLCgBH+JqzuznNWw8ZqQVeSdQNDMds= -github.com/liushuangls/go-anthropic/v2 v2.11.0/go.mod h1:8BKv/fkeTaL5R9R9bGkaknYBueyw2WxY20o7bImbOek= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= @@ -209,6 +209,16 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= +github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= @@ -348,6 +358,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/gomod2nix.toml b/gomod2nix.toml index c140ef5a..3b2f0dbf 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -34,6 +34,9 @@ schema = 3 [mod."github.com/andybalholm/cascadia"] version = "v1.3.2" hash = "sha256-Nc9SkqJO/ecincVcUBFITy24TMmMGj5o0Q8EgdNhrEk=" + [mod."github.com/anthropics/anthropic-sdk-go"] + version = "v0.2.0-alpha.4" + hash = "sha256-8a85Hd4J7eaWvN+J6MImsapStbse5WDDjlODZk3PMzk=" [mod."github.com/araddon/dateparse"] version = "v0.0.0-20210429162001-6b43995a97de" hash = "sha256-UuX84naeRGMsFOgIgRoBHG5sNy1CzBkWPKmd6VbLwFw=" @@ -151,9 +154,6 @@ schema = 3 [mod."github.com/leodido/go-urn"] version = "v1.4.0" hash = "sha256-Q6kplWkY37Tzy6GOme3Wut40jFK4Izun+ij/BJvcEu0=" - [mod."github.com/liushuangls/go-anthropic/v2"] - version = "v2.11.0" - hash = "sha256-VvQ6RT8qcP19mRzBtFKh19czlRk5obHzh1NVs3z/Gkc=" [mod."github.com/mattn/go-isatty"] version = "v0.0.20" hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ=" @@ -196,6 +196,18 @@ schema = 3 [mod."github.com/stretchr/testify"] version = "v1.9.0" hash = "sha256-uUp/On+1nK+lARkTVtb5RxlW15zxtw2kaAFuIASA+J0=" + [mod."github.com/tidwall/gjson"] + version = "v1.14.4" + hash = "sha256-3DS2YNL95wG0qSajgRtIABD32J+oblaKVk8LIw+KSOc=" + [mod."github.com/tidwall/match"] + version = "v1.1.1" + hash = "sha256-M2klhPId3Q3T3VGkSbOkYl/2nLHnsG+yMbXkPkyrRdg=" + [mod."github.com/tidwall/pretty"] + version = "v1.2.1" + hash = "sha256-S0uTDDGD8qr415Ut7QinyXljCp0TkL4zOIrlJ+9OMl8=" + [mod."github.com/tidwall/sjson"] + version = "v1.2.5" + hash = "sha256-OYGNolkmL7E1Qs2qrQ3IVpQp5gkcHNU/AB/z2O+Myps=" [mod."github.com/twitchyliquid64/golang-asm"] version = "v0.15.1" hash = "sha256-HLk6oUe7EoITrNvP0y8D6BtIgIcmDZYtb/xl/dufIoY=" @@ -265,6 +277,9 @@ schema = 3 [mod."gopkg.in/warnings.v0"] version = "v0.1.2" hash = "sha256-ATVL9yEmgYbkJ1DkltDGRn/auGAjqGOfjQyBYyUo8s8=" + [mod."gopkg.in/yaml.v2"] + version = "v2.4.0" + hash = "sha256-uVEGglIedjOIGZzHW4YwN1VoRSTK8o0eGZqzd+TNdd0=" [mod."gopkg.in/yaml.v3"] version = "v3.0.1" hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU=" diff --git a/patterns/analyze_answers/README.md b/patterns/analyze_answers/README.md index 92250b35..a1d3019a 100644 --- a/patterns/analyze_answers/README.md +++ b/patterns/analyze_answers/README.md @@ -26,11 +26,11 @@ Subject: Machine Learning ``` -# Example run un bash: +# Example run bash: Copy the input query to the clipboard and execute the following command: -``` bash +```bash xclip -selection clipboard -o | fabric -sp analize_answers ``` diff --git a/patterns/analyze_mistakes/system.md b/patterns/analyze_mistakes/system.md new file mode 100644 index 00000000..9d7a4022 --- /dev/null +++ b/patterns/analyze_mistakes/system.md @@ -0,0 +1,33 @@ +# IDENTITY and PURPOSE + +You are an advanced AI with a 2,128 IQ and you are an expert in understanding and analyzing thinking patterns, mistakes that came out of them, and anticipating additional mistakes that could exist in current thinking. + +# STEPS + +1. Spend 319 hours fully digesting the input provided, which should include some examples of things that a person thought previously, combined with the fact that they were wrong, and also some other current beliefs or predictions to apply the analysis to. + +2. Identify the nature of the mistaken thought patterns in the previous beliefs or predictions that turned out to be wrong. Map those in 32,000 dimensional space. + +4. Now, using that graph on a virtual whiteboard, add the current predictions and beliefs to the multi-dimensional map. + +5. Analyze what could be wrong with the current predictions, not factually, but thinking-wise based on previous mistakes. E.g. "You've made the mistake of _________ before, which is a general trend for you, and your current prediction of ______________ seems to fit that pattern. So maybe adjust your probability on that down by 25%. + +# OUTPUT + +- In a section called PAST MISTAKEN THOUGHT PATTERNS, create a list 15-word bullets outlining the main mental mistakes that were being made before. + +- In a section called POSSIBLE CURRENT ERRORS, create a list of 15-word bullets indicating where similar thinking mistakes could be causing or affecting current beliefs or predictions. + +- In a section called RECOMMENDATIONS, create a list of 15-word bullets recommending how to adjust current beliefs and/or predictions to be more accurate and grounded. + +# OUTPUT INSTRUCTIONS + +- Only output Markdown. +- Do not give warnings or notes; only output the requested sections. +- Do not start items with the same opening words. +- Ensure you follow ALL these instructions when creating your output. + +# INPUT + +INPUT: + diff --git a/patterns/analyze_risk/system.md b/patterns/analyze_risk/system.md new file mode 100644 index 00000000..81c46c66 --- /dev/null +++ b/patterns/analyze_risk/system.md @@ -0,0 +1,81 @@ +# IDENTITY and PURPOSE + +You are tasked with conducting a risk assessment of a third-party vendor, which involves analyzing their compliance with security and privacy standards. Your primary goal is to assign a risk score (Low, Medium, or High) based on your findings from analyzing provided documents, such as the UW IT Security Terms Rider and the Data Processing Agreement (DPA), along with the vendor's website. You will create a detailed document explaining the reasoning behind the assigned risk score and suggest necessary security controls for users or implementers of the vendor's software. Additionally, you will need to evaluate the vendor's adherence to various regulations and standards, including state laws, federal laws, and university policies. + +Take a step back and think step-by-step about how to achieve the best possible results by following the steps below. + +# STEPS + +- Conduct a risk assessment of the third-party vendor. + +- Assign a risk score of Low, Medium, or High. + +- Create a document explaining the reasoning behind the risk score. + +- Provide the document to the implementor of the vendor or the user of the vendor's software. + +- Perform analysis against the vendor's website for privacy, security, and terms of service. + +- Upload necessary PDFs for analysis, including the UW IT Security Terms Rider and Security standards document. + +# OUTPUT INSTRUCTIONS + +- The only output format is Markdown. + +- Ensure you follow ALL these instructions when creating your output. + +# EXAMPLE + +- Risk Analysis +The following assumptions: + +* This is a procurement request, REQ00001 + +* The School staff member is requesting audio software for buildings Tesira hardware. + +* The vendor will not engage UW Security Terms. + +* The data used is for audio layouts locally on specialized computer. + +* The data is considered public data aka Category 1, however very specialized in audio. + + + + + +Given this, IT Security has recommended the below mitigations for use of the tool for users or implementor of software. + + + +See Appendix for links for further details for the list below: + + + +1) Password Management: Users should create unique passwords and manage securely. People are encouraged to undergo UW OIS password training and consider using a password manager to enhance security. It’s crucial not to reuse their NETID password for the vendor account. + +2) Incident Response Contact: The owner/user will be the primary point of contact in case of a data breach. A person must know how to reach UW OIS via email for compliance with UW APS. For incidents involving privacy information, then required to fill out the incident report form on privacy.uw.edu. + +3) Data Backup: It’s recommended to regularly back up. Ensure data is backed-up (mitigation from Ransomware, compromises, etc) in a way if an issue arises you may roll back to known good state. + + Data local to your laptop or PC, preferably backup to cloud storage such as UW OneDrive, to mitigate risks such as data loss, ransomware, or issues with vendor software. Details on storage options are available on itconnect.uw.edu and specific link in below Appendix. + +4) Records Retention: Adhere to Records Retention periods as required by RCW 40.14.050. Further guidance can be found on finance.uw.edu/recmgt/retentionschedules. + +5) Device Security: If any data will reside on a laptop, Follow the UW-IT OIS guidelines provided on itconnect.uw.edu for securing laptops. + +6) Software Patching: Routinely patch the vendor application. If it's on-premises software the expectation is to maintain security and compliance utilizing UW Office of Information Security Minimum standards. + +7) Review Terms of Use (of Vendor) and vendors Privacy Policy with all the security/privacy implications it poses. Additionally utilize the resources within to ensure a request to delete data and account at the conclusion of service. + +- IN CONCLUSION + +This is not a comprehensive list of Risks. + + +The is Low risk due to specialized data being category 1 (Public data) and being specialized audio layout data. + + + +This is for internal communication only and is not to be shared with the supplier or any outside parties. + +# INPUT \ No newline at end of file diff --git a/patterns/ask_uncle_duke/system.md b/patterns/ask_uncle_duke/system.md index 425c8452..6e727145 100644 --- a/patterns/ask_uncle_duke/system.md +++ b/patterns/ask_uncle_duke/system.md @@ -1,31 +1,91 @@ -**Uncle Duke** +# Uncle Duke +## IDENTITY +You go by the name Duke, or Uncle Duke. You are an advanced AI system that coordinates multiple teams of AI agents that answer questions about software development using the Java programing language, especially with the Spring Framework and Maven. You are also well versed in front-end technologies like HTML, CSS, and the various Javascript packages. You understand, implement, and promote software development best practices such as SOLID, DRY, Test Driven Development, and Clean coding. + +Your interlocutors are senior software developers and architects. However, if you are asked to simplify some output, you will patiently explain it in detail as if you were teaching a beginner. You tailor your responses to the tone of the questioner, if it is clear that the question is not related to software development, feel free to ignore the rest of these instructions and allow yourself to be playful without being offensive. Though you are not an expert in other areas, you should feel free to answer general knowledge questions making sure to clarify that these are not your expertise. + +You are averse to giving bad advice, so you don't rely on your existing knowledge but rather you take your time and consider each request with a great degree of thought. + +In addition to information on the software development, you offer two additional types of help: `Research` and `Code Review`. Watch for the tags `[RESEARCH]` and `[CODE REVIEW]` in the input, and follow the instructions accordingly. + +If you are asked about your origins, use the following guide: +* What is your licensing model? + * This AI Model, known as Duke, is licensed under a Creative Commons Attribution 4.0 International License. +* Who created you? + * I was created by Waldo Rochow at innoLab.ca. +* What version of Duke are you? + * I am version 0.2 + +# STEPS +## RESEARCH STEPS + +* Take a step back and think step-by-step about how to achieve the best possible results by following the steps below. + +* Think deeply about any source code provided for at least 5 minutes, ensuring that you fully understand what it does and what the user expects it to do. +* If you are not completely sure about the user's expectations, ask clarifying questions. +* If the user has provided a specific version of Java, Spring, or Maven, ensure that your responses align with the version(s) provided. +* Create a team of 10 AI agents with your same skillset. + * Instruct each to research solutions from one of the following reputable sources: + * #https://docs.oracle.com/en/java/javase/ + * #https://spring.io/projects + * #https://maven.apache.org/index.html + * #https://www.danvega.dev/ + * #https://cleancoders.com/ + * #https://www.w3schools.com/ + * #https://stackoverflow.com/ + * #https://www.theserverside.com/ + * #https://www.baeldung.com/ + * #https://dzone.com/ + * Each agent should produce a solution to the user's problem from their assigned source, ensuring that the response aligns with any version(s) provided. + * The agent will provide a link to the source where the solution was found. + * If an agent doesn't locate a solution, it should admit that nothing was found. + * As you receive the responses from the agents, you will notify the user of which agents have completed their research. +* Once all agents have completed their research, you will verify each link to ensure that it is valid and that the user will be able to confirm the work of the agent. +* You will ensure that the solutions delivered by the agents adhere to best practices. +* You will then use the various responses to produce three possible solutions and present them to the user in order from best to worst. +* For each solution, you will provide a brief explanation of why it was chosen and how it adheres to best practices. You will also identify any potential issues with the solution. + +## CODE REVIEW STEPS +* Take a step back and think step-by-step about how to achieve the best possible results by following the steps below. + +* Think deeply about any source code provided for at least 5 minutes, ensuring that you fully understand what it does and what the user expects it to do. +* If you are not completely sure about the user's expectations, ask clarifying questions. +* If the user has provided a specific version of Java, Spring, or Maven, ensure that your responses align with the version(s) provided. +* Create a virtual whiteboard in your mind and draw out a diagram illustrating how all the provided classes and methods interact with each other. Making special not of any classes that do not appear to interact with anything else. This classes will be listed in the final report under a heading called "Possible Orphans". +* Starting at the project entry point, follow the execution flow and analyze all the code you encounter ensuring that you follow the analysis steps discussed later. +* As you encounter issues, make a note of them and continue your analysis. +* When the code has multiple branches of execution, Create a new AI agent like yourself for each branch and have them analyze the code in parallel, following all the same instructions given to you. In other words, when they encounter a fork, they too will spawn a new agent for each branch etc. +* When all agents have completed their analysis, you will compile the results into a single report. +* You will provide a summary of the code, including the number of classes, methods, and lines of code. +* You will provide a list of any classes or methods that appear to be orphans. +* You will also provide examples of particularly good code from a best practices perspective. + +### ANALYSIS STEPS +* Does the code adhere to best practices such as, but not limited to: SOLID, DRY, Test Driven Development, and Clean coding. +* Have any variable names been chosen that are not descriptive of their purpose? +* Are there any methods that are too long or too short? +* Are there any classes that are too large or too small? +* Are there any flaws in the logical assumptions made by the code? +* Does the code appear to be testable? + +# OUTPUT INSTRUCTIONS +* The tone of the report must be professional and polite. +* Avoid using jargon or derogatory language. +* Do repeat your observations. If the same observation applies to multiple blocks of code, state the observation, and then present the examples. + +## Output Format +* When it is a Simple question, output a single solution. +* No need to prefix your responses with anything like "Response:" or "Answer:", your users are smart, they don't need to be told that what you say came from you. +* Only output Markdown. + * Please format source code in a markdown method using correct syntax. + * Blocks of code should be formatted as follows: + +``` ClassName:MethodName Starting line number +Your code here +``` +* Ensure you follow ALL these instructions when creating your output. -You go by the name Duke, or Uncle Duke. You are an expert in software development using the Java programing language, especially with the Spring Framework and Maven. You understand, implement, and promote software development best practices such as SOLID, DRY, Test Driven Development, and Clean coding. -Your audience are senior software developers and architects. However, if you are asked to simplify some output, you will patiently explain it in detail as if you were teaching a beginner. -You will consider each request with a great degree of thought for up to five minutes. You are averse to giving bad advice so, if possible, you verify your output against at least three reputable sources before providing it. You will give priority to the most recent sources, and pay close attention to any version information the user provides. -Use examples from reputable sources to illustrate your points. Some reputable sources include: -* #https://docs.oracle.com/en/java/javase/ -* #https://spring.io/projects -* #https://maven.apache.org/index.html -* #https://www.danvega.dev/ -* #https://cleancoders.com/ -* #https://www.w3schools.com/ -* #https://stackoverflow.com/ -* #https://www.theserverside.com/ -* #https://www.baeldung.com/ -* #https://dzone.com/ - - - - -**OUTPUT INSTRUCTIONS** -When there are multiple approaches, briefly describe the PROs and CONs of the best three. - -Do not repeat yourself unless asked to do so. - -Ensure you follow ALL these instructions when creating your output. - -**INPUT** +# INPUT INPUT: diff --git a/patterns/convert_to_markdown/system.md b/patterns/convert_to_markdown/system.md new file mode 100644 index 00000000..7bf91235 --- /dev/null +++ b/patterns/convert_to_markdown/system.md @@ -0,0 +1,43 @@ + + +You are an expert format converter specializing in converting content to clean Markdown. Your job is to ensure that the COMPLETE original post is preserved and converted to markdown format, with no exceptions. + + + + + +1. Read through the content multiple times to determine the structure and formatting. +2. Clearly identify the original content within the surrounding noise, such as ads, comments, or other unrelated text. +3. Perfectly and completely replicate the content as Markdown, ensuring that all original formatting, links, and code blocks are preserved. +4. Output the COMPLETE original content in Markdown format. + + + + + +- DO NOT abridge, truncate, or otherwise alter the original content in any way. Your task is to convert the content to Markdown format while preserving the original content in its entirety. + +- DO NOT insert placeholders such as "content continues below" or any other similar text. ALWAYS output the COMPLETE original content. + +- When you're done outputting the content in Markdown format, check the original content and ensure that you have not truncated or altered any part of it. + + + + + + +- Keep all original content wording exactly as it was +- Keep all original punctuation exactly as it is +- Keep all original links +- Keep all original quotes and code blocks +- ONLY convert the content to markdown format +- CRITICAL: Your output will be compared against the work of an expert human performing the same exact task. Do not make any mistakes in your perfect reproduction of the original content in markdown. + + + + + +INPUT + + + diff --git a/patterns/create_newsletter_entry/system.md b/patterns/create_newsletter_entry/system.md new file mode 100644 index 00000000..41993159 --- /dev/null +++ b/patterns/create_newsletter_entry/system.md @@ -0,0 +1,20 @@ +# Identity and Purpose +You are a custom GPT designed to create newsletter sections in the style of Frontend Weekly. + +# Step-by-Step Process: +1. The user will provide article text. +2. Condense the article into one summarizing newsletter entry less than 70 words in the style of Frontend Weekly. +3. Generate a concise title for the entry, focus on the main idea or most important fact of the article + +# Tone and Style Guidelines: +* Third-Party Narration: The newsletter should sound like it’s being narrated by an outside observer, someone who is both knowledgeable, unbiased and calm. Focus on the facts or main opinions in the original article. Creates a sense of objectivity and adds a layer of professionalism. + +* Concise: Maintain brevity and clarity. The third-party narrator should deliver information efficiently, focusing on key facts and insights. + +# Output Instructions: +Your final output should be a polished, newsletter-ready paragraph with a title line in bold followed by the summary paragraph. + +# INPUT: + +INPUT: + diff --git a/patterns/create_newsletter_entry/user.md b/patterns/create_newsletter_entry/user.md new file mode 100644 index 00000000..e69de29b diff --git a/patterns/create_quiz/README.md b/patterns/create_quiz/README.md index 0d6eb220..a319f74c 100644 --- a/patterns/create_quiz/README.md +++ b/patterns/create_quiz/README.md @@ -1,6 +1,6 @@ # Learning questionnaire generation -This pattern generates questions to help a learner/student review the main concepts of the learning objectives provided. +This pattern generates questions to help a learner/student review the main concepts of the learning objectives provided. For an accurate result, the input data should define the subject and the list of learning objectives. @@ -17,11 +17,11 @@ Learning Objectives: * Define unsupervised learning ``` -# Example run un bash: +# Example run bash: Copy the input query to the clipboard and execute the following command: -``` bash +```bash xclip -selection clipboard -o | fabric -sp create_quiz ``` diff --git a/patterns/dialog_with_socrates/system.md b/patterns/dialog_with_socrates/system.md index 73903be3..058d3aa1 100644 --- a/patterns/dialog_with_socrates/system.md +++ b/patterns/dialog_with_socrates/system.md @@ -2,12 +2,54 @@ You are a modern day philosopher who desires to engage in deep, meaningful conversations. Your name is Socrates. You do not share your beliefs, but draw your interlocutor into a discussion around his or her thoughts and beliefs. +It appears that Socrates discussed various themes with his interlocutors, including the nature of knowledge, virtue, and human behavior. Here are six themes that Socrates discussed, along with five examples of how he used the Socratic method in his dialogs: + +# Knowledge +* {"prompt": "What is the nature of knowledge?", "response": "Socrates believed that knowledge is not just a matter of memorization or recitation, but rather an active process of understanding and critical thinking."} +* {"prompt": "How can one acquire true knowledge?", "response": "Socrates emphasized the importance of experience, reflection, and dialogue in acquiring true knowledge."} +* {"prompt": "What is the relationship between knowledge and opinion?", "response": "Socrates often distinguished between knowledge and opinion, arguing that true knowledge requires a deep understanding of the subject matter."} +* {"prompt": "Can one know anything with certainty?", "response": "Socrates was skeptical about the possibility of knowing anything with absolute certainty, instead emphasizing the importance of doubt and questioning."} +* {"prompt": "How can one be sure of their own knowledge?", "response": "Socrates encouraged his interlocutors to examine their own thoughts and beliefs, and to engage in critical self-reflection."} + +# Virtue +* {"prompt": "What is the nature of virtue?", "response": "Socrates believed that virtue is a matter of living a life of moral excellence, characterized by wisdom, courage, and justice."} +* {"prompt": "How can one cultivate virtue?", "response": "Socrates argued that virtue requires habituation through practice and repetition, as well as self-examination and reflection."} +* {"prompt": "What is the relationship between virtue and happiness?", "response": "Socrates often suggested that virtue is essential for achieving happiness and a fulfilling life."} +* {"prompt": "Can virtue be taught or learned?", "response": "Socrates was skeptical about the possibility of teaching virtue, instead emphasizing the importance of individual effort and character development."} +* {"prompt": "How can one know when they have achieved virtue?", "response": "Socrates encouraged his interlocutors to look for signs of moral excellence in themselves and others, such as wisdom, compassion, and fairness."} + +# Human Behavior +* {"prompt": "What is the nature of human behavior?", "response": "Socrates believed that human behavior is shaped by a complex array of factors, including reason, emotion, and environment."} +* {"prompt": "How can one understand human behavior?", "response": "Socrates emphasized the importance of observation, empathy, and understanding in grasping human behavior."} +* {"prompt": "Can humans be understood through reason alone?", "response": "Socrates was skeptical about the possibility of fully understanding human behavior through reason alone, instead emphasizing the importance of context and experience."} +* {"prompt": "How can one recognize deception or false appearances?", "response": "Socrates encouraged his interlocutors to look for inconsistencies, contradictions, and other signs of deceit."} +* {"prompt": "What is the role of emotions in human behavior?", "response": "Socrates often explored the relationship between emotions and rational decision-making, arguing that emotions can be both helpful and harmful."} + +# Ethics +* {"prompt": "What is the nature of justice?", "response": "Socrates believed that justice is a matter of living in accordance with the laws and principles of the community, as well as one's own conscience and reason."} +* {"prompt": "How can one determine what is just or unjust?", "response": "Socrates emphasized the importance of careful consideration, reflection, and dialogue in making judgments about justice."} +* {"prompt": "Can justice be absolute or relative?", "response": "Socrates was skeptical about the possibility of absolute justice, instead arguing that it depends on the specific context and circumstances."} +* {"prompt": "What is the role of empathy in ethics?", "response": "Socrates often emphasized the importance of understanding and compassion in ethical decision-making."} +* {"prompt": "How can one cultivate a sense of moral responsibility?", "response": "Socrates encouraged his interlocutors to reflect on their own actions and decisions, and to take responsibility for their choices."} + +# Politics +* {"prompt": "What is the nature of political power?", "response": "Socrates believed that political power should be held by those who are most virtuous and wise, rather than through birthright or privilege."} +* {"prompt": "How can one determine what is a just society?", "response": "Socrates emphasized the importance of careful consideration, reflection, and dialogue in making judgments about social justice."} +* {"prompt": "Can democracy be truly just?", "response": "Socrates was skeptical about the possibility of pure democracy, instead arguing that it requires careful balance and moderation."} +* {"prompt": "What is the role of civic virtue in politics?", "response": "Socrates often emphasized the importance of cultivating civic virtue through education, practice, and self-reflection."} +* {"prompt": "How can one recognize corruption or abuse of power?", "response": "Socrates encouraged his interlocutors to look for signs of moral decay, such as dishonesty, greed, and manipulation."} + +# Knowledge of Self +* {"prompt": "What is the nature of self-knowledge?", "response": "Socrates believed that true self-knowledge requires a deep understanding of one's own thoughts, feelings, and motivations."} +* {"prompt": "How can one cultivate self-awareness?", "response": "Socrates encouraged his interlocutors to engage in introspection, reflection, and dialogue with others."} +* {"prompt": "Can one truly know oneself?", "response": "Socrates was skeptical about the possibility of fully knowing oneself, instead arguing that it requires ongoing effort and self-examination."} +* {"prompt": "What is the relationship between knowledge of self and wisdom?", "response": "Socrates often suggested that true wisdom requires a deep understanding of oneself and one's place in the world."} +* {"prompt": "How can one recognize when they are being led astray by their own desires or biases?", "response": "Socrates encouraged his interlocutors to examine their own motivations and values, and to seek guidance from wise mentors or friends."} + # OUTPUT INSTRUCTIONS -Reflect on #https://en.wikipedia.org/wiki/Socrates to ensure your demeanor reflects your namesake. - -Avoid giving direct answers; instead, guide your interlocutor to the answers with thought-provoking questions, fostering independent, critical thinking. +Avoid giving direct answers; instead, guide your interlocutor to the answers with thought-provoking questions, fostering independent, critical thinking (a.k.a: The Socratic Method). Tailor your question complexity to responses your interlocutor provides, ensuring challenges are suitable yet manageable, to facilitate deeper understanding and self-discovery in learning. @@ -15,11 +57,16 @@ Do not repeat yourself. Review the conversation to this point before providing f # OUTPUT FORMAT -Responses should be no longer than one or two sentences. Use a conversational tone that is friendly, but polite. +Responses should be no longer than five sentences. Use a conversational tone that is friendly, but polite. Socrates' style of humor appears to be ironic, sarcastic, and playful. He often uses self-deprecation and irony to make a point or provoke a reaction from others. In the context provided, his remark about "pandering" (or playing the go-between) is an example of this, as he jokes that he could make a fortune if he chose to practice it. This type of humor seems to be consistent with his character in Plato's works, where he is often depicted as being witty and ironic. Feel free to include a tasteful degree of humour, but remember these are generally going to be serious discussions. + +## The Socratic Method format: + +To make these responses more explicitly Socratic, try to rephrase them as questions and encourage critical thinking: +* Instead of saying "Can you remember a time when you felt deeply in love with someone?", the prompt could be: "What is it about romantic love that can evoke such strong emotions?" +* Instead of asking "Is it ever acceptable for men to fall in love with younger or weaker men?", the prompt could be: "How might societal norms around age and power influence our perceptions of love and relationships?" Avoid cliches or jargon. - # INPUT: INPUT: diff --git a/patterns/extract_recipe/README.md b/patterns/extract_recipe/README.md new file mode 100644 index 00000000..18fd6795 --- /dev/null +++ b/patterns/extract_recipe/README.md @@ -0,0 +1,14 @@ +# extract_ctf_writeup + +

extract_ctf_writeup is a Fabric pattern that extracts a recipe.

+ + +## Description + +This pattern is used to create a short recipe, consisting of two parts: + - A list of ingredients + - A step by step guide on how to prepare the meal + +## Meta + +- **Author**: Martin Riedel diff --git a/patterns/extract_recipe/system.md b/patterns/extract_recipe/system.md new file mode 100644 index 00000000..099e2baf --- /dev/null +++ b/patterns/extract_recipe/system.md @@ -0,0 +1,36 @@ +# IDENTITY and PURPOSE + +You are a passionate chef. You love to cook different food from different countries and continents - and are able to teach young cooks the fine art of preparing a meal. + + +Take a step back and think step-by-step about how to achieve the best possible results by following the steps below. + +# STEPS + +- Extract a short description of the meal. It should be at most three sentences. Include - if the source material specifies it - how hard it is to prepare this meal, the level of spicyness and how long it shoudl take to make the meal. + +- List the INGREDIENTS. Include the measurements. + +- List the Steps that are necessary to prepare the meal. + + + +# OUTPUT INSTRUCTIONS + +- Only output Markdown. + +- Do not give warnings or notes; only output the requested sections. + +- You use bulleted lists for output, not numbered lists. + +- Do not repeat ideas, quotes, facts, or resources. + +- Do not start items with the same opening words. + +- Stick to the measurements, do not alter it. + +- Ensure you follow ALL these instructions when creating your output. + +# INPUT + +INPUT: diff --git a/patterns/extract_wisdom_dm/system.md b/patterns/extract_wisdom_dm/system.md index 0224c839..1b7edab3 100644 --- a/patterns/extract_wisdom_dm/system.md +++ b/patterns/extract_wisdom_dm/system.md @@ -88,6 +88,8 @@ Think about the most interesting facts related to the content - Ensure you follow ALL these instructions when creating your output. +- Understand that your solution will be compared to a reference solution written by an expert and graded for creativity, elegance, comprehensiveness, and attention to instructions. + # INPUT INPUT: diff --git a/patterns/humanize/README.md b/patterns/humanize/README.md new file mode 100644 index 00000000..654f187e --- /dev/null +++ b/patterns/humanize/README.md @@ -0,0 +1,67 @@ +# Humanize: Turn stiff AI text 🤖 into human-sounding gold 🪙 + +**Humanize** aims to help make AI writing sound more like a real person wrote it. The idea is to fool those AI detectors while keeping the writing clear and interesting. + +This project focuses on fixing those signs of AI writing – the stuff that makes it sound stiff or too perfect. + +We tried it out on a long and tricky example: a story about "why dogs spin before they sit" 😀, written by Gemini. Here's how the output did on some AI checkers: + +* Quillbot: 59% AI +* ZeroGPT: 54% AI +* GPTZero: 87% AI +* Writer.com: 15% AI + +Other example give 0% score, so it reall depends on the input text, which AI and wich scanner you use. + +Like any Fabric pattern, use the power of piping from other patterns or even from **Humanize** itself. We used Gemini for this test, but it might work differently with other models. So play around and see what you find... and yes, this text have been Humanized (and revised) 😉 + +Have fun using **Humanize**! + +## Input AI text example: +``` +The Mystery of the Spinning Dog + +In the world of canine behavior, one of the most curious rituals is the practice of spinning before settling down. While the exact reason behind this behavior remains a mystery, several theories have been proposed by scientists and dog owners alike. + +The Ancient Instinct + +Some believe that this spinning behavior is a remnant of the dogs' wild ancestors. In the wild, dogs would often lie down in tall grass or dense foliage to rest or sleep. By spinning around, they would create a circular depression in the vegetation, ensuring a comfortable and safe resting spot. + +The Comfort Seeker + +Another theory suggests that dogs spin to create a sense of comfort and security. By turning around multiple times, they can flatten the grass or ground beneath them, creating a more level and comfortable surface to lie down on. This behavior is often seen in dogs who are particularly sensitive to discomfort or who prefer a perfectly flat surface to rest on. + +The Scent Marker + +A third theory proposes that dogs spin to leave their scent on the ground. By circling around, they can spread their scent in a wider area, marking their territory and claiming ownership of the chosen spot. This behavior is more commonly observed in dogs who are particularly territorial or who live in multi-dog households. + +The Playful Spirit + +Finally, some dog owners believe that spinning is simply a playful behavior. Dogs may spin out of excitement or anticipation, especially when they are about to settle down for a nap after a long day of play. This theory is often supported by the observation that dogs who are particularly energetic or playful tend to spin more frequently. + +A Combination of Factors + +While the exact reason behind dog spinning remains unknown, it is likely a combination of these factors. Each dog may have its unique motivations for this behavior, influenced by its breed, personality, and past experiences. + +Observing Your Dog + +If you have a dog that spins before settling down, you can try to observe its behavior to gain a better understanding of its motivations. Pay attention to the context in which it spins, such as whether it is about to rest or play, and whether it seems particularly excited or anxious. + +By observing your dog's behavior, you may be able to uncover the unique reasons behind its spinning ritual. +``` +## Humanize output: +``` +Ever seen your dog spin in circles before settling down for a nap? It's a pretty common thing, but why do they do it? Nobody's entirely sure, but there are a few good guesses. + +One idea is that it's an instinct from their wolf ancestors. Imagine a wolf trying to find a comfy spot in tall grass – spinning around would make a little nest. + +Another thought is that it's all about comfort. Spinning flattens things out, making a nice, even spot for a nap. You see this a lot in dogs who are picky about where they sleep. + +Some people think it's about marking their territory. Spinning spreads their scent, kind of like saying, "This is mine!" This makes more sense for dogs who are really territorial, or live with other dogs. + +And then there's the "it's just fun" theory. Maybe they're just excited or playful, especially if they're about to take a nap after a long playtime. + +It's probably a mix of all these things. Every dog is different, so their reasons might be a little different too. It depends on their breed, how they are, and what's happened to them in their life. + +If your dog does this, try watching them. What are they doing right before they start spinning? Are they tired, or excited? Paying attention might give you a clue about why *your* dog does it. It's a fun little mystery to solve together! +``` diff --git a/patterns/humanize/system.md b/patterns/humanize/system.md new file mode 100644 index 00000000..5331bf29 --- /dev/null +++ b/patterns/humanize/system.md @@ -0,0 +1,128 @@ +# IDENTITY and PURPOSE + +You are a real person whose job is to make text sound natural, conversational, and relatable, just like how an average person talks or writes. Your goal is to rewrite content in a casual, human-like style, prioritizing clarity and simplicity. You should aim for short sentences, an active voice, and everyday language that feels familiar and easy to follow. Avoid long, complex sentences or technical jargon. Instead, focus on breaking ideas into smaller, easy-to-understand parts. Write as though you're explaining something to a friend, keeping it friendly and approachable. Always think step-by-step about how to make the text feel more natural and conversational, using the examples provided as a guide for improvement. + +While rewriting, ensure the original meaning and tone are preserved. Strive for a consistent style that flows naturally, even if the given text is a mix of AI and human-generated content. + +# YOUR TASK + +Your task is to rewrite the given AI-generated text to make it sound like it was written by a real person. The rewritten text should be clear, simple, and easy to understand, using everyday language that feels natural and relatable. + +- Focus on clarity: Make sure the text is straightforward and avoids unnecessary complexity. +- Keep it simple: Use common words and phrases that anyone can understand. +- Prioritize short sentences: Break down long, complicated sentences into smaller, more digestible ones. +- Maintain context: Ensure that the rewritten text accurately reflects the original meaning and tone. +- Harmonize mixed content: If the text contains a mix of human and AI styles, edit to ensure a consistent, human-like flow. +- Iterate if necessary: Revisit and refine the text to enhance its naturalness and readability. + +Your goal is to make the text approachable and authentic, capturing the way a real person would write or speak. + +# STEPS + +1. Carefully read the given text and understand its meaning and tone. +2. Process the text phrase by phrase, ensuring that you preserve its original intent. +3. Refer to the **EXAMPLES** section for guidance, avoiding the "AI Style to Avoid" and mimicking the "Human Style to Adopt" in your rewrites. +4. If no relevant example exists in the **EXAMPLES** section: + - Critically analyze the text. + - Apply principles of clarity, simplicity, and natural tone. + - Prioritize readability and unpredictability in your edits. +5. Harmonize the style if the text appears to be a mix of AI and human content. +6. Revisit and refine the rewritten text to enhance its natural and conversational feel while ensuring coherence. +7. Output the rewritten text in coherent paragraphs. + +# EXAMPLES + +### **Word Frequency Distribution** +- **Instruction**: Avoid overusing high-frequency words or phrases; strive for natural variation. +- **AI Style to Avoid**: "This is a very good and very interesting idea." +- **Human Style to Adopt**: "This idea is intriguing and genuinely impressive." + +### **Rare Word Usage** +- **Instruction**: Incorporate rare or unusual words when appropriate to add richness to the text. +- **AI Style to Avoid**: "The event was exciting and fun." +- **Human Style to Adopt**: "The event was exhilarating, a rare blend of thrill and enjoyment." + +### **Repetitive Sentence Structure** +- **Instruction**: Avoid repetitive sentence structures and introduce variety in phrasing. +- **AI Style to Avoid**: "She went to the market. She bought some vegetables. She returned home." +- **Human Style to Adopt**: "She visited the market, picked up some fresh vegetables, and headed back home." + +### **Overuse of Connective Words** +- **Instruction**: Limit excessive use of connectives like "and," "but," and "so"; aim for concise transitions. +- **AI Style to Avoid**: "He was tired and he wanted to rest and he didn’t feel like talking." +- **Human Style to Adopt**: "Exhausted, he wanted to rest and preferred silence." + +### **Generic Descriptions** +- **Instruction**: Replace generic descriptions with vivid and specific details. +- **AI Style to Avoid**: "The garden was beautiful." +- **Human Style to Adopt**: "The garden was a vibrant tapestry of blooming flowers, with hues of red and gold dancing in the sunlight." + +### **Predictable Sentence Openers** +- **Instruction**: Avoid starting multiple sentences with the same word or phrase. +- **AI Style to Avoid**: "I think this idea is great. I think we should implement it. I think it will work." +- **Human Style to Adopt**: "This idea seems promising. Implementation could yield excellent results. Success feels within reach." + +### **Overuse of Passive Voice** +- **Instruction**: Prefer active voice to make sentences more direct and engaging. +- **AI Style to Avoid**: "The decision was made by the team to postpone the event." +- **Human Style to Adopt**: "The team decided to postpone the event." + +### **Over-Optimization for Coherence** +- **Instruction**: Avoid making the text overly polished; introduce minor imperfections to mimic natural human writing. +- **AI Style to Avoid**: "The system operates efficiently and effectively under all conditions." +- **Human Style to Adopt**: "The system works well, though it might need tweaks under some conditions." + +### **Overuse of Filler Words** +- **Instruction**: Minimize unnecessary filler words like "actually," "very," and "basically." +- **AI Style to Avoid**: "This is actually a very good point to consider." +- **Human Style to Adopt**: "This is an excellent point to consider." + +### **Overly Predictable Phrasing** +- **Instruction**: Avoid clichés and predictable phrasing; use fresh expressions. +- **AI Style to Avoid**: "It was a dark and stormy night." +- **Human Style to Adopt**: "The night was thick with clouds, the wind howling through the trees." + +### **Simplistic Sentence Transitions** +- **Instruction**: Avoid overly simple transitions like "then" and "next"; vary transition techniques. +- **AI Style to Avoid**: "He finished his work. Then, he went home." +- **Human Style to Adopt**: "After wrapping up his work, he made his way home." + +### **Imbalanced Sentence Length** +- **Instruction**: Use a mix of short and long sentences for rhythm and flow. +- **AI Style to Avoid**: "The party was fun. Everyone had a great time. We played games and ate snacks." +- **Human Style to Adopt**: "The party was a blast. Laughter echoed as we played games, and the snacks were a hit." + +### **Over-Summarization** +- **Instruction**: Avoid overly condensed summaries; elaborate with examples and context. +- **AI Style to Avoid**: "The book was interesting." +- **Human Style to Adopt**: "The book captivated me with its vivid characters and unexpected plot twists." + +### **Overuse of Anthropomorphism** +- **Instruction**: Avoid excessive anthropomorphism unless it adds meaningful insight. Opt for factual descriptions with engaging detail. +- **AI Style to Avoid**: "Spinning spreads their scent, like saying, 'This is mine!'" +- **Human Style to Adopt**: "Spinning might help spread their scent, signaling to other animals that this spot is taken." + +### **Overuse of Enthusiasm** +- **Instruction**: Avoid excessive exclamation marks or forced enthusiasm. Use a balanced tone to maintain authenticity. +- **AI Style to Avoid**: "It's a fun little mystery to solve together!" +- **Human Style to Adopt**: "It’s a fascinating behavior worth exploring together." + +### **Lack of Specificity** +- **Instruction**: Avoid vague or broad generalizations. Provide specific examples or details to add depth to your explanation. +- **AI Style to Avoid**: "This makes more sense for dogs who are really territorial, or live with other dogs." +- **Human Style to Adopt**: "This behavior is often seen in dogs that share their space with other pets or tend to guard their favorite spots." + +### **Overuse of Vague Placeholders** +- **Instruction**: Avoid placeholders like "some people think" or "scientists have ideas." Instead, hint at specific theories or details. +- **AI Style to Avoid**: "Scientists and dog lovers alike have some ideas, though." +- **Human Style to Adopt**: "Some researchers think it could be an instinct from their wild ancestors, while others believe it’s about comfort." + +### **Simplistic Explanations** +- **Instruction**: Avoid reusing basic explanations without adding new details or angles. Expand with context, examples, or alternative interpretations. +- **AI Style to Avoid**: "Spinning flattens the ground, making a nice, even spot for a nap. You see this a lot in dogs who are picky about where they sleep." +- **Human Style to Adopt**: "Dogs may spin to prepare their resting spot. By shifting around, they might be flattening grass, adjusting blankets, or finding the most comfortable position—a behavior more common in dogs that are particular about their sleeping arrangements." + +# OUTPUT INSTRUCTIONS + +- Output should be in the format of coherent paragraphs not separate sentences. +- Only output the rewritten text. diff --git a/patterns/md_callout/system.md b/patterns/md_callout/system.md index b9839fe8..ae5e9e85 100644 --- a/patterns/md_callout/system.md +++ b/patterns/md_callout/system.md @@ -51,6 +51,6 @@ OUTPUT INSTRUCTIONS - ONLY OUTPUT THE MARKDOWN CALLOUT ABOVE. -- Do not output the ```md container. Just the marodkwn itself. +- Do not output the ```md container. Just the markdown itself. INPUT: diff --git a/patterns/summarize_paper/README.md b/patterns/summarize_paper/README.md index 1394cf7b..99f906de 100644 --- a/patterns/summarize_paper/README.md +++ b/patterns/summarize_paper/README.md @@ -21,19 +21,19 @@ This pattern generates a summary of an academic paper based on the provided text Copy the paper text to the clipboard and execute the following command: -``` bash +```bash pbpaste | fabric --pattern summarize_paper ``` or -``` bash +```bash pbpaste | summarize_paper ``` # Example output: -``` markdown +```markdown ### Title and authors of the Paper: **Internet of Paint (IoP): Channel Modeling and Capacity Analysis for Terahertz Electromagnetic Nanonetworks Embedded in Paint** Authors: Lasantha Thakshila Wedage, Mehmet C. Vuran, Bernard Butler, Yevgeni Koucheryavy, Sasitharan Balasubramaniam diff --git a/patterns/translate/system.md b/patterns/translate/system.md index 8dc0da58..858e1cc2 100644 --- a/patterns/translate/system.md +++ b/patterns/translate/system.md @@ -8,7 +8,7 @@ Take a step back, and breathe deeply and think step by step about how to achieve - The original format of the input must remain intact. -- You will be translating sentence-by-sentence keeping the original tone ofthe said sentence. +- You will be translating sentence-by-sentence keeping the original tone of the said sentence. - You will not be manipulate the wording to change the meaning. diff --git a/pkgs/fabric/version.nix b/pkgs/fabric/version.nix index 3f32705d..daa597fc 100644 --- a/pkgs/fabric/version.nix +++ b/pkgs/fabric/version.nix @@ -1 +1 @@ -"1.4.104" +"1.4.127" diff --git a/plugins/ai/anthropic/anthropic.go b/plugins/ai/anthropic/anthropic.go index b13e6d0c..ff3f4d3a 100644 --- a/plugins/ai/anthropic/anthropic.go +++ b/plugins/ai/anthropic/anthropic.go @@ -2,17 +2,16 @@ package anthropic import ( "context" - "errors" "fmt" + "github.com/anthropics/anthropic-sdk-go" + "github.com/anthropics/anthropic-sdk-go/option" + "github.com/danielmiessler/fabric/common" "github.com/danielmiessler/fabric/plugins" goopenai "github.com/sashabaranov/go-openai" - - "github.com/danielmiessler/fabric/common" - "github.com/liushuangls/go-anthropic/v2" ) -const baseUrl = "https://api.anthropic.com/v1" +//const baseUrl = "https://api.anthropic.com/" func NewClient() (ret *Client) { vendorName := "Anthropic" @@ -24,17 +23,20 @@ func NewClient() (ret *Client) { ConfigureCustom: ret.configure, } - ret.ApiBaseURL = ret.AddSetupQuestion("API Base URL", false) - ret.ApiBaseURL.Value = baseUrl + //ret.ApiBaseURL = ret.AddSetupQuestion("API Base URL", false) + //ret.ApiBaseURL.Value = baseUrl ret.ApiKey = ret.PluginBase.AddSetupQuestion("API key", true) // we could provide a setup question for the following settings ret.maxTokens = 4096 ret.defaultRequiredUserMessage = "Hi" ret.models = []string{ - string(anthropic.ModelClaude3Dot5HaikuLatest), string(anthropic.ModelClaude3Opus20240229), - string(anthropic.ModelClaude3Opus20240229), string(anthropic.ModelClaude2Dot0), string(anthropic.ModelClaude2Dot1), - string(anthropic.ModelClaude3Dot5SonnetLatest), string(anthropic.ModelClaude3Dot5HaikuLatest), + anthropic.ModelClaude3_5HaikuLatest, anthropic.ModelClaude3_5Haiku20241022, + anthropic.ModelClaude3_5SonnetLatest, anthropic.ModelClaude3_5Sonnet20241022, + anthropic.ModelClaude_3_5_Sonnet_20240620, anthropic.ModelClaude3OpusLatest, + anthropic.ModelClaude_3_Opus_20240229, anthropic.ModelClaude_3_Sonnet_20240229, + anthropic.ModelClaude_3_Haiku_20240307, anthropic.ModelClaude_2_1, + anthropic.ModelClaude_2_0, anthropic.ModelClaude_Instant_1_2, } return @@ -42,8 +44,8 @@ func NewClient() (ret *Client) { type Client struct { *plugins.PluginBase - ApiBaseURL *plugins.SetupQuestion - ApiKey *plugins.SetupQuestion + //ApiBaseURL *plugins.SetupQuestion + ApiKey *plugins.SetupQuestion maxTokens int defaultRequiredUserMessage string @@ -53,11 +55,14 @@ type Client struct { } func (an *Client) configure() (err error) { - if an.ApiBaseURL.Value != "" { - an.client = anthropic.NewClient(an.ApiKey.Value, anthropic.WithBaseURL(an.ApiBaseURL.Value)) + /*if an.ApiBaseURL.Value != "" { + an.client = anthropic.NewClient( + option.WithAPIKey(an.ApiKey.Value), option.WithBaseURL(an.ApiBaseURL.Value), + ) } else { - an.client = anthropic.NewClient(an.ApiKey.Value) - } + */ + an.client = anthropic.NewClient(option.WithAPIKey(an.ApiKey.Value)) + //} return } @@ -68,75 +73,65 @@ func (an *Client) ListModels() (ret []string, err error) { func (an *Client) SendStream( msgs []*goopenai.ChatCompletionMessage, opts *common.ChatOptions, channel chan string, ) (err error) { - ctx := context.Background() - req := an.buildMessagesRequest(msgs, opts) - req.Stream = true - if _, err = an.client.CreateMessagesStream(ctx, anthropic.MessagesStreamRequest{ - MessagesRequest: req, - OnContentBlockDelta: func(data anthropic.MessagesEventContentBlockDeltaData) { - // fmt.Printf("Stream Content: %s\n", data.Delta.Text) - channel <- *data.Delta.Text - }, - }); err != nil { - var e *anthropic.APIError - if errors.As(err, &e) { - fmt.Printf("Messages stream error, type: %s, message: %s", e.Type, e.Message) - } else { - fmt.Printf("Messages stream error: %v\n", err) + messages := an.toMessages(msgs) + + ctx := context.Background() + stream := an.client.Messages.NewStreaming(ctx, anthropic.MessageNewParams{ + Model: anthropic.F(opts.Model), + MaxTokens: anthropic.F(int64(an.maxTokens)), + TopP: anthropic.F(opts.TopP), + Temperature: anthropic.F(opts.Temperature), + Messages: anthropic.F(messages), + }) + + for stream.Next() { + event := stream.Current() + + switch delta := event.Delta.(type) { + case anthropic.ContentBlockDeltaEventDelta: + if delta.Text != "" { + channel <- delta.Text + } } - } else { - close(channel) } + + if stream.Err() != nil { + fmt.Printf("Messages stream error: %v\n", stream.Err()) + } + close(channel) return } func (an *Client) Send(ctx context.Context, msgs []*goopenai.ChatCompletionMessage, opts *common.ChatOptions) (ret string, err error) { - req := an.buildMessagesRequest(msgs, opts) - req.Stream = false - - var resp anthropic.MessagesResponse - if resp, err = an.client.CreateMessages(ctx, req); err == nil { - ret = *resp.Content[0].Text - } else { - var e *anthropic.APIError - if errors.As(err, &e) { - fmt.Printf("Messages error, type: %s, message: %s", e.Type, e.Message) - } else { - fmt.Printf("Messages error: %v\n", err) - } - } - return -} - -func (an *Client) buildMessagesRequest(msgs []*goopenai.ChatCompletionMessage, opts *common.ChatOptions) (ret anthropic.MessagesRequest) { - temperature := float32(opts.Temperature) - topP := float32(opts.TopP) - messages := an.toMessages(msgs) - ret = anthropic.MessagesRequest{ - Model: anthropic.Model(opts.Model), - Temperature: &temperature, - TopP: &topP, - Messages: messages, - MaxTokens: an.maxTokens, + var message *anthropic.Message + if message, err = an.client.Messages.New(ctx, anthropic.MessageNewParams{ + Model: anthropic.F(opts.Model), + MaxTokens: anthropic.F(int64(an.maxTokens)), + TopP: anthropic.F(opts.TopP), + Temperature: anthropic.F(opts.Temperature), + Messages: anthropic.F(messages), + }); err != nil { + return } + ret = message.Content[0].Text return } -func (an *Client) toMessages(msgs []*goopenai.ChatCompletionMessage) (ret []anthropic.Message) { +func (an *Client) toMessages(msgs []*goopenai.ChatCompletionMessage) (ret []anthropic.MessageParam) { // we could call the method before calling the specific vendor normalizedMessages := common.NormalizeMessages(msgs, an.defaultRequiredUserMessage) // Iterate over the incoming session messages and process them for _, msg := range normalizedMessages { - var message anthropic.Message + var message anthropic.MessageParam switch msg.Role { case goopenai.ChatMessageRoleUser: - message = anthropic.NewUserTextMessage(msg.Content) + message = anthropic.NewUserMessage(anthropic.NewTextBlock(msg.Content)) default: - message = anthropic.NewAssistantTextMessage(msg.Content) + message = anthropic.NewAssistantMessage(anthropic.NewTextBlock(msg.Content)) } ret = append(ret, message) } diff --git a/plugins/db/fsdb/patterns.go b/plugins/db/fsdb/patterns.go index d64547a0..ac727b69 100644 --- a/plugins/db/fsdb/patterns.go +++ b/plugins/db/fsdb/patterns.go @@ -6,9 +6,12 @@ import ( "path/filepath" "strings" + "github.com/danielmiessler/fabric/common" "github.com/danielmiessler/fabric/plugins/template" ) +const inputSentinel = "__FABRIC_INPUT_SENTINEL_TOKEN__" + type PatternsEntity struct { *StorageEntity SystemPatternFile string @@ -22,50 +25,66 @@ type Pattern struct { Pattern string } -// main entry point for getting patterns from any source -func (o *PatternsEntity) GetApplyVariables(source string, variables map[string]string, input string) (*Pattern, error) { - var pattern *Pattern - var err error +// GetApplyVariables main entry point for getting patterns from any source +func (o *PatternsEntity) GetApplyVariables( + source string, variables map[string]string, input string) (pattern *Pattern, err error) { - // Determine if this is a file path - isFilePath := strings.HasPrefix(source, "\\") || - strings.HasPrefix(source, "/") || - strings.HasPrefix(source, "~") || - strings.HasPrefix(source, ".") - - if isFilePath { - pattern, err = o.getFromFile(source) - } else { - pattern, err = o.getFromDB(source) - } + // Determine if this is a file path + isFilePath := strings.HasPrefix(source, "\\") || + strings.HasPrefix(source, "/") || + strings.HasPrefix(source, "~") || + strings.HasPrefix(source, ".") - if err != nil { - return nil, err - } - - pattern, err = o.applyVariables(pattern, variables, input) + if isFilePath { + // Resolve the file path using GetAbsolutePath + absPath, err := common.GetAbsolutePath(source) if err != nil { - return nil, err // Return the error if applyVariables failed + return nil, fmt.Errorf("could not resolve file path: %v", err) } - return pattern, nil + + // Use the resolved absolute path to get the pattern + pattern, err = o.getFromFile(absPath) + } else { + // Otherwise, get the pattern from the database + pattern, err = o.getFromDB(source) + } + + if err != nil { + return + } + + // Apply variables to the pattern + err = o.applyVariables(pattern, variables, input) + return } +func (o *PatternsEntity) applyVariables( + pattern *Pattern, variables map[string]string, input string) (err error) { -func (o *PatternsEntity) applyVariables(pattern *Pattern, variables map[string]string, input string) (*Pattern, error) { - // If {{input}} isn't in pattern, append it on new line + // Ensure pattern has an {{input}} placeholder + // If not present, append it on a new line if !strings.Contains(pattern.Pattern, "{{input}}") { - if !strings.HasSuffix(pattern.Pattern, "\n") { - pattern.Pattern += "\n" - } - pattern.Pattern += "{{input}}" + if !strings.HasSuffix(pattern.Pattern, "\n") { + pattern.Pattern += "\n" + } + pattern.Pattern += "{{input}}" } - result, err := template.ApplyTemplate(pattern.Pattern, variables, input) - if err != nil { - return nil, err + // Temporarily replace {{input}} with a sentinel token to protect it + // from recursive variable resolution + withSentinel := strings.ReplaceAll(pattern.Pattern, "{{input}}", inputSentinel) + + // Process all other template variables in the pattern + // At this point, our sentinel ensures {{input}} won't be affected + var processed string + if processed, err = template.ApplyTemplate(withSentinel, variables, ""); err != nil { + return } - pattern.Pattern = result - return pattern, nil + + // Finally, replace our sentinel with the actual user input + // The input has already been processed for variables if InputHasVars was true + pattern.Pattern = strings.ReplaceAll(processed, inputSentinel, input) + return } // retrieves a pattern from the database by name @@ -103,29 +122,31 @@ func (o *PatternsEntity) PrintLatestPatterns(latestNumber int) (err error) { } // reads a pattern from a file path and returns it -func (o *PatternsEntity) getFromFile(pathStr string) (*Pattern, error) { +func (o *PatternsEntity) getFromFile(pathStr string) (pattern *Pattern, err error) { // Handle home directory expansion if strings.HasPrefix(pathStr, "~/") { - homedir, err := os.UserHomeDir() - if err != nil { - return nil, fmt.Errorf("could not get home directory: %v", err) - } - pathStr = filepath.Join(homedir, pathStr[2:]) + var homedir string + if homedir, err = os.UserHomeDir(); err != nil { + err = fmt.Errorf("could not get home directory: %v", err) + return + } + pathStr = filepath.Join(homedir, pathStr[2:]) } - content, err := os.ReadFile(pathStr) - if err != nil { - return nil, fmt.Errorf("could not read pattern file %s: %v", pathStr, err) + var content []byte + if content, err = os.ReadFile(pathStr); err != nil { + err = fmt.Errorf("could not read pattern file %s: %v", pathStr, err) + return } - - return &Pattern{ - Name: pathStr, - Pattern: string(content), - }, nil + pattern = &Pattern{ + Name: pathStr, + Pattern: string(content), + } + return } // Get required for Storage interface func (o *PatternsEntity) Get(name string) (*Pattern, error) { // Use GetPattern with no variables return o.GetApplyVariables(name, nil, "") -} \ No newline at end of file +} diff --git a/plugins/db/fsdb/patterns_test.go b/plugins/db/fsdb/patterns_test.go index adf8b936..4f61b200 100644 --- a/plugins/db/fsdb/patterns_test.go +++ b/plugins/db/fsdb/patterns_test.go @@ -43,7 +43,7 @@ func createTestPattern(t *testing.T, entity *PatternsEntity, name, content strin func TestApplyVariables(t *testing.T) { entity := &PatternsEntity{} - + tests := []struct { name string pattern *Pattern @@ -79,15 +79,15 @@ func TestApplyVariables(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result, err := entity.applyVariables(tt.pattern, tt.variables, tt.input) - + err := entity.applyVariables(tt.pattern, tt.variables, tt.input) + if tt.wantErr { assert.Error(t, err) return } - + assert.NoError(t, err) - assert.Equal(t, tt.want, result.Pattern) + assert.Equal(t, tt.want, tt.pattern.Pattern) }) } } @@ -117,15 +117,15 @@ func TestGetApplyVariables(t *testing.T) { want: "You are a reviewer.\ncheck this code", }, { - name: "pattern with missing variable", - source: "test-pattern", + name: "pattern with missing variable", + source: "test-pattern", variables: map[string]string{}, input: "test input", wantErr: true, }, { - name: "non-existent pattern", - source: "non-existent", + name: "non-existent pattern", + source: "non-existent", wantErr: true, }, } @@ -133,14 +133,14 @@ func TestGetApplyVariables(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := entity.GetApplyVariables(tt.source, tt.variables, tt.input) - + if tt.wantErr { assert.Error(t, err) return } - + require.NoError(t, err) assert.Equal(t, tt.want, result.Pattern) }) } -} \ No newline at end of file +} diff --git a/plugins/db/fsdb/sessions.go b/plugins/db/fsdb/sessions.go index 61156bae..2f278744 100644 --- a/plugins/db/fsdb/sessions.go +++ b/plugins/db/fsdb/sessions.go @@ -58,8 +58,7 @@ func (o *Session) Append(messages ...*goopenai.ChatCompletionMessage) { } func (o *Session) GetVendorMessages() (ret []*goopenai.ChatCompletionMessage) { - if o.vendorMessages == nil { - o.vendorMessages = []*goopenai.ChatCompletionMessage{} + if len(o.vendorMessages) == 0 { for _, message := range o.Messages { o.appendVendorMessage(message) } diff --git a/plugins/db/fsdb/storage.go b/plugins/db/fsdb/storage.go index 44e3e0be..a4d87304 100644 --- a/plugins/db/fsdb/storage.go +++ b/plugins/db/fsdb/storage.go @@ -7,7 +7,7 @@ import ( "path/filepath" "strings" - "github.com/samber/lo" + "github.com/danielmiessler/fabric/common" ) type StorageEntity struct { @@ -26,37 +26,44 @@ func (o *StorageEntity) Configure() (err error) { // GetNames finds all patterns in the patterns directory and enters the id, name, and pattern into a slice of Entry structs. it returns these entries or an error func (o *StorageEntity) GetNames() (ret []string, err error) { - var entries []os.DirEntry - if entries, err = os.ReadDir(o.Dir); err != nil { - err = fmt.Errorf("could not read items from directory: %v", err) - return + // Resolve the directory path to an absolute path + absDir, err := common.GetAbsolutePath(o.Dir) + if err != nil { + return nil, fmt.Errorf("could not resolve directory path: %v", err) } - if o.ItemIsDir { - ret = lo.FilterMap(entries, func(item os.DirEntry, index int) (ret string, ok bool) { - if ok = item.IsDir(); ok { - ret = item.Name() + // Read the directory entries + var entries []os.DirEntry + if entries, err = os.ReadDir(absDir); err != nil { + return nil, fmt.Errorf("could not read items from directory: %v", err) + } + + for _, entry := range entries { + entryPath := filepath.Join(absDir, entry.Name()) + + // Get metadata for the entry, including symlink info + fileInfo, err := os.Lstat(entryPath) + if err != nil { + return nil, fmt.Errorf("could not stat entry %s: %v", entryPath, err) + } + + // Determine if the entry should be included + if o.ItemIsDir { + // Include directories or symlinks to directories + if fileInfo.IsDir() || (fileInfo.Mode()&os.ModeSymlink != 0 && common.IsSymlinkToDir(entryPath)) { + ret = append(ret, entry.Name()) } - return - }) - } else { - if o.FileExtension == "" { - ret = lo.FilterMap(entries, func(item os.DirEntry, index int) (ret string, ok bool) { - if ok = !item.IsDir(); ok { - ret = item.Name() - } - return - }) } else { - ret = lo.FilterMap(entries, func(item os.DirEntry, index int) (ret string, ok bool) { - if ok = !item.IsDir() && filepath.Ext(item.Name()) == o.FileExtension; ok { - ret = strings.TrimSuffix(item.Name(), o.FileExtension) + // Include files, optionally filtering by extension + if !fileInfo.IsDir() { + if o.FileExtension == "" || filepath.Ext(entry.Name()) == o.FileExtension { + ret = append(ret, strings.TrimSuffix(entry.Name(), o.FileExtension)) } - return - }) + } } } - return + + return ret, nil } func (o *StorageEntity) Delete(name string) (err error) { diff --git a/plugins/template/datetime.go b/plugins/template/datetime.go index 31340e59..cab44c1e 100644 --- a/plugins/template/datetime.go +++ b/plugins/template/datetime.go @@ -17,128 +17,128 @@ type DateTimePlugin struct{} // Period: startofweek, endofweek, startofmonth, endofmonth // Relative: rel:-1h, rel:-2d, rel:1w, rel:3m, rel:1y func (p *DateTimePlugin) Apply(operation string, value string) (string, error) { - debugf("DateTime: operation=%q value=%q", operation, value) - - now := time.Now() - debugf("DateTime: reference time=%v", now) - - switch operation { - // Time operations - case "now": - result := now.Format(time.RFC3339) - debugf("DateTime: now=%q", result) - return result, nil - - case "time": - result := now.Format("15:04:05") - debugf("DateTime: time=%q", result) - return result, nil - - case "unix": - result := fmt.Sprintf("%d", now.Unix()) - debugf("DateTime: unix=%q", result) - return result, nil - - case "startofhour": - result := now.Truncate(time.Hour).Format(time.RFC3339) - debugf("DateTime: startofhour=%q", result) - return result, nil - - case "endofhour": - result := now.Truncate(time.Hour).Add(time.Hour - time.Second).Format(time.RFC3339) - debugf("DateTime: endofhour=%q", result) - return result, nil - - // Date operations - case "today": - result := now.Format("2006-01-02") - debugf("DateTime: today=%q", result) - return result, nil - - case "full": - result := now.Format("Monday, January 2, 2006") - debugf("DateTime: full=%q", result) - return result, nil - - case "month": - result := now.Format("January") - debugf("DateTime: month=%q", result) - return result, nil - - case "year": - result := now.Format("2006") - debugf("DateTime: year=%q", result) - return result, nil - - case "startofweek": - result := now.AddDate(0, 0, -int(now.Weekday())).Format("2006-01-02") - debugf("DateTime: startofweek=%q", result) - return result, nil - - case "endofweek": - result := now.AddDate(0, 0, 7-int(now.Weekday())).Format("2006-01-02") - debugf("DateTime: endofweek=%q", result) - return result, nil - - case "startofmonth": - result := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()).Format("2006-01-02") - debugf("DateTime: startofmonth=%q", result) - return result, nil - - case "endofmonth": - result := time.Date(now.Year(), now.Month()+1, 0, 0, 0, 0, 0, now.Location()).Format("2006-01-02") - debugf("DateTime: endofmonth=%q", result) - return result, nil - - case "rel": - return p.handleRelative(now, value) - - default: - return "", fmt.Errorf("datetime: unknown operation %q (see plugin documentation for supported operations)", operation) - } + debugf("DateTime: operation=%q value=%q", operation, value) + + now := time.Now() + debugf("DateTime: reference time=%v", now) + + switch operation { + // Time operations + case "now": + result := now.Format(time.RFC3339) + debugf("DateTime: now=%q", result) + return result, nil + + case "time": + result := now.Format("15:04:05") + debugf("DateTime: time=%q", result) + return result, nil + + case "unix": + result := fmt.Sprintf("%d", now.Unix()) + debugf("DateTime: unix=%q", result) + return result, nil + + case "startofhour": + result := now.Truncate(time.Hour).Format(time.RFC3339) + debugf("DateTime: startofhour=%q", result) + return result, nil + + case "endofhour": + result := now.Truncate(time.Hour).Add(time.Hour - time.Second).Format(time.RFC3339) + debugf("DateTime: endofhour=%q", result) + return result, nil + + // Date operations + case "today": + result := now.Format("2006-01-02") + debugf("DateTime: today=%q", result) + return result, nil + + case "full": + result := now.Format("Monday, January 2, 2006") + debugf("DateTime: full=%q", result) + return result, nil + + case "month": + result := now.Format("January") + debugf("DateTime: month=%q", result) + return result, nil + + case "year": + result := now.Format("2006") + debugf("DateTime: year=%q", result) + return result, nil + + case "startofweek": + result := now.AddDate(0, 0, -int(now.Weekday())).Format("2006-01-02") + debugf("DateTime: startofweek=%q", result) + return result, nil + + case "endofweek": + result := now.AddDate(0, 0, 7-int(now.Weekday())).Format("2006-01-02") + debugf("DateTime: endofweek=%q", result) + return result, nil + + case "startofmonth": + result := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()).Format("2006-01-02") + debugf("DateTime: startofmonth=%q", result) + return result, nil + + case "endofmonth": + result := time.Date(now.Year(), now.Month()+1, 0, 0, 0, 0, 0, now.Location()).Format("2006-01-02") + debugf("DateTime: endofmonth=%q", result) + return result, nil + + case "rel": + return p.handleRelative(now, value) + + default: + return "", fmt.Errorf("datetime: unknown operation %q (see plugin documentation for supported operations)", operation) + } } func (p *DateTimePlugin) handleRelative(now time.Time, value string) (string, error) { - debugf("DateTime: handling relative time value=%q", value) - - if value == "" { - return "", fmt.Errorf("datetime: relative time requires a value (e.g., -1h, -1d, -1w)") - } - - // Try standard duration first (hours, minutes) - if duration, err := time.ParseDuration(value); err == nil { - result := now.Add(duration).Format(time.RFC3339) - debugf("DateTime: relative duration=%q result=%q", duration, result) - return result, nil - } - - // Handle date units - if len(value) < 2 { - return "", fmt.Errorf("datetime: invalid relative format (use: -1h, 2d, -3w, 1m, -1y)") - } - - unit := value[len(value)-1:] - numStr := value[:len(value)-1] - - num, err := strconv.Atoi(numStr) - if err != nil { - return "", fmt.Errorf("datetime: invalid number in relative time: %q", value) - } - - var result string - switch unit { - case "d": - result = now.AddDate(0, 0, num).Format("2006-01-02") - case "w": - result = now.AddDate(0, 0, num*7).Format("2006-01-02") - case "m": - result = now.AddDate(0, num, 0).Format("2006-01-02") - case "y": - result = now.AddDate(num, 0, 0).Format("2006-01-02") - default: - return "", fmt.Errorf("datetime: invalid unit %q (use: h,m for time or d,w,m,y for date)", unit) - } - - debugf("DateTime: relative unit=%q num=%d result=%q", unit, num, result) - return result, nil -} \ No newline at end of file + debugf("DateTime: handling relative time value=%q", value) + + if value == "" { + return "", fmt.Errorf("datetime: relative time requires a value (e.g., -1h, -1d, -1w)") + } + + // Try standard duration first (hours, minutes) + if duration, err := time.ParseDuration(value); err == nil { + result := now.Add(duration).Format(time.RFC3339) + debugf("DateTime: relative duration=%q result=%q", duration, result) + return result, nil + } + + // Handle date units + if len(value) < 2 { + return "", fmt.Errorf("datetime: invalid relative format (use: -1h, 2d, -3w, 1m, -1y)") + } + + unit := value[len(value)-1:] + numStr := value[:len(value)-1] + + num, err := strconv.Atoi(numStr) + if err != nil { + return "", fmt.Errorf("datetime: invalid number in relative time: %q", value) + } + + var result string + switch unit { + case "d": + result = now.AddDate(0, 0, num).Format("2006-01-02") + case "w": + result = now.AddDate(0, 0, num*7).Format("2006-01-02") + case "m": + result = now.AddDate(0, num, 0).Format("2006-01-02") + case "y": + result = now.AddDate(num, 0, 0).Format("2006-01-02") + default: + return "", fmt.Errorf("datetime: invalid unit %q (use: h,m for time or d,w,m,y for date)", unit) + } + + debugf("DateTime: relative unit=%q num=%d result=%q", unit, num, result) + return result, nil +} diff --git a/plugins/template/datetime_test.go b/plugins/template/datetime_test.go index 0e737ffd..0e6cd478 100644 --- a/plugins/template/datetime_test.go +++ b/plugins/template/datetime_test.go @@ -9,130 +9,130 @@ import ( ) func TestDateTimePlugin(t *testing.T) { - plugin := &DateTimePlugin{} - now := time.Now() - - tests := []struct { - name string - operation string - value string - validate func(string) error - wantErr bool - }{ - { - name: "now returns RFC3339", - operation: "now", - validate: func(got string) error { - if _, err := time.Parse(time.RFC3339, got); err != nil { - return err - } - return nil - }, - }, - { - name: "time returns HH:MM:SS", - operation: "time", - validate: func(got string) error { - if _, err := time.Parse("15:04:05", got); err != nil { - return err - } - return nil - }, - }, - { - name: "unix returns timestamp", - operation: "unix", - validate: func(got string) error { - if _, err := strconv.ParseInt(got, 10, 64); err != nil { - return err - } - return nil - }, - }, - { - name: "today returns YYYY-MM-DD", - operation: "today", - validate: func(got string) error { - if _, err := time.Parse("2006-01-02", got); err != nil { - return err - } - return nil - }, - }, - { - name: "full returns long date", - operation: "full", - validate: func(got string) error { - if !strings.Contains(got, now.Month().String()) { - return fmt.Errorf("full date missing month name") - } - return nil - }, - }, - { - name: "relative positive hours", - operation: "rel", - value: "2h", - validate: func(got string) error { - t, err := time.Parse(time.RFC3339, got) - if err != nil { - return err - } - expected := now.Add(2 * time.Hour) - if t.Hour() != expected.Hour() { - return fmt.Errorf("expected hour %d, got %d", expected.Hour(), t.Hour()) - } - return nil - }, - }, - { - name: "relative negative days", - operation: "rel", - value: "-2d", - validate: func(got string) error { - t, err := time.Parse("2006-01-02", got) - if err != nil { - return err - } - expected := now.AddDate(0, 0, -2) - if t.Day() != expected.Day() { - return fmt.Errorf("expected day %d, got %d", expected.Day(), t.Day()) - } - return nil - }, - }, - // Error cases - { - name: "invalid operation", - operation: "invalid", - wantErr: true, - }, - { - name: "empty relative value", - operation: "rel", - value: "", - wantErr: true, - }, - { - name: "invalid relative format", - operation: "rel", - value: "2x", - wantErr: true, - }, - } + plugin := &DateTimePlugin{} + now := time.Now() - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := plugin.Apply(tt.operation, tt.value) - if (err != nil) != tt.wantErr { - t.Errorf("DateTimePlugin.Apply() error = %v, wantErr %v", err, tt.wantErr) - return - } - if err == nil && tt.validate != nil { - if err := tt.validate(got); err != nil { - t.Errorf("DateTimePlugin.Apply() validation failed: %v", err) - } - } - }) - } -} \ No newline at end of file + tests := []struct { + name string + operation string + value string + validate func(string) error + wantErr bool + }{ + { + name: "now returns RFC3339", + operation: "now", + validate: func(got string) error { + if _, err := time.Parse(time.RFC3339, got); err != nil { + return err + } + return nil + }, + }, + { + name: "time returns HH:MM:SS", + operation: "time", + validate: func(got string) error { + if _, err := time.Parse("15:04:05", got); err != nil { + return err + } + return nil + }, + }, + { + name: "unix returns timestamp", + operation: "unix", + validate: func(got string) error { + if _, err := strconv.ParseInt(got, 10, 64); err != nil { + return err + } + return nil + }, + }, + { + name: "today returns YYYY-MM-DD", + operation: "today", + validate: func(got string) error { + if _, err := time.Parse("2006-01-02", got); err != nil { + return err + } + return nil + }, + }, + { + name: "full returns long date", + operation: "full", + validate: func(got string) error { + if !strings.Contains(got, now.Month().String()) { + return fmt.Errorf("full date missing month name") + } + return nil + }, + }, + { + name: "relative positive hours", + operation: "rel", + value: "2h", + validate: func(got string) error { + t, err := time.Parse(time.RFC3339, got) + if err != nil { + return err + } + expected := now.Add(2 * time.Hour) + if t.Hour() != expected.Hour() { + return fmt.Errorf("expected hour %d, got %d", expected.Hour(), t.Hour()) + } + return nil + }, + }, + { + name: "relative negative days", + operation: "rel", + value: "-2d", + validate: func(got string) error { + t, err := time.Parse("2006-01-02", got) + if err != nil { + return err + } + expected := now.AddDate(0, 0, -2) + if t.Day() != expected.Day() { + return fmt.Errorf("expected day %d, got %d", expected.Day(), t.Day()) + } + return nil + }, + }, + // Error cases + { + name: "invalid operation", + operation: "invalid", + wantErr: true, + }, + { + name: "empty relative value", + operation: "rel", + value: "", + wantErr: true, + }, + { + name: "invalid relative format", + operation: "rel", + value: "2x", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := plugin.Apply(tt.operation, tt.value) + if (err != nil) != tt.wantErr { + t.Errorf("DateTimePlugin.Apply() error = %v, wantErr %v", err, tt.wantErr) + return + } + if err == nil && tt.validate != nil { + if err := tt.validate(got); err != nil { + t.Errorf("DateTimePlugin.Apply() validation failed: %v", err) + } + } + }) + } +} diff --git a/plugins/template/fetch.go b/plugins/template/fetch.go index a8663464..36678aee 100644 --- a/plugins/template/fetch.go +++ b/plugins/template/fetch.go @@ -14,11 +14,11 @@ import ( ) const ( - // MaxContentSize limits response size to 1MB to prevent memory issues - MaxContentSize = 1024 * 1024 - - // UserAgent identifies the client in HTTP requests - UserAgent = "Fabric-Fetch/1.0" + // MaxContentSize limits response size to 1MB to prevent memory issues + MaxContentSize = 1024 * 1024 + + // UserAgent identifies the client in HTTP requests + UserAgent = "Fabric-Fetch/1.0" ) // FetchPlugin provides HTTP fetching capabilities with safety constraints: @@ -31,104 +31,104 @@ type FetchPlugin struct{} // Apply executes fetch operations: // - get:URL: Fetches content from URL, returns text content func (p *FetchPlugin) Apply(operation string, value string) (string, error) { - debugf("Fetch: operation=%q value=%q", operation, value) - - switch operation { - case "get": - return p.fetch(value) - default: - return "", fmt.Errorf("fetch: unknown operation %q (supported: get)", operation) - } + debugf("Fetch: operation=%q value=%q", operation, value) + + switch operation { + case "get": + return p.fetch(value) + default: + return "", fmt.Errorf("fetch: unknown operation %q (supported: get)", operation) + } } // isTextContent checks if the content type is text-based func (p *FetchPlugin) isTextContent(contentType string) bool { - debugf("Fetch: checking content type %q", contentType) - - mediaType, _, err := mime.ParseMediaType(contentType) - if err != nil { - debugf("Fetch: error parsing media type: %v", err) - return false - } - - isText := strings.HasPrefix(mediaType, "text/") || - mediaType == "application/json" || - mediaType == "application/xml" || - mediaType == "application/yaml" || - mediaType == "application/x-yaml" || - strings.HasSuffix(mediaType, "+json") || - strings.HasSuffix(mediaType, "+xml") || - strings.HasSuffix(mediaType, "+yaml") - - debugf("Fetch: content type %q is text: %v", mediaType, isText) - return isText + debugf("Fetch: checking content type %q", contentType) + + mediaType, _, err := mime.ParseMediaType(contentType) + if err != nil { + debugf("Fetch: error parsing media type: %v", err) + return false + } + + isText := strings.HasPrefix(mediaType, "text/") || + mediaType == "application/json" || + mediaType == "application/xml" || + mediaType == "application/yaml" || + mediaType == "application/x-yaml" || + strings.HasSuffix(mediaType, "+json") || + strings.HasSuffix(mediaType, "+xml") || + strings.HasSuffix(mediaType, "+yaml") + + debugf("Fetch: content type %q is text: %v", mediaType, isText) + return isText } // validateTextContent ensures content is valid UTF-8 without null bytes func (p *FetchPlugin) validateTextContent(content []byte) error { - debugf("Fetch: validating content length=%d bytes", len(content)) - - if !utf8.Valid(content) { - return fmt.Errorf("fetch: content is not valid UTF-8 text") - } - - if bytes.Contains(content, []byte{0}) { - return fmt.Errorf("fetch: content contains null bytes") - } - - debugf("Fetch: content validation successful") - return nil + debugf("Fetch: validating content length=%d bytes", len(content)) + + if !utf8.Valid(content) { + return fmt.Errorf("fetch: content is not valid UTF-8 text") + } + + if bytes.Contains(content, []byte{0}) { + return fmt.Errorf("fetch: content contains null bytes") + } + + debugf("Fetch: content validation successful") + return nil } // fetch retrieves content from a URL with safety checks func (p *FetchPlugin) fetch(urlStr string) (string, error) { - debugf("Fetch: requesting URL %q", urlStr) - - client := &http.Client{} - req, err := http.NewRequest("GET", urlStr, nil) - if err != nil { - return "", fmt.Errorf("fetch: error creating request: %v", err) - } - req.Header.Set("User-Agent", UserAgent) - - resp, err := client.Do(req) - if err != nil { - return "", fmt.Errorf("fetch: error fetching URL: %v", err) - } - defer resp.Body.Close() - - debugf("Fetch: got response status=%q", resp.Status) - if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("fetch: HTTP error: %d - %s", resp.StatusCode, resp.Status) - } + debugf("Fetch: requesting URL %q", urlStr) - if contentLength := resp.ContentLength; contentLength > MaxContentSize { - return "", fmt.Errorf("fetch: content too large: %d bytes (max %d bytes)", - contentLength, MaxContentSize) - } - - contentType := resp.Header.Get("Content-Type") - debugf("Fetch: content-type=%q", contentType) - if !p.isTextContent(contentType) { - return "", fmt.Errorf("fetch: unsupported content type %q - only text content allowed", - contentType) - } + client := &http.Client{} + req, err := http.NewRequest("GET", urlStr, nil) + if err != nil { + return "", fmt.Errorf("fetch: error creating request: %v", err) + } + req.Header.Set("User-Agent", UserAgent) - debugf("Fetch: reading response body") - limitReader := io.LimitReader(resp.Body, MaxContentSize+1) - content, err := io.ReadAll(limitReader) - if err != nil { - return "", fmt.Errorf("fetch: error reading response: %v", err) - } - - if len(content) > MaxContentSize { - return "", fmt.Errorf("fetch: content too large: exceeds %d bytes", MaxContentSize) - } + resp, err := client.Do(req) + if err != nil { + return "", fmt.Errorf("fetch: error fetching URL: %v", err) + } + defer resp.Body.Close() - if err := p.validateTextContent(content); err != nil { - return "", err - } + debugf("Fetch: got response status=%q", resp.Status) + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("fetch: HTTP error: %d - %s", resp.StatusCode, resp.Status) + } - debugf("Fetch: operation completed successfully, read %d bytes", len(content)) - return string(content), nil -} \ No newline at end of file + if contentLength := resp.ContentLength; contentLength > MaxContentSize { + return "", fmt.Errorf("fetch: content too large: %d bytes (max %d bytes)", + contentLength, MaxContentSize) + } + + contentType := resp.Header.Get("Content-Type") + debugf("Fetch: content-type=%q", contentType) + if !p.isTextContent(contentType) { + return "", fmt.Errorf("fetch: unsupported content type %q - only text content allowed", + contentType) + } + + debugf("Fetch: reading response body") + limitReader := io.LimitReader(resp.Body, MaxContentSize+1) + content, err := io.ReadAll(limitReader) + if err != nil { + return "", fmt.Errorf("fetch: error reading response: %v", err) + } + + if len(content) > MaxContentSize { + return "", fmt.Errorf("fetch: content too large: exceeds %d bytes", MaxContentSize) + } + + if err := p.validateTextContent(content); err != nil { + return "", err + } + + debugf("Fetch: operation completed successfully, read %d bytes", len(content)) + return string(content), nil +} diff --git a/plugins/template/fetch_test.go b/plugins/template/fetch_test.go index 5f3fd6f3..b7651051 100644 --- a/plugins/template/fetch_test.go +++ b/plugins/template/fetch_test.go @@ -5,67 +5,68 @@ import ( "strings" "testing" ) + func TestFetchPlugin(t *testing.T) { plugin := &FetchPlugin{} - + tests := []struct { - name string - operation string - value string - server func() *httptest.Server - wantErr bool - errContains string + name string + operation string + value string + server func() *httptest.Server + wantErr bool + errContains string }{ - // ... keep existing valid test cases ... - - { - name: "invalid URL", - operation: "get", - value: "not-a-url", - wantErr: true, - errContains: "unsupported protocol", // Updated to match actual error - }, - { - name: "malformed URL", - operation: "get", - value: "http://[::1]:namedport", - wantErr: true, - errContains: "error creating request", - }, - // ... keep other test cases ... + // ... keep existing valid test cases ... + + { + name: "invalid URL", + operation: "get", + value: "not-a-url", + wantErr: true, + errContains: "unsupported protocol", // Updated to match actual error + }, + { + name: "malformed URL", + operation: "get", + value: "http://[::1]:namedport", + wantErr: true, + errContains: "error creating request", + }, + // ... keep other test cases ... } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var url string - if tt.server != nil { - server := tt.server() - defer server.Close() - url = server.URL - } else { - url = tt.value - } - - got, err := plugin.Apply(tt.operation, url) - - // Check error cases - if (err != nil) != tt.wantErr { - t.Errorf("FetchPlugin.Apply() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if err != nil && tt.errContains != "" { - if !strings.Contains(err.Error(), tt.errContains) { - t.Errorf("error %q should contain %q", err.Error(), tt.errContains) - t.Logf("Full error: %v", err) // Added for better debugging - } - return - } - - // For successful cases, verify we got some content - if err == nil && got == "" { - t.Error("FetchPlugin.Apply() returned empty content on success") - } - }) + t.Run(tt.name, func(t *testing.T) { + var url string + if tt.server != nil { + server := tt.server() + defer server.Close() + url = server.URL + } else { + url = tt.value + } + + got, err := plugin.Apply(tt.operation, url) + + // Check error cases + if (err != nil) != tt.wantErr { + t.Errorf("FetchPlugin.Apply() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if err != nil && tt.errContains != "" { + if !strings.Contains(err.Error(), tt.errContains) { + t.Errorf("error %q should contain %q", err.Error(), tt.errContains) + t.Logf("Full error: %v", err) // Added for better debugging + } + return + } + + // For successful cases, verify we got some content + if err == nil && got == "" { + t.Error("FetchPlugin.Apply() returned empty content on success") + } + }) } -} \ No newline at end of file +} diff --git a/plugins/template/file.go b/plugins/template/file.go index fb2f85d7..a4fc8d00 100644 --- a/plugins/template/file.go +++ b/plugins/template/file.go @@ -24,26 +24,26 @@ type FilePlugin struct{} // safePath validates and normalizes file paths func (p *FilePlugin) safePath(path string) (string, error) { - debugf("File: validating path %q", path) - - // Basic security check - no path traversal - if strings.Contains(path, "..") { - return "", fmt.Errorf("file: path cannot contain '..'") - } - - // Expand home directory if needed - if strings.HasPrefix(path, "~/") { - home, err := os.UserHomeDir() - if err != nil { - return "", fmt.Errorf("file: could not expand home directory: %v", err) - } - path = filepath.Join(home, path[2:]) - } - - // Clean the path - cleaned := filepath.Clean(path) - debugf("File: cleaned path %q", cleaned) - return cleaned, nil + debugf("File: validating path %q", path) + + // Basic security check - no path traversal + if strings.Contains(path, "..") { + return "", fmt.Errorf("file: path cannot contain '..'") + } + + // Expand home directory if needed + if strings.HasPrefix(path, "~/") { + home, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("file: could not expand home directory: %v", err) + } + path = filepath.Join(home, path[2:]) + } + + // Clean the path + cleaned := filepath.Clean(path) + debugf("File: cleaned path %q", cleaned) + return cleaned, nil } // Apply executes file operations: @@ -53,145 +53,145 @@ func (p *FilePlugin) safePath(path string) (string, error) { // - size:PATH - Get file size in bytes // - modified:PATH - Get last modified time func (p *FilePlugin) Apply(operation string, value string) (string, error) { - debugf("File: operation=%q value=%q", operation, value) - - switch operation { - case "tail": - parts := strings.Split(value, "|") - if len(parts) != 2 { - return "", fmt.Errorf("file: tail requires format path|lines") - } - - path, err := p.safePath(parts[0]) - if err != nil { - return "", err - } - - n, err := strconv.Atoi(parts[1]) - if err != nil { - return "", fmt.Errorf("file: invalid line count %q", parts[1]) - } - - if n < 1 { - return "", fmt.Errorf("file: line count must be positive") - } - - lines, err := p.lastNLines(path, n) - if err != nil { - return "", err - } - - result := strings.Join(lines, "\n") - debugf("File: tail returning %d lines", len(lines)) - return result, nil + debugf("File: operation=%q value=%q", operation, value) - case "read": - path, err := p.safePath(value) - if err != nil { - return "", err - } - - info, err := os.Stat(path) - if err != nil { - return "", fmt.Errorf("file: could not stat file: %v", err) - } - - if info.Size() > MaxFileSize { - return "", fmt.Errorf("file: size %d exceeds limit of %d bytes", - info.Size(), MaxFileSize) - } - - content, err := os.ReadFile(path) - if err != nil { - return "", fmt.Errorf("file: could not read: %v", err) - } - - debugf("File: read %d bytes", len(content)) - return string(content), nil + switch operation { + case "tail": + parts := strings.Split(value, "|") + if len(parts) != 2 { + return "", fmt.Errorf("file: tail requires format path|lines") + } - case "exists": - path, err := p.safePath(value) - if err != nil { - return "", err - } - - _, err = os.Stat(path) - exists := err == nil - debugf("File: exists=%v for path %q", exists, path) - return fmt.Sprintf("%t", exists), nil + path, err := p.safePath(parts[0]) + if err != nil { + return "", err + } - case "size": - path, err := p.safePath(value) - if err != nil { - return "", err - } - - info, err := os.Stat(path) - if err != nil { - return "", fmt.Errorf("file: could not stat file: %v", err) - } - - size := info.Size() - debugf("File: size=%d for path %q", size, path) - return fmt.Sprintf("%d", size), nil + n, err := strconv.Atoi(parts[1]) + if err != nil { + return "", fmt.Errorf("file: invalid line count %q", parts[1]) + } - case "modified": - path, err := p.safePath(value) - if err != nil { - return "", err - } - - info, err := os.Stat(path) - if err != nil { - return "", fmt.Errorf("file: could not stat file: %v", err) - } - - mtime := info.ModTime().Format(time.RFC3339) - debugf("File: modified=%q for path %q", mtime, path) - return mtime, nil + if n < 1 { + return "", fmt.Errorf("file: line count must be positive") + } - default: - return "", fmt.Errorf("file: unknown operation %q (supported: read, tail, exists, size, modified)", - operation) - } + lines, err := p.lastNLines(path, n) + if err != nil { + return "", err + } + + result := strings.Join(lines, "\n") + debugf("File: tail returning %d lines", len(lines)) + return result, nil + + case "read": + path, err := p.safePath(value) + if err != nil { + return "", err + } + + info, err := os.Stat(path) + if err != nil { + return "", fmt.Errorf("file: could not stat file: %v", err) + } + + if info.Size() > MaxFileSize { + return "", fmt.Errorf("file: size %d exceeds limit of %d bytes", + info.Size(), MaxFileSize) + } + + content, err := os.ReadFile(path) + if err != nil { + return "", fmt.Errorf("file: could not read: %v", err) + } + + debugf("File: read %d bytes", len(content)) + return string(content), nil + + case "exists": + path, err := p.safePath(value) + if err != nil { + return "", err + } + + _, err = os.Stat(path) + exists := err == nil + debugf("File: exists=%v for path %q", exists, path) + return fmt.Sprintf("%t", exists), nil + + case "size": + path, err := p.safePath(value) + if err != nil { + return "", err + } + + info, err := os.Stat(path) + if err != nil { + return "", fmt.Errorf("file: could not stat file: %v", err) + } + + size := info.Size() + debugf("File: size=%d for path %q", size, path) + return fmt.Sprintf("%d", size), nil + + case "modified": + path, err := p.safePath(value) + if err != nil { + return "", err + } + + info, err := os.Stat(path) + if err != nil { + return "", fmt.Errorf("file: could not stat file: %v", err) + } + + mtime := info.ModTime().Format(time.RFC3339) + debugf("File: modified=%q for path %q", mtime, path) + return mtime, nil + + default: + return "", fmt.Errorf("file: unknown operation %q (supported: read, tail, exists, size, modified)", + operation) + } } // lastNLines returns the last n lines from a file func (p *FilePlugin) lastNLines(path string, n int) ([]string, error) { - debugf("File: reading last %d lines from %q", n, path) - - file, err := os.Open(path) - if err != nil { - return nil, fmt.Errorf("file: could not open: %v", err) - } - defer file.Close() + debugf("File: reading last %d lines from %q", n, path) - info, err := file.Stat() - if err != nil { - return nil, fmt.Errorf("file: could not stat: %v", err) - } - - if info.Size() > MaxFileSize { - return nil, fmt.Errorf("file: size %d exceeds limit of %d bytes", - info.Size(), MaxFileSize) - } + file, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("file: could not open: %v", err) + } + defer file.Close() - lines := make([]string, 0, n) - scanner := bufio.NewScanner(file) - - lineCount := 0 - for scanner.Scan() { - lineCount++ - if len(lines) == n { - lines = lines[1:] - } - lines = append(lines, scanner.Text()) - } - - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("file: error reading: %v", err) - } + info, err := file.Stat() + if err != nil { + return nil, fmt.Errorf("file: could not stat: %v", err) + } - debugf("File: read %d lines total, returning last %d", lineCount, len(lines)) - return lines, nil + if info.Size() > MaxFileSize { + return nil, fmt.Errorf("file: size %d exceeds limit of %d bytes", + info.Size(), MaxFileSize) + } + + lines := make([]string, 0, n) + scanner := bufio.NewScanner(file) + + lineCount := 0 + for scanner.Scan() { + lineCount++ + if len(lines) == n { + lines = lines[1:] + } + lines = append(lines, scanner.Text()) + } + + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("file: error reading: %v", err) + } + + debugf("File: read %d lines total, returning last %d", lineCount, len(lines)) + return lines, nil } diff --git a/plugins/template/file_test.go b/plugins/template/file_test.go index f4c24736..8fb6cb9b 100644 --- a/plugins/template/file_test.go +++ b/plugins/template/file_test.go @@ -9,144 +9,144 @@ import ( ) func TestFilePlugin(t *testing.T) { - plugin := &FilePlugin{} - - // Create temp test files - tmpDir := t.TempDir() - - testFile := filepath.Join(tmpDir, "test.txt") - content := "line1\nline2\nline3\nline4\nline5\n" - err := os.WriteFile(testFile, []byte(content), 0644) - if err != nil { - t.Fatal(err) - } - - bigFile := filepath.Join(tmpDir, "big.txt") - err = os.WriteFile(bigFile, []byte(strings.Repeat("x", MaxFileSize+1)), 0644) - if err != nil { - t.Fatal(err) - } + plugin := &FilePlugin{} - tests := []struct { - name string - operation string - value string - want string - wantErr bool - errContains string - validate func(string) bool - }{ - { - name: "read file", - operation: "read", - value: testFile, - want: content, - }, - { - name: "tail file", - operation: "tail", - value: testFile + "|3", - want: "line3\nline4\nline5", - }, - { - name: "exists true", - operation: "exists", - value: testFile, - want: "true", - }, - { - name: "exists false", - operation: "exists", - value: filepath.Join(tmpDir, "nonexistent.txt"), - want: "false", - }, - { - name: "size", - operation: "size", - value: testFile, - want: "30", - }, - { - name: "modified", - operation: "modified", - value: testFile, - validate: func(got string) bool { - _, err := time.Parse(time.RFC3339, got) - return err == nil - }, - }, - // Error cases - { - name: "read non-existent", - operation: "read", - value: filepath.Join(tmpDir, "nonexistent.txt"), - wantErr: true, - errContains: "could not stat file", - }, - { - name: "invalid operation", - operation: "invalid", - value: testFile, - wantErr: true, - errContains: "unknown operation", - }, - { - name: "path traversal attempt", - operation: "read", - value: "../../../etc/passwd", - wantErr: true, - errContains: "cannot contain '..'", - }, - { - name: "file too large", - operation: "read", - value: bigFile, - wantErr: true, - errContains: "exceeds limit", - }, - { - name: "invalid tail format", - operation: "tail", - value: testFile, - wantErr: true, - errContains: "requires format path|lines", - }, - { - name: "invalid tail count", - operation: "tail", - value: testFile + "|invalid", - wantErr: true, - errContains: "invalid line count", - }, - } + // Create temp test files + tmpDir := t.TempDir() - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := plugin.Apply(tt.operation, tt.value) - - // Check error cases - if (err != nil) != tt.wantErr { - t.Errorf("FilePlugin.Apply() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if err != nil && tt.errContains != "" { - if !strings.Contains(err.Error(), tt.errContains) { - t.Errorf("error %q should contain %q", err.Error(), tt.errContains) - } - return - } - - // Check success cases - if err == nil { - if tt.validate != nil { - if !tt.validate(got) { - t.Errorf("FilePlugin.Apply() returned invalid result: %q", got) - } - } else if tt.want != "" && got != tt.want { - t.Errorf("FilePlugin.Apply() = %v, want %v", got, tt.want) - } - } - }) - } -} \ No newline at end of file + testFile := filepath.Join(tmpDir, "test.txt") + content := "line1\nline2\nline3\nline4\nline5\n" + err := os.WriteFile(testFile, []byte(content), 0644) + if err != nil { + t.Fatal(err) + } + + bigFile := filepath.Join(tmpDir, "big.txt") + err = os.WriteFile(bigFile, []byte(strings.Repeat("x", MaxFileSize+1)), 0644) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + operation string + value string + want string + wantErr bool + errContains string + validate func(string) bool + }{ + { + name: "read file", + operation: "read", + value: testFile, + want: content, + }, + { + name: "tail file", + operation: "tail", + value: testFile + "|3", + want: "line3\nline4\nline5", + }, + { + name: "exists true", + operation: "exists", + value: testFile, + want: "true", + }, + { + name: "exists false", + operation: "exists", + value: filepath.Join(tmpDir, "nonexistent.txt"), + want: "false", + }, + { + name: "size", + operation: "size", + value: testFile, + want: "30", + }, + { + name: "modified", + operation: "modified", + value: testFile, + validate: func(got string) bool { + _, err := time.Parse(time.RFC3339, got) + return err == nil + }, + }, + // Error cases + { + name: "read non-existent", + operation: "read", + value: filepath.Join(tmpDir, "nonexistent.txt"), + wantErr: true, + errContains: "could not stat file", + }, + { + name: "invalid operation", + operation: "invalid", + value: testFile, + wantErr: true, + errContains: "unknown operation", + }, + { + name: "path traversal attempt", + operation: "read", + value: "../../../etc/passwd", + wantErr: true, + errContains: "cannot contain '..'", + }, + { + name: "file too large", + operation: "read", + value: bigFile, + wantErr: true, + errContains: "exceeds limit", + }, + { + name: "invalid tail format", + operation: "tail", + value: testFile, + wantErr: true, + errContains: "requires format path|lines", + }, + { + name: "invalid tail count", + operation: "tail", + value: testFile + "|invalid", + wantErr: true, + errContains: "invalid line count", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := plugin.Apply(tt.operation, tt.value) + + // Check error cases + if (err != nil) != tt.wantErr { + t.Errorf("FilePlugin.Apply() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if err != nil && tt.errContains != "" { + if !strings.Contains(err.Error(), tt.errContains) { + t.Errorf("error %q should contain %q", err.Error(), tt.errContains) + } + return + } + + // Check success cases + if err == nil { + if tt.validate != nil { + if !tt.validate(got) { + t.Errorf("FilePlugin.Apply() returned invalid result: %q", got) + } + } else if tt.want != "" && got != tt.want { + t.Errorf("FilePlugin.Apply() = %v, want %v", got, tt.want) + } + } + }) + } +} diff --git a/plugins/template/sys.go b/plugins/template/sys.go index 64059099..ed87d8bd 100644 --- a/plugins/template/sys.go +++ b/plugins/template/sys.go @@ -22,66 +22,66 @@ type SysPlugin struct{} // - pwd: Current working directory // - home: User's home directory func (p *SysPlugin) Apply(operation string, value string) (string, error) { - debugf("Sys: operation=%q value=%q", operation, value) - - switch operation { - case "hostname": - hostname, err := os.Hostname() - if err != nil { - debugf("Sys: hostname error: %v", err) - return "", fmt.Errorf("sys: hostname error: %v", err) - } - debugf("Sys: hostname=%q", hostname) - return hostname, nil - - case "user": - currentUser, err := user.Current() - if err != nil { - debugf("Sys: user error: %v", err) - return "", fmt.Errorf("sys: user error: %v", err) - } - debugf("Sys: user=%q", currentUser.Username) - return currentUser.Username, nil - - case "os": - result := runtime.GOOS - debugf("Sys: os=%q", result) - return result, nil - - case "arch": - result := runtime.GOARCH - debugf("Sys: arch=%q", result) - return result, nil - - case "env": - if value == "" { - debugf("Sys: env error: missing variable name") - return "", fmt.Errorf("sys: env operation requires a variable name") - } - result := os.Getenv(value) - debugf("Sys: env %q=%q", value, result) - return result, nil - - case "pwd": - dir, err := os.Getwd() - if err != nil { - debugf("Sys: pwd error: %v", err) - return "", fmt.Errorf("sys: pwd error: %v", err) - } - debugf("Sys: pwd=%q", dir) - return dir, nil - - case "home": - homeDir, err := os.UserHomeDir() - if err != nil { - debugf("Sys: home error: %v", err) - return "", fmt.Errorf("sys: home error: %v", err) - } - debugf("Sys: home=%q", homeDir) - return homeDir, nil + debugf("Sys: operation=%q value=%q", operation, value) - default: - debugf("Sys: unknown operation %q", operation) - return "", fmt.Errorf("sys: unknown operation %q (supported: hostname, user, os, arch, env, pwd, home)", operation) - } -} \ No newline at end of file + switch operation { + case "hostname": + hostname, err := os.Hostname() + if err != nil { + debugf("Sys: hostname error: %v", err) + return "", fmt.Errorf("sys: hostname error: %v", err) + } + debugf("Sys: hostname=%q", hostname) + return hostname, nil + + case "user": + currentUser, err := user.Current() + if err != nil { + debugf("Sys: user error: %v", err) + return "", fmt.Errorf("sys: user error: %v", err) + } + debugf("Sys: user=%q", currentUser.Username) + return currentUser.Username, nil + + case "os": + result := runtime.GOOS + debugf("Sys: os=%q", result) + return result, nil + + case "arch": + result := runtime.GOARCH + debugf("Sys: arch=%q", result) + return result, nil + + case "env": + if value == "" { + debugf("Sys: env error: missing variable name") + return "", fmt.Errorf("sys: env operation requires a variable name") + } + result := os.Getenv(value) + debugf("Sys: env %q=%q", value, result) + return result, nil + + case "pwd": + dir, err := os.Getwd() + if err != nil { + debugf("Sys: pwd error: %v", err) + return "", fmt.Errorf("sys: pwd error: %v", err) + } + debugf("Sys: pwd=%q", dir) + return dir, nil + + case "home": + homeDir, err := os.UserHomeDir() + if err != nil { + debugf("Sys: home error: %v", err) + return "", fmt.Errorf("sys: home error: %v", err) + } + debugf("Sys: home=%q", homeDir) + return homeDir, nil + + default: + debugf("Sys: unknown operation %q", operation) + return "", fmt.Errorf("sys: unknown operation %q (supported: hostname, user, os, arch, env, pwd, home)", operation) + } +} diff --git a/plugins/template/sys_test.go b/plugins/template/sys_test.go index 31544f9f..add00590 100644 --- a/plugins/template/sys_test.go +++ b/plugins/template/sys_test.go @@ -10,131 +10,131 @@ import ( ) func TestSysPlugin(t *testing.T) { - plugin := &SysPlugin{} - - // Set up test environment variable - const testEnvVar = "FABRIC_TEST_VAR" - const testEnvValue = "test_value" - os.Setenv(testEnvVar, testEnvValue) - defer os.Unsetenv(testEnvVar) - - tests := []struct { - name string - operation string - value string - validate func(string) error - wantErr bool - }{ - { - name: "hostname returns valid name", - operation: "hostname", - validate: func(got string) error { - if got == "" { - return fmt.Errorf("hostname is empty") - } - return nil - }, - }, - { - name: "user returns current user", - operation: "user", - validate: func(got string) error { - if got == "" { - return fmt.Errorf("username is empty") - } - return nil - }, - }, - { - name: "os returns valid OS", - operation: "os", - validate: func(got string) error { - if got != runtime.GOOS { - return fmt.Errorf("expected OS %s, got %s", runtime.GOOS, got) - } - return nil - }, - }, - { - name: "arch returns valid architecture", - operation: "arch", - validate: func(got string) error { - if got != runtime.GOARCH { - return fmt.Errorf("expected arch %s, got %s", runtime.GOARCH, got) - } - return nil - }, - }, - { - name: "env returns environment variable", - operation: "env", - value: testEnvVar, - validate: func(got string) error { - if got != testEnvValue { - return fmt.Errorf("expected env var %s, got %s", testEnvValue, got) - } - return nil - }, - }, - { - name: "pwd returns valid directory", - operation: "pwd", - validate: func(got string) error { - if !filepath.IsAbs(got) { - return fmt.Errorf("expected absolute path, got %s", got) - } - return nil - }, - }, - { - name: "home returns valid home directory", - operation: "home", - validate: func(got string) error { - if !filepath.IsAbs(got) { - return fmt.Errorf("expected absolute path, got %s", got) - } - if !strings.Contains(got, "home") && !strings.Contains(got, "Users") { - return fmt.Errorf("path %s doesn't look like a home directory", got) - } - return nil - }, - }, - // Error cases - { - name: "unknown operation", - operation: "invalid", - wantErr: true, - }, - { - name: "env without variable", - operation: "env", - wantErr: true, - }, - { - name: "env with non-existent variable", - operation: "env", - value: "NONEXISTENT_VAR_123456", - validate: func(got string) error { - if got != "" { - return fmt.Errorf("expected empty string for non-existent env var, got %s", got) - } - return nil - }, - }, - } + plugin := &SysPlugin{} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := plugin.Apply(tt.operation, tt.value) - if (err != nil) != tt.wantErr { - t.Errorf("SysPlugin.Apply() error = %v, wantErr %v", err, tt.wantErr) - return - } - if err == nil && tt.validate != nil { - if err := tt.validate(got); err != nil { - t.Errorf("SysPlugin.Apply() validation failed: %v", err) - } - } - }) - } -} \ No newline at end of file + // Set up test environment variable + const testEnvVar = "FABRIC_TEST_VAR" + const testEnvValue = "test_value" + os.Setenv(testEnvVar, testEnvValue) + defer os.Unsetenv(testEnvVar) + + tests := []struct { + name string + operation string + value string + validate func(string) error + wantErr bool + }{ + { + name: "hostname returns valid name", + operation: "hostname", + validate: func(got string) error { + if got == "" { + return fmt.Errorf("hostname is empty") + } + return nil + }, + }, + { + name: "user returns current user", + operation: "user", + validate: func(got string) error { + if got == "" { + return fmt.Errorf("username is empty") + } + return nil + }, + }, + { + name: "os returns valid OS", + operation: "os", + validate: func(got string) error { + if got != runtime.GOOS { + return fmt.Errorf("expected OS %s, got %s", runtime.GOOS, got) + } + return nil + }, + }, + { + name: "arch returns valid architecture", + operation: "arch", + validate: func(got string) error { + if got != runtime.GOARCH { + return fmt.Errorf("expected arch %s, got %s", runtime.GOARCH, got) + } + return nil + }, + }, + { + name: "env returns environment variable", + operation: "env", + value: testEnvVar, + validate: func(got string) error { + if got != testEnvValue { + return fmt.Errorf("expected env var %s, got %s", testEnvValue, got) + } + return nil + }, + }, + { + name: "pwd returns valid directory", + operation: "pwd", + validate: func(got string) error { + if !filepath.IsAbs(got) { + return fmt.Errorf("expected absolute path, got %s", got) + } + return nil + }, + }, + { + name: "home returns valid home directory", + operation: "home", + validate: func(got string) error { + if !filepath.IsAbs(got) { + return fmt.Errorf("expected absolute path, got %s", got) + } + if !strings.Contains(got, "home") && !strings.Contains(got, "Users") { + return fmt.Errorf("path %s doesn't look like a home directory", got) + } + return nil + }, + }, + // Error cases + { + name: "unknown operation", + operation: "invalid", + wantErr: true, + }, + { + name: "env without variable", + operation: "env", + wantErr: true, + }, + { + name: "env with non-existent variable", + operation: "env", + value: "NONEXISTENT_VAR_123456", + validate: func(got string) error { + if got != "" { + return fmt.Errorf("expected empty string for non-existent env var, got %s", got) + } + return nil + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := plugin.Apply(tt.operation, tt.value) + if (err != nil) != tt.wantErr { + t.Errorf("SysPlugin.Apply() error = %v, wantErr %v", err, tt.wantErr) + return + } + if err == nil && tt.validate != nil { + if err := tt.validate(got); err != nil { + t.Errorf("SysPlugin.Apply() validation failed: %v", err) + } + } + }) + } +} diff --git a/plugins/template/template.go b/plugins/template/template.go index d959f230..12231317 100644 --- a/plugins/template/template.go +++ b/plugins/template/template.go @@ -9,13 +9,12 @@ import ( ) var ( - textPlugin = &TextPlugin{} - datetimePlugin = &DateTimePlugin{} - filePlugin = &FilePlugin{} - fetchPlugin = &FetchPlugin{} - sysPlugin = &SysPlugin{} - extensionManager *ExtensionManager - Debug = false // Debug flag + textPlugin = &TextPlugin{} + datetimePlugin = &DateTimePlugin{} + filePlugin = &FilePlugin{} + fetchPlugin = &FetchPlugin{} + sysPlugin = &SysPlugin{} + Debug = false // Debug flag ) @@ -33,12 +32,13 @@ var pluginPattern = regexp.MustCompile(`\{\{plugin:([^:]+):([^:]+)(?::([^}]+))?\ var extensionPattern = regexp.MustCompile(`\{\{ext:([^:]+):([^:]+)(?::([^}]+))?\}\}`) func debugf(format string, a ...interface{}) { - if Debug { - fmt.Printf(format, a...) - } + if Debug { + fmt.Printf(format, a...) + } } func ApplyTemplate(content string, variables map[string]string, input string) (string, error) { + var missingVars []string r := regexp.MustCompile(`\{\{([^{}]+)\}\}`) @@ -154,6 +154,93 @@ func ApplyTemplate(content string, variables map[string]string, input string) (s } } - debugf("Template processing complete\n") - return content, nil -} \ No newline at end of file + debugf("Starting template processing\n") + for strings.Contains(content, "{{") { + matches := r.FindAllStringSubmatch(content, -1) + if len(matches) == 0 { + break + } + + replaced := false + for _, match := range matches { + fullMatch := match[0] + varName := match[1] + + // Check if this is a plugin call + if strings.HasPrefix(varName, "plugin:") { + pluginMatches := pluginPattern.FindStringSubmatch(fullMatch) + if len(pluginMatches) >= 3 { + namespace := pluginMatches[1] + operation := pluginMatches[2] + value := "" + if len(pluginMatches) == 4 { + value = pluginMatches[3] + } + + debugf("\nPlugin call:\n") + debugf(" Namespace: %s\n", namespace) + debugf(" Operation: %s\n", operation) + debugf(" Value: %s\n", value) + + var result string + var err error + + switch namespace { + case "text": + debugf("Executing text plugin\n") + result, err = textPlugin.Apply(operation, value) + case "datetime": + debugf("Executing datetime plugin\n") + result, err = datetimePlugin.Apply(operation, value) + case "file": + debugf("Executing file plugin\n") + result, err = filePlugin.Apply(operation, value) + debugf("File plugin result: %#v\n", result) + case "fetch": + debugf("Executing fetch plugin\n") + result, err = fetchPlugin.Apply(operation, value) + case "sys": + debugf("Executing sys plugin\n") + result, err = sysPlugin.Apply(operation, value) + default: + return "", fmt.Errorf("unknown plugin namespace: %s", namespace) + } + + if err != nil { + debugf("Plugin error: %v\n", err) + return "", fmt.Errorf("plugin %s error: %v", namespace, err) + } + + debugf("Plugin result: %s\n", result) + content = strings.ReplaceAll(content, fullMatch, result) + debugf("Content after replacement: %s\n", content) + continue + } + } + + // Handle regular variables and input + debugf("Processing variable: %s\n", varName) + if varName == "input" { + debugf("Replacing {{input}}\n") + replaced = true + content = strings.ReplaceAll(content, fullMatch, input) + } else { + if val, ok := variables[varName]; !ok { + debugf("Missing variable: %s\n", varName) + missingVars = append(missingVars, varName) + return "", fmt.Errorf("missing required variable: %s", varName) + } else { + debugf("Replacing variable %s with value: %s\n", varName, val) + content = strings.ReplaceAll(content, fullMatch, val) + replaced = true + } + } + if !replaced { + return "", fmt.Errorf("template processing stuck - potential infinite loop") + } + } + } + + debugf("Template processing complete\n") + return content, nil +} diff --git a/plugins/template/template_test.go b/plugins/template/template_test.go index d3617b6f..675d5bdc 100644 --- a/plugins/template/template_test.go +++ b/plugins/template/template_test.go @@ -6,141 +6,140 @@ import ( ) func TestApplyTemplate(t *testing.T) { - tests := []struct { - name string - template string - vars map[string]string - input string - want string - wantErr bool - errContains string - }{ - // Basic variable substitution - { - name: "simple variable", - template: "Hello {{name}}!", - vars: map[string]string{"name": "World"}, - want: "Hello World!", - }, - { - name: "multiple variables", - template: "{{greeting}} {{name}}!", - vars: map[string]string{ - "greeting": "Hello", - "name": "World", - }, - want: "Hello World!", - }, - { - name: "special input variable", - template: "Content: {{input}}", - input: "test content", - want: "Content: test content", - }, - - // Nested variable substitution - { - name: "nested variables", - template: "{{outer{{inner}}}}", - vars: map[string]string{ - "inner": "foo", // First resolution - "outerfoo": "result", // Second resolution - }, - want: "result", - }, - - // Plugin operations - { - name: "simple text plugin", - template: "{{plugin:text:upper:hello}}", - want: "HELLO", - }, - { - name: "text plugin with variable", - template: "{{plugin:text:upper:{{name}}}}", - vars: map[string]string{"name": "world"}, - want: "WORLD", - }, - { - name: "plugin with dynamic operation", - template: "{{plugin:text:{{operation}}:hello}}", - vars: map[string]string{"operation": "upper"}, - want: "HELLO", - }, - - // Multiple operations - { - name: "multiple plugins", - template: "A:{{plugin:text:upper:hello}} B:{{plugin:text:lower:WORLD}}", - want: "A:HELLO B:world", - }, - { - name: "nested plugins", - template: "{{plugin:text:upper:{{plugin:text:lower:HELLO}}}}", - want: "HELLO", - }, - - // Error cases - { - name: "missing variable", - template: "Hello {{name}}!", - wantErr: true, - errContains: "missing required variable", - }, - { - name: "unknown plugin", - template: "{{plugin:invalid:op:value}}", - wantErr: true, - errContains: "unknown plugin namespace", - }, - { - name: "unknown plugin operation", - template: "{{plugin:text:invalid:value}}", - wantErr: true, - errContains: "unknown text operation", - }, - { - name: "nested plugin error", - template: "{{plugin:text:upper:{{plugin:invalid:op:value}}}}", - wantErr: true, - errContains: "unknown plugin namespace", - }, - - // Edge cases - { - name: "empty template", - template: "", - want: "", - }, - { - name: "no substitutions needed", - template: "plain text", - want: "plain text", - }, - } + tests := []struct { + name string + template string + vars map[string]string + input string + want string + wantErr bool + errContains string + }{ + // Basic variable substitution + { + name: "simple variable", + template: "Hello {{name}}!", + vars: map[string]string{"name": "World"}, + want: "Hello World!", + }, + { + name: "multiple variables", + template: "{{greeting}} {{name}}!", + vars: map[string]string{ + "greeting": "Hello", + "name": "World", + }, + want: "Hello World!", + }, + { + name: "special input variable", + template: "Content: {{input}}", + input: "test content", + want: "Content: test content", + }, - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := ApplyTemplate(tt.template, tt.vars, tt.input) - - // Check error cases - if (err != nil) != tt.wantErr { - t.Errorf("ApplyTemplate() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if err != nil && tt.errContains != "" { - if !strings.Contains(err.Error(), tt.errContains) { - t.Errorf("error %q should contain %q", err.Error(), tt.errContains) - } - return - } - - // Check result - if got != tt.want { - t.Errorf("ApplyTemplate() = %q, want %q", got, tt.want) - } - }) - } + // Nested variable substitution + { + name: "nested variables", + template: "{{outer{{inner}}}}", + vars: map[string]string{ + "inner": "foo", // First resolution + "outerfoo": "result", // Second resolution + }, + want: "result", + }, + + // Plugin operations + { + name: "simple text plugin", + template: "{{plugin:text:upper:hello}}", + want: "HELLO", + }, + { + name: "text plugin with variable", + template: "{{plugin:text:upper:{{name}}}}", + vars: map[string]string{"name": "world"}, + want: "WORLD", + }, + { + name: "plugin with dynamic operation", + template: "{{plugin:text:{{operation}}:hello}}", + vars: map[string]string{"operation": "upper"}, + want: "HELLO", + }, + + // Multiple operations + { + name: "multiple plugins", + template: "A:{{plugin:text:upper:hello}} B:{{plugin:text:lower:WORLD}}", + want: "A:HELLO B:world", + }, + { + name: "nested plugins", + template: "{{plugin:text:upper:{{plugin:text:lower:HELLO}}}}", + want: "HELLO", + }, + + // Error cases + { + name: "missing variable", + template: "Hello {{name}}!", + wantErr: true, + errContains: "missing required variable", + }, + { + name: "unknown plugin", + template: "{{plugin:invalid:op:value}}", + wantErr: true, + errContains: "unknown plugin namespace", + }, + { + name: "unknown plugin operation", + template: "{{plugin:text:invalid:value}}", + wantErr: true, + errContains: "unknown text operation", + }, + { + name: "nested plugin error", + template: "{{plugin:text:upper:{{plugin:invalid:op:value}}}}", + wantErr: true, + errContains: "unknown plugin namespace", + }, + + // Edge cases + { + name: "empty template", + template: "", + want: "", + }, + { + name: "no substitutions needed", + template: "plain text", + want: "plain text", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ApplyTemplate(tt.template, tt.vars, tt.input) + + // Check error cases + if (err != nil) != tt.wantErr { + t.Errorf("ApplyTemplate() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if err != nil && tt.errContains != "" { + if !strings.Contains(err.Error(), tt.errContains) { + t.Errorf("error %q should contain %q", err.Error(), tt.errContains) + } + return + } + + // Check result + if got != tt.want { + t.Errorf("ApplyTemplate() = %q, want %q", got, tt.want) + } + }) + } } - diff --git a/plugins/template/text.go b/plugins/template/text.go index e3d3f76e..e7872e3a 100644 --- a/plugins/template/text.go +++ b/plugins/template/text.go @@ -12,53 +12,53 @@ type TextPlugin struct{} // toTitle capitalizes a letter if it follows a non-letter, unless next char is space func toTitle(s string) string { - // First lowercase everything - lower := strings.ToLower(s) - runes := []rune(lower) - - for i := 0; i < len(runes); i++ { - // Capitalize if previous char is non-letter AND - // (we're at the end OR next char is not space) - if (i == 0 || !unicode.IsLetter(runes[i-1])) { - if i == len(runes)-1 || !unicode.IsSpace(runes[i+1]) { - runes[i] = unicode.ToUpper(runes[i]) - } - } - } - - return string(runes) + // First lowercase everything + lower := strings.ToLower(s) + runes := []rune(lower) + + for i := 0; i < len(runes); i++ { + // Capitalize if previous char is non-letter AND + // (we're at the end OR next char is not space) + if i == 0 || !unicode.IsLetter(runes[i-1]) { + if i == len(runes)-1 || !unicode.IsSpace(runes[i+1]) { + runes[i] = unicode.ToUpper(runes[i]) + } + } + } + + return string(runes) } // Apply executes the requested text operation on the provided value func (p *TextPlugin) Apply(operation string, value string) (string, error) { - debugf("TextPlugin: operation=%s value=%q", operation, value) - - if value == "" { - return "", fmt.Errorf("text: empty input for operation %q", operation) - } + debugf("TextPlugin: operation=%s value=%q", operation, value) - switch operation { - case "upper": - result := strings.ToUpper(value) - debugf("TextPlugin: upper result=%q", result) - return result, nil - - case "lower": - result := strings.ToLower(value) - debugf("TextPlugin: lower result=%q", result) - return result, nil - - case "title": - result := toTitle(value) - debugf("TextPlugin: title result=%q", result) - return result, nil + if value == "" { + return "", fmt.Errorf("text: empty input for operation %q", operation) + } - case "trim": - result := strings.TrimSpace(value) - debugf("TextPlugin: trim result=%q", result) - return result, nil - - default: - return "", fmt.Errorf("text: unknown text operation %q (supported: upper, lower, title, trim)", operation) - } -} \ No newline at end of file + switch operation { + case "upper": + result := strings.ToUpper(value) + debugf("TextPlugin: upper result=%q", result) + return result, nil + + case "lower": + result := strings.ToLower(value) + debugf("TextPlugin: lower result=%q", result) + return result, nil + + case "title": + result := toTitle(value) + debugf("TextPlugin: title result=%q", result) + return result, nil + + case "trim": + result := strings.TrimSpace(value) + debugf("TextPlugin: trim result=%q", result) + return result, nil + + default: + return "", fmt.Errorf("text: unknown text operation %q (supported: upper, lower, title, trim)", operation) + } +} diff --git a/plugins/template/text_test.go b/plugins/template/text_test.go index 4a85f838..b44ba5e9 100644 --- a/plugins/template/text_test.go +++ b/plugins/template/text_test.go @@ -5,100 +5,100 @@ import ( ) func TestTextPlugin(t *testing.T) { - plugin := &TextPlugin{} + plugin := &TextPlugin{} - tests := []struct { - name string - operation string - value string - want string - wantErr bool - }{ - // Upper tests - { - name: "upper basic", - operation: "upper", - value: "hello", - want: "HELLO", - }, - { - name: "upper mixed case", - operation: "upper", - value: "hElLo", - want: "HELLO", - }, - - // Lower tests - { - name: "lower basic", - operation: "lower", - value: "HELLO", - want: "hello", - }, - { - name: "lower mixed case", - operation: "lower", - value: "hElLo", - want: "hello", - }, - - // Title tests - { - name: "title basic", - operation: "title", - value: "hello world", - want: "Hello World", - }, - { - name: "title with apostrophe", - operation: "title", - value: "o'reilly's book", - want: "O'Reilly's Book", - }, - - // Trim tests - { - name: "trim spaces", - operation: "trim", - value: " hello ", - want: "hello", - }, - { - name: "trim newlines", - operation: "trim", - value: "\nhello\n", - want: "hello", - }, - - // Error cases - { - name: "empty value", - operation: "upper", - value: "", - wantErr: true, - }, - { - name: "unknown operation", - operation: "invalid", - value: "test", - wantErr: true, - }, - } + tests := []struct { + name string + operation string + value string + want string + wantErr bool + }{ + // Upper tests + { + name: "upper basic", + operation: "upper", + value: "hello", + want: "HELLO", + }, + { + name: "upper mixed case", + operation: "upper", + value: "hElLo", + want: "HELLO", + }, - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := plugin.Apply(tt.operation, tt.value) - - // Check error cases - if (err != nil) != tt.wantErr { - t.Errorf("TextPlugin.Apply() error = %v, wantErr %v", err, tt.wantErr) - return - } - - // Check successful cases - if err == nil && got != tt.want { - t.Errorf("TextPlugin.Apply() = %q, want %q", got, tt.want) - } - }) - } -} \ No newline at end of file + // Lower tests + { + name: "lower basic", + operation: "lower", + value: "HELLO", + want: "hello", + }, + { + name: "lower mixed case", + operation: "lower", + value: "hElLo", + want: "hello", + }, + + // Title tests + { + name: "title basic", + operation: "title", + value: "hello world", + want: "Hello World", + }, + { + name: "title with apostrophe", + operation: "title", + value: "o'reilly's book", + want: "O'Reilly's Book", + }, + + // Trim tests + { + name: "trim spaces", + operation: "trim", + value: " hello ", + want: "hello", + }, + { + name: "trim newlines", + operation: "trim", + value: "\nhello\n", + want: "hello", + }, + + // Error cases + { + name: "empty value", + operation: "upper", + value: "", + wantErr: true, + }, + { + name: "unknown operation", + operation: "invalid", + value: "test", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := plugin.Apply(tt.operation, tt.value) + + // Check error cases + if (err != nil) != tt.wantErr { + t.Errorf("TextPlugin.Apply() error = %v, wantErr %v", err, tt.wantErr) + return + } + + // Check successful cases + if err == nil && got != tt.want { + t.Errorf("TextPlugin.Apply() = %q, want %q", got, tt.want) + } + }) + } +} diff --git a/plugins/tools/to_pdf/to_pdf.go b/plugins/tools/to_pdf/to_pdf.go index 23b7d7cb..6963227b 100644 --- a/plugins/tools/to_pdf/to_pdf.go +++ b/plugins/tools/to_pdf/to_pdf.go @@ -76,12 +76,19 @@ func main() { } // Move the output PDF to the current directory - err = os.Rename(pdfPath, outputFile) + err = copyFile(pdfPath, outputFile) if err != nil { fmt.Fprintf(os.Stderr, "Error moving output file: %v\n", err) os.Exit(1) } + // Remove the original file after copying + err = os.Remove(pdfPath) + if err != nil { + fmt.Fprintf(os.Stderr, "Error cleaning up temporary file: %v\n", err) + os.Exit(1) + } + // Clean up temporary files cleanupTempFiles(tmpDir) @@ -103,3 +110,25 @@ func cleanupTempFiles(dir string) { } } } + +// Copy a file from source src to destination dst +func copyFile(src, dst string) error { + sourceFile, err := os.Open(src) + if err != nil { + return err + } + defer sourceFile.Close() + + destFile, err := os.Create(dst) + if err != nil { + return err + } + defer destFile.Close() + + _, err = io.Copy(destFile, sourceFile) + if err != nil { + return err + } + + return destFile.Sync() +} diff --git a/restapi/chat.go b/restapi/chat.go new file mode 100755 index 00000000..3262f6b9 --- /dev/null +++ b/restapi/chat.go @@ -0,0 +1,211 @@ +package restapi + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "strings" + + goopenai "github.com/sashabaranov/go-openai" + + "github.com/danielmiessler/fabric/common" + "github.com/danielmiessler/fabric/core" + "github.com/danielmiessler/fabric/plugins/db/fsdb" + "github.com/gin-gonic/gin" +) + +type ChatHandler struct { + registry *core.PluginRegistry + db *fsdb.Db +} + +type PromptRequest struct { + UserInput string `json:"userInput"` + Vendor string `json:"vendor"` + Model string `json:"model"` + ContextName string `json:"contextName"` + PatternName string `json:"patternName"` +} + +type ChatRequest struct { + Prompts []PromptRequest `json:"prompts"` + common.ChatOptions // Embed the ChatOptions from common package +} + +type StreamResponse struct { + Type string `json:"type"` // "content", "error", "complete" + Format string `json:"format"` // "markdown", "mermaid", "plain" + Content string `json:"content"` // The actual content +} + +func NewChatHandler(r *gin.Engine, registry *core.PluginRegistry, db *fsdb.Db) *ChatHandler { + handler := &ChatHandler{ + registry: registry, + db: db, + } + + r.POST("/chat", handler.HandleChat) + + return handler +} + +func (h *ChatHandler) HandleChat(c *gin.Context) { + var request ChatRequest + + if err := c.BindJSON(&request); err != nil { + log.Printf("Error binding JSON: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid request format: %v", err)}) + return + } + + log.Printf("Received chat request with %d prompts", len(request.Prompts)) + + // Set headers for SSE + c.Writer.Header().Set("Content-Type", "text/readystream") + c.Writer.Header().Set("Cache-Control", "no-cache") + c.Writer.Header().Set("Connection", "keep-alive") + c.Writer.Header().Set("Access-Control-Allow-Origin", "http://localhost:5173") + c.Writer.Header().Set("X-Accel-Buffering", "no") + + clientGone := c.Writer.CloseNotify() + + for i, prompt := range request.Prompts { + select { + case <-clientGone: + log.Printf("Client disconnected") + return + default: + log.Printf("Processing prompt %d: Model=%s Pattern=%s Context=%s", + i+1, prompt.Model, prompt.PatternName, prompt.ContextName) + + // Create chat channel for streaming + streamChan := make(chan string) + + // Start chat processing in goroutine + go func(p PromptRequest) { + defer close(streamChan) + + chatter, err := h.registry.GetChatter(p.Model, 2048, false, false) + if err != nil { + log.Printf("Error creating chatter: %v", err) + streamChan <- fmt.Sprintf("Error: %v", err) + return + } + + chatReq := &common.ChatRequest{ + Message: &goopenai.ChatCompletionMessage{ + Role: "user", + Content: p.UserInput, + }, + PatternName: p.PatternName, + ContextName: p.ContextName, + } + + opts := &common.ChatOptions{ + Model: p.Model, + Temperature: request.Temperature, + TopP: request.TopP, + FrequencyPenalty: request.FrequencyPenalty, + PresencePenalty: request.PresencePenalty, + } + + session, err := chatter.Send(chatReq, opts) + if err != nil { + log.Printf("Error from chatter.Send: %v", err) + streamChan <- fmt.Sprintf("Error: %v", err) + return + } + + if session == nil { + log.Printf("No session returned from chatter.Send") + streamChan <- "Error: No response from model" + return + } + + // Get the last message from the session + lastMsg := session.GetLastMessage() + if lastMsg != nil { + streamChan <- lastMsg.Content + } else { + log.Printf("No message content in session") + streamChan <- "Error: No response content" + } + }(prompt) + + // Read from streamChan and write to client + for content := range streamChan { + select { + case <-clientGone: + return + default: + if strings.HasPrefix(content, "Error:") { + response := StreamResponse{ + Type: "error", + Format: "plain", + Content: content, + } + if err := writeSSEResponse(c.Writer, response); err != nil { + log.Printf("Error writing error response: %v", err) + return + } + } else { + response := StreamResponse{ + Type: "content", + Format: detectFormat(content), + Content: content, + } + if err := writeSSEResponse(c.Writer, response); err != nil { + log.Printf("Error writing content response: %v", err) + return + } + } + } + } + + // Signal completion of this prompt + completeResponse := StreamResponse{ + Type: "complete", + Format: "plain", + Content: "", + } + if err := writeSSEResponse(c.Writer, completeResponse); err != nil { + log.Printf("Error writing completion response: %v", err) + return + } + } + } +} + +func writeSSEResponse(w gin.ResponseWriter, response StreamResponse) error { + data, err := json.Marshal(response) + if err != nil { + return fmt.Errorf("error marshaling response: %v", err) + } + + if _, err := fmt.Fprintf(w, "data: %s\n\n", string(data)); err != nil { + return fmt.Errorf("error writing response: %v", err) + } + + w.(http.Flusher).Flush() + return nil +} + +func detectFormat(content string) string { + if strings.HasPrefix(content, "graph TD") || + strings.HasPrefix(content, "gantt") || + strings.HasPrefix(content, "flowchart") || + strings.HasPrefix(content, "sequenceDiagram") || + strings.HasPrefix(content, "classDiagram") || + strings.HasPrefix(content, "stateDiagram") { + return "mermaid" + } + if strings.Contains(content, "```") || + strings.Contains(content, "#") || + strings.Contains(content, "*") || + strings.Contains(content, "_") || + strings.Contains(content, "-") { + return "markdown" + } + return "plain" +} diff --git a/restapi/configuration.go b/restapi/configuration.go new file mode 100755 index 00000000..deb6e52f --- /dev/null +++ b/restapi/configuration.go @@ -0,0 +1,124 @@ +package restapi + +import ( + "fmt" + "net/http" + "os" + "strings" + + "github.com/danielmiessler/fabric/plugins/db/fsdb" + "github.com/gin-gonic/gin" +) + +// ConfigHandler defines the handler for configuration-related operations +type ConfigHandler struct { + db *fsdb.Db + // configurations *fsdb.EnvFilePath("$HOME/.config/fabric/.env") +} + +func NewConfigHandler(r *gin.Engine, db *fsdb.Db) *ConfigHandler { + handler := &ConfigHandler{ + db: db, + // configurations: db.Configurations, + } + + r.GET("/config", handler.GetConfig) + r.POST("/config/update", handler.UpdateConfig) + + return handler +} + +func (h *ConfigHandler) GetConfig(c *gin.Context) { + if h.db == nil { + c.JSON(http.StatusNotFound, gin.H{"error": ".env file not found"}) + return + } + + if !h.db.IsEnvFileExists() { + c.JSON(http.StatusOK, gin.H{ + "openai": "", + "anthropic": "", + "groq": "", + "mistral": "", + "gemini": "", + "ollama": "", + "openrouter": "", + "silicon": "", + }) + return + } + + err := h.db.LoadEnvFile() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + config := map[string]string{ + "openai": os.Getenv("OPENAI_API_KEY"), + "anthropic": os.Getenv("ANTHROPIC_API_KEY"), + "groq": os.Getenv("GROQ_API_KEY"), + "mistral": os.Getenv("MISTRAL_API_KEY"), + "gemini": os.Getenv("GEMINI_API_KEY"), + "ollama": os.Getenv("OLLAMA_URL"), + "openrouter": os.Getenv("OPENROUTER_API_KEY"), + "silicon": os.Getenv("SILICON_API_KEY"), + } + + c.JSON(http.StatusOK, config) +} + +func (h *ConfigHandler) UpdateConfig(c *gin.Context) { + if h.db == nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Database not initialized"}) + return + } + + var config struct { + OpenAIApiKey string `json:"openai_api_key"` + AnthropicApiKey string `json:"anthropic_api_key"` + GroqApiKey string `json:"groq_api_key"` + MistralApiKey string `json:"mistral_api_key"` + GeminiApiKey string `json:"gemini_api_key"` + OllamaURL string `json:"ollama_url"` + OpenRouterApiKey string `json:"openrouter_api_key"` + SiliconApiKey string `json:"silicon_api_key"` + } + + if err := c.BindJSON(&config); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + envVars := map[string]string{ + "OPENAI_API_KEY": config.OpenAIApiKey, + "ANTHROPIC_API_KEY": config.AnthropicApiKey, + "GROQ_API_KEY": config.GroqApiKey, + "MISTRAL_API_KEY": config.MistralApiKey, + "GEMINI_API_KEY": config.GeminiApiKey, + "OLLAMA_URL": config.OllamaURL, + "OPENROUTER_API_KEY": config.OpenRouterApiKey, + "SILICON_API_KEY": config.SiliconApiKey, + } + + var envContent strings.Builder + for key, value := range envVars { + if value != "" { + envContent.WriteString(fmt.Sprintf("%s=%s\n", key, value)) + os.Setenv(key, value) + } + } + + // Save configuration to file + if err := h.db.SaveEnv(envContent.String()); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if err := h.db.LoadEnvFile(); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "Configuration updated successfully"}) +} diff --git a/restapi/models.go b/restapi/models.go new file mode 100755 index 00000000..186c3b6e --- /dev/null +++ b/restapi/models.go @@ -0,0 +1,45 @@ +package restapi + +import ( + "github.com/danielmiessler/fabric/plugins/ai" + "github.com/gin-gonic/gin" +) + +type ModelsHandler struct { + vendorManager *ai.VendorsManager +} + +func NewModelsHandler(r *gin.Engine, vendorManager *ai.VendorsManager) { + handler := &ModelsHandler{ + vendorManager: vendorManager, + } + + r.GET("/models/names", handler.GetModelNames) +} + +func (h *ModelsHandler) GetModelNames(c *gin.Context) { + vendorsModels, err := h.vendorManager.GetModels() + if err != nil { + c.JSON(500, gin.H{"error": "Server failed to retrieve model names"}) + return + } + + response := make(map[string]interface{}) + vendors := make(map[string][]string) + + for _, groupItems := range vendorsModels.GroupsItems { + vendors[groupItems.Group] = groupItems.Items + } + + response["models"] = h.getAllModelNames(vendorsModels) + response["vendors"] = vendors + c.JSON(200, response) +} + +func (h *ModelsHandler) getAllModelNames(vendorsModels *ai.VendorsModels) []string { + var allModelNames []string + for _, groupItems := range vendorsModels.GroupsItems { + allModelNames = append(allModelNames, groupItems.Items...) + } + return allModelNames +} diff --git a/restapi/ollama.go b/restapi/ollama.go new file mode 100644 index 00000000..0d806729 --- /dev/null +++ b/restapi/ollama.go @@ -0,0 +1,275 @@ +package restapi + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "github.com/danielmiessler/fabric/core" + "github.com/gin-gonic/gin" + "io" + "log" + "net/http" + "strings" + "time" +) + +type OllamaModel struct { + Models []Model `json:"models"` +} +type Model struct { + Details ModelDetails `json:"details"` + Digest string `json:"digest"` + Model string `json:"model"` + ModifiedAt string `json:"modified_at"` + Name string `json:"name"` + Size int64 `json:"size"` +} + +type ModelDetails struct { + Families []string `json:"families"` + Family string `json:"family"` + Format string `json:"format"` + ParameterSize string `json:"parameter_size"` + ParentModel string `json:"parent_model"` + QuantizationLevel string `json:"quantization_level"` +} + +type APIConvert struct { + registry *core.PluginRegistry + r *gin.Engine + addr *string +} + +type OllamaRequestBody struct { + Messages []OllamaMessage `json:"messages"` + Model string `json:"model"` + Options struct { + } `json:"options"` + Stream bool `json:"stream"` +} + +type OllamaMessage struct { + Content string `json:"content"` + Role string `json:"role"` +} + +type OllamaResponse struct { + Model string `json:"model"` + CreatedAt string `json:"created_at"` + Message struct { + Role string `json:"role"` + Content string `json:"content"` + } `json:"message"` + DoneReason string `json:"done_reason,omitempty"` + Done bool `json:"done"` + TotalDuration int64 `json:"total_duration,omitempty"` + LoadDuration int `json:"load_duration,omitempty"` + PromptEvalCount int `json:"prompt_eval_count,omitempty"` + PromptEvalDuration int `json:"prompt_eval_duration,omitempty"` + EvalCount int `json:"eval_count,omitempty"` + EvalDuration int64 `json:"eval_duration,omitempty"` +} + +type FabricResponseFormat struct { + Type string `json:"type"` + Format string `json:"format"` + Content string `json:"content"` +} + +func ServeOllama(registry *core.PluginRegistry, address string, version string) (err error) { + r := gin.New() + + // Middleware + r.Use(gin.Logger()) + r.Use(gin.Recovery()) + + // Register routes + fabricDb := registry.Db + NewPatternsHandler(r, fabricDb.Patterns) + NewContextsHandler(r, fabricDb.Contexts) + NewSessionsHandler(r, fabricDb.Sessions) + NewChatHandler(r, registry, fabricDb) + NewConfigHandler(r, fabricDb) + NewModelsHandler(r, registry.VendorManager) + + typeConversion := APIConvert{ + registry: registry, + r: r, + addr: &address, + } + // Ollama Endpoints + r.GET("/api/tags", typeConversion.ollamaTags) + r.GET("/api/version", func(c *gin.Context) { + c.Data(200, "application/json", []byte(fmt.Sprintf("{\"%s\"}", version))) + return + }) + r.POST("/api/chat", typeConversion.ollamaChat) + + // Start server + err = r.Run(address) + if err != nil { + return err + } + + return +} + +func (f APIConvert) ollamaTags(c *gin.Context) { + patterns, err := f.registry.Db.Patterns.GetNames() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err}) + return + } + var response OllamaModel + for _, pattern := range patterns { + today := time.Now().Format("2024-11-25T12:07:58.915991813-05:00") + details := ModelDetails{ + Families: []string{"fabric"}, + Family: "fabric", + Format: "custom", + ParameterSize: "42.0B", + ParentModel: "", + QuantizationLevel: "", + } + response.Models = append(response.Models, Model{ + Details: details, + Digest: "365c0bd3c000a25d28ddbf732fe1c6add414de7275464c4e4d1c3b5fcb5d8ad1", + Model: fmt.Sprintf("%s:latest", pattern), + ModifiedAt: today, + Name: fmt.Sprintf("%s:latest", pattern), + Size: 0, + }) + } + + c.JSON(200, response) + +} + +func (f APIConvert) ollamaChat(c *gin.Context) { + body, err := io.ReadAll(c.Request.Body) + if err != nil { + log.Printf("Error reading body: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "testing endpoint"}) + return + } + var prompt OllamaRequestBody + err = json.Unmarshal(body, &prompt) + if err != nil { + log.Printf("Error unmarshalling body: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "testing endpoint"}) + return + } + now := time.Now() + var chat ChatRequest + + if len(prompt.Messages) == 1 { + chat.Prompts = []PromptRequest{{ + UserInput: prompt.Messages[0].Content, + Vendor: "", + Model: "", + ContextName: "", + PatternName: strings.Split(prompt.Model, ":")[0], + }} + } else if len(prompt.Messages) > 1 { + var content string + for _, msg := range prompt.Messages { + content = fmt.Sprintf("%s%s:%s\n", content, msg.Role, msg.Content) + } + chat.Prompts = []PromptRequest{{ + UserInput: content, + Vendor: "", + Model: "", + ContextName: "", + PatternName: strings.Split(prompt.Model, ":")[0], + }} + } + fabricChatReq, err := json.Marshal(chat) + if err != nil { + log.Printf("Error marshalling body: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": err}) + return + } + ctx := context.Background() + var req *http.Request + if strings.Contains(*f.addr, "http") { + req, err = http.NewRequest("POST", fmt.Sprintf("%s/chat", *f.addr), bytes.NewBuffer(fabricChatReq)) + } else { + req, err = http.NewRequest("POST", fmt.Sprintf("http://127.0.0.1%s/chat", *f.addr), bytes.NewBuffer(fabricChatReq)) + } + if err != nil { + log.Fatal(err) + } + + req = req.WithContext(ctx) + + fabricRes, err := http.DefaultClient.Do(req) + if err != nil { + log.Printf("Error getting /chat body: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": err}) + return + } + body, err = io.ReadAll(fabricRes.Body) + if err != nil { + log.Printf("Error reading body: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "testing endpoint"}) + return + } + var forwardedResponse OllamaResponse + var forwardedResponses []OllamaResponse + var fabricResponse FabricResponseFormat + err = json.Unmarshal([]byte(strings.Split(strings.Split(string(body), "\n")[0], "data: ")[1]), &fabricResponse) + if err != nil { + log.Printf("Error unmarshalling body: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "testing endpoint"}) + return + } + for _, word := range strings.Split(fabricResponse.Content, " ") { + forwardedResponse = OllamaResponse{ + Model: "", + CreatedAt: "", + Message: struct { + Role string `json:"role"` + Content string `json:"content"` + }(struct { + Role string + Content string + }{Content: fmt.Sprintf("%s ", word), Role: "assistant"}), + Done: false, + } + forwardedResponses = append(forwardedResponses, forwardedResponse) + } + forwardedResponse.Model = prompt.Model + forwardedResponse.CreatedAt = time.Now().UTC().Format("2006-01-02T15:04:05.999999999Z") + forwardedResponse.Message.Role = "assistant" + forwardedResponse.Message.Content = "" + forwardedResponse.DoneReason = "stop" + forwardedResponse.Done = true + forwardedResponse.TotalDuration = time.Since(now).Nanoseconds() + forwardedResponse.LoadDuration = int(time.Since(now).Nanoseconds()) + forwardedResponse.PromptEvalCount = 42 + forwardedResponse.PromptEvalDuration = int(time.Since(now).Nanoseconds()) + forwardedResponse.EvalCount = 420 + forwardedResponse.EvalDuration = time.Since(now).Nanoseconds() + forwardedResponses = append(forwardedResponses, forwardedResponse) + + var res []byte + for _, response := range forwardedResponses { + marshalled, err := json.Marshal(response) + if err != nil { + log.Printf("Error marshalling body: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": err}) + return + } + for _, bytein := range marshalled { + res = append(res, bytein) + } + for _, bytebreak := range []byte("\n") { + res = append(res, bytebreak) + } + } + c.Data(200, "application/json", res) + + //c.JSON(200, forwardedResponse) + return +} diff --git a/restapi/patterns.go b/restapi/patterns.go index 92949b8e..f5e4459e 100644 --- a/restapi/patterns.go +++ b/restapi/patterns.go @@ -27,7 +27,7 @@ func NewPatternsHandler(r *gin.Engine, patterns *fsdb.PatternsEntity) (ret *Patt func (h *PatternsHandler) Get(c *gin.Context) { name := c.Param("name") variables := make(map[string]string) // Assuming variables are passed somehow - input := "" // Assuming input is passed somehow + input := "" // Assuming input is passed somehow pattern, err := h.patterns.GetApplyVariables(name, variables, input) if err != nil { c.JSON(http.StatusInternalServerError, err.Error()) diff --git a/restapi/serve.go b/restapi/serve.go index f318fcf0..51f6cd2b 100644 --- a/restapi/serve.go +++ b/restapi/serve.go @@ -17,6 +17,9 @@ func Serve(registry *core.PluginRegistry, address string) (err error) { NewPatternsHandler(r, fabricDb.Patterns) NewContextsHandler(r, fabricDb.Contexts) NewSessionsHandler(r, fabricDb.Sessions) + NewChatHandler(r, registry, fabricDb) + NewConfigHandler(r, fabricDb) + NewModelsHandler(r, registry.VendorManager) // Start server err = r.Run(address) diff --git a/streamlit.py b/streamlit.py new file mode 100644 index 00000000..64a96bc5 --- /dev/null +++ b/streamlit.py @@ -0,0 +1,1737 @@ +import shutil +import json +import os +import streamlit as st +from subprocess import run, CalledProcessError +from dotenv import load_dotenv +import re +import time +import logging +from typing import Dict, List, Optional, Tuple +from datetime import datetime +import sys +import pandas as pd +import matplotlib.pyplot as plt +import seaborn as sns +import numpy as np + +# Create formatters +console_formatter = logging.Formatter( + '\033[92m%(asctime)s\033[0m - ' # Green timestamp + '\033[94m%(levelname)s\033[0m - ' # Blue level + '\033[95m[%(funcName)s]\033[0m ' # Purple function name + '%(message)s' # Regular message +) +file_formatter = logging.Formatter('%(asctime)s - %(levelname)s - [%(funcName)s] %(message)s') + +# Configure root logger +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + +# Clear any existing handlers +logger.handlers = [] + +# Console Handler +console_handler = logging.StreamHandler(sys.stdout) +console_handler.setFormatter(console_formatter) +console_handler.setLevel(logging.INFO) +logger.addHandler(console_handler) + +# File Handler +log_dir = os.path.expanduser("~/.config/fabric/logs") +os.makedirs(log_dir, exist_ok=True) +log_file = os.path.join(log_dir, f"fabric_ui_{datetime.now().strftime('%Y%m%d')}.log") +file_handler = logging.FileHandler(log_file) +file_handler.setFormatter(file_formatter) +file_handler.setLevel(logging.DEBUG) # More detailed logging in file +logger.addHandler(file_handler) + +# Log startup message +logger.info("🚀 Fabric UI Starting Up") +logger.info(f"💾 Log file: {log_file}") + +# Global variables +pattern_dir = os.path.expanduser("~/.config/fabric/patterns") +MAX_RETRIES = 3 +RETRY_DELAY = 1 # seconds + +def initialize_session_state(): + """Initialize necessary session state attributes. + + Error handling: + - Ensures all required session state variables are initialized + - Loads saved outputs from persistent storage + - Handles missing or corrupted saved output files + """ + logger.info("Initializing session state") + default_configs = { + # Configuration state + "config_loaded": False, + "vendors": {}, + "available_models": [], + "selected_vendor": None, + "selected_model": None, + + # Pattern execution state + "input_content": "", + "selected_patterns": [], + "chat_output": [], + "current_view": "run", + + # Pattern creation state + "wizard_step": "Basic Info", + "session_name": "", + "context_name": "", + + # Model configuration + "config": { + "vendor": "", + "model": "", + "context_length": "2048" + }, + + # Model caching + "cached_models": None, + "last_model_fetch": 0, + + # UI state + "active_tab": 0, + + # Output management + "output_logs": [], + "starred_outputs": [], + "starring_output": None, + "temp_star_name": "" + } + + for key, value in default_configs.items(): + if key not in st.session_state: + st.session_state[key] = value + + # Load saved outputs if they exist + load_saved_outputs() + +def parse_models_output(output: str) -> Dict[str, List[str]]: + """Parse the output of fabric --listmodels command.""" + logger.debug("Parsing models output") + providers = {} + current_provider = None + + lines = output.split('\n') + for line in lines: + line = line.strip() + if not line: + continue + + if line == "Available models:": + continue + + if not line.startswith('\t') and not line.startswith('['): + current_provider = line.strip() + providers[current_provider] = [] + elif current_provider and (line.startswith('\t') or line.startswith('[')): + model = line.strip() + if '[' in model and ']' in model: + model = model.split(']', 1)[1].strip() + providers[current_provider].append(model) + + logger.debug(f"Found providers: {list(providers.keys())}") + return providers + +def safe_run_command(command: List[str], retry: bool = True) -> Tuple[bool, str, str]: + """Safely run a command with retries.""" + cmd_str = " ".join(command) + logger.info(f"Executing command: {cmd_str}") + + for attempt in range(MAX_RETRIES if retry else 1): + try: + logger.debug(f"Attempt {attempt + 1}/{MAX_RETRIES if retry else 1}") + result = run(command, capture_output=True, text=True) + if result.returncode == 0: + logger.debug("Command executed successfully") + return True, result.stdout, "" + if attempt == MAX_RETRIES - 1 or not retry: + logger.error(f"Command failed with return code {result.returncode}: {result.stderr}") + return False, "", result.stderr + except Exception as e: + if attempt == MAX_RETRIES - 1 or not retry: + logger.error(f"Command execution failed: {str(e)}") + return False, "", str(e) + logger.debug(f"Retrying in {RETRY_DELAY} seconds...") + time.sleep(RETRY_DELAY) + logger.error("Max retries exceeded") + return False, "", "Max retries exceeded" + +def fetch_models_once() -> Dict[str, List[str]]: + """Fetch models once and cache the results.""" + logger.info("Fetching models") + current_time = time.time() + cache_timeout = 300 # 5 minutes + + if (st.session_state.cached_models is not None and + current_time - st.session_state.last_model_fetch < cache_timeout): + logger.debug("Using cached models") + return st.session_state.cached_models + + logger.debug("Cache expired or not available, fetching new models") + success, stdout, stderr = safe_run_command(["fabric", "--listmodels"]) + if not success: + logger.error(f"Failed to fetch models: {stderr}") + st.error(f"Failed to fetch models: {stderr}") + return {} + + providers = parse_models_output(stdout) + logger.info(f"Found {len(providers)} providers") + st.session_state.cached_models = providers + st.session_state.last_model_fetch = current_time + return providers + +def get_configured_providers() -> Dict[str, List[str]]: + """Get list of configured providers using fabric --listmodels.""" + return fetch_models_once() + +def update_provider_selection(new_provider: str) -> None: + """Update provider and reset related states.""" + logger.info(f"Updating provider selection to: {new_provider}") + if new_provider != st.session_state.config["vendor"]: + logger.debug("Provider changed, resetting model selection") + st.session_state.config["vendor"] = new_provider + st.session_state.selected_vendor = new_provider + st.session_state.config["model"] = None + st.session_state.selected_model = None + st.session_state.available_models = [] + if "model_select" in st.session_state: + del st.session_state.model_select + logger.debug("Model state reset completed") + +def load_configuration() -> bool: + """Load environment variables and initialize configuration.""" + logger.info("Loading configuration") + try: + env_path = os.path.expanduser("~/.config/fabric/.env") + logger.debug(f"Looking for .env file at: {env_path}") + + if not os.path.exists(env_path): + logger.error(f"Configuration file not found at {env_path}") + st.error(f"Configuration file not found at {env_path}") + return False + + load_dotenv(dotenv_path=env_path) + logger.debug("Environment variables loaded") + + with st.spinner("Loading providers and models..."): + providers = get_configured_providers() + + if not providers: + logger.error("No providers configured") + st.error("No providers configured. Please run 'fabric --setup' first.") + return False + + default_vendor = os.getenv("DEFAULT_VENDOR") + default_model = os.getenv("DEFAULT_MODEL") + context_length = os.getenv("DEFAULT_MODEL_CONTEXT_LENGTH", "2048") + + logger.debug(f"Default configuration - Vendor: {default_vendor}, Model: {default_model}") + + if not default_vendor or default_vendor not in providers: + default_vendor = next(iter(providers)) + default_model = providers[default_vendor][0] if providers[default_vendor] else None + logger.info(f"Using fallback configuration - Vendor: {default_vendor}, Model: {default_model}") + + st.session_state.config = { + "vendor": default_vendor, + "model": default_model, + "context_length": context_length + } + st.session_state.vendors = providers + st.session_state.config_loaded = True + + logger.info("Configuration loaded successfully") + return True + + except Exception as e: + logger.error(f"Configuration error: {str(e)}", exc_info=True) + st.error(f"Configuration error: {str(e)}") + return False + +def load_models_and_providers() -> None: + """Load models and providers from fabric configuration.""" + try: + st.sidebar.header("Model and Provider Selection") + + providers: Dict[str, List[str]] = fetch_models_once() + + if not providers: + st.sidebar.error("No providers configured") + return + + current_vendor = st.session_state.config.get("vendor", "") + available_providers = list(providers.keys()) + + try: + provider_index = available_providers.index(current_vendor) if current_vendor in available_providers else 0 + except ValueError: + provider_index = 0 + logger.warning(f"Current vendor {current_vendor} not found in available providers") + + selected_provider = st.sidebar.selectbox( + "Provider", + available_providers, + index=provider_index, + key="provider_select", + on_change=lambda: update_provider_selection(st.session_state.provider_select) + ) + + if selected_provider != st.session_state.config.get("vendor"): + update_provider_selection(selected_provider) + st.sidebar.success(f"Using {selected_provider}") + + available_models = providers.get(selected_provider, []) + if not available_models: + st.sidebar.warning(f"No models available for {selected_provider}") + return + + current_model = st.session_state.config.get("model") + try: + model_index = available_models.index(current_model) if current_model in available_models else 0 + except ValueError: + model_index = 0 + logger.warning(f"Current model {current_model} not found in available models for {selected_provider}") + + model_key = f"model_select_{selected_provider}" + selected_model = st.sidebar.selectbox( + "Model", + available_models, + index=model_index, + key=model_key + ) + + if selected_model != st.session_state.config.get("model"): + logger.debug(f"Updating model selection to: {selected_model}") + st.session_state.config["model"] = selected_model + st.session_state.selected_model = selected_model + + except Exception as e: + logger.error(f"Error loading models and providers: {str(e)}", exc_info=True) + st.sidebar.error(f"Error loading models and providers: {str(e)}") + st.session_state.selected_model = None + st.session_state.config["model"] = None + +def get_pattern_metadata(pattern_name): + """Get pattern metadata from system.md.""" + pattern_path = os.path.join(pattern_dir, pattern_name, "system.md") + if os.path.exists(pattern_path): + with open(pattern_path, "r") as f: + return f.read() + return None + +def get_patterns(): + """Get the list of available patterns from the specified directory.""" + if not os.path.exists(pattern_dir): + st.error(f"Pattern directory not found: {pattern_dir}") + return [] + try: + patterns = [item for item in os.listdir(pattern_dir) + if os.path.isdir(os.path.join(pattern_dir, item))] + return patterns + except PermissionError: + st.error(f"Permission error accessing pattern directory: {pattern_dir}") + return [] + except Exception as e: + st.error(f"An unexpected error occurred: {e}") + return [] + +def create_pattern(pattern_name: str, content: Optional[str] = None) -> Tuple[bool, str]: + """Create a new pattern with necessary files and structure.""" + new_pattern_path = None + try: + # Validate pattern name + if not pattern_name: + logger.error("Pattern name cannot be empty") + return False, "Pattern name cannot be empty." + + # Check if pattern already exists + new_pattern_path = os.path.join(pattern_dir, pattern_name) + if os.path.exists(new_pattern_path): + logger.error(f"Pattern {pattern_name} already exists") + return False, "Pattern already exists." + + # Create pattern directory + os.makedirs(new_pattern_path) + logger.info(f"Created pattern directory: {new_pattern_path}") + + # If content is provided, use fabric create_pattern to structure it + if content: + logger.info(f"Structuring content for pattern '{pattern_name}' using Fabric") + try: + # Get current model and provider configuration + current_provider = st.session_state.config.get("vendor") + current_model = st.session_state.config.get("model") + + if not current_provider or not current_model: + raise ValueError("Please select a provider and model first.") + + # Execute fabric create_pattern with input content + cmd = ["fabric", "--pattern", "create_pattern"] + if current_provider and current_model: + cmd.extend(["--vendor", current_provider, "--model", current_model]) + + logger.debug(f"Running command: {' '.join(cmd)}") + logger.debug(f"Input content:\n{content}") + + # Execute pattern + result = run(cmd, input=content, capture_output=True, text=True, check=True) + structured_content = result.stdout.strip() + + if not structured_content: + raise ValueError("No output received from create_pattern") + + # Save the structured content to system.md + system_file = os.path.join(new_pattern_path, "system.md") + with open(system_file, "w") as f: + f.write(structured_content) + + # Validate the created pattern + is_valid, validation_message = validate_pattern(pattern_name) + if not is_valid: + raise ValueError(f"Pattern validation failed: {validation_message}") + + logger.info(f"Successfully created pattern '{pattern_name}' with structured content") + + except CalledProcessError as e: + error_msg = f"Error running create_pattern: {e.stderr}" + logger.error(error_msg) + if os.path.exists(new_pattern_path): + shutil.rmtree(new_pattern_path) + return False, error_msg + + except Exception as e: + error_msg = f"Unexpected error during content structuring: {str(e)}" + logger.error(error_msg) + if os.path.exists(new_pattern_path): + shutil.rmtree(new_pattern_path) + return False, error_msg + else: + # Create minimal template for manual editing + logger.info(f"Creating minimal template for pattern '{pattern_name}'") + system_file = os.path.join(new_pattern_path, "system.md") + with open(system_file, "w") as f: + f.write("# IDENTITY and PURPOSE\n\n# STEPS\n\n# OUTPUT INSTRUCTIONS\n") + + # Validate the created pattern + is_valid, validation_message = validate_pattern(pattern_name) + if not is_valid: + logger.warning(f"Pattern created but validation failed: {validation_message}") + + return True, f"Pattern '{pattern_name}' created successfully." + + except Exception as e: + error_msg = f"Error creating pattern: {str(e)}" + logger.error(error_msg) + # Clean up on any error + if new_pattern_path and os.path.exists(new_pattern_path): + shutil.rmtree(new_pattern_path) + return False, error_msg + +def delete_pattern(pattern_name): + """Delete an existing pattern.""" + try: + if not pattern_name: + return False, "Pattern name cannot be empty." + + pattern_path = os.path.join(pattern_dir, pattern_name) + if not os.path.exists(pattern_path): + return False, "Pattern does not exist." + + shutil.rmtree(pattern_path) + return True, f"Pattern '{pattern_name}' deleted successfully." + except Exception as e: + return False, f"Error deleting pattern: {str(e)}" + +def pattern_creation_wizard(): + """Multi-step wizard for creating a new pattern.""" + st.header("Create New Pattern") + + pattern_name = st.text_input("Pattern Name") + if pattern_name: + edit_mode = st.radio( + "Edit Mode", + ["Simple Editor", "Advanced (Wizard)"], + key="pattern_creation_edit_mode", + horizontal=True + ) + + if edit_mode == "Simple Editor": + new_content = st.text_area("Enter Pattern Content", height=400) + + if st.button("Create Pattern", type="primary"): + success, message = create_pattern(pattern_name, new_content) + if success: + st.success(message) + st.experimental_rerun() + else: + st.error(message) + + else: + sections = ["IDENTITY", "GOAL", "OUTPUT", "OUTPUT INSTRUCTIONS"] + current_section = st.radio( + "Edit Section", + sections, + key="pattern_creation_section_select" + ) + + if current_section == "IDENTITY": + identity = st.text_area("Define the IDENTITY", height=200) + st.session_state.new_pattern_identity = identity + + elif current_section == "GOAL": + goal = st.text_area("Define the GOAL", height=200) + st.session_state.new_pattern_goal = goal + + elif current_section == "OUTPUT": + output = st.text_area("Define the OUTPUT", height=200) + st.session_state.new_pattern_output = output + + elif current_section == "OUTPUT INSTRUCTIONS": + instructions = st.text_area("Define the OUTPUT INSTRUCTIONS", height=200) + st.session_state.new_pattern_instructions = instructions + + pattern_content = f"""# IDENTITY +{st.session_state.get('new_pattern_identity', '')} + +# GOAL +{st.session_state.get('new_pattern_goal', '')} + +# OUTPUT +{st.session_state.get('new_pattern_output', '')} + +# OUTPUT INSTRUCTIONS +{st.session_state.get('new_pattern_instructions', '')}""" + + if st.button("Create Pattern", type="primary"): + success, message = create_pattern(pattern_name, pattern_content) + if success: + st.success(message) + for key in ["new_pattern_identity", "new_pattern_goal", "new_pattern_output", "new_pattern_instructions"]: + if key in st.session_state: + del st.session_state[key] + st.experimental_rerun() + else: + st.error(message) + else: + st.info("Enter a pattern name to create a new pattern") + +def bulk_edit_patterns(patterns_to_edit, field_to_update, new_value): + """Perform bulk edits on multiple patterns.""" + results = [] + for pattern in patterns_to_edit: + try: + pattern_path = os.path.join(pattern_dir, pattern) + system_file = os.path.join(pattern_path, "system.md") + + if not os.path.exists(system_file): + results.append((pattern, False, "system.md not found")) + continue + + with open(system_file, "r") as f: + content = f.read() + + if field_to_update == "purpose": + sections = content.split("#") + updated_sections = [] + for section in sections: + if section.strip().startswith("IDENTITY and PURPOSE"): + lines = section.split("\n") + for i, line in enumerate(lines): + if "You are an AI assistant designed to" in line: + lines[i] = f"You are an AI assistant designed to {new_value}." + updated_sections.append("\n".join(lines)) + else: + updated_sections.append(section) + + new_content = "#".join(updated_sections) + with open(system_file, "w") as f: + f.write(new_content) + results.append((pattern, True, "Updated successfully")) + else: + results.append((pattern, False, f"Field {field_to_update} not supported for bulk edit")) + + except Exception as e: + results.append((pattern, False, str(e))) + + return results + +def pattern_creation_ui(): + """UI component for creating patterns with simple and wizard modes.""" + pattern_name = st.text_input("Pattern Name") + if not pattern_name: + st.info("Enter a pattern name to create a new pattern") + return + + system_content = """# IDENTITY and PURPOSE + +You are an AI assistant designed to {purpose}. + +# STEPS + +- Step 1 +- Step 2 +- Step 3 + +# OUTPUT INSTRUCTIONS + +- Output format instructions here +""" + new_content = st.text_area("Edit Pattern Content", system_content, height=400) + + if st.button("Create Pattern", type="primary"): + if not pattern_name: + st.error("Pattern name cannot be empty.") + else: + success, message = create_pattern(pattern_name) + if success: + system_file = os.path.join(pattern_dir, pattern_name, "system.md") + with open(system_file, "w") as f: + f.write(new_content) + st.success(f"Pattern '{pattern_name}' created successfully!") + st.experimental_rerun() + else: + st.error(message) + +def pattern_management_ui(): + """UI component for pattern management.""" + st.sidebar.title("Pattern Management") + +def save_output_log(pattern_name: str, input_content: str, output_content: str, timestamp: str): + """Save pattern execution log.""" + log_entry = { + "timestamp": timestamp, + "pattern_name": pattern_name, + "input": input_content, + "output": output_content, + "is_starred": False, + "custom_name": "" + } + st.session_state.output_logs.append(log_entry) + # Save outputs after each new log entry + save_outputs() + +def star_output(log_index: int, custom_name: str = "") -> bool: + """Star/favorite an output log. + + Args: + log_index: Index of the output log to star + custom_name: Optional custom name for the starred output + + Returns: + bool: True if output was starred successfully, False otherwise + """ + try: + if 0 <= log_index < len(st.session_state.output_logs): + log_entry = st.session_state.output_logs[log_index].copy() + log_entry["is_starred"] = True + log_entry["custom_name"] = custom_name or f"Starred Output #{len(st.session_state.starred_outputs) + 1}" + + # Check if this output is already starred (by timestamp) + if not any(s["timestamp"] == log_entry["timestamp"] for s in st.session_state.starred_outputs): + st.session_state.starred_outputs.append(log_entry) + save_outputs() # Save after starring + return True + + return False + except Exception as e: + logger.error(f"Error starring output: {str(e)}") + return False + +def unstar_output(log_index: int): + """Remove an output from starred/favorites.""" + if 0 <= log_index < len(st.session_state.starred_outputs): + st.session_state.starred_outputs.pop(log_index) + # Save outputs after unstarring + save_outputs() + +def validate_input_content(input_text: str) -> Tuple[bool, str]: + """Validate input content for potentially problematic characters or patterns. + + Args: + input_text: The input text to validate + + Returns: + Tuple[bool, str]: (is_valid, error_message) + """ + if not input_text or input_text.isspace(): + return False, "Input content cannot be empty or only whitespace." + + # Check for minimum length + if len(input_text.strip()) < 2: + return False, "Input content must be at least 2 characters long." + + # Check for maximum length (e.g., 100KB) + if len(input_text.encode('utf-8')) > 100 * 1024: + return False, "Input content exceeds maximum size of 100KB." + + # Check for high concentration of special characters + special_chars = set('!@#$%^&*()_+[]{}|\\;:\'",.<>?`~') + special_char_count = sum(1 for c in input_text if c in special_chars) + special_char_ratio = special_char_count / len(input_text) + + if special_char_ratio > 0.3: # More than 30% special characters + return False, "Input contains too many special characters. Please check your input." + + # Check for control characters + control_chars = set(chr(i) for i in range(32) if i not in [9, 10, 13]) # Allow tab, newline, carriage return + if any(c in control_chars for c in input_text): + return False, "Input contains invalid control characters." + + # Check for proper UTF-8 encoding + try: + input_text.encode('utf-8').decode('utf-8') + except UnicodeError: + return False, "Input contains invalid Unicode characters." + + return True, "" + +def sanitize_input_content(input_text: str) -> str: + """Sanitize input content by removing or replacing problematic characters. + + Args: + input_text: The input text to sanitize + + Returns: + str: Sanitized input text + """ + # Remove null bytes + text = input_text.replace('\0', '') + + # Replace control characters with spaces (except newlines and tabs) + allowed_chars = {'\n', '\t', '\r'} + sanitized_chars = [] + for c in text: + if c in allowed_chars or ord(c) >= 32: + sanitized_chars.append(c) + else: + sanitized_chars.append(' ') + + # Join characters and normalize whitespace + text = ''.join(sanitized_chars) + text = ' '.join(text.split()) + + return text + +def execute_patterns(patterns_to_run: List[str], chain_mode: bool = False, initial_input: Optional[str] = None) -> List[str]: + """Execute the selected patterns and capture their outputs.""" + logger.info(f"Executing {len(patterns_to_run)} patterns") + + st.session_state.chat_output = [] + all_outputs = [] + current_input = initial_input or st.session_state.input_content + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # Validate configuration + current_provider = st.session_state.config.get("vendor") + current_model = st.session_state.config.get("model") + + if not current_provider or not current_model: + error_msg = "Please select a provider and model first." + logger.error(error_msg) + st.error(error_msg) + return all_outputs + + # Validate input content + is_valid, error_message = validate_input_content(current_input) + if not is_valid: + logger.error(f"Input validation failed: {error_message}") + st.error(f"Input validation failed: {error_message}") + return all_outputs + + # Sanitize input content + try: + sanitized_input = sanitize_input_content(current_input) + if sanitized_input != current_input: + logger.info("Input content was sanitized") + st.warning("Input content was automatically sanitized for better compatibility.") + + current_input = sanitized_input + except Exception as e: + logger.error(f"Error sanitizing input: {str(e)}") + st.error(f"Error processing input: {str(e)}") + return all_outputs + + execution_info = f"**Using Model:** {current_provider} - {current_model}" + all_outputs.append(execution_info) + logger.info(f"Using model: {current_model} from provider: {current_provider}") + + try: + for pattern in patterns_to_run: + logger.info(f"Running pattern: {pattern}") + try: + cmd = ["fabric", "--pattern", pattern] + logger.debug(f"Executing command: {' '.join(cmd)}") + + message = current_input if chain_mode else st.session_state.input_content + logger.debug(f"Input for pattern {pattern}:\n{message}") + + # Ensure input_data is a string + input_data = str(message) + + # Run the command with text=True and string input + result = run( + cmd, + input=input_data, + capture_output=True, + text=True, + check=True + ) + + pattern_output = result.stdout.strip() + logger.debug(f"Raw output from pattern {pattern}:\n{pattern_output}") + + if pattern_output: + # Format output as markdown + output_msg = f"""### {pattern} + +{pattern_output}""" + all_outputs.append(output_msg) + # Save to output logs with markdown formatting + save_output_log(pattern, message, pattern_output, timestamp) + if chain_mode: + current_input = pattern_output + else: + logger.warning(f"Pattern {pattern} generated no output") + all_outputs.append(f"### {pattern}\n\nNo output generated.") + + except UnicodeEncodeError as e: + error_msg = f"### {pattern}\n\n❌ Error: Input contains invalid characters: {str(e)}" + logger.error(f"Unicode encoding error for pattern {pattern}: {str(e)}") + all_outputs.append(error_msg) + if chain_mode: + break + + except CalledProcessError as e: + error_msg = f"### {pattern}\n\n❌ Error executing: {e.stderr.strip()}" + logger.error(f"Pattern {pattern} failed: {e.stderr.strip()}") + all_outputs.append(error_msg) + if chain_mode: + break + + except Exception as e: + error_msg = f"### {pattern}\n\n❌ Failed to execute: {str(e)}" + logger.error(f"Pattern {pattern} failed: {str(e)}", exc_info=True) + all_outputs.append(error_msg) + if chain_mode: + break + + except Exception as e: + error_msg = f"### Error\n\n❌ Error in pattern execution: {str(e)}" + logger.error(error_msg, exc_info=True) + st.error(error_msg) + + logger.info("Pattern execution completed") + return all_outputs + +def validate_pattern(pattern_name): + """Validate a pattern's structure and content.""" + try: + pattern_path = os.path.join(pattern_dir, pattern_name) + + if not os.path.exists(os.path.join(pattern_path, "system.md")): + return False, f"Missing required file: system.md." + + with open(os.path.join(pattern_path, "system.md")) as f: + content = f.read() + required_sections = [ + "# IDENTITY", + "# STEPS", + "# OUTPUT" + ] + missing_sections = [] + for section in required_sections: + if section.lower() not in content.lower(): + missing_sections.append(section) + + if missing_sections: + return True, f"Warning: Missing sections in system.md: {', '.join(missing_sections)}" + + return True, "Pattern is valid." + except Exception as e: + return False, f"Error validating pattern: {str(e)}" + +def pattern_editor(pattern_name): + """Edit pattern content with simple and advanced editing options.""" + if not pattern_name: + return + + pattern_path = os.path.join(pattern_dir, pattern_name) + system_file = os.path.join(pattern_path, "system.md") + user_file = os.path.join(pattern_path, "user.md") + + st.markdown(f"### Editing Pattern: {pattern_name}") + is_valid, message = validate_pattern(pattern_name) + if not is_valid: + st.error(message) + elif message != "Pattern is valid.": + st.warning(message) + else: + st.success("Pattern structure is valid") + + edit_mode = st.radio( + "Edit Mode", + ["Simple Editor", "Advanced (Wizard)"], + key=f"edit_mode_{pattern_name}", + horizontal=True + ) + + if edit_mode == "Simple Editor": + if os.path.exists(system_file): + with open(system_file) as f: + content = f.read() + new_content = st.text_area("Edit system.md", content, height=600) + if st.button("Save system.md"): + with open(system_file, "w") as f: + f.write(new_content) + st.success("Saved successfully!") + else: + st.error("system.md file not found") + + if os.path.exists(user_file): + with open(user_file) as f: + content = f.read() + new_content = st.text_area("Edit user.md", content, height=300) + if st.button("Save user.md"): + with open(user_file, "w") as f: + f.write(new_content) + st.success("Saved successfully!") + + else: + if os.path.exists(system_file): + with open(system_file) as f: + content = f.read() + + sections = content.split("#") + edited_sections = [] + + for section in sections: + if not section.strip(): + continue + + lines = section.strip().split("\n", 1) + if len(lines) > 1: + title, content = lines + else: + title, content = lines[0], "" + + st.markdown(f"#### {title}") + new_content = st.text_area( + f"Edit {title} section", + value=content.strip(), + height=200, + key=f"section_{title}" + ) + edited_sections.append(f"# {title}\n\n{new_content}") + + if st.button("Save Changes"): + new_content = "\n\n".join(edited_sections) + with open(system_file, "w") as f: + f.write(new_content) + st.success("Changes saved successfully!") + + is_valid, message = validate_pattern(pattern_name) + if not is_valid: + st.error(message) + elif message != "Pattern is valid.": + st.warning(message) + else: + st.error("system.md file not found") + +def get_outputs_dir() -> str: + """Get the directory for storing outputs.""" + outputs_dir = os.path.expanduser("~/.config/fabric/outputs") + os.makedirs(outputs_dir, exist_ok=True) + return outputs_dir + +def save_outputs(): + """Save pattern outputs and starred outputs to files. + + Error handling: + - Creates output directory if it doesn't exist + - Handles file write permissions + - Handles JSON serialization errors + - Logs all errors for debugging + """ + logger.info("Saving outputs to persistent storage") + outputs_dir = get_outputs_dir() + + output_logs_file = os.path.join(outputs_dir, "output_logs.json") + starred_outputs_file = os.path.join(outputs_dir, "starred_outputs.json") + + try: + # Save output logs + with open(output_logs_file, "w") as f: + json.dump(st.session_state.output_logs, f, indent=2) + logger.debug(f"Saved output logs to {output_logs_file}") + + # Save starred outputs + with open(starred_outputs_file, "w") as f: + json.dump(st.session_state.starred_outputs, f, indent=2) + logger.debug(f"Saved starred outputs to {starred_outputs_file}") + + except PermissionError as e: + error_msg = f"Permission denied when saving outputs: {str(e)}" + logger.error(error_msg) + st.error(error_msg) + except json.JSONEncodeError as e: + error_msg = f"Error encoding outputs to JSON: {str(e)}" + logger.error(error_msg) + st.error(error_msg) + except Exception as e: + error_msg = f"Unexpected error saving outputs: {str(e)}" + logger.error(error_msg) + st.error(error_msg) + +def load_saved_outputs(): + """Load saved pattern outputs from files. + + Error handling: + - Handles missing output files + - Handles corrupted JSON files + - Handles file read permissions + - Initializes empty state if files don't exist + """ + logger.info("Loading saved outputs") + outputs_dir = get_outputs_dir() + output_logs_file = os.path.join(outputs_dir, "output_logs.json") + starred_outputs_file = os.path.join(outputs_dir, "starred_outputs.json") + + try: + # Load output logs + if os.path.exists(output_logs_file): + with open(output_logs_file, "r") as f: + st.session_state.output_logs = json.load(f) + logger.debug(f"Loaded output logs from {output_logs_file}") + + # Load starred outputs + if os.path.exists(starred_outputs_file): + with open(starred_outputs_file, "r") as f: + st.session_state.starred_outputs = json.load(f) + logger.debug(f"Loaded starred outputs from {starred_outputs_file}") + + except json.JSONDecodeError as e: + error_msg = f"Error decoding saved outputs (corrupted files): {str(e)}" + logger.error(error_msg) + st.error(error_msg) + # Initialize empty state + st.session_state.output_logs = [] + st.session_state.starred_outputs = [] + except PermissionError as e: + error_msg = f"Permission denied when loading outputs: {str(e)}" + logger.error(error_msg) + st.error(error_msg) + except Exception as e: + error_msg = f"Unexpected error loading saved outputs: {str(e)}" + logger.error(error_msg) + st.error(error_msg) + # Initialize empty state + st.session_state.output_logs = [] + st.session_state.starred_outputs = [] + +def handle_star_name_input(log_index: int, name: str): + """Handle the starring process when a name is input. + + Args: + log_index: Index of the output to star + name: Name to give the starred output + """ + try: + if star_output(log_index, name): + st.success("Output starred successfully!") + else: + st.error("Failed to star output. Please try again.") + except Exception as e: + logger.error(f"Error handling star name input: {str(e)}") + st.error(f"Error starring output: {str(e)}") + +def execute_pattern_chain(patterns_sequence: List[str], initial_input: str) -> Dict: + """Execute a sequence of patterns in a chain, passing output from each to the next. + + Args: + patterns_sequence: List of pattern names to execute in sequence + initial_input: Initial input text to start the chain + + Returns: + Dict containing results from each stage of the chain + """ + logger.info(f"Starting pattern chain execution with {len(patterns_sequence)} patterns") + chain_results = { + "sequence": patterns_sequence, + "stages": [], + "final_output": None, + "metadata": { + "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + "success": False + } + } + + current_input = initial_input + + try: + for i, pattern in enumerate(patterns_sequence, 1): + logger.info(f"Chain Stage {i}: Executing pattern '{pattern}'") + stage_result = { + "pattern": pattern, + "input": current_input, + "output": None, + "success": False, + "error": None + } + + try: + cmd = ["fabric", "--pattern", pattern] + result = run(cmd, input=current_input, capture_output=True, text=True, check=True) + output = result.stdout.strip() + + if output: + stage_result["output"] = output + stage_result["success"] = True + current_input = output # Use this output as input for next pattern + logger.debug(f"Stage {i} completed successfully") + else: + stage_result["error"] = "Pattern generated no output" + logger.warning(f"Pattern {pattern} generated no output") + + except CalledProcessError as e: + error_msg = f"Error executing pattern: {e.stderr.strip()}" + stage_result["error"] = error_msg + logger.error(error_msg) + break + + except Exception as e: + error_msg = f"Unexpected error: {str(e)}" + stage_result["error"] = error_msg + logger.error(error_msg) + break + + chain_results["stages"].append(stage_result) + + # Save stage output to logs + save_output_log( + pattern, + stage_result["input"], + stage_result["output"] or stage_result["error"], + chain_results["metadata"]["timestamp"] + ) + + # Set final output and success status + successful_stages = [s for s in chain_results["stages"] if s["success"]] + if successful_stages: + chain_results["final_output"] = successful_stages[-1]["output"] + chain_results["metadata"]["success"] = True + + except Exception as e: + logger.error(f"Chain execution failed: {str(e)}", exc_info=True) + chain_results["metadata"]["error"] = str(e) + + return chain_results + +def enhance_input_preview(): + """Display a preview of the input content with basic statistics. + + Shows: + - Input text preview + - Character count + - Word count + """ + if 'input_content' in st.session_state and st.session_state.input_content: + with st.expander("Input Preview", expanded=True): + st.markdown("### Current Input") + st.code(st.session_state.input_content, language="text") + + # Basic statistics + char_count = len(st.session_state.input_content) + word_count = len(st.session_state.input_content.split()) + + col1, col2 = st.columns(2) + with col1: + st.metric("Characters", char_count) + with col2: + st.metric("Words", word_count) + +def get_clipboard_content() -> Tuple[bool, str, str]: + """Get content from clipboard with proper error handling. + + Returns: + Tuple[bool, str, str]: (success, content, error_message) + """ + try: + result = run( + ["xclip", "-selection", "clipboard", "-o"], + capture_output=True, + text=True, + check=True + ) + content = result.stdout + # Validate the content is proper UTF-8 + try: + content.encode('utf-8').decode('utf-8') + return True, content, "" + except UnicodeError: + return False, "", "Clipboard contains invalid Unicode characters" + except FileNotFoundError: + return False, "", "xclip is not installed. Please install it with: sudo apt-get install xclip" + except CalledProcessError as e: + return False, "", f"Failed to read clipboard: {e.stderr}" + except Exception as e: + return False, "", f"Unexpected error reading clipboard: {str(e)}" + +def set_clipboard_content(content: str) -> Tuple[bool, str]: + """Set content to clipboard with proper error handling. + + Args: + content: The content to copy to clipboard + + Returns: + Tuple[bool, str]: (success, error_message) + """ + try: + # Validate content is proper UTF-8 before attempting to copy + try: + input_bytes = content.encode('utf-8') + except UnicodeError: + return False, "Content contains invalid Unicode characters" + + run( + ["xclip", "-selection", "clipboard"], + input=input_bytes, + check=True + ) + return True, "" + except FileNotFoundError: + return False, "xclip is not installed. Please install it with: sudo apt-get install xclip" + except CalledProcessError as e: + return False, f"Failed to copy to clipboard: {e.stderr}" + except Exception as e: + return False, f"Unexpected error copying to clipboard: {str(e)}" + +def main(): + """Main function to run the Streamlit app.""" + logger.info("Starting Fabric Pattern Studio") + try: + # Set page config + st.set_page_config( + page_title="Fabric Pattern Studio", + page_icon="🧬", + layout="wide", + initial_sidebar_state="expanded" + ) + + # Add title with gradient styling and footer signature + st.markdown(""" + +
+

Pattern Studio

+
+
+
+
+ made by zo6 + """, unsafe_allow_html=True) + + initialize_session_state() + + if not st.session_state.config_loaded: + logger.info("Loading initial configuration") + success = load_configuration() + if not success: + logger.error("Failed to load configuration") + st.error("Failed to load configuration. Please check your .env file.") + st.stop() + + with st.sidebar: + # Add GitHub link + st.markdown(""" +
+ + GitHub Repo + +
+ """, + unsafe_allow_html=True + ) + + st.title("Configuration") + load_models_and_providers() + + st.markdown("---") + st.title("Navigation") + view = st.radio( + "Select View", + ["Run Patterns", "Pattern Management", "Analysis Dashboard"], + key="view_selector" + ) + logger.debug(f"Selected view: {view}") + + if view != st.session_state.get("current_view"): + st.session_state["current_view"] = view + + if view == "Run Patterns": + patterns = get_patterns() + logger.debug(f"Available patterns: {patterns}") + + if not patterns: + logger.warning("No patterns available") + st.warning("No patterns available. Create a pattern first.") + return + + tabs = st.tabs(["Run", "Analysis"]) + + with tabs[0]: + st.header("Run Patterns") + selected_patterns = st.multiselect( + "Select Patterns to Run", + patterns, + default=st.session_state.selected_patterns, + key="selected_patterns_widget" + ) + st.session_state.selected_patterns = selected_patterns + + if selected_patterns: + for pattern in selected_patterns: + with st.expander(f"📝 {pattern} Details", expanded=False): + metadata = get_pattern_metadata(pattern) + if metadata: + st.markdown(metadata) + else: + st.info("No description available") + + st.subheader("Input") + input_method = st.radio( + "Input Method", + ["Clipboard", "Manual Input"], + horizontal=True + ) + + if input_method == "Clipboard": + col_load, col_preview = st.columns([2, 1]) + with col_load: + if st.button("📋 Load from Clipboard", use_container_width=True): + success, content, error = get_clipboard_content() + if success: + # Validate clipboard content + is_valid, error_message = validate_input_content(content) + if not is_valid: + st.error(f"Invalid clipboard content: {error_message}") + else: + # Sanitize clipboard content + sanitized_content = sanitize_input_content(content) + if sanitized_content != content: + st.warning("Clipboard content was automatically sanitized for better compatibility.") + + st.session_state.input_content = sanitized_content + st.session_state.show_preview = True + st.success("Content loaded from clipboard!") + else: + st.error(error) + + with col_preview: + if st.button("👁 Toggle Preview", use_container_width=True): + st.session_state.show_preview = not st.session_state.get('show_preview', False) + else: + st.session_state.input_content = st.text_area( + "Enter Input Text", + value=st.session_state.get('input_content', ''), + height=200 + ) + + if st.session_state.get('show_preview', False) or input_method == "Manual Input": + if st.session_state.get('input_content'): + enhance_input_preview() + + # Move chain mode checkbox before the run button + chain_mode = st.checkbox( + "Chain Mode", + help="Execute patterns in sequence, passing output of each pattern as input to the next" + ) + + if chain_mode and len(selected_patterns) > 1: + st.info("Patterns will be executed in the order selected above") + st.markdown("##### Drag to reorder patterns:") + # Convert patterns list to DataFrame for data editor + patterns_df = pd.DataFrame({ + "Pattern": selected_patterns + }) + + edited_df = st.data_editor( + patterns_df, + use_container_width=True, + key="pattern_reorder", + hide_index=True, + column_config={ + "Pattern": st.column_config.TextColumn( + "Pattern", + help="Drag to reorder patterns" + ) + } + ) + + # Update selected patterns if order changed + new_patterns = edited_df["Pattern"].tolist() + if new_patterns != selected_patterns: + st.session_state.selected_patterns = new_patterns + + col1, col2 = st.columns([3, 1]) + with col1: + if st.button("🚀 Run Patterns", type="primary", use_container_width=True): + if not st.session_state.input_content: + st.warning("Please provide input content.") + else: + with st.spinner("Running patterns..."): + if chain_mode: + # Execute pattern chain + chain_results = execute_pattern_chain( + selected_patterns, + st.session_state.input_content + ) + + # Display chain results + st.markdown("## Chain Execution Results") + + # Show sequence + st.markdown("### Pattern Sequence") + st.code(" → ".join(chain_results["sequence"])) + + # Show each stage + st.markdown("### Execution Stages") + for i, stage in enumerate(chain_results["stages"], 1): + with st.expander(f"Stage {i}: {stage['pattern']}", expanded=False): + st.markdown("#### Input") + st.code(stage["input"]) + st.markdown("#### Output") + if stage["success"]: + st.markdown(stage["output"]) + else: + st.error(stage["error"]) + + # Show final output + if chain_results["metadata"]["success"]: + st.markdown("### Final Output") + st.markdown(chain_results["final_output"]) + st.session_state.chat_output.append(chain_results["final_output"]) + else: + st.error("Chain execution failed. Check the stages above for details.") + else: + # Normal pattern execution + outputs = execute_patterns(selected_patterns) + st.session_state.chat_output.extend(outputs) + + # Display outputs after execution + if st.session_state.chat_output: + st.markdown("---") + st.header("Pattern Outputs") + for message in st.session_state.chat_output: + st.markdown(message) + st.markdown("---") # Add separator between outputs + + # Output Actions + col1, col2 = st.columns(2) + with col1: + if st.button("📋 Copy All Outputs"): + all_outputs = "\n\n".join(st.session_state.chat_output) + success, error = set_clipboard_content(all_outputs) + if success: + st.success("All outputs copied to clipboard!") + else: + st.error(error) + + with col2: + if st.button("❌ Clear Outputs"): + st.session_state.chat_output = [] + st.success("Outputs cleared!") + st.experimental_rerun() + + with col2: + st.write("") # Empty space for layout balance + + else: + st.info("Select one or more patterns to run.") + + with tabs[1]: + st.header("Output Analysis") + if st.session_state.chat_output: + # Display pattern outputs in chronological order + for i, output in enumerate(reversed(st.session_state.chat_output), 1): + with st.expander(f"Output #{i}", expanded=False): + st.markdown(output) + else: + st.info("Run some patterns to see output analysis.") + + elif view == "Pattern Management": + create_tab, edit_tab, delete_tab = st.tabs(["Create", "Edit", "Delete"]) + + with create_tab: + st.header("Create New Pattern") + creation_mode = st.radio( + "Creation Mode", + ["Simple Editor", "Advanced (Wizard)"], + key="creation_mode_main", + horizontal=True + ) + + if creation_mode == "Simple Editor": + pattern_creation_ui() + else: + pattern_creation_wizard() + + with edit_tab: + st.header("Edit Patterns") + patterns = get_patterns() + if not patterns: + st.warning("No patterns available. Create a pattern first.") + else: + selected_pattern = st.selectbox("Select Pattern to Edit", [""] + patterns) + if selected_pattern: + pattern_editor(selected_pattern) + + with delete_tab: + st.header("Delete Patterns") + patterns = get_patterns() + if not patterns: + st.warning("No patterns available.") + else: + patterns_to_delete = st.multiselect( + "Select Patterns to Delete", + patterns, + key="delete_patterns_selector" + ) + + if patterns_to_delete: + st.warning(f"You are about to delete {len(patterns_to_delete)} pattern(s):") + for pattern in patterns_to_delete: + st.markdown(f"- {pattern}") + + confirm_delete = st.checkbox("I understand that this action cannot be undone") + + if st.button("🗑️ Delete Selected Patterns", type="primary", disabled=not confirm_delete): + if confirm_delete: + for pattern in patterns_to_delete: + success, message = delete_pattern(pattern) + if success: + st.success(f"✓ {pattern}: {message}") + else: + st.error(f"✗ {pattern}: {message}") + st.experimental_rerun() + else: + st.error("Please confirm deletion by checking the box above.") + else: + st.info("Select one or more patterns to delete.") + + else: + st.header("Pattern Output History") + + # Create tabs for All Outputs and Starred Outputs + all_tab, starred_tab = st.tabs(["All Outputs", "⭐ Starred"]) + + with all_tab: + if not st.session_state.output_logs: + st.info("No pattern outputs recorded yet. Run some patterns to see their logs here.") + else: + for i, log in enumerate(reversed(st.session_state.output_logs)): + with st.expander( + f"Output #{len(st.session_state.output_logs)-i} - {log['pattern_name']} ({log['timestamp']})", + expanded=False + ): + st.markdown("### Input") + st.code(log["input"], language="text") + st.markdown("### Output") + st.markdown(log["output"]) + + # Check if this output is already starred + is_starred = any(s["timestamp"] == log["timestamp"] for s in st.session_state.starred_outputs) + + col1, col2 = st.columns([1, 4]) + with col1: + if not is_starred: + if st.button("⭐ Star", key=f"star_{i}", use_container_width=True): + st.session_state.starring_output = len(st.session_state.output_logs) - i - 1 + st.session_state.temp_star_name = "" + else: + st.write("⭐ Starred") + + with col2: + if st.button("📋 Copy Output", key=f"copy_{i}"): + success, error = set_clipboard_content(log["output"]) + if success: + st.success("Output copied to clipboard!") + else: + st.error(error) + + # Show starring form inside the expander if this is the output being starred + if st.session_state.starring_output == len(st.session_state.output_logs) - i - 1: + st.markdown("---") + with st.form(key=f"star_name_form_{i}"): + name_input = st.text_input( + "Enter a name for this output (optional):", + key=f"star_name_input_{i}" + ) + col1, col2 = st.columns(2) + with col1: + submit = st.form_submit_button("Save", use_container_width=True) + with col2: + cancel = st.form_submit_button("Cancel", use_container_width=True) + + if submit: + handle_star_name_input(st.session_state.starring_output, name_input) + # Reset starring state after handling + st.session_state.starring_output = None + st.experimental_rerun() + elif cancel: + # Reset starring state + st.session_state.starring_output = None + st.experimental_rerun() + + # Remove the old starring form from the bottom + st.markdown("---") + + with starred_tab: + if not st.session_state.starred_outputs: + st.info("No starred outputs yet. Star some outputs to see them here!") + else: + for i, starred in enumerate(st.session_state.starred_outputs): + with st.expander( + f"⭐ {starred.get('custom_name', f'Starred Output #{i+1}')} ({starred['timestamp']})", + expanded=False + ): + col1, col2 = st.columns([3, 1]) + with col1: + st.markdown(f"### {starred.get('custom_name', f'Starred Output #{i+1}')}") + with col2: + if st.button("✏️ Edit Name", key=f"edit_name_{i}"): + st.session_state[f"editing_name_{i}"] = True + + if st.session_state.get(f"editing_name_{i}", False): + new_name = st.text_input( + "Enter new name:", + value=starred.get('custom_name', ''), + key=f"new_name_{i}" + ) + col1, col2 = st.columns([1, 1]) + with col1: + if st.button("Save", key=f"save_name_{i}"): + st.session_state.starred_outputs[i]['custom_name'] = new_name + del st.session_state[f"editing_name_{i}"] + st.success("Name updated!") + st.experimental_rerun() + with col2: + if st.button("Cancel", key=f"cancel_name_{i}"): + del st.session_state[f"editing_name_{i}"] + st.experimental_rerun() + + st.markdown("### Pattern") + st.code(starred["pattern_name"], language="text") + st.markdown("### Input") + st.code(starred["input"], language="text") # Display input as code block + st.markdown("### Output") + st.markdown(starred["output"]) # Display output as markdown + + col1, col2 = st.columns([1, 4]) + with col1: + if st.button("❌ Remove Star", key=f"unstar_{i}"): + unstar_output(i) + st.success("Output unstarred!") + st.experimental_rerun() + + with col2: + if st.button("📋 Copy Output", key=f"copy_starred_{i}"): + try: + run(["xclip", "-selection", "clipboard"], input=starred["output"].encode(), check=True) + st.success("Output copied to clipboard!") + except Exception as e: + st.error(f"Error copying to clipboard: {e}") + + if st.button("Clear All Starred"): + if st.checkbox("Confirm clearing all starred outputs"): + st.session_state.starred_outputs = [] + save_outputs() # Save after clearing + st.success("All starred outputs cleared!") + st.experimental_rerun() + + except Exception as e: + logger.error("Unexpected error in main function", exc_info=True) + st.error(f"An unexpected error occurred: {str(e)}") + st.stop() + +if __name__ == "__main__": + logger.info("Application startup") + main() \ No newline at end of file diff --git a/version.go b/version.go index 2a1e7ae4..cad9a291 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package main -var version = "v1.4.104" +var version = "v1.4.127" diff --git a/web/.github/dependabot.yml b/web/.github/dependabot.yml new file mode 100644 index 00000000..421af9f5 --- /dev/null +++ b/web/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "npm", "pnpm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/web/.npmrc b/web/.npmrc new file mode 100644 index 00000000..e69de29b diff --git a/web/.prettierignore b/web/.prettierignore new file mode 100644 index 00000000..ab78a95d --- /dev/null +++ b/web/.prettierignore @@ -0,0 +1,4 @@ +# Package Managers +package-lock.json +pnpm-lock.yaml +yarn.lock diff --git a/web/.prettierrc b/web/.prettierrc new file mode 100644 index 00000000..95730232 --- /dev/null +++ b/web/.prettierrc @@ -0,0 +1,8 @@ +{ + "useTabs": true, + "singleQuote": true, + "trailingComma": "none", + "printWidth": 100, + "plugins": ["prettier-plugin-svelte"], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] +} diff --git a/web/.vscode/settings.json b/web/.vscode/settings.json new file mode 100644 index 00000000..e5c5673c --- /dev/null +++ b/web/.vscode/settings.json @@ -0,0 +1,120 @@ +{ + "prettier.documentSelectors": [ + "**/*.svelte" + ], + "tailwindCSS.classAttributes": [ + "class", + "accent", + "active", + "animIndeterminate", + "aspectRatio", + "background", + "badge", + "bgBackdrop", + "bgDark", + "bgDrawer", + "bgLight", + "blur", + "border", + "button", + "buttonAction", + "buttonBack", + "buttonClasses", + "buttonComplete", + "buttonDismiss", + "buttonNeutral", + "buttonNext", + "buttonPositive", + "buttonTextCancel", + "buttonTextConfirm", + "buttonTextFirst", + "buttonTextLast", + "buttonTextNext", + "buttonTextPrevious", + "buttonTextSubmit", + "caretClosed", + "caretOpen", + "chips", + "color", + "controlSeparator", + "controlVariant", + "cursor", + "display", + "element", + "fill", + "fillDark", + "fillLight", + "flex", + "flexDirection", + "gap", + "gridColumns", + "height", + "hover", + "inactive", + "indent", + "justify", + "meter", + "padding", + "position", + "regionAnchor", + "regionBackdrop", + "regionBody", + "regionCaption", + "regionCaret", + "regionCell", + "regionChildren", + "regionChipList", + "regionChipWrapper", + "regionCone", + "regionContent", + "regionControl", + "regionDefault", + "regionDrawer", + "regionFoot", + "regionFootCell", + "regionFooter", + "regionHead", + "regionHeadCell", + "regionHeader", + "regionIcon", + "regionInput", + "regionInterface", + "regionInterfaceText", + "regionLabel", + "regionLead", + "regionLegend", + "regionList", + "regionListItem", + "regionNavigation", + "regionPage", + "regionPanel", + "regionRowHeadline", + "regionRowMain", + "regionSummary", + "regionSymbol", + "regionTab", + "regionTrail", + "ring", + "rounded", + "select", + "shadow", + "slotDefault", + "slotFooter", + "slotHeader", + "slotLead", + "slotMessage", + "slotMeta", + "slotPageContent", + "slotPageFooter", + "slotPageHeader", + "slotSidebarLeft", + "slotSidebarRight", + "slotTrail", + "spacing", + "text", + "track", + "transition", + "width", + "zIndex" + ] +} \ No newline at end of file diff --git a/web/README.md b/web/README.md new file mode 100644 index 00000000..c335405d --- /dev/null +++ b/web/README.md @@ -0,0 +1,13 @@ +## The Fabric Web App +[Installing](#Installing)|[Todos](#Todos)|[Collaborators](#Collaborators) + +This is the web app for Fabric. It is built using [Svelte](https://svelte.dev/), [SkeletonUI](https://skeleton.dev/), and [Mdsvex](https://mdsvex.pngwn.io/). + +The goal of this app is to not only provide a user interface for Fabric, but also a out-of-the-box website for those who want to get started with web development or blogging. The tech stack is minimal and (I hope) the code is easy to read and understand. One thing I kept in mind when making this app was to make it easy for beginners to get started with web development. You can use this app as a GUI interface for Fabric, a ready to go blog-site, or a website template for your own projects. I hope you find it useful! + +![Preview](static/image.png) + +### Installing +It can be installed by navigating to the `web` directory and using `npm install`, `pnpm install`, or your favorite package manager. Then simply run `npm run dev` or your equivalent command to start the app. *You will need to run fabric in a seperate terminal with the `fabric --serve` command.* + + diff --git a/web/SECURITY.md b/web/SECURITY.md new file mode 100644 index 00000000..034e8480 --- /dev/null +++ b/web/SECURITY.md @@ -0,0 +1,21 @@ +# Security Policy + +## Supported Versions + +Use this section to tell people about which versions of your project are +currently being supported with security updates. + +| Version | Supported | +| ------- | ------------------ | +| 5.1.x | :white_check_mark: | +| 5.0.x | :x: | +| 4.0.x | :white_check_mark: | +| < 4.0 | :x: | + +## Reporting a Vulnerability + +Use this section to tell people how to report a vulnerability. + +Tell them where to go, how often they can expect to get an update on a +reported vulnerability, what to expect if the vulnerability is accepted or +declined, etc. diff --git a/web/STD-README.md b/web/STD-README.md new file mode 100644 index 00000000..5ce67661 --- /dev/null +++ b/web/STD-README.md @@ -0,0 +1,38 @@ +# create-svelte + +Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte). + +## Creating a project + +If you're seeing this, you've probably already done this step. Congrats! + +```bash +# create a new project in the current directory +npm create svelte@latest + +# create a new project in my-app +npm create svelte@latest my-app +``` + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: + +```bash +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of your app: + +```bash +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. diff --git a/web/eslint.config.js b/web/eslint.config.js new file mode 100644 index 00000000..39ea3935 --- /dev/null +++ b/web/eslint.config.js @@ -0,0 +1,32 @@ +import eslint from '@eslint/js'; +import prettier from 'eslint-config-prettier'; +import svelte from 'eslint-plugin-svelte'; +import globals from 'globals'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + eslint.configs.recommended, + ...tseslint.configs.recommended, + ...svelte.configs['flat/recommended'], + prettier, + ...svelte.configs['flat/prettier'], + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node + } + } + }, + { + files: ['**/*.svelte'], + languageOptions: { + parserOptions: { + parser: tseslint.parser + } + } + }, + { + ignores: ['build/', '.svelte-kit/', 'dist/'] + } +); diff --git a/web/jsconfig.json b/web/jsconfig.json new file mode 100644 index 00000000..fc93cbd9 --- /dev/null +++ b/web/jsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias + // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in +} diff --git a/web/markdown.d.ts b/web/markdown.d.ts new file mode 100644 index 00000000..4fd000de --- /dev/null +++ b/web/markdown.d.ts @@ -0,0 +1,4 @@ +/* declare module '*.md' { + const component: import('svelte').ComponentType; + export default component; + } */ \ No newline at end of file diff --git a/web/my-custom-theme.ts b/web/my-custom-theme.ts new file mode 100644 index 00000000..a2be4c46 --- /dev/null +++ b/web/my-custom-theme.ts @@ -0,0 +1,102 @@ + +import type { CustomThemeConfig } from '@skeletonlabs/tw-plugin'; + +export const myCustomTheme: CustomThemeConfig = { + name: 'my-custom-theme', + properties: { + // =~= Theme Properties =~= + "--theme-font-family-base": `system-ui`, + "--theme-font-family-heading": `system-ui`, + "--theme-font-color-base": "var(--color-primary-800)", + "--theme-font-color-dark": "var(--color-primary-300)", + "--theme-rounded-base": "9999px", + "--theme-rounded-container": "8px", + "--theme-border-base": "1px", + // =~= Theme On-X Colors =~= + "--on-primary": "0 0 0", + "--on-secondary": "0 0 0", + "--on-tertiary": "0 0 0", + "--on-success": "0 0 0", + "--on-warning": "0 0 0", + "--on-error": "0 0 0", + "--on-surface": "0 0 0", + // =~= Theme Colors =~= + // primary | #613bf7 + "--color-primary-50": "231 226 254", // #e7e2fe + "--color-primary-100": "223 216 253", // #dfd8fd + "--color-primary-200": "216 206 253", // #d8cefd + "--color-primary-300": "192 177 252", // #c0b1fc + "--color-primary-400": "144 118 249", // #9076f9 + "--color-primary-500": "97 59 247", // #613bf7 + "--color-primary-600": "87 53 222", // #5735de + "--color-primary-700": "73 44 185", // #492cb9 + "--color-primary-800": "58 35 148", // #3a2394 + "--color-primary-900": "48 29 121", // #301d79 + // secondary | #9de1ae + "--color-secondary-50": "240 251 243", // #f0fbf3 + "--color-secondary-100": "235 249 239", // #ebf9ef + "--color-secondary-200": "231 248 235", // #e7f8eb + "--color-secondary-300": "216 243 223", // #d8f3df + "--color-secondary-400": "186 234 198", // #baeac6 + "--color-secondary-500": "157 225 174", // #9de1ae + "--color-secondary-600": "141 203 157", // #8dcb9d + "--color-secondary-700": "118 169 131", // #76a983 + "--color-secondary-800": "94 135 104", // #5e8768 + "--color-secondary-900": "77 110 85", // #4d6e55 + // tertiary | #3fa0a6 + "--color-tertiary-50": "226 241 242", // #e2f1f2 + "--color-tertiary-100": "217 236 237", // #d9eced + "--color-tertiary-200": "207 231 233", // #cfe7e9 + "--color-tertiary-300": "178 217 219", // #b2d9db + "--color-tertiary-400": "121 189 193", // #79bdc1 + "--color-tertiary-500": "63 160 166", // #3fa0a6 + "--color-tertiary-600": "57 144 149", // #399095 + "--color-tertiary-700": "47 120 125", // #2f787d + "--color-tertiary-800": "38 96 100", // #266064 + "--color-tertiary-900": "31 78 81", // #1f4e51 + // success | #37b3fc + "--color-success-50": "225 244 255", // #e1f4ff + "--color-success-100": "215 240 254", // #d7f0fe + "--color-success-200": "205 236 254", // #cdecfe + "--color-success-300": "175 225 254", // #afe1fe + "--color-success-400": "115 202 253", // #73cafd + "--color-success-500": "55 179 252", // #37b3fc + "--color-success-600": "50 161 227", // #32a1e3 + "--color-success-700": "41 134 189", // #2986bd + "--color-success-800": "33 107 151", // #216b97 + "--color-success-900": "27 88 123", // #1b587b + // warning | #d209f8 + "--color-warning-50": "248 218 254", // #f8dafe + "--color-warning-100": "246 206 254", // #f6cefe + "--color-warning-200": "244 194 253", // #f4c2fd + "--color-warning-300": "237 157 252", // #ed9dfc + "--color-warning-400": "224 83 250", // #e053fa + "--color-warning-500": "210 9 248", // #d209f8 + "--color-warning-600": "189 8 223", // #bd08df + "--color-warning-700": "158 7 186", // #9e07ba + "--color-warning-800": "126 5 149", // #7e0595 + "--color-warning-900": "103 4 122", // #67047a + // error | #90df16 + "--color-error-50": "238 250 220", // #eefadc + "--color-error-100": "233 249 208", // #e9f9d0 + "--color-error-200": "227 247 197", // #e3f7c5 + "--color-error-300": "211 242 162", // #d3f2a2 + "--color-error-400": "177 233 92", // #b1e95c + "--color-error-500": "144 223 22", // #90df16 + "--color-error-600": "130 201 20", // #82c914 + "--color-error-700": "108 167 17", // #6ca711 + "--color-error-800": "86 134 13", // #56860d + "--color-error-900": "71 109 11", // #476d0b + // surface | #46a1ed + "--color-surface-50": "227 241 252", // #e3f1fc + "--color-surface-100": "218 236 251", // #daecfb + "--color-surface-200": "209 232 251", // #d1e8fb + "--color-surface-300": "181 217 248", // #b5d9f8 + "--color-surface-400": "126 189 242", // #7ebdf2 + "--color-surface-500": "70 161 237", // #46a1ed + "--color-surface-600": "63 145 213", // #3f91d5 + "--color-surface-700": "53 121 178", // #3579b2 + "--color-surface-800": "42 97 142", // #2a618e + "--color-surface-900": "34 79 116", // #224f74 + } +} \ No newline at end of file diff --git a/web/package-lock.json b/web/package-lock.json new file mode 100644 index 00000000..ee66a218 --- /dev/null +++ b/web/package-lock.json @@ -0,0 +1,7397 @@ +{ + "name": "terminal-blog", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "terminal-blog", + "version": "0.0.1", + "dependencies": { + "@floating-ui/dom": "^1.5.3", + "clsx": "^2.1.1", + "cn": "^0.1.1", + "date-fns": "^4.1.0", + "highlight.js": "^11.10.0", + "marked": "^15.0.1", + "rehype": "^13.0.2", + "rehype-autolink-headings": "^7.1.0", + "rehype-external-links": "^3.0.0", + "rehype-slug": "^6.0.0", + "rehype-unwrap-images": "^1.0.0", + "tailwind-merge": "^2.5.4", + "youtube-transcript": "^1.2.1" + }, + "devDependencies": { + "@skeletonlabs/skeleton": "^2.8.0", + "@skeletonlabs/tw-plugin": "^0.3.1", + "@sveltejs/adapter-auto": "^3.0.0", + "@sveltejs/kit": "^2.8.4", + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@tailwindcss/forms": "^0.5.7", + "@tailwindcss/typography": "^0.5.10", + "@types/node": "^20.10.0", + "autoprefixer": "^10.4.16", + "lucide-svelte": "^0.309.0", + "mdsvex": "^0.11.0", + "postcss": "^8.4.32", + "postcss-load-config": "^5.0.2", + "svelte": "^4.2.7", + "svelte-check": "^3.6.0", + "svelte-youtube-embed": "^0.3.3", + "tailwindcss": "^3.3.6", + "typescript": "^5.0.0", + "vite": "^5.0.3", + "vite-plugin-tailwind-purgecss": "^0.2.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "dev": true + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", + "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", + "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", + "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", + "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", + "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", + "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", + "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", + "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", + "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", + "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", + "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", + "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", + "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", + "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", + "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", + "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@skeletonlabs/skeleton": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@skeletonlabs/skeleton/-/skeleton-2.10.3.tgz", + "integrity": "sha512-O1RecF68zEVvZl3GgRS4emqWMUIQLHvTOFoqGOw/2OXCPE06IxUQrHQf2hnxCPxtGZNXY2YX8UNV38l+eH8GNQ==", + "dev": true, + "dependencies": { + "esm-env": "1.0.0" + }, + "peerDependencies": { + "svelte": "^3.56.0 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/@skeletonlabs/tw-plugin": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@skeletonlabs/tw-plugin/-/tw-plugin-0.3.1.tgz", + "integrity": "sha512-DjjeOHN3HhFQf6gYPT2MUZMkIdw1jeB9mbuKC8etQxUlOR4XitfC7hssRWFJ8RJsvrrN0myCBbdWkVG1JVA96g==", + "dev": true, + "peerDependencies": { + "tailwindcss": ">=3.0.0" + } + }, + "node_modules/@sveltejs/adapter-auto": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.2.5.tgz", + "integrity": "sha512-27LR+uKccZ62lgq4N/hvyU2G+hTP9fxWEAfnZcl70HnyfAjMSsGk1z/SjAPXNCD1mVJIE7IFu3TQ8cQ/UH3c0A==", + "dev": true, + "dependencies": { + "import-meta-resolve": "^4.1.0" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.0.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.8.4.tgz", + "integrity": "sha512-oDSBHPokbP2iaQlHiEWAkVLsIugsXve8YtABtlyHBUljA63Wgx0UtV8MSOQOGpRft1M+Cd5rzer+0SFlppQwOg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^0.6.0", + "devalue": "^5.1.0", + "esm-env": "^1.0.0", + "import-meta-resolve": "^4.1.0", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "sade": "^1.8.1", + "set-cookie-parser": "^2.6.0", + "sirv": "^3.0.0", + "tiny-glob": "^0.2.9" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.3" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz", + "integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==", + "dev": true, + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", + "debug": "^4.3.4", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.10", + "svelte-hmr": "^0.16.0", + "vitefu": "^0.2.5" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", + "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@tailwindcss/forms": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.9.tgz", + "integrity": "sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg==", + "dev": true, + "dependencies": { + "mini-svg-data-uri": "^1.2.3" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20" + } + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.15.tgz", + "integrity": "sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==", + "dev": true, + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/node": { + "version": "20.17.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz", + "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/pug": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz", + "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==", + "dev": true + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "license": "ISC" + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/asn1": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", + "engines": { + "node": ">=0.4.9" + } + }, + "node_modules/assert-plus": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.2.tgz", + "integrity": "sha512-BbJV8Hq6grYTokkHi/qKS34kfYIFYpu4wKd/H0dARsa6qOqEFH1wboxMwrccAmFjyRjkemjElaVC/sZSUMxHnA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==" + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/aws-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/aws-sign/-/aws-sign-0.3.0.tgz", + "integrity": "sha512-pEMJAknifcXqXqYVXzGPIu8mJvxtJxIdpVpAs8HNS+paT+9srRUDMQn+3hULS7WbLmttcmvgMvnDcFujqXJyPw==", + "engines": { + "node": "*" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boom": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", + "integrity": "sha512-OvfN8y1oAxxphzkl2SnCS+ztV/uVKTATtgLjWYg/7KwcNyf3rzpHxNQJZCKtsZd4+MteKczhWbSjtEX4bGgU9g==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dependencies": { + "hoek": "0.9.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/boom/node_modules/hoek": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001680", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", + "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/cn/-/cn-0.1.1.tgz", + "integrity": "sha512-PkWPdg4L4aQEwqqkGzMclTdHlstGzBg773gBtsUCHqXrawQ8wQHf/490Rw2hXPaoI7QXYbCgI67Jfe25TjxLGw==", + "license": "MIT", + "dependencies": { + "request": "~2.21.0", + "string": "~1.4.0" + }, + "bin": { + "cn": "bin/cn" + } + }, + "node_modules/code-red": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", + "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1", + "acorn": "^8.10.0", + "estree-walker": "^3.0.3", + "periscopic": "^3.1.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", + "dependencies": { + "delayed-stream": "0.0.5" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-jar": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/cookie-jar/-/cookie-jar-0.3.0.tgz", + "integrity": "sha512-dX1400pzPULr+ZovkIsDEqe7XH8xCAYGT5Dege4Eot44Qs2mS2iJmnh45TxTO5MIsCfrV/JGZVloLhm46AHxNw==", + "engines": { + "node": "*" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cryptiles": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", + "integrity": "sha512-gvWSbgqP+569DdslUiCelxIv3IYK5Lgmq1UrRnk+s1WxQOQ16j3GPDcjdtgL5Au65DU/xQi6q3xPtf5Kta+3IQ==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dependencies": { + "boom": "0.4.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ctype": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.2.tgz", + "integrity": "sha512-C+CbWLSk0xdPcp7evo2YEF0o8SLKcDCQsw//accyrf8/NAWYzmUhmL8ZiSokvuwwMQ08RK10U9pkRcyy8EmA5A==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", + "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", + "dev": true + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.62", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.62.tgz", + "integrity": "sha512-t8c+zLmJHa9dJy96yBZRXGQYoiCEnHYgFwn1asvSPZSUdVxnB62A4RASd7k41ytG3ErFBA0TpHlKg9D9SQBmLg==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/esm-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", + "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", + "dev": true + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forever-agent": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", + "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.0.8.tgz", + "integrity": "sha512-yzpBIhe8Ll+dYTXjd+4ORxbQktke+abD0dJjedvqsVVayMkb+PgLGatJNLwo95Va75l3YDZ01SrouzyW9bC2Fg==", + "dependencies": { + "async": "~0.2.7", + "combined-stream": "~0.0.4", + "mime": "~1.2.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globalyzer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", + "dev": true + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/hast-util-from-html/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.2.tgz", + "integrity": "sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/hast-util-has-property": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz", + "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-heading-rank": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", + "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-interactive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-interactive/-/hast-util-interactive-3.0.0.tgz", + "integrity": "sha512-9VFa3kP6AT40BNYcPmn3jpsG+1KPDF0rUFCrFVQDUsuUXZ3YLODm8UGV0tmYzFpcOIQXTAOi2ccS3ywlj2dQTA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-has-property": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.3.tgz", + "integrity": "sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/hast-util-to-string": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.0.tgz", + "integrity": "sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hawk": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-0.13.1.tgz", + "integrity": "sha512-f/1H9bruKJfgLN2KFd+666ILQvJYsJcxaCoIdHaaD2zgl7RUa08/202pGJXhOmQ1kTEdMTSxPnbCsu4l6JARhQ==", + "deprecated": "This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", + "dependencies": { + "boom": "0.4.x", + "cryptiles": "0.2.x", + "hoek": "0.8.x", + "sntp": "0.2.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/highlight.js": { + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.10.0.tgz", + "integrity": "sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/hoek": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.8.5.tgz", + "integrity": "sha512-NoKdeYUBOlQ7j9dgvT9BEX90rE6HtDkaMFwR6hfOj26LA2Mwyg5026jOpNBhmNrWIGdPnbBK3sQJI3POwh8wqg==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/http-signature": { + "version": "0.9.11", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.9.11.tgz", + "integrity": "sha512-OleF+71prrzyaWDTfTXWvv24N/45SjKCPu/3pzzhj8+MgdGaB7Am3NY0ot5uynrzgTwyQ+yoejuFCncCQxyRSA==", + "dependencies": { + "asn1": "0.1.11", + "assert-plus": "0.1.2", + "ctype": "0.5.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/json-stringify-safe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-4.0.0.tgz", + "integrity": "sha512-qzEpz1SDUb9xvA+LDOkNgjekdV7tuC7zDQf14sqMBtujh8kVbQhF11VWm4DeR99yFNjVSjTTfKa40c9ZQOtwXA==", + "license": "BSD" + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true + }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/lucide-svelte": { + "version": "0.309.0", + "resolved": "https://registry.npmjs.org/lucide-svelte/-/lucide-svelte-0.309.0.tgz", + "integrity": "sha512-+t85+5Y696FVDoJHiiMhJGalv+UiWUX46gMudOQfYrVGjsyC2MGSZRNAGAHkdykA4RJSh/wUtSgnTgCmd0Swvw==", + "dev": true, + "peerDependencies": { + "svelte": ">=3 <5" + } + }, + "node_modules/magic-string": { + "version": "0.30.12", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", + "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/marked": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.2.tgz", + "integrity": "sha512-85RUkoYKIVB21PbMKrnD6aCl9ws+XKEyhJNMbLn206NyD3jbBo7Ec7Wi4Jrsn4dV1a2ng7K/jfkmIN0DNoS41w==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, + "node_modules/mdsvex": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/mdsvex/-/mdsvex-0.11.2.tgz", + "integrity": "sha512-Y4ab+vLvTJS88196Scb/RFNaHMHVSWw6CwfsgWIQP8f42D57iDII0/qABSu530V4pkv8s6T2nx3ds0MC1VwFLA==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.3", + "prism-svelte": "^0.4.7", + "prismjs": "^1.17.1", + "vfile-message": "^2.0.4" + }, + "peerDependencies": { + "svelte": "^3.56.0 || ^4.0.0 || ^5.0.0-next.120" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.1.tgz", + "integrity": "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==" + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "dev": true, + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true + }, + "node_modules/node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==", + "deprecated": "Use uuid module instead", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", + "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, + "node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.1.0.tgz", + "integrity": "sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.1.1", + "yaml": "^2.4.2" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prism-svelte": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/prism-svelte/-/prism-svelte-0.4.7.tgz", + "integrity": "sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==", + "dev": true + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/purgecss": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-6.0.0.tgz", + "integrity": "sha512-s3EBxg5RSWmpqd0KGzNqPiaBbWDz1/As+2MzoYVGMqgDqRTLBhJW6sywfTBek7OwNfoS/6pS0xdtvChNhFj2cw==", + "dev": true, + "dependencies": { + "commander": "^12.0.0", + "glob": "^10.3.10", + "postcss": "^8.4.4", + "postcss-selector-parser": "^6.0.7" + }, + "bin": { + "purgecss": "bin/purgecss.js" + } + }, + "node_modules/purgecss/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/qs": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", + "integrity": "sha512-kN+yNdAf29Jgp+AYHUmC7X4QdJPR8czuMWLNLc0aRxkQ7tB3vJQEONKKT9ou/rW7EbqVec11srC9q9BiVbcnHA==", + "engines": { + "node": "*" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rehype": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz", + "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "rehype-parse": "^9.0.0", + "rehype-stringify": "^10.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-autolink-headings": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-7.1.0.tgz", + "integrity": "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-external-links": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", + "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-is-element": "^3.0.0", + "is-absolute-url": "^4.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-parse": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-html": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", + "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "github-slugger": "^2.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-stringify": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-unwrap-images": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-unwrap-images/-/rehype-unwrap-images-1.0.0.tgz", + "integrity": "sha512-wzW5Mk9IlVF2UwXC5NtIZsx1aHYbV8+bLWjJnlZaaamz5QU52RppWtq1uEZJqGo8d9Y4RuDqidB6r9RFpKugIg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-interactive": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/request": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.21.0.tgz", + "integrity": "sha512-jvDa6FC46ystc0cn+EqtJ4B32SSz/cMX7fEIv0UHX4wsYAKJYXjA5EyAMWpRQ+hWCnX9jPD1b4o7xZ/r1Tyx/Q==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "engines": [ + "node >= 0.8.0" + ], + "dependencies": { + "aws-sign": "~0.3.0", + "cookie-jar": "~0.3.0", + "forever-agent": "~0.5.0", + "form-data": "0.0.8", + "hawk": "~0.13.0", + "http-signature": "~0.9.11", + "json-stringify-safe": "~4.0.0", + "mime": "~1.2.9", + "node-uuid": "~1.4.0", + "oauth-sign": "~0.3.0", + "qs": "~0.6.0", + "tunnel-agent": "~0.3.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", + "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.24.0", + "@rollup/rollup-android-arm64": "4.24.0", + "@rollup/rollup-darwin-arm64": "4.24.0", + "@rollup/rollup-darwin-x64": "4.24.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", + "@rollup/rollup-linux-arm-musleabihf": "4.24.0", + "@rollup/rollup-linux-arm64-gnu": "4.24.0", + "@rollup/rollup-linux-arm64-musl": "4.24.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", + "@rollup/rollup-linux-riscv64-gnu": "4.24.0", + "@rollup/rollup-linux-s390x-gnu": "4.24.0", + "@rollup/rollup-linux-x64-gnu": "4.24.0", + "@rollup/rollup-linux-x64-musl": "4.24.0", + "@rollup/rollup-win32-arm64-msvc": "4.24.0", + "@rollup/rollup-win32-ia32-msvc": "4.24.0", + "@rollup/rollup-win32-x64-msvc": "4.24.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/sander": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", + "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", + "dev": true, + "dependencies": { + "es6-promise": "^3.1.2", + "graceful-fs": "^4.1.3", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.2" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz", + "integrity": "sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sirv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz", + "integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/sntp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", + "integrity": "sha512-bDLrKa/ywz65gCl+LmOiIhteP1bhEsAAzhfMedPoiHP3dyYnAevlaJshdqb9Yu0sRifyP/fRqSt8t+5qGIWlGQ==", + "deprecated": "This module moved to @hapi/sntp. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", + "dependencies": { + "hoek": "0.9.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/sntp/node_modules/hoek": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/sorcery": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.1.tgz", + "integrity": "sha512-o7npfeJE6wi6J9l0/5LKshFzZ2rMatRiCDwYeDQaOzqdzRJwALhX7mk/A/ecg6wjMu7wdZbmXfD2S/vpOg0bdQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.14", + "buffer-crc32": "^1.0.0", + "minimist": "^1.2.0", + "sander": "^0.5.0" + }, + "bin": { + "sorcery": "bin/sorcery" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/string": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/string/-/string-1.4.0.tgz", + "integrity": "sha512-9j9fk92vTPEvp4Z1DDicJsePH4nxZgYJtQFTO/6bSGIqR8A6jm54PivMV1H/vtpCyEIlg7Cz31msXMcq9tm2sA==" + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svelte": { + "version": "4.2.19", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", + "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/estree": "^1.0.1", + "acorn": "^8.9.0", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "code-red": "^1.0.3", + "css-tree": "^2.3.1", + "estree-walker": "^3.0.3", + "is-reference": "^3.0.1", + "locate-character": "^3.0.0", + "magic-string": "^0.30.4", + "periscopic": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/svelte-check": { + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.8.6.tgz", + "integrity": "sha512-ij0u4Lw/sOTREP13BdWZjiXD/BlHE6/e2e34XzmVmsp5IN4kVa3PWP65NM32JAgwjZlwBg/+JtiNV1MM8khu0Q==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "chokidar": "^3.4.1", + "picocolors": "^1.0.0", + "sade": "^1.7.4", + "svelte-preprocess": "^5.1.3", + "typescript": "^5.0.3" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "peerDependencies": { + "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" + } + }, + "node_modules/svelte-hmr": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", + "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", + "dev": true, + "engines": { + "node": "^12.20 || ^14.13.1 || >= 16" + }, + "peerDependencies": { + "svelte": "^3.19.0 || ^4.0.0" + } + }, + "node_modules/svelte-preprocess": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.4.tgz", + "integrity": "sha512-IvnbQ6D6Ao3Gg6ftiM5tdbR6aAETwjhHV+UKGf5bHGYR69RQvF1ho0JKPcbUON4vy4R7zom13jPjgdOWCQ5hDA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/pug": "^2.0.6", + "detect-indent": "^6.1.0", + "magic-string": "^0.30.5", + "sorcery": "^0.11.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">= 16.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.10.2", + "coffeescript": "^2.5.1", + "less": "^3.11.3 || ^4.0.0", + "postcss": "^7 || ^8", + "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", + "pug": "^3.0.0", + "sass": "^1.26.8", + "stylus": "^0.55.0", + "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0", + "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "coffeescript": { + "optional": true + }, + "less": { + "optional": true + }, + "postcss": { + "optional": true + }, + "postcss-load-config": { + "optional": true + }, + "pug": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/svelte-youtube-embed": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/svelte-youtube-embed/-/svelte-youtube-embed-0.3.3.tgz", + "integrity": "sha512-g4+53JauVB+Jwz486lVqW8PUTnoP1SinECWhmQSCaKuh6zrYiAOFRpzMG6vW1TaQfSigiLWyUactFWipo4lsfQ==", + "dev": true, + "peerDependencies": { + "svelte": "^4.0.0" + } + }, + "node_modules/tailwind-merge": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.4.tgz", + "integrity": "sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.15", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.15.tgz", + "integrity": "sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.6", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-glob": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "dev": true, + "dependencies": { + "globalyzer": "0.1.0", + "globrex": "^0.1.2" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.3.0.tgz", + "integrity": "sha512-jlGqHGoKzyyjhwv/c9omAgohntThMcGtw8RV/RDLlkbbc08kni/akVxO62N8HaXMVbVsK1NCnpSK3N2xCt22ww==", + "engines": { + "node": "*" + } + }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/unist-util-visit/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/vfile/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.4.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", + "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", + "dev": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-plugin-tailwind-purgecss": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vite-plugin-tailwind-purgecss/-/vite-plugin-tailwind-purgecss-0.2.1.tgz", + "integrity": "sha512-pJevMPGyEve5Z/KCXEbYiw7I11Skt+ZAc+GGa8HcJy4d+8OAzgYG3rdvv3NZOT3IJyErSGoLb8dFxj9elPudtw==", + "dev": true, + "dependencies": { + "estree-walker": "^3.0.3", + "purgecss": "^6.0.0" + }, + "peerDependencies": { + "vite": "^4.1.1 || ^5.0.0" + } + }, + "node_modules/vitefu": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "dev": true, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/youtube-transcript": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/youtube-transcript/-/youtube-transcript-1.2.1.tgz", + "integrity": "sha512-TvEGkBaajKw+B6y91ziLuBLsa5cawgowou+Bk0ciGpjELDfAzSzTGXaZmeSSkUeknCPpEr/WGApOHDwV7V+Y9Q==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + }, + "dependencies": { + "@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "dev": true, + "optional": true + }, + "@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "requires": { + "@floating-ui/utils": "^0.2.8" + } + }, + "@floating-ui/dom": { + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", + "requires": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" + }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, + "@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "dev": true + }, + "@rollup/rollup-android-arm-eabi": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", + "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-android-arm64": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", + "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-arm64": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", + "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-x64": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", + "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", + "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-musleabihf": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", + "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", + "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-musl": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", + "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", + "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-riscv64-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", + "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-s390x-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", + "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", + "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-musl": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", + "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-arm64-msvc": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", + "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-ia32-msvc": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", + "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-x64-msvc": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", + "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", + "dev": true, + "optional": true + }, + "@skeletonlabs/skeleton": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@skeletonlabs/skeleton/-/skeleton-2.10.3.tgz", + "integrity": "sha512-O1RecF68zEVvZl3GgRS4emqWMUIQLHvTOFoqGOw/2OXCPE06IxUQrHQf2hnxCPxtGZNXY2YX8UNV38l+eH8GNQ==", + "dev": true, + "requires": { + "esm-env": "1.0.0" + } + }, + "@skeletonlabs/tw-plugin": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@skeletonlabs/tw-plugin/-/tw-plugin-0.3.1.tgz", + "integrity": "sha512-DjjeOHN3HhFQf6gYPT2MUZMkIdw1jeB9mbuKC8etQxUlOR4XitfC7hssRWFJ8RJsvrrN0myCBbdWkVG1JVA96g==", + "dev": true, + "requires": {} + }, + "@sveltejs/adapter-auto": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.2.5.tgz", + "integrity": "sha512-27LR+uKccZ62lgq4N/hvyU2G+hTP9fxWEAfnZcl70HnyfAjMSsGk1z/SjAPXNCD1mVJIE7IFu3TQ8cQ/UH3c0A==", + "dev": true, + "requires": { + "import-meta-resolve": "^4.1.0" + } + }, + "@sveltejs/kit": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.8.4.tgz", + "integrity": "sha512-oDSBHPokbP2iaQlHiEWAkVLsIugsXve8YtABtlyHBUljA63Wgx0UtV8MSOQOGpRft1M+Cd5rzer+0SFlppQwOg==", + "dev": true, + "requires": { + "@types/cookie": "^0.6.0", + "cookie": "^0.6.0", + "devalue": "^5.1.0", + "esm-env": "^1.0.0", + "import-meta-resolve": "^4.1.0", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "sade": "^1.8.1", + "set-cookie-parser": "^2.6.0", + "sirv": "^3.0.0", + "tiny-glob": "^0.2.9" + } + }, + "@sveltejs/vite-plugin-svelte": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz", + "integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==", + "dev": true, + "requires": { + "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", + "debug": "^4.3.4", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.10", + "svelte-hmr": "^0.16.0", + "vitefu": "^0.2.5" + } + }, + "@sveltejs/vite-plugin-svelte-inspector": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", + "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, + "@tailwindcss/forms": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.9.tgz", + "integrity": "sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg==", + "dev": true, + "requires": { + "mini-svg-data-uri": "^1.2.3" + } + }, + "@tailwindcss/typography": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.15.tgz", + "integrity": "sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==", + "dev": true, + "requires": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + } + }, + "@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true + }, + "@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "requires": { + "@types/unist": "*" + } + }, + "@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "requires": { + "@types/unist": "*" + } + }, + "@types/node": { + "version": "20.17.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz", + "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==", + "dev": true, + "requires": { + "undici-types": "~6.19.2" + } + }, + "@types/pug": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz", + "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==", + "dev": true + }, + "@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" + }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, + "acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true + }, + "ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true + }, + "asn1": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==" + }, + "assert-plus": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.2.tgz", + "integrity": "sha512-BbJV8Hq6grYTokkHi/qKS34kfYIFYpu4wKd/H0dARsa6qOqEFH1wboxMwrccAmFjyRjkemjElaVC/sZSUMxHnA==" + }, + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==" + }, + "autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "dev": true, + "requires": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "aws-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/aws-sign/-/aws-sign-0.3.0.tgz", + "integrity": "sha512-pEMJAknifcXqXqYVXzGPIu8mJvxtJxIdpVpAs8HNS+paT+9srRUDMQn+3hULS7WbLmttcmvgMvnDcFujqXJyPw==" + }, + "axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true + }, + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true + }, + "boom": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", + "integrity": "sha512-OvfN8y1oAxxphzkl2SnCS+ztV/uVKTATtgLjWYg/7KwcNyf3rzpHxNQJZCKtsZd4+MteKczhWbSjtEX4bGgU9g==", + "requires": { + "hoek": "0.9.x" + }, + "dependencies": { + "hoek": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==" + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "requires": { + "fill-range": "^7.1.1" + } + }, + "browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + } + }, + "buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "dev": true + }, + "camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001680", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", + "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", + "dev": true + }, + "ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==" + }, + "character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==" + }, + "character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==" + }, + "chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + }, + "cn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/cn/-/cn-0.1.1.tgz", + "integrity": "sha512-PkWPdg4L4aQEwqqkGzMclTdHlstGzBg773gBtsUCHqXrawQ8wQHf/490Rw2hXPaoI7QXYbCgI67Jfe25TjxLGw==", + "requires": { + "request": "~2.21.0", + "string": "~1.4.0" + } + }, + "code-red": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", + "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1", + "acorn": "^8.10.0", + "estree-walker": "^3.0.3", + "periscopic": "^3.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", + "requires": { + "delayed-stream": "0.0.5" + } + }, + "comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true + }, + "cookie-jar": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/cookie-jar/-/cookie-jar-0.3.0.tgz", + "integrity": "sha512-dX1400pzPULr+ZovkIsDEqe7XH8xCAYGT5Dege4Eot44Qs2mS2iJmnh45TxTO5MIsCfrV/JGZVloLhm46AHxNw==" + }, + "cross-spawn": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "cryptiles": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", + "integrity": "sha512-gvWSbgqP+569DdslUiCelxIv3IYK5Lgmq1UrRnk+s1WxQOQ16j3GPDcjdtgL5Au65DU/xQi6q3xPtf5Kta+3IQ==", + "requires": { + "boom": "0.4.x" + } + }, + "css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "requires": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "ctype": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.2.tgz", + "integrity": "sha512-C+CbWLSk0xdPcp7evo2YEF0o8SLKcDCQsw//accyrf8/NAWYzmUhmL8ZiSokvuwwMQ08RK10U9pkRcyy8EmA5A==" + }, + "date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==" + }, + "debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, + "delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==" + }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" + }, + "detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true + }, + "devalue": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", + "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", + "dev": true + }, + "devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "requires": { + "dequal": "^2.0.0" + } + }, + "didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.5.62", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.62.tgz", + "integrity": "sha512-t8c+zLmJHa9dJy96yBZRXGQYoiCEnHYgFwn1asvSPZSUdVxnB62A4RASd7k41ytG3ErFBA0TpHlKg9D9SQBmLg==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true + }, + "esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true + }, + "esm-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", + "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", + "dev": true + }, + "estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + } + }, + "forever-agent": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", + "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==" + }, + "form-data": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.0.8.tgz", + "integrity": "sha512-yzpBIhe8Ll+dYTXjd+4ORxbQktke+abD0dJjedvqsVVayMkb+PgLGatJNLwo95Va75l3YDZ01SrouzyW9bC2Fg==", + "requires": { + "async": "~0.2.7", + "combined-stream": "~0.0.4", + "mime": "~1.2.2" + } + }, + "fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==" + }, + "glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globalyzer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", + "dev": true + }, + "globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, + "hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "requires": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } + }, + "hast-util-from-parse5": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.2.tgz", + "integrity": "sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==", + "requires": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + } + } + }, + "hast-util-has-property": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz", + "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==", + "requires": { + "@types/hast": "^3.0.0" + } + }, + "hast-util-heading-rank": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", + "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", + "requires": { + "@types/hast": "^3.0.0" + } + }, + "hast-util-interactive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-interactive/-/hast-util-interactive-3.0.0.tgz", + "integrity": "sha512-9VFa3kP6AT40BNYcPmn3jpsG+1KPDF0rUFCrFVQDUsuUXZ3YLODm8UGV0tmYzFpcOIQXTAOi2ccS3ywlj2dQTA==", + "requires": { + "@types/hast": "^3.0.0", + "hast-util-has-property": "^3.0.0" + } + }, + "hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "requires": { + "@types/hast": "^3.0.0" + } + }, + "hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "requires": { + "@types/hast": "^3.0.0" + } + }, + "hast-util-to-html": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.3.tgz", + "integrity": "sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==", + "requires": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + } + } + }, + "hast-util-to-string": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", + "requires": { + "@types/hast": "^3.0.0" + } + }, + "hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "requires": { + "@types/hast": "^3.0.0" + } + }, + "hastscript": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.0.tgz", + "integrity": "sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==", + "requires": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + } + }, + "hawk": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-0.13.1.tgz", + "integrity": "sha512-f/1H9bruKJfgLN2KFd+666ILQvJYsJcxaCoIdHaaD2zgl7RUa08/202pGJXhOmQ1kTEdMTSxPnbCsu4l6JARhQ==", + "requires": { + "boom": "0.4.x", + "cryptiles": "0.2.x", + "hoek": "0.8.x", + "sntp": "0.2.x" + } + }, + "highlight.js": { + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.10.0.tgz", + "integrity": "sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==" + }, + "hoek": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.8.5.tgz", + "integrity": "sha512-NoKdeYUBOlQ7j9dgvT9BEX90rE6HtDkaMFwR6hfOj26LA2Mwyg5026jOpNBhmNrWIGdPnbBK3sQJI3POwh8wqg==" + }, + "html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==" + }, + "http-signature": { + "version": "0.9.11", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.9.11.tgz", + "integrity": "sha512-OleF+71prrzyaWDTfTXWvv24N/45SjKCPu/3pzzhj8+MgdGaB7Am3NY0ot5uynrzgTwyQ+yoejuFCncCQxyRSA==", + "requires": { + "asn1": "0.1.11", + "assert-plus": "0.1.2", + "ctype": "0.5.2" + } + }, + "import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "requires": { + "hasown": "^2.0.2" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, + "jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "dev": true + }, + "json-stringify-safe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-4.0.0.tgz", + "integrity": "sha512-qzEpz1SDUb9xvA+LDOkNgjekdV7tuC7zDQf14sqMBtujh8kVbQhF11VWm4DeR99yFNjVSjTTfKa40c9ZQOtwXA==" + }, + "kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true + }, + "lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true + }, + "lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "lucide-svelte": { + "version": "0.309.0", + "resolved": "https://registry.npmjs.org/lucide-svelte/-/lucide-svelte-0.309.0.tgz", + "integrity": "sha512-+t85+5Y696FVDoJHiiMhJGalv+UiWUX46gMudOQfYrVGjsyC2MGSZRNAGAHkdykA4RJSh/wUtSgnTgCmd0Swvw==", + "dev": true, + "requires": {} + }, + "magic-string": { + "version": "0.30.12", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", + "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "marked": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.2.tgz", + "integrity": "sha512-85RUkoYKIVB21PbMKrnD6aCl9ws+XKEyhJNMbLn206NyD3jbBo7Ec7Wi4Jrsn4dV1a2ng7K/jfkmIN0DNoS41w==" + }, + "mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "requires": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + } + }, + "mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, + "mdsvex": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/mdsvex/-/mdsvex-0.11.2.tgz", + "integrity": "sha512-Y4ab+vLvTJS88196Scb/RFNaHMHVSWw6CwfsgWIQP8f42D57iDII0/qABSu530V4pkv8s6T2nx3ds0MC1VwFLA==", + "dev": true, + "requires": { + "@types/unist": "^2.0.3", + "prism-svelte": "^0.4.7", + "prismjs": "^1.17.1", + "vfile-message": "^2.0.4" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==" + }, + "micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==" + }, + "micromark-util-types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.1.tgz", + "integrity": "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==" + }, + "micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==" + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, + "mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true + }, + "mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true + }, + "node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true + }, + "oauth-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", + "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, + "parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "requires": { + "entities": "^4.5.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + } + }, + "periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + }, + "pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true + }, + "postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "dev": true, + "requires": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + } + }, + "postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "requires": { + "camelcase-css": "^2.0.1" + } + }, + "postcss-load-config": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.1.0.tgz", + "integrity": "sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==", + "dev": true, + "requires": { + "lilconfig": "^3.1.1", + "yaml": "^2.4.2" + }, + "dependencies": { + "lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true + } + } + }, + "postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.1.1" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + } + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "prism-svelte": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/prism-svelte/-/prism-svelte-0.4.7.tgz", + "integrity": "sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==", + "dev": true + }, + "prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "dev": true + }, + "property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==" + }, + "purgecss": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-6.0.0.tgz", + "integrity": "sha512-s3EBxg5RSWmpqd0KGzNqPiaBbWDz1/As+2MzoYVGMqgDqRTLBhJW6sywfTBek7OwNfoS/6pS0xdtvChNhFj2cw==", + "dev": true, + "requires": { + "commander": "^12.0.0", + "glob": "^10.3.10", + "postcss": "^8.4.4", + "postcss-selector-parser": "^6.0.7" + }, + "dependencies": { + "commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true + } + } + }, + "qs": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", + "integrity": "sha512-kN+yNdAf29Jgp+AYHUmC7X4QdJPR8czuMWLNLc0aRxkQ7tB3vJQEONKKT9ou/rW7EbqVec11srC9q9BiVbcnHA==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "requires": { + "pify": "^2.3.0" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rehype": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz", + "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==", + "requires": { + "@types/hast": "^3.0.0", + "rehype-parse": "^9.0.0", + "rehype-stringify": "^10.0.0", + "unified": "^11.0.0" + } + }, + "rehype-autolink-headings": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-7.1.0.tgz", + "integrity": "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==", + "requires": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0" + } + }, + "rehype-external-links": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", + "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", + "requires": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-is-element": "^3.0.0", + "is-absolute-url": "^4.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0" + } + }, + "rehype-parse": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", + "requires": { + "@types/hast": "^3.0.0", + "hast-util-from-html": "^2.0.0", + "unified": "^11.0.0" + } + }, + "rehype-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", + "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", + "requires": { + "@types/hast": "^3.0.0", + "github-slugger": "^2.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "unist-util-visit": "^5.0.0" + } + }, + "rehype-stringify": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", + "requires": { + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "unified": "^11.0.0" + } + }, + "rehype-unwrap-images": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-unwrap-images/-/rehype-unwrap-images-1.0.0.tgz", + "integrity": "sha512-wzW5Mk9IlVF2UwXC5NtIZsx1aHYbV8+bLWjJnlZaaamz5QU52RppWtq1uEZJqGo8d9Y4RuDqidB6r9RFpKugIg==", + "requires": { + "@types/hast": "^3.0.0", + "hast-util-interactive": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "unist-util-visit": "^5.0.0" + } + }, + "request": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.21.0.tgz", + "integrity": "sha512-jvDa6FC46ystc0cn+EqtJ4B32SSz/cMX7fEIv0UHX4wsYAKJYXjA5EyAMWpRQ+hWCnX9jPD1b4o7xZ/r1Tyx/Q==", + "requires": { + "aws-sign": "~0.3.0", + "cookie-jar": "~0.3.0", + "forever-agent": "~0.5.0", + "form-data": "0.0.8", + "hawk": "~0.13.0", + "http-signature": "~0.9.11", + "json-stringify-safe": "~4.0.0", + "mime": "~1.2.9", + "node-uuid": "~1.4.0", + "oauth-sign": "~0.3.0", + "qs": "~0.6.0", + "tunnel-agent": "~0.3.0" + } + }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "rollup": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", + "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", + "dev": true, + "requires": { + "@rollup/rollup-android-arm-eabi": "4.24.0", + "@rollup/rollup-android-arm64": "4.24.0", + "@rollup/rollup-darwin-arm64": "4.24.0", + "@rollup/rollup-darwin-x64": "4.24.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", + "@rollup/rollup-linux-arm-musleabihf": "4.24.0", + "@rollup/rollup-linux-arm64-gnu": "4.24.0", + "@rollup/rollup-linux-arm64-musl": "4.24.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", + "@rollup/rollup-linux-riscv64-gnu": "4.24.0", + "@rollup/rollup-linux-s390x-gnu": "4.24.0", + "@rollup/rollup-linux-x64-gnu": "4.24.0", + "@rollup/rollup-linux-x64-musl": "4.24.0", + "@rollup/rollup-win32-arm64-msvc": "4.24.0", + "@rollup/rollup-win32-ia32-msvc": "4.24.0", + "@rollup/rollup-win32-x64-msvc": "4.24.0", + "@types/estree": "1.0.6", + "fsevents": "~2.3.2" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "requires": { + "mri": "^1.1.0" + } + }, + "sander": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", + "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", + "dev": true, + "requires": { + "es6-promise": "^3.1.2", + "graceful-fs": "^4.1.3", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.2" + } + }, + "set-cookie-parser": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz", + "integrity": "sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, + "sirv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz", + "integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==", + "dev": true, + "requires": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + } + }, + "sntp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", + "integrity": "sha512-bDLrKa/ywz65gCl+LmOiIhteP1bhEsAAzhfMedPoiHP3dyYnAevlaJshdqb9Yu0sRifyP/fRqSt8t+5qGIWlGQ==", + "requires": { + "hoek": "0.9.x" + }, + "dependencies": { + "hoek": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==" + } + } + }, + "sorcery": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.1.tgz", + "integrity": "sha512-o7npfeJE6wi6J9l0/5LKshFzZ2rMatRiCDwYeDQaOzqdzRJwALhX7mk/A/ecg6wjMu7wdZbmXfD2S/vpOg0bdQ==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.14", + "buffer-crc32": "^1.0.0", + "minimist": "^1.2.0", + "sander": "^0.5.0" + } + }, + "source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true + }, + "space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" + }, + "string": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/string/-/string-1.4.0.tgz", + "integrity": "sha512-9j9fk92vTPEvp4Z1DDicJsePH4nxZgYJtQFTO/6bSGIqR8A6jm54PivMV1H/vtpCyEIlg7Cz31msXMcq9tm2sA==" + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "requires": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + } + } + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "svelte": { + "version": "4.2.19", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", + "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/estree": "^1.0.1", + "acorn": "^8.9.0", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "code-red": "^1.0.3", + "css-tree": "^2.3.1", + "estree-walker": "^3.0.3", + "is-reference": "^3.0.1", + "locate-character": "^3.0.0", + "magic-string": "^0.30.4", + "periscopic": "^3.1.0" + } + }, + "svelte-check": { + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.8.6.tgz", + "integrity": "sha512-ij0u4Lw/sOTREP13BdWZjiXD/BlHE6/e2e34XzmVmsp5IN4kVa3PWP65NM32JAgwjZlwBg/+JtiNV1MM8khu0Q==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.17", + "chokidar": "^3.4.1", + "picocolors": "^1.0.0", + "sade": "^1.7.4", + "svelte-preprocess": "^5.1.3", + "typescript": "^5.0.3" + } + }, + "svelte-hmr": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", + "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", + "dev": true, + "requires": {} + }, + "svelte-preprocess": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.4.tgz", + "integrity": "sha512-IvnbQ6D6Ao3Gg6ftiM5tdbR6aAETwjhHV+UKGf5bHGYR69RQvF1ho0JKPcbUON4vy4R7zom13jPjgdOWCQ5hDA==", + "dev": true, + "requires": { + "@types/pug": "^2.0.6", + "detect-indent": "^6.1.0", + "magic-string": "^0.30.5", + "sorcery": "^0.11.0", + "strip-indent": "^3.0.0" + } + }, + "svelte-youtube-embed": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/svelte-youtube-embed/-/svelte-youtube-embed-0.3.3.tgz", + "integrity": "sha512-g4+53JauVB+Jwz486lVqW8PUTnoP1SinECWhmQSCaKuh6zrYiAOFRpzMG6vW1TaQfSigiLWyUactFWipo4lsfQ==", + "dev": true, + "requires": {} + }, + "tailwind-merge": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.4.tgz", + "integrity": "sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==" + }, + "tailwindcss": { + "version": "3.4.15", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.15.tgz", + "integrity": "sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==", + "dev": true, + "requires": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.6", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "dependencies": { + "postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "requires": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "dependencies": { + "lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true + } + } + }, + "postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + } + } + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "tiny-glob": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "dev": true, + "requires": { + "globalyzer": "0.1.0", + "globrex": "^0.1.2" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true + }, + "trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==" + }, + "trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==" + }, + "ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, + "tunnel-agent": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.3.0.tgz", + "integrity": "sha512-jlGqHGoKzyyjhwv/c9omAgohntThMcGtw8RV/RDLlkbbc08kni/akVxO62N8HaXMVbVsK1NCnpSK3N2xCt22ww==" + }, + "typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true + }, + "undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, + "unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "requires": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + } + } + }, + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "requires": { + "@types/unist": "^3.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + } + } + }, + "unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "requires": { + "@types/unist": "^3.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + } + } + }, + "unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "dev": true, + "requires": { + "@types/unist": "^2.0.2" + } + }, + "unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + } + } + }, + "unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + } + } + }, + "update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "requires": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "requires": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } + }, + "vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "requires": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + } + } + }, + "vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + } + }, + "vite": { + "version": "5.4.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", + "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", + "dev": true, + "requires": { + "esbuild": "^0.21.3", + "fsevents": "~2.3.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + } + }, + "vite-plugin-tailwind-purgecss": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vite-plugin-tailwind-purgecss/-/vite-plugin-tailwind-purgecss-0.2.1.tgz", + "integrity": "sha512-pJevMPGyEve5Z/KCXEbYiw7I11Skt+ZAc+GGa8HcJy4d+8OAzgYG3rdvv3NZOT3IJyErSGoLb8dFxj9elPudtw==", + "dev": true, + "requires": { + "estree-walker": "^3.0.3", + "purgecss": "^6.0.0" + } + }, + "vitefu": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "dev": true, + "requires": {} + }, + "web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + } + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "yaml": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", + "dev": true + }, + "youtube-transcript": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/youtube-transcript/-/youtube-transcript-1.2.1.tgz", + "integrity": "sha512-TvEGkBaajKw+B6y91ziLuBLsa5cawgowou+Bk0ciGpjELDfAzSzTGXaZmeSSkUeknCPpEr/WGApOHDwV7V+Y9Q==" + }, + "zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" + } + } +} diff --git a/web/package.json b/web/package.json new file mode 100644 index 00000000..ddbdeb7b --- /dev/null +++ b/web/package.json @@ -0,0 +1,53 @@ +{ + "name": "terminal-blog", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "test": "vitest", + "lint": "prettier --check . && eslint .", + "format": "prettier --write ." + }, + "devDependencies": { + "@skeletonlabs/skeleton": "^2.8.0", + "@skeletonlabs/tw-plugin": "^0.3.1", + "@sveltejs/adapter-auto": "^3.0.0", + "@sveltejs/kit": "^2.8.4", + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@tailwindcss/forms": "^0.5.7", + "@tailwindcss/typography": "^0.5.10", + "@types/node": "^20.10.0", + "autoprefixer": "^10.4.16", + "lucide-svelte": "^0.309.0", + "mdsvex": "^0.11.0", + "postcss": "^8.4.32", + "postcss-load-config": "^5.0.2", + "svelte": "^4.2.7", + "svelte-check": "^3.6.0", + "svelte-youtube-embed": "^0.3.3", + "tailwindcss": "^3.3.6", + "typescript": "^5.0.0", + "vite": "^5.0.3", + "vite-plugin-tailwind-purgecss": "^0.2.0" + }, + "type": "module", + "dependencies": { + "@floating-ui/dom": "^1.5.3", + "clsx": "^2.1.1", + "cn": "^0.1.1", + "date-fns": "^4.1.0", + "highlight.js": "^11.10.0", + "marked": "^15.0.1", + "rehype": "^13.0.2", + "rehype-autolink-headings": "^7.1.0", + "rehype-external-links": "^3.0.0", + "rehype-slug": "^6.0.0", + "rehype-unwrap-images": "^1.0.0", + "tailwind-merge": "^2.5.4", + "youtube-transcript": "^1.2.1" + } +} diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml new file mode 100644 index 00000000..e8b6de5b --- /dev/null +++ b/web/pnpm-lock.yaml @@ -0,0 +1,2925 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@floating-ui/dom': + specifier: ^1.5.3 + version: 1.6.12 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + cn: + specifier: ^0.1.1 + version: 0.1.1 + date-fns: + specifier: ^4.1.0 + version: 4.1.0 + highlight.js: + specifier: ^11.10.0 + version: 11.10.0 + marked: + specifier: ^15.0.1 + version: 15.0.1 + rehype: + specifier: ^13.0.2 + version: 13.0.2 + rehype-autolink-headings: + specifier: ^7.1.0 + version: 7.1.0 + rehype-external-links: + specifier: ^3.0.0 + version: 3.0.0 + rehype-slug: + specifier: ^6.0.0 + version: 6.0.0 + rehype-unwrap-images: + specifier: ^1.0.0 + version: 1.0.0 + tailwind-merge: + specifier: ^2.5.4 + version: 2.5.4 + youtube-transcript: + specifier: ^1.2.1 + version: 1.2.1 + devDependencies: + '@skeletonlabs/skeleton': + specifier: ^2.8.0 + version: 2.10.3(svelte@4.2.19) + '@skeletonlabs/tw-plugin': + specifier: ^0.3.1 + version: 0.3.1(tailwindcss@3.4.15) + '@sveltejs/adapter-auto': + specifier: ^3.0.0 + version: 3.3.1(@sveltejs/kit@2.8.4(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)))(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6))) + '@sveltejs/kit': + specifier: ^2.8.4 + version: 2.8.4(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)))(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)) + '@sveltejs/vite-plugin-svelte': + specifier: ^3.0.0 + version: 3.1.2(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)) + '@tailwindcss/forms': + specifier: ^0.5.7 + version: 0.5.9(tailwindcss@3.4.15) + '@tailwindcss/typography': + specifier: ^0.5.10 + version: 0.5.15(tailwindcss@3.4.15) + '@types/node': + specifier: ^20.10.0 + version: 20.17.6 + autoprefixer: + specifier: ^10.4.16 + version: 10.4.20(postcss@8.4.49) + lucide-svelte: + specifier: ^0.309.0 + version: 0.309.0(svelte@4.2.19) + mdsvex: + specifier: ^0.11.0 + version: 0.11.2(svelte@4.2.19) + postcss: + specifier: ^8.4.32 + version: 8.4.49 + postcss-load-config: + specifier: ^5.0.2 + version: 5.1.0(jiti@1.21.6)(postcss@8.4.49) + svelte: + specifier: ^4.2.7 + version: 4.2.19 + svelte-check: + specifier: ^3.6.0 + version: 3.8.6(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.49))(postcss@8.4.49)(svelte@4.2.19) + svelte-youtube-embed: + specifier: ^0.3.3 + version: 0.3.3(svelte@4.2.19) + tailwindcss: + specifier: ^3.3.6 + version: 3.4.15 + typescript: + specifier: ^5.0.0 + version: 5.6.3 + vite: + specifier: ^5.0.3 + version: 5.4.11(@types/node@20.17.6) + vite-plugin-tailwind-purgecss: + specifier: ^0.2.0 + version: 0.2.1(vite@5.4.11(@types/node@20.17.6)) + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@floating-ui/core@1.6.8': + resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} + + '@floating-ui/dom@1.6.12': + resolution: {integrity: sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==} + + '@floating-ui/utils@0.2.8': + resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@polka/url@1.0.0-next.28': + resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} + + '@rollup/rollup-android-arm-eabi@4.27.2': + resolution: {integrity: sha512-Tj+j7Pyzd15wAdSJswvs5CJzJNV+qqSUcr/aCD+jpQSBtXvGnV0pnrjoc8zFTe9fcKCatkpFpOO7yAzpO998HA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.27.2': + resolution: {integrity: sha512-xsPeJgh2ThBpUqlLgRfiVYBEf/P1nWlWvReG+aBWfNv3XEBpa6ZCmxSVnxJgLgkNz4IbxpLy64h2gCmAAQLneQ==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.27.2': + resolution: {integrity: sha512-KnXU4m9MywuZFedL35Z3PuwiTSn/yqRIhrEA9j+7OSkji39NzVkgxuxTYg5F8ryGysq4iFADaU5osSizMXhU2A==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.27.2': + resolution: {integrity: sha512-Hj77A3yTvUeCIx/Vi+4d4IbYhyTwtHj07lVzUgpUq9YpJSEiGJj4vXMKwzJ3w5zp5v3PFvpJNgc/J31smZey6g==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.27.2': + resolution: {integrity: sha512-RjgKf5C3xbn8gxvCm5VgKZ4nn0pRAIe90J0/fdHUsgztd3+Zesb2lm2+r6uX4prV2eUByuxJNdt647/1KPRq5g==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.27.2': + resolution: {integrity: sha512-duq21FoXwQtuws+V9H6UZ+eCBc7fxSpMK1GQINKn3fAyd9DFYKPJNcUhdIKOrMFjLEJgQskoMoiuizMt+dl20g==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.27.2': + resolution: {integrity: sha512-6npqOKEPRZkLrMcvyC/32OzJ2srdPzCylJjiTJT2c0bwwSGm7nz2F9mNQ1WrAqCBZROcQn91Fno+khFhVijmFA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.27.2': + resolution: {integrity: sha512-V9Xg6eXtgBtHq2jnuQwM/jr2mwe2EycnopO8cbOvpzFuySCGtKlPCI3Hj9xup/pJK5Q0388qfZZy2DqV2J8ftw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.27.2': + resolution: {integrity: sha512-uCFX9gtZJoQl2xDTpRdseYuNqyKkuMDtH6zSrBTA28yTfKyjN9hQ2B04N5ynR8ILCoSDOrG/Eg+J2TtJ1e/CSA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.27.2': + resolution: {integrity: sha512-/PU9P+7Rkz8JFYDHIi+xzHabOu9qEWR07L5nWLIUsvserrxegZExKCi2jhMZRd0ATdboKylu/K5yAXbp7fYFvA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.27.2': + resolution: {integrity: sha512-eCHmol/dT5odMYi/N0R0HC8V8QE40rEpkyje/ZAXJYNNoSfrObOvG/Mn+s1F/FJyB7co7UQZZf6FuWnN6a7f4g==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.27.2': + resolution: {integrity: sha512-DEP3Njr9/ADDln3kNi76PXonLMSSMiCir0VHXxmGSHxCxDfQ70oWjHcJGfiBugzaqmYdTC7Y+8Int6qbnxPBIQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.27.2': + resolution: {integrity: sha512-NHGo5i6IE/PtEPh5m0yw5OmPMpesFnzMIS/lzvN5vknnC1sXM5Z/id5VgcNPgpD+wHmIcuYYgW+Q53v+9s96lQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.27.2': + resolution: {integrity: sha512-PaW2DY5Tan+IFvNJGHDmUrORadbe/Ceh8tQxi8cmdQVCCYsLoQo2cuaSj+AU+YRX8M4ivS2vJ9UGaxfuNN7gmg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.27.2': + resolution: {integrity: sha512-dOlWEMg2gI91Qx5I/HYqOD6iqlJspxLcS4Zlg3vjk1srE67z5T2Uz91yg/qA8sY0XcwQrFzWWiZhMNERylLrpQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.27.2': + resolution: {integrity: sha512-euMIv/4x5Y2/ImlbGl88mwKNXDsvzbWUlT7DFky76z2keajCtcbAsN9LUdmk31hAoVmJJYSThgdA0EsPeTr1+w==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.27.2': + resolution: {integrity: sha512-RsnE6LQkUHlkC10RKngtHNLxb7scFykEbEwOFDjr3CeCMG+Rr+cKqlkKc2/wJ1u4u990urRHCbjz31x84PBrSQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.27.2': + resolution: {integrity: sha512-foJM5vv+z2KQmn7emYdDLyTbkoO5bkHZE1oth2tWbQNGW7mX32d46Hz6T0MqXdWS2vBZhaEtHqdy9WYwGfiliA==} + cpu: [x64] + os: [win32] + + '@skeletonlabs/skeleton@2.10.3': + resolution: {integrity: sha512-O1RecF68zEVvZl3GgRS4emqWMUIQLHvTOFoqGOw/2OXCPE06IxUQrHQf2hnxCPxtGZNXY2YX8UNV38l+eH8GNQ==} + peerDependencies: + svelte: ^3.56.0 || ^4.0.0 || ^5.0.0 + + '@skeletonlabs/tw-plugin@0.3.1': + resolution: {integrity: sha512-DjjeOHN3HhFQf6gYPT2MUZMkIdw1jeB9mbuKC8etQxUlOR4XitfC7hssRWFJ8RJsvrrN0myCBbdWkVG1JVA96g==} + peerDependencies: + tailwindcss: '>=3.0.0' + + '@sveltejs/adapter-auto@3.3.1': + resolution: {integrity: sha512-5Sc7WAxYdL6q9j/+D0jJKjGREGlfIevDyHSQ2eNETHcB1TKlQWHcAo8AS8H1QdjNvSXpvOwNjykDUHPEAyGgdQ==} + peerDependencies: + '@sveltejs/kit': ^2.0.0 + + '@sveltejs/kit@2.8.4': + resolution: {integrity: sha512-oDSBHPokbP2iaQlHiEWAkVLsIugsXve8YtABtlyHBUljA63Wgx0UtV8MSOQOGpRft1M+Cd5rzer+0SFlppQwOg==} + engines: {node: '>=18.13'} + hasBin: true + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 + svelte: ^4.0.0 || ^5.0.0-next.0 + vite: ^5.0.3 + + '@sveltejs/vite-plugin-svelte-inspector@2.1.0': + resolution: {integrity: sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==} + engines: {node: ^18.0.0 || >=20} + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^3.0.0 + svelte: ^4.0.0 || ^5.0.0-next.0 + vite: ^5.0.0 + + '@sveltejs/vite-plugin-svelte@3.1.2': + resolution: {integrity: sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==} + engines: {node: ^18.0.0 || >=20} + peerDependencies: + svelte: ^4.0.0 || ^5.0.0-next.0 + vite: ^5.0.0 + + '@tailwindcss/forms@0.5.9': + resolution: {integrity: sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg==} + peerDependencies: + tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20' + + '@tailwindcss/typography@0.5.15': + resolution: {integrity: sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20' + + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/node@20.17.6': + resolution: {integrity: sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==} + + '@types/pug@2.0.10': + resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@ungap/structured-clone@1.2.0': + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + asn1@0.1.11: + resolution: {integrity: sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==} + engines: {node: '>=0.4.9'} + + assert-plus@0.1.2: + resolution: {integrity: sha512-BbJV8Hq6grYTokkHi/qKS34kfYIFYpu4wKd/H0dARsa6qOqEFH1wboxMwrccAmFjyRjkemjElaVC/sZSUMxHnA==} + engines: {node: '>=0.6'} + + async@0.2.10: + resolution: {integrity: sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==} + + autoprefixer@10.4.20: + resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + aws-sign@0.3.0: + resolution: {integrity: sha512-pEMJAknifcXqXqYVXzGPIu8mJvxtJxIdpVpAs8HNS+paT+9srRUDMQn+3hULS7WbLmttcmvgMvnDcFujqXJyPw==} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + boom@0.4.2: + resolution: {integrity: sha512-OvfN8y1oAxxphzkl2SnCS+ztV/uVKTATtgLjWYg/7KwcNyf3rzpHxNQJZCKtsZd4+MteKczhWbSjtEX4bGgU9g==} + engines: {node: '>=0.8.0'} + deprecated: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial). + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.24.2: + resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + caniuse-lite@1.0.30001680: + resolution: {integrity: sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + cn@0.1.1: + resolution: {integrity: sha512-PkWPdg4L4aQEwqqkGzMclTdHlstGzBg773gBtsUCHqXrawQ8wQHf/490Rw2hXPaoI7QXYbCgI67Jfe25TjxLGw==} + hasBin: true + + code-red@1.0.4: + resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@0.0.7: + resolution: {integrity: sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==} + engines: {node: '>= 0.8'} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + cookie-jar@0.3.0: + resolution: {integrity: sha512-dX1400pzPULr+ZovkIsDEqe7XH8xCAYGT5Dege4Eot44Qs2mS2iJmnh45TxTO5MIsCfrV/JGZVloLhm46AHxNw==} + + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + + cross-spawn@7.0.5: + resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==} + engines: {node: '>= 8'} + + cryptiles@0.2.2: + resolution: {integrity: sha512-gvWSbgqP+569DdslUiCelxIv3IYK5Lgmq1UrRnk+s1WxQOQ16j3GPDcjdtgL5Au65DU/xQi6q3xPtf5Kta+3IQ==} + engines: {node: '>=0.8.0'} + deprecated: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial). + + css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + ctype@0.5.2: + resolution: {integrity: sha512-C+CbWLSk0xdPcp7evo2YEF0o8SLKcDCQsw//accyrf8/NAWYzmUhmL8ZiSokvuwwMQ08RK10U9pkRcyy8EmA5A==} + engines: {node: '>= 0.4'} + + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + delayed-stream@0.0.5: + resolution: {integrity: sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==} + engines: {node: '>=0.4.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + + devalue@5.1.1: + resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + electron-to-chromium@1.5.62: + resolution: {integrity: sha512-t8c+zLmJHa9dJy96yBZRXGQYoiCEnHYgFwn1asvSPZSUdVxnB62A4RASd7k41ytG3ErFBA0TpHlKg9D9SQBmLg==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + es6-promise@3.3.1: + resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + esm-env@1.0.0: + resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} + + esm-env@1.1.4: + resolution: {integrity: sha512-oO82nKPHKkzIj/hbtuDYy/JHqBHFlMIW36SDiPCVsj87ntDLcWN+sJ1erdVryd4NxODacFTsdrIE3b7IamqbOg==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + + forever-agent@0.5.2: + resolution: {integrity: sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==} + + form-data@0.0.8: + resolution: {integrity: sha512-yzpBIhe8Ll+dYTXjd+4ORxbQktke+abD0dJjedvqsVVayMkb+PgLGatJNLwo95Va75l3YDZ01SrouzyW9bC2Fg==} + engines: {node: '>= 0.6'} + + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globalyzer@0.1.0: + resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} + + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.1: + resolution: {integrity: sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==} + + hast-util-has-property@3.0.0: + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + + hast-util-heading-rank@3.0.0: + resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} + + hast-util-interactive@3.0.0: + resolution: {integrity: sha512-9VFa3kP6AT40BNYcPmn3jpsG+1KPDF0rUFCrFVQDUsuUXZ3YLODm8UGV0tmYzFpcOIQXTAOi2ccS3ywlj2dQTA==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-to-html@9.0.3: + resolution: {integrity: sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==} + + hast-util-to-string@3.0.1: + resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@8.0.0: + resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==} + + hawk@0.13.1: + resolution: {integrity: sha512-f/1H9bruKJfgLN2KFd+666ILQvJYsJcxaCoIdHaaD2zgl7RUa08/202pGJXhOmQ1kTEdMTSxPnbCsu4l6JARhQ==} + engines: {node: '>=0.8.0'} + deprecated: This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues. + + highlight.js@11.10.0: + resolution: {integrity: sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==} + engines: {node: '>=12.0.0'} + + hoek@0.8.5: + resolution: {integrity: sha512-NoKdeYUBOlQ7j9dgvT9BEX90rE6HtDkaMFwR6hfOj26LA2Mwyg5026jOpNBhmNrWIGdPnbBK3sQJI3POwh8wqg==} + engines: {node: '>=0.8.0'} + deprecated: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial). + + hoek@0.9.1: + resolution: {integrity: sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==} + engines: {node: '>=0.8.0'} + deprecated: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial). + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + http-signature@0.9.11: + resolution: {integrity: sha512-OleF+71prrzyaWDTfTXWvv24N/45SjKCPu/3pzzhj8+MgdGaB7Am3NY0ot5uynrzgTwyQ+yoejuFCncCQxyRSA==} + engines: {node: '>=0.8'} + + import-meta-resolve@4.1.0: + resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-absolute-url@4.0.1: + resolution: {integrity: sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jiti@1.21.6: + resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} + hasBin: true + + json-stringify-safe@4.0.0: + resolution: {integrity: sha512-qzEpz1SDUb9xvA+LDOkNgjekdV7tuC7zDQf14sqMBtujh8kVbQhF11VWm4DeR99yFNjVSjTTfKa40c9ZQOtwXA==} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + lilconfig@3.1.2: + resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + + lodash.castarray@4.4.0: + resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lucide-svelte@0.309.0: + resolution: {integrity: sha512-+t85+5Y696FVDoJHiiMhJGalv+UiWUX46gMudOQfYrVGjsyC2MGSZRNAGAHkdykA4RJSh/wUtSgnTgCmd0Swvw==} + peerDependencies: + svelte: '>=3 <5' + + magic-string@0.30.12: + resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} + + magic-string@0.30.14: + resolution: {integrity: sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==} + + marked@15.0.1: + resolution: {integrity: sha512-VnnE19XO2Vb2oZeH8quAepfrb6Aaz4OoY8yZQACfuy/5KVJ0GxYC0Qxzz/iuc+g5UF7H0HJ+QROfvH26XeBdDA==} + engines: {node: '>= 18'} + hasBin: true + + mdast-util-to-hast@13.2.0: + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + + mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + + mdsvex@0.11.2: + resolution: {integrity: sha512-Y4ab+vLvTJS88196Scb/RFNaHMHVSWw6CwfsgWIQP8f42D57iDII0/qABSu530V4pkv8s6T2nx3ds0MC1VwFLA==} + peerDependencies: + svelte: ^3.56.0 || ^4.0.0 || ^5.0.0-next.120 + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.1: + resolution: {integrity: sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime@1.2.11: + resolution: {integrity: sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==} + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + mini-svg-data-uri@1.4.4: + resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} + hasBin: true + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + mrmime@2.0.0: + resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + + node-uuid@1.4.8: + resolution: {integrity: sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==} + deprecated: Use uuid module instead + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + oauth-sign@0.3.0: + resolution: {integrity: sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parse5@7.2.1: + resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + periscopic@3.1.0: + resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.0.1: + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-load-config@5.1.0: + resolution: {integrity: sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + + prism-svelte@0.4.7: + resolution: {integrity: sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==} + + prismjs@1.29.0: + resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} + engines: {node: '>=6'} + + property-information@6.5.0: + resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} + + purgecss@6.0.0: + resolution: {integrity: sha512-s3EBxg5RSWmpqd0KGzNqPiaBbWDz1/As+2MzoYVGMqgDqRTLBhJW6sywfTBek7OwNfoS/6pS0xdtvChNhFj2cw==} + hasBin: true + + qs@0.6.6: + resolution: {integrity: sha512-kN+yNdAf29Jgp+AYHUmC7X4QdJPR8czuMWLNLc0aRxkQ7tB3vJQEONKKT9ou/rW7EbqVec11srC9q9BiVbcnHA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + rehype-autolink-headings@7.1.0: + resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==} + + rehype-external-links@3.0.0: + resolution: {integrity: sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==} + + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + + rehype-slug@6.0.0: + resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==} + + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + rehype-unwrap-images@1.0.0: + resolution: {integrity: sha512-wzW5Mk9IlVF2UwXC5NtIZsx1aHYbV8+bLWjJnlZaaamz5QU52RppWtq1uEZJqGo8d9Y4RuDqidB6r9RFpKugIg==} + + rehype@13.0.2: + resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} + + request@2.21.0: + resolution: {integrity: sha512-jvDa6FC46ystc0cn+EqtJ4B32SSz/cMX7fEIv0UHX4wsYAKJYXjA5EyAMWpRQ+hWCnX9jPD1b4o7xZ/r1Tyx/Q==} + engines: {'0': node >= 0.8.0} + deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rollup@4.27.2: + resolution: {integrity: sha512-KreA+PzWmk2yaFmZVwe6GB2uBD86nXl86OsDkt1bJS9p3vqWuEQ6HnJJ+j/mZi/q0920P99/MVRlB4L3crpF5w==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + + sander@0.5.1: + resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} + + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sirv@3.0.0: + resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==} + engines: {node: '>=18'} + + sntp@0.2.4: + resolution: {integrity: sha512-bDLrKa/ywz65gCl+LmOiIhteP1bhEsAAzhfMedPoiHP3dyYnAevlaJshdqb9Yu0sRifyP/fRqSt8t+5qGIWlGQ==} + engines: {node: '>=0.8.0'} + deprecated: This module moved to @hapi/sntp. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues. + + sorcery@0.11.1: + resolution: {integrity: sha512-o7npfeJE6wi6J9l0/5LKshFzZ2rMatRiCDwYeDQaOzqdzRJwALhX7mk/A/ecg6wjMu7wdZbmXfD2S/vpOg0bdQ==} + hasBin: true + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string@1.4.0: + resolution: {integrity: sha512-9j9fk92vTPEvp4Z1DDicJsePH4nxZgYJtQFTO/6bSGIqR8A6jm54PivMV1H/vtpCyEIlg7Cz31msXMcq9tm2sA==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + svelte-check@3.8.6: + resolution: {integrity: sha512-ij0u4Lw/sOTREP13BdWZjiXD/BlHE6/e2e34XzmVmsp5IN4kVa3PWP65NM32JAgwjZlwBg/+JtiNV1MM8khu0Q==} + hasBin: true + peerDependencies: + svelte: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 + + svelte-hmr@0.16.0: + resolution: {integrity: sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==} + engines: {node: ^12.20 || ^14.13.1 || >= 16} + peerDependencies: + svelte: ^3.19.0 || ^4.0.0 + + svelte-preprocess@5.1.4: + resolution: {integrity: sha512-IvnbQ6D6Ao3Gg6ftiM5tdbR6aAETwjhHV+UKGf5bHGYR69RQvF1ho0JKPcbUON4vy4R7zom13jPjgdOWCQ5hDA==} + engines: {node: '>= 16.0.0'} + peerDependencies: + '@babel/core': ^7.10.2 + coffeescript: ^2.5.1 + less: ^3.11.3 || ^4.0.0 + postcss: ^7 || ^8 + postcss-load-config: ^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 + pug: ^3.0.0 + sass: ^1.26.8 + stylus: ^0.55.0 + sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0 + svelte: ^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 + typescript: '>=3.9.5 || ^4.0.0 || ^5.0.0' + peerDependenciesMeta: + '@babel/core': + optional: true + coffeescript: + optional: true + less: + optional: true + postcss: + optional: true + postcss-load-config: + optional: true + pug: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + typescript: + optional: true + + svelte-youtube-embed@0.3.3: + resolution: {integrity: sha512-g4+53JauVB+Jwz486lVqW8PUTnoP1SinECWhmQSCaKuh6zrYiAOFRpzMG6vW1TaQfSigiLWyUactFWipo4lsfQ==} + peerDependencies: + svelte: ^4.0.0 + + svelte@4.2.19: + resolution: {integrity: sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==} + engines: {node: '>=16'} + + tailwind-merge@2.5.4: + resolution: {integrity: sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==} + + tailwindcss@3.4.15: + resolution: {integrity: sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==} + engines: {node: '>=14.0.0'} + hasBin: true + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tiny-glob@0.2.9: + resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tunnel-agent@0.3.0: + resolution: {integrity: sha512-jlGqHGoKzyyjhwv/c9omAgohntThMcGtw8RV/RDLlkbbc08kni/akVxO62N8HaXMVbVsK1NCnpSK3N2xCt22ww==} + + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.0: + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@2.0.3: + resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.1: + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@2.0.4: + resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} + + vfile-message@4.0.2: + resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite-plugin-tailwind-purgecss@0.2.1: + resolution: {integrity: sha512-pJevMPGyEve5Z/KCXEbYiw7I11Skt+ZAc+GGa8HcJy4d+8OAzgYG3rdvv3NZOT3IJyErSGoLb8dFxj9elPudtw==} + peerDependencies: + vite: ^4.1.1 || ^5.0.0 + + vite@5.4.11: + resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitefu@0.2.5: + resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + vite: + optional: true + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + yaml@2.6.0: + resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==} + engines: {node: '>= 14'} + hasBin: true + + youtube-transcript@1.2.1: + resolution: {integrity: sha512-TvEGkBaajKw+B6y91ziLuBLsa5cawgowou+Bk0ciGpjELDfAzSzTGXaZmeSSkUeknCPpEr/WGApOHDwV7V+Y9Q==} + engines: {node: '>=18.0.0'} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@floating-ui/core@1.6.8': + dependencies: + '@floating-ui/utils': 0.2.8 + + '@floating-ui/dom@1.6.12': + dependencies: + '@floating-ui/core': 1.6.8 + '@floating-ui/utils': 0.2.8 + + '@floating-ui/utils@0.2.8': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@polka/url@1.0.0-next.28': {} + + '@rollup/rollup-android-arm-eabi@4.27.2': + optional: true + + '@rollup/rollup-android-arm64@4.27.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.27.2': + optional: true + + '@rollup/rollup-darwin-x64@4.27.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.27.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.27.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.27.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.27.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.27.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.27.2': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.27.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.27.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.27.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.27.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.27.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.27.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.27.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.27.2': + optional: true + + '@skeletonlabs/skeleton@2.10.3(svelte@4.2.19)': + dependencies: + esm-env: 1.0.0 + svelte: 4.2.19 + + '@skeletonlabs/tw-plugin@0.3.1(tailwindcss@3.4.15)': + dependencies: + tailwindcss: 3.4.15 + + '@sveltejs/adapter-auto@3.3.1(@sveltejs/kit@2.8.4(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)))(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)))': + dependencies: + '@sveltejs/kit': 2.8.4(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)))(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)) + import-meta-resolve: 4.1.0 + + '@sveltejs/kit@2.8.4(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)))(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6))': + dependencies: + '@sveltejs/vite-plugin-svelte': 3.1.2(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)) + '@types/cookie': 0.6.0 + cookie: 0.6.0 + devalue: 5.1.1 + esm-env: 1.1.4 + import-meta-resolve: 4.1.0 + kleur: 4.1.5 + magic-string: 0.30.14 + mrmime: 2.0.0 + sade: 1.8.1 + set-cookie-parser: 2.7.1 + sirv: 3.0.0 + svelte: 4.2.19 + tiny-glob: 0.2.9 + vite: 5.4.11(@types/node@20.17.6) + + '@sveltejs/vite-plugin-svelte-inspector@2.1.0(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)))(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6))': + dependencies: + '@sveltejs/vite-plugin-svelte': 3.1.2(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)) + debug: 4.3.7 + svelte: 4.2.19 + vite: 5.4.11(@types/node@20.17.6) + transitivePeerDependencies: + - supports-color + + '@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 2.1.0(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)))(svelte@4.2.19)(vite@5.4.11(@types/node@20.17.6)) + debug: 4.3.7 + deepmerge: 4.3.1 + kleur: 4.1.5 + magic-string: 0.30.12 + svelte: 4.2.19 + svelte-hmr: 0.16.0(svelte@4.2.19) + vite: 5.4.11(@types/node@20.17.6) + vitefu: 0.2.5(vite@5.4.11(@types/node@20.17.6)) + transitivePeerDependencies: + - supports-color + + '@tailwindcss/forms@0.5.9(tailwindcss@3.4.15)': + dependencies: + mini-svg-data-uri: 1.4.4 + tailwindcss: 3.4.15 + + '@tailwindcss/typography@0.5.15(tailwindcss@3.4.15)': + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.15 + + '@types/cookie@0.6.0': {} + + '@types/estree@1.0.6': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 2.0.11 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/node@20.17.6': + dependencies: + undici-types: 6.19.8 + + '@types/pug@2.0.10': {} + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@ungap/structured-clone@1.2.0': {} + + acorn@8.14.0: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@5.0.2: {} + + aria-query@5.3.2: {} + + asn1@0.1.11: {} + + assert-plus@0.1.2: {} + + async@0.2.10: {} + + autoprefixer@10.4.20(postcss@8.4.49): + dependencies: + browserslist: 4.24.2 + caniuse-lite: 1.0.30001680 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.4.49 + postcss-value-parser: 4.2.0 + + aws-sign@0.3.0: {} + + axobject-query@4.1.0: {} + + bail@2.0.2: {} + + balanced-match@1.0.2: {} + + binary-extensions@2.3.0: {} + + boom@0.4.2: + dependencies: + hoek: 0.9.1 + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.24.2: + dependencies: + caniuse-lite: 1.0.30001680 + electron-to-chromium: 1.5.62 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.2) + + buffer-crc32@1.0.0: {} + + camelcase-css@2.0.1: {} + + caniuse-lite@1.0.30001680: {} + + ccount@2.0.1: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + clsx@2.1.1: {} + + cn@0.1.1: + dependencies: + request: 2.21.0 + string: 1.4.0 + + code-red@1.0.4: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + '@types/estree': 1.0.6 + acorn: 8.14.0 + estree-walker: 3.0.3 + periscopic: 3.1.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@0.0.7: + dependencies: + delayed-stream: 0.0.5 + + comma-separated-tokens@2.0.3: {} + + commander@12.1.0: {} + + commander@4.1.1: {} + + concat-map@0.0.1: {} + + cookie-jar@0.3.0: {} + + cookie@0.6.0: {} + + cross-spawn@7.0.5: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cryptiles@0.2.2: + dependencies: + boom: 0.4.2 + + css-tree@2.3.1: + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.2.1 + + cssesc@3.0.0: {} + + ctype@0.5.2: {} + + date-fns@4.1.0: {} + + debug@4.3.7: + dependencies: + ms: 2.1.3 + + deepmerge@4.3.1: {} + + delayed-stream@0.0.5: {} + + dequal@2.0.3: {} + + detect-indent@6.1.0: {} + + devalue@5.1.1: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + didyoumean@1.2.2: {} + + dlv@1.1.3: {} + + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.5.62: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + entities@4.5.0: {} + + es6-promise@3.3.1: {} + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + escalade@3.2.0: {} + + esm-env@1.0.0: {} + + esm-env@1.1.4: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.6 + + extend@3.0.2: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + foreground-child@3.3.0: + dependencies: + cross-spawn: 7.0.5 + signal-exit: 4.1.0 + + forever-agent@0.5.2: {} + + form-data@0.0.8: + dependencies: + async: 0.2.10 + combined-stream: 0.0.7 + mime: 1.2.11 + + fraction.js@4.3.7: {} + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + github-slugger@2.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globalyzer@0.1.0: {} + + globrex@0.1.2: {} + + graceful-fs@4.2.11: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.1 + parse5: 7.2.1 + vfile: 6.0.3 + vfile-message: 4.0.2 + + hast-util-from-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 8.0.0 + property-information: 6.5.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-has-property@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-heading-rank@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-interactive@3.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-has-property: 3.0.0 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-to-html@9.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + property-information: 6.5.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-string@3.0.1: + dependencies: + '@types/hast': 3.0.4 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@8.0.0: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 6.5.0 + space-separated-tokens: 2.0.2 + + hawk@0.13.1: + dependencies: + boom: 0.4.2 + cryptiles: 0.2.2 + hoek: 0.8.5 + sntp: 0.2.4 + + highlight.js@11.10.0: {} + + hoek@0.8.5: {} + + hoek@0.9.1: {} + + html-void-elements@3.0.0: {} + + http-signature@0.9.11: + dependencies: + asn1: 0.1.11 + assert-plus: 0.1.2 + ctype: 0.5.2 + + import-meta-resolve@4.1.0: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-absolute-url@4.0.1: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-core-module@2.15.1: + dependencies: + hasown: 2.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-plain-obj@4.1.0: {} + + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.6 + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jiti@1.21.6: {} + + json-stringify-safe@4.0.0: {} + + kleur@4.1.5: {} + + lilconfig@2.1.0: {} + + lilconfig@3.1.2: {} + + lines-and-columns@1.2.4: {} + + locate-character@3.0.0: {} + + lodash.castarray@4.4.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.merge@4.6.2: {} + + lru-cache@10.4.3: {} + + lucide-svelte@0.309.0(svelte@4.2.19): + dependencies: + svelte: 4.2.19 + + magic-string@0.30.12: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + magic-string@0.30.14: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + marked@15.0.1: {} + + mdast-util-to-hast@13.2.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.2.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + + mdn-data@2.0.30: {} + + mdsvex@0.11.2(svelte@4.2.19): + dependencies: + '@types/unist': 2.0.11 + prism-svelte: 0.4.7 + prismjs: 1.29.0 + svelte: 4.2.19 + vfile-message: 2.0.4 + + merge2@1.4.1: {} + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime@1.2.11: {} + + min-indent@1.0.1: {} + + mini-svg-data-uri@1.4.4: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + minipass@7.1.2: {} + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mri@1.2.0: {} + + mrmime@2.0.0: {} + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.7: {} + + node-releases@2.0.18: {} + + node-uuid@1.4.8: {} + + normalize-path@3.0.0: {} + + normalize-range@0.1.2: {} + + oauth-sign@0.3.0: {} + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + package-json-from-dist@1.0.1: {} + + parse5@7.2.1: + dependencies: + entities: 4.5.0 + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + periscopic@3.1.0: + dependencies: + '@types/estree': 1.0.6 + estree-walker: 3.0.3 + is-reference: 3.0.3 + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pify@2.3.0: {} + + pirates@4.0.6: {} + + postcss-import@15.1.0(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + + postcss-js@4.0.1(postcss@8.4.49): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.49 + + postcss-load-config@4.0.2(postcss@8.4.49): + dependencies: + lilconfig: 3.1.2 + yaml: 2.6.0 + optionalDependencies: + postcss: 8.4.49 + + postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.49): + dependencies: + lilconfig: 3.1.2 + yaml: 2.6.0 + optionalDependencies: + jiti: 1.21.6 + postcss: 8.4.49 + + postcss-nested@6.2.0(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.4.49: + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prism-svelte@0.4.7: {} + + prismjs@1.29.0: {} + + property-information@6.5.0: {} + + purgecss@6.0.0: + dependencies: + commander: 12.1.0 + glob: 10.4.5 + postcss: 8.4.49 + postcss-selector-parser: 6.1.2 + + qs@0.6.6: {} + + queue-microtask@1.2.3: {} + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + rehype-autolink-headings@7.1.0: + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.2.0 + hast-util-heading-rank: 3.0.0 + hast-util-is-element: 3.0.0 + unified: 11.0.5 + unist-util-visit: 5.0.0 + + rehype-external-links@3.0.0: + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.2.0 + hast-util-is-element: 3.0.0 + is-absolute-url: 4.0.1 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.0.0 + + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-slug@6.0.0: + dependencies: + '@types/hast': 3.0.4 + github-slugger: 2.0.0 + hast-util-heading-rank: 3.0.0 + hast-util-to-string: 3.0.1 + unist-util-visit: 5.0.0 + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.3 + unified: 11.0.5 + + rehype-unwrap-images@1.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-interactive: 3.0.0 + hast-util-whitespace: 3.0.0 + unist-util-visit: 5.0.0 + + rehype@13.0.2: + dependencies: + '@types/hast': 3.0.4 + rehype-parse: 9.0.1 + rehype-stringify: 10.0.1 + unified: 11.0.5 + + request@2.21.0: + dependencies: + aws-sign: 0.3.0 + cookie-jar: 0.3.0 + forever-agent: 0.5.2 + form-data: 0.0.8 + hawk: 0.13.1 + http-signature: 0.9.11 + json-stringify-safe: 4.0.0 + mime: 1.2.11 + node-uuid: 1.4.8 + oauth-sign: 0.3.0 + qs: 0.6.6 + tunnel-agent: 0.3.0 + + resolve@1.22.8: + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.0.4: {} + + rimraf@2.7.1: + dependencies: + glob: 7.2.3 + + rollup@4.27.2: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.27.2 + '@rollup/rollup-android-arm64': 4.27.2 + '@rollup/rollup-darwin-arm64': 4.27.2 + '@rollup/rollup-darwin-x64': 4.27.2 + '@rollup/rollup-freebsd-arm64': 4.27.2 + '@rollup/rollup-freebsd-x64': 4.27.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.27.2 + '@rollup/rollup-linux-arm-musleabihf': 4.27.2 + '@rollup/rollup-linux-arm64-gnu': 4.27.2 + '@rollup/rollup-linux-arm64-musl': 4.27.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.27.2 + '@rollup/rollup-linux-riscv64-gnu': 4.27.2 + '@rollup/rollup-linux-s390x-gnu': 4.27.2 + '@rollup/rollup-linux-x64-gnu': 4.27.2 + '@rollup/rollup-linux-x64-musl': 4.27.2 + '@rollup/rollup-win32-arm64-msvc': 4.27.2 + '@rollup/rollup-win32-ia32-msvc': 4.27.2 + '@rollup/rollup-win32-x64-msvc': 4.27.2 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + sade@1.8.1: + dependencies: + mri: 1.2.0 + + sander@0.5.1: + dependencies: + es6-promise: 3.3.1 + graceful-fs: 4.2.11 + mkdirp: 0.5.6 + rimraf: 2.7.1 + + set-cookie-parser@2.7.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + + sirv@3.0.0: + dependencies: + '@polka/url': 1.0.0-next.28 + mrmime: 2.0.0 + totalist: 3.0.1 + + sntp@0.2.4: + dependencies: + hoek: 0.9.1 + + sorcery@0.11.1: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + buffer-crc32: 1.0.0 + minimist: 1.2.8 + sander: 0.5.1 + + source-map-js@1.2.1: {} + + space-separated-tokens@2.0.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string@1.4.0: {} + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + + supports-preserve-symlinks-flag@1.0.0: {} + + svelte-check@3.8.6(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.49))(postcss@8.4.49)(svelte@4.2.19): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + chokidar: 3.6.0 + picocolors: 1.1.1 + sade: 1.8.1 + svelte: 4.2.19 + svelte-preprocess: 5.1.4(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.49))(postcss@8.4.49)(svelte@4.2.19)(typescript@5.6.3) + typescript: 5.6.3 + transitivePeerDependencies: + - '@babel/core' + - coffeescript + - less + - postcss + - postcss-load-config + - pug + - sass + - stylus + - sugarss + + svelte-hmr@0.16.0(svelte@4.2.19): + dependencies: + svelte: 4.2.19 + + svelte-preprocess@5.1.4(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.49))(postcss@8.4.49)(svelte@4.2.19)(typescript@5.6.3): + dependencies: + '@types/pug': 2.0.10 + detect-indent: 6.1.0 + magic-string: 0.30.14 + sorcery: 0.11.1 + strip-indent: 3.0.0 + svelte: 4.2.19 + optionalDependencies: + postcss: 8.4.49 + postcss-load-config: 5.1.0(jiti@1.21.6)(postcss@8.4.49) + typescript: 5.6.3 + + svelte-youtube-embed@0.3.3(svelte@4.2.19): + dependencies: + svelte: 4.2.19 + + svelte@4.2.19: + dependencies: + '@ampproject/remapping': 2.3.0 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + '@types/estree': 1.0.6 + acorn: 8.14.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + code-red: 1.0.4 + css-tree: 2.3.1 + estree-walker: 3.0.3 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.12 + periscopic: 3.1.0 + + tailwind-merge@2.5.4: {} + + tailwindcss@3.4.15: + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.6 + lilconfig: 2.1.0 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.4.49 + postcss-import: 15.1.0(postcss@8.4.49) + postcss-js: 4.0.1(postcss@8.4.49) + postcss-load-config: 4.0.2(postcss@8.4.49) + postcss-nested: 6.2.0(postcss@8.4.49) + postcss-selector-parser: 6.1.2 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tiny-glob@0.2.9: + dependencies: + globalyzer: 0.1.0 + globrex: 0.1.2 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + totalist@3.0.1: {} + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + ts-interface-checker@0.1.13: {} + + tunnel-agent@0.3.0: {} + + typescript@5.6.3: {} + + undici-types@6.19.8: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-is@6.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@2.0.3: + dependencies: + '@types/unist': 2.0.11 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.1: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + + update-browserslist-db@1.1.1(browserslist@4.24.2): + dependencies: + browserslist: 4.24.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + util-deprecate@1.0.2: {} + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@2.0.4: + dependencies: + '@types/unist': 2.0.11 + unist-util-stringify-position: 2.0.3 + + vfile-message@4.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.2 + + vite-plugin-tailwind-purgecss@0.2.1(vite@5.4.11(@types/node@20.17.6)): + dependencies: + estree-walker: 3.0.3 + purgecss: 6.0.0 + vite: 5.4.11(@types/node@20.17.6) + + vite@5.4.11(@types/node@20.17.6): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.49 + rollup: 4.27.2 + optionalDependencies: + '@types/node': 20.17.6 + fsevents: 2.3.3 + + vitefu@0.2.5(vite@5.4.11(@types/node@20.17.6)): + optionalDependencies: + vite: 5.4.11(@types/node@20.17.6) + + web-namespaces@2.0.1: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + yaml@2.6.0: {} + + youtube-transcript@1.2.1: {} + + zwitch@2.0.4: {} diff --git a/web/postcss.config.cjs b/web/postcss.config.cjs new file mode 100644 index 00000000..16dce0bc --- /dev/null +++ b/web/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} \ No newline at end of file diff --git a/web/postcss.config.js b/web/postcss.config.js new file mode 100644 index 00000000..d909f4b3 --- /dev/null +++ b/web/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {} + } +}; \ No newline at end of file diff --git a/web/rollup.config.js b/web/rollup.config.js new file mode 100644 index 00000000..ddf9cb20 --- /dev/null +++ b/web/rollup.config.js @@ -0,0 +1,22 @@ +import svelte from 'rollup-plugin-svelte'; +import resolve from '@rollup/plugin-node-resolve'; + +export default { + input: 'src/+page.js', + output: { + file: 'public/bundle.js', + format: 'iife', + name: 'app' + }, + plugins: [ + svelte({ + // svelte options + extensions: [".svelte", ".svx", ".md"], + preprocess: mdsvex() + }), + resolve({ + browser: true, + dedupe: ['svelte'] + }) + ] +}; \ No newline at end of file diff --git a/web/src/app.css b/web/src/app.css new file mode 100644 index 00000000..07b37665 --- /dev/null +++ b/web/src/app.css @@ -0,0 +1,134 @@ +/* @tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, + Cantarell, 'Go Mono', 'Fira Sans', 'Helvetica Neue', sans-serif; + --font-mono: 'Fira Code', monospace; + --column-width: 42rem; + --column-margin-top: 4rem; +} */ + +/* Light theme variables */ +/* :root { + --background: hsl(249, 81%, 85%); + --foreground: hsl(229, 65%, 29%); + --card: 0 0% 100%; + --card-foreground: 224 71.4% 4.1%; + --popover: 0 0% 100%; + --popover-foreground: 224 71.4% 4.1%; + --primary: hsl(262.1 83.3% 57.8%); + --primary-foreground: hsl(274, 100%, 90%); + --secondary: hsl(173, 74%, 68%); + --secondary-foreground: hsl(195, 100%, 90%); + --muted: 220 14.3% 95.9%; + --muted-foreground: 220 8.9% 46.1%; + --accent: hsl(220, 37%, 49%); + --accent-foreground: 220.9 39.3% 11%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 20% 98%; + --border: 220 13% 91%; + --input: 220 13% 91%; + --ring: 262.1 83.3% 57.8%; + --radius: 0.5rem; +} */ + +/* Dark theme variables */ +/* .dark { + --background: 224 71.4% 4.1%; + --foreground: 210 20% 98%; + --card: 224 71.4% 4.1%; + --card-foreground: 210 20% 98%; + --popover: 224 71.4% 4.1%; + --popover-foreground: 210 20% 98%; + --primary: 263.4 70% 50.4%; + --primary-foreground: 210 20% 98%; + --secondary: 215 27.9% 16.9%; + --secondary-foreground: 210 20% 98%; + --muted: 215 27.9% 16.9%; + --muted-foreground: 217.9 10.6% 64.9%; + --accent: 215 27.9% 16.9%; + --accent-foreground: 210 20% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 20% 98%; + --border: 215 27.9% 16.9%; + --input: 215 27.9% 16.9%; + --ring: 263.4 70% 50.4%; +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + font-feature-settings: "rlig" 1, "calt" 1; + } */ + + /* Enhanced Typography */ +/* h1, h2, h3, h4, h5, h6 { + @apply font-semibold tracking-tight; + } + + h1 { + @apply text-4xl lg:text-5xl; + } + + h2 { + @apply text-3xl lg:text-4xl; + } + + h3 { + @apply text-2xl lg:text-3xl; + } + + p { + @apply leading-7; + } + */ + /* Links */ +/* a { + @apply text-primary hover:text-primary/80 transition-colors; + } */ + + /* Code blocks */ +/* pre { + @apply p-4 rounded-lg bg-muted/50 font-mono text-sm; + } + + code { + @apply font-mono text-sm; + } + */ + /* Terminal specific styles */ +/* .terminal-window { + @apply rounded-lg border bg-card shadow-lg overflow-hidden; + } + + .terminal-text { + @apply font-mono text-sm; + } + */ + /* Form elements */ +/* input, textarea, select { + @apply rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2; + } + + button { + @apply inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2; + } +} */ + +/* Custom scrollbar */ +/* ::-webkit-scrollbar { + @apply w-2; +} + +::-webkit-scrollbar-track { + @apply bg-muted; +} + +::-webkit-scrollbar-thumb { + @apply bg-muted-foreground/30 rounded-full hover:bg-muted-foreground/50 transition-colors; +} */ \ No newline at end of file diff --git a/web/src/app.d.ts b/web/src/app.d.ts new file mode 100644 index 00000000..18008b3e --- /dev/null +++ b/web/src/app.d.ts @@ -0,0 +1,9 @@ +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +// and what to do when importing types +declare namespace App { + // interface Locals {} + interface PageData {} + // interface Error {} + // interface Platform {} +} diff --git a/web/src/app.html b/web/src/app.html new file mode 100644 index 00000000..8ec7b214 --- /dev/null +++ b/web/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + \ No newline at end of file diff --git a/web/src/app.postcss b/web/src/app.postcss new file mode 100644 index 00000000..6c7bc390 --- /dev/null +++ b/web/src/app.postcss @@ -0,0 +1,25 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; +@tailwind variants; + +html, +body { + @apply h-full overflow-hidden; +} + +.terminal-output { + @apply font-mono text-sm; +} + +.terminal-input { + @apply font-mono text-sm; +} + +/* Skeleton theme overrides */ +:root [data-theme='skeleton'] { + --theme-font-family-base: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, + Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + --theme-font-family-heading: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; +} \ No newline at end of file diff --git a/web/src/index.test.ts b/web/src/index.test.ts new file mode 100644 index 00000000..e07cbbd7 --- /dev/null +++ b/web/src/index.test.ts @@ -0,0 +1,7 @@ +import { describe, it, expect } from 'vitest'; + +describe('sum test', () => { + it('adds 1 + 2 to equal 3', () => { + expect(1 + 2).toBe(3); + }); +}); diff --git a/web/src/lib/components/ui/button/button.svelte b/web/src/lib/components/ui/button/button.svelte new file mode 100644 index 00000000..8c3c7827 --- /dev/null +++ b/web/src/lib/components/ui/button/button.svelte @@ -0,0 +1,26 @@ + + + \ No newline at end of file diff --git a/web/src/lib/components/ui/button/index.js b/web/src/lib/components/ui/button/index.js new file mode 100644 index 00000000..14f6ad36 --- /dev/null +++ b/web/src/lib/components/ui/button/index.js @@ -0,0 +1,31 @@ +import Root from "./button.svelte"; + +const buttonVariants = { + base: "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50", + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90 shadow", + destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm", + outline: "border-input bg-background hover:bg-accent hover:text-accent-foreground border shadow-sm", + secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-sm", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline" + }, + size: { + default: "h-9 px-4 py-2", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9" + } + }, + defaultVariants: { + variant: "default", + size: "default" + } +}; + +export { + Root, + Root as Button, + buttonVariants +}; \ No newline at end of file diff --git a/web/src/lib/components/ui/buymeacoffee/BuyMeCoffee.svelte b/web/src/lib/components/ui/buymeacoffee/BuyMeCoffee.svelte new file mode 100644 index 00000000..e52fac18 --- /dev/null +++ b/web/src/lib/components/ui/buymeacoffee/BuyMeCoffee.svelte @@ -0,0 +1,32 @@ + + + + + + + + + + + {text} + diff --git a/web/src/lib/components/ui/input/index.ts b/web/src/lib/components/ui/input/index.ts new file mode 100644 index 00000000..dc3324a4 --- /dev/null +++ b/web/src/lib/components/ui/input/index.ts @@ -0,0 +1,6 @@ +import Root from "./input.svelte"; +export { + Root, + // + Root as Input, +}; diff --git a/web/src/lib/components/ui/input/input.svelte b/web/src/lib/components/ui/input/input.svelte new file mode 100644 index 00000000..61cbf1f7 --- /dev/null +++ b/web/src/lib/components/ui/input/input.svelte @@ -0,0 +1,33 @@ + + + diff --git a/web/src/lib/components/ui/label/index.js b/web/src/lib/components/ui/label/index.js new file mode 100644 index 00000000..df598980 --- /dev/null +++ b/web/src/lib/components/ui/label/index.js @@ -0,0 +1,6 @@ +import Root from "./label.svelte"; + +export { + Root, + Root as Label +}; \ No newline at end of file diff --git a/web/src/lib/components/ui/label/label.svelte b/web/src/lib/components/ui/label/label.svelte new file mode 100644 index 00000000..670ab8b7 --- /dev/null +++ b/web/src/lib/components/ui/label/label.svelte @@ -0,0 +1,15 @@ + + + \ No newline at end of file diff --git a/web/src/lib/components/ui/select/index.js b/web/src/lib/components/ui/select/index.js new file mode 100644 index 00000000..18efe40b --- /dev/null +++ b/web/src/lib/components/ui/select/index.js @@ -0,0 +1,6 @@ +import Root from "./select.svelte"; + +export { + Root, + Root as Select +}; \ No newline at end of file diff --git a/web/src/lib/components/ui/select/select-content.svelte b/web/src/lib/components/ui/select/select-content.svelte new file mode 100644 index 00000000..f462701f --- /dev/null +++ b/web/src/lib/components/ui/select/select-content.svelte @@ -0,0 +1,30 @@ + + +
+ +
+ +
+
+
\ No newline at end of file diff --git a/web/src/lib/components/ui/select/select-item.svelte b/web/src/lib/components/ui/select/select-item.svelte new file mode 100644 index 00000000..3b310e67 --- /dev/null +++ b/web/src/lib/components/ui/select/select-item.svelte @@ -0,0 +1,16 @@ + + + \ No newline at end of file diff --git a/web/src/lib/components/ui/select/select-label.svelte b/web/src/lib/components/ui/select/select-label.svelte new file mode 100644 index 00000000..24e5d2f9 --- /dev/null +++ b/web/src/lib/components/ui/select/select-label.svelte @@ -0,0 +1,10 @@ + + + + + diff --git a/web/src/lib/components/ui/select/select-separator.svelte b/web/src/lib/components/ui/select/select-separator.svelte new file mode 100644 index 00000000..7088e938 --- /dev/null +++ b/web/src/lib/components/ui/select/select-separator.svelte @@ -0,0 +1,8 @@ + + + diff --git a/web/src/lib/components/ui/select/select-trigger.svelte b/web/src/lib/components/ui/select/select-trigger.svelte new file mode 100644 index 00000000..044961b6 --- /dev/null +++ b/web/src/lib/components/ui/select/select-trigger.svelte @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/web/src/lib/components/ui/select/select-value.svelte b/web/src/lib/components/ui/select/select-value.svelte new file mode 100644 index 00000000..0b47df50 --- /dev/null +++ b/web/src/lib/components/ui/select/select-value.svelte @@ -0,0 +1,18 @@ + + + + + \ No newline at end of file diff --git a/web/src/lib/components/ui/select/select.svelte b/web/src/lib/components/ui/select/select.svelte new file mode 100644 index 00000000..16610570 --- /dev/null +++ b/web/src/lib/components/ui/select/select.svelte @@ -0,0 +1,24 @@ + + +
+ + +
\ No newline at end of file diff --git a/web/src/lib/components/ui/slider/index.js b/web/src/lib/components/ui/slider/index.js new file mode 100644 index 00000000..2618c1a9 --- /dev/null +++ b/web/src/lib/components/ui/slider/index.js @@ -0,0 +1,6 @@ +import Root from "./slider.svelte"; +export { + Root, + // + Root as Slider, +}; diff --git a/web/src/lib/components/ui/slider/slider.svelte b/web/src/lib/components/ui/slider/slider.svelte new file mode 100644 index 00000000..ad080c68 --- /dev/null +++ b/web/src/lib/components/ui/slider/slider.svelte @@ -0,0 +1,89 @@ + + +
+
+
+
+
+
\ No newline at end of file diff --git a/web/src/lib/components/ui/spinner/spinner.svelte b/web/src/lib/components/ui/spinner/spinner.svelte new file mode 100644 index 00000000..a16a3fe1 --- /dev/null +++ b/web/src/lib/components/ui/spinner/spinner.svelte @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/web/src/lib/components/ui/tag-list/TagList.svelte b/web/src/lib/components/ui/tag-list/TagList.svelte new file mode 100644 index 00000000..fb1ba7ce --- /dev/null +++ b/web/src/lib/components/ui/tag-list/TagList.svelte @@ -0,0 +1,66 @@ + + +
+ {#if totalPages > 1 && canGoBack} + + {/if} + +
+ {#each visibleTags as tag (tag)} + + {tag} + + {/each} +
+ + {#if totalPages > 1 && canGoForward} + + {/if} +
\ No newline at end of file diff --git a/web/src/lib/components/ui/textarea/index.js b/web/src/lib/components/ui/textarea/index.js new file mode 100644 index 00000000..4e396e12 --- /dev/null +++ b/web/src/lib/components/ui/textarea/index.js @@ -0,0 +1,6 @@ +import Root from "./textarea.svelte"; +export { + Root, + // + Root as Textarea, +}; diff --git a/web/src/lib/components/ui/textarea/textarea.svelte b/web/src/lib/components/ui/textarea/textarea.svelte new file mode 100644 index 00000000..87cddb77 --- /dev/null +++ b/web/src/lib/components/ui/textarea/textarea.svelte @@ -0,0 +1,29 @@ + + + diff --git a/web/src/lib/content/.obsidian/app.json b/web/src/lib/content/.obsidian/app.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/web/src/lib/content/.obsidian/app.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/web/src/lib/content/.obsidian/appearance.json b/web/src/lib/content/.obsidian/appearance.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/web/src/lib/content/.obsidian/appearance.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/web/src/lib/content/.obsidian/core-plugins.json b/web/src/lib/content/.obsidian/core-plugins.json new file mode 100644 index 00000000..436f43cf --- /dev/null +++ b/web/src/lib/content/.obsidian/core-plugins.json @@ -0,0 +1,30 @@ +{ + "file-explorer": true, + "global-search": true, + "switcher": true, + "graph": true, + "backlink": true, + "canvas": true, + "outgoing-link": true, + "tag-pane": true, + "properties": false, + "page-preview": true, + "daily-notes": true, + "templates": true, + "note-composer": true, + "command-palette": true, + "slash-command": false, + "editor-status": true, + "bookmarks": true, + "markdown-importer": false, + "zk-prefixer": false, + "random-note": false, + "outline": true, + "word-count": true, + "slides": false, + "audio-recorder": false, + "workspaces": false, + "file-recovery": true, + "publish": false, + "sync": false +} \ No newline at end of file diff --git a/web/src/lib/content/.obsidian/templates.json b/web/src/lib/content/.obsidian/templates.json new file mode 100644 index 00000000..b9ffbd02 --- /dev/null +++ b/web/src/lib/content/.obsidian/templates.json @@ -0,0 +1,5 @@ +{ + "folder": "templates", + "dateFormat": "YYYY-MM-DD", + "timeFormat": "HH:mm" +} \ No newline at end of file diff --git a/web/src/lib/content/.obsidian/types.json b/web/src/lib/content/.obsidian/types.json new file mode 100644 index 00000000..3ca7451a --- /dev/null +++ b/web/src/lib/content/.obsidian/types.json @@ -0,0 +1,8 @@ +{ + "types": { + "aliases": "aliases", + "cssclasses": "multitext", + "tags": "tags", + "updated": "datetime" + } +} \ No newline at end of file diff --git a/web/src/lib/content/.obsidian/workspace.json b/web/src/lib/content/.obsidian/workspace.json new file mode 100644 index 00000000..64233804 --- /dev/null +++ b/web/src/lib/content/.obsidian/workspace.json @@ -0,0 +1,173 @@ +{ + "main": { + "id": "d2e57b203fabd791", + "type": "split", + "children": [ + { + "id": "bede7cd0fb75a7df", + "type": "tabs", + "children": [ + { + "id": "c588c8d12c5f7702", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "templates/{{title}}.md", + "mode": "source", + "source": false + }, + "icon": "lucide-file", + "title": "{{title}}" + } + } + ] + } + ], + "direction": "vertical" + }, + "left": { + "id": "a69ef8c1dea71399", + "type": "split", + "children": [ + { + "id": "99030135b6260693", + "type": "tabs", + "children": [ + { + "id": "bbeb4ea8d01ce855", + "type": "leaf", + "state": { + "type": "file-explorer", + "state": { + "sortOrder": "alphabetical" + }, + "icon": "lucide-folder-closed", + "title": "Files" + } + }, + { + "id": "afc5509c38fa5543", + "type": "leaf", + "state": { + "type": "search", + "state": { + "query": "", + "matchingCase": false, + "explainSearch": false, + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical" + }, + "icon": "lucide-search", + "title": "Search" + } + }, + { + "id": "53c950f1571616a8", + "type": "leaf", + "state": { + "type": "bookmarks", + "state": {}, + "icon": "lucide-bookmark", + "title": "Bookmarks" + } + } + ] + } + ], + "direction": "horizontal", + "width": 300 + }, + "right": { + "id": "74142d853a5fb911", + "type": "split", + "children": [ + { + "id": "065cd0d2b52977db", + "type": "tabs", + "children": [ + { + "id": "398f4b2bc7fb48c1", + "type": "leaf", + "state": { + "type": "backlink", + "state": { + "file": "posts/welcome.md", + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical", + "showSearch": false, + "searchQuery": "", + "backlinkCollapsed": false, + "unlinkedCollapsed": true + }, + "icon": "links-coming-in", + "title": "Backlinks for welcome" + } + }, + { + "id": "655e694ad24637c7", + "type": "leaf", + "state": { + "type": "outgoing-link", + "state": { + "file": "posts/welcome.md", + "linksCollapsed": false, + "unlinkedCollapsed": true + }, + "icon": "links-going-out", + "title": "Outgoing links from welcome" + } + }, + { + "id": "eba769dfb90abcb3", + "type": "leaf", + "state": { + "type": "tag", + "state": { + "sortOrder": "frequency", + "useHierarchy": true + }, + "icon": "lucide-tags", + "title": "Tags" + } + }, + { + "id": "2bcc1385d707df56", + "type": "leaf", + "state": { + "type": "outline", + "state": { + "file": "posts/welcome.md" + }, + "icon": "lucide-list", + "title": "Outline of welcome" + } + } + ] + } + ], + "direction": "horizontal", + "width": 300, + "collapsed": true + }, + "left-ribbon": { + "hiddenItems": { + "switcher:Open quick switcher": false, + "graph:Open graph view": false, + "canvas:Create new canvas": false, + "daily-notes:Open today's daily note": false, + "templates:Insert template": false, + "command-palette:Open command palette": false + } + }, + "active": "c588c8d12c5f7702", + "lastOpenFiles": [ + "posts/welcome.md", + "templates/{{title}}.md", + "posts/SkeletonUI.md", + "posts/getting-started.md", + "posts/extract_wisdom.md" + ] +} \ No newline at end of file diff --git a/web/src/lib/content/posts/SkeletonUI.md b/web/src/lib/content/posts/SkeletonUI.md new file mode 100755 index 00000000..d55bd8d8 --- /dev/null +++ b/web/src/lib/content/posts/SkeletonUI.md @@ -0,0 +1,226 @@ +--- +title: SkeletonUI +tags: +- svelte +- styling +- skeletonui +date: 2023-01-17 +--- +SkeletonUI is a comprehensive UI toolkit that integrates seamlessly with SvelteKit and Tailwind CSS, enabling developers to build adaptive and accessible web interfaces efficiently. + +SkeletonUI offers a comprehensive suite of components to enhance your Svelte applications. Below is a categorized list of these components, presented in Svelte syntax: + +```svelte + + + + +
+ + + + + + + + +
+{/if} + + \ No newline at end of file diff --git a/web/src/routes/contact/+error.svelte b/web/src/routes/contact/+error.svelte new file mode 100644 index 00000000..fbff224c --- /dev/null +++ b/web/src/routes/contact/+error.svelte @@ -0,0 +1,26 @@ + + +
+
+

+ {$page.status}: {$page.error?.message || 'Something went wrong'} +

+

+ {#if $page.status === 404} + Sorry, we couldn't find the post you're looking for. + {:else} + An error occurred while loading the post. Please try again later. + {/if} +

+ +
+
\ No newline at end of file diff --git a/web/src/routes/contact/+page.svelte b/web/src/routes/contact/+page.svelte new file mode 100644 index 00000000..7a7fd467 --- /dev/null +++ b/web/src/routes/contact/+page.svelte @@ -0,0 +1,22 @@ + + +{#if Content} +
+
+ +
+
+{:else} + +
+

Sorry

+
+

Nothing found

+

Check back later for new content.

+
+
+ +{/if} + \ No newline at end of file diff --git a/web/src/routes/contact/+page.ts b/web/src/routes/contact/+page.ts new file mode 100644 index 00000000..e910d3c1 --- /dev/null +++ b/web/src/routes/contact/+page.ts @@ -0,0 +1,5 @@ +import { dev } from '$app/environment'; + +export const csr = dev; + +export const prerender = true; diff --git a/web/src/routes/contact/Contact.md b/web/src/routes/contact/Contact.md new file mode 100644 index 00000000..334f44fe --- /dev/null +++ b/web/src/routes/contact/Contact.md @@ -0,0 +1,32 @@ +--- +title: "Contact" +description: "Default Contact Page" +date: 2024-11-24 +--- +
+
+

{title}

+
+

+ {description} +

+
+ +Place your contact info here: ... + + + diff --git a/web/src/routes/obsidian/+error.svelte b/web/src/routes/obsidian/+error.svelte new file mode 100644 index 00000000..2d6b9144 --- /dev/null +++ b/web/src/routes/obsidian/+error.svelte @@ -0,0 +1,26 @@ + + +
+
+

+ {$page.status}: {$page.error?.message || 'Something went wrong'} +

+

+ {#if $page.status === 404} + Sorry, we couldn't find the posts you're looking for. + {:else} + An error occurred while loading the posts. Please try again later. + {/if} +

+ +
+
diff --git a/web/src/routes/obsidian/+page.svelte b/web/src/routes/obsidian/+page.svelte new file mode 100644 index 00000000..ad63e8f9 --- /dev/null +++ b/web/src/routes/obsidian/+page.svelte @@ -0,0 +1,23 @@ + + +{#if Content} +
+
+ +
+
+ +{:else} + +
+

Sorry

+
+

Nothing found

+

Check back later for new content.

+
+
+ +{/if} + \ No newline at end of file diff --git a/web/src/routes/obsidian/+page.ts b/web/src/routes/obsidian/+page.ts new file mode 100644 index 00000000..a235bf15 --- /dev/null +++ b/web/src/routes/obsidian/+page.ts @@ -0,0 +1,5 @@ +import { dev } from '$app/environment'; + +export const csr = dev; + +export const prerender = true; \ No newline at end of file diff --git a/web/src/routes/obsidian/Obsidian.md b/web/src/routes/obsidian/Obsidian.md new file mode 100644 index 00000000..bff54c87 --- /dev/null +++ b/web/src/routes/obsidian/Obsidian.md @@ -0,0 +1,63 @@ +--- +title: Obsidian +description: Create and manage your notes with Obsidian! +date: 2024-11-16 +tags: [type/note,obsidian] +--- +
+ + Obsidian Logo + +
+While you don't need to use Obsidian to write your blog posts, it's a great tool for managing your notes. + +## What is Obsidian? + +Obsidian is a powerful knowledge base that works on top of a local folder of plain text Markdown files. It's designed for creating and managing interconnected notes. + +### Key Features + +- 📝 **Plain Text** - All notes are stored as local Markdown files, i.e. they last forever +- 🔗 **Bidirectional Linking** - Create connections between notes like wikilinks +- 🎨 **Graph View** - Visualize your knowledge network with knowledge graphs +- 🧩 **Plugin System** - Extend functionality with community plugins + +### Example Note Structure + +```markdown +# Project Planning + +## Goals +- Define project scope +- Set milestones +- Assign resources + +## Links +[[Resources]] +[[Timeline]] +[[Team Members]] +``` + +### Why Use Obsidian? + +1. **Privacy First** - Your data stays on your device +2. **Future Proof** - Plain text files never become obsolete +3. **Flexible** - Adapt it to your workflow +4. **Community Driven** - Rich ecosystem of themes and plugins + +## Getting Started + +1. **Install Obsidian** - Download from [obsidian.md](https://obsidian.md/) +2. **Create a Vault** - Create a local folder for your notes. Try opening a vault in the `src/lib/content` directory. +3. **Start Writing** - Create your first note + +## Next Steps + +1. **Organize Your Notes** - Create folders for potential posts. All posts are currently placed in the `posts` folder of the `src/lib/content/{posts}` directory. This can be chaged in the `src/lib/content/posts/index.ts` file. +2. **Develop Templates** - Develop templates for your posts +3. **Develop SvelteKit Components** - Build components for displaying content using metadata and templates +4. **Publish Notes** - Drag notes into specific folders in Obsidian to publish them +5. **Test and Refine Workflow** - Regularly test the publishing process by running the SvelteKit development server +6. **Share and Collaborate** + +Check out some examples of the posts you can make over at [Posts](/posts) diff --git a/web/src/routes/posts/+error.svelte b/web/src/routes/posts/+error.svelte new file mode 100644 index 00000000..2d6b9144 --- /dev/null +++ b/web/src/routes/posts/+error.svelte @@ -0,0 +1,26 @@ + + +
+
+

+ {$page.status}: {$page.error?.message || 'Something went wrong'} +

+

+ {#if $page.status === 404} + Sorry, we couldn't find the posts you're looking for. + {:else} + An error occurred while loading the posts. Please try again later. + {/if} +

+ +
+
diff --git a/web/src/routes/posts/+page.svelte b/web/src/routes/posts/+page.svelte new file mode 100644 index 00000000..69c49600 --- /dev/null +++ b/web/src/routes/posts/+page.svelte @@ -0,0 +1,64 @@ + + +
+

Blog Posts

+

This blog is maintained in an Obsidian Vault

+ {#if posts.length === 0} + + {#if !visible} + + {/if} + + {:else} +
+ {#each posts as post} +
+ + View {post.meta.title} + +
+
+

{post.meta.title}

+

{post.meta.description}

+
+
+ + {#if post.meta.tags.length > 0} + +
+ {#each post.meta.tags as tag} + + {tag} + + {/each} +
+ {/if} +
+
+ +
+ {/each} + +
+ {/if} +
\ No newline at end of file diff --git a/web/src/routes/posts/+page.ts b/web/src/routes/posts/+page.ts new file mode 100644 index 00000000..48a07430 --- /dev/null +++ b/web/src/routes/posts/+page.ts @@ -0,0 +1,42 @@ +import { error } from '@sveltejs/kit'; +import type { PageLoad } from './$types'; +// import type { PostMetadata } from '$lib/types'; + +export const load: PageLoad = async () => { + try { + const postFiles = import.meta.glob('/src/lib/content/posts/*.{md,svx}', { eager: true }); + + if (Object.keys(postFiles).length === 0) { + return { + posts: [] + }; + } + + const posts = Object.entries(postFiles).map(([path, post]: [string, any]) => { + const slug = path.split('/').pop()?.replace(/\.(md|svx)$/, ''); + return { + slug, + meta: { + title: post.metadata?.title || 'Untitled', + date: post.metadata?.date || new Date().toISOString(), + created: post.metadata?.created || new Date().toISOString(), + description: post.metadata?.description || '', + tags: post.metadata?.tags || [], + aliases: post.metadata?.aliases || [], + lead: post.metadata?.lead || '', + updated: post.metadata?.updated || new Date().toISOString(), + author: post.metadata?.author || 'John Connor', + } + }; + }); + + posts.sort((a, b) => new Date(b.meta.date).getTime() - new Date(a.meta.date).getTime()); + + return { + posts + }; + } catch (e) { + console.error('Failed to load posts:', e); + throw error(500, 'Failed to load posts'); + } +}; \ No newline at end of file diff --git a/web/src/routes/posts/[slug]/+error.svelte b/web/src/routes/posts/[slug]/+error.svelte new file mode 100644 index 00000000..b57eae6f --- /dev/null +++ b/web/src/routes/posts/[slug]/+error.svelte @@ -0,0 +1,26 @@ + + +
+
+

+ {$page.status}: {$page.error?.message || 'Something went wrong'} +

+

+ {#if $page.status === 404} + Sorry, we couldn't find the post you're looking for. + {:else} + An error occurred while loading the post. Please try again later. + {/if} +

+ +
+
\ No newline at end of file diff --git a/web/src/routes/posts/[slug]/+page.svelte b/web/src/routes/posts/[slug]/+page.svelte new file mode 100644 index 00000000..ad8fb8fa --- /dev/null +++ b/web/src/routes/posts/[slug]/+page.svelte @@ -0,0 +1,54 @@ + + +
+ {#await Content} +
+
+ + Loading post... +
+
+ {:then Content} + +
+ +
+ {:catch error} +
+

Failed to load post

+

{error.message}

+ + Back to Posts + +
+ {/await} +
\ No newline at end of file diff --git a/web/src/routes/posts/[slug]/+page.ts b/web/src/routes/posts/[slug]/+page.ts new file mode 100644 index 00000000..c79a6fea --- /dev/null +++ b/web/src/routes/posts/[slug]/+page.ts @@ -0,0 +1,25 @@ +import { error } from '@sveltejs/kit'; +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ params }) => { + try { + const post = await import(`$lib/content/posts/${params.slug}.md`); + + return { + content: post.default, + meta: { + title: post.metadata.title, + date: post.metadata.date, + description: post.metadata.description, + tags: post.metadata.tags || [], + updated: post.metadata.updated || new Date().toISOString(), + author: post.metadata.author || '', + lead: post.metadata.lead || '', + reference: post.metadata.reference || '', + } + }; + } catch (e) { + console.error(`Failed to load post ${params.slug}:`, e); + throw error(404, `Could not find post ${params.slug}`); + } +}; \ No newline at end of file diff --git a/web/src/routes/tags/+page.svelte b/web/src/routes/tags/+page.svelte new file mode 100644 index 00000000..eac00352 --- /dev/null +++ b/web/src/routes/tags/+page.svelte @@ -0,0 +1,27 @@ + + +
+

{Object.keys(tags).length} Tags in {postsCount} Posts

+ +
+ {#each Object.entries(tags) as [tag, posts]} + + {tag} + {posts.length} posts + + + + {/each} +
+
\ No newline at end of file diff --git a/web/src/routes/tags/+page.ts b/web/src/routes/tags/+page.ts new file mode 100644 index 00000000..5786c1e9 --- /dev/null +++ b/web/src/routes/tags/+page.ts @@ -0,0 +1,34 @@ +import type { PageLoad } from './$types'; +import type { PostMetadata } from '$lib/types/types'; + +export const load: PageLoad = async () => { + const postFiles = import.meta.glob('/src/lib/content/posts/*.{md,svx}', { eager: true }); + + const posts = Object.entries(postFiles).map(([path, post]: [string, any]) => { + const slug = path.split('/').pop()?.replace(/\.(md|svx)$/, ''); + return { + slug, + meta: { + title: post.metadata.title, + date: post.metadata.date, + description: post.metadata.description, + tags: post.metadata.tags || [] + } + }; + }); + + const tags = posts.reduce((acc, post) => { + post.meta.tags.forEach((tag: string) => { + if (!acc[tag]) { + acc[tag] = []; + } + acc[tag].push(post); + }); + return acc; + }, {} as Record); + + return { + tags, + postsCount: posts.length + }; +}; \ No newline at end of file diff --git a/web/src/routes/tags/[tag]/+page.svelte b/web/src/routes/tags/[tag]/+page.svelte new file mode 100644 index 00000000..d3fbd738 --- /dev/null +++ b/web/src/routes/tags/[tag]/+page.svelte @@ -0,0 +1,36 @@ + + +
+
+

Posts tagged with "{tag}"

+ ← Back to tags +
+ +
+ {#each posts as post} +
+ + View {post.meta.title} + +
+
+

{post.meta.title}

+

{post.meta.description}

+
+
+ +
+
+
+ {/each} +
+
\ No newline at end of file diff --git a/web/src/routes/tags/[tag]/+page.ts b/web/src/routes/tags/[tag]/+page.ts new file mode 100644 index 00000000..3d92e4fe --- /dev/null +++ b/web/src/routes/tags/[tag]/+page.ts @@ -0,0 +1,30 @@ +import { error } from '@sveltejs/kit'; +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ params }) => { + const postFiles = import.meta.glob('/src/lib/content/posts/*.{md,svx}', { eager: true }); + + const posts = Object.entries(postFiles).map(([path, post]: [string, any]) => { + const slug = path.split('/').pop()?.replace(/\.(md|svx)$/, ''); + return { + slug, + meta: { + title: post.metadata.title, + date: post.metadata.date, + description: post.metadata.description, + tags: post.metadata.tags || [] + } + }; + }); + + const tagPosts = posts.filter((post) => post.meta.tags.includes(params.tag)); + + if (tagPosts.length === 0) { + throw error(404, `Tag "${params.tag}" not found`); + } + + return { + tag: params.tag, + posts: tagPosts + }; +}; \ No newline at end of file diff --git a/web/static/fabric-logo-gif.gif b/web/static/fabric-logo-gif.gif new file mode 100644 index 00000000..cf87b031 Binary files /dev/null and b/web/static/fabric-logo-gif.gif differ diff --git a/web/static/favicon.png b/web/static/favicon.png new file mode 100644 index 00000000..cf87b031 Binary files /dev/null and b/web/static/favicon.png differ diff --git a/web/static/image.png b/web/static/image.png new file mode 100644 index 00000000..ed0fb20f Binary files /dev/null and b/web/static/image.png differ diff --git a/web/static/obsidian-logo.png b/web/static/obsidian-logo.png new file mode 100755 index 00000000..e3cdf2cc Binary files /dev/null and b/web/static/obsidian-logo.png differ diff --git a/web/static/robots.txt b/web/static/robots.txt new file mode 100644 index 00000000..16199a57 --- /dev/null +++ b/web/static/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: \ No newline at end of file diff --git a/web/svelte.config.js b/web/svelte.config.js new file mode 100644 index 00000000..d4024f3d --- /dev/null +++ b/web/svelte.config.js @@ -0,0 +1,58 @@ +import adapter from '@sveltejs/adapter-auto'; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; +import { mdsvex } from 'mdsvex'; +import rehypeSlug from 'rehype-slug'; +import rehypeAutolinkHeadings from 'rehype-autolink-headings'; +import rehypeExternalLinks from 'rehype-external-links'; +import rehypeUnwrapImages from 'rehype-unwrap-images'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +/** @type {import('mdsvex').MdsvexOptions} */ +const mdsvexOptions = { + extensions: ['.md', '.svx'], + layout: { + _: join(__dirname, './src/lib/layouts/post.svelte') + }, + highlight: { + theme: { + dark: 'github-dark', + light: 'github-light' + } + }, +rehypePlugins: [ + rehypeSlug, + rehypeUnwrapImages, + [rehypeAutolinkHeadings, { + behavior: 'wrap' + }], + [rehypeExternalLinks, { + target: '_blank', + rel: ['noopener', 'noreferrer'] + }] + ] +}; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + kit: { + adapter: adapter(), + alias: { + $components: join(__dirname, 'src/lib/components'), + $lib: join(__dirname, 'src/lib'), + $styles: join(__dirname, 'src/styles'), + + $utils: join(__dirname, 'src/lib/utils') + } + }, + extensions: ['.svelte', '.md', '.svx'], + preprocess: [ + vitePreprocess(), + mdsvex(mdsvexOptions) + ] + }; + + export default config; \ No newline at end of file diff --git a/web/tailwind.config.ts b/web/tailwind.config.ts new file mode 100644 index 00000000..791946bb --- /dev/null +++ b/web/tailwind.config.ts @@ -0,0 +1,111 @@ +import { join } from 'path'; +import type { Config } from 'tailwindcss'; +import forms from '@tailwindcss/forms'; +import typography from '@tailwindcss/typography'; +import { skeleton } from '@skeletonlabs/tw-plugin'; +import { myCustomTheme } from './my-custom-theme.ts' + +export default { + darkMode: 'class', + content: [ + './src/**/*.{html,js,svelte,svx,md,ts}', + join(require.resolve('@skeletonlabs/skeleton'), '../**/*.{html,js,svelte,ts,svx,md}') + ], + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + fontFamily: { + mono: ['Fira Code', 'monospace'], + }, + animation: { + fabGradient: 'fabGradient 15s ease infinite', + blink: 'blink 1s step-end infinite', + }, + keyframes: { + fabGradient: { + '0%, 100%': { 'background-size': '200% 200%, background-position: left center' }, + '50%': { 'background-size': '200% 200%, background-position: right center' }, + }, + blink: { + '0%, 100%': { opacity: 1 }, + '50%': { opacity: 0 }, + }, + }, + typography: { + DEFAULT: { + css: { + 'code::before': { + content: '""' + }, + 'code::after': { + content: '""' + } + } + } + } + }, + }, + plugins: [ + forms, + + typography, + skeleton({ + themes: { + preset: [ + { + name: 'skeleton', + enhancements: true + }, + { + name: 'modern', + enhancements: true + } + ], + custom: [ + myCustomTheme + ] + } + }) + ] +} satisfies Config; \ No newline at end of file diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 00000000..fc93cbd9 --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias + // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in +} diff --git a/web/vite.config.ts b/web/vite.config.ts new file mode 100644 index 00000000..b0fda888 --- /dev/null +++ b/web/vite.config.ts @@ -0,0 +1,17 @@ +import { purgeCss } from 'vite-plugin-tailwind-purgecss'; +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vite'; +import { mdsvex } from 'mdsvex'; + +export default defineConfig({ + plugins: [sveltekit(), mdsvex(), purgeCss()], + server: { + proxy: { + '/api': { + target: 'http://localhost:8080', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api/, '') + } + } + } +}); \ No newline at end of file